001 /***************************************************************************** 002 * Copyright (C) PicoContainer 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.picocontainer.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.NativeJavaObject; 021 import org.mozilla.javascript.RhinoException; 022 import org.mozilla.javascript.Scriptable; 023 import org.picocontainer.PicoContainer; 024 import org.picocontainer.script.LifecycleMode; 025 import org.picocontainer.script.ScriptedPicoContainerMarkupException; 026 import org.picocontainer.script.ScriptedContainerBuilder; 027 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 this(script,classLoader, LifecycleMode.AUTO_LIFECYCLE); 045 } 046 047 public JavascriptContainerBuilder(Reader script, ClassLoader classLoader, LifecycleMode lifecycleMode) { 048 super(script, classLoader, lifecycleMode); 049 } 050 051 public JavascriptContainerBuilder(URL script, ClassLoader classLoader) { 052 this(script,classLoader, LifecycleMode.AUTO_LIFECYCLE); 053 } 054 055 public JavascriptContainerBuilder(URL script, ClassLoader classLoader, LifecycleMode lifecycleMode) { 056 super(script, classLoader, lifecycleMode); 057 } 058 059 protected PicoContainer createContainerFromScript(PicoContainer parentContainer, Object assemblyScope) { 060 final ClassLoader loader = getClassLoader(); 061 Context cx = new Context() { 062 public GeneratedClassLoader createClassLoader(ClassLoader parent) { 063 return new DefiningClassLoader(loader); 064 } 065 }; 066 cx = Context.enter(cx); 067 068 try { 069 Scriptable scope = new ImporterTopLevel(cx); 070 scope.put("parent", scope, parentContainer); 071 scope.put("assemblyScope", scope, assemblyScope); 072 cx.evaluateReader(scope, getScriptReader(), "picocontainer.js", 1, null); 073 Object pico = scope.get("pico", scope); 074 075 if (pico == null) { 076 throw new ScriptedPicoContainerMarkupException("The script must define a variable named 'pico'"); 077 } 078 if (!(pico instanceof NativeJavaObject)) { 079 throw new ScriptedPicoContainerMarkupException("The 'pico' variable must be of type " + NativeJavaObject.class.getName()); 080 } 081 Object javaObject = ((NativeJavaObject) pico).unwrap(); 082 if (!(javaObject instanceof PicoContainer)) { 083 throw new ScriptedPicoContainerMarkupException("The 'pico' variable must be of type " + PicoContainer.class.getName()); 084 } 085 return (PicoContainer) javaObject; 086 } catch (ScriptedPicoContainerMarkupException e) { 087 throw e; 088 } catch (RhinoException e) { 089 StringBuilder message = new StringBuilder(); 090 message.append("There was an error in script '"); 091 message.append(e.sourceName()); 092 message.append("'. Line number: "); 093 message.append(e.lineNumber()); 094 message.append(" and Column number: "); 095 message.append(e.columnNumber()); 096 message.append(" ."); 097 throw new ScriptedPicoContainerMarkupException(message.toString(), e); 098 } catch (IOException e) { 099 throw new ScriptedPicoContainerMarkupException("IOException encountered, message -'" + e.getMessage() + "'", e); 100 } finally { 101 Context.exit(); 102 } 103 } 104 }