001: /*
002: $Id: GroovyEngine.java 4166 2006-10-25 07:07:33Z paulk $
003:
004: Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
005:
006: Redistribution and use of this software and associated documentation
007: ("Software"), with or without modification, are permitted provided
008: that the following conditions are met:
009:
010: 1. Redistributions of source code must retain copyright
011: statements and notices. Redistributions must also contain a
012: copy of this document.
013:
014: 2. Redistributions in binary form must reproduce the
015: above copyright notice, this list of conditions and the
016: following disclaimer in the documentation and/or other
017: materials provided with the distribution.
018:
019: 3. The name "groovy" must not be used to endorse or promote
020: products derived from this Software without prior written
021: permission of The Codehaus. For written permission,
022: please contact info@codehaus.org.
023:
024: 4. Products derived from this Software may not be called "groovy"
025: nor may "groovy" appear in their names without prior written
026: permission of The Codehaus. "groovy" is a registered
027: trademark of The Codehaus.
028:
029: 5. Due credit should be given to The Codehaus -
030: http://groovy.codehaus.org/
031:
032: THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
033: ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
034: NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
035: FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
036: THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
037: INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
038: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
039: SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
040: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
041: STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
042: ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
043: OF THE POSSIBILITY OF SUCH DAMAGE.
044:
045: */
046: package org.codehaus.groovy.bsf;
047:
048: import groovy.lang.Closure;
049: import groovy.lang.GroovyShell;
050: import org.apache.bsf.BSFDeclaredBean;
051: import org.apache.bsf.BSFException;
052: import org.apache.bsf.BSFManager;
053: import org.apache.bsf.util.BSFEngineImpl;
054: import org.apache.bsf.util.BSFFunctions;
055: import org.codehaus.groovy.runtime.InvokerHelper;
056:
057: import java.util.Vector;
058:
059: /**
060: * A BSF Engine for the <a href="http://groovy.codehaus.org/">Groovy</a>
061: * scripting language.
062: * <p/>
063: * It's derived from the Jython / JPython engine
064: *
065: * @author James Strachan
066: */
067: public class GroovyEngine extends BSFEngineImpl {
068: protected GroovyShell shell;
069:
070: /*
071: * Convert a non java class name to a java classname
072: * This is used to convert a script name to a name
073: * that can be used as a classname with the script is
074: * loaded in GroovyClassloader#load()
075: * The method simply replaces any invalid characters
076: * with "_".
077: */
078: private String convertToValidJavaClassname(String inName) {
079: if (inName == null || inName.equals("")) {
080: return "_";
081: }
082: StringBuffer output = new StringBuffer(inName.length());
083: boolean firstChar = true;
084: for (int i = 0; i < inName.length(); ++i) {
085: char ch = inName.charAt(i);
086: if (firstChar && !Character.isJavaIdentifierStart(ch)) {
087: ch = '_';
088: } else if (!firstChar
089: && !(Character.isJavaIdentifierPart(ch) || ch == '.')) {
090: ch = '_';
091: }
092: firstChar = (ch == '.');
093: output.append(ch);
094: }
095: return output.toString();
096: }
097:
098: /**
099: * Allow an anonymous function to be declared and invoked
100: */
101: public Object apply(String source, int lineNo, int columnNo,
102: Object funcBody, Vector paramNames, Vector arguments)
103: throws BSFException {
104: Object object = eval(source, lineNo, columnNo, funcBody);
105: if (object instanceof Closure) {
106: // lets call the function
107: Closure closure = (Closure) object;
108: return closure.call(arguments.toArray());
109: }
110: return object;
111: }
112:
113: /**
114: * Call the named method of the given object.
115: */
116: public Object call(Object object, String method, Object[] args)
117: throws BSFException {
118: return InvokerHelper.invokeMethod(object, method, args);
119: }
120:
121: /**
122: * Evaluate an expression.
123: */
124: public Object eval(String source, int lineNo, int columnNo,
125: Object script) throws BSFException {
126: try {
127: source = convertToValidJavaClassname(source);
128: return getEvalShell().evaluate(script.toString(), source);
129: } catch (Exception e) {
130: throw new BSFException(BSFException.REASON_EXECUTION_ERROR,
131: "exception from Groovy: " + e, e);
132: }
133: }
134:
135: /**
136: * Execute a script.
137: */
138: public void exec(String source, int lineNo, int columnNo,
139: Object script) throws BSFException {
140: try {
141: // use evaluate to pass in the BSF variables
142: source = convertToValidJavaClassname(source);
143: getEvalShell().evaluate(script.toString(), source);
144: } catch (Exception e) {
145: throw new BSFException(BSFException.REASON_EXECUTION_ERROR,
146: "exception from Groovy: " + e, e);
147: }
148: }
149:
150: /**
151: * Initialize the engine.
152: */
153: public void initialize(BSFManager mgr, String lang,
154: Vector declaredBeans) throws BSFException {
155: super .initialize(mgr, lang, declaredBeans);
156:
157: // create a shell
158: shell = new GroovyShell(mgr.getClassLoader());
159:
160: // register the mgr with object name "bsf"
161: shell.setVariable("bsf", new BSFFunctions(mgr, this ));
162:
163: int size = declaredBeans.size();
164: for (int i = 0; i < size; i++) {
165: declareBean((BSFDeclaredBean) declaredBeans.elementAt(i));
166: }
167: }
168:
169: /**
170: * Declare a bean
171: */
172: public void declareBean(BSFDeclaredBean bean) throws BSFException {
173: shell.setVariable(bean.name, bean.bean);
174: }
175:
176: /**
177: * Undeclare a previously declared bean.
178: */
179: public void undeclareBean(BSFDeclaredBean bean) throws BSFException {
180: shell.setVariable(bean.name, null);
181: }
182:
183: /**
184: * @return a newly created GroovyShell using the same variable scope but a new class loader
185: */
186: protected GroovyShell getEvalShell() {
187: return new GroovyShell(shell);
188: }
189: }
|