/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.tools.ant.taskdefs.optional.extension; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.jar.Manifest; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.taskdefs.optional.extension.resolvers.AntResolver; import org.apache.tools.ant.taskdefs.optional.extension.resolvers.LocationResolver; import org.apache.tools.ant.taskdefs.optional.extension.resolvers.URLResolver; /** * Tries to locate a JAR to satisfy an extension and place * location of JAR into property. * * @ant.task name="jarlib-resolve" */ public class JarLibResolveTask extends Task { /** * The name of the property in which the location of * library is stored. */ private String propertyName; /** * The extension that is required. */ private Extension requiredExtension; /** * The set of resolvers to use to attempt to locate library. */ private final List<ExtensionResolver> resolvers = new ArrayList<>(); /** * Flag to indicate that you should check that * the librarys resolved actually contain * extension and if they don't then raise * an exception. */ private boolean checkExtension = true; /** * Flag indicating whether or not you should * throw a BuildException if you cannot resolve * library. */ private boolean failOnError = true; /** * The name of the property in which the location of * library is stored. * * @param property The name of the property in which the location of * library is stored. */ public void setProperty(final String property) { this.propertyName = property; } /** * Check nested libraries for extensions * * @param checkExtension if true, libraries returned by nested * resolvers should be checked to see if they supply extension. */ public void setCheckExtension(final boolean checkExtension) { this.checkExtension = checkExtension; } /** * Set whether to fail if error. * * @param failOnError if true, failure to locate library should fail build. */ public void setFailOnError(final boolean failOnError) { this.failOnError = failOnError; } /** * Adds location resolver to look for a library in a location * relative to project directory. * * @param loc the resolver location to search. */ public void addConfiguredLocation(final LocationResolver loc) { resolvers.add(loc); } /** * Adds a URL resolver to download a library from a URL * to a local file. * * @param url the URL resolver from which to download the library */ public void addConfiguredUrl(final URLResolver url) { resolvers.add(url); } /** * Adds Ant resolver to run an Ant build file to generate a library. * * @param ant the AntResolver to generate the library. */ public void addConfiguredAnt(final AntResolver ant) { resolvers.add(ant); } /** * Set the Extension looking for. * * @param extension Set the Extension looking for. */ public void addConfiguredExtension(final ExtensionAdapter extension) { if (null != requiredExtension) { throw new BuildException( "Can not specify extension to resolve multiple times."); } requiredExtension = extension.toExtension(); } /** * Execute the task. * * @throws BuildException if the task fails. */ @Override public void execute() throws BuildException { validate(); getProject().log("Resolving extension: " + requiredExtension, Project.MSG_VERBOSE); String candidate = getProject().getProperty(propertyName); if (null != candidate) { final String message = "Property Already set to: " + candidate; if (failOnError) { throw new BuildException(message); } getProject().log(message, Project.MSG_ERR); return; } for (ExtensionResolver resolver : resolvers) { getProject().log("Searching for extension using Resolver:" + resolver, Project.MSG_VERBOSE); try { final File file = resolver.resolve(requiredExtension, getProject()); try { checkExtension(file); return; } catch (final BuildException be) { getProject().log("File " + file + " returned by " + "resolver failed to satisfy extension due to: " + be.getMessage(), Project.MSG_WARN); } } catch (final BuildException be) { getProject() .log( "Failed to resolve extension to file " + "using resolver " + resolver + " due to: " + be, Project.MSG_WARN); } } missingExtension(); } /** * Utility method that will throw a {@link BuildException} * if {@link #failOnError} is true else it just displays * a warning. */ private void missingExtension() { final String message = "Unable to resolve extension to a file"; if (failOnError) { throw new BuildException(message); } getProject().log(message, Project.MSG_ERR); } /** * Check if specified file satisfies extension. * If it does then set the relevant property * else throw a BuildException. * * @param file the candidate library * @throws BuildException if library does not satisfy extension */ private void checkExtension(final File file) { if (!file.exists()) { throw new BuildException("File %s does not exist", file); } if (!file.isFile()) { throw new BuildException("File %s is not a file", file); } if (!checkExtension) { getProject().log("Setting property to " + file + " without verifying library satisfies extension", Project.MSG_VERBOSE); setLibraryProperty(file); } else { getProject().log("Checking file " + file + " to see if it satisfies extension", Project.MSG_VERBOSE); final Manifest manifest = ExtensionUtil.getManifest(file); for (final Extension extension : Extension.getAvailable(manifest)) { if (extension.isCompatibleWith(requiredExtension)) { setLibraryProperty(file); return; } } final String message = "File " + file + " skipped as it " + "does not satisfy extension"; getProject().log(message, Project.MSG_VERBOSE); throw new BuildException(message); } } /** * Utility method to set the appropriate property * to indicate that specified file satisfies library * requirements. * * @param file the library */ private void setLibraryProperty(final File file) { getProject().setNewProperty(propertyName, file.getAbsolutePath()); } /** * Validate the tasks parameters. * * @throws BuildException if invalid parameters found */ private void validate() throws BuildException { if (null == propertyName) { throw new BuildException("Property attribute must be specified."); } if (null == requiredExtension) { throw new BuildException("Extension element must be specified."); } } }