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

com.google.code.rees.scope.conversation.configuration.DefaultConversationConfigurationProvider Maven / Gradle / Ivy

There is a newer version: 1.7.4
Show newest version
/*******************************************************************************
 * 
 *  Struts2-Conversation-Plugin - An Open Source Conversation- and Flow-Scope Solution for Struts2-based Applications
 *  =================================================================================================================
 * 
 *  Copyright (C) 2012 by Rees Byars
 *  http://code.google.com/p/struts2-conversation/
 * 
 * **********************************************************************************************************************
 * 
 *  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.
 * 
 * **********************************************************************************************************************
 * 
 *  $Id: DefaultConversationConfigurationProvider.java reesbyars $
 ******************************************************************************/
package com.google.code.rees.scope.conversation.configuration;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.code.rees.scope.ActionProvider;
import com.google.code.rees.scope.container.Component;
import com.google.code.rees.scope.container.Property;
import com.google.code.rees.scope.conversation.ConversationConstants;
import com.google.code.rees.scope.conversation.ConversationConstants.Properties;
import com.google.code.rees.scope.conversation.annotations.BeginConversation;
import com.google.code.rees.scope.util.ReflectionUtil;

/**
 * The default implementation of {@link ConversationConfigurationProvider}
 * 
 * @author rees.byars
 */
public class DefaultConversationConfigurationProvider implements ConversationConfigurationProvider {

    private static final long serialVersionUID = -1227350994518195549L;
    private static final Logger LOG = LoggerFactory.getLogger(DefaultConversationConfigurationProvider.class);

    protected ConversationArbitrator arbitrator;
    protected ActionProvider actionProvider;
    protected ConcurrentMap, Collection> classConfigurations = new ConcurrentHashMap, Collection>();
	protected long maxIdleTimeMillis = ConversationConstants.DEFAULT_CONVERSATION_MAX_IDLE_TIME;
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	@Property(Properties.CONVERSATION_IDLE_TIMEOUT)
	public void setDefaultMaxIdleTime(long maxIdleTimeMillis) {
		double idleTimeHours = maxIdleTimeMillis / (1000.0 * 60 * 60);
    	LOG.info("Setting default conversation timeout:  " + maxIdleTimeMillis + " milliseconds.");
    	LOG.info("Converted default conversation timeout:  " + String.format("%.2f", idleTimeHours) + " hours.");
		this.maxIdleTimeMillis = maxIdleTimeMillis;
	}

    /**
     * {@inheritDoc}
     */
    @Override
    @Component
    public void setArbitrator(ConversationArbitrator arbitrator) {
        this.arbitrator = arbitrator;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @Component
	public void setActionProvider(ActionProvider actionProvider) {
    	this.actionProvider = actionProvider;
	}

    /**
     * {@inheritDoc}
     */
	@Override
	public void init() {
		try {
			if (this.classConfigurations.size() != actionProvider.getActionClasses().size()) { //in case it's already been called
				LOG.info("Building Conversation Configurations...");
				if (this.arbitrator == null) {
					LOG.error("No ConversationArbitrator set for the ConversationConfigurationProvider, review configuration files to make sure an arbitrator is declared.");
				}
			    for (Class clazz : actionProvider.getActionClasses()) {
			        processClass(clazz, classConfigurations);
			    }
			    LOG.info("...building of Conversation Configurations successfully completed.");
			}
		} catch (Exception e) {
			LOG.warn("The was an error attempting to retrieve the action classes.  This could be due to an older version of Struts2. Configurations will be built on the fly");
		}
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Collection getConfigurations(Class clazz) {
        Collection configurations = classConfigurations.get(clazz);
        if (configurations == null) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("No cached ConversationClassConfiguration found for class " + clazz.getName());
            }
            configurations = this.processClass(clazz, classConfigurations);
        }
        return configurations;
    }

    /**
     * good candidate for refactoring... but it works!
     * 
     * @param clazz
     * @param classConfigurations
     * @return
     */
    protected Collection processClass(Class clazz, ConcurrentMap, Collection> classConfigurations) {
        Collection configurations = classConfigurations.get(clazz);
        if (configurations == null) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("Building ConversationClassConfigurationImpl for class " + clazz.getName());
            }
            configurations = new HashSet();
            Map temporaryConversationMap = new HashMap();
            for (Field field : this.arbitrator.getCandidateConversationFields(clazz)) {
                Collection fieldConversations = this.arbitrator.getConversations(clazz, field);
                if (fieldConversations != null) {
                    String fieldName = this.arbitrator.getName(field);
                    ReflectionUtil.makeAccessible(field);
                    for (String conversation : fieldConversations) {
                        ConversationClassConfiguration configuration = temporaryConversationMap.get(conversation);
                        if (configuration == null) {
                            configuration = new ConversationClassConfiguration(conversation);
                            temporaryConversationMap.put(conversation, configuration);
                        }
                        if (LOG.isDebugEnabled()) {
                            LOG.debug("Adding field " + fieldName + " to ConversationClassConfigurationImpl for Conversation " + conversation);
                        }
                        configuration.addField(fieldName, field);
                    }
                }
            }
            
            // TODO refactor into multiple methods to make more beautimous
            for (Method method : this.arbitrator.getCandidateConversationMethods(clazz)) {
            	
            	//intermediate action methods
                Collection methodConversations = this.arbitrator.getConversations(clazz, method);
                if (methodConversations != null) {
                    String methodName = this.arbitrator.getName(method);
                    for (String conversation : methodConversations) {
                        ConversationClassConfiguration configuration = temporaryConversationMap.get(conversation);
                        if (configuration == null) {
                            configuration = new ConversationClassConfiguration(conversation);
                            temporaryConversationMap.put(conversation, configuration);
                        }
                        if (LOG.isDebugEnabled()) {
                            LOG.debug("Adding method " + methodName + " as an Action to ConversationClassConfigurationImpl for Conversation " + conversation);
                        }
                        
                        configuration.addAction(methodName);
                        
                    }
                }
                
                //begin action methods
                Collection methodBeginConversations = this.arbitrator.getBeginConversations(clazz, method);
                if (methodBeginConversations != null) {
                    String methodName = this.arbitrator.getName(method);
                    for (String conversation : methodBeginConversations) {
                        ConversationClassConfiguration configuration = temporaryConversationMap.get(conversation);
                        if (configuration == null) {
                            configuration = new ConversationClassConfiguration(conversation);
                            temporaryConversationMap.put(conversation, configuration);
                        }
                        
                        //yeah this code just got placed here because it was easy - again, this class and the arbitrator just need overhauling (but thats a lot of work!)
                        long maxIdleTime = this.maxIdleTimeMillis;
                		if (method.isAnnotationPresent(BeginConversation.class)) {
                			BeginConversation beginConversation = method.getAnnotation(BeginConversation.class);
                			if (beginConversation.maxIdleTimeMillis() != -1L) {
                				maxIdleTime = beginConversation.maxIdleTimeMillis();
                			}
                		}
                		
                		if (LOG.isDebugEnabled()) {
                            LOG.debug("Adding method " + methodName + " as a Begin Action to ConversationClassConfigurationImpl for Conversation " + conversation + " with a timeout of " + maxIdleTime / 1000 + " seconds.");
                        }
                		
                        configuration.addBeginAction(methodName, maxIdleTime);
                    }
                }
                
                //end action methods
                Collection methodEndConversations = this.arbitrator.getEndConversations(clazz, method);
                if (methodEndConversations != null) {
                    String methodName = this.arbitrator.getName(method);
                    for (String conversation : methodEndConversations) {
                        ConversationClassConfiguration configuration = temporaryConversationMap.get(conversation);
                        if (configuration == null) {
                            configuration = new ConversationClassConfiguration(conversation);
                            temporaryConversationMap.put(conversation, configuration);
                        }
                        if (LOG.isDebugEnabled()) {
                            LOG.debug("Adding method " + methodName + " as an End Action to ConversationClassConfigurationImpl for Conversation " + conversation);
                        }
                        configuration.addEndAction(methodName);
                    }
                }
            }
            configurations.addAll(temporaryConversationMap.values());
            classConfigurations.putIfAbsent(clazz, configurations);
        }
        
        return configurations;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy