/* PropertyBindingImpl.java Purpose: Description: History: Thu Jul 28 11:59:20 2011, Created by henrichen Copyright (C) 2011 Potix Corporation. All Rights Reserved. */ package org.zkoss.bind.impl; import java.util.Map; import java.util.regex.Pattern; import org.zkoss.bind.BindContext; import org.zkoss.bind.Binder; import org.zkoss.bind.Converter; import org.zkoss.bind.sys.BindEvaluatorX; import org.zkoss.bind.sys.ConditionType; import org.zkoss.bind.sys.PropertyBinding; import org.zkoss.xel.ExpressionX; import org.zkoss.zk.ui.Component; /** * A base implementation of {@link PropertyBinding}. * @author henrichen * @since 6.0.0 */ public abstract class PropertyBindingImpl extends BindingImpl implements PropertyBinding { private static final long serialVersionUID = 1463169907348730644L; protected final ExpressionX _fieldExpr; protected final AccessInfo _accessInfo; private final ExpressionX _converter; private final Map<String, Object> _converterArgs; private String _filedName; private static final Pattern FIELD_COMPILER = Pattern.compile("(?:\\(|\\)|\\[|\\]|\\.)"); /** * @param binder * @param comp * @param fieldName the name of component field (ex, style, value) * @param fieldExpr the EL expression to access component field (ex, self.style, self.value) * @param accessExpr the binding expression , to access the bean * @param conditionType the condition type * @param command the command, if the conditionType is not prompt, then command must not null * @param bindingArgs * @param converterExpr * @param converterArgs */ protected PropertyBindingImpl(Binder binder, Component comp, String fieldName, String fieldExpr, String accessExpr, ConditionType conditionType, String command, Map<String, Object> bindingArgs, String converterExpr, Map<String, Object> converterArgs) { super(binder, comp, bindingArgs); final BindEvaluatorX eval = binder.getEvaluatorX(); final Class<Object> returnType = Object.class; if (!FIELD_COMPILER.matcher(fieldName).find()) { if (fieldExpr.contains("self.")) this._fieldExpr = new PropertyExpression(comp, fieldExpr.substring(5)); else // use old implementation this._fieldExpr = eval.parseExpressionX(null, fieldExpr, returnType); } else { this._fieldExpr = eval.parseExpressionX(null, fieldExpr, returnType); } this._accessInfo = AccessInfo.create(this, accessExpr, returnType, conditionType, command, ignoreTracker()); _converterArgs = converterArgs; _converter = converterExpr == null ? null : parseConverter(eval, converterExpr); _filedName = fieldName; } public Map<String, Object> getConverterArgs() { return _converterArgs; } //should this binding set the ignore tracker attribute when evaluate the expression. protected boolean ignoreTracker() { return false; } private ExpressionX parseConverter(BindEvaluatorX eval, String converterExpr) { final BindContext ctx = BindContextUtil.newBindContext(getBinder(), this, false, null, getComponent(), null); //provide a bindcontext when pare expression of converter with this binding, //do so, the tracker will also tracking the converter dependence with this binding. return eval.parseExpressionX(ctx, converterExpr, Object.class); } public Converter getConverter() { if (_converter == null) return null; final BindContext ctx = BindContextUtil.newBindContext(getBinder(), this, false, null, getComponent(), null); final BindEvaluatorX eval = getBinder().getEvaluatorX(); Object obj = eval.getValue(ctx, getComponent(), _converter); if (obj instanceof Converter) { return (Converter) obj; } else if (obj instanceof String) { return getBinder().getConverter((String) obj); //binder will throw exception if not found } else { throw new ClassCastException( "result of expression '" + _converter.getExpressionString() + "' is not a Converter, is " + obj); } } public String getFieldName() { return _filedName; } public String getCommandName() { return this._accessInfo.getCommandName(); } public String getPropertyString() { return BindEvaluatorXUtil.getExpressionString(_accessInfo.getProperty()); } public ConditionType getConditionType() { return this._accessInfo.getConditionType(); } //F80-ZK-2668: New Build-in Converter - FormattedTimeConverter public ExpressionX getProperty() { return this._accessInfo.getProperty(); } public String toString() { return new StringBuilder().append(getClass().getSimpleName()).append("@") .append(Integer.toHexString(hashCode())).append(",component:").append(getComponent()).append(",field:") .append(getFieldName()).append(",access:").append(getProperty().getExpressionString()) .append(",condition:").append(getConditionType()).append(",command:").append(getCommandName()) .toString(); } }