/* * Copyright open knowledge GmbH * * 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 de.openknowledge.cdi.scope; import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.enterprise.inject.Any; import javax.enterprise.inject.Instance; import javax.inject.Inject; import javax.interceptor.InvocationContext; import de.openknowledge.cdi.common.spi.CorrespondingLiteral; /** * Abstract class with the begin/end interceptors. Provides methods to receive the scope. * * @author Arne Limburg - open knowledge GmbH (arne.limburg@openknowledge.de) */ public abstract class AbstractScopeInterceptor<A extends Annotation> implements Serializable { @Inject @Any private Instance<DestroyableContext> destroyableContexts; private Class<A> annotationType; protected AbstractScopeInterceptor() { // we try to find the concrete class of the generic "A" Type actualType = getParameterizedType(); this.annotationType = getActualClass(actualType); } @SuppressWarnings("unchecked") private Class<A> getActualClass(Type actualType) { if (!(actualType instanceof Class)) { throw new IllegalStateException("Generic type argument of " + AbstractScopeInterceptor.class.getName() + " must be actual class"); } return (Class<A>) actualType; } private Type getParameterizedType() { Type abstractScopeInterceptorType = getAbstractScopeInterceptorType(); if (!(abstractScopeInterceptorType instanceof ParameterizedType)) { throw new IllegalStateException(AbstractScopeInterceptor.class + " must be instantiated with generic type argument"); } Type actualType = ((ParameterizedType) abstractScopeInterceptorType).getActualTypeArguments()[0]; return actualType; } private Type getAbstractScopeInterceptorType() { return getAbstractScopeInterceptorType(getClass()); } private Type getAbstractScopeInterceptorType(Class<?> superClass) { if (AbstractScopeInterceptor.class.equals(superClass.getSuperclass())) { return superClass.getGenericSuperclass(); } throw new IllegalStateException(AbstractScopeInterceptor.class.getName() + " not found in type-hierarchy"); } protected void destroyContexts(InvocationContext context) { for (Class<? extends Annotation> scope : getScopes(context)) { DestroyableContext destroyableContext = this.destroyableContexts.select(new CorrespondingLiteral(scope)).get(); destroyableContext.destroy(context.getTarget()); } } protected Set<Class<? extends Annotation>> getScopes(InvocationContext context) { Set<Class<? extends Annotation>> scopes = new HashSet<Class<? extends Annotation>>(); if (context.getMethod() != null) { scopes.addAll(getScopes(context.getMethod())); } else { for (Method method : context.getTarget().getClass().getMethods()) { scopes.addAll(getScopes(method)); } } if (context.getTarget() != null) { scopes.addAll(getScopes(context.getTarget().getClass())); } if (scopes.isEmpty()) { throw new IllegalStateException(this.annotationType.getName() + " annotation not found"); } return scopes; } protected Set<Class<? extends Annotation>> getScopes(Method method) { A annotation = method.getAnnotation(this.annotationType); return annotation != null ? new HashSet<Class<? extends Annotation>>(getValue(annotation)) : Collections .<Class<? extends Annotation>>emptySet(); } protected Set<Class<? extends Annotation>> getScopes(Class<?> targetClass) { if (targetClass == null) { return Collections.emptySet(); } A annotation = targetClass.getAnnotation(this.annotationType); if (annotation != null) { return new HashSet<Class<? extends Annotation>>(getValue(annotation)); } return getScopes(targetClass.getSuperclass()); } protected abstract List<Class<? extends Annotation>> getValue(A annotation); }