Package org.lilyproject.runtime.module.build

Source Code of org.lilyproject.runtime.module.build.ModuleBuilder

/*
* Copyright 2013 NGDATA nv
* Copyright 2008 Outerthought bvba and Schaubroeck nv
*
* 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 org.lilyproject.runtime.module.build;

import java.io.InputStream;
import java.lang.reflect.Proxy;
import java.net.MalformedURLException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.lilyproject.runtime.LilyRTException;
import org.lilyproject.runtime.LilyRuntime;
import org.lilyproject.runtime.module.Module;
import org.lilyproject.runtime.module.ModuleConfig;
import org.lilyproject.runtime.module.ModuleImpl;
import org.lilyproject.runtime.module.javaservice.JavaServiceShield;
import org.lilyproject.runtime.rapi.ModuleSource;
import org.lilyproject.runtime.repository.ArtifactNotFoundException;
import org.lilyproject.util.io.IOUtils;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.InputStreamResource;

public class ModuleBuilder {
    // These ThreadLocal's serve as communication mechanism for LilyRuntimeNamespaceHandler
    protected static ThreadLocal<SpringBuildContext> SPRING_BUILD_CONTEXT = new ThreadLocal<SpringBuildContext>();

    protected final Log infolog = LogFactory.getLog(LilyRuntime.INFO_LOG_CATEGORY);
    private final Log log = LogFactory.getLog(getClass());

    private ModuleBuilder() {
        // private constructor to avoid instantiation
    }

    public static Module build(ModuleConfig cfg, ClassLoader classLoader, LilyRuntime runtime) throws ArtifactNotFoundException, MalformedURLException {
        return new ModuleBuilder().buildInt(cfg, classLoader, runtime);
    }

    private Module buildInt(ModuleConfig cfg, ClassLoader classLoader, LilyRuntime runtime) throws ArtifactNotFoundException, MalformedURLException {
        infolog.info("Starting module " + cfg.getId() + " - " + cfg.getLocation());
        ClassLoader previousContextClassLoader = Thread.currentThread().getContextClassLoader();
        try {
            Thread.currentThread().setContextClassLoader(classLoader);

            GenericApplicationContext applicationContext = new GenericApplicationContext();
            applicationContext.setDisplayName(cfg.getId());
            applicationContext.setClassLoader(classLoader);

            // Note: before loading any beans in the spring container:
            //   * the spring build context needs access to the module, for possible injection & module-protocol resolving during bean initialization
            //   * the module also needs to have the reference to the applicationcontext, as there might be beans trying to get while initializing
            ModuleImpl module = new ModuleImpl(classLoader, applicationContext, cfg.getDefinition(), cfg.getModuleSource());

            SpringBuildContext springBuildContext = new SpringBuildContext(runtime, module, classLoader);
            SPRING_BUILD_CONTEXT.set(springBuildContext);

            XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(applicationContext);
            xmlReader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_XSD);
            xmlReader.setBeanClassLoader(classLoader);

            for (ModuleSource.SpringConfigEntry entry : cfg.getModuleSource().getSpringConfigs(runtime.getMode())) {
                InputStream is = entry.getStream();
                try {
                    xmlReader.loadBeanDefinitions(new InputStreamResource(is, entry.getLocation() + " in " + cfg.getDefinition().getFile().getAbsolutePath()));
                } finally {
                    IOUtils.closeQuietly(is, entry.getLocation());
                }
            }
            applicationContext.refresh();

            // Handle the service exports
            for (SpringBuildContext.JavaServiceExport entry : springBuildContext.getExportedJavaServices()) {
                Class serviceType = entry.serviceType;
                if (!serviceType.isInterface()) {
                    throw new LilyRTException("Exported service is not an interface: " + serviceType.getName());
                }

                String beanName = entry.beanName;
                Object component;
                try {
                    component = applicationContext.getBean(beanName);
                } catch (NoSuchBeanDefinitionException e) {
                    throw new LilyRTException("Bean not found for service to export, service type " + serviceType.getName() + ", bean name " + beanName, e);
                }

                if (!serviceType.isAssignableFrom(component.getClass())) {
                    throw new LilyRTException("Exported service does not implemented specified type interface. Bean = " + beanName + ", interface = " + serviceType.getName());
                }

                infolog.debug(" exporting bean " + beanName + " for service " + serviceType.getName());
                Object service = shieldJavaService(serviceType, component, module, classLoader);
                runtime.getJavaServiceManager().addService(serviceType, cfg.getId(), entry.name, service);
            }

            module.start();
            return module;
        } catch (Throwable e) {
            // TODO module source and classloader handle might need disposing!
            // especially important if the lily runtime is launched as part of a longer-living VM
            throw new LilyRTException("Error constructing module defined at " + cfg.getDefinition().getFile().getAbsolutePath(), e);
        } finally {
            Thread.currentThread().setContextClassLoader(previousContextClassLoader);
            SPRING_BUILD_CONTEXT.set(null);
        }
    }

    /**
     * Wraps the bean to assure only that only methods of the published service
     * can be accessed.
     */
    private Object shieldJavaService(Class serviceInterface, Object bean, Module module, ClassLoader classLoader) {
        JavaServiceShield handler = new JavaServiceShield(bean, module, serviceInterface, classLoader);
        return Proxy.newProxyInstance(classLoader, new Class[] { serviceInterface }, handler);
    }
}
TOP

Related Classes of org.lilyproject.runtime.module.build.ModuleBuilder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.