All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.tools.ant.taskdefs.Definer Maven / Gradle / Ivy

The newest version!
/*
 *  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.Enumeration;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
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 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.
     * 
*
  • error - throw build exception
  • *
  • report - output at warning level
  • *
  • ignore - output at debug level
  • *
    * * @param onError an 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/**/ urls = null; if (file != null) { final URL url = fileToURL(); if (url == null) { return; } urls = new Enumeration() { private boolean more = true; public boolean hasMoreElements() { return more; } public Object nextElement() throws NoSuchElementException { if (more) { more = false; return url; } else { throw new NoSuchElementException(); } } }; } else { urls = resourceToURLs(al); } while (urls.hasMoreElements()) { URL 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 (resourceStack.getStack().get(url) != null) { log("Warning: Recursive loading of " + url + " ignored" + " at " + getLocation() + " originally loaded at " + resourceStack.getStack().get(url), Project.MSG_WARN); } else { try { resourceStack.getStack().put(url, getLocation()); loadAntlib(al, url); } finally { resourceStack.getStack().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/**/ resourceToURLs(ClassLoader classLoader) { Enumeration 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 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.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()); } }




    © 2015 - 2025 Weber Informatics LLC | Privacy Policy