KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > nanocontainer > deployer > NanoContainerDeployer


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

10
11 /**
12  * @author Aslak Hellesøy
13  * @version $Revision: 2947 $
14  */

15 package org.nanocontainer.deployer;
16
17 import java.io.InputStreamReader JavaDoc;
18 import java.io.Reader JavaDoc;
19
20 import org.apache.commons.vfs.FileObject;
21 import org.apache.commons.vfs.FileSelectInfo;
22 import org.apache.commons.vfs.FileSelector;
23 import org.apache.commons.vfs.FileSystemException;
24 import org.apache.commons.vfs.FileSystemManager;
25 import org.apache.commons.vfs.impl.VFSClassLoader;
26 import org.apache.commons.vfs.VFS;
27 import org.nanocontainer.integrationkit.ContainerBuilder;
28 import org.nanocontainer.script.ScriptedContainerBuilderFactory;
29 import org.picocontainer.defaults.ObjectReference;
30 import org.picocontainer.defaults.SimpleReference;
31 import org.nanocontainer.script.UnsupportedScriptTypeException;
32 import org.nanocontainer.script.ScriptBuilderResolver;
33
34 /**
35  * This class is capable of deploying an application from any kind of file system
36  * supported by <a HREF="http://jakarta.apache.org/commons/sandbox/vfs/">Jakarta VFS</a>.
37  * (Like local files, zip files etc.) - following the ScriptedContainerBuilderFactory scripting model.
38  *
39  * The root folder to deploy must have the following file structure:
40  * <pre>
41  * +-someapp/
42  * +-META-INF/
43  * | +-nanocontainer.[py|js|xml|bsh]
44  * +-com/
45  * +-blablah/
46  * +-Hip.class
47  * +-Hop.class
48  * </pre>
49  *
50  * For those familiar with J2EE containers (or other containers for that matter), the
51  * META-INF/picocontainer script is the ScriptedContainerBuilderFactory <em>composition script</em>. It plays the same
52  * role as more classical "deployment descriptors", except that deploying via a full blown
53  * scripting language is a lot more powerful!
54  *
55  * A new class loader (which will be a child of parentClassLoader) will be created. This classloader will make
56  * the classes under the root folder available to the deployment script.
57  *
58  * IMPORTANT NOTE:
59  * The scripting engine (rhino, jython, groovy etc.) should be loaded by the same classLoader as
60  * the appliacation classes, i.e. the VFSClassLoader pointing to the app directory.
61  *
62  * <pre>
63  * +-------------------+
64  * | xxx | <-- parent app loader (must not contain classes from app builder classloader)
65  * +-------------------+
66  * |
67  * +-------------------+
68  * | someapp | <-- app classloader (must not contain classes from app builder classloader)
69  * +-------------------+
70  * |
71  * +-------------------+
72  * | picocontainer |
73  * | nanocontainer | <-- app builder classloader
74  * | rhino |
75  * | jython |
76  * | groovy |
77  * +-------------------+
78  * </pre>
79  *
80  * This means that these scripting engines should *not* be accessible by any of the app classloader, since this
81  * may prevent the scripting engine from seeing the classes loaded by the VFSClassLoader. In other words,
82  * the scripting engine classed may be loaded several times by different class loaders - once for each
83  * deployed application.
84  *
85  * @author Aslak Helles&oslash;y
86  */

87 public class NanoContainerDeployer implements Deployer {
88
89     /**
90      * VFS file system manager.
91      */

92     private final FileSystemManager fileSystemManager;
93
94     /**
95      * File system basename. Defaults to 'nanocontainer'. May be set differently
96      * for other applications.
97      */

98     private final String JavaDoc fileBasename;
99
100
101     /**
102      * File Name to builder class name resolver.
103      */

104     private ScriptBuilderResolver resolver;
105
106
107     /**
108      * Default constructor that makes sensible defaults.
109      * @throws FileSystemException
110      */

111     public NanoContainerDeployer() throws FileSystemException {
112         this(VFS.getManager(), new ScriptBuilderResolver());
113     }
114
115     /**
116      * Constructs a nanocontainer deployer with the specified file system manager.
117      * @param fileSystemManager A VFS FileSystemManager.
118      */

119     public NanoContainerDeployer(final FileSystemManager fileSystemManager) {
120         this(fileSystemManager,"nanocontainer");
121     }
122
123
124     /**
125      * Constructs this object with both a VFS file system manager, and
126      * @param fileSystemManager FileSystemManager
127      * @param builderResolver ScriptBuilderResolver
128      */

129     public NanoContainerDeployer(final FileSystemManager fileSystemManager, ScriptBuilderResolver builderResolver) {
130         this(fileSystemManager);
131         resolver = builderResolver;
132     }
133
134     /**
135      * Constructs a nanocontainer deployer with the specified file system manager
136      * and specifies a 'base name' for the configuration file that will be loaded.
137      * @param fileSystemManager A VFS FileSystemManager.
138      * @todo Deprecate this and replace 'base file name' with the concept
139      * of a ArchiveLayout that defines where jars are stored, where the composition
140      * script is stored, etc.
141      */

142     public NanoContainerDeployer(final FileSystemManager fileSystemManager, String JavaDoc baseFileName) {
143         this.fileSystemManager = fileSystemManager;
144         fileBasename = baseFileName;
145         resolver = new ScriptBuilderResolver();
146     }
147
148
149     /**
150      * Deploys an application.
151      *
152      * @param applicationFolder the root applicationFolder of the application.
153      * @param parentClassLoader the classloader that loads the application classes.
154      * @param parentContainerRef reference to the parent container (can be used to lookup components form a parent container).
155      * @return an ObjectReference holding a PicoContainer with the deployed components
156      * @throws org.apache.commons.vfs.FileSystemException if the file structure was bad.
157      * @throws org.nanocontainer.integrationkit.PicoCompositionException if the deployment failed for some reason.
158      */

159     public ObjectReference deploy(FileObject applicationFolder, ClassLoader JavaDoc parentClassLoader, ObjectReference parentContainerRef) throws FileSystemException, ClassNotFoundException JavaDoc {
160         return deploy(applicationFolder, parentClassLoader, parentContainerRef, null);
161     }
162
163     public ObjectReference deploy(FileObject applicationFolder, ClassLoader JavaDoc parentClassLoader, ObjectReference parentContainerRef, Object JavaDoc assemblyScope) throws FileSystemException, ClassNotFoundException JavaDoc {
164         ClassLoader JavaDoc applicationClassLoader = new VFSClassLoader(applicationFolder, fileSystemManager, parentClassLoader);
165
166         FileObject deploymentScript = getDeploymentScript(applicationFolder);
167
168         ObjectReference result = new SimpleReference();
169
170         String JavaDoc extension = "." + deploymentScript.getName().getExtension();
171         Reader JavaDoc scriptReader = new InputStreamReader JavaDoc(deploymentScript.getContent().getInputStream());
172         String JavaDoc builderClassName = null;
173         try {
174             builderClassName = resolver.getBuilderClassName(extension);
175         } catch (UnsupportedScriptTypeException ex) {
176             throw new FileSystemException("Could not find a suitable builder for: " + deploymentScript.getName()
177                 + ". Known extensions are: [groovy|bsh|js|py|xml]", ex);
178         }
179
180
181         ScriptedContainerBuilderFactory scriptedContainerBuilderFactory = new ScriptedContainerBuilderFactory(scriptReader, builderClassName, applicationClassLoader);
182         ContainerBuilder builder = scriptedContainerBuilderFactory.getContainerBuilder();
183         builder.buildContainer(result, parentContainerRef, assemblyScope, true);
184
185         return result;
186
187     }
188
189
190
191
192     /**
193      * Given the base application folder, return a file object that represents the
194      * nanocontainer configuration script.
195      * @param applicationFolder FileObject
196      * @return FileObject
197      * @throws FileSystemException
198      */

199     protected FileObject getDeploymentScript(FileObject applicationFolder) throws FileSystemException {
200         final FileObject metaInf = applicationFolder.getChild("META-INF");
201         if(metaInf == null) {
202             throw new FileSystemException("Missing META-INF folder in " + applicationFolder.getName().getPath());
203         }
204         final FileObject[] nanocontainerScripts = metaInf.findFiles(new FileSelector(){
205
206             public boolean includeFile(FileSelectInfo fileSelectInfo) throws Exception JavaDoc {
207                 return fileSelectInfo.getFile().getName().getBaseName().startsWith(getFileBasename());
208             }
209
210             public boolean traverseDescendents(FileSelectInfo fileSelectInfo) throws Exception JavaDoc {
211               //
212
//nanocontainer.* can easily be deep inside a directory tree and
213
//we end up not picking up our desired script.
214
//
215
if (fileSelectInfo.getDepth() > 1) {
216                 return false;
217               } else {
218                 return true;
219               }
220             }
221         });
222
223         if(nanocontainerScripts == null || nanocontainerScripts.length < 1) {
224             throw new FileSystemException("No deployment script ("+ getFileBasename() +".[groovy|bsh|js|py|xml]) in " + applicationFolder.getName().getPath() + "/META-INF");
225         }
226
227         if (nanocontainerScripts.length == 1) {
228           return nanocontainerScripts[0];
229         } else {
230           throw new FileSystemException("Found more than one candidate config script in : " + applicationFolder.getName().getPath() + "/META-INF."
231               + "Please only have one " + getFileBasename() + ".[groovy|bsh|js|py|xml] this directory.");
232         }
233
234     }
235
236
237     /**
238      * Retrieve the file base name.
239      * @return String
240      */

241     public String JavaDoc getFileBasename() {
242         return fileBasename;
243     }
244 }
245
Popular Tags