alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Ant example source code file (Definer.java)

This example Ant source code file (Definer.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Ant tags/keywords

antlib_xml, buildexception, buildexception, could, enumeration, file, file, io, net, network, onerror, properties, resourcestack, string, string, url, url, util

The Definer.java source code

/*
 *  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.
     * <dl>
     *   <li>error - throw build exception
     *   <li>report - output at warning level
     *   <li>ignore - output at debug level
     * </dl>
     *
     * @param onError an <code>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/*<URL>*/ 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.US).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";
        }
        try {
            if (message == null) {
                return file.toURL();
            }
        } 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 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.
     * @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());
    }
}

Other Ant examples (source code examples)

Here is a short list of links related to this Ant Definer.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.