0

Multiple AnnotateDataBinders and their Privacy

asked 2012-02-21 13:43:45 +0800

mirjalali gravatar image mirjalali
27 1

Hi.
Assume that we have developed a macro-component M.
A special instance of AnnotateDataBinder (b1) is used in the implementation of M, with some internal bindings that need some 'bindBean()' calls to be previously performed in its afterCompose phase.
summary:
M (with binder b1)
class (M.java):

	....
	b1.bindBean("a", this.a);
	....

macro-uri (M.zul):
	....
	<textbox id="textbox1" value="@{a.x}" />
	....

Now assume that M is used in some other zul page (X) with its own instance of AnnotateDataBinder (b2).
X.zul:

	....
	<M id="m1" prop1="@{g.h}" .... />
	....

on some event handling:
	....
	AnnotateDataBinder b2= (AnnotateDataBinder) rootComponent.getAttribute("binder");
	b2.loadAll();
	....


This makes the macro-component M to malfunction.
The problem is that the bindings inside M, are not only considered in b1 but also in b2.
Though, the needed beans (like "a" in the example above) are only defined for b1.
So, when 'b2.loadAll();' is called, 'b2' tries to load the 'value' of 'textbox1' in 'm1',
but it does not know which bean is referred by 'a' in the expression "@{a.x}".

Obviously, the solution is that we should be able to tell 'AnnotateDataBinder's to avoid considering the bindings inside a special component (like the macro-component above).
For example, during the binder initialization phase,
the binder should not enter a component (with 'AnnotateDataBinder.loadAnnotations()')
if the component implements a special interface (something like 'org.zkoss.zkplus.databind.ExternalAnnotateDataBinderRestricter'),
or if the component has a special custom-attribute with a special value (something like 'org.zkoss.zkplus.databind.restrictExternalAnnotateDataBinders' with value 'true').

I wanted to implement this idea for our own project with extending the class 'AnnotateDataBinder',
but unfortunately (as usual), many methods of the class 'AnnotateDataBinder' are private. :(
So although I really hate that, I was forced to copy its source code and change the required parts.

1- Is there already any feature in zk which solves the problem of interfering data binders?
2- If no, would you please add the feature above to zk?
3- Generally, could you please make your methods 'protected' instead of 'private'?!!!

delete flag offensive retag edit

3 Replies

Sort by ยป oldest newest

answered 2012-02-23 11:29:48 +0800

benbai gravatar image benbai
2228 6
http://www.zkoss.org

Hi mirjalali,

There is a new Databinding Composer after 5.0.8,
You can try use it and prevent the 'nested' of different Databinding Composer.

For example, the code blow will work as expected:

<?component name="macrocomp" macroURI="/macrocomp.zul"
   class="test.MacroComp"?>
<zk>
	<div apply="test.TestComposer">
		<window id="innerWin" apply="org.zkoss.zkplus.databind.AnnotateDataBindingComposer">
			<label id="windowLabel" value="@{beanTwo.time}" />
		</window>
		<!-- There is another AnnotateDataBindingComposer
			and bind another bean in macrocomp -->
		<macrocomp />
	</div>
</zk>

Regards,
ben

link publish delete flag offensive edit

answered 2012-02-23 16:46:31 +0800

mirjalali gravatar image mirjalali
27 1

It obviously has no effect on the problem mentioned above.

link publish delete flag offensive edit

answered 2012-02-24 03:09:26 +0800

benbai gravatar image benbai
2228 6
http://www.zkoss.org

updated 2012-02-24 05:19:02 +0800

Just point out in stead of make it nested then workaround restrict this or prevent that,
prevent the nested directly is another choice.

Another way is make the parent to keep the binding bean for BindingMacro child,
please refer to the sample below.

In first case there are four macro component with binding with respect to the specified bean name,
two of them are nested and the other two are not, all work fine.

In second case there are two macro component with binding,
one is nested and the other is not, both work fine.

test with 5.0.8 or later:

consider multiple macro with dynamic bean name:

ZKFiddle-Link

MacroComposer.java
package jtsptbo$v2;

import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.util.GenericForwardComposer;

public class MacroComposer extends GenericForwardComposer {
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
String beanName = ((MacroComp)comp.getParent().getParent()).getBeanName();
Executions.createComponentsDirectly("<label id=\"mc_label\" value=\"@{"+beanName+".time}\" />", null, comp, null);
}
}


Bean.java
package jtsptbo$v2;


import java.util.Date;

public class Bean {
String _entity;
public Bean (String entity) {
_entity = entity;
}
public String getTime() {
return _entity + " time: " + new Date(System.currentTimeMillis()).toString();
}
}


BindingMacro.java
package jtsptbo$v2;

import org.zkoss.zkplus.databind.AnnotateDataBinder;

public interface BindingMacro {
/**
* return whether this component has binding
*/
public boolean hasBinding();
/**
* put all binding to another binder
*/
public void delegateBinding(AnnotateDataBinder adb);
}


MacroComp.java
package jtsptbo$v2;

import org.zkoss.zk.ui.HtmlMacroComponent;
import org.zkoss.zkplus.databind.AnnotateDataBinder;

