org.exoplatform.container.spring.SpringContainer.java Source code

Java tutorial

Introduction

Here is the source code for org.exoplatform.container.spring.SpringContainer.java

Source

/*
 * Copyright (C) 2013 eXo Platform SAS.
 *
 * This 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.
 *
 * This software 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 software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.exoplatform.container.spring;

import org.exoplatform.commons.utils.SecurityHelper;
import org.exoplatform.container.AbstractComponentAdapter;
import org.exoplatform.container.AbstractInterceptor;
import org.exoplatform.container.configuration.ConfigurationManager;
import org.exoplatform.container.spi.ComponentAdapter;
import org.exoplatform.container.spi.ContainerException;
import org.exoplatform.container.spi.Interceptor;
import org.exoplatform.container.xml.Component;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericApplicationContext;

import java.lang.annotation.Annotation;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.inject.Named;

/**
 * The implementation of an {@link Interceptor} allowing eXo Kernel to interact with a spring container
 * 
 * @author <a href="mailto:nfilotto@exoplatform.com">Nicolas Filotto</a>
 * @version $Id$
 *
 */
public class SpringContainer extends AbstractInterceptor {

    /**
     * The serial version UID
     */
    private static final long serialVersionUID = -4841328894117928913L;

    /**
     * The logger
     */
    private static final Log LOG = ExoLogger
            .getLogger("exo.kernel.container.ext.provider.impl.spring.v3.SpringContainer");

    /**
     * The Spring {@link ApplicationContext}
     */
    private ApplicationContext ctx;

