/* XelELResolver.java Purpose: Description: History: Wed Jul 20 14:53:14 2011, Created by henrichen Copyright (C) 2011 Potix Corporation. All Rights Reserved. {{IS_RIGHT }}IS_RIGHT */ package org.zkoss.xel.zel; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.zkoss.xel.VariableResolver; import org.zkoss.xel.VariableResolverX; import org.zkoss.xel.XelContext; import org.zkoss.zel.ArrayELResolver; import org.zkoss.zel.BeanELResolver; import org.zkoss.zel.BeanNameELResolver; import org.zkoss.zel.BeanNameResolver; import org.zkoss.zel.CompositeELResolver; import org.zkoss.zel.ELContext; import org.zkoss.zel.ELException; import org.zkoss.zel.ELResolver; import org.zkoss.zel.ListELResolver; import org.zkoss.zel.MapELResolver; import org.zkoss.zel.MethodNotFoundException; import org.zkoss.zel.PropertyNotFoundException; import org.zkoss.zel.PropertyNotWritableException; import org.zkoss.zel.ResourceBundleELResolver; import org.zkoss.zel.StaticFieldELResolver; import org.zkoss.zel.impl.stream.StreamELResolverImpl; /** * An XEL implementation of ZEL ELResolver. * * @since 6.0.0 */ public class XelELResolver extends ELResolver { private static final CompositeELResolver DEFAULT; private final static Map<String, Object> localBeans = new HashMap<String, Object>(); private static final Class REFERENCE_BINDING; private static final Method GET_VALUE; static { DEFAULT = new CompositeELResolver(); //add resolver in order to support EL 3.0 DEFAULT.add(new BeanNameELResolver( new StandardBeanNameResolver(localBeans))); // for semicolon expression DEFAULT.add(new StreamELResolverImpl()); // for stream operations DEFAULT.add(new StaticFieldELResolver()); //for calling static method DEFAULT.add(new MapELResolver()); DEFAULT.add(new ResourceBundleELResolver()); DEFAULT.add(new ListELResolver()); DEFAULT.add(new ArrayELResolver()); DEFAULT.add(new BeanELResolver()); // Bug ZK-3021 Class tempCls = null; Method tempMethod = null; try { tempCls = XelELResolver.class.getClassLoader().loadClass("org.zkoss.bind.sys.ReferenceBinding"); Class temp1 = XelELResolver.class.getClassLoader().loadClass("org.zkoss.bind.xel.zel.BindELContext"); tempMethod = tempCls.getDeclaredMethod("getValue", temp1); } catch (ClassNotFoundException e) { } catch (NoSuchMethodException e) { } REFERENCE_BINDING = tempCls; GET_VALUE = tempMethod; } protected final XelContext _ctx; /** Constructor. */ public XelELResolver(XelContext ctx) { _ctx = ctx; } protected ELResolver getELResolver() { return DEFAULT; } protected XelContext getXelContext() { return _ctx; } //ELResolver// public Object getValue(ELContext ctx, Object base, Object property) throws PropertyNotFoundException, ELException { if (ctx == null) throw new IllegalArgumentException(); final Object o = getELResolver().getValue(ctx, base, property); return ctx.isPropertyResolved() ? o : resolve(ctx, base, property); } protected Object resolve(ELContext ctx, Object base, Object property) { VariableResolver resolver = _ctx.getVariableResolver(); if (resolver != null) { if (resolver instanceof VariableResolverX) { final Object o = ((VariableResolverX)resolver) .resolveVariable(_ctx, base, property); //in order to call static method, we can't set property as resolved if (o != null) ctx.setPropertyResolved(true); // Bug ZK-3021 if (REFERENCE_BINDING != null && o != null) { if (REFERENCE_BINDING.isAssignableFrom(o.getClass())) { try { return GET_VALUE.invoke(o, new Object[]{null}); } catch (Exception e) { // do nothing. } } } return o; } else if (base == null && property != null) { final Object o = resolver.resolveVariable(property.toString()); //in order to call static method, we can't set property as resolved if (o != null) ctx.setPropertyResolved(true); return o; } } return null; } public Class<?> getType(ELContext ctx, Object base, Object property) throws PropertyNotFoundException, ELException { if (ctx == null) throw new IllegalArgumentException(); final Class<?> type = getELResolver().getType(ctx, base, property); if (ctx.isPropertyResolved()) { return type; } final Object o = resolve(ctx, base, property); //might change isPropertyResolved return o != null ? o.getClass() : null; } public void setValue(ELContext ctx, Object base, Object property, Object value) throws PropertyNotFoundException, PropertyNotWritableException, ELException { if (ctx == null) { throw new IllegalArgumentException(); } if (base == null) { //some situation occurs here, //we should pass them to the following resolver rather than throw exception } getELResolver().setValue(ctx, base, property, value); } public boolean isReadOnly(ELContext ctx, Object base, Object property) throws PropertyNotFoundException, ELException { if (ctx == null) throw new IllegalArgumentException(); if (base == null) { ctx.setPropertyResolved(true); return true; } return getELResolver().isReadOnly(ctx, base, property); } public Iterator<java.beans.FeatureDescriptor> getFeatureDescriptors(ELContext ctx, Object base) { return getELResolver().getFeatureDescriptors(ctx, base); } public Class getCommonPropertyType(ELContext ctx, Object base) { return base == null ? String.class: getELResolver().getCommonPropertyType(ctx, base); } public Object invoke(ELContext ctx, Object base, Object method, Class[] paramTypes, Object[] params) throws MethodNotFoundException { if (ctx == null) throw new IllegalArgumentException(); if (base == null) { ctx.setPropertyResolved(true); throw new MethodNotFoundException(); } return getELResolver().invoke(ctx, base, method, paramTypes, params); } /** * It's a class copied from StandardELContext * @author Chunfu * */ public static class StandardBeanNameResolver extends BeanNameResolver { private final Map<String,Object> beans; public StandardBeanNameResolver(Map<String,Object> beans) { this.beans = beans; } public boolean isNameResolved(String beanName) { return beans.containsKey(beanName); } public Object getBean(String beanName) { return beans.get(beanName); } public void setBeanValue(String beanName, Object value) throws PropertyNotWritableException { beans.put(beanName, value); } public boolean isReadOnly(String beanName) { return false; } public boolean canCreateBean(String beanName) { return true; } } }