public class MacroComp extends HtmlMacroComponent implements BindingMacro {
Bean b;
String _beanName;
boolean _hasBinding = true;
public void afterCompose() {
super.afterCompose();
b = new Bean(_beanName);
AnnotateDataBinder binderOne = (AnnotateDataBinder)getFirstChild().getAttribute("binder");
binderOne.bindBean(_beanName, b);
binderOne.loadAll();
}
/**
* return whether this component has binding
*/
public boolean hasBinding() {
return _hasBinding;
}
/**
* put all binding to another binder
*/
public void delegateBinding(AnnotateDataBinder adb) {
adb.bindBean(_beanName, b);
getFirstChild().setAttribute("binder", null);
_hasBinding = false;
}
public void setBeanName(String beanName) {
_beanName = beanName;
}
public String getBeanName() {
return _beanName;
}
}


TestComposer.java
package jtsptbo$v2;


import java.util.*;

import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zkplus.databind.AnnotateDataBinder;

public class TestComposer extends GenericForwardComposer {
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
// get the binder of this composer
AnnotateDataBinder binderTwo = (AnnotateDataBinder)comp.getAttribute("binder");
List<Component> children = comp.getChildren();
for (Component c : children) {
if (c instanceof BindingMacro) {
// if the child is a BindingMacro and has binding,
// get binding from it
BindingMacro bc = (BindingMacro) c;
if (bc.hasBinding())
bc.delegateBinding(binderTwo);
}
}
binderTwo.bindBean("beanTwo", new Bean(" outer div"));
binderTwo.loadAll();
}
}


macrocomp.zul
<zk>
<window style="display: inline-block;" apply="org.zkoss.zkplus.databind.AnnotateDataBindingComposer">
<window id="mc_innerWin" apply="jtsptbo$v2.MacroComposer">

</window>
</window>
</zk>


index.zul
<?component name="macrocomp" macroURI="macrocomp.zul"
class="jtsptbo$v2.MacroComp"?>
<zk>
<div apply="org.zkoss.zkplus.databind.AnnotateDataBindingComposer,jtsptbo$v2.TestComposer">
<label id="windowLabel" value="@{beanTwo.time}" /><div></div>
<!-- There is another AnnotateDataBindingComposer
and bind another bean in macrocomp -->
<macrocomp beanName="firstMacro" /><div></div>
<macrocomp beanName="secondMacro" />
</div>
<macrocomp beanName="thirdMacro" /><div></div>
<macrocomp beanName="4thMacro" />
</zk>

allowed only one macro in nested:


Bean.java
package jtsptbo$v1;


import java.util.Date;

public class Bean {
public String getTime() {
return "time: " + new Date(System.currentTimeMillis()).toString();
}
}


BindingMacro.java
package jtsptbo$v1;

import org.zkoss.zkplus.databind.AnnotateDataBinder;

public interface BindingMacro {
/**
* return whether this component has binding
*/
public boolean hasBinding();
/**
* put all binding to another binder
*/
public void delegateBinding(AnnotateDataBinder adb);
}


MacroComp.java
package jtsptbo$v1;

import org.zkoss.zk.ui.HtmlMacroComponent;
import org.zkoss.zkplus.databind.AnnotateDataBinder;

public class MacroComp extends HtmlMacroComponent implements BindingMacro {
Bean b = new Bean();
boolean _hasBinding = true;
public void afterCompose() {
super.afterCompose();
AnnotateDataBinder binderOne = (AnnotateDataBinder)getFirstChild().getAttribute("binder");
binderOne.bindBean("bean", b);
getFirstChild().getFellow("mc_label");
binderOne.loadAll();
}
/**
* return whether this component has binding
*/
public boolean hasBinding() {
return _hasBinding;
}
/**
* put all binding to another binder
*/
public void delegateBinding(AnnotateDataBinder adb) {
adb.bindBean("bean", b);
getFirstChild().setAttribute("binder", null);
_hasBinding = false;
}
}


TestComposer.java
package jtsptbo$v1;

import java.util.*;

import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zkplus.databind.AnnotateDataBinder;

public class TestComposer extends GenericForwardComposer {
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
// get the binder of this composer
AnnotateDataBinder binderTwo = (AnnotateDataBinder)comp.getAttribute("binder");
List<Component> children = comp.getChildren();
for (Component c : children) {
if (c instanceof BindingMacro) {
// if the child is a BindingMacro and has binding,
// get binding from it
BindingMacro bc = (BindingMacro) c;
if (bc.hasBinding())
bc.delegateBinding(binderTwo);
}
}
binderTwo.bindBean("beanTwo", new Bean());
binderTwo.loadAll();
}
}


macrocomp.zul
<zk>
<window style="display: inline-block;" apply="org.zkoss.zkplus.databind.AnnotateDataBindingComposer">
<label id="mc_label" value="@{bean.time}" />
</window>
</zk>

index.zul
<?component name="macrocomp" macroURI="macrocomp.zul"
class="jtsptbo$v1.MacroComp"?>
<zk>
<div apply="org.zkoss.zkplus.databind.AnnotateDataBindingComposer,jtsptbo$v1.TestComposer">
<label id="windowLabel" value="@{beanTwo.time}" /><div></div>
<!-- There is another AnnotateDataBindingComposer
and bind another bean in macrocomp -->
<macrocomp />
</div>
<macrocomp />
</zk>

Regards,
ben

link publish delete flag offensive edit
Your reply
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!

[hide preview]

Question tools

Follow

RSS

Stats

Asked: 2012-02-21 13:43:45 +0800

Seen: 252 times

Last updated: Feb 24 '12

Support Options
  • Email Support
  • Training
  • Consulting
  • Outsourcing
Learn More