001    /*
002      GRANITE DATA SERVICES
003      Copyright (C) 2011 GRANITE DATA SERVICES S.A.S.
004    
005      This file is part of Granite Data Services.
006    
007      Granite Data Services is free software; you can redistribute it and/or modify
008      it under the terms of the GNU Library General Public License as published by
009      the Free Software Foundation; either version 2 of the License, or (at your
010      option) any later version.
011    
012      Granite Data Services is distributed in the hope that it will be useful, but
013      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014      FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015      for more details.
016    
017      You should have received a copy of the GNU Library General Public License
018      along with this library; if not, see <http://www.gnu.org/licenses/>.
019    */
020    
021    package org.granite.tide.seam.async;
022    
023    import java.lang.annotation.Annotation;
024    import java.util.Date;
025    
026    import org.granite.tide.seam.AbstractSeamServiceContext;
027    import org.granite.tide.seam.TideInvocation;
028    import org.jboss.seam.Component;
029    import org.jboss.seam.annotations.async.Asynchronous;
030    import org.jboss.seam.annotations.async.Duration;
031    import org.jboss.seam.annotations.async.Expiration;
032    import org.jboss.seam.annotations.async.FinalExpiration;
033    import org.jboss.seam.annotations.async.IntervalCron;
034    import org.jboss.seam.annotations.async.IntervalDuration;
035    import org.jboss.seam.annotations.intercept.AroundInvoke;
036    import org.jboss.seam.annotations.intercept.Interceptor;
037    import org.jboss.seam.annotations.intercept.InterceptorType;
038    import org.jboss.seam.async.AbstractDispatcher;
039    import org.jboss.seam.async.AsynchronousInterceptor;
040    import org.jboss.seam.contexts.Contexts;
041    import org.jboss.seam.intercept.AbstractInterceptor;
042    import org.jboss.seam.intercept.InvocationContext;
043    
044    /**
045     * Slightly modified version of the Seam asynchronous interceptor which saves the current username
046     * 
047     * Dispatches method calls to @Asynchronous methods
048     * asynchronously, and returns the "timer" object
049     * if necessary.
050     * 
051     * @author William DRAI
052     *
053     */
054    @Interceptor(stateless=true, type=InterceptorType.CLIENT, around={ AsynchronousInterceptor.class })
055    public class TideAsynchronousInterceptor extends AbstractInterceptor {
056        
057        private static final long serialVersionUID = 9194177339867853303L;
058        
059        
060        @AroundInvoke
061        public Object aroundInvoke(InvocationContext invocation) throws Exception {
062            if (invocation.getTarget() instanceof AsynchronousInvoker) {
063                    if (Contexts.getEventContext().isSet(AbstractDispatcher.EXECUTING_ASYNCHRONOUS_CALL))
064                            TideInvocation.init();
065                return invocation.proceed();
066            }
067            
068            boolean scheduleAsync = invocation.getMethod().isAnnotationPresent(Asynchronous.class) && 
069                (!Contexts.getEventContext().isSet(AbstractDispatcher.EXECUTING_ASYNCHRONOUS_CALL) 
070                        || Contexts.getEventContext().isSet("org.jboss.seam.async.AsynchronousIntercepter.REENTRANT"));
071            if (scheduleAsync) {
072                AbstractSeamServiceContext serviceContext = (AbstractSeamServiceContext)Component.getInstance(AbstractSeamServiceContext.COMPONENT_NAME, false);
073                if (serviceContext != null && serviceContext.getSessionId() != null) {
074                    Annotation[][] parameterAnnotations = invocation.getMethod().getParameterAnnotations();
075                    Long duration = null;
076                    Date expiration = null;
077                    Date finalExpiration = null;
078                    Long intervalDuration = null;
079                    String intervalCron = null;
080                    for (int i = 0; i < parameterAnnotations.length; i++) {
081                        Annotation[] annotations = parameterAnnotations[i];
082                        for (Annotation annotation : annotations) {
083                            if (annotation.annotationType().equals(Duration.class))
084                                duration = (Long)invocation.getParameters()[i];
085                            else if (annotation.annotationType().equals(Expiration.class))
086                                expiration = (Date)invocation.getParameters()[i];
087                            else if (annotation.annotationType().equals(FinalExpiration.class))
088                                finalExpiration = (Date)invocation.getParameters()[i];
089                            else if (annotation.annotationType().equals(IntervalDuration.class))
090                                intervalDuration = (Long)invocation.getParameters()[i];
091                            else if (annotation.annotationType().equals(IntervalCron.class))
092                                intervalCron = (String)invocation.getParameters()[i];
093                        }
094                    }
095                    
096                    String targetComponentName = getComponent().getName();
097                    Class<?> targetComponentClass = getComponent().getBeanClass();
098                    String methodName = invocation.getMethod().getName();
099                    Class<?>[] paramTypes = invocation.getMethod().getParameterTypes();
100                    Object[] params = invocation.getParameters();
101                    
102                    AsynchronousInvoker invoker = (AsynchronousInvoker)Component.getInstance("org.granite.tide.seam.asynchronousInvoker");
103                    
104                    AsyncContext asyncContext = serviceContext.getAsyncContext();
105                    
106                    if (intervalCron != null)
107                        return invoker.invokeAsynchronousCron(asyncContext, targetComponentName, targetComponentClass, methodName, paramTypes, params, 
108                                duration, expiration, finalExpiration, intervalCron);
109                    
110                    if (finalExpiration != null)
111                        return invoker.invokeAsynchronousDuration(asyncContext, targetComponentName, targetComponentClass, methodName, paramTypes, params, 
112                                duration, expiration, finalExpiration, intervalDuration);
113                    
114                    return invoker.invokeAsynchronousDuration(asyncContext, targetComponentName, targetComponentClass, methodName, paramTypes, params, 
115                            duration, expiration, intervalDuration);
116                }
117            }
118            
119            return invocation.proceed();
120        }
121    
122            // Needed for Seam 2.1
123        public boolean isInterceptorEnabled() {
124            return true;
125        }
126    }