1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with this 4 * work for additional information regarding copyright ownership. The ASF 5 * licenses this file to You under the Apache License, Version 2.0 (the 6 * "License"); you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law 9 * or agreed to in writing, software distributed under the License is 10 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11 * KIND, either express or implied. See the License for the specific language 12 * governing permissions and limitations under the License. 13 */ 14 package org.apache.webbeans.decorator; 15 16 import java.io.Serializable; 17 import java.lang.annotation.Annotation; 18 import java.lang.reflect.Field; 19 import java.lang.reflect.Method; 20 import java.lang.reflect.Type; 21 import java.util.HashSet; 22 import java.util.Set; 23 24 import javax.decorator.Decorates; 25 import javax.enterprise.context.spi.CreationalContext; 26 import javax.enterprise.inject.spi.Decorator; 27 import javax.enterprise.inject.spi.InjectionPoint; 28 29 import org.apache.webbeans.component.AbstractBean; 30 import org.apache.webbeans.component.ManagedBean; 31 import org.apache.webbeans.component.WebBeansType; 32 import org.apache.webbeans.exception.WebBeansException; 33 import org.apache.webbeans.inject.InjectableField; 34 import org.apache.webbeans.inject.InjectableMethods; 35 import org.apache.webbeans.logger.WebBeansLogger; 36 import org.apache.webbeans.proxy.JavassistProxyFactory; 37 import org.apache.webbeans.util.AnnotationUtil; 38 import org.apache.webbeans.util.ClassUtil; 39 40 /** 41 * Defines decorators. It wraps the bean instance related 42 * with decorator class. Actually, each decorator is an instance 43 * of the {@link ManagedBean}. 44 * 45 * @version $Rev$ $Date$ 46 * 47 * @param <T> decorator type info 48 */ 49 public class WebBeansDecorator<T> extends AbstractBean<T> implements Decorator<T> 50 { 51 private static WebBeansLogger logger = WebBeansLogger.getLogger(WebBeansDecorator.class); 52 53 /** Decorator class */ 54 private Class<?> clazz; 55 56 /** Decorates api types */ 57 private Set<Type> decoratedTypes = new HashSet<Type>(); 58 59 /** Delegate field class type */ 60 protected Type delegateType; 61 62 /** Delegate field bindings */ 63 protected Set<Annotation> delegateBindings = new HashSet<Annotation>(); 64 65 /** Wrapped bean*/ 66 private AbstractBean<T> wrappedBean; 67 68 /**Creational context*/ 69 private CreationalContext<Object> creationalContext; 70 71 /** 72 * Creates a new decorator bean instance with the given wrapped bean. 73 * @param delegateComponent delegate bean instance 74 */ 75 public WebBeansDecorator(AbstractBean<T> wrappedBean) 76 { 77 super(WebBeansType.DECORATOR,wrappedBean.getReturnType()); 78 79 this.wrappedBean = wrappedBean; 80 this.clazz = wrappedBean.getReturnType(); 81 82 init(); 83 } 84 85 protected void init() 86 { 87 ClassUtil.setInterfaceTypeHierarchy(this.decoratedTypes, this.clazz); 88 89 if (this.decoratedTypes.contains(Serializable.class)) 90 { 91 this.decoratedTypes.remove(Serializable.class); 92 } 93 94 initDelegate(); 95 } 96 97 protected void initDelegate() 98 { 99 Field field = ClassUtil.getFieldWithAnnotation(this.clazz, Decorates.class); 100 101 if(field == null) 102 { 103 initDelegateRecursively(this.clazz); 104 } 105 else 106 { 107 initDelegateInternal(field); 108 } 109 } 110 111 private void initDelegateRecursively(Class<?> delegateClazz) 112 { 113 Class<?> superClazz = delegateClazz.getSuperclass(); 114 if(!superClazz.equals(Object.class)) 115 { 116 Field field = ClassUtil.getFieldWithAnnotation(superClazz, Decorates.class); 117 if(field != null) 118 { 119 initDelegateInternal(field); 120 } 121 else 122 { 123 initDelegateRecursively(superClazz); 124 } 125 } 126 } 127 128 private void initDelegateInternal(Field field) 129 { 130 this.delegateType = field.getGenericType(); 131 132 Annotation[] anns = field.getAnnotations(); 133 134 for (Annotation ann : anns) 135 { 136 if (AnnotationUtil.isQualifierAnnotation(ann.annotationType())) 137 { 138 this.delegateBindings.add(ann); 139 } 140 } 141 142 } 143 144 public boolean isDecoratorMatch(Set<Type> apiType, Set<Annotation> annotation) 145 { 146 boolean foundApi = false; 147 for (Type t : apiType) 148 { 149 //TODO Check for generic 150 if (this.delegateType.equals(t)) 151 { 152 foundApi = true; 153 break; 154 } 155 } 156 157 boolean allBindingsOk = false; 158 if (foundApi) 159 { 160 for (Annotation annot : annotation) 161 { 162 boolean bindingOk = false; 163 for (Annotation bindingType : delegateBindings) 164 { 165 if (AnnotationUtil.isAnnotationMemberExist(bindingType.annotationType(), annot, bindingType)) 166 { 167 bindingOk = true; 168 break; 169 } 170 } 171 172 if (bindingOk) 173 { 174 allBindingsOk = true; 175 } 176 else 177 { 178 allBindingsOk = false; 179 break; 180 } 181 } 182 } 183 184 if (!allBindingsOk) 185 { 186 return false; 187 } 188 189 return true; 190 } 191 192 @Override 193 public Set<Annotation> getDelegateBindings() 194 { 195 return delegateBindings; 196 } 197 198 @Override 199 public Type getDelegateType() 200 { 201 return delegateType; 202 } 203 204 public void setDelegate(Object instance, Object delegate) 205 { 206 Field field = ClassUtil.getFieldWithAnnotation(getClazz(), Decorates.class); 207 if (!field.isAccessible()) 208 { 209 field.setAccessible(true); 210 } 211 212 try 213 { 214 field.set(instance, delegate); 215 216 } 217 catch (IllegalArgumentException e) 218 { 219 logger.error("Delegate field is not found on the given decorator class : " + instance.getClass().getName(), e); 220 throw new WebBeansException(e); 221 222 } 223 catch (IllegalAccessException e) 224 { 225 logger.error("Illegal access exception for field " + field.getName() + " in decorator class : " + instance.getClass().getName(), e); 226 } 227 228 } 229 230 231 @SuppressWarnings("unchecked") 232 protected T createInstance(CreationalContext<T> creationalContext) 233 { 234 T proxy = (T)JavassistProxyFactory.createNewProxyInstance(this); 235 236 this.wrappedBean.setCreationalContext(creationalContext); 237 238 return proxy; 239 240 } 241 242 public void setInjections(Object proxy) 243 { 244 // Set injected fields 245 ManagedBean<T> delegate = (ManagedBean<T>) this.wrappedBean; 246 247 Set<Field> injectedFields = delegate.getInjectedFields(); 248 for (Field injectedField : injectedFields) 249 { 250 boolean isDecorates = injectedField.isAnnotationPresent(Decorates.class); 251 252 if (!isDecorates) 253 { 254 InjectableField ife = new InjectableField(injectedField, proxy, this.wrappedBean,this.creationalContext); 255 ife.doInjection(); 256 } 257 } 258 259 Set<Method> injectedMethods = delegate.getInjectedMethods(); 260 for (Method injectedMethod : injectedMethods) 261 { 262 @SuppressWarnings("unchecked") 263 InjectableMethods<?> ife = new InjectableMethods(injectedMethod, proxy, this.wrappedBean,this.creationalContext); 264 ife.doInjection(); 265 } 266 } 267 268 public void destroy(T instance,CreationalContext<T> context) 269 { 270 wrappedBean.destroy(instance,context); 271 } 272 273 @Override 274 public Set<Annotation> getQualifiers() 275 { 276 return wrappedBean.getQualifiers(); 277 } 278 279 @Override 280 public Class<? extends Annotation> getDeploymentType() 281 { 282 return wrappedBean.getDeploymentType(); 283 } 284 285 @Override 286 public String getName() 287 { 288 return wrappedBean.getName(); 289 } 290 291 @Override 292 public Class<? extends Annotation> getScope() 293 { 294 return wrappedBean.getScope(); 295 } 296 297 298 public Set<Type> getTypes() 299 { 300 return wrappedBean.getTypes(); 301 } 302 303 @Override 304 public boolean isNullable() 305 { 306 return wrappedBean.isNullable(); 307 } 308 309 @Override 310 public boolean isSerializable() 311 { 312 return wrappedBean.isSerializable(); 313 } 314 315 /** 316 * @return the delegateComponent 317 */ 318 public AbstractBean<T> getDelegateComponent() 319 { 320 return wrappedBean; 321 } 322 323 public Set<InjectionPoint> getInjectionPoints() 324 { 325 return wrappedBean.getInjectionPoints(); 326 } 327 328 /** 329 * @return the clazz 330 */ 331 public Class<?> getClazz() 332 { 333 return clazz; 334 } 335 336 /* 337 * (non-Javadoc) 338 * @see java.lang.Object#hashCode() 339 */ 340 @Override 341 public int hashCode() 342 { 343 final int prime = 31; 344 int result = 1; 345 result = prime * result + ((clazz == null) ? 0 : clazz.hashCode()); 346 return result; 347 } 348 349 /* 350 * (non-Javadoc) 351 * @see java.lang.Object#equals(java.lang.Object) 352 */ 353 @Override 354 public boolean equals(Object obj) 355 { 356 if (this == obj) 357 return true; 358 if (obj == null) 359 return false; 360 if (getClass() != obj.getClass()) 361 return false; 362 final WebBeansDecorator<?> other = (WebBeansDecorator<?>) obj; 363 if (clazz == null) 364 { 365 if (other.clazz != null) 366 return false; 367 } 368 else if (!clazz.equals(other.clazz)) 369 return false; 370 return true; 371 } 372 373 @Override 374 public Class<?> getBeanClass() 375 { 376 return this.wrappedBean.getBeanClass(); 377 } 378 379 @Override 380 public Set<Class<? extends Annotation>> getStereotypes() 381 { 382 return this.wrappedBean.getStereotypes(); 383 } 384 385 @Override 386 public Set<Type> getDecoratedTypes() { 387 return this.wrappedBean.getTypes(); 388 } 389 390 @Override 391 public boolean isAlternative() 392 { 393 return this.wrappedBean.isAlternative(); 394 } 395 396 397 }