All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.zkoss.bind.impl.AnnotateBinderHelper Maven / Gradle / Ivy

There is a newer version: 10.0.0-jakarta
Show newest version
/* 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.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.zkoss.bind.Binder;
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.zk.ui.Component;
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 {
	final private Binder _binder;
	
	final static private String INIT_ANNO = "init";
	final static private String BIND_ANNO = "bind";
	final static private String LOAD_ANNO = "load";
	final static private String SAVE_ANNO = "save";
	final static private String REFERENCE_ANNO = "ref";
	final static private String ID_ANNO = "id";
	final static private String VALIDATOR_ANNO = "validator";
	final static private String CONVERTER_ANNO = "converter";
	final static private String TEMPLATE_ANNO = "template";
	final static private String COMMAND_ANNO = "command";
	final static private String GLOBAL_COMMAND_ANNO = "global-command";
	
	final static public String FORM_ATTR = "form";
	final static public String VIEW_MODEL_ATTR = "viewModel";
	final static public String BINDER_ATTR = "binder";
	final static public String VALIDATION_MESSAGES_ATTR = "validationMessages";
	final static public String CHILDREN_ATTR = "children";
	
	//control key
	final static public 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();
			processAllComponentsBindings(kid); //recursive to each child
		}
	}
	
	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();
		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 HashMap();
				}
				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.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 HashMap();
				}
				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 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);

		//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)){
				processPropertyPromptBindings(comp,propName,anno,converterInfo,validatorInfo);
			}else if(anno.getName().equals(LOAD_ANNO)){
				processPropertyLoadBindings(comp,propName,anno,converterInfo);
			}else if(anno.getName().equals(SAVE_ANNO)){
				processPropertySaveBindings(comp,propName,anno,converterInfo,validatorInfo);
			}else if(anno.getName().equals(REFERENCE_ANNO)){
				processReferenceBinding(comp,propName,anno);
			}
		}

		ExpressionAnnoInfo templateInfo = parseTemplate(comp,propName);
		if(templateInfo!=null){
			_binder.setTemplate(comp, propName, templateInfo.expr, templateInfo.args);
		}
	}
	
	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){
			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;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy