/* * 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; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Map; import java.util.HashMap; import java.util.Enumeration; import java.util.Locale; import java.util.NoSuchElementException; import java.util.Properties; import org.apache.tools.ant.AntTypeDefinition; import org.apache.tools.ant.ComponentHelper; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.ProjectHelper; import org.apache.tools.ant.MagicNames; import org.apache.tools.ant.util.FileUtils; import org.apache.tools.ant.types.EnumeratedAttribute; /** * Base class for Taskdef and Typedef - handles all * the attributes for Typedef. The uri and class * handling is handled by DefBase * * @since Ant 1.4 */ public abstract class Definer extends DefBase { /** * the extension of an antlib file for autoloading. * {@value[ */ private static final String ANTLIB_XML = "/antlib.xml"; private static class ResourceStack extends ThreadLocal { public Object initialValue() { return new HashMap(); } Map getStack() { return (Map) get(); } } private static ResourceStack resourceStack = new ResourceStack(); private String name; private String classname; private File file; private String resource; private int format = Format.PROPERTIES; private boolean definerSet = false; private int onError = OnError.FAIL; private String adapter; private String adaptTo; private Class adapterClass; private Class adaptToClass; /** * Enumerated type for onError attribute * * @see EnumeratedAttribute */ public static class OnError extends EnumeratedAttribute { /** Enumerated values */ public static final int FAIL = 0, REPORT = 1, IGNORE = 2, FAIL_ALL = 3; /** * text value of onerror option {@value} */ public static final String POLICY_FAIL = "fail"; /** * text value of onerror option {@value} */ public static final String POLICY_REPORT = "report"; /** * text value of onerror option {@value} */ public static final String POLICY_IGNORE = "ignore"; /** * text value of onerror option {@value} */ public static final String POLICY_FAILALL = "failall"; /** * Constructor */ public OnError() { super(); } /** * Constructor using a string. * @param value the value of the attribute */ public OnError(String value) { setValue(value); } /** * get the values * @return an array of the allowed values for this attribute. */ public String[] getValues() { return new String[] {POLICY_FAIL, POLICY_REPORT, POLICY_IGNORE, POLICY_FAILALL}; } } /** * Enumerated type for format attribute * * @see EnumeratedAttribute */ public static class Format extends EnumeratedAttribute { /** Enumerated values */ public static final int PROPERTIES = 0, XML = 1; /** * get the values * @return an array of the allowed values for this attribute. */ public String[] getValues() { return new String[] {"properties", "xml"}; } } /** * What to do if there is an error in loading the class. *
OnError value
*/
public void setOnError(OnError onError) {
this.onError = onError.getIndex();
}
/**
* Sets the format of the file or resource
* @param format the enumerated value - xml or properties
*/
public void setFormat(Format format) {
this.format = format.getIndex();
}
/**
* @return the name for this definition
*/
public String getName() {
return name;
}
/**
* @return the file containing definitions
*/
public File getFile() {
return file;
}
/**
* @return the resource containing definitions
*/
public String getResource() {
return resource;
}
/**
* Run the definition.
*
* @exception BuildException if an error occurs
*/
public void execute() throws BuildException {
ClassLoader al = createLoader();
if (!definerSet) {
//we arent fully defined yet. this is an error unless
//we are in an antlib, in which case the resource name is determined
//automatically.
//NB: URIs in the ant core package will be "" at this point.
if (getURI() == null) {
throw new BuildException(
"name, file or resource attribute of "
+ getTaskName() + " is undefined",
getLocation());
}
if (getURI().startsWith(MagicNames.ANTLIB_PREFIX)) {
//convert the URI to a resource
String uri1 = getURI();
setResource(makeResourceFromURI(uri1));
} else {
throw new BuildException(
"Only antlib URIs can be located from the URI alone,"
+ "not the URI " + getURI());
}
}
if (name != null) {
if (classname == null) {
throw new BuildException(
"classname attribute of " + getTaskName() + " element "
+ "is undefined", getLocation());
}
addDefinition(al, name, classname);
} else {
if (classname != null) {
String msg = "You must not specify classname "
+ "together with file or resource.";
throw new BuildException(msg, getLocation());
}
Enumeration/*null.
* @return the class name
*/
public String getClassname() {
return classname;
}
/**
* The full class name of the object being defined.
* Required, unless file or resource have
* been specified.
* @param classname the name of the class
*/
public void setClassname(String classname) {
this.classname = classname;
}
/**
* Set the class name of the adapter class.
* An adapter class is used to proxy the
* definition class. It is used if the
* definition class is not assignable to
* the adaptto class, or if the adaptto
* class is not present.
*
* @param adapter the name of the adapter class
*/
public void setAdapter(String adapter) {
this.adapter = adapter;
}
/**
* Set the adapter class.
*
* @param adapterClass the class to use to adapt the definition class
*/
protected void setAdapterClass(Class adapterClass) {
this.adapterClass = adapterClass;
}
/**
* Set the classname of the class that the definition
* must be compatible with, either directly or
* by use of the adapter class.
*
* @param adaptTo the name of the adaptto class
*/
public void setAdaptTo(String adaptTo) {
this.adaptTo = adaptTo;
}
/**
* Set the class for adaptToClass, to be
* used by derived classes, used instead of
* the adaptTo attribute.
*
* @param adaptToClass the class for adapto.
*/
protected void setAdaptToClass(Class adaptToClass) {
this.adaptToClass = adaptToClass;
}
/**
* Add a definition using the attributes of Definer
*
* @param al the ClassLoader to use
* @param name the name of the definition
* @param classname the classname of the definition
* @exception BuildException if an error occurs
*/
protected void addDefinition(ClassLoader al, String name, String classname)
throws BuildException {
Class cl = null;
try {
try {
name = ProjectHelper.genComponentName(getURI(), name);
if (onError != OnError.IGNORE) {
cl = Class.forName(classname, true, al);
}
if (adapter != null) {
adapterClass = Class.forName(adapter, true, al);
}
if (adaptTo != null) {
adaptToClass = Class.forName(adaptTo, true, al);
}
AntTypeDefinition def = new AntTypeDefinition();
def.setName(name);
def.setClassName(classname);
def.setClass(cl);
def.setAdapterClass(adapterClass);
def.setAdaptToClass(adaptToClass);
def.setClassLoader(al);
if (cl != null) {
def.checkClass(getProject());
}
ComponentHelper.getComponentHelper(getProject())
.addDataTypeDefinition(def);
} catch (ClassNotFoundException cnfe) {
String msg = getTaskName() + " class " + classname
+ " cannot be found";
throw new BuildException(msg, cnfe, getLocation());
} catch (NoClassDefFoundError ncdfe) {
String msg = getTaskName() + " A class needed by class "
+ classname + " cannot be found: " + ncdfe.getMessage();
throw new BuildException(msg, ncdfe, getLocation());
}
} catch (BuildException ex) {
switch (onError) {
case OnError.FAIL_ALL:
case OnError.FAIL:
throw ex;
case OnError.REPORT:
log(ex.getLocation() + "Warning: " + ex.getMessage(),
Project.MSG_WARN);
break;
default:
log(ex.getLocation() + ex.getMessage(),
Project.MSG_DEBUG);
}
}
}
/**
* handle too many definitions by raising an exception.
* @throws BuildException always.
*/
private void tooManyDefinitions() {
throw new BuildException(
"Only one of the attributes name, file and resource"
+ " can be set", getLocation());
}
}