You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

ScriptRunnerBase.java 13 kB

11 years ago
11 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  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;
  19. import java.io.BufferedReader;
  20. import java.io.File;
  21. import java.io.FileInputStream;
  22. import java.io.FileNotFoundException;
  23. import java.io.IOException;
  24. import java.io.InputStream;
  25. import java.io.InputStreamReader;
  26. import java.io.Reader;
  27. import java.nio.charset.Charset;
  28. import java.util.HashMap;
  29. import java.util.Iterator;
  30. import java.util.Map;
  31. import org.apache.tools.ant.BuildException;
  32. import org.apache.tools.ant.Project;
  33. import org.apache.tools.ant.ProjectComponent;
  34. import org.apache.tools.ant.types.Resource;
  35. import org.apache.tools.ant.types.ResourceCollection;
  36. import org.apache.tools.ant.types.resources.PropertyResource;
  37. import org.apache.tools.ant.types.resources.StringResource;
  38. /**
  39. * This is a common abstract base case for script runners.
  40. * These classes need to implement executeScript, evaluateScript
  41. * and supportsLanguage.
  42. * @since Ant 1.7.0
  43. */
  44. public abstract class ScriptRunnerBase {
  45. /** Whether to keep the engine between calls to execute/eval */
  46. private boolean keepEngine = false;
  47. /** Script language */
  48. private String language;
  49. /** Script content */
  50. private String script = "";
  51. private String encoding;
  52. /** Enable script compilation. */
  53. private boolean compiled;
  54. /** Project this runner is used in */
  55. private Project project;
  56. /** Classloader to be used when running the script. */
  57. private ClassLoader scriptLoader;
  58. /** Beans to be provided to the script */
  59. private Map beans = new HashMap();
  60. /**
  61. * Add a list of named objects to the list to be exported to the script
  62. *
  63. * @param dictionary a map of objects to be placed into the script context
  64. * indexed by String names.
  65. */
  66. public void addBeans(Map dictionary) {
  67. for (Iterator i = dictionary.keySet().iterator(); i.hasNext();) {
  68. String key = (String) i.next();
  69. try {
  70. Object val = dictionary.get(key);
  71. addBean(key, val);
  72. } catch (BuildException ex) {
  73. // The key is in the dictionary but cannot be retrieved
  74. // This is usually due references that refer to tasks
  75. // that have not been taskdefed in the current run.
  76. // Ignore
  77. }
  78. }
  79. }
  80. /**
  81. * Add a single object into the script context.
  82. *
  83. * @param key the name in the context this object is to stored under.
  84. * @param bean the object to be stored in the script context.
  85. */
  86. public void addBean(String key, Object bean) {
  87. boolean isValid = key.length() > 0
  88. && Character.isJavaIdentifierStart(key.charAt(0));
  89. for (int i = 1; isValid && i < key.length(); i++) {
  90. isValid = Character.isJavaIdentifierPart(key.charAt(i));
  91. }
  92. if (isValid) {
  93. beans.put(key, bean);
  94. }
  95. }
  96. /**
  97. * Get the beans used for the script.
  98. * @return the map of beans.
  99. */
  100. protected Map getBeans() {
  101. return beans;
  102. }
  103. /**
  104. * Do the work.
  105. * @param execName the name that will be passed to BSF for this script
  106. * execution.
  107. */
  108. public abstract void executeScript(String execName);
  109. /**
  110. * Evaluate the script.
  111. * @param execName the name that will be passed to the
  112. * scripting engine for this script execution.
  113. * @return the result of evaluating the script.
  114. */
  115. public abstract Object evaluateScript(String execName);
  116. /**
  117. * Check if a script engine can be created for
  118. * this language.
  119. * @return true if a script engine can be created, false
  120. * otherwise.
  121. */
  122. public abstract boolean supportsLanguage();
  123. /**
  124. * Get the name of the manager prefix used for this
  125. * scriptrunner.
  126. * @return the prefix string.
  127. */
  128. public abstract String getManagerName();
  129. /**
  130. * Defines the language (required).
  131. * @param language the scripting language name for the script.
  132. */
  133. public void setLanguage(String language) {
  134. this.language = language;
  135. }
  136. /**
  137. * Get the script language
  138. * @return the script language
  139. */
  140. public String getLanguage() {
  141. return language;
  142. }
  143. /**
  144. * Set the script classloader.
  145. * @param classLoader the classloader to use.
  146. */
  147. public void setScriptClassLoader(ClassLoader classLoader) {
  148. this.scriptLoader = classLoader;
  149. }
  150. /**
  151. * Get the classloader used to load the script engine.
  152. * @return the classloader.
  153. */
  154. protected ClassLoader getScriptClassLoader() {
  155. return scriptLoader;
  156. }
  157. /**
  158. * Whether to keep the script engine between calls.
  159. * @param keepEngine if true, keep the engine.
  160. */
  161. public void setKeepEngine(boolean keepEngine) {
  162. this.keepEngine = keepEngine;
  163. }
  164. /**
  165. * Get the keep engine attribute.
  166. * @return the attribute.
  167. */
  168. public boolean getKeepEngine() {
  169. return keepEngine;
  170. }
  171. /**
  172. * Whether to use script compilation if available.
  173. * @since Ant 1.10.2
  174. * @param compiled if true, compile the script if possible.
  175. */
  176. public final void setCompiled(boolean compiled) {
  177. this.compiled = compiled;
  178. }
  179. /**
  180. * Get the compiled attribute.
  181. * @since Ant 1.10.2
  182. * @return the attribute.
  183. */
  184. public final boolean getCompiled() {
  185. return compiled;
  186. }
  187. /**
  188. * Set encoding of the script from an external file; optional.
  189. * @since Ant 1.10.2
  190. * @param encoding encoding of the external file containing the script source.
  191. */
  192. public void setEncoding(String encoding) {
  193. this.encoding = encoding;
  194. }
  195. /**
  196. * Load the script from an external file; optional.
  197. * @param file the file containing the script source.
  198. */
  199. public void setSrc(File file) {
  200. String filename = file.getPath();
  201. if (!file.exists()) {
  202. throw new BuildException("file " + filename + " not found.");
  203. }
  204. InputStream in = null;
  205. try {
  206. in = new FileInputStream(file);
  207. } catch (FileNotFoundException e) {
  208. //this can only happen if the file got deleted a short moment ago
  209. throw new BuildException("file " + filename + " not found.");
  210. }
  211. final Charset charset;
  212. if (null == encoding) {
  213. charset = null;
  214. } else {
  215. charset = Charset.forName(encoding);
  216. }
  217. try {
  218. readSource(in, filename, charset);
  219. } finally {
  220. FileUtils.close(in);
  221. }
  222. }
  223. /**
  224. * Read some source in from the given reader
  225. * @param reader the reader; this is closed afterwards.
  226. * @param name the name to use in error messages
  227. * @param charset the encoding for the reader, may be null.
  228. */
  229. private void readSource(InputStream in, String name, Charset charset) {
  230. Reader reader = null;
  231. try {
  232. if (null == charset) {
  233. reader = new InputStreamReader(in);
  234. } else {
  235. reader = new InputStreamReader(in, charset);
  236. }
  237. reader = new BufferedReader(reader);
  238. script += FileUtils.safeReadFully(reader);
  239. } catch (IOException ex) {
  240. throw new BuildException("Failed to read " + name, ex);
  241. } finally {
  242. FileUtils.close(reader);
  243. }
  244. }
  245. /**
  246. * Add a resource to the source list.
  247. * @since Ant 1.7.1
  248. * @param sourceResource the resource to load
  249. * @throws BuildException if the resource cannot be read
  250. */
  251. public void loadResource(Resource sourceResource) {
  252. if (sourceResource instanceof StringResource) {
  253. script += ((StringResource) sourceResource).getValue();
  254. return;
  255. }
  256. if (sourceResource instanceof PropertyResource) {
  257. script += ((PropertyResource) sourceResource).getValue();
  258. return;
  259. }
  260. String name = sourceResource.toLongString();
  261. InputStream in = null;
  262. try {
  263. in = sourceResource.getInputStream();
  264. } catch (IOException e) {
  265. throw new BuildException("Failed to open " + name, e);
  266. } catch (UnsupportedOperationException e) {
  267. throw new BuildException(
  268. "Failed to open " + name + " - it is not readable", e);
  269. }
  270. try {
  271. readSource(in, name, (Charset) null);
  272. } finally {
  273. FileUtils.close(in);
  274. }
  275. }
  276. /**
  277. * Add all resources in a resource collection to the source list.
  278. * @since Ant 1.7.1
  279. * @param collection the resource to load
  280. * @throws BuildException if a resource cannot be read
  281. */
  282. public void loadResources(ResourceCollection collection) {
  283. for (Resource resource : collection) {
  284. loadResource(resource);
  285. }
  286. }
  287. /**
  288. * Set the script text. Properties in the text are not expanded!
  289. *
  290. * @param text a component of the script text to be added.
  291. */
  292. public void addText(String text) {
  293. script += text;
  294. }
  295. /**
  296. * Get the current script text content.
  297. * @return the script text.
  298. */
  299. public String getScript() {
  300. return script;
  301. }
  302. /**
  303. * Clear the current script text content.
  304. */
  305. public void clearScript() {
  306. this.script = "";
  307. }
  308. /**
  309. * Set the project for this runner.
  310. * @param project the project.
  311. */
  312. public void setProject(Project project) {
  313. this.project = project;
  314. }
  315. /**
  316. * Get the project for this runner.
  317. * @return the project.
  318. */
  319. public Project getProject() {
  320. return project;
  321. }
  322. /**
  323. * Bind the runner to a project component.
  324. * Properties, targets and references are all added as beans;
  325. * project is bound to project, and self to the component.
  326. * @param component to become <code>self</code>
  327. */
  328. public void bindToComponent(ProjectComponent component) {
  329. project = component.getProject();
  330. addBeans(project.getProperties());
  331. addBeans(project.getUserProperties());
  332. addBeans(project.getCopyOfTargets());
  333. addBeans(project.getCopyOfReferences());
  334. addBean("project", project);
  335. addBean("self", component);
  336. }
  337. /**
  338. * Bind the runner to a project component.
  339. * The project and self are the only beans set.
  340. * @param component to become <code>self</code>
  341. */
  342. public void bindToComponentMinimum(ProjectComponent component) {
  343. project = component.getProject();
  344. addBean("project", project);
  345. addBean("self", component);
  346. }
  347. /**
  348. * Check if the language attribute is set.
  349. * @throws BuildException if it is not.
  350. */
  351. protected void checkLanguage() {
  352. if (language == null) {
  353. throw new BuildException(
  354. "script language must be specified");
  355. }
  356. }
  357. /**
  358. * Replace the current context classloader with the
  359. * script context classloader.
  360. * @return the current context classloader.
  361. */
  362. protected ClassLoader replaceContextLoader() {
  363. ClassLoader origContextClassLoader =
  364. Thread.currentThread().getContextClassLoader();
  365. if (getScriptClassLoader() == null) {
  366. setScriptClassLoader(getClass().getClassLoader());
  367. }
  368. Thread.currentThread().setContextClassLoader(getScriptClassLoader());
  369. return origContextClassLoader;
  370. }
  371. /**
  372. * Restore the context loader with the original context classloader.
  373. *
  374. * script context loader.
  375. * @param origLoader the original context classloader.
  376. */
  377. protected void restoreContextLoader(ClassLoader origLoader) {
  378. Thread.currentThread().setContextClassLoader(
  379. origLoader);
  380. }
  381. }