diff options
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Definer.java')
-rw-r--r-- | framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Definer.java | 639 |
1 files changed, 639 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Definer.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Definer.java new file mode 100644 index 00000000..8196fa51 --- /dev/null +++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Definer.java @@ -0,0 +1,639 @@ +/* + * 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.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Properties; + +import org.apache.tools.ant.AntTypeDefinition; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.ComponentHelper; +import org.apache.tools.ant.Location; +import org.apache.tools.ant.MagicNames; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.ProjectHelper; +import org.apache.tools.ant.types.EnumeratedAttribute; +import org.apache.tools.ant.util.FileUtils; + +/** + * 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 final ThreadLocal<Map<URL, Location>> RESOURCE_STACK = new ThreadLocal<Map<URL, Location>>() { + protected Map<URL, Location> initialValue() { + return new HashMap<URL, Location>(); + } + }; + + private String name; + private String classname; + private File file; + private String resource; + private boolean restrict = false; + + 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"}; + } + } + + /** + * The restrict attribute. + * If this is true, only use this definition in add(X). + * @param restrict the value to set. + */ + protected void setRestrict(boolean restrict) { + this.restrict = restrict; + } + + + /** + * What to do if there is an error in loading the class. + * <ul> + * <li>error - throw build exception</li> + * <li>report - output at warning level</li> + * <li>ignore - output at debug level</li> + * </ul> + * + * @param onError an <code>OnError</code> 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()); + } + final Enumeration<URL> urls; + if (file == null) { + urls = resourceToURLs(al); + } else { + final URL url = fileToURL(); + if (url == null) { + return; + } + urls = Collections.enumeration(Collections.singleton(url)); + } + + while (urls.hasMoreElements()) { + URL url = urls.nextElement(); + + int fmt = this.format; + if (url.toString().toLowerCase(Locale.ENGLISH).endsWith(".xml")) { + fmt = Format.XML; + } + + if (fmt == Format.PROPERTIES) { + loadProperties(al, url); + break; + } else { + if (RESOURCE_STACK.get().get(url) != null) { + log("Warning: Recursive loading of " + url + + " ignored" + + " at " + getLocation() + + " originally loaded at " + + RESOURCE_STACK.get().get(url), + Project.MSG_WARN); + } else { + try { + RESOURCE_STACK.get().put(url, getLocation()); + loadAntlib(al, url); + } finally { + RESOURCE_STACK.get().remove(url); + } + } + } + } + } + } + + /** + * This is where the logic to map from a URI to an antlib resource + * is kept. + * @param uri the xml namespace uri that to convert. + * @return the name of a resource. It may not exist + */ + + public static String makeResourceFromURI(String uri) { + String path = uri.substring(MagicNames.ANTLIB_PREFIX.length()); + String resource; + if (path.startsWith("//")) { + //handle new style full paths to an antlib, in which + //all but the forward slashes are allowed. + resource = path.substring("//".length()); + if (!resource.endsWith(".xml")) { + //if we haven't already named an XML file, it gets antlib.xml + resource = resource + ANTLIB_XML; + } + } else { + //convert from a package to a path + resource = path.replace('.', '/') + ANTLIB_XML; + } + return resource; + } + + /** + * Convert a file to a file: URL. + * + * @return the URL, or null if it isn't valid and the active error policy + * is not to raise a fault + * @throws BuildException if the file is missing/not a file and the + * policy requires failure at this point. + */ + private URL fileToURL() { + String message = null; + if (!(file.exists())) { + message = "File " + file + " does not exist"; + } + if (message == null && !(file.isFile())) { + message = "File " + file + " is not a file"; + } + if (message == null) { + try { + return FileUtils.getFileUtils().getFileURL(file); + } catch (Exception ex) { + message = + "File " + file + " cannot use as URL: " + + ex.toString(); + } + } + // Here if there is an error + switch (onError) { + case OnError.FAIL_ALL: + throw new BuildException(message); + case OnError.FAIL: + // Fall Through + case OnError.REPORT: + log(message, Project.MSG_WARN); + break; + case OnError.IGNORE: + // log at a lower level + log(message, Project.MSG_VERBOSE); + break; + default: + // Ignore the problem + break; + } + return null; + } + + private Enumeration<URL> resourceToURLs(ClassLoader classLoader) { + Enumeration<URL> ret; + try { + ret = classLoader.getResources(resource); + } catch (IOException e) { + throw new BuildException( + "Could not fetch resources named " + resource, + e, getLocation()); + } + if (!ret.hasMoreElements()) { + String message = "Could not load definitions from resource " + + resource + ". It could not be found."; + switch (onError) { + case OnError.FAIL_ALL: + throw new BuildException(message); + case OnError.FAIL: + case OnError.REPORT: + log(message, Project.MSG_WARN); + break; + case OnError.IGNORE: + log(message, Project.MSG_VERBOSE); + break; + default: + // Ignore the problem + break; + } + } + return ret; + } + + /** + * Load type definitions as properties from a URL. + * + * @param al the classloader to use + * @param url the url to get the definitions from + */ + protected void loadProperties(ClassLoader al, URL url) { + InputStream is = null; + try { + is = url.openStream(); + if (is == null) { + log("Could not load definitions from " + url, + Project.MSG_WARN); + return; + } + Properties props = new Properties(); + props.load(is); + Enumeration<?> keys = props.keys(); + while (keys.hasMoreElements()) { + name = ((String) keys.nextElement()); + classname = props.getProperty(name); + addDefinition(al, name, classname); + } + } catch (IOException ex) { + throw new BuildException(ex, getLocation()); + } finally { + FileUtils.close(is); + } + } + + /** + * Load an antlib from a URL. + * + * @param classLoader the classloader to use. + * @param url the url to load the definitions from. + */ + private void loadAntlib(ClassLoader classLoader, URL url) { + try { + Antlib antlib = Antlib.createAntlib(getProject(), url, getURI()); + antlib.setClassLoader(classLoader); + antlib.setURI(getURI()); + antlib.execute(); + } catch (BuildException ex) { + throw ProjectHelper.addLocationToBuildException( + ex, getLocation()); + } + } + + /** + * Name of the property file to load + * ant name/classname pairs from. + * @param file the file + */ + public void setFile(File file) { + if (definerSet) { + tooManyDefinitions(); + } + definerSet = true; + this.file = file; + } + + /** + * Name of the property resource to load + * ant name/classname pairs from. + * @param res the resource to use + */ + public void setResource(String res) { + if (definerSet) { + tooManyDefinitions(); + } + definerSet = true; + this.resource = res; + } + + /** + * Antlib attribute, sets resource and uri. + * uri is set the antlib value and, resource is set + * to the antlib.xml resource in the classpath. + * For example antlib="antlib:org.acme.bland.cola" + * corresponds to uri="antlib:org.acme.bland.cola" + * resource="org/acme/bland/cola/antlib.xml". + * ASF Bugzilla Bug 31999 + * @param antlib the value to set. + */ + public void setAntlib(String antlib) { + if (definerSet) { + tooManyDefinitions(); + } + if (!antlib.startsWith("antlib:")) { + throw new BuildException( + "Invalid antlib attribute - it must start with antlib:"); + } + setURI(antlib); + this.resource = antlib.substring("antlib:".length()).replace('.', '/') + + "/antlib.xml"; + definerSet = true; + } + + /** + * Name of the definition + * @param name the name of the definition + */ + public void setName(String name) { + if (definerSet) { + tooManyDefinitions(); + } + definerSet = true; + this.name = name; + } + + /** + * Returns the classname of the object we are defining. + * May be <code>null</code>. + * @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 adaptor. + */ + 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.setRestrict(restrict); + 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" + + "\n using the classloader " + al; + throw new BuildException(msg, cnfe, getLocation()); + } catch (NoClassDefFoundError ncdfe) { + String msg = getTaskName() + " A class needed by class " + + classname + " cannot be found: " + ncdfe.getMessage() + + "\n using the classloader " + al; + 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()); + } +} |