1 17 18 package javax.el; 19 20 import java.beans.BeanInfo ; 21 import java.beans.FeatureDescriptor ; 22 import java.beans.IntrospectionException ; 23 import java.beans.Introspector ; 24 import java.beans.PropertyDescriptor ; 25 import java.lang.reflect.InvocationTargetException ; 26 import java.lang.reflect.Method ; 27 import java.lang.reflect.Modifier ; 28 import java.util.Arrays ; 29 import java.util.HashMap ; 30 import java.util.Iterator ; 31 import java.util.Map ; 32 import java.util.WeakHashMap ; 33 import java.util.concurrent.ConcurrentHashMap ; 34 35 public class BeanELResolver extends ELResolver { 36 37 private final boolean readOnly; 38 39 private final ConcurrentCache<String , BeanProperties> cache = new ConcurrentCache<String , BeanProperties>( 40 1000); 41 42 public BeanELResolver() { 43 this.readOnly = false; 44 } 45 46 public BeanELResolver(boolean readOnly) { 47 this.readOnly = readOnly; 48 } 49 50 public Object getValue(ELContext context, Object base, Object property) 51 throws NullPointerException , PropertyNotFoundException, ELException { 52 if (context == null) { 53 throw new NullPointerException (); 54 } 55 if (base == null || property == null) { 56 return null; 57 } 58 59 context.setPropertyResolved(true); 60 Method m = this.property(context, base, property).read(context); 61 try { 62 return m.invoke(base, (Object []) null); 63 } catch (IllegalAccessException e) { 64 throw new ELException(e); 65 } catch (InvocationTargetException e) { 66 throw new ELException(message(context, "propertyReadError", 67 new Object [] { base.getClass().getName(), 68 property.toString() }), e.getCause()); 69 } catch (Exception e) { 70 throw new ELException(e); 71 } 72 } 73 74 public Class <?> getType(ELContext context, Object base, Object property) 75 throws NullPointerException , PropertyNotFoundException, ELException { 76 if (context == null) { 77 throw new NullPointerException (); 78 } 79 if (base == null || property == null) { 80 return null; 81 } 82 83 context.setPropertyResolved(true); 84 return this.property(context, base, property).getType(); 85 } 86 87 public void setValue(ELContext context, Object base, Object property, 88 Object value) throws NullPointerException , 89 PropertyNotFoundException, PropertyNotWritableException, 90 ELException { 91 if (context == null) { 92 throw new NullPointerException (); 93 } 94 if (base == null || property == null) { 95 return; 96 } 97 98 context.setPropertyResolved(true); 99 100 if (this.readOnly) { 101 throw new PropertyNotWritableException(message(context, 102 "resolverNotWriteable", new Object [] { base.getClass() 103 .getName() })); 104 } 105 106 Method m = this.property(context, base, property).write(context); 107 try { 108 m.invoke(base, new Object [] { value }); 109 } catch (IllegalAccessException e) { 110 throw new ELException(e); 111 } catch (InvocationTargetException e) { 112 throw new ELException(message(context, "propertyWriteError", 113 new Object [] { base.getClass().getName(), 114 property.toString() }), e.getCause()); 115 } catch (Exception e) { 116 throw new ELException(e); 117 } 118 } 119 120 public boolean isReadOnly(ELContext context, Object base, Object property) 121 throws NullPointerException , PropertyNotFoundException, ELException { 122 if (context == null) { 123 throw new NullPointerException (); 124 } 125 if (base == null || property == null) { 126 return false; 127 } 128 129 context.setPropertyResolved(true); 130 return this.readOnly 131 || this.property(context, base, property).isReadOnly(); 132 } 133 134 public Iterator <FeatureDescriptor > getFeatureDescriptors(ELContext context, Object base) { 135 if (context == null) { 136 throw new NullPointerException (); 137 } 138 139 if (base == null) { 140 return null; 141 } 142 143 try { 144 BeanInfo info = Introspector.getBeanInfo(base.getClass()); 145 PropertyDescriptor [] pds = info.getPropertyDescriptors(); 146 for (int i = 0; i < pds.length; i++) { 147 pds[i].setValue(RESOLVABLE_AT_DESIGN_TIME, Boolean.TRUE); 148 pds[i].setValue(TYPE, pds[i].getPropertyType()); 149 } 150 return Arrays.asList((FeatureDescriptor []) pds).iterator(); 151 } catch (IntrospectionException e) { 152 } 154 155 return null; 156 } 157 158 public Class <?> getCommonPropertyType(ELContext context, Object base) { 159 if (context == null) { 160 throw new NullPointerException (); 161 } 162 163 if (base != null) { 164 return Object .class; 165 } 166 167 return null; 168 } 169 170 protected final static class BeanProperties { 171 private final Map <String , BeanProperty> properties; 172 173 private final Class <?> type; 174 175 public BeanProperties(Class <?> type) throws ELException { 176 this.type = type; 177 this.properties = new HashMap <String , BeanProperty>(); 178 try { 179 BeanInfo info = Introspector.getBeanInfo(this.type); 180 PropertyDescriptor [] pds = info.getPropertyDescriptors(); 181 for (int i = 0; i < pds.length; i++) { 182 this.properties.put(pds[i].getName(), new BeanProperty( 183 type, pds[i])); 184 } 185 } catch (IntrospectionException ie) { 186 throw new ELException(ie); 187 } 188 } 189 190 public BeanProperty get(ELContext ctx, String name) { 191 BeanProperty property = this.properties.get(name); 192 if (property == null) { 193 throw new PropertyNotFoundException(message(ctx, 194 "propertyNotFound", 195 new Object [] { type.getName(), name })); 196 } 197 return property; 198 } 199 200 public Class <?> getType() { 201 return type; 202 } 203 } 204 205 protected final static class BeanProperty { 206 private final Class type; 207 208 private final Class owner; 209 210 private final PropertyDescriptor descriptor; 211 212 private Method read; 213 214 private Method write; 215 216 public BeanProperty(Class owner, PropertyDescriptor descriptor) { 217 this.owner = owner; 218 this.descriptor = descriptor; 219 this.type = descriptor.getPropertyType(); 220 } 221 222 public Class <?> getType() { 223 return this.type; 224 } 225 226 public boolean isReadOnly() { 227 return this.write == null 228 && (null == (this.write = getMethod(this.owner, descriptor.getWriteMethod()))); 229 } 230 231 public Method write(ELContext ctx) { 232 if (this.write == null) { 233 this.write = getMethod(this.owner, descriptor.getWriteMethod()); 234 if (this.write == null) { 235 throw new PropertyNotFoundException(message(ctx, 236 "propertyNotWritable", new Object [] { 237 type.getName(), descriptor.getName() })); 238 } 239 } 240 return this.write; 241 } 242 243 public Method read(ELContext ctx) { 244 if (this.read == null) { 245 this.read = getMethod(this.owner, descriptor.getReadMethod()); 246 if (this.read == null) { 247 throw new PropertyNotFoundException(message(ctx, 248 "propertyNotReadable", new Object [] { 249 type.getName(), descriptor.getName() })); 250 } 251 } 252 return this.read; 253 } 254 } 255 256 private final BeanProperty property(ELContext ctx, Object base, 257 Object property) { 258 Class <?> type = base.getClass(); 259 String prop = property.toString(); 260 261 BeanProperties props = this.cache.get(type.getName()); 262 if (props == null || type != props.getType()) { 263 props = new BeanProperties(type); 264 this.cache.put(type.getName(), props); 265 } 266 267 return props.get(ctx, prop); 268 } 269 270 private final static Method getMethod(Class type, Method m) { 271 if (m == null || Modifier.isPublic(type.getModifiers())) { 272 return m; 273 } 274 Class [] inf = type.getInterfaces(); 275 Method mp = null; 276 for (int i = 0; i < inf.length; i++) { 277 try { 278 mp = inf[i].getMethod(m.getName(), (Class []) m.getParameterTypes()); 279 mp = getMethod(mp.getDeclaringClass(), mp); 280 if (mp != null) { 281 return mp; 282 } 283 } catch (NoSuchMethodException e) { 284 } 285 } 286 Class sup = type.getSuperclass(); 287 if (sup != null) { 288 try { 289 mp = sup.getMethod(m.getName(), (Class []) m.getParameterTypes()); 290 mp = getMethod(mp.getDeclaringClass(), mp); 291 if (mp != null) { 292 return mp; 293 } 294 } catch (NoSuchMethodException e) { 295 } 296 } 297 return null; 298 } 299 300 private final static class ConcurrentCache<K,V> { 301 302 private final int size; 303 private final Map <K,V> eden; 304 private final Map <K,V> longterm; 305 306 public ConcurrentCache(int size) { 307 this.size = size; 308 this.eden = new ConcurrentHashMap <K,V>(size); 309 this.longterm = new WeakHashMap <K,V>(size); 310 } 311 312 public V get(K key) { 313 V value = this.eden.get(key); 314 if (value == null) { 315 value = this.longterm.get(key); 316 if (value != null) { 317 this.eden.put(key, value); 318 } 319 } 320 return value; 321 } 322 323 public void put(K key, V value) { 324 if (this.eden.size() >= this.size) { 325 this.longterm.putAll(this.eden); 326 this.eden.clear(); 327 } 328 this.eden.put(key, value); 329 } 330 331 } 332 } 333 | Popular Tags |