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 * Original code by * 009 *****************************************************************************/ 010 package org.nanocontainer.script.rhino; 011 012 import java.io.IOException; 013 import java.io.Reader; 014 import java.net.URL; 015 016 import org.mozilla.javascript.Context; 017 import org.mozilla.javascript.DefiningClassLoader; 018 import org.mozilla.javascript.GeneratedClassLoader; 019 import org.mozilla.javascript.ImporterTopLevel; 020 import org.mozilla.javascript.JavaScriptException; 021 import org.mozilla.javascript.NativeJavaObject; 022 import org.mozilla.javascript.NativeJavaPackage; 023 import org.mozilla.javascript.Script; 024 import org.mozilla.javascript.Scriptable; 025 import org.nanocontainer.script.NanoContainerMarkupException; 026 import org.nanocontainer.script.ScriptedContainerBuilder; 027 import org.picocontainer.PicoContainer; 028 029 /** 030 * {@inheritDoc} 031 * The script has to assign a "pico" variable with an instance of 032 * {@link PicoContainer}. 033 * There is an implicit variable named "parent" that may contain a reference to a parent 034 * container. It is recommended to use this as a constructor argument to the instantiated 035 * PicoContainer. 036 * 037 * @author Paul Hammant 038 * @author Aslak Hellesøy 039 * @author Mauro Talevi 040 */ 041 public class JavascriptContainerBuilder extends ScriptedContainerBuilder { 042 043 public JavascriptContainerBuilder(Reader script, ClassLoader classLoader) { 044 super(script, classLoader); 045 } 046 047 public JavascriptContainerBuilder(URL script, ClassLoader classLoader) { 048 super(script, classLoader); 049 } 050 051 protected PicoContainer createContainerFromScript(PicoContainer parentContainer, Object assemblyScope) { 052 final ClassLoader loader = getClassLoader(); 053 Context cx = new Context() { 054 public GeneratedClassLoader createClassLoader(ClassLoader parent) { 055 return new DefiningClassLoader(loader); 056 } 057 }; 058 cx = Context.enter(cx); 059 060 try { 061 ImporterTopLevel imp = new ImporterTopLevel(cx); 062 Scriptable scope = imp; 063 scope.put("parent", scope, parentContainer); 064 scope.put("assemblyScope", scope, assemblyScope); 065 imp.importPackage(cx, 066 scope, new NativeJavaPackage[]{ 067 new NativeJavaPackage("org.picocontainer.defaults", loader), 068 new NativeJavaPackage("org.nanocontainer", loader), 069 new NativeJavaPackage("org.nanocontainer.reflection", loader), 070 // File, URL and URLClassLoader will be frequently used by scripts. 071 new NativeJavaPackage("java.net", loader), 072 new NativeJavaPackage("java.io", loader), 073 }, 074 null); 075 Script scriptObject = cx.compileReader(scope, getScriptReader(), "javascript", 1, null); 076 scriptObject.exec(cx, scope); 077 Object pico = scope.get("pico", scope); 078 079 if (pico == null) { 080 throw new NanoContainerMarkupException("The script must define a variable named 'pico'"); 081 } 082 if (!(pico instanceof NativeJavaObject)) { 083 throw new NanoContainerMarkupException("The 'pico' variable must be of type " + NativeJavaObject.class.getName()); 084 } 085 Object javaObject = ((NativeJavaObject) pico).unwrap(); 086 if (!(javaObject instanceof PicoContainer)) { 087 throw new NanoContainerMarkupException("The 'pico' variable must be of type " + PicoContainer.class.getName()); 088 } 089 return (PicoContainer) javaObject; 090 } catch (NanoContainerMarkupException e) { 091 throw e; 092 } catch (JavaScriptException e) { 093 Object value = e.getValue(); 094 if (value instanceof Throwable) { 095 throw new NanoContainerMarkupException((Throwable) value); 096 } else { 097 throw new NanoContainerMarkupException(e); 098 } 099 } catch (IOException e) { 100 throw new NanoContainerMarkupException("IOException encountered, message -'" + e.getMessage() + "'", e); 101 } finally { 102 Context.exit(); 103 } 104 } 105 }