Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.zkoss.bind.impl.AnnotateBinderHelper Maven / Gradle / Ivy
/* AnnotateBinderHelper.java
Purpose:
Description:
History:
Sep 9, 2011 6:06:10 PM, Created by henrichen
Copyright (C) 2011 Potix Corporation. All Rights Reserved.
*/
package org.zkoss.bind.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.zkoss.bind.BindComposer;
import org.zkoss.bind.BindContext;
import org.zkoss.bind.Binder;
import org.zkoss.bind.Phase;
import org.zkoss.bind.impl.BinderUtil.UtilContext;
import org.zkoss.bind.sys.BindEvaluatorX;
import org.zkoss.bind.sys.BinderCtrl;
import org.zkoss.bind.sys.debugger.BindingAnnotationInfoChecker;
import org.zkoss.lang.Strings;
import org.zkoss.util.IllegalSyntaxException;
import org.zkoss.zhtml.impl.AbstractTag;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.ShadowElement;
import org.zkoss.zk.ui.metainfo.Annotation;
import org.zkoss.zk.ui.sys.ComponentCtrl;
/**
* Helper class to parse binding annotations and create bindings.
* @author henrichen
* @author dennischen
* @since 6.0.0
*/
public class AnnotateBinderHelper {
private final Binder _binder;
public static final String INIT_ANNO = "init";
public static final String BIND_ANNO = "bind";
public static final String LOAD_ANNO = "load";
public static final String SAVE_ANNO = "save";
public static final String REFERENCE_ANNO = "ref";
public static final String ID_ANNO = "id";
public static final String VALIDATOR_ANNO = "validator";
public static final String CONVERTER_ANNO = "converter";
public static final String TEMPLATE_ANNO = "template";
public static final String COMMAND_ANNO = "command";
public static final String GLOBAL_COMMAND_ANNO = "global-command";
public static final String FORM_ATTR = "form";
public static final String VIEW_MODEL_ATTR = "viewModel";
public static final String BINDER_ATTR = "binder";
public static final String VALIDATION_MESSAGES_ATTR = "validationMessages";
public static final String CHILDREN_ATTR = "children";
//control key
public static final String CHILDREN_KEY = "$CHILDREN$";
public AnnotateBinderHelper(Binder binder) {
_binder = binder;
}
public void initComponentBindings(Component comp) {
processAllComponentsBindings(comp);
}
private void processAllComponentsBindings(Component comp) {
final Binder selfBinder = BinderUtil.getBinder(comp);
//check if a component was binded already(by any binder)
if (selfBinder != null) //this component already binded ! skip all of its children
return;
BindingAnnotationInfoChecker checker = ((BinderCtrl) _binder).getBindingAnnotationInfoChecker();
if (checker != null) {
checker.checkBinding(_binder, comp);
}
processComponentBindings0(comp);
for (final Iterator it = comp.getChildren().iterator(); it.hasNext();) {
final Component kid = it.next();
// it may be a nested binder.
if (!kid.hasAttribute(BindComposer.BINDER_ID)) {
processAllComponentsBindings(kid); //recursive to each child
} else if (kid.hasAttribute(BinderCtrl.REMOVE_BINDINGS)) { // for nested binder
kid.removeAttribute(BinderCtrl.REMOVE_BINDINGS);
final Binder nestedBinder = (Binder) kid
.getAttribute((String) kid.getAttribute(BindComposer.BINDER_ID));
new AnnotateBinderHelper(nestedBinder).initComponentBindings(kid);
BinderUtil.markHandling(kid, nestedBinder);
((BinderImpl) nestedBinder).initQueue();
((BinderImpl) nestedBinder).initActivator();
nestedBinder.loadComponent(kid, true);
}
}
// support shadow element
if (comp instanceof ComponentCtrl) {
for (ShadowElement se : ((ComponentCtrl) comp).getShadowRoots()) {
processAllComponentsBindings((Component) se);
}
}
}
private void processComponentBindings0(Component comp) {
final List props = AnnotationUtil.getNonSystemProperties(comp); // look every property has annotation
for (final Iterator> it = props.iterator(); it.hasNext();) {
final String propName = (String) it.next();
if (isEventProperty(propName)) {
processCommandBinding(comp, propName);
processGlobalCommandBinding(comp, propName);
} else if (FORM_ATTR.equals(propName)) {
processFormBindings(comp);
} else if (CHILDREN_ATTR.equals(propName)) {
processChildrenBindings(comp);
} else if (VIEW_MODEL_ATTR.equals(propName)) {
//ignore
} else if (BINDER_ATTR.equals(propName)) {
//ignore
} else if (VALIDATION_MESSAGES_ATTR.equals(propName)) {
//ignore
} else {
processPropertyBindings(comp, propName);
}
}
//don't mark the component is controlled, if we do this, it will always create a attribute map for a component.
//and consume more memory, make performance worse.
//if(!BinderUtil.isHandling(comp)){
// BinderUtil.markHandling(comp, _binder);
//}
}
private boolean isEventProperty(String propName) {
return propName.startsWith("on") && propName.length() >= 3 && Character.isUpperCase(propName.charAt(2));
}
private void processCommandBinding(Component comp, String propName) {
final ComponentCtrl compCtrl = (ComponentCtrl) comp;
final Collection anncol = compCtrl.getAnnotations(propName, COMMAND_ANNO);
if (anncol.size() == 0)
return;
if (anncol.size() > 1) {
throw new IllegalSyntaxException(MiscUtil.formatLocationMessage(
"Allow only one command binding for event " + propName + " of " + comp, comp));
}
final Annotation ann = anncol.iterator().next();
final Map attrs = ann.getAttributes(); //(tag, tagExpr)
Map args = null;
final List cmdExprs = new ArrayList();
Binder commandBinder = _binder;
for (final Iterator> it = attrs.entrySet().iterator(); it.hasNext();) {
final Entry entry = it.next();
final String tag = entry.getKey();
final String[] tagExpr = entry.getValue();
if ("value".equals(tag)) {
cmdExprs.add(AnnotationUtil.testString(tagExpr, ann));
} else { //other unknown tag, keep as arguments
if (args == null) {
args = new LinkedHashMap();
}
args.put(tag, tagExpr);
}
}
final Map parsedArgs = args == null ? null
: BindEvaluatorXUtil.parseArgs(_binder.getEvaluatorX(), args);
try {
BinderUtil.pushContext().setCurrentLocation(ann.getLocation());
for (String cmd : cmdExprs) {
commandBinder.addCommandBinding(comp, propName, cmd, parsedArgs);
}
} finally {
BinderUtil.popContext();
}
}
private void processGlobalCommandBinding(Component comp, String propName) {
final ComponentCtrl compCtrl = (ComponentCtrl) comp;
final Collection anncol = compCtrl.getAnnotations(propName, GLOBAL_COMMAND_ANNO);
if (anncol.size() == 0)
return;
if (anncol.size() > 1) {
throw new IllegalSyntaxException(MiscUtil.formatLocationMessage(
"Allow only one global-command binding for event " + propName + " of " + comp, comp));
}
final Annotation ann = anncol.iterator().next();
final Map attrs = ann.getAttributes(); //(tag, tagExpr)
Map args = null;
final List cmdExprs = new ArrayList();
for (final Iterator> it = attrs.entrySet().iterator(); it.hasNext();) {
final Entry entry = it.next();
final String tag = entry.getKey();
final String[] tagExpr = entry.getValue();
if ("value".equals(tag)) {
cmdExprs.add(AnnotationUtil.testString(tagExpr, ann));
} else { //other unknown tag, keep as arguments
if (args == null) {
args = new LinkedHashMap();
}
args.put(tag, tagExpr);
}
}
final Map parsedArgs = args == null ? null
: BindEvaluatorXUtil.parseArgs(_binder.getEvaluatorX(), args);
try {
BinderUtil.pushContext().setCurrentLocation(ann.getLocation());
for (String cmd : cmdExprs) {
_binder.addGlobalCommandBinding(comp, propName, cmd, parsedArgs);
}
} finally {
BinderUtil.popContext();
}
}
private BindContext doPreInitPhase(Component comp, String propName) {
if (_binder instanceof BinderImpl) {
BindContext ctx = BindContextUtil.newBindContext(_binder, null, false, propName, comp, null);
((BinderImpl) _binder).doPrePhase(Phase.INITIAL_BINDING, ctx);
return ctx;
}
return null;
}
private void processPropertyBindings(Component comp, String propName) {
final ComponentCtrl compCtrl = (ComponentCtrl) comp;
//validator and converter information
ExpressionAnnoInfo validatorInfo = parseValidator(comp, propName);
ExpressionAnnoInfo converterInfo = parseConverter(comp, propName);
BindContext ctx = null;
try {
//scan init
Collection initannos = compCtrl.getAnnotations(propName, INIT_ANNO);
if (initannos.size() > 1) {
throw new IllegalSyntaxException(MiscUtil.formatLocationMessage(
"Allow only one @init for " + propName + " of " + comp, initannos.iterator().next()));
} else if (initannos.size() == 1) {
processPropertyInit(comp, propName, initannos.iterator().next(), converterInfo);
}
Collection annos = compCtrl.getAnnotations(propName); //init in the annotation with the sequence
for (Annotation anno : annos) {
if (anno.getName().equals(BIND_ANNO)) {
if (ctx == null) {
ctx = doPreInitPhase(comp, propName);
}
processPropertyPromptBindings(comp, propName, anno, converterInfo, validatorInfo);
} else if (anno.getName().equals(LOAD_ANNO)) {
if (ctx == null) {
ctx = doPreInitPhase(comp, propName);
}
processPropertyLoadBindings(comp, propName, anno, converterInfo);
} else if (anno.getName().equals(SAVE_ANNO)) {
if (ctx == null) {
ctx = doPreInitPhase(comp, propName);
}
processPropertySaveBindings(comp, propName, anno, converterInfo, validatorInfo);
} else if (anno.getName().equals(REFERENCE_ANNO)) {
if (ctx == null) {
ctx = doPreInitPhase(comp, propName);
}
processReferenceBinding(comp, propName, anno);
}
}
ExpressionAnnoInfo templateInfo = parseTemplate(comp, propName);
if (templateInfo != null) {
_binder.setTemplate(comp, propName, templateInfo.expr, templateInfo.args);
}
} finally {
if (_binder instanceof BinderImpl && ctx != null) {
((BinderImpl) _binder).doPostPhase(Phase.INITIAL_BINDING, ctx);
}
}
}
private void processReferenceBinding(Component comp, String propName, Annotation ann) {
String loadExpr = null;
Map args = null;
for (final Iterator> it = ann.getAttributes().entrySet().iterator(); it.hasNext();) {
final Entry entry = it.next();
final String tag = entry.getKey();
final String[] tagExpr = entry.getValue();
if ("value".equals(tag)) {
loadExpr = AnnotationUtil.testString(tagExpr, ann);
} else { //other unknown tag, keep as arguments
if (args == null) {
args = new HashMap();
}
args.put(tag, tagExpr);
}
}
final Map parsedArgs = args == null ? null
: BindEvaluatorXUtil.parseArgs(_binder.getEvaluatorX(), args);
try {
BinderUtil.pushContext().setCurrentLocation(ann.getLocation());
_binder.addReferenceBinding(comp, propName, loadExpr, parsedArgs);
} finally {
BinderUtil.popContext();
}
}
private void processPropertyInit(Component comp, String propName, Annotation ann,
ExpressionAnnoInfo converterInfo) {
String initExpr = null;
Map args = null;
for (final Iterator> it = ann.getAttributes().entrySet().iterator(); it.hasNext();) {
final Entry entry = it.next();
final String tag = entry.getKey();
final String[] tagExpr = entry.getValue();
if ("value".equals(tag)) {
initExpr = AnnotationUtil.testString(tagExpr, ann);
} else { //other unknown tag, keep as arguments
if (args == null) {
args = new HashMap();
}
args.put(tag, tagExpr);
}
}
final Map parsedArgs = args == null ? null
: BindEvaluatorXUtil.parseArgs(_binder.getEvaluatorX(), args);
try {
BinderUtil.pushContext().setCurrentLocation(ann.getLocation());
_binder.addPropertyInitBinding(comp, propName, initExpr, parsedArgs,
converterInfo == null ? null : converterInfo.expr,
converterInfo == null ? null : converterInfo.args);
} finally {
BinderUtil.popContext();
}
}
//process @bind(expr)
private void processPropertyPromptBindings(Component comp, String propName, Annotation ann,
ExpressionAnnoInfo converterInfo, ExpressionAnnoInfo validatorInfo) {
String expr = null;
Map args = null;
for (final Iterator> it = ann.getAttributes().entrySet().iterator(); it.hasNext();) {
final Entry entry = it.next();
final String tag = entry.getKey();
final String[] tagExpr = entry.getValue();
if ("value".equals(tag)) {
expr = AnnotationUtil.testString(tagExpr, ann);
} else if ("before".equals(tag)) {
throw new IllegalSyntaxException(MiscUtil.formatLocationMessage(
"@bind is for prompt binding only, doesn't support before commands, check property " + propName
+ " of " + comp,
ann));
} else if ("after".equals(tag)) {
throw new IllegalSyntaxException(MiscUtil.formatLocationMessage(
"@bind is for prompt binding only, doesn't support after commands, check property " + propName
+ " of " + comp,
ann));
} else { //other unknown tag, keep as arguments
if (args == null) {
args = new HashMap();
}
args.put(tag, tagExpr);
}
}
final Map parsedArgs = args == null ? null
: BindEvaluatorXUtil.parseArgs(_binder.getEvaluatorX(), args);
try {
UtilContext ctx = BinderUtil.pushContext();
ctx.setIgnoreAccessCreationWarn(true);
ctx.setCurrentLocation(ann.getLocation());
_binder.addPropertyLoadBindings(comp, propName, expr, null, null, parsedArgs,
converterInfo == null ? null : converterInfo.expr,
converterInfo == null ? null : converterInfo.args);
_binder.addPropertySaveBindings(comp, propName, expr, null, null, parsedArgs,
converterInfo == null ? null : converterInfo.expr,
converterInfo == null ? null : converterInfo.args,
validatorInfo == null ? null : validatorInfo.expr,
validatorInfo == null ? null : validatorInfo.args);
} finally {
BinderUtil.popContext();
}
}
private void addCommand(Component comp, List cmds, String[] cmdExprs) {
for (String cmdExpr : (String[]) cmdExprs) {
addCommand(comp, cmds, cmdExpr);
}
}
private void addCommand(Component comp, List cmds, String cmdExpr) {
String cmd = BindEvaluatorXUtil.eval(_binder.getEvaluatorX(), comp, cmdExpr, String.class);
if (Strings.isEmpty(cmd)) {
throw new IllegalSyntaxException(
MiscUtil.formatLocationMessage("command of expression " + cmdExpr + " is empty", comp));
}
cmds.add(cmd);
}
private void processPropertyLoadBindings(Component comp, String propName, Annotation ann,
ExpressionAnnoInfo converterInfo) {
String loadExpr = null;
final List beforeCmds = new ArrayList();
final List afterCmds = new ArrayList();
Map args = null;
for (final Iterator> it = ann.getAttributes().entrySet().iterator(); it.hasNext();) {
final Entry entry = it.next();
final String tag = entry.getKey();
final String[] tagExpr = entry.getValue();
if ("value".equals(tag)) {
loadExpr = AnnotationUtil.testString(tagExpr, ann);
} else if ("before".equals(tag)) {
addCommand(comp, beforeCmds, tagExpr);
} else if ("after".equals(tag)) {
addCommand(comp, afterCmds, tagExpr);
} else { //other unknown tag, keep as arguments
if (args == null) {
args = new HashMap();
}
args.put(tag, tagExpr);
}
}
final Map parsedArgs = args == null ? null
: BindEvaluatorXUtil.parseArgs(_binder.getEvaluatorX(), args);
try {
BinderUtil.pushContext().setCurrentLocation(ann.getLocation());
_binder.addPropertyLoadBindings(comp, propName, loadExpr,
beforeCmds.size() == 0 ? null : beforeCmds.toArray(new String[beforeCmds.size()]),
afterCmds.size() == 0 ? null : afterCmds.toArray(new String[afterCmds.size()]), parsedArgs,
converterInfo == null ? null : converterInfo.expr,
converterInfo == null ? null : converterInfo.args);
} finally {
BinderUtil.popContext();
}
}
private void processPropertySaveBindings(Component comp, String propName, Annotation ann,
ExpressionAnnoInfo converterInfo, ExpressionAnnoInfo validatorInfo) {
String saveExpr = null;
final List beforeCmds = new ArrayList();
final List afterCmds = new ArrayList();
Map args = null;
for (final Iterator> it = ann.getAttributes().entrySet().iterator(); it.hasNext();) {
final Entry entry = it.next();
final String tag = entry.getKey();
final String[] tagExpr = entry.getValue();
if ("value".equals(tag)) {
saveExpr = AnnotationUtil.testString(tagExpr, ann);
} else if ("before".equals(tag)) {
addCommand(comp, beforeCmds, tagExpr);
} else if ("after".equals(tag)) {
addCommand(comp, afterCmds, tagExpr);
} else { //other unknown tag, keep as arguments
if (args == null) {
args = new HashMap();
}
args.put(tag, tagExpr);
}
}
final Map parsedArgs = args == null ? null
: BindEvaluatorXUtil.parseArgs(_binder.getEvaluatorX(), args);
try {
BinderUtil.pushContext().setCurrentLocation(ann.getLocation());
_binder.addPropertySaveBindings(comp, propName, saveExpr,
beforeCmds.size() == 0 ? null : beforeCmds.toArray(new String[beforeCmds.size()]),
afterCmds.size() == 0 ? null : afterCmds.toArray(new String[afterCmds.size()]), parsedArgs,
converterInfo == null ? null : converterInfo.expr,
converterInfo == null ? null : converterInfo.args,
validatorInfo == null ? null : validatorInfo.expr,
validatorInfo == null ? null : validatorInfo.args);
} finally {
BinderUtil.popContext();
}
}
private void processFormBindings(Component comp) {
final ComponentCtrl compCtrl = (ComponentCtrl) comp;
final BindEvaluatorX eval = _binder.getEvaluatorX();
//validator information
ExpressionAnnoInfo validatorInfo = parseValidator(comp, FORM_ATTR);
String formId = null;
Collection idannos = compCtrl.getAnnotations(FORM_ATTR, ID_ANNO);
if (idannos.size() == 0) {
if (comp instanceof AbstractTag) {
return; // ignore since HTML5 has "form" attribute.
}
throw new IllegalSyntaxException(
MiscUtil.formatLocationMessage("@id is not found for a form binding of " + comp, comp));
} else if (idannos.size() > 1) {
throw new IllegalSyntaxException(MiscUtil.formatLocationMessage(
"Allow only one @id for a form binding of " + comp, idannos.iterator().next()));
}
final Annotation idanno = idannos.iterator().next();
final String idExpr = idanno.getAttribute("value");
if (idExpr != null) {
formId = BindEvaluatorXUtil.eval(eval, comp, idExpr, String.class);
}
if (formId == null) {
throw new IllegalSyntaxException(MiscUtil.formatLocationMessage(
"value of @id is not found for a form binding of " + compCtrl + ", exprssion is " + idExpr,
idanno));
}
//scan init first
Collection initannos = compCtrl.getAnnotations(FORM_ATTR, INIT_ANNO);
if (initannos.size() > 1) {
throw new IllegalSyntaxException(MiscUtil.formatLocationMessage(
"Allow only one @init for " + FORM_ATTR + " of " + comp, initannos.iterator().next()));
} else if (initannos.size() == 1) {
processFormInit(comp, formId, initannos.iterator().next());
}
Collection annos = compCtrl.getAnnotations(FORM_ATTR); //get all annotation in the form with the order.
for (Annotation anno : annos) {
if (anno.getName().equals(LOAD_ANNO)) {
processFormLoadBindings(comp, formId, anno);
} else if (anno.getName().equals(SAVE_ANNO)) {
processFormSaveBindings(comp, formId, anno, validatorInfo);
}
}
}
private void processFormInit(Component comp, String formId, Annotation ann) {
String initExpr = null;
Map args = null;
for (final Iterator> it = ann.getAttributes().entrySet().iterator(); it.hasNext();) {
final Entry entry = it.next();
final String tag = entry.getKey();
final String[] tagExpr = entry.getValue();
if ("value".equals(tag)) {
initExpr = AnnotationUtil.testString(tagExpr, ann);
} else { //other unknown tag, keep as arguments
if (args == null) {
args = new HashMap();
}
args.put(tag, tagExpr);
}
}
final Map parsedArgs = args == null ? null
: BindEvaluatorXUtil.parseArgs(_binder.getEvaluatorX(), args);
try {
BinderUtil.pushContext().setCurrentLocation(ann.getLocation());
_binder.addFormInitBinding(comp, formId, initExpr, parsedArgs);
} finally {
BinderUtil.popContext();
}
}
private void processFormLoadBindings(Component comp, String formId, Annotation ann) {
String loadExpr = null;
final List beforeCmds = new ArrayList();
final List afterCmds = new ArrayList();
Map args = null;
for (final Iterator> it = ann.getAttributes().entrySet().iterator(); it.hasNext();) {
final Entry entry = it.next();
final String tag = entry.getKey();
final String[] tagExpr = entry.getValue();
if ("value".equals(tag)) {
loadExpr = AnnotationUtil.testString(tagExpr, ann);
} else if ("before".equals(tag)) {
addCommand(comp, beforeCmds, tagExpr);
} else if ("after".equals(tag)) {
addCommand(comp, afterCmds, tagExpr);
} else { //other unknown tag, keep as arguments
if (args == null) {
args = new HashMap();
}
args.put(tag, tagExpr);
}
}
final Map parsedArgs = args == null ? null
: BindEvaluatorXUtil.parseArgs(_binder.getEvaluatorX(), args);
try {
BinderUtil.pushContext().setCurrentLocation(ann.getLocation());
_binder.addFormLoadBindings(comp, formId, loadExpr,
beforeCmds.size() == 0 ? null : beforeCmds.toArray(new String[beforeCmds.size()]),
afterCmds.size() == 0 ? null : afterCmds.toArray(new String[afterCmds.size()]), parsedArgs);
} finally {
BinderUtil.popContext();
}
}
private void processFormSaveBindings(Component comp, String formId, Annotation ann,
ExpressionAnnoInfo validatorInfo) {
String saveExpr = null;
final List beforeCmds = new ArrayList();
final List afterCmds = new ArrayList();
Map args = null;
for (final Iterator> it = ann.getAttributes().entrySet().iterator(); it.hasNext();) {
final Entry entry = it.next();
final String tag = entry.getKey();
final String[] tagExpr = entry.getValue();
if ("value".equals(tag)) {
saveExpr = AnnotationUtil.testString(tagExpr, ann);
} else if ("before".equals(tag)) {
addCommand(comp, beforeCmds, tagExpr);
} else if ("after".equals(tag)) {
addCommand(comp, afterCmds, tagExpr);
} else { //other unknown tag, keep as arguments
if (args == null) {
args = new HashMap();
}
args.put(tag, tagExpr);
}
}
final Map parsedArgs = args == null ? null
: BindEvaluatorXUtil.parseArgs(_binder.getEvaluatorX(), args);
try {
BinderUtil.pushContext().setCurrentLocation(ann.getLocation());
_binder.addFormSaveBindings(comp, formId, saveExpr,
beforeCmds.size() == 0 ? null : beforeCmds.toArray(new String[beforeCmds.size()]),
afterCmds.size() == 0 ? null : afterCmds.toArray(new String[afterCmds.size()]), parsedArgs,
validatorInfo == null ? null : validatorInfo.expr,
validatorInfo == null ? null : validatorInfo.args);
} finally {
BinderUtil.popContext();
}
}
private void processChildrenBindings(Component comp) {
final ComponentCtrl compCtrl = (ComponentCtrl) comp;
ExpressionAnnoInfo converterInfo = parseConverter(comp, CHILDREN_ATTR);
//scan init first
Collection initannos = compCtrl.getAnnotations(CHILDREN_ATTR, INIT_ANNO);
if (initannos.size() > 1) {
throw new IllegalSyntaxException(MiscUtil.formatLocationMessage(
"Allow only one @init for " + CHILDREN_ATTR + " of " + comp, initannos.iterator().next()));
} else if (initannos.size() == 1) {
processChildrenInit(comp, initannos.iterator().next(), converterInfo);
}
Collection annos = compCtrl.getAnnotations(CHILDREN_ATTR); //get all annotation in the children with the order.
for (Annotation anno : annos) {
if (anno.getName().equals(BIND_ANNO)) {
processChildrenPromptBindings(comp, anno, converterInfo);
} else if (anno.getName().equals(LOAD_ANNO)) {
processChildrenLoadBindings(comp, anno, converterInfo);
}
}
ExpressionAnnoInfo templateInfo = parseTemplate(comp, CHILDREN_ATTR);
if (templateInfo != null) {
//use special CHILDREN_KEY to avoid conflict
_binder.setTemplate(comp, CHILDREN_KEY, templateInfo.expr, templateInfo.args);
}
}
private void processChildrenInit(Component comp, Annotation ann, ExpressionAnnoInfo converterInfo) {
String initExpr = null;
Map args = null;
for (final Iterator> it = ann.getAttributes().entrySet().iterator(); it.hasNext();) {
final Entry entry = it.next();
final String tag = entry.getKey();
final String[] tagExpr = entry.getValue();
if ("value".equals(tag)) {
initExpr = AnnotationUtil.testString(tagExpr, ann);
} else { //other unknown tag, keep as arguments
if (args == null) {
args = new HashMap();
}
args.put(tag, tagExpr);
}
}
final Map parsedArgs = args == null ? null
: BindEvaluatorXUtil.parseArgs(_binder.getEvaluatorX(), args);
try {
BinderUtil.pushContext().setCurrentLocation(ann.getLocation());
_binder.addChildrenInitBinding(comp, initExpr, parsedArgs,
converterInfo == null ? getDefaultChildBindingConverter() : converterInfo.expr,
converterInfo == null ? null : converterInfo.args);
} finally {
BinderUtil.popContext();
}
}
private String getDefaultChildBindingConverter() {
if (SystemConverters.get("childrenBinding") != null) {
return "'childrenBinding'";
}
return null;
}
private void processChildrenPromptBindings(Component comp, Annotation ann, ExpressionAnnoInfo converterInfo) {
String expr = null;
Map args = null;
for (final Iterator> it = ann.getAttributes().entrySet().iterator(); it.hasNext();) {
final Entry entry = it.next();
final String tag = entry.getKey();
final String[] tagExpr = entry.getValue();
if ("value".equals(tag)) {
expr = AnnotationUtil.testString(tagExpr, ann);
} else if ("before".equals(tag)) {
throw new IllegalSyntaxException(MiscUtil.formatLocationMessage(
"@bind is for prompt binding only, doesn't support before commands, check property "
+ CHILDREN_ATTR + " of " + comp,
comp));
} else if ("after".equals(tag)) {
throw new IllegalSyntaxException(MiscUtil.formatLocationMessage(
"@bind is for prompt binding only, doesn't support after commands, check property "
+ CHILDREN_ATTR + " of " + comp,
comp));
} else { //other unknown tag, keep as arguments
if (args == null) {
args = new HashMap();
}
args.put(tag, tagExpr);
}
}
final Map parsedArgs = args == null ? null
: BindEvaluatorXUtil.parseArgs(_binder.getEvaluatorX(), args);
try {
BinderUtil.pushContext().setCurrentLocation(ann.getLocation());
_binder.addChildrenLoadBindings(comp, expr, null, null, parsedArgs,
converterInfo == null ? getDefaultChildBindingConverter() : converterInfo.expr,
converterInfo == null ? null : converterInfo.args);
} finally {
BinderUtil.popContext();
}
}
private void processChildrenLoadBindings(Component comp, Annotation ann, ExpressionAnnoInfo converterInfo) {
String loadExpr = null;
final List beforeCmds = new ArrayList();
final List afterCmds = new ArrayList();
Map args = null;
for (final Iterator> it = ann.getAttributes().entrySet().iterator(); it.hasNext();) {
final Entry entry = it.next();
final String tag = entry.getKey();
final String[] tagExpr = entry.getValue();
if ("value".equals(tag)) {
loadExpr = AnnotationUtil.testString(tagExpr, ann);
} else if ("before".equals(tag)) {
addCommand(comp, beforeCmds, tagExpr);
} else if ("after".equals(tag)) {
addCommand(comp, afterCmds, tagExpr);
} else { //other unknown tag, keep as arguments
if (args == null) {
args = new HashMap();
}
args.put(tag, tagExpr);
}
}
final Map parsedArgs = args == null ? null
: BindEvaluatorXUtil.parseArgs(_binder.getEvaluatorX(), args);
try {
BinderUtil.pushContext().setCurrentLocation(ann.getLocation());
_binder.addChildrenLoadBindings(comp, loadExpr,
beforeCmds.size() == 0 ? null : beforeCmds.toArray(new String[beforeCmds.size()]),
afterCmds.size() == 0 ? null : afterCmds.toArray(new String[afterCmds.size()]), parsedArgs,
converterInfo == null ? getDefaultChildBindingConverter() : converterInfo.expr,
converterInfo == null ? null : converterInfo.args);
} finally {
BinderUtil.popContext();
}
}
private ExpressionAnnoInfo parseConverter(Component comp, String propName) {
final Collection annos = ((ComponentCtrl) comp).getAnnotations(propName, CONVERTER_ANNO);
if (annos.size() == 0)
return null;
if (annos.size() > 1) {
throw new IllegalSyntaxException(
MiscUtil.formatLocationMessage("Allow only one converter for " + propName + " of " + comp, comp));
}
final Annotation ann = annos.iterator().next();
ExpressionAnnoInfo info = new ExpressionAnnoInfo();
Map args = null;
for (final Iterator> it = ann.getAttributes().entrySet().iterator(); it.hasNext();) {
final Entry entry = it.next();
final String tag = entry.getKey();
final String[] tagExpr = entry.getValue();
if ("value".equals(tag)) {
info.expr = AnnotationUtil.testString(tagExpr, ann);
} else { // other unknown tag, keep as arguments
if (args == null) {
args = new HashMap();
}
args.put(tag, tagExpr);
}
}
if (Strings.isBlank(info.expr)) {
throw new IllegalSyntaxException(MiscUtil
.formatLocationMessage("value of converter is empty, check " + propName + " of " + comp, comp));
}
info.args = args == null ? null : BindEvaluatorXUtil.parseArgs(_binder.getEvaluatorX(), args);
return info;
}
private ExpressionAnnoInfo parseValidator(Component comp, String propName) {
final Collection annos = ((ComponentCtrl) comp).getAnnotations(propName, VALIDATOR_ANNO);
if (annos.size() == 0)
return null;
if (annos.size() > 1) {
throw new IllegalSyntaxException(
MiscUtil.formatLocationMessage("Allow only one validator for " + propName + " of " + comp, comp));
}
final Annotation ann = annos.iterator().next();
ExpressionAnnoInfo info = new ExpressionAnnoInfo();
Map args = null;
for (final Iterator> it = ann.getAttributes().entrySet().iterator(); it.hasNext();) {
final Entry entry = it.next();
final String tag = entry.getKey();
final String[] tagExpr = entry.getValue();
if ("value".equals(tag)) {
info.expr = AnnotationUtil.testString(tagExpr, ann);
} else { // other unknown tag, keep as arguments
if (args == null) {
args = new HashMap();
}
args.put(tag, tagExpr);
}
}
if (Strings.isBlank(info.expr)) {
throw new IllegalSyntaxException(MiscUtil
.formatLocationMessage("value of validator is empty, check " + propName + " of " + comp, comp));
}
info.args = args == null ? null : BindEvaluatorXUtil.parseArgs(_binder.getEvaluatorX(), args);
return info;
}
private ExpressionAnnoInfo parseTemplate(Component comp, String propName) {
final Collection annos = ((ComponentCtrl) comp).getAnnotations(propName, TEMPLATE_ANNO);
if (annos.size() == 0)
return null;
if (annos.size() > 1) {
throw new IllegalSyntaxException(
MiscUtil.formatLocationMessage("Allow only one template for " + propName + " of " + comp, comp));
}
final Annotation ann = annos.iterator().next();
ExpressionAnnoInfo info = new ExpressionAnnoInfo();
Map args = null;
for (final Iterator> it = ann.getAttributes().entrySet().iterator(); it.hasNext();) {
final Entry entry = it.next();
final String tag = entry.getKey();
final String[] tagExpr = entry.getValue();
if ("value".equals(tag)) {
info.expr = AnnotationUtil.testString(tagExpr, ann);
} else { // other unknown tag, keep as arguments
if (args == null) {
args = new HashMap();
}
args.put(tag, tagExpr);
}
}
if (Strings.isBlank(info.expr)) {
throw new IllegalSyntaxException(
MiscUtil.formatLocationMessage("Must specify a template for " + propName + " of " + comp, comp));
}
info.args = args == null ? null : BindEvaluatorXUtil.parseArgs(_binder.getEvaluatorX(), args);
return info;
}
private static class ExpressionAnnoInfo {
Map args;
String expr;
}
}