org.nuunframework.spring.SpringModule.java Source code

Java tutorial

Introduction

Here is the source code for org.nuunframework.spring.SpringModule.java

Source

/**
 * Copyright (C) 2013 Kametic <epo.jemba@kametic.com>
 *
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE, Version 3, 29 June 2007;
 * or any later version
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.gnu.org/licenses/lgpl-3.0.txt
 *
 * 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 org.nuunframework.spring;

import com.google.inject.AbstractModule;
import com.google.inject.name.Names;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

import java.util.HashMap;
import java.util.Map;

class SpringModule extends AbstractModule {
    class SpringBeanDefinition {
        private String name;
        private ConfigurableListableBeanFactory beanFactory;

        SpringBeanDefinition(String name, ConfigurableListableBeanFactory beanFactory) {
            this.name = name;
            this.beanFactory = beanFactory;
        }

        public String getName() {
            return name;
        }

        public ConfigurableListableBeanFactory getBeanFactory() {
            return beanFactory;
        }
    }

    private Logger logger = LoggerFactory.getLogger(InternalDependencyInjectionProvider.class);

    private final ConfigurableListableBeanFactory beanFactory;
    private Map<Class<?>, Map<String, SpringBeanDefinition>> beanDefinitions;

    public SpringModule(ConfigurableListableBeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    @Override
    protected void configure() {
        this.beanDefinitions = new HashMap<Class<?>, Map<String, SpringBeanDefinition>>();
        bindFromApplicationContext();
    }

    @SuppressWarnings("unchecked")
    private void bindFromApplicationContext() {
        boolean debugEnabled = logger.isDebugEnabled();

        ConfigurableListableBeanFactory currentBeanFactory = this.beanFactory;
        do {
            for (String beanName : currentBeanFactory.getBeanDefinitionNames()) {
                BeanDefinition beanDefinition = currentBeanFactory.getMergedBeanDefinition(beanName);
                if (!beanDefinition.isAbstract()) {
                    Class<?> beanClass = classFromString(beanDefinition.getBeanClassName());
                    if (beanClass == null) {
                        logger.warn("Cannot bind spring bean " + beanName + " because its class "
                                + beanDefinition.getBeanClassName() + " failed to load");
                        return;
                    }

                    SpringBeanDefinition springBeanDefinition = new SpringBeanDefinition(beanName,
                            currentBeanFactory);

                    // Adding bean with its base type
                    addBeanDefinition(beanClass, springBeanDefinition);

                    // Adding bean with its parent type if enabled
                    Class<?> parentClass = beanClass.getSuperclass();
                    if (parentClass != null && parentClass != Object.class)
                        addBeanDefinition(parentClass, springBeanDefinition);

                    // Adding bean with its immediate interfaces if enabled
                    for (Class<?> i : beanClass.getInterfaces())
                        addBeanDefinition(i, springBeanDefinition);
                }
            }
            BeanFactory factory = currentBeanFactory.getParentBeanFactory();
            if (factory != null) {
                if (factory instanceof ConfigurableListableBeanFactory)
                    currentBeanFactory = (ConfigurableListableBeanFactory) factory;
                else {
                    logger.info(
                            "Cannot go up further in the bean factory hierarchy, parent bean factory doesn't implement ConfigurableListableBeanFactory");
                    currentBeanFactory = null;
                }
            } else
                currentBeanFactory = null;
        } while (currentBeanFactory != null);

        for (Map.Entry<Class<?>, Map<String, SpringBeanDefinition>> entry : this.beanDefinitions.entrySet()) {
            Class<?> type = entry.getKey();
            Map<String, SpringBeanDefinition> definitions = entry.getValue();

            // Bind by name for each bean of this type and by type if there is no ambiguity
            for (SpringBeanDefinition candidate : definitions.values()) {
                if (debugEnabled)
                    logger.info("Binding spring bean " + candidate.getName() + " by name and type "
                            + type.getCanonicalName());

                bind(type).annotatedWith(Names.named(candidate.getName())).toProvider(
                        new ByNameSpringContextProvider(type, candidate.getName(), candidate.getBeanFactory()));
            }
        }
    }

    private void addBeanDefinition(Class<?> beanClass, SpringBeanDefinition springBeanDefinition) {
        Map<String, SpringBeanDefinition> beansOfType = this.beanDefinitions.get(beanClass);
        if (beansOfType == null)
            this.beanDefinitions.put(beanClass, beansOfType = new HashMap<String, SpringBeanDefinition>());

        if (!beansOfType.containsKey(springBeanDefinition.getName())) // TODO determine which beans override which in spring semantics ? Here first discovered wins...
            beansOfType.put(springBeanDefinition.getName(), springBeanDefinition);
    }

    private Class<?> classFromString(String className) {
        try {
            return Class.forName(className);
        } catch (ClassNotFoundException e) {
            return null;
        }
    }

}