1. /*
  2. * Copyright 2002-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.taskdefs.optional.extension;
  18. import java.io.File;
  19. import java.util.ArrayList;
  20. import java.util.jar.Manifest;
  21. import org.apache.tools.ant.BuildException;
  22. import org.apache.tools.ant.Project;
  23. import org.apache.tools.ant.Task;
  24. import org.apache.tools.ant.taskdefs.optional.extension.resolvers.AntResolver;
  25. import org.apache.tools.ant.taskdefs.optional.extension.resolvers.LocationResolver;
  26. import org.apache.tools.ant.taskdefs.optional.extension.resolvers.URLResolver;
  27. /**
  28. * Tries to locate a JAR to satisfy an extension and place
  29. * location of JAR into property.
  30. *
  31. * @ant.task name="jarlib-resolve"
  32. */
  33. public class JarLibResolveTask extends Task {
  34. /**
  35. * The name of the property in which the location of
  36. * library is stored.
  37. */
  38. private String propertyName;
  39. /**
  40. * The extension that is required.
  41. */
  42. private Extension requiredExtension;
  43. /**
  44. * The set of resolvers to use to attempt to locate library.
  45. */
  46. private final ArrayList resolvers = new ArrayList();
  47. /**
  48. * Flag to indicate that you should check that
  49. * the librarys resolved actually contain
  50. * extension and if they don't then raise
  51. * an exception.
  52. */
  53. private boolean checkExtension = true;
  54. /**
  55. * Flag indicating whether or not you should
  56. * throw a BuildException if you cannot resolve
  57. * library.
  58. */
  59. private boolean failOnError = true;
  60. /**
  61. * The name of the property in which the location of
  62. * library is stored.
  63. *
  64. * @param property The name of the property in which the location of
  65. * library is stored.
  66. */
  67. public void setProperty(final String property) {
  68. this.propertyName = property;
  69. }
  70. /**
  71. * Check nested libraries for extensions
  72. *
  73. * @param checkExtension if true, libraries returned by nested
  74. * resolvers should be checked to see if they supply extension.
  75. */
  76. public void setCheckExtension(final boolean checkExtension) {
  77. this.checkExtension = checkExtension;
  78. }
  79. /**
  80. * Set whether to fail if error.
  81. *
  82. * @param failOnError if true, failure to locate library should fail build.
  83. */
  84. public void setFailOnError(final boolean failOnError) {
  85. this.failOnError = failOnError;
  86. }
  87. /**
  88. * Adds location resolver to look for a library in a location
  89. * relative to project directory.
  90. *
  91. * @param location the resolver location to search.
  92. */
  93. public void addConfiguredLocation(final LocationResolver location) {
  94. resolvers.add(location);
  95. }
  96. /**
  97. * Adds a URL resolver to download a library from a URL
  98. * to a local file.
  99. *
  100. * @param url the URL resolver from which to download the library
  101. */
  102. public void addConfiguredUrl(final URLResolver url) {
  103. resolvers.add(url);
  104. }
  105. /**
  106. * Adds Ant resolver to run an Ant build file to generate a library.
  107. *
  108. * @param ant the AntResolver to generate the library.
  109. */
  110. public void addConfiguredAnt(final AntResolver ant) {
  111. resolvers.add(ant);
  112. }
  113. /**
  114. * Set the Extension looking for.
  115. *
  116. * @param extension Set the Extension looking for.
  117. */
  118. public void addConfiguredExtension(final ExtensionAdapter extension) {
  119. if (null != requiredExtension) {
  120. final String message = "Can not specify extension to "
  121. + "resolve multiple times.";
  122. throw new BuildException(message);
  123. }
  124. requiredExtension = extension.toExtension();
  125. }
  126. /**
  127. * Execute the task.
  128. *
  129. * @throws BuildException if the task fails.
  130. */
  131. public void execute() throws BuildException {
  132. validate();
  133. getProject().log("Resolving extension: " + requiredExtension,
  134. Project.MSG_VERBOSE);
  135. String candidate =
  136. getProject().getProperty(propertyName);
  137. if (null != candidate) {
  138. final String message = "Property Already set to: " + candidate;
  139. if (failOnError) {
  140. throw new BuildException(message);
  141. } else {
  142. getProject().log(message, Project.MSG_ERR);
  143. return;
  144. }
  145. }
  146. final int size = resolvers.size();
  147. for (int i = 0; i < size; i++) {
  148. final ExtensionResolver resolver =
  149. (ExtensionResolver) resolvers.get(i);
  150. getProject().log("Searching for extension using Resolver:" + resolver,
  151. Project.MSG_VERBOSE);
  152. try {
  153. final File file =
  154. resolver.resolve(requiredExtension, getProject());
  155. try {
  156. checkExtension(file);
  157. return;
  158. } catch (final BuildException be) {
  159. final String message = "File " + file + " returned by "
  160. + "resolver failed to satisfy extension due to: "
  161. + be.getMessage();
  162. getProject().log(message, Project.MSG_WARN);
  163. }
  164. } catch (final BuildException be) {
  165. final String message = "Failed to resolve extension to file "
  166. + "using resolver " + resolver + " due to: " + be;
  167. getProject().log(message, Project.MSG_WARN);
  168. }
  169. }
  170. missingExtension();
  171. }
  172. /**
  173. * Utility method that will throw a {@link BuildException}
  174. * if {@link #failOnError} is true else it just displays
  175. * a warning.
  176. */
  177. private void missingExtension() {
  178. final String message =
  179. "Unable to resolve extension to a file";
  180. if (failOnError) {
  181. throw new BuildException(message);
  182. } else {
  183. getProject().log(message, Project.MSG_ERR);
  184. }
  185. }
  186. /**
  187. * Check if specified file satisfies extension.
  188. * If it does then set the relevent property
  189. * else throw a BuildException.
  190. *
  191. * @param file the candidate library
  192. * @throws BuildException if library does not satisfy extension
  193. */
  194. private void checkExtension(final File file) {
  195. if (!file.exists()) {
  196. final String message =
  197. "File " + file + " does not exist";
  198. throw new BuildException(message);
  199. }
  200. if (!file.isFile()) {
  201. final String message =
  202. "File " + file + " is not a file";
  203. throw new BuildException(message);
  204. }
  205. if (!checkExtension) {
  206. final String message = "Setting property to " + file
  207. + " without verifying library satisfies extension";
  208. getProject().log(message, Project.MSG_VERBOSE);
  209. setLibraryProperty(file);
  210. } else {
  211. getProject().log("Checking file " + file
  212. + " to see if it satisfies extension", Project.MSG_VERBOSE);
  213. final Manifest manifest =
  214. ExtensionUtil.getManifest(file);
  215. final Extension[] extensions =
  216. Extension.getAvailable(manifest);
  217. for (int i = 0; i < extensions.length; i++) {
  218. final Extension extension = extensions[ i ];
  219. if (extension.isCompatibleWith(requiredExtension)) {
  220. setLibraryProperty(file);
  221. return;
  222. }
  223. }
  224. getProject().log("File " + file + " skipped as it "
  225. + "does not satisfy extension", Project.MSG_VERBOSE);
  226. final String message =
  227. "File " + file + " does not satisfy extension";
  228. throw new BuildException(message);
  229. }
  230. }
  231. /**
  232. * Utility method to set the appropriate property
  233. * to indicate that specified file satisfies library
  234. * requirements.
  235. *
  236. * @param file the library
  237. */
  238. private void setLibraryProperty(final File file) {
  239. getProject().setNewProperty(propertyName,
  240. file.getAbsolutePath());
  241. }
  242. /**
  243. * Validate the tasks parameters.
  244. *
  245. * @throws BuildException if invalid parameters found
  246. */
  247. private void validate() throws BuildException {
  248. if (null == propertyName) {
  249. final String message = "Property attribute must be specified.";
  250. throw new BuildException(message);
  251. }
  252. if (null == requiredExtension) {
  253. final String message = "Extension element must be specified.";
  254. throw new BuildException(message);
  255. }
  256. }
  257. }