001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.tools.ant.util;
019:
020: import java.io.BufferedReader;
021: import java.io.File;
022: import java.io.FileReader;
023: import java.io.IOException;
024:
025: import org.apache.tools.ant.BuildException;
026: import org.apache.tools.ant.ProjectComponent;
027: import org.apache.tools.ant.Project;
028:
029: import java.util.Map;
030: import java.util.HashMap;
031: import java.util.Iterator;
032:
033: /**
034: * This is a common abstract base case for script runners.
035: * These classes need to implement executeScript, evaluateScript
036: * and supportsLanguage.
037: * @since Ant 1.7.0
038: */
039: public abstract class ScriptRunnerBase {
040: /** Whether to keep the engine between calls to execute/eval */
041: private boolean keepEngine = false;
042:
043: /** Script language */
044: private String language;
045:
046: /** Script content */
047: private String script = "";
048:
049: /** Project this runner is used in */
050: private Project project;
051:
052: /** Classloader to be used when running the script. */
053: private ClassLoader scriptLoader;
054:
055: /** Beans to be provided to the script */
056: private Map beans = new HashMap();
057:
058: /**
059: * Add a list of named objects to the list to be exported to the script
060: *
061: * @param dictionary a map of objects to be placed into the script context
062: * indexed by String names.
063: */
064: public void addBeans(Map dictionary) {
065: for (Iterator i = dictionary.keySet().iterator(); i.hasNext();) {
066: String key = (String) i.next();
067: try {
068: Object val = dictionary.get(key);
069: addBean(key, val);
070: } catch (BuildException ex) {
071: // The key is in the dictionary but cannot be retrieved
072: // This is usually due references that refer to tasks
073: // that have not been taskdefed in the current run.
074: // Ignore
075: }
076: }
077: }
078:
079: /**
080: * Add a single object into the script context.
081: *
082: * @param key the name in the context this object is to stored under.
083: * @param bean the object to be stored in the script context.
084: */
085: public void addBean(String key, Object bean) {
086: boolean isValid = key.length() > 0
087: && Character.isJavaIdentifierStart(key.charAt(0));
088:
089: for (int i = 1; isValid && i < key.length(); i++) {
090: isValid = Character.isJavaIdentifierPart(key.charAt(i));
091: }
092:
093: if (isValid) {
094: beans.put(key, bean);
095: }
096: }
097:
098: /**
099: * Get the beans used for the script.
100: * @return the map of beans.
101: */
102: protected Map getBeans() {
103: return beans;
104: }
105:
106: /**
107: * Do the work.
108: * @param execName the name that will be passed to BSF for this script
109: * execution.
110: */
111: public abstract void executeScript(String execName);
112:
113: /**
114: * Evalulate the script.
115: * @param execName the name that will be passed to BSF for this script
116: * execution.
117: * @return the result of evalulating the script.
118: */
119: public abstract Object evaluateScript(String execName);
120:
121: /**
122: * Check if a script engine can be created for
123: * this language.
124: * @return true if a script engine can be created, false
125: * otherwise.
126: */
127: public abstract boolean supportsLanguage();
128:
129: /**
130: * Get the name of the manager prefix used for this
131: * scriptrunner.
132: * @return the prefix string.
133: */
134: public abstract String getManagerName();
135:
136: /**
137: * Defines the language (required).
138: * @param language the scripting language name for the script.
139: */
140: public void setLanguage(String language) {
141: this .language = language;
142: }
143:
144: /**
145: * Get the script language
146: * @return the script language
147: */
148: public String getLanguage() {
149: return language;
150: }
151:
152: /**
153: * Set the script classloader.
154: * @param classLoader the classloader to use.
155: */
156: public void setScriptClassLoader(ClassLoader classLoader) {
157: this .scriptLoader = classLoader;
158: }
159:
160: /**
161: * Get the classloader used to load the script engine.
162: * @return the classloader.
163: */
164: protected ClassLoader getScriptClassLoader() {
165: return scriptLoader;
166: }
167:
168: /**
169: * Whether to keep the script engine between calls.
170: * @param keepEngine if true, keep the engine.
171: */
172: public void setKeepEngine(boolean keepEngine) {
173: this .keepEngine = keepEngine;
174: }
175:
176: /**
177: * Get the keep engine attribute.
178: * @return the attribute.
179: */
180: public boolean getKeepEngine() {
181: return keepEngine;
182: }
183:
184: /**
185: * Load the script from an external file; optional.
186: * @param file the file containing the script source.
187: */
188: public void setSrc(File file) {
189: if (!file.exists()) {
190: throw new BuildException("file " + file.getPath()
191: + " not found.");
192: }
193: BufferedReader in = null;
194: try {
195: in = new BufferedReader(new FileReader(file));
196: script += FileUtils.readFully(in);
197: } catch (IOException ex) {
198: throw new BuildException(ex);
199: } finally {
200: FileUtils.close(in);
201: }
202: }
203:
204: /**
205: * Set the script text.
206: *
207: * @param text a component of the script text to be added.
208: */
209: public void addText(String text) {
210: this .script += text;
211: }
212:
213: /**
214: * Get the current script text content.
215: * @return the script text.
216: */
217: public String getScript() {
218: return script;
219: }
220:
221: /**
222: * Clear the current script text content.
223: */
224: public void clearScript() {
225: this .script = "";
226: }
227:
228: /**
229: * Set the project for this runner.
230: * @param project the project.
231: */
232: public void setProject(Project project) {
233: this .project = project;
234: }
235:
236: /**
237: * Get the project for this runner.
238: * @return the project.
239: */
240: public Project getProject() {
241: return project;
242: }
243:
244: /**
245: * Bind the runner to a project component.
246: * Properties, targets and references are all added as beans;
247: * project is bound to project, and self to the component.
248: * @param component to become <code>self</code>
249: */
250: public void bindToComponent(ProjectComponent component) {
251: project = component.getProject();
252: addBeans(project.getProperties());
253: addBeans(project.getUserProperties());
254: addBeans(project.getTargets());
255: addBeans(project.getReferences());
256: addBean("project", project);
257: addBean("self", component);
258: }
259:
260: /**
261: * Bind the runner to a project component.
262: * The project and self are the only beans set.
263: * @param component to become <code>self</code>
264: */
265: public void bindToComponentMinimum(ProjectComponent component) {
266: project = component.getProject();
267: addBean("project", project);
268: addBean("self", component);
269: }
270:
271: /**
272: * Check if the language attribute is set.
273: * @throws BuildException if it is not.
274: */
275: protected void checkLanguage() {
276: if (language == null) {
277: throw new BuildException(
278: "script language must be specified");
279: }
280: }
281:
282: /**
283: * Replace the current context classloader with the
284: * script context classloader.
285: * @return the current context classloader.
286: */
287: protected ClassLoader replaceContextLoader() {
288: ClassLoader origContextClassLoader = Thread.currentThread()
289: .getContextClassLoader();
290: if (getScriptClassLoader() == null) {
291: setScriptClassLoader(getClass().getClassLoader());
292: }
293: Thread.currentThread().setContextClassLoader(
294: getScriptClassLoader());
295: return origContextClassLoader;
296: }
297:
298: /**
299: * Restore the context loader with the original context classloader.
300: *
301: * script context loader.
302: * @param origLoader the original context classloader.
303: */
304: protected void restoreContextLoader(ClassLoader origLoader) {
305: Thread.currentThread().setContextClassLoader(origLoader);
306: }
307:
308: }
|