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 }