blob: 1123b339098151382df80c5ed42c20e5aa66e2a2 [file] [log] [blame]
/*
* 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.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 ArrayList 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) {
final String message = "Can not specify extension to "
+ "resolve multiple times.";
throw new BuildException(message);
}
requiredExtension = extension.toExtension();
}
/**
* Execute the task.
*
* @throws BuildException if the task fails.
*/
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;
}
final int size = resolvers.size();
for (int i = 0; i < size; i++) {
final ExtensionResolver resolver =
(ExtensionResolver) resolvers.get(i);
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) {
final String message = "File " + file + " returned by "
+ "resolver failed to satisfy extension due to: "
+ be.getMessage();
getProject().log(message, Project.MSG_WARN);
}
} catch (final BuildException be) {
final String message = "Failed to resolve extension to file "
+ "using resolver " + resolver + " due to: " + be;
getProject().log(message, 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 relevent 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()) {
final String message =
"File " + file + " does not exist";
throw new BuildException(message);
}
if (!file.isFile()) {
final String message =
"File " + file + " is not a file";
throw new BuildException(message);
}
if (!checkExtension) {
final String message = "Setting property to " + file
+ " without verifying library satisfies extension";
getProject().log(message, 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);
final Extension[] extensions =
Extension.getAvailable(manifest);
for (int i = 0; i < extensions.length; i++) {
final Extension extension = extensions[ i ];
if (extension.isCompatibleWith(requiredExtension)) {
setLibraryProperty(file);
return;
}
}
getProject().log("File " + file + " skipped as it "
+ "does not satisfy extension", Project.MSG_VERBOSE);
final String message =
"File " + file + " does not satisfy extension";
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) {
final String message = "Property attribute must be specified.";
throw new BuildException(message);
}
if (null == requiredExtension) {
final String message = "Extension element must be specified.";
throw new BuildException(message);
}
}
}