org.nanocontainer.deployer.NanoContainerDeployer.java Source code

Java tutorial

Introduction

Here is the source code for org.nanocontainer.deployer.NanoContainerDeployer.java

Source

/*****************************************************************************
 * Copyright (C) NanoContainer Organization. All rights reserved.            *
 * ------------------------------------------------------------------------- *
 * The software in this package is published under the terms of the BSD      *
 * style license a copy of which has been included with this distribution in *
 * the LICENSE.txt file.                                                     *
 *                                                                           *
 * Original code by                                                          *
 *****************************************************************************/

/**
 * @author Aslak Hellesøy
 * @version $Revision$
 */
package org.nanocontainer.deployer;

import org.apache.commons.vfs.FileObject;
import org.apache.commons.vfs.FileSelectInfo;
import org.apache.commons.vfs.FileSelector;
import org.apache.commons.vfs.FileSystemException;
import org.apache.commons.vfs.FileSystemManager;
import org.apache.commons.vfs.impl.VFSClassLoader;
import org.nanocontainer.script.ScriptedContainerBuilderFactory;
import org.nanocontainer.script.ScriptedContainerBuilderFactory;
import org.nanocontainer.integrationkit.ContainerBuilder;
import org.picocontainer.defaults.ObjectReference;
import org.picocontainer.defaults.SimpleReference;

import java.io.InputStreamReader;
import java.io.Reader;

/**
 * This class is capable of deploying an application from any kind of file system
 * supported by <a href="http://jakarta.apache.org/commons/sandbox/vfs/">Jakarta VFS</a>.
 * (Like local files, zip files etc.) - following the ScriptedContainerBuilderFactory scripting model.
 *
 * The root folder to deploy must have the following file structure:
 * <pre>
 * +-someapp/
 *   +-META-INF/
 *   | +-nanocontainer.[py|js|xml|bsh]
 *   +-com/
 *     +-blablah/
 *       +-Hip.class
 *       +-Hop.class
 * </pre>
 *
 * For those familiar with J2EE containers (or other containers for that matter), the
 * META-INF/picocontainer script is the ScriptedContainerBuilderFactory <em>composition script</em>. It plays the same
 * role as more classical "deployment descriptors", except that deploying via a full blown
 * scripting language is a lot more powerful!
 *
 * A new class loader (which will be a child of parentClassLoader) will be created. This classloader will make
 * the classes under the root folder available to the deployment script.
 *
 * IMPORTANT NOTE:
 * The scripting engine (rhino, jython, groovy etc.) should be loaded by the same classLoader as
 * the appliacation classes, i.e. the VFSClassLoader pointing to the app directory.
 *
 * <pre>
 *    +-------------------+
 *    | xxx               |  <-- parent app loader (must not contain classes from app builder classloader)
 *    +-------------------+
 *              |
 *    +-------------------+
 *    | someapp           | <-- app classloader (must not contain classes from app builder classloader)
 *    +-------------------+
 *              |
 *    +-------------------+
 *    | picocontainer     |
 *    | nanocontainer     |  <-- app builder classloader
 *    | rhino             |
 *    | jython            |
 *    | groovy            |
 *    +-------------------+
 * </pre>
 *
 * This means that these scripting engines should *not* be accessible by any of the app classloader, since this
 * may prevent the scripting engine from seeing the classes loaded by the VFSClassLoader. In other words,
 * the scripting engine classed may be loaded several times by different class loaders - once for each
 * deployed application.
 *
 * @author Aslak Helles&oslash;y
 */
public class NanoContainerDeployer implements Deployer {
    private final FileSystemManager fileSystemManager;

    public NanoContainerDeployer(FileSystemManager fileSystemManager) {
        this.fileSystemManager = fileSystemManager;
    }

    /**
     * Deploys an application.
     *
     * @param applicationFolder the root applicationFolder of the application.
     * @param parentClassLoader the classloader that loads the application classes.
     * @param parentContainerRef reference to the parent container (can be used to lookup components form a parent container).
     * @return an ObjectReference holding a PicoContainer with the deployed components
     * @throws org.apache.commons.vfs.FileSystemException if the file structure was bad.
     * @throws org.nanocontainer.integrationkit.PicoCompositionException if the deployment failed for some reason.
     */
    public ObjectReference deploy(FileObject applicationFolder, ClassLoader parentClassLoader,
            ObjectReference parentContainerRef) throws FileSystemException, ClassNotFoundException {
        ClassLoader applicationClassLoader = new VFSClassLoader(applicationFolder, fileSystemManager,
                parentClassLoader);

        FileObject deploymentScript = getDeploymentScript(applicationFolder);

        ObjectReference result = new SimpleReference();

        String extension = "." + deploymentScript.getName().getExtension();
        Reader scriptReader = new InputStreamReader(deploymentScript.getContent().getInputStream());
        String builderClassName = ScriptedContainerBuilderFactory.getBuilderClassName(extension);

        ScriptedContainerBuilderFactory scriptedContainerBuilderFactory = new ScriptedContainerBuilderFactory(
                scriptReader, builderClassName, applicationClassLoader);
        ContainerBuilder builder = scriptedContainerBuilderFactory.getContainerBuilder();
        builder.buildContainer(result, parentContainerRef, null, true);

        return result;
    }

    private FileObject getDeploymentScript(FileObject applicationFolder) throws FileSystemException {
        final FileObject metaInf = applicationFolder.getChild("META-INF");
        if (metaInf == null) {
            throw new FileSystemException("Missing META-INF folder in " + applicationFolder.getName().getPath());
        }
        final FileObject[] nanocontainerScripts = metaInf.findFiles(new FileSelector() {
            public boolean includeFile(FileSelectInfo fileSelectInfo) throws Exception {
                return fileSelectInfo.getFile().getName().getBaseName().startsWith("nanocontainer");
            }

            public boolean traverseDescendents(FileSelectInfo fileSelectInfo) throws Exception {
                return true;
            }
        });
        if (nanocontainerScripts == null || nanocontainerScripts.length < 1) {
            throw new FileSystemException("No deployment script (nanocontainer.[groovy|bsh|js|py|xml]) in "
                    + applicationFolder.getName().getPath() + "/META-INF");
        }
        return nanocontainerScripts[0];
    }
}