/* * JBoss, Home of Professional Open Source * Copyright 2008, Red Hat, Inc., and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jboss.weld.util; import java.io.Serializable; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.enterprise.context.spi.CreationalContext; import javax.enterprise.inject.spi.AnnotatedMethod; import javax.enterprise.inject.spi.AnnotatedType; import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.Decorator; import javax.enterprise.inject.spi.InjectionPoint; import javax.enterprise.inject.spi.PassivationCapable; import org.jboss.weld.annotated.enhanced.EnhancedAnnotatedMethod; import org.jboss.weld.annotated.enhanced.EnhancedAnnotatedType; import org.jboss.weld.annotated.enhanced.MethodSignature; import org.jboss.weld.annotated.runtime.InvokableAnnotatedMethod; import org.jboss.weld.bean.CustomDecoratorWrapper; import org.jboss.weld.bean.DecoratorImpl; import org.jboss.weld.bean.WeldDecorator; import org.jboss.weld.bean.proxy.DecorationHelper; import org.jboss.weld.bean.proxy.TargetBeanInstance; import org.jboss.weld.exceptions.DefinitionException; import org.jboss.weld.exceptions.WeldException; import org.jboss.weld.injection.attributes.WeldInjectionPointAttributes; import org.jboss.weld.logging.BeanLogger; import org.jboss.weld.manager.BeanManagerImpl; import org.jboss.weld.resources.ClassTransformer; import org.jboss.weld.serialization.spi.ContextualStore; import org.jboss.weld.util.collections.ImmutableSet; import org.jboss.weld.util.reflection.Formats; import org.jboss.weld.util.reflection.HierarchyDiscovery; import org.jboss.weld.util.reflection.Reflections; /** * Helper class for {@link javax.enterprise.inject.spi.Decorator} inspections. * * @author Marius Bogoevici */ public class Decorators { private Decorators() { } /** * Determines the set of {@link InvokableAnnotatedMethod}s representing decorated methods of the specified decorator. A decorated method * is any method declared by a decorated type which is implemented by the decorator. * * @param beanManager the bean manager * @param decorator the specified decorator * @return the set of {@link InvokableAnnotatedMethod}s representing decorated methods of the specified decorator */ public static Set<InvokableAnnotatedMethod<?>> getDecoratorMethods(BeanManagerImpl beanManager, WeldDecorator<?> decorator) { ImmutableSet.Builder<InvokableAnnotatedMethod<?>> builder = ImmutableSet.builder(); for (Type type : decorator.getDecoratedTypes()) { EnhancedAnnotatedType<?> weldClass = getEnhancedAnnotatedTypeOfDecoratedType(beanManager, type); for (EnhancedAnnotatedMethod<?, ?> method : weldClass.getDeclaredEnhancedMethods()) { if (decorator.getEnhancedAnnotated().getEnhancedMethod(method.getSignature()) != null) { builder.add(InvokableAnnotatedMethod.of(method.slim())); } } } return builder.build(); } private static EnhancedAnnotatedType<?> getEnhancedAnnotatedTypeOfDecoratedType(BeanManagerImpl beanManager, Type type) { if (type instanceof Class<?>) { return beanManager.createEnhancedAnnotatedType((Class<?>) type); } if (type instanceof ParameterizedType && (((ParameterizedType) type).getRawType() instanceof Class)) { return beanManager.createEnhancedAnnotatedType((Class<?>) ((ParameterizedType) type).getRawType()); } throw BeanLogger.LOG.unableToProcessDecoratedType(type); } public static WeldInjectionPointAttributes<?, ?> findDelegateInjectionPoint(AnnotatedType<?> type, Iterable<InjectionPoint> injectionPoints) { WeldInjectionPointAttributes<?, ?> result = null; for (InjectionPoint injectionPoint : injectionPoints) { if (injectionPoint.isDelegate()) { if (result != null) { throw BeanLogger.LOG.tooManyDelegateInjectionPoints(type); } result = InjectionPoints.getWeldInjectionPoint(injectionPoint); } } if (result == null) { throw BeanLogger.LOG.noDelegateInjectionPoint(type); } return result; } public static <T> T getOuterDelegate(Bean<T> bean, T instance, CreationalContext<T> creationalContext, Class<T> proxyClass, InjectionPoint originalInjectionPoint, BeanManagerImpl manager, List<Decorator<?>> decorators) { TargetBeanInstance beanInstance = new TargetBeanInstance(bean, instance); DecorationHelper<T> decorationHelper = new DecorationHelper<T>(beanInstance, bean, proxyClass, manager, manager.getServices().get(ContextualStore.class), decorators); DecorationHelper.push(decorationHelper); try { final T outerDelegate = decorationHelper.getNextDelegate(originalInjectionPoint, creationalContext); if (outerDelegate == null) { throw new WeldException(BeanLogger.LOG.proxyInstantiationFailed(bean)); } return outerDelegate; } finally { DecorationHelper.pop(); } } /** * Check whether the delegate type implements or extends all decorated types. * * @param decorator * @throws DefinitionException If the delegate type doesn't implement or extend all decorated types */ public static void checkDelegateType(Decorator<?> decorator) { Set<Type> types = new HierarchyDiscovery(decorator.getDelegateType()).getTypeClosure(); for (Type decoratedType : decorator.getDecoratedTypes()) { if(!types.contains(decoratedType)) { throw BeanLogger.LOG.delegateMustSupportEveryDecoratedType(decoratedType, decorator); } } } /** * Check all abstract methods are declared by the decorated types. * * @param type * @param beanManager * @param delegateType * @throws DefinitionException If any of the abstract methods is not declared by the decorated types */ public static <T> void checkAbstractMethods(Set<Type> decoratedTypes, EnhancedAnnotatedType<T> type, BeanManagerImpl beanManager) { if (decoratedTypes == null) { decoratedTypes = new HashSet<Type>(type.getInterfaceClosure()); decoratedTypes.remove(Serializable.class); } Set<MethodSignature> signatures = new HashSet<MethodSignature>(); for (Type decoratedType : decoratedTypes) { for (EnhancedAnnotatedMethod<?, ?> method : ClassTransformer.instance(beanManager) .getEnhancedAnnotatedType(Reflections.getRawType(decoratedType), beanManager.getId()).getEnhancedMethods()) { signatures.add(method.getSignature()); } } for (EnhancedAnnotatedMethod<?, ?> method : type.getEnhancedMethods()) { if (Reflections.isAbstract(((AnnotatedMethod<?>) method).getJavaMember())) { MethodSignature methodSignature = method.getSignature(); if (!signatures.contains(methodSignature)) { throw BeanLogger.LOG.abstractMethodMustMatchDecoratedType(method, Formats.formatAsStackTraceElement(method.getJavaMember())); } } } } /** * Indicates whether a {@link Decorator} is passivation capable or not. * @return */ public static boolean isPassivationCapable(Decorator<?> decorator) { if (decorator instanceof CustomDecoratorWrapper<?>) { // unwrap decorator = Reflections.<CustomDecoratorWrapper<?>>cast(decorator).delegate(); } if (decorator instanceof DecoratorImpl<?>) { DecoratorImpl<?> weldDecorator = (DecoratorImpl<?>) decorator; return weldDecorator.getEnhancedAnnotated().isSerializable(); } return decorator instanceof PassivationCapable; } }