/*
 *  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
 *
 *      https://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;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;


This class contains all the information on a particular ant type, the classname, adapter and the class it should be assignable from. This type replaces the task/datatype split of pre ant 1.6.
/** * This class contains all the information * on a particular ant type, * the classname, adapter and the class * it should be assignable from. * This type replaces the task/datatype split * of pre ant 1.6. * */
public class AntTypeDefinition { private String name; private Class<?> clazz; private Class<?> adapterClass; private Class<?> adaptToClass; private String className; private ClassLoader classLoader; private boolean restrict = false;
Set the restrict attribute.
Params:
  • restrict – the value to set.
/** * Set the restrict attribute. * @param restrict the value to set. */
public void setRestrict(boolean restrict) { this.restrict = restrict; }
Get the restrict attribute.
Returns:the restrict attribute.
/** * Get the restrict attribute. * @return the restrict attribute. */
public boolean isRestrict() { return restrict; }
Set the definition's name.
Params:
  • name – the name of the definition.
/** * Set the definition's name. * @param name the name of the definition. */
public void setName(String name) { this.name = name; }
Return the definition's name.
Returns:the name of the definition.
/** * Return the definition's name. * @return the name of the definition. */
public String getName() { return name; }
Set the class of the definition. As a side-effect may set the classloader and classname.
Params:
  • clazz – the class of this definition.
/** * Set the class of the definition. * As a side-effect may set the classloader and classname. * @param clazz the class of this definition. */
public void setClass(Class<?> clazz) { this.clazz = clazz; if (clazz == null) { return; } this.classLoader = (classLoader == null) ? clazz.getClassLoader() : classLoader; this.className = (className == null) ? clazz.getName() : className; }
Set the classname of the definition.
Params:
  • className – the classname of this definition.
/** * Set the classname of the definition. * @param className the classname of this definition. */
public void setClassName(String className) { this.className = className; }
Get the classname of the definition.
Returns:the name of the class of this definition.
/** * Get the classname of the definition. * @return the name of the class of this definition. */
public String getClassName() { return className; }
Set the adapter class for this definition. This class is used to adapt the definitions class if required.
Params:
  • adapterClass – the adapterClass.
/** * Set the adapter class for this definition. * This class is used to adapt the definitions class if * required. * @param adapterClass the adapterClass. */
public void setAdapterClass(Class<?> adapterClass) { this.adapterClass = adapterClass; }
Set the assignable class for this definition.
Params:
  • adaptToClass – the assignable class.
/** * Set the assignable class for this definition. * @param adaptToClass the assignable class. */
public void setAdaptToClass(Class<?> adaptToClass) { this.adaptToClass = adaptToClass; }
Set the classloader to use to create an instance of the definition.
Params:
  • classLoader – the ClassLoader.
/** * Set the classloader to use to create an instance * of the definition. * @param classLoader the ClassLoader. */
public void setClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; }
Get the classloader for this definition.
Returns:the classloader for this definition.
/** * Get the classloader for this definition. * @return the classloader for this definition. */
public ClassLoader getClassLoader() { return classLoader; }
Get the exposed class for this definition. This will be a proxy class (adapted class) if there is an adapter class and the definition class is not assignable from the assignable class.
Params:
  • project – the current project.
Returns:the exposed class - may return null if unable to load the class
/** * Get the exposed class for this * definition. This will be a proxy class * (adapted class) if there is an adapter * class and the definition class is not * assignable from the assignable class. * @param project the current project. * @return the exposed class - may return null if unable to load the class */
public Class<?> getExposedClass(Project project) { if (adaptToClass != null) { Class<?> z = getTypeClass(project); if (z == null || adaptToClass.isAssignableFrom(z)) { return z; } } return (adapterClass == null) ? getTypeClass(project) : adapterClass; }
Get the definition class.
Params:
  • project – the current project.
Returns:the type of the definition.
/** * Get the definition class. * @param project the current project. * @return the type of the definition. */
public Class<?> getTypeClass(Project project) { try { return innerGetTypeClass(); } catch (NoClassDefFoundError ncdfe) { project.log("Could not load a dependent class (" + ncdfe.getMessage() + ") for type " + name, Project.MSG_DEBUG); } catch (ClassNotFoundException cnfe) { project.log("Could not load class (" + className + ") for type " + name, Project.MSG_DEBUG); } return null; }
Try and load a class, with no attempt to catch any fault.
Throws:
Returns:the class that implements this component
/** * Try and load a class, with no attempt to catch any fault. * @return the class that implements this component * @throws ClassNotFoundException if the class cannot be found. * @throws NoClassDefFoundError if the there is an error * finding the class. */
public Class<?> innerGetTypeClass() throws ClassNotFoundException { if (clazz != null) { return clazz; } if (classLoader == null) { clazz = Class.forName(className); } else { clazz = classLoader.loadClass(className); } return clazz; }
Create an instance of the definition. The instance may be wrapped in a proxy class.
Params:
  • project – the current project.
Returns:the created object.
/** * Create an instance of the definition. * The instance may be wrapped in a proxy class. * @param project the current project. * @return the created object. */
public Object create(Project project) { return icreate(project); }
Create a component object based on its definition.
Returns:the component as an Object.
/** * Create a component object based on * its definition. * @return the component as an <code>Object</code>. */
private Object icreate(Project project) { Class<?> c = getTypeClass(project); if (c == null) { return null; } Object o = createAndSet(project, c); if (adapterClass == null || (adaptToClass != null && adaptToClass.isAssignableFrom(o.getClass()))) { return o; } TypeAdapter adapterObject = (TypeAdapter) createAndSet( project, adapterClass); adapterObject.setProxy(o); return adapterObject; }
Checks if the attributes are correct.
  • if the class can be created.
  • if an adapter class can be created
  • if the type is assignable from adapter
  • if the type can be used with the adapter class
