All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.granite.tide.seam.TideInterceptor Maven / Gradle / Ivy

The newest version!
/**
 *   GRANITE DATA SERVICES
 *   Copyright (C) 2006-2014 GRANITE DATA SERVICES S.A.S.
 *
 *   This file is part of the Granite Data Services Platform.
 *
 *   Granite Data Services is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU Lesser General Public
 *   License as published by the Free Software Foundation; either
 *   version 2.1 of the License, or (at your option) any later version.
 *
 *   Granite Data Services 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. See the GNU Lesser
 *   General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public
 *   License along with this library; if not, write to the Free Software
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
 *   USA, or see .
 */
package org.granite.tide.seam;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.granite.tide.TidePersistenceManager;
import org.granite.tide.annotations.BypassTideInterceptor;
import org.granite.tide.invocation.ContextUpdate;
import org.granite.tide.seam.TideInit.FactoryVariable;
import org.granite.tide.seam.lazy.SeamInitializer;
import org.granite.tide.seam.lazy.TidePersistenceFactory;
import org.jboss.seam.Component;
import org.jboss.seam.ScopeType;
import org.jboss.seam.Component.BijectedAttribute;
import org.jboss.seam.annotations.DataBinderClass;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.intercept.AroundInvoke;
import org.jboss.seam.annotations.intercept.Interceptor;
import org.jboss.seam.annotations.security.Restrict;
import org.jboss.seam.bpm.BusinessProcessInterceptor;
import org.jboss.seam.contexts.Context;
import org.jboss.seam.contexts.Contexts;
import org.jboss.seam.core.BijectionInterceptor;
import org.jboss.seam.core.EventInterceptor;
import org.jboss.seam.databinding.DataBinder;
import org.jboss.seam.intercept.AbstractInterceptor;
import org.jboss.seam.intercept.InvocationContext;
import org.jboss.seam.log.LogProvider;
import org.jboss.seam.log.Logging;


/**
 * This interceptor has 4 activities :
 * - Updating the context with data received from the Flex client, remerging client data in the persistence context when needed
 * - Intercept outjected values to return it to the client
 * - Determine the Persistence Context being used for the conversation and creating a lazyinitializer
 *   storing it in the current conversation
 * - Return all changed values to the client
 *
 * @author Venkat DANDA
 * @author Cameron INGRAM
 * @author William DRAI
 */


@Interceptor(around={BijectionInterceptor.class, EventInterceptor.class, BusinessProcessInterceptor.class})
public class TideInterceptor extends AbstractInterceptor {

    private static final long serialVersionUID = 1L;

    
    private static final LogProvider log = Logging.getLogProvider(TideInterceptor.class);

    private boolean reentrant; //OK, since all Seam components are single-threaded


    @AroundInvoke
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public Object aroundInvoke(InvocationContext invocation) throws Exception {

        if (reentrant) {
            log.trace("About to invoke method");

            if (log.isTraceEnabled())
                log.trace("reentrant call to component: " + getComponent().getName() );

            Object result = invocation.proceed();

            log.trace("Method invoked");
 
            return result;
        }

        reentrant = true;
  
        try {
            if (getComponent().getBeanClass().isAnnotationPresent(BypassTideInterceptor.class))
            	return invocation.proceed();
            
            TideInvocation tideInvocation = TideInvocation.get();
            
            if (tideInvocation == null || tideInvocation.isLocked())
                return invocation.proceed();

            AbstractSeamServiceContext tideContext = null;
            if (Contexts.isSessionContextActive()) 
            	tideContext = (AbstractSeamServiceContext)Component.getInstance(AbstractSeamServiceContext.COMPONENT_NAME, true); 
            
            if (tideContext == null)
                return invocation.proceed();
            
            // Ignore lifecycle methods
            if (SeamUtils.isLifecycleMethod(getComponent(), invocation.getMethod())) {
                tideInvocation.lock();

                Object result = invocation.proceed();

                tideInvocation.unlock();

                return result;
            }

            
            boolean evaluate = false;
            
            //Check for persistence
            checkForPersistenceContexts(invocation);

            // Ignore inner interceptions of other components during processing
            if (tideInvocation.isEnabled() && !tideInvocation.isUpdated()) {
                List updates = new ArrayList(tideInvocation.getUpdates());
                tideInvocation.updated();
                tideContext.restoreContext(updates, getComponent(), invocation.getTarget());
                evaluate = true;

                // Inject DataModel selections
                Field field = getComponent().getClass().getDeclaredField("dataModelGetters");
                field.setAccessible(true);
                List> dataModelGetters = (List>)field.get(getComponent());
                for (BijectedAttribute getter : dataModelGetters) {
                    Annotation dataModelAnn = getter.getAnnotation();
                    DataBinder wrapper = dataModelAnn.annotationType().getAnnotation(DataBinderClass.class).value().newInstance();
                    String name = getter.getName();
                    ScopeType scope = wrapper.getVariableScope(dataModelAnn);
                    if (scope == ScopeType.UNSPECIFIED) {
                        scope = getComponent().getScope();
                        if (scope == ScopeType.STATELESS)
                            scope = ScopeType.EVENT;
                    }
                    Object dataModel = scope.getContext().get(name);
                    if (dataModel != null && dataModel instanceof TideDataModel) {
                        Field field2 = getComponent().getClass().getDeclaredField("dataModelSelectionSetters");
                        field2.setAccessible(true);
                        Map> setters = (Map>)field2.get(getComponent());
                        BijectedAttribute setter = setters.get(name);
                        if (setter != null) {
                            Object value = setter.get(invocation.getTarget());
                            ((TideDataModel)dataModel).setRowData(value);
                        }
                    }
                }
            }
            
            // Do invocation
            Object result = invocation.proceed();

            boolean restrict = getComponent().beanClassHasAnnotation(Restrict.class);
            
            // Intercept outjected values
            if (getComponent().needsOutjection()) {               
                List> li = getComponent().getOutAttributes();
                for (BijectedAttribute att: li) {
                    ScopeType scope = att.getAnnotation().scope();
                    if (ScopeType.UNSPECIFIED.equals(scope)) {
                        Component outComponent = Component.forName(att.getName());
                        if (outComponent != null)
                            scope = outComponent.getScope();
                        else
                            scope = getComponent().getScope();
                    }
                    if (ScopeType.STATELESS.equals(scope))
                        scope = ScopeType.EVENT;
                    
                    if (!(ScopeType.EVENT.equals(scope))) {
                        Context context = Contexts.getEventContext();
                        if (context.get(att.getName() + "_tide_unspecified_") != null) {
                            context.remove(att.getName() + "_tide_unspecified_");
                            context.remove(att.getName());
                        }
                    }    
                    
                    tideContext.addResultEval(new ScopedContextResult(att.getName(), null, scope, restrict));
                }

                Field field = getComponent().getClass().getDeclaredField("dataModelGetters");
                field.setAccessible(true);
                List> dataModelGetters = (List>)field.get(getComponent());
                for (BijectedAttribute getter : dataModelGetters) {
                    Annotation anno = getter.getAnnotation();
                    DataBinder wrapper = anno.annotationType().getAnnotation(DataBinderClass.class).value().newInstance();
                    ScopeType scope = wrapper.getVariableScope(anno);
                    if (ScopeType.UNSPECIFIED.equals(scope))
                        scope = getComponent().getScope();
                    if (ScopeType.STATELESS.equals(scope))
                        scope = ScopeType.EVENT;
                    
                    if (!(ScopeType.EVENT.equals(scope))) {
                        Context context = Contexts.getEventContext();
                        if (context.get(getter.getName() + "_tide_unspecified_") != null) {
                            context.remove(getter.getName() + "_tide_unspecified_");
                            context.remove(getter.getName());
                        }
                    }
                    
                    tideContext.addResultEval(new ScopedContextResult(getter.getName(), null, scope, restrict));
                }
            }
            
            // Force evaluation of factory components dependent on the called component
            Set factoredVariables = TideInit.getFactoredVariables(getComponent());
            if (factoredVariables != null) {
	            for (FactoryVariable variable : factoredVariables) {
	            	ScopeType scope = variable.getScope();
	            	if (ScopeType.UNSPECIFIED.equals(scope))
	            		scope = getComponent().getScope();
	            	if (ScopeType.STATELESS.equals(scope))
	            		scope = ScopeType.EVENT;
	            	
	                tideContext.addResultEval(new ScopedContextResult(variable.getVariableName(), null, scope, restrict));
	            }
            }
            

            if (evaluate)
                tideInvocation.evaluated(tideContext.evaluateResults(getComponent(), invocation.getTarget(), false));

            return result;
        }
        finally {
            reentrant = false;
        }
    } 
    
    /**
     * Try to determine what the PersistenceContext is and create an appropriate 
     * lazy initializer for it.
     * @param ctx the bean bieng accessed.
     */
    private void checkForPersistenceContexts(InvocationContext ctx) {        
        Object bean = ctx.getTarget();
        TidePersistenceManager pm = null;
        
        for ( BijectedAttribute ba: getComponent().getPersistenceContextAttributes() ) {
   		    Object object = ba.get(bean);
   		    SeamInitializer.instance().setTidePersistenceManager(TidePersistenceFactory.createTidePersistence(getComponent(), object));
   		    return;
        }
        
   	    if (getComponent().needsInjection()) {
		    List> li = getComponent().getInAttributes();
		    
			for (BijectedAttribute att: li) {
				
				try {
					pm = TidePersistenceFactory.createTidePersistence(getComponent(), att);
				} catch (RuntimeException ex) {
					continue;
				}
				
				if (pm != null) {
			        SeamInitializer.instance().setTidePersistenceManager(pm);
			        return;
				} 
			}
		}
   	    
   	    //Last chance to see a PersistenceManager can be found for this invocation
   	    pm = TidePersistenceFactory.createTidePersistence(getComponent(), ctx.getTarget());
   	    if (pm != null)
    	    SeamInitializer.instance().setTidePersistenceManager(pm);
    }
    
	// Needed for Seam 2.1
    public boolean isInterceptorEnabled() {
        return true;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy