Package org.nanocontainer.deployer

Source Code of org.nanocontainer.deployer.NanoContainerDeployer

/*****************************************************************************
* 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: 2343 $
*/
package org.nanocontainer.deployer;

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

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.integrationkit.ContainerBuilder;
import org.nanocontainer.script.ScriptedContainerBuilderFactory;
import org.picocontainer.defaults.ObjectReference;
import org.picocontainer.defaults.SimpleReference;

/**
* 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 {

    /**
     * VFS file system manager.
     */
    private final FileSystemManager fileSystemManager;

    /**
     * File system basename.  Defaults to 'nanocontainer'.  May be set differently
     * for other applications.
     */
    private final String fileBasename;

    /**
     * Constructs a nanocontainer deployer with the specified file system manager.
     * @param fileSystemManager A VFS FileSystemManager.
     */
    public NanoContainerDeployer(final FileSystemManager fileSystemManager) {
        this(fileSystemManager,"nanocontainer");
    }

    /**
     * Constructs a nanocontainer deployer with the specified file system manager
     * and specifies a 'base name' for the configuration file that will be loaded.
     * @param fileSystemManager A VFS FileSystemManager.
     */
    public NanoContainerDeployer(final FileSystemManager fileSystemManager, String baseFileName) {
        this.fileSystemManager = fileSystemManager;
        fileBasename = baseFileName;
    }


    /**
     * 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);

        if (builderClassName == null) {
          throw new FileSystemException("Could not find a suitable builder for: " + deploymentScript.getName()
              + ".  Known extensions are: [groovy|bsh|js|py|xml]");
        }

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

        return result;
    }

    /**
     * Given the base application folder, return a file object that represents the
     * nanocontainer configuration script.
     * @param applicationFolder FileObject
     * @return FileObject
     * @throws FileSystemException
     */
    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(getFileBasename());
            }

            public boolean traverseDescendents(FileSelectInfo fileSelectInfo) throws Exception {
              //
              //nanocontainer.* can easily be deep inside a directory tree and
              //we end up not picking up our desired script.
              //
              if (fileSelectInfo.getDepth() > 1) {
                return false;
              } else {
                return true;
              }
            }
        });

        if(nanocontainerScripts == null || nanocontainerScripts.length < 1) {
            throw new FileSystemException("No deployment script ("+ getFileBasename() +".[groovy|bsh|js|py|xml]) in " + applicationFolder.getName().getPath() + "/META-INF");
        }

        if (nanocontainerScripts.length == 1) {
          return nanocontainerScripts[0];
        } else {
          throw new FileSystemException("Found more than one candidate config script in : " + applicationFolder.getName().getPath() + "/META-INF."
              + "Please only have one " + getFileBasename() + ".[groovy|bsh|js|py|xml] this directory.");
        }

    }


    /**
     * Retrieve the file base name.
     * @return String
     */
    public String getFileBasename() {
        return fileBasename;
    }
}
TOP

Related Classes of org.nanocontainer.deployer.NanoContainerDeployer

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.