Params:
  • project – the current project.
/** * Checks if the attributes are correct. * <ul> * <li>if the class can be created.</li> * <li>if an adapter class can be created</li> * <li>if the type is assignable from adapter</li> * <li>if the type can be used with the adapter class</li> * </ul> * @param project the current project. */
public void checkClass(Project project) { if (clazz == null) { clazz = getTypeClass(project); if (clazz == null) { throw new BuildException( "Unable to create class for " + getName()); } } // check adapter if (adapterClass != null && (adaptToClass == null || !adaptToClass.isAssignableFrom(clazz))) { TypeAdapter adapter = (TypeAdapter) createAndSet( project, adapterClass); adapter.checkProxyClass(clazz); } }
Get the constructor of the definition and invoke it.
Returns:the instantiated Object, will never be null.
/** * Get the constructor of the definition * and invoke it. * @return the instantiated <code>Object</code>, will never be null. */
private Object createAndSet(Project project, Class<?> c) { try { return innerCreateAndSet(c, project); } catch (InvocationTargetException ex) { Throwable t = ex.getTargetException(); throw new BuildException( "Could not create type " + name + " due to " + t, t); } catch (NoClassDefFoundError ncdfe) { String msg = "Type " + name + ": A class needed by class " + c + " cannot be found: " + ncdfe.getMessage(); throw new BuildException(msg, ncdfe); } catch (NoSuchMethodException nsme) { throw new BuildException("Could not create type " + name + " as the class " + c + " has no compatible constructor"); } catch (InstantiationException nsme) { throw new BuildException("Could not create type " + name + " as the class " + c + " is abstract"); } catch (IllegalAccessException e) { throw new BuildException("Could not create type " + name + " as the constructor " + c + " is not accessible"); } catch (Throwable t) { throw new BuildException( "Could not create type " + name + " due to " + t, t); } }
Inner implementation of the createAndSet(Project, Class<?>) logic, with no exception catching.
Params:
  • newclass – class to create
  • project – the project to use
Type parameters:
  • <T> – return type of the method
Throws:
Returns:a newly constructed and bound instance.
/** * Inner implementation of the {@link #createAndSet(Project, Class)} logic, with no * exception catching. * @param <T> return type of the method * @param newclass class to create * @param project the project to use * @return a newly constructed and bound instance. * @throws NoSuchMethodException no good constructor. * @throws InstantiationException cannot initialize the object. * @throws IllegalAccessException cannot access the object. * @throws InvocationTargetException error in invocation. */
public <T> T innerCreateAndSet(Class<T> newclass, Project project) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { Constructor<T> ctor; boolean noArg = false; // DataType can have a "no arg" constructor or take a single // Project argument. try { ctor = newclass.getConstructor(); noArg = true; } catch (NoSuchMethodException nse) { //can throw the same exception, if there is no this(Project) ctor. ctor = newclass.getConstructor(Project.class); noArg = false; } //now we instantiate T o = ctor.newInstance( ((noArg) ? new Object[0] : new Object[] {project})); //set up project references. project.setProjectReference(o); return o; }
Equality method for this definition (assumes the names are the same).
Params:
  • other – another definition.
  • project – the project the definition.
Returns:true if the definitions are the same.
/** * Equality method for this definition (assumes the names are the same). * * @param other another definition. * @param project the project the definition. * @return true if the definitions are the same. */
public boolean sameDefinition(AntTypeDefinition other, Project project) { return (other != null && other.getClass() == getClass() && other.getTypeClass(project).equals(getTypeClass(project)) && other.getExposedClass(project).equals(getExposedClass(project)) && other.restrict == restrict && other.adapterClass == adapterClass && other.adaptToClass == adaptToClass); }
Similar definition; used to compare two definitions defined twice with the same name and the same types. The classloader may be different but have the same path so #sameDefinition cannot be used.
Params:
  • other – the definition to compare to.
  • project – the current project.
Returns:true if the definitions are the same.
/** * Similar definition; * used to compare two definitions defined twice with the same * name and the same types. * The classloader may be different but have the same * path so #sameDefinition cannot * be used. * @param other the definition to compare to. * @param project the current project. * @return true if the definitions are the same. */
public boolean similarDefinition(AntTypeDefinition other, Project project) { if (other == null || getClass() != other.getClass() || !getClassName().equals(other.getClassName()) || !extractClassname(adapterClass).equals( extractClassname(other.adapterClass)) || !extractClassname(adaptToClass).equals( extractClassname(other.adaptToClass)) || restrict != other.restrict) { return false; } // all the names are the same: check if the class path of the loader // is the same ClassLoader oldLoader = other.getClassLoader(); ClassLoader newLoader = getClassLoader(); return oldLoader == newLoader || (oldLoader instanceof AntClassLoader && newLoader instanceof AntClassLoader && ((AntClassLoader) oldLoader).getClasspath() .equals(((AntClassLoader) newLoader).getClasspath())); } private String extractClassname(Class<?> c) { return (c == null) ? "<null>" : c.getName(); } }