org.broadleafcommerce.core.workflow.BaseProcessor.java Source code

Java tutorial

Introduction

Here is the source code for org.broadleafcommerce.core.workflow.BaseProcessor.java

Source

/*
 * #%L
 * BroadleafCommerce Framework
 * %%
 * Copyright (C) 2009 - 2013 Broadleaf Commerce
 * %%
 * 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.
 * #L%
 */
package org.broadleafcommerce.core.workflow;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Transformer;
import org.broadleafcommerce.common.logging.LifeCycleEvent;
import org.broadleafcommerce.common.logging.SupportLogManager;
import org.broadleafcommerce.common.logging.SupportLogger;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.UnsatisfiedDependencyException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.OrderComparator;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

/**
 * Base class for all Workflow Processors.  Responsible of keeping track of an ordered collection
 * of {@link Activity Activities}
 * 
 * @since March 1, 2005
 * @see Activity
 * 
 */
public abstract class BaseProcessor implements InitializingBean, BeanNameAware, BeanFactoryAware, Processor {

    protected BeanFactory beanFactory;
    protected String beanName;
    protected List<Activity<ProcessContext<? extends Object>>> activities = new ArrayList<Activity<ProcessContext<? extends Object>>>();
    protected List<ModuleActivity> moduleActivities = new ArrayList<ModuleActivity>();

    protected ErrorHandler defaultErrorHandler;

    @Value("${workflow.auto.rollback.on.error}")
    private boolean autoRollbackOnError = true;

    /**
     * If set to true, this will allow an empty set of activities, thus creating a 'do-nothing' workflow
     */
    protected boolean allowEmptyActivities = false;

    protected SupportLogger supportLogger = SupportLogManager.getLogger("Workflows", BaseProcessor.class);

    /**
     * Sets name of the spring bean in the application context that this
     * processor is configured under
     * @see org.springframework.beans.factory.BeanNameAware#setBeanName(java.lang.String)
     */
    @Override
    public void setBeanName(String beanName) {
        this.beanName = beanName;

    }

    /** Sets the spring bean factroy bean that is responsible for this processor.
     * @see org.springframework.beans.factory.BeanFactoryAware#setBeanFactory(org.springframework.beans.factory.BeanFactory)
     */
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    /**
     * Whether or not the ActivityStateManager should automatically attempt to rollback any RollbackHandlers registered.
     * If false, rolling back will require an explicit call to ActivityStateManagerImpl.getStateManager().rollbackAllState().
     * The default value is true.
     *
     * @return Whether or not the ActivityStateManager should automatically attempt to rollback
     */
    public boolean getAutoRollbackOnError() {
        return autoRollbackOnError;
    }

    /**
     * Set whether or not the ActivityStateManager should automatically attempt to rollback any RollbackHandlers registered.
     * If false, rolling back will require an explicit call to ActivityStateManagerImpl.getStateManager().rollbackAllState().
     * The default value is true.
     *
     * @param autoRollbackOnError Whether or not the ActivityStateManager should automatically attempt to rollback
     */
    public void setAutoRollbackOnError(boolean autoRollbackOnError) {
        this.autoRollbackOnError = autoRollbackOnError;
    }

    /**
     * Defaults to 'false'. This will prevent an exception from being thrown when no activities have been configured
     * for a processor, and thus will create a 'do-nothing' workflow.
     * @return the allowEmptyActivities
     */
    public boolean isAllowEmptyActivities() {
        return allowEmptyActivities;
    }

    /**
     * @param allowEmptyActivities the allowEmptyActivities to set
     */
    public void setAllowEmptyActivities(boolean allowEmptyActivities) {
        this.allowEmptyActivities = allowEmptyActivities;
    }

    /**
     * Called after the properties have been set, Ensures the list of activities
     *  is not empty and each activity is supported by this Workflow Processor
     *
     * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
     */
    @Override
    public void afterPropertiesSet() throws Exception {

        if (!(beanFactory instanceof ListableBeanFactory)) {
            throw new BeanInitializationException("The workflow processor [" + beanName + "] "
                    + "is not managed by a ListableBeanFactory, please re-deploy using some derivative of ListableBeanFactory such as"
                    + "ClassPathXmlApplicationContext ");
        }

        if (CollectionUtils.isEmpty(activities) && !isAllowEmptyActivities()) {
            throw new UnsatisfiedDependencyException(getBeanDesc(), beanName, "activities",
                    "No activities were wired for this workflow");
        }

        //sort the activities based on their configured order
        OrderComparator.sort(activities);

        HashSet<String> moduleNames = new HashSet<String>();
        for (Iterator<Activity<ProcessContext<? extends Object>>> iter = activities.iterator(); iter.hasNext();) {
            Activity<? extends ProcessContext<? extends Object>> activity = iter.next();
            if (!supports(activity)) {
                throw new BeanInitializationException("The workflow processor [" + beanName + "] does "
                        + "not support the activity of type" + activity.getClass().getName());
            }

            if (activity instanceof ModuleActivity) {
                moduleActivities.add((ModuleActivity) activity);
                moduleNames.add(((ModuleActivity) activity).getModuleName());
            }
        }

        if (CollectionUtils.isNotEmpty(moduleActivities)) {
            //log the fact that we've got some modifications to the workflow
            StringBuffer message = new StringBuffer();
            message.append("The following modules have made changes to the " + getBeanName() + " workflow: ");
            message.append(Arrays.toString(moduleNames.toArray()));
            message.append("\n");
            message.append("The final ordering of activities for the " + getBeanName() + " workflow is: \n");
            ArrayList<String> activityNames = new ArrayList<String>();
            CollectionUtils.collect(activities, new Transformer() {

                @Override
                public Object transform(Object input) {
                    return ((Activity) input).getBeanName();
                }
            }, activityNames);
            message.append(Arrays.toString(activityNames.toArray()));

            supportLogger.lifecycle(LifeCycleEvent.CONFIG, message.toString());
        }

    }

    /**
     * Returns the bean description if the current bean factory allows it.
     * @return spring bean description configure via the spring description tag
     */
    protected String getBeanDesc() {
        return (beanFactory instanceof ConfigurableListableBeanFactory)
                ? ((ConfigurableListableBeanFactory) beanFactory).getBeanDefinition(beanName)
                        .getResourceDescription()
                : "Workflow Processor: " + beanName;
    }

    /**
     * Sets the collection of Activities to be executed by the Workflow Process
     * 
     * @param activities ordered collection (List) of activities to be executed by the processor
     */
    @Override
    public void setActivities(List<Activity<ProcessContext<? extends Object>>> activities) {
        this.activities = activities;
    }

    @Override
    public void setDefaultErrorHandler(ErrorHandler defaultErrorHandler) {
        this.defaultErrorHandler = defaultErrorHandler;
    }

    public List<Activity<ProcessContext<? extends Object>>> getActivities() {
        return activities;
    }

    /**
     * Returns a filtered set of {@link #getActivities()} that have implemented the {@link ModuleActivity} interface. This
     * set of module activities is only set once during {@link #afterPropertiesSet()}, so if you invoke
     * {@link #setActivities(List)} after the bean has been initialized you will need to manually reset the list of module
     * activities as well (which could be achieved by manually invoking {@link #afterPropertiesSet()}).
     * 
     * @return
     */
    public List<ModuleActivity> getModuleActivities() {
        return moduleActivities;
    }

    public String getBeanName() {
        return beanName;
    }

    public ErrorHandler getDefaultErrorHandler() {
        return defaultErrorHandler;
    }

    public BeanFactory getBeanFactory() {
        return beanFactory;
    }
}