Package org.apache.webbeans.ejb.common.interceptor

Source Code of org.apache.webbeans.ejb.common.interceptor.OpenWebBeansEjbInterceptor$CallReturnValue

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.webbeans.ejb.common.interceptor;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;

import javassist.util.proxy.ProxyFactory;
import javassist.util.proxy.ProxyObject;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.context.spi.Context;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;

import org.apache.webbeans.component.InjectionTargetBean;
import org.apache.webbeans.config.OWBLogConst;
import org.apache.webbeans.config.OpenWebBeansConfiguration;
import org.apache.webbeans.container.BeanManagerImpl;
import org.apache.webbeans.context.ContextFactory;
import org.apache.webbeans.context.creational.CreationalContextImpl;
import org.apache.webbeans.corespi.ServiceLoader;
import org.apache.webbeans.decorator.DelegateHandler;
import org.apache.webbeans.decorator.WebBeansDecoratorConfig;
import org.apache.webbeans.decorator.WebBeansDecoratorInterceptor;
import org.apache.webbeans.ejb.common.component.BaseEjbBean;
import org.apache.webbeans.ejb.common.util.EjbUtility;
import org.apache.webbeans.inject.OWBInjector;
import org.apache.webbeans.intercept.InterceptorData;
import org.apache.webbeans.intercept.InterceptorDataImpl;
import org.apache.webbeans.intercept.InterceptorType;
import org.apache.webbeans.intercept.InterceptorUtil;
import org.apache.webbeans.intercept.InvocationContextImpl;
import org.apache.webbeans.logger.WebBeansLogger;
import org.apache.webbeans.proxy.JavassistProxyFactory;
import org.apache.webbeans.spi.ContextsService;
import org.apache.webbeans.util.ClassUtil;
import org.apache.webbeans.util.SecurityUtil;
import org.apache.webbeans.util.WebBeansUtil;

/**
* EJB interceptor that is responsible
* for injection dependent instances, and call
* OWB based interceptors and decorators.
*
* @version $Rev$ $Date$
*
*/
public class OpenWebBeansEjbInterceptor implements Serializable
{
    //Logger instance
    private final WebBeansLogger logger = WebBeansLogger.getLogger(OpenWebBeansEjbInterceptor.class);
   
    /**Thread local for calling bean*/
    private static transient ThreadLocal<BaseEjbBean<?>> threadLocal = new ThreadLocal<BaseEjbBean<?>>();
   
    /**Thread local for calling creational context*/
    private static transient ThreadLocal<CreationalContext<?>> threadLocalCreationalContext = new ThreadLocal<CreationalContext<?>>();
   
    /**Intercepted methods*/
    protected transient Map<Method, List<InterceptorData>> interceptedMethodMap = new WeakHashMap<Method, List<InterceptorData>>();

    /**Non contextual Intercepted methods*/
    protected transient Map<Method, List<InterceptorData>> nonCtxInterceptedMethodMap = new WeakHashMap<Method, List<InterceptorData>>();
   
    /**Injector*/
    private transient OWBInjector injector;
   
    /**Resolved ejb beans for non-contexctual interceptors*/
    private transient Map<Class<?>, BaseEjbBean<?>> resolvedBeans = new HashMap<Class<?>, BaseEjbBean<?>>();
   
    /**
     * Creates a new instance.
     */
    public OpenWebBeansEjbInterceptor()
    {
       
    }
   
    private static class CallReturnValue
    {
        // true if OWB kicked off the interceptor/decorator stack, so the EJB method does not need to be separately invoked.
        public boolean INTERCEPTOR_OR_DECORATOR_CALL = false;
        public Object RETURN_VALUE = null;
    }
   
    /**
     * Sets thread local.
     * @param ejbBean bean
     * @param creationalContext context
     */
    public static void setThreadLocal(BaseEjbBean<?> ejbBean, CreationalContext<?> creationalContext)
    {
        threadLocal.set(ejbBean);
        threadLocalCreationalContext.set(creationalContext);
    }
   
    /**
     * Remove locals.
     */
    public static void unsetThreadLocal()
    {
        threadLocal.set(null);
        threadLocalCreationalContext.set(null);
       
        threadLocal.remove();
        threadLocalCreationalContext.remove();
    }
   
    /**
     * Called for every business methods.
     * @param ejbContext invocation context
     * @return instance
     * @throws Exception
     */
    @AroundInvoke
    public Object callToOwbInterceptors(InvocationContext ejbContext) throws Exception
    {
        CallReturnValue rv = null;
        boolean requestCreated = false;
        boolean applicationCreated = false;
        boolean requestAlreadyActive = false;
        boolean applicationAlreadyActive = false;
      
        if (logger.wblWillLogDebug())
        {
            logger.debug("Intercepting EJB method {0} ", ejbContext.getMethod());
        }
       
        try
        {
            int result = activateContexts(RequestScoped.class);
            //Context activities
            if(result == 1)
            {
                requestCreated = true;
            }
            else if(result == -1)
            {
                requestAlreadyActive = true;
            }

            result = activateContexts(ApplicationScoped.class);
            if(result == 1)
            {
                applicationCreated = true;
            }
            else if(result == -1)
            {
                applicationAlreadyActive = true;
            }
                       
            if(threadLocal.get() != null)
            {
                //Calls OWB interceptors and decorators
                rv = callInterceptorsAndDecorators(ejbContext.getMethod(), ejbContext.getTarget(), ejbContext.getParameters(), ejbContext);   
            }
            else
            {
                //Call OWB interceptors
                rv = callInterceptorsForNonContextuals(ejbContext.getMethod(), ejbContext.getTarget(), ejbContext.getParameters(), ejbContext);
            }
           
        }
        finally
        {
            if(!requestAlreadyActive)
            {
                deActivateContexts(requestCreated, RequestScoped.class);  
            }
            if(!applicationAlreadyActive)
            {
                deActivateContexts(applicationCreated, ApplicationScoped.class);  
            }
        }
       
        //If bean has no interceptor or decorator
        //Call ejb bean instance
        if(!rv.INTERCEPTOR_OR_DECORATOR_CALL)
        {
            return ejbContext.proceed();
        }
       
        return rv.RETURN_VALUE;
    }
   
    /**
     * Post construct.
     * @param context invocation ctx
     */
    @PostConstruct
    public void afterConstruct(InvocationContext context)
    {
        InjectionTargetBean<?> injectionTarget = (InjectionTargetBean<?>) threadLocal.get();

        if (injectionTarget != null)
        {
            try
            {
                if (WebBeansUtil.isContainsInterceptorMethod(injectionTarget.getInterceptorStack(), InterceptorType.POST_CONSTRUCT))
                {
                    InvocationContextImpl impl = new InvocationContextImpl(null, context.getTarget(), null, null,
                            InterceptorUtil.getInterceptorMethods(injectionTarget.getInterceptorStack(), InterceptorType.POST_CONSTRUCT), InterceptorType.POST_CONSTRUCT);
                    impl.setCreationalContext(threadLocalCreationalContext.get());

                    // run OWB interceptors
                    impl.proceed();
                }

                // run EJB interceptors
                context.proceed();
            }
            catch (Exception e)
            {
                logger.error(OWBLogConst.ERROR_0008, e, "@PostConstruct.");
                throw new RuntimeException(e);
            }
        }
        else
        {
            runPrePostForNonContextual(context, InterceptorType.POST_CONSTRUCT);
        }
       
        if (OpenWebBeansConfiguration.getInstance().isUseEJBInterceptorInjection())
        {
            Object instance = context.getTarget();
            this.injector = new OWBInjector();
            try
            {
                this.injector.inject(instance, threadLocalCreationalContext.get());
            }
            catch (Exception e)
            {
                logger.error(OWBLogConst.ERROR_0026, e, threadLocal.get());
            }
        }
    }
   
    /**
     * Pre destroy.
     * @param context invocation context
     */
    @PreDestroy
    public void preDestroy(InvocationContext context)
    {
        InjectionTargetBean<?> injectionTarget = (InjectionTargetBean<?>) threadLocal.get();

        if (injectionTarget != null)
        {
            try
            {
                if (WebBeansUtil.isContainsInterceptorMethod(injectionTarget.getInterceptorStack(), InterceptorType.PRE_DESTROY))
                {
                    InvocationContextImpl impl = new InvocationContextImpl(null, context.getTarget(), null, null,
                            InterceptorUtil.getInterceptorMethods(injectionTarget.getInterceptorStack(),InterceptorType.PRE_DESTROY), InterceptorType.PRE_DESTROY);
                    impl.setCreationalContext(threadLocalCreationalContext.get());

                    // Call OWB interceptors
                    impl.proceed();
                }
                // Call EJB interceptors
                context.proceed();
            }
            catch (Exception e)
            {
                logger.error(OWBLogConst.ERROR_0008, e, "@PreDestroy.");
                throw new RuntimeException(e);
            }
        }
        else
        {
            runPrePostForNonContextual(context, InterceptorType.PRE_DESTROY);
        }

        if (this.injector != null)
        {
            this.injector.destroy();
        }

        this.interceptedMethodMap.clear();
        this.resolvedBeans.clear();
        this.nonCtxInterceptedMethodMap.clear();
    }
   
    /**
     * Activate given context.
     * @param scopeType scope type
     * @return true if also creates context.
     */
    private int activateContexts(Class<? extends Annotation> scopeType)
    {
        ContextsService service = ServiceLoader.getService(ContextsService.class);
        Context ctx = service.getCurrentContext(scopeType);
       
        if(scopeType == RequestScoped.class)
        {
            if(ctx != null && !ctx.isActive())
            {
                ContextFactory.activateContext(scopeType);
                return 0;
            }
            else if(ctx == null)
            {
                ContextFactory.initRequestContext(null);
                return 1;
            }
           
        }
       
        ctx = service.getCurrentContext(scopeType);
        if(ctx != null && !ctx.isActive())
        {
            ContextFactory.activateContext(scopeType);
            return 0;
        }
        else if(ctx == null)
        {
            ContextFactory.initApplicationContext(null);
            return 1;

        }    
       
        return -1;
    }
   
    /**
     * Deacitvate context.
     * @param destroy if destroy context
     * @param scopeType scope type
     */
    private void deActivateContexts(boolean destroy, Class<? extends Annotation> scopeType)
    {
        if(scopeType == ApplicationScoped.class)
        {
            if(destroy)
            {
                ContextFactory.destroyApplicationContext(null);
            }
            else
            {
                ContextFactory.deActivateContext(ApplicationScoped.class);
            }           
        }
        else
        {
            if(destroy)
            {
                ContextFactory.destroyRequestContext(null);
            }
            else
            {
                ContextFactory.deActivateContext(RequestScoped.class);
            }           
        }               
    }

    /**
     * Find the ManagedBean that corresponds to an instance of an EJB class
     * @param instance an instance of a class whose corresponding Managed Bean is to be searched for
     * @return the correspondin BaseEjbBean, null if not found
     */
    private BaseEjbBean<?> findTargetBean(Object instance)
    {
        BeanManagerImpl manager = BeanManagerImpl.getManager();
        if (instance == null)
        {
            logger.debug("findTargetBean was passed a null instance.");
            return null;
        }
        if (logger.wblWillLogDebug())
        {
            logger.debug("looking up bean for instance [{0}]", instance.getClass());
        }

        BaseEjbBean<?> ejbBean = this.resolvedBeans.get(instance.getClass());
       
        //Not found
        if(ejbBean == null)
        {
            Set<Bean<?>> beans = manager.getComponents();
            for(Bean<?> bean : beans)
            {
                if(bean instanceof BaseEjbBean)
                {
                    if(bean.getBeanClass() == instance.getClass())
                    {
                        ejbBean = (BaseEjbBean<?>)bean;
                        if (logger.wblWillLogDebug())
                        {
                            logger.debug("Found managed bean for [{0}] [{1}]", instance.getClass(), ejbBean);
                        }
                        this.resolvedBeans.put(instance.getClass(), ejbBean);
                        break;
                    }
                }
            }
        }       
        else
        {
            if (logger.wblWillLogDebug())
            {
                logger.debug("Managed bean for [{0}] found in cache: [{1}]", instance.getClass(),  ejbBean);
            }
        }
       
        return ejbBean;
    }
    /**
     * Calls OWB related interceptors.
     * @param method business method
     * @param instance bean instance
     * @param arguments method arguments
     * @return result of operation
     * @throws Exception for any exception
     */   
    private CallReturnValue callInterceptorsForNonContextuals(Method method, Object instance, Object[] arguments, InvocationContext ejbContext) throws Exception
    {
        BeanManagerImpl manager = BeanManagerImpl.getManager();
       
        //Try to resolve ejb bean
        BaseEjbBean<?> ejbBean =  findTargetBean(instance);
           
        CallReturnValue rv = new CallReturnValue();
        rv.INTERCEPTOR_OR_DECORATOR_CALL = false;
        if(ejbBean == null)
        {
            if (logger.wblWillLogDebug())
            {
                logger.debug(OWBLogConst.WARN_0008,  instance.getClass(), manager.getComponents());
            }
            return rv;
        }
        else
        {
            CreationalContext<?> cc = manager.createCreationalContext(null);
            try
            {
                return runInterceptorStack(ejbBean.getInterceptorStack(), method, instance, arguments, ejbBean, cc, ejbContext);
            }
            finally
            {
                cc.release();
            }
        }

    }
   
    /**
     * Calls OWB related interceptors and decorators.
     * @param method business method
     * @param instance bean instance
     * @param arguments method arguments
     * @return result of operation
     * @throws Exception for any exception
     */
    private CallReturnValue callInterceptorsAndDecorators(Method method, Object instance, Object[] arguments, InvocationContext ejbContext) throws Exception
    {
        CallReturnValue rv = new CallReturnValue();
        InjectionTargetBean<?> injectionTarget = (InjectionTargetBean<?>) threadLocal.get();
        InterceptorDataImpl decoratorInterceptorDataImpl = null;

        String methodName = method.getName();
        if(ClassUtil.isObjectMethod(methodName) && !methodName.equals("toString"))
        {
            logger.trace("Calling method on proxy is restricted except Object.toString(), but current method is Object. [{0}]", methodName);
        }
               
        if (InterceptorUtil.isWebBeansBusinessMethod(method) &&
                EjbUtility.isBusinessMethod(method, threadLocal.get()))
        {

            List<Object> decorators = null;
            DelegateHandler delegateHandler = null;
            logger.debug("Decorator stack for target {0}", injectionTarget.getDecoratorStack());

            if (injectionTarget.getDecoratorStack().size() > 0)
            {
                Class<?> proxyClass = JavassistProxyFactory.getInstance().getInterceptorProxyClasses().get(injectionTarget);
                if (proxyClass == null)
                {
                    ProxyFactory delegateFactory = JavassistProxyFactory.getInstance().createProxyFactory(injectionTarget);
                    proxyClass = JavassistProxyFactory.getInstance().getProxyClass(delegateFactory);
                    JavassistProxyFactory.getInstance().getInterceptorProxyClasses().put(injectionTarget, proxyClass);
                }
                Object delegate = proxyClass.newInstance();
                delegateHandler = new DelegateHandler(threadLocal.get(),ejbContext);
                ((ProxyObject)delegate).setHandler(delegateHandler);

                // Gets component decorator stack
                decorators = WebBeansDecoratorConfig.getDecoratorStack(injectionTarget, instance, delegate,
                                                                       (CreationalContextImpl<?>)threadLocalCreationalContext.get());                       
                //Sets decorator stack of delegate
                delegateHandler.setDecorators(decorators);
               
            }

            // Run around invoke chain
            List<InterceptorData> interceptorStack = injectionTarget.getInterceptorStack();
            if (interceptorStack.size() > 0)
            {
                if (decorators != null)
                {
                    // We have interceptors and decorators, Our delegateHandler will need to be wrapped in an interceptor
                    WebBeansDecoratorInterceptor lastInterceptor = new WebBeansDecoratorInterceptor(delegateHandler, instance);
                    decoratorInterceptorDataImpl = new InterceptorDataImpl(true, lastInterceptor);
                    decoratorInterceptorDataImpl.setDefinedInInterceptorClass(true);
                    decoratorInterceptorDataImpl.setAroundInvoke(SecurityUtil.doPrivilegedGetDeclaredMethods(lastInterceptor.getClass())[0]);
                }
               
                if (this.interceptedMethodMap.get(method) == null)
                {
                    //Holds filtered interceptor stack
                    List<InterceptorData> filteredInterceptorStack = new ArrayList<InterceptorData>(interceptorStack);

                    // Filter both EJB and WebBeans interceptors
                    InterceptorUtil.filterCommonInterceptorStackList(filteredInterceptorStack, method);

                    this.interceptedMethodMap.put(method, filteredInterceptorStack);
                }
               
                List<InterceptorData> filteredInterceptorStack = new ArrayList<InterceptorData>(this.interceptedMethodMap.get(method));
                if (decoratorInterceptorDataImpl != null)
                {
                    // created an intereceptor to run our decorators, add it to the calculated stack
                    filteredInterceptorStack.add(decoratorInterceptorDataImpl);
                }

                // Call Around Invokes
                if (WebBeansUtil.isContainsInterceptorMethod(filteredInterceptorStack, InterceptorType.AROUND_INVOKE))
                {
                     rv.INTERCEPTOR_OR_DECORATOR_CALL = true;
                     rv.RETURN_VALUE = InterceptorUtil.callAroundInvokes(threadLocal.get(), instance, (CreationalContextImpl<?>)threadLocalCreationalContext.get(), method,
                            arguments, InterceptorUtil.getInterceptorMethods(filteredInterceptorStack, InterceptorType.AROUND_INVOKE), ejbContext);
                    
                     return rv;
                }
               
            }
           
            // If there are Decorators, allow the delegate handler to
            // manage the stack
            if (decorators != null)
            {
                rv.INTERCEPTOR_OR_DECORATOR_CALL = true;
                rv.RETURN_VALUE = delegateHandler.invoke(instance, method, null, arguments);
                return rv;
            }
        }   
       
        rv.INTERCEPTOR_OR_DECORATOR_CALL = false;
       
        return rv;
    }
   
    private CallReturnValue runInterceptorStack(List<InterceptorData> interceptorStack, Method method, Object instance,
                                        Object[] arguments, BaseEjbBean<?> bean, CreationalContext<?> creationalContext, InvocationContext ejbContext) throws Exception
    {
        CallReturnValue rv = new CallReturnValue();
        if (interceptorStack.size() > 0)
        {
            if(this.nonCtxInterceptedMethodMap.get(method) == null)
            {
                //Holds filtered interceptor stack
                List<InterceptorData> filteredInterceptorStack = new ArrayList<InterceptorData>(interceptorStack);

                // Filter both EJB and WebBeans interceptors
                InterceptorUtil.filterCommonInterceptorStackList(filteredInterceptorStack, method)
                logger.debug("Interceptor stack for method {0}: {1}", method, filteredInterceptorStack);
                this.nonCtxInterceptedMethodMap.put(method, filteredInterceptorStack);
            }
           
            // Call Around Invokes
            if (WebBeansUtil.isContainsInterceptorMethod(this.nonCtxInterceptedMethodMap.get(method), InterceptorType.AROUND_INVOKE))
            {
                 rv.INTERCEPTOR_OR_DECORATOR_CALL = true;
                 rv.RETURN_VALUE = InterceptorUtil.callAroundInvokes(bean, instance, (CreationalContextImpl<?>)creationalContext, method,
                        arguments, InterceptorUtil.getInterceptorMethods(this.nonCtxInterceptedMethodMap.get(method), InterceptorType.AROUND_INVOKE),
                        ejbContext);
                
                 return rv;
            }
           
        }
       
        rv.INTERCEPTOR_OR_DECORATOR_CALL = false;
       
        return rv;
       
    }
  
    /**
     * Run @PostConstruct or @PreDestroy for a non-contextual EJB
     * @param ejbContext the EJB containers InvocationContext
     * @param interceptorType PreDestroy or PostConstruct
     */
    public void runPrePostForNonContextual(InvocationContext ejbContext, InterceptorType interceptorType)
    {
        CreationalContext<?> localcc = null;
        BeanManagerImpl manager = BeanManagerImpl.getManager();
        Object instance = ejbContext.getTarget();
       
        try
        {
           
            BaseEjbBean<?> bean = findTargetBean(instance);
            if (bean == null)
            {
                logger.debug("No bean for instance [{0}]", instance);
                ejbContext.proceed();
                return;
            }
           
            List<InterceptorData> interceptorStack = bean.getInterceptorStack();
           
            if (interceptorStack.size() > 0 && WebBeansUtil.isContainsInterceptorMethod(interceptorStack, interceptorType))
            {
                localcc = manager.createCreationalContext(null);
               
                InvocationContextImpl impl = new InvocationContextImpl(null, instance, null, null,
                        InterceptorUtil.getInterceptorMethods(interceptorStack, interceptorType), interceptorType);
                impl.setCreationalContext(localcc);
               
                try
                {
                    impl.proceed();
                }
                catch (Exception e)
                {
                    logger.error(OWBLogConst.ERROR_0008, e, interceptorType);               
                }   
            }      
            else
            {
                logger.debug("No lifecycle interceptors for [{0}]", instance);
            }
   
            //Call next interceptor
            ejbContext.proceed();
        }
        catch (Exception e)
        {
            logger.warn(OWBLogConst.WARN_0007, e);
            throw new RuntimeException(e);
        }
        finally
        {
          if (localcc != null)
          {
              localcc.release();
          }
        }
    }
   
    private void writeObject(java.io.ObjectOutputStream out) throws IOException
    {
        // Do nothing
    }
   
    //Read object
    private  void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException
    {
        threadLocal = new ThreadLocal<BaseEjbBean<?>>();
        threadLocalCreationalContext = new ThreadLocal<CreationalContext<?>>();
        interceptedMethodMap = new WeakHashMap<Method, List<InterceptorData>>();
        nonCtxInterceptedMethodMap = new WeakHashMap<Method, List<InterceptorData>>();
        resolvedBeans = new HashMap<Class<?>, BaseEjbBean<?>>();
    }
   
}
TOP

Related Classes of org.apache.webbeans.ejb.common.interceptor.OpenWebBeansEjbInterceptor$CallReturnValue

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.