001 /*****************************************************************************
002 * Copyright (C) NanoContainer Organization. All rights reserved. *
003 * ------------------------------------------------------------------------- *
004 * The software in this package is published under the terms of the BSD *
005 * style license a copy of which has been included with this distribution in *
006 * the LICENSE.txt file. *
007 * *
008 *****************************************************************************/
009
010 package org.nanocontainer.script;
011
012 import java.io.File;
013 import java.io.FileNotFoundException;
014 import java.io.FileReader;
015 import java.io.IOException;
016 import java.io.Reader;
017 import java.net.URL;
018 import org.nanocontainer.DefaultNanoContainer;
019 import org.picocontainer.ComponentAdapter;
020 import org.picocontainer.defaults.DefaultPicoContainer;
021
022 /**
023 * The main class for configuration of PicoContainer with various scripting languages.
024 * When using the constructors taking a file, the extensions must be one of the following:
025 * <ul>
026 * <li>.groovy</li>
027 * <li>.bsh</li>
028 * <li>.js</li>
029 * <li>.py</li>
030 * <li>.xml</li>
031 * </ul>
032 * -And the content of the file likewise. See <a href="http://docs.codehaus.org/display/NANO/NanoContainer">NanoContainer documentation</a>
033 * for details.
034 *
035 * @author Paul Hammant
036 * @author Aslak Helles&oslah;y
037 * @author Obie Fernandez
038 * @author Michael Rimov
039 */
040 public class ScriptedContainerBuilderFactory {
041
042 /**
043 * @deprecated Since NanoContainer RC-2. (14-Dec-2005). Use ScriptBuilderResolver.GROOVY
044 * instead.
045 */
046 public static final String GROOVY = ".groovy";
047
048 /**
049 * @deprecated Since NanoContainer RC-2. (14-Dec-2005). Use ScriptBuilderResolver.BEANSHELL
050 * instead.
051 */
052 public static final String BEANSHELL = ".bsh";
053
054 /**
055 * @deprecated Since NanoContainer RC-2. (14-Dec-2005). Use ScriptBuilderResolver.JAVASCRIPT
056 * instead.
057 */
058 public static final String JAVASCRIPT = ".js";
059
060 /**
061 * @deprecated Since NanoContainer RC-2. (14-Dec-2005). Use ScriptBuilderResolver.JYTHON
062 * instead.
063 */
064 public static final String JYTHON = ".py";
065
066 /**
067 * @deprecated Since NanoContainer RC-2. (14-Dec-2005). Use ScriptBuilderResolver.XML
068 * instead.
069 */
070 public static final String XML = ".xml";
071
072
073 private ScriptedContainerBuilder containerBuilder;
074
075
076
077 public ScriptedContainerBuilderFactory(File compositionFile, ClassLoader classLoader) throws IOException, ClassNotFoundException {
078 this(compositionFile, classLoader, new ScriptBuilderResolver());
079 }
080
081 /**
082 * Added since Nano RC-2. This allows you to add/modify registered builders to replace
083 * script handling or add new extensions by modifying a constructed ScriptBuilderResolver
084 * before constructing this object.
085 * @param compositionFile File The script file.
086 * @param classLoader ClassLoader for class resolution once we resolve what the name of the
087 * builder should be..
088 * @param builderClassResolver ScriptBuilderResolver the resolver for figuring out
089 * file names to container builder class names.
090 * @throws IOException upon java.io.File name resolution error.
091 * @throws ClassNotFoundException If there is an error loading
092 * the specified builder using the specified classloader.
093 * @throws UnsupportedScriptTypeException if the extension of the file
094 * does not match that of any known script.
095 */
096 public ScriptedContainerBuilderFactory(File compositionFile, ClassLoader classLoader, ScriptBuilderResolver builderClassResolver) throws IOException, ClassNotFoundException ,UnsupportedScriptTypeException {
097 this(new FileReader(fileExists(compositionFile)), builderClassResolver.getBuilderClassName(compositionFile), classLoader);
098 }
099
100
101 public ScriptedContainerBuilderFactory(File compositionFile) throws IOException, ClassNotFoundException {
102 this(compositionFile, Thread.currentThread().getContextClassLoader());
103 }
104
105 public ScriptedContainerBuilderFactory(URL compositionURL) throws ClassNotFoundException {
106 this(compositionURL, Thread.currentThread().getContextClassLoader(),new ScriptBuilderResolver());
107 }
108
109 /**
110 *
111 * Added since Nano RC-2. This allows you to add/modify registered builders to replace
112 * script handling or add new extensions by modifying a constructed ScriptBuilderResolver
113 * before constructing this object.
114 * @param compositionURL The script URL.
115 * @param builderClassResolver ScriptBuilderResolver the resolver for figuring out
116 * file names to container builder class names.
117 * @param classLoader ClassLoader for class resolution once we resolve what the name of the
118 * builder should be..
119 * @throws ClassNotFoundException If there is an error loading
120 * the specified builder using the specified classloader.
121 * @throws UnsupportedScriptTypeException if the extension of the file
122 * does not match that of any known script.
123 */
124 public ScriptedContainerBuilderFactory(URL compositionURL, ClassLoader classLoader, ScriptBuilderResolver builderClassResolver) throws ClassNotFoundException ,UnsupportedScriptTypeException {
125 this(compositionURL, builderClassResolver.getBuilderClassName(compositionURL), classLoader);
126 }
127
128
129 public ScriptedContainerBuilderFactory(URL compositionURL, String builderClassName, ClassLoader contextClassLoader) throws ClassNotFoundException {
130 createContainerBuilder(compositionURL, contextClassLoader, builderClassName);
131 }
132
133
134 public ScriptedContainerBuilderFactory(Reader composition, String builderClass) throws ClassNotFoundException {
135 this(composition, builderClass, Thread.currentThread().getContextClassLoader());
136 }
137
138 /**
139 * Allows you to create a factory that isntantiats the builder class you desire.
140 * @param composition Reader the script you wish to create the builder for.
141 * @param builderClass String the builder class that instantiate.
142 * @param classLoader ClassLoader the classloader to use for instantiation.
143 * @throws ClassNotFoundException if the specified class cannot be found.
144 */
145 public ScriptedContainerBuilderFactory(Reader composition, String builderClass, ClassLoader classLoader) throws ClassNotFoundException {
146 createContainerBuilder(composition, classLoader, builderClass);
147 }
148
149
150 /**
151 * Performs the actual instantiation of the builder.
152 * @param composition Object Either a URL or a File, it doesn't matter which here.
153 * @param classLoader ClassLoader the classloader ot use for classname resolution
154 * and loading.
155 * @param builderClass String the builder class to load.
156 * @throws ClassNotFoundException if the specified builder class cannot be loaded.
157 */
158 private void createContainerBuilder(Object composition, ClassLoader classLoader, String builderClass) throws ClassNotFoundException {
159 DefaultNanoContainer defaultNanoContainer;
160 {
161 // transient.
162 DefaultPicoContainer factory = new DefaultPicoContainer();
163 if(composition == null) {
164 throw new NullPointerException("composition can't be null");
165 }
166 factory.registerComponentInstance(composition);
167
168 if(classLoader == null) {
169 // on some weird JVMs (like jeode) Thread.currentThread().getContextClassLoader() returns null !?!?
170 //Found out on JDK 1.5 javadocs that Thread.currentThread().getContextClassLoader() MAY return null
171 //while Class.getClassLoader() should NEVER return null. -MR
172 //
173 //
174 classLoader = getClass().getClassLoader();
175 }
176 factory.registerComponentInstance(classLoader);
177
178 //
179 //If we don't specify the classloader here, some of the things that make
180 //up a nanocontainer may bomb. And we're only talking a reload
181 //within a webapp! -MR
182 //
183 defaultNanoContainer = new DefaultNanoContainer(classLoader,factory);
184 }
185 ComponentAdapter componentAdapter = defaultNanoContainer.registerComponentImplementation(builderClass);
186 containerBuilder = (ScriptedContainerBuilder) componentAdapter.getComponentInstance(defaultNanoContainer.getPico());
187 }
188
189 private static File fileExists(final File file) throws FileNotFoundException {
190 if (file.exists()) {
191 return file;
192 } else {
193 //todo a proper exception.
194 throw new FileNotFoundException("File " + file.getAbsolutePath() + " does not exist.");
195 }
196 }
197
198 /**
199 * This function does not support custom file type resolving -- for backwards
200 * compatibility, it uses a fresh instance of ScriptBuilderResolver for
201 * each invocation. Use ScriptBuilderResolver instead.
202 * @param extension String the file extension to res
203 * @return String the classname to use for the specified extension.
204 * @deprecated Since NanoContainer 1.0 RC-2. Use the class ScriptBuilderResolver
205 * for this functionality.
206 */
207 public static String getBuilderClassName(final String extension) {
208 return new ScriptBuilderResolver().getBuilderClassName(extension);
209 }
210
211
212 /**
213 * Retrieve the created container builder instance.
214 * @return ScriptedContainerBuilder instance, never null.
215 */
216 public ScriptedContainerBuilder getContainerBuilder() {
217 return containerBuilder;
218 }
219
220 }