com.caucho.config.gen.InterceptorFactory Maven / Gradle / Ivy
/*
* Copyright (c) 1998-2018 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.config.gen;
import static javax.enterprise.inject.spi.InterceptionType.AROUND_INVOKE;
import static javax.enterprise.inject.spi.InterceptionType.POST_CONSTRUCT;
import static javax.enterprise.inject.spi.InterceptionType.PRE_DESTROY;
import java.io.IOException;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.decorator.Delegate;
import javax.ejb.Stateful;
import javax.enterprise.inject.Stereotype;
import javax.enterprise.inject.spi.AnnotatedField;
import javax.enterprise.inject.spi.AnnotatedMethod;
import javax.enterprise.inject.spi.AnnotatedParameter;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Decorator;
import javax.enterprise.inject.spi.InterceptionType;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Qualifier;
import javax.interceptor.AroundInvoke;
import javax.interceptor.ExcludeClassInterceptors;
import javax.interceptor.ExcludeDefaultInterceptors;
import javax.interceptor.InterceptorBinding;
import javax.interceptor.Interceptors;
import javax.interceptor.InvocationContext;
import com.caucho.config.ConfigException;
import com.caucho.config.inject.AnnotatedOverrideMap;
import com.caucho.config.inject.AnyLiteral;
import com.caucho.config.inject.DefaultLiteral;
import com.caucho.config.inject.InjectManager;
import com.caucho.config.reflect.AnnotatedTypeImpl;
import com.caucho.config.reflect.AnnotatedTypeUtil;
import com.caucho.config.reflect.BaseType;
import com.caucho.inject.Module;
import com.caucho.java.JavaWriter;
import com.caucho.util.L10N;
/**
* Represents the interception
*/
@Module
public class InterceptorFactory
extends AbstractAspectFactory
{
private static final L10N L = new L10N(InterceptorFactory.class);
private InjectManager _manager;
private boolean _isInterceptorOrDecorator;
/*
private ArrayList> _classInterceptors
= new ArrayList>();
private ArrayList> _defaultInterceptors
= new ArrayList>();
private ArrayList> _selfInterceptors
= new ArrayList>();
*/
private HashMap, ClassInterceptors> _interceptorMap
= new HashMap, ClassInterceptors>();
private ClassInterceptors _selfInterceptors;
private HashMap, Annotation> _classInterceptorBindings;
private HashSet> _decoratorClasses;
private boolean _isExcludeClassInterceptors;
private boolean _isExcludeDefaultInterceptors;
private boolean _isPassivating;
private boolean _isStateful;
public InterceptorFactory(AspectBeanFactory beanFactory,
AspectFactory next,
InjectManager manager)
{
super(beanFactory, next);
// ejb/0i5c
if (manager.isChildManager())
manager = manager.getParent();
_manager = manager;
introspectType();
}
public HashMap, Annotation>
getClassInterceptorBindings()
{
return _classInterceptorBindings;
}
public HashSet> getDecoratorClasses()
{
return _decoratorClasses;
}
public boolean isPassivating()
{
return _isPassivating;
}
public boolean isStateful()
{
return _isStateful || getBeanType().isAnnotationPresent(Stateful.class);
}
public boolean isSelfInterceptor()
{
return _selfInterceptors.getSelfInterceptors() != null;
// return _selfInterceptors.size() > 0;
}
/**
* Creates an aspect for interception if the method should be intercepted.
*/
@Override
public AspectGenerator create(AnnotatedMethod super X> method,
boolean isEnhanced)
{
if (_isInterceptorOrDecorator)
return super.create(method, isEnhanced);
boolean isPrivate
= Modifier.isPrivate(method.getJavaMember().getModifiers());
boolean isLifecycle
= method.isAnnotationPresent(PostConstruct.class);
AnnotatedType> beanType;
// XXX: interceptor/singleton/business/annotated
// packaging/war/mbean/interceptor/lifecycle
/*
if (isPrivate)
beanType = method.getDeclaringType();
else
beanType = getBeanType();
*/
/*
if (isLifecycle)
beanType = method.getDeclaringType();
else
beanType = getBeanType();
*/
beanType = getBeanType();
// beanType = method.getDeclaringType();
// beanType = getBeanType();
boolean isExcludeClassInterceptors = false;
if (method.isAnnotationPresent(ExcludeClassInterceptors.class)
|| beanType.isAnnotationPresent(ExcludeClassInterceptors.class)) {
isExcludeClassInterceptors = true;
}
boolean isExcludeDefaultInterceptors = false;
if (method.isAnnotationPresent(ExcludeDefaultInterceptors.class)
|| beanType.isAnnotationPresent(ExcludeDefaultInterceptors.class)) {
isExcludeDefaultInterceptors = true;
}
HashSet> methodInterceptors = null;
InterceptionType type = InterceptionType.AROUND_INVOKE;
Class extends Annotation> annType = AroundInvoke.class;
if (method.isAnnotationPresent(PostConstruct.class)){
type = InterceptionType.POST_CONSTRUCT;
annType = PostConstruct.class;
}
else if (method.isAnnotationPresent(PreDestroy.class)){
type = InterceptionType.PRE_DESTROY;
annType = PreDestroy.class;
}
// ejb/0cb3, ejb/1060
ClassInterceptors typeInterceptors = getTypeInterceptors(beanType);
//ClassInterceptors typeInterceptors = getTypeInterceptors(method.getDeclaringType());
if (! isExcludeDefaultInterceptors) {
methodInterceptors = addInterceptors(methodInterceptors,
typeInterceptors.getDefaultInterceptors(),
annType);
}
if (! isExcludeClassInterceptors) {
methodInterceptors = addInterceptors(methodInterceptors,
typeInterceptors.getClassInterceptors(),
annType);
}
Interceptors interceptorsAnn = method.getAnnotation(Interceptors.class);
boolean isMethodInterceptor = false;
if (interceptorsAnn != null) {
for (Class> iClass : interceptorsAnn.value()) {
if (! hasAroundInvoke(iClass)) {
continue;
}
isMethodInterceptor = true;
if (methodInterceptors == null)
methodInterceptors = new LinkedHashSet>();
methodInterceptors.add(iClass);
}
}
methodInterceptors = addInterceptors(methodInterceptors,
typeInterceptors.getSelfInterceptors(),
annType);
HashMap, Annotation> interceptorMap = null;
interceptorMap = addInterceptorBindings(interceptorMap,
method.getAnnotations());
HashSet> decoratorSet = introspectDecorators(method);
if (method.isAnnotationPresent(Inject.class)
|| method.isAnnotationPresent(PostConstruct.class)) {
if (isMethodInterceptor || interceptorMap != null) {
throw new ConfigException(L.l("{0}.{1} is invalid because it's annotated with @Inject or @PostConstruct but also has interceptor bindings",
method.getJavaMember().getDeclaringClass().getName(),
method.getJavaMember().getName()));
}
}
if (method.isAnnotationPresent(Inject.class)) {
// ioc/0c57, ejb/60b0
return super.create(method, isEnhanced);
}
if (isExcludeClassInterceptors || _classInterceptorBindings == null) {
}
else if (interceptorMap != null) {
interceptorMap.putAll(_classInterceptorBindings);
}
else {
interceptorMap = _classInterceptorBindings;
}
if (methodInterceptors != null
|| interceptorMap != null
// || _selfInterceptors.size() > 0
|| decoratorSet != null) {
AspectGenerator next = super.create(method, true);
return new InterceptorGenerator(this, method, next,
type,
methodInterceptors,
interceptorMap,
decoratorSet,
isExcludeClassInterceptors);
}
else
return super.create(method, isEnhanced);
}
private boolean hasAroundInvoke(Class> cl)
{
if (cl == null)
return false;
for (Method m : cl.getDeclaredMethods()) {
if (m.isAnnotationPresent(AroundInvoke.class))
return true;
}
return hasAroundInvoke(cl.getSuperclass());
}
@Override
public void generateInject(JavaWriter out, HashMap map)
throws IOException
{
super.generateInject(out, map);
if (_isInterceptorOrDecorator)
return;
if (isEnhanced()) {
generateInject(out, map, POST_CONSTRUCT, PostConstruct.class);
generateInject(out, map, AROUND_INVOKE, AroundInvoke.class);
generateInject(out, map, PRE_DESTROY, PreDestroy.class);
}
}
private void generateInject(JavaWriter out,
HashMap map,
InterceptionType type,
Class extends Annotation> annType)
throws IOException
{
HashSet> interceptors = null;
interceptors = addInterceptors(interceptors,
_selfInterceptors.getClassInterceptors(),
annType);
interceptors = addInterceptors(interceptors,
_selfInterceptors.getDefaultInterceptors(),
annType);
interceptors = addInterceptors(interceptors,
_selfInterceptors.getSelfInterceptors(),
annType);
if (interceptors != null) {
InterceptorGenerator gen
= new InterceptorGenerator(this, interceptors, type);
gen.generateInject(out, map);
}
}
@Override
public void generatePostConstruct(JavaWriter out, HashMap map)
throws IOException
{
if (! _isInterceptorOrDecorator && isEnhanced()) {
HashSet> set = null;
/*
set = addInterceptors(set,
_selfInterceptors.getClassInterceptors(),
PostConstruct.class);
set = addInterceptors(set,
_selfInterceptors.getDefaultInterceptors(),
PostConstruct.class);
*/
set = addInterceptors(set,
_selfInterceptors.getClassInterceptors(),
AroundInvoke.class);
set = addInterceptors(set,
_selfInterceptors.getDefaultInterceptors(),
AroundInvoke.class);
if (set != null) {
/*
InterceptorGenerator gen
= new InterceptorGenerator(this,
set,
InterceptionType.POST_CONSTRUCT);
*/
InterceptorGenerator gen
= new InterceptorGenerator(this,
set,
InterceptionType.AROUND_INVOKE);
gen.generateClassPostConstruct(out, map);
return;
}
}
super.generatePostConstruct(out, map);
}
@Override
public void generatePreDestroy(JavaWriter out, HashMap map)
throws IOException
{
super.generatePreDestroy(out, map);
if (_isInterceptorOrDecorator)
return;
if (isEnhanced()) {
HashSet> set = null;
set = addInterceptors(set,
_selfInterceptors.getClassInterceptors(),
PreDestroy.class);
// ioc/055b
if (set != null || _classInterceptorBindings != null) {
InterceptorGenerator gen
= new InterceptorGenerator(this,
set,
InterceptionType.PRE_DESTROY);
gen.generateClassPreDestroy(out, map);
}
}
}
@Override
public void generateEpilogue(JavaWriter out, HashMap map)
throws IOException
{
super.generateEpilogue(out, map);
if (_isInterceptorOrDecorator)
return;
if (isEnhanced()) {
//generateEpilogue(out, map, POST_CONSTRUCT, PostConstruct.class);
generateEpilogue(out, map, AROUND_INVOKE, AroundInvoke.class);
generateEpilogue(out, map, PRE_DESTROY, PreDestroy.class);
}
}
private void generateEpilogue(JavaWriter out,
HashMap map,
InterceptionType type,
Class extends Annotation> annType)
throws IOException
{
HashSet> interceptors = new LinkedHashSet>();
interceptors = addInterceptors(interceptors,
_selfInterceptors.getClassInterceptors(),
annType);
interceptors = addInterceptors(interceptors,
_selfInterceptors.getDefaultInterceptors(),
annType);
interceptors = addInterceptors(interceptors,
_selfInterceptors.getSelfInterceptors(),
annType);
InterceptorGenerator gen
= new InterceptorGenerator(this, interceptors, type);
gen.generateEpilogue(out, map);
}
@Override
public boolean isEnhanced()
{
if (_isInterceptorOrDecorator)
return false;
else if (_selfInterceptors.getClassInterceptors() != null)
return true;
else if (_selfInterceptors.getSelfInterceptors() != null)
return true;
else if (_classInterceptorBindings != null)
return true;
else
return super.isEnhanced();
}
private boolean isInterceptorPresentRec(Class> cl)
{
if (cl == null)
return false;
else if (isInterceptorPresent(cl))
return true;
else
return isInterceptorPresentRec(cl.getSuperclass());
}
private boolean isInterceptorPresent(Class> cl)
{
for (Method m : cl.getDeclaredMethods()) {
Class> []param = m.getParameterTypes();
if (param.length == 1 && param[0].equals(InvocationContext.class))
return true;
// if (m.isAnnotationPresent(annType))
}
return false;
}
private HashSet>
addInterceptors(HashSet> set,
ArrayList> sourceList,
Class extends Annotation> annType)
{
if (sourceList == null)
return set;
for (Class> cl : sourceList) {
set = addInterceptor(set, cl, cl, annType);
}
return set;
}
private HashSet>
addInterceptor(HashSet> set,
Class> cl,
Class> subClass,
Class extends Annotation> annType)
{
if (subClass == null || subClass == Object.class)
return set;
for (Method m : subClass.getDeclaredMethods()) {
if (Modifier.isAbstract(m.getModifiers()))
continue;
Class> []param = m.getParameterTypes();
if (param.length != 1 || ! param[0].equals(InvocationContext.class))
continue;
if (! isAnnotationPresent(m, annType))
continue;
if (set == null)
set = new LinkedHashSet>();
set.add(cl);
return set;
}
return addInterceptor(set, cl, subClass.getSuperclass(), annType);
}
private boolean isAnnotationPresent(Method m,
Class extends Annotation> annType)
{
if (m.isAnnotationPresent(annType))
return true;
AnnotatedMethod> annMethod = AnnotatedOverrideMap.getMethod(m);
if (annMethod == null)
return false;
else
return annMethod.isAnnotationPresent(annType);
}
//
// introspection
//
private void introspectType()
{
// interceptors aren't intercepted
if (getBeanType().isAnnotationPresent(javax.interceptor.Interceptor.class)
|| getBeanType().isAnnotationPresent(javax.decorator.Decorator.class)) {
_isInterceptorOrDecorator = true;
return;
}
for (AnnotatedField super X> field : getBeanType().getFields()) {
if (field.isAnnotationPresent(Delegate.class)) {
_isInterceptorOrDecorator = true;
return;
}
}
for (AnnotatedMethod super X> method : getBeanType().getMethods()) {
for (AnnotatedParameter super X> param : method.getParameters()) {
if (param.isAnnotationPresent(Delegate.class)) {
_isInterceptorOrDecorator = true;
return;
}
}
}
for (Annotation ann : getBeanType().getAnnotations()) {
if (_manager.isPassivatingScope(ann.annotationType())) {
_isPassivating = true;
}
else if (Stateful.class.equals(ann.annotationType())) {
_isStateful = true;
// ioc/05as, ejb/5019
// _isPassivating = true;
}
}
_selfInterceptors = getTypeInterceptors(getBeanType());
introspectClassInterceptorBindings();
introspectClassDecorators();
if (isPassivating())
validatePassivating();
}
private void validatePassivating()
{
/*
for (Class> cl : _classInterceptors) {
if (! Serializable.class.isAssignableFrom(cl) && false) {
throw new ConfigException(L.l("{0} has an invalid interceptor {1} because it's not serializable.",
getBeanType().getJavaClass().getName(),
cl.getName()));
}
}
*/
}
/**
* Introspects the @Interceptors annotation on the class
*/
private ClassInterceptors
getTypeInterceptors(AnnotatedType> beanType)
{
ClassInterceptors interceptors = _interceptorMap.get(beanType);
if (interceptors == null) {
interceptors = introspectTypeInterceptors(beanType);
_interceptorMap.put(beanType, interceptors);
}
return interceptors;
}
/**
* Introspects the @Interceptors annotation on the class
*/
private ClassInterceptors
introspectTypeInterceptors(AnnotatedType> beanType)
{
ArrayList> selfInterceptors
= introspectSelfInterceptors(beanType);
ArrayList> classInterceptors
= introspectClassInterceptors(beanType);
ArrayList> defaultInterceptors
= introspectDefaultInterceptors(beanType);
ClassInterceptors interceptors
= new ClassInterceptors(classInterceptors,
defaultInterceptors,
selfInterceptors);
return interceptors;
}
/**
* Introspects the @Interceptors annotation on the class
*/
private ArrayList>
introspectClassInterceptors(AnnotatedType> beanType)
{
if (beanType == null)
return null;
ArrayList> classInterceptors = null;
if (beanType.isAnnotationPresent(ExcludeClassInterceptors.class)) {
// _isExcludeClassInterceptors = true;
return classInterceptors;
}
Interceptors interceptors = beanType.getAnnotation(Interceptors.class);
if (interceptors != null) {
classInterceptors = new ArrayList>();
for (Class> iClass : interceptors.value()) {
if (! classInterceptors.contains(iClass))
classInterceptors.add(iClass);
}
}
return classInterceptors;
}
/**
* Introspects the @Interceptors annotation on the class
*/
private ArrayList>
introspectSelfInterceptors(AnnotatedType> beanType)
{
ArrayList> selfInterceptors = null;
if (isInterceptorPresentRec(beanType.getJavaClass())) {
selfInterceptors = new ArrayList>();
selfInterceptors.add(beanType.getJavaClass());
}
return selfInterceptors;
}
/**
* Introspects the @Interceptors annotation on the class
*/
private ArrayList>
introspectDefaultInterceptors(AnnotatedType> beanType)
{
ArrayList> defaultInterceptors = null;
if (beanType.isAnnotationPresent(ExcludeDefaultInterceptors.class)) {
// _isExcludeDefaultInterceptors = true;
return defaultInterceptors;
}
DefaultInterceptors interceptors
= beanType.getAnnotation(DefaultInterceptors.class);
if (interceptors != null) {
defaultInterceptors = new ArrayList>();
for (Class> iClass : interceptors.value()) {
if (! defaultInterceptors.contains(iClass)) {
defaultInterceptors.add(iClass);
}
}
}
return defaultInterceptors;
}
private void introspectClassInterceptors(ArrayList> list,
Class> iClass)
{
if (isInterceptorPresent(iClass)) {
if (! list.contains(iClass)) {
list.add(iClass);
}
}
}
/**
* Introspects the CDI interceptor bindings on the class
*/
private void introspectClassInterceptorBindings()
{
/*
for (Annotation ann : getBeanType().getAnnotations()) {
if (ann.annotationType().isAnnotationPresent(InterceptorBinding.class)) {
}
}
*/
_classInterceptorBindings
= addInterceptorBindings(null, getBeanType().getAnnotations());
}
/**
* Finds the matching decorators for the class
*/
private void introspectClassDecorators()
{
Set types = getBeanType().getTypeClosure();
HashSet decoratorBindingSet = new HashSet();
boolean isQualifier = false;
for (Annotation ann : getBeanType().getAnnotations()) {
if (ann.annotationType().isAnnotationPresent(Qualifier.class)) {
decoratorBindingSet.add(ann);
if (! Named.class.equals(ann.annotationType())) {
isQualifier = true;
}
}
}
if (! isQualifier)
decoratorBindingSet.add(DefaultLiteral.DEFAULT);
decoratorBindingSet.add(AnyLiteral.ANY);
Annotation []decoratorBindings;
if (decoratorBindingSet != null) {
decoratorBindings = new Annotation[decoratorBindingSet.size()];
decoratorBindingSet.toArray(decoratorBindings);
}
else
decoratorBindings = new Annotation[0];
List> decorators
= _manager.resolveDecorators(types, decoratorBindings);
if (decorators.size() == 0)
return;
if (isPassivating() || isStateful()) {
// ioc/0i5e
CandiUtil.validatePassivatingDecorators(getBeanType().getJavaClass(), decorators);
}
HashSet closure = new HashSet();
for (Decorator> decorator : decorators) {
BaseType type = _manager.createTargetBaseType(decorator.getDelegateType());
closure.addAll(type.getTypeClosure(_manager));
}
_decoratorClasses = new HashSet>();
for (Type genericType : closure) {
BaseType type = _manager.createTargetBaseType(genericType);
Class> rawClass = type.getRawClass();
if (Object.class.equals(rawClass))
continue;
_decoratorClasses.add(rawClass);
}
}
private HashSet>
introspectDecorators(AnnotatedMethod super X> annMethod)
{
if (annMethod.getJavaMember().getDeclaringClass().equals(Object.class))
return null;
if (_decoratorClasses == null)
return null;
HashSet> decoratorSet = null;
for (Class> decoratorClass : _decoratorClasses) {
for (Method method : decoratorClass.getMethods()) {
if (AnnotatedTypeUtil.isMatch(method, annMethod.getJavaMember())) {
if (decoratorSet == null)
decoratorSet = new HashSet>();
decoratorSet.add(decoratorClass);
}
}
}
return decoratorSet;
}
private HashMap,Annotation>
addInterceptorBindings(HashMap,Annotation> interceptorMap,
Set annotations)
{
for (Annotation ann : annotations) {
interceptorMap = addInterceptorBindings(interceptorMap, ann);
}
return interceptorMap;
}
private HashMap,Annotation>
addInterceptorBindings(HashMap,Annotation> interceptorMap,
Annotation ann)
{
Class> annType = ann.annotationType();
if (annType.isAnnotationPresent(InterceptorBinding.class)) {
if (interceptorMap == null)
interceptorMap = new HashMap,Annotation>();
Annotation oldAnn = interceptorMap.put(ann.annotationType(), ann);
if (oldAnn != null && ! oldAnn.equals(ann))
throw new ConfigException(L.l("duplicate @InterceptorBindings {0} and {1} are not allowed, because Resin can't tell which one to use.",
ann, oldAnn));
}
if (annType.isAnnotationPresent(Stereotype.class)) {
for (Annotation subAnn : annType.getAnnotations()) {
interceptorMap = addInterceptorBindings(interceptorMap, subAnn);
}
}
return interceptorMap;
}
public AnnotatedMethod super X> getAroundInvokeMethod()
{
return null;
}
/**
* @param out
*/
public void generateThis(JavaWriter out)
throws IOException
{
out.print("this");
}
/**
* @param out
*/
public void generateBeanInfo(JavaWriter out)
throws IOException
{
out.print("bean");
}
static class ClassInterceptors {
private ArrayList> _classInterceptors
= new ArrayList>();
private ArrayList> _defaultInterceptors
= new ArrayList>();
private ArrayList> _selfInterceptors
= new ArrayList>();
ClassInterceptors(ArrayList> classInterceptors,
ArrayList> defaultInterceptors,
ArrayList> selfInterceptors)
{
_classInterceptors = classInterceptors;
_defaultInterceptors = defaultInterceptors;
_selfInterceptors = selfInterceptors;
}
public ArrayList> getClassInterceptors()
{
return _classInterceptors;
}
public ArrayList> getDefaultInterceptors()
{
return _defaultInterceptors;
}
public ArrayList> getSelfInterceptors()
{
return _selfInterceptors;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy