jrouter.spring.DefaultActionFactoryBean.java Source code

Java tutorial

Introduction

Here is the source code for jrouter.spring.DefaultActionFactoryBean.java

Source

/*
 * Copyright (C) 2010-2111 sunjumper@163.com
 *
 * 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.
 *
 */
package jrouter.spring;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import jrouter.ActionFactory;
import jrouter.ConverterFactory;
import jrouter.JRouterException;
import jrouter.ObjectFactory;
import jrouter.config.AopAction;
import jrouter.config.Configuration;
import jrouter.impl.PathActionFactory;
import jrouter.util.AntPathMatcher;
import jrouter.util.ClassUtil;
import jrouter.util.CollectionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.io.Resource;

/**
 * ??springframework?ActionFactoryActionpathspringframeworkbean?
 *
 * @param <T> ActionFactory
 */
public class DefaultActionFactoryBean<T extends ActionFactory>
        implements FactoryBean<T>, InitializingBean, DisposableBean, ApplicationContextAware {

    /** LOG */
    private static final Logger LOG = LoggerFactory.getLogger(DefaultActionFactoryBean.class);

    /**
     * Location of a single JRouter XML config file. ???ActionFactory??
     */
    private Resource configLocation;

    /* ActionFactory */
    private T actionFactory;

    /* ActionFactory */
    private Class<T> actionFactoryClass = null;

    /** Configuration */
    private Configuration configuration;

    /**
     * Configuration
     *
     * @deprecated since 1.6.4
     */
    @Deprecated
    private Class<? extends Configuration> configurationClass = Configuration.class;

    /** @see ActionFactory#getObjectFactory() */
    private ObjectFactory objectFactory;

    /** @see ActionFactory#getConverterFactory() */
    private ConverterFactory converterFactory;

    /**
     * @see Configuration#actionFactoryProperties
     * @see jrouter.impl.PathActionFactory#setActionFactoryProperties(java.util.Map)
     */
    private Properties actionFactoryProperties = new Properties();

    ////////////////////////////////////////////////////////////////////////////////////////////////////
    /* bean????? */
    private List<Object> interceptors = null;

    /* bean????? */
    private List<Object> interceptorStacks = null;

    /* bean????? */
    private List<Object> resultTypes = null;

    /* bean????? */
    private List<Object> results = null;

    /* Actionbean????? */
    private List<Object> actions = null;

    /**
     * ??????(??/??/?)
     *
     * @see Configuration#parsecComponentClassScanner(java.util.Map)
     */
    private List<Properties> componentClassScanProperties;

    /** actions' aop */
    private List<? extends AopAction> aopActions;
    ////////////////////////////////////////////////////////////////////////////////////////////////////

    /** ??nameBean???(?/)beans' name */
    private Properties componentBeanScanProperties;

    /** ApplicationContext */
    private ApplicationContext applicationContext;

    /**
     * ?ActionFactory
     *
     * @see #buildActionFactory()
     * @see #afterActionFactoryCreation(jrouter.ActionFactory)
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        actionFactory = (T) buildActionFactory();
        afterActionFactoryCreation(actionFactory);
    }

    /**
     * ActionFactory
     *
     * @return ActionFactory
     *
     * @throws Exception ?
     */
    protected ActionFactory buildActionFactory() throws Exception {
        LOG.info("Initiating JRouter ActionFactory at : " + new java.util.Date());
        if (configuration == null) {
            configuration = createDefaultConfiguration();
        }
        //???ActionFactory??
        if (configLocation != null) {
            LOG.debug("Load configuration : " + configLocation.getURL());
            configuration.load(configLocation.getURL());
        }

        if (actionFactoryClass != null) {
            LOG.debug("Set actionFactoryClass : " + actionFactoryClass);
            configuration.setActionFactoryClass(actionFactoryClass);
        } else {
            setDefaultActionFactoryClass(configuration);
        }
        if (objectFactory == null) {
            objectFactory = createDefaultObjectFactory(configuration);
        }
        actionFactoryProperties.put("objectFactory", objectFactory);

        if (converterFactory != null) {
            actionFactoryProperties.put("converterFactory", converterFactory);
        }
        configuration.addActionFactoryProperties((Map) actionFactoryProperties);

        //??
        if (componentClassScanProperties != null)
            configuration.addComponentClassScanProperties(
                    componentClassScanProperties.toArray(new Map[componentClassScanProperties.size()]));

        //convert string to class
        convertList(interceptors, interceptorStacks, resultTypes, results, actions);

        if (CollectionUtil.isNotEmpty(componentBeanScanProperties)) {
            char[] sep = { ',', ';' };
            //??bean???
            List<String> includeComponentBeanExpressions = new ArrayList<String>(2);
            CollectionUtil.stringToCollection(
                    componentBeanScanProperties.getProperty("includeComponentBeanExpression"),
                    includeComponentBeanExpressions, sep);
            //?bean???
            List<String> excludeComponentBeanExpressions = new ArrayList<String>(2);
            CollectionUtil.stringToCollection(
                    componentBeanScanProperties.getProperty("excludeComponentBeanExpression"),
                    excludeComponentBeanExpressions, sep);

            //??class?
            List<String> includeComponentClassExpressions = new ArrayList<String>(2);
            CollectionUtil.stringToCollection(
                    componentBeanScanProperties.getProperty("includeComponentClassExpression"),
                    includeComponentClassExpressions, sep);

            //?class???
            List<String> excludeComponentClassExpressions = new ArrayList<String>(2);
            CollectionUtil.stringToCollection(
                    componentBeanScanProperties.getProperty("excludeComponentClassExpression"),
                    excludeComponentClassExpressions, sep);

            AntPathMatcher matcher = new AntPathMatcher(".");
            String[] beanNames = applicationContext.getBeanDefinitionNames();
            Set<String> includes = new LinkedHashSet<String>();
            out: for (String name : beanNames) {
                for (String excludeComponentBeanExpression : excludeComponentBeanExpressions) {
                    if (matcher.match(excludeComponentBeanExpression, name)) {
                        continue out;
                    }
                }
                for (String includeComponentBeanExpression : includeComponentBeanExpressions) {
                    if (matcher.match(includeComponentBeanExpression, name)) {
                        includes.add(name);
                    }
                }
            }
            //add include beans
            out: for (String includeName : includes) {
                try {
                    Object bean = applicationContext.getBean(includeName);
                    String clsName = bean.getClass().getName();
                    for (String excludeComponentClassExpression : excludeComponentClassExpressions) {
                        //exclude class
                        if (matcher.match(excludeComponentClassExpression, clsName)) {
                            continue out;
                        }
                    }
                    if (CollectionUtil.isNotEmpty(includeComponentClassExpressions)) {
                        for (String includeComponentClassExpression : includeComponentClassExpressions) {
                            if (matcher.match(includeComponentClassExpression, clsName)) {
                                //only add matched-class bean
                                addComponentToList(bean, interceptors, interceptorStacks, resultTypes, results,
                                        actions);
                                continue out;
                            }
                        }
                    } else {
                        //if no includeComponentClassExpression, means allow all
                        addComponentToList(bean, interceptors, interceptorStacks, resultTypes, results, actions);
                    }
                } catch (BeansException e) {
                    //ignore
                    LOG.warn("Can't get bean : " + includeName);
                }
            }
        }

        //set configuration
        if (CollectionUtil.isNotEmpty(interceptors))
            configuration.addInterceptors(interceptors);
        if (CollectionUtil.isNotEmpty(interceptorStacks))
            configuration.addInterceptorStacks(interceptorStacks);
        if (CollectionUtil.isNotEmpty(resultTypes))
            configuration.addResultTypes(resultTypes);
        if (CollectionUtil.isNotEmpty(results))
            configuration.addResults(results);
        if (CollectionUtil.isNotEmpty(actions))
            configuration.addActions(actions);

        //TODO
        //configuration.setPathProperties(null);
        //actions' aop
        if (CollectionUtil.isNotEmpty(aopActions)) {
            configuration.addAopActions(aopActions);
        }
        return configuration.buildActionFactory();
    }

    /**
     * Configuration??{@code SpringConfiguration}
     *
     * @return {@code SpringConfiguration}
     *
     * @see #setConfiguration(jrouter.config.Configuration)
     */
    protected Configuration createDefaultConfiguration() {
        //create SpringObjectFactory
        return new SpringConfiguration(applicationContext);
    }

    /**
     * actionFactoryClass??{@code PathActionFactory.class}
     *
     * @param config Configuration
     *
     * @see #setActionFactoryClass(java.lang.Class)
     */
    protected void setDefaultActionFactoryClass(Configuration config) {
        config.setActionFactoryClass(PathActionFactory.class);
    }

    /**
     * objectFactory??{@code SpringObjectFactory}
     *
     * @param config Configuration
     *
     * @return {@code SpringObjectFactory}
     *
     * @see #setObjectFactory(jrouter.ObjectFactory)
     */
    protected ObjectFactory createDefaultObjectFactory(Configuration config) {
        //create SpringObjectFactory
        return new SpringObjectFactory(applicationContext);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////
    /**
     * Add matched bean.
     *
     * @param bean matched bean.
     * @param listArray the array of list.
     */
    private void addComponentToList(Object bean, List... listArray) {
        out: for (List<Object> componentList : listArray) {
            if (CollectionUtil.isNotEmpty(componentList)) {
                for (Object exist : componentList) {
                    if (bean.getClass() == (exist instanceof Class ? exist : exist.getClass()))
                        continue out;
                }
                componentList.add(bean);
            }
        }
    }

    /**
     * Convert the {@code String} element of the list into {@code Class}.
     *
     * @param listArray the array of list.
     *
     * @throws ClassNotFoundException If the class was not found.
     */
    private static void convertList(List... listArray) throws ClassNotFoundException {
        for (List componentList : listArray) {
            if (CollectionUtil.isNotEmpty(componentList)) {
                for (int i = 0; i < componentList.size(); i++) {
                    Object obj = componentList.get(i);
                    if (obj instanceof String) {
                        componentList.set(i, ClassUtil.loadClass((String) obj));
                    }
                }
            }
        }
    }

    /**
     * beanActionFactory?
     *
     * @throws JRouterException ?
     */
    @Override
    public void destroy() throws JRouterException {
        LOG.info("Closing JRouter ActionFactory : " + actionFactory);
        try {
            beforeActionFactoryDestruction();
        } finally {
            if (actionFactory != null)
                this.actionFactory.clear();
        }
    }

    /**
     * ActionFactory??
     */
    @Override
    public T getObject() {
        return (T) this.actionFactory;
    }

    @Override
    public Class<? extends ActionFactory> getObjectType() {
        return actionFactory == null ? null : actionFactory.getClass();
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    /**
     * Hook that allows post-processing after the ActionFactory has been successfully created.
     * The ActionFactory is already available through {@code getActionFactory()} at this point.
     * <p>
     * This implementation is empty.
     *
     * @param actionFactory ActionFactory
     *
     * @see #buildActionFactory()
     */
    protected void afterActionFactoryCreation(T actionFactory) {
    }

    /**
     * Hook that allows shutdown processing before the ActionFactory will be closed.
     * The ActionFactory is still available through {@code getActionFactory()} at this point.
     * <p>
     * This implementation is empty.
     *
     * @see #destroy()
     */
    protected void beforeActionFactoryDestruction() {
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
     * Set the location of a single JRouter XML config file.
     *
     * @param configLocation Location of a single JRouter XML config file.
     *
     * @see jrouter.config.Configuration#load(java.net.URL)
     */
    public void setConfigLocation(Resource configLocation) {
        this.configLocation = configLocation;
    }

    /**
     * JRouter Configuration
     *
     * @param configurationClass Configuration
     *
     * @see jrouter.config.Configuration
     * @see #setConfiguration(jrouter.config.Configuration)
     *
     * @deprecated since 1.6.4
     */
    @Deprecated
    public void setConfigurationClass(Class<? extends Configuration> configurationClass) {
        if (configurationClass == null || !Configuration.class.isAssignableFrom(configurationClass)) {
            throw new IllegalArgumentException(
                    "'configurationClass' must be assignable to [jrouter.config.Configuration]");
        }
        this.configurationClass = (Class<? extends Configuration>) configurationClass;
    }

    /**
     * Configuration
     *
     * @param configuration Configuration
     */
    public void setConfiguration(Configuration configuration) {
        this.configuration = configuration;
    }

    /**
     * Get the JRouter Configuration object used to build the ActionFactory.
     *
     * @return the JRouter Configuration object used to build the ActionFactory.
     */
    public final Configuration getConfiguration() {
        if (this.configuration == null) {
            throw new IllegalStateException("Configuration not initialized yet");
        }
        return this.configuration;
    }

    /**
     * ActionFactory
     *
     * @param actionFactoryClass ActionFactory
     *
     * @see Configuration#setActionFactoryClass(java.lang.Class)
     */
    public void setActionFactoryClass(Class<T> actionFactoryClass) {
        if (actionFactoryClass == null || !ActionFactory.class.isAssignableFrom(actionFactoryClass)) {
            throw new IllegalArgumentException(
                    "'actionFactoryClass' must be assignable to [jrouter.ActionFactory]");
        }
        this.actionFactoryClass = actionFactoryClass;
    }

    /**
     * ActionFactory?
     *
     * @param actionFactoryProperties ActionFactory?
     *
     * @see Configuration#addActionFactoryProperties(java.util.Map)
     * @see jrouter.impl.PathActionFactory#setActionFactoryProperties(java.util.Map)
     */
    public void setActionFactoryProperties(Properties actionFactoryProperties) {
        this.actionFactoryProperties = actionFactoryProperties;
    }

    /**
     * ActionFactory
     *
     * @param objectFactory ActionFactory
     *
     * @see Configuration#addActionFactoryProperties(java.util.Map)
     * @see ActionFactory#getObjectFactory()
     */
    public void setObjectFactory(ObjectFactory objectFactory) {
        this.objectFactory = objectFactory;
    }

    /**
     * ActionFactory?
     *
     * @param converterFactory ActionFactory?
     *
     * @see Configuration#addActionFactoryProperties(java.util.Map)
     * @see ActionFactory#getConverterFactory()
     */
    public void setConverterFactory(ConverterFactory converterFactory) {
        this.converterFactory = converterFactory;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////
    /**
     * Actionbean?????
     *
     * @param actions Actionbean?????
     */
    public void setActions(List<Object> actions) {
        this.actions = actions;
    }

    /**
     * bean?????
     *
     * @param interceptorStacks bean?????
     */
    public void setInterceptorStacks(List<Object> interceptorStacks) {
        this.interceptorStacks = interceptorStacks;
    }

    /**
     * bean?????
     *
     * @param interceptors bean?????
     */
    public void setInterceptors(List<Object> interceptors) {
        this.interceptors = interceptors;
    }

    /**
     * bean?????
     *
     * @param resultTypes bean?????
     */
    public void setResultTypes(List<Object> resultTypes) {
        this.resultTypes = resultTypes;
    }

    /**
     * bean?????
     *
     * @param results bean?????
     */
    public void setResults(List<Object> results) {
        this.results = results;
    }

    /**
     * @see #setComponentClassScanProperties(java.util.List)
     *
     * @deprecated
     */
    @Deprecated
    public void setClassScannerProperties(List<Properties> classScannerProperties) {
        this.setComponentClassScanProperties(classScannerProperties);
    }

    /**
     * ????
     *
     * @param componentClassScanProperties ?????
     *
     * @see Configuration#parsecComponentClassScanner(java.util.Map)
     */
    public void setComponentClassScanProperties(List<Properties> componentClassScanProperties) {
        this.componentClassScanProperties = componentClassScanProperties;
    }

    /**
     * Actionaop
     *
     * @param aopActions Actions' Aop
     */
    public void setAopActions(List<? extends AopAction> aopActions) {
        this.aopActions = aopActions;
    }

    /**
     * ??/beans' name
     *
     * @param componentBeanScanProperties ??/beans' name
     *
     */
    public void setComponentBeanScanProperties(Properties componentBeanScanProperties) {
        this.componentBeanScanProperties = componentBeanScanProperties;
    }

    /**
     * Configuration for springframework's DI.
     */
    private static class SpringConfiguration extends Configuration {

        /** ApplicationContext */
        private final ApplicationContext applicationContext;

        /**
         * ApplicationContext
         *
         * @param applicationContext ApplicationContext
         */
        public SpringConfiguration(ApplicationContext applicationContext) {
            this.applicationContext = applicationContext;
        }

        @Override
        public void afterActionFactoryCreation(ActionFactory actionFactory) {
            applicationContext.getAutowireCapableBeanFactory().autowireBeanProperties(actionFactory,
                    AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false);
        }

        @Override
        protected void afterActionFactoryBuild(ActionFactory actionFactory) {
            applicationContext.getAutowireCapableBeanFactory().initializeBean(actionFactory, null);
        }
    }
}