    /**
     * {@inheritDoc}
     */
    @Override
    public <T> T getComponentInstance(Object componentKey, Class<T> bindType, boolean autoRegistration) {
        T result = super.getComponentInstance(componentKey, bindType, autoRegistration);
        if (ctx != null && result == null) {
            if (componentKey instanceof Class<?> && !((Class<?>) componentKey).isAnnotation()) {
                return bindType.cast(getInstanceOfType((Class<?>) componentKey));
            } else if (!(componentKey instanceof String) && !(componentKey instanceof Class<?>)) {
                return null;
            }
            String beanName = keyToBeanName(componentKey);
            if (ctx.containsBean(beanName) && bindType.isAssignableFrom(ctx.getType(beanName))) {
                return bindType.cast(ctx.getBean(beanName));
            }
            String[] names = ctx.getBeanNamesForType(bindType);
            if (names != null && names.length > 0) {
                for (int i = 0, length = names.length; i < length; i++) {
                    String name = names[i];
                    if (componentKey instanceof String) {
                        Named n = ctx.findAnnotationOnBean(name, Named.class);
                        if (n != null && componentKey.equals(n.value())) {
                            return bindType.cast(ctx.getBean(name));
                        }
                    } else {
                        @SuppressWarnings("unchecked")
                        Annotation a = ctx.findAnnotationOnBean(name, (Class<? extends Annotation>) componentKey);
                        if (a != null) {
                            return bindType.cast(ctx.getBean(name));
                        }
                    }
                }
            }
        }
        return result;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <T> T getComponentInstanceOfType(final Class<T> componentType, boolean autoRegistration) {
        T result = super.getComponentInstanceOfType(componentType, autoRegistration);
        if (ctx != null && result == null) {
            result = getInstanceOfType(componentType);
        }
        return result;
    }

    private <T> T getInstanceOfType(final Class<T> componentType) {
        T result;
        PrivilegedAction<T> action = new PrivilegedAction<T>() {
            public T run() {
                String name = classToBeanName(componentType);
                if (ctx.containsBean(name) && componentType.isAssignableFrom(ctx.getType(name))) {
                    return componentType.cast(ctx.getBean(name));
                }
                String[] names = ctx.getBeanNamesForType(componentType);
                if (names != null && names.length > 0) {
                    return componentType.cast(ctx.getBean(names[0]));
                }
                return null;
            }
        };
        result = SecurityHelper.doPrivilegedAction(action);
        return result;
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    @Override
    public <T> ComponentAdapter<T> getComponentAdapter(Object componentKey, Class<T> bindType,
            boolean autoRegistration) {
        ComponentAdapter<?> result = super.getComponentAdapter(componentKey, bindType, autoRegistration);
        if (ctx != null && result == null) {
            if (componentKey instanceof Class<?> && !((Class<?>) componentKey).isAnnotation()) {
                return getAdapterOfType(bindType);
            } else if (!(componentKey instanceof String) && !(componentKey instanceof Class<?>)) {
                return null;
            }
            String beanName = keyToBeanName(componentKey);
            if (ctx.containsBean(beanName) && bindType.isAssignableFrom(ctx.getType(beanName))) {
                return createComponentAdapter(bindType, beanName);
            }
            String[] names = ctx.getBeanNamesForType(bindType);
            if (names != null && names.length > 0) {
                for (int i = 0, length = names.length; i < length; i++) {
                    String name = names[i];
                    if (componentKey instanceof String) {
                        Named n = ctx.findAnnotationOnBean(name, Named.class);
                        if (n != null && componentKey.equals(n.value())) {
                            return createComponentAdapter(bindType, name);
                        }
                    } else {
                        Annotation a = ctx.findAnnotationOnBean(name, (Class<? extends Annotation>) componentKey);
                        if (a != null) {
                            return createComponentAdapter(bindType, name);
                        }
                    }
                }
            }
        }
        return (ComponentAdapter<T>) result;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <T> ComponentAdapter<T> getComponentAdapterOfType(Class<T> componentType, boolean autoRegistration) {
        ComponentAdapter<T> result = super.getComponentAdapterOfType(componentType, autoRegistration);
        if (ctx != null && result == null) {
            result = getAdapterOfType(componentType);
        }
        return result;
    }

    private <T> ComponentAdapter<T> getAdapterOfType(Class<T> componentType) {
        String name = classToBeanName(componentType);
        if (ctx.containsBean(name) && componentType.isAssignableFrom(ctx.getType(name))) {
            return createComponentAdapter(componentType, name);
        }
        String[] names = ctx.getBeanNamesForType(componentType);
        if (names != null && names.length > 0) {
            return createComponentAdapter(componentType, names[0]);
        }
        return null;
    }

    private <T> ComponentAdapter<T> createComponentAdapter(final Class<T> type, final String name) {
        return new AbstractComponentAdapter<T>(type, type) {
            /**
             * The serial UID
             */
            private static final long serialVersionUID = -4625398501079851570L;

            public T getComponentInstance() throws ContainerException {
                return type.cast(ctx.getBean(name));
            }

            public boolean isSingleton() {
                return ctx.isSingleton(name);
            }
        };
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    @Override
    public <T> List<ComponentAdapter<T>> getComponentAdaptersOfType(Class<T> componentType) {
        List<ComponentAdapter<T>> result = super.getComponentAdaptersOfType(componentType);
        if (ctx != null) {
            result = new ArrayList<ComponentAdapter<T>>(result);
            String[] names = ctx.getBeanNamesForType(componentType);
            if (names != null) {
                for (int i = 0, length = names.length; i < length; i++) {
                    String name = names[i];
                    result.add((ComponentAdapter<T>) createComponentAdapter(ctx.getType(name), name));
                }
            }
        }
        return result;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <T> List<T> getComponentInstancesOfType(Class<T> componentType) throws ContainerException {
        List<T> result = super.getComponentInstancesOfType(componentType);
        if (ctx != null) {
            result = new ArrayList<T>(result);
            result.addAll(ctx.getBeansOfType(componentType).values());
        }
        return result;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public void start() {
        ConfigurationManager cm = super.getComponentInstanceOfType(ConfigurationManager.class, false);
        // We check if the component has been defined in the configuration of the current container
        // The goal is to enable the SpringContainer only if it is needed
        Component component = cm.getComponent(ApplicationContextProvider.class);
        if (component == null) {
            if (LOG.isDebugEnabled()) {
                LOG.debug(
                        "No ApplicationContextProvider has been defined, thus the SpringContainer will be disabled."
                                + " To enable the Spring Integration please define an ApplicationContextProvider");
            }
        } else {
            DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
            bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
            Collection<ComponentAdapter<?>> adapters = delegate.getComponentAdapters();
            for (ComponentAdapter<?> adapter : adapters) {
                Object key = adapter.getComponentKey();
                String name = keyToBeanName(key);
                String factoryName = name + "#factory";
                RootBeanDefinition def = new RootBeanDefinition(adapter.getComponentImplementation(),
                        AbstractBeanDefinition.AUTOWIRE_NO, false);
                def.setScope(BeanDefinition.SCOPE_PROTOTYPE);
                def.setFactoryBeanName(factoryName);
                def.setFactoryMethodName("getInstance");
                def.setLazyInit(true);
                def.setTargetType(adapter.getComponentImplementation());
                if (key instanceof String) {
                    def.addQualifier(new AutowireCandidateQualifier(Named.class, key));
                } else if (key instanceof Class<?> && ((Class<?>) key).isAnnotation()) {
                    def.addQualifier(new AutowireCandidateQualifier((Class<?>) key));
                } else {
                    def.setPrimary(true);
                }
                bf.registerBeanDefinition(name, def);
                bf.registerSingleton(factoryName, new ComponentAdapterFactoryBean(adapter));
            }
            GenericApplicationContext parentContext = new GenericApplicationContext(bf);
            parentContext.refresh();
            ApplicationContextProvider provider = super.getComponentInstanceOfType(ApplicationContextProvider.class,
                    false);
            ctx = provider.getApplicationContext(parentContext);
            LOG.info("A SpringContainer has been enabled using the ApplicationContextProvider "
                    + provider.getClass());
        }
        super.start();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void stop() {
        super.stop();
        if (ctx instanceof DisposableBean) {
            try {
                ((DisposableBean) ctx).destroy();
            } catch (Exception e) {
                LOG.warn("Could not destroy the container: " + e.getMessage());
            } finally {
                ctx = null;
            }
        }
    }

    private static String classToBeanName(Class<?> type) {
        return type.getName();
    }

    private static String keyToBeanName(Object key) {
        if (key instanceof Class<?>) {
            return classToBeanName((Class<?>) key);
        } else {
            if (key instanceof String) {
                return (String) key;
            } else {
                return classToBeanName(key.getClass());
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    public String getId() {
        return "SpringIntegration";
    }

    static class ComponentAdapterFactoryBean<T> {
        private final ComponentAdapter<T> adapter;

        private ComponentAdapterFactoryBean(ComponentAdapter<T> adapter) {
            this.adapter = adapter;
        }

        public T getInstance() throws Exception {
            return adapter.getComponentInstance();
        }
    }
}