1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18 package org.apache.tools.ant.util.optional;
19
20 import org.apache.bsf.BSFException;
21 import org.apache.bsf.BSFManager;
22 import org.apache.bsf.BSFEngine;
23
24 import java.util.Iterator;
25 import java.util.Hashtable;
26
27 import org.apache.tools.ant.BuildException;
28 import org.apache.tools.ant.Project;
29
30 import org.apache.tools.ant.util.ReflectUtil;
31 import org.apache.tools.ant.util.ScriptRunnerBase;
32
33 /**
34 * This class is used to run BSF scripts
35 *
36 */
37 public class ScriptRunner extends ScriptRunnerBase {
38 // Register Groovy ourselves, since BSF did not
39 // natively support it in versions previous to 1.2.4.
40 static {
41 BSFManager.registerScriptingEngine(
42 "groovy",
43 "org.codehaus.groovy.bsf.GroovyEngine",
44 new String[] {"groovy", "gy"});
45 }
46
47 private BSFEngine engine;
48 private BSFManager manager;
49
50 /**
51 * Get the name of the manager prefix.
52 * @return "bsf"
53 */
54 public String getManagerName() {
55 return "bsf";
56 }
57
58 /**
59 * Check if bsf supports the language.
60 * @return true if bsf can create an engine for this language.
61 */
62 public boolean supportsLanguage() {
63 Hashtable table = (Hashtable) ReflectUtil.getField(
64 new BSFManager(), "registeredEngines");
65 String engineClassName = (String) table.get(getLanguage());
66 if (engineClassName == null) {
67 getProject().log(
68 "This is no BSF engine class for language '"
69 + getLanguage() + "'",
70 Project.MSG_VERBOSE);
71 return false;
72 }
73 try {
74 getScriptClassLoader().loadClass(engineClassName);
75 return true;
76 } catch (Throwable ex) {
77 getProject().log(
78 "unable to create BSF engine class for language '"
79 + getLanguage() + "'",
80 ex,
81 Project.MSG_VERBOSE);
82 return false;
83 }
84 }
85
86 /**
87 * Do the work.
88 *
89 * @param execName the name that will be passed to BSF for this script execution.
90 * @exception BuildException if something goes wrong executing the script.
91 */
92 public void executeScript(String execName) throws BuildException {
93 checkLanguage();
94 ClassLoader origLoader = replaceContextLoader();
95 try {
96 BSFManager m = createManager();
97 declareBeans(m);
98 // execute the script
99 if (engine == null) {
100 m.exec(getLanguage(), execName, 0, 0, getScript());
101 } else {
102 engine.exec(execName, 0, 0, getScript());
103 }
104 } catch (BSFException be) {
105 throw getBuildException(be);
106 } finally {
107 restoreContextLoader(origLoader);
108 }
109 }
110
111 /**
112 * Evaluate the script.
113 *
114 * @param execName the name that will be passed to BSF for this script execution.
115 * @return the result of the evaluation
116 * @exception BuildException if something goes wrong executing the script.
117 */
118 public Object evaluateScript(String execName) throws BuildException {
119 checkLanguage();
120 ClassLoader origLoader = replaceContextLoader();
121 try {
122 BSFManager m = createManager();
123 declareBeans(m);
124 // execute the script
125 if (engine == null) {
126 return m.eval(getLanguage(), execName, 0, 0, getScript());
127 }
128 return engine.eval(execName, 0, 0, getScript());
129 } catch (BSFException be) {
130 throw getBuildException(be);
131 } finally {
132 restoreContextLoader(origLoader);
133 }
134 }
135
136 /**
137 * Get/create a BuildException from a BSFException.
138 * @param be BSFException to convert.
139 * @return BuildException the converted exception.
140 */
141 private BuildException getBuildException(BSFException be) {
142 Throwable t = be;
143 Throwable te = be.getTargetException();
144 if (te instanceof BuildException) {
145 return (BuildException) te;
146 }
147 return new BuildException(te == null ? t : te);
148 }
149
150 private void declareBeans(BSFManager m) throws BSFException {
151 for (Iterator i = getBeans().keySet().iterator(); i.hasNext();) {
152 String key = (String) i.next();
153 Object value = getBeans().get(key);
154 if (value != null) {
155 m.declareBean(key, value, value.getClass());
156 } else {
157 // BSF uses a hashtable to store values
158 // so cannot declareBean with a null value
159 // So need to remove any bean of this name as
160 // that bean should not be visible
161 m.undeclareBean(key);
162 }
163 }
164 }
165
166 private BSFManager createManager() throws BSFException {
167 if (manager != null) {
168 return manager;
169 }
170 BSFManager m = new BSFManager();
171 m.setClassLoader(getScriptClassLoader());
172 if (getKeepEngine()) {
173 BSFEngine e = manager.loadScriptingEngine(getLanguage());
174 this.manager = m;
175 this.engine = e;
176 }
177 return m;
178 }
179 }