git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@270215 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -8,12 +8,9 @@ | |||
| package org.apache.tools.ant; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.lang.reflect.Modifier; | |||
| import java.util.Enumeration; | |||
| import java.util.Hashtable; | |||
| import java.util.Properties; | |||
| import java.util.Stack; | |||
| import java.util.Vector; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| @@ -171,78 +168,6 @@ public class Project | |||
| return path.toString(); | |||
| } | |||
| private static TaskException makeCircularException( String end, Stack stk ) | |||
| { | |||
| StringBuffer sb = new StringBuffer( "Circular dependency: " ); | |||
| sb.append( end ); | |||
| String c; | |||
| do | |||
| { | |||
| c = (String)stk.pop(); | |||
| sb.append( " <- " ); | |||
| sb.append( c ); | |||
| } while( !c.equals( end ) ); | |||
| return new TaskException( new String( sb ) ); | |||
| } | |||
| /** | |||
| * set the base directory; XML attribute. checks for the directory existing | |||
| * and being a directory type | |||
| * | |||
| * @param baseDir project base directory. | |||
| * @throws TaskException if the directory was invalid | |||
| */ | |||
| public void setBaseDir( File baseDir ) | |||
| throws TaskException | |||
| { | |||
| baseDir = FileUtils.newFileUtils().normalize( baseDir.getAbsolutePath() ); | |||
| if( !baseDir.exists() ) | |||
| throw new TaskException( "Basedir " + baseDir.getAbsolutePath() + " does not exist" ); | |||
| if( !baseDir.isDirectory() ) | |||
| throw new TaskException( "Basedir " + baseDir.getAbsolutePath() + " is not a directory" ); | |||
| this.baseDir = baseDir; | |||
| setPropertyInternal( "basedir", this.baseDir.getPath() ); | |||
| String msg = "Project base dir set to: " + this.baseDir; | |||
| log( msg, MSG_VERBOSE ); | |||
| } | |||
| /** | |||
| * match basedir attribute in xml | |||
| * | |||
| * @param baseD project base directory. | |||
| * @throws TaskException if the directory was invalid | |||
| */ | |||
| public void setBasedir( String baseD ) | |||
| throws TaskException | |||
| { | |||
| setBaseDir( new File( baseD ) ); | |||
| } | |||
| public void setCoreLoader( ClassLoader coreLoader ) | |||
| { | |||
| this.coreLoader = coreLoader; | |||
| } | |||
| /** | |||
| * set the default target of the project XML attribute name. | |||
| * | |||
| * @param defaultTarget The new Default value | |||
| */ | |||
| public void setDefault( String defaultTarget ) | |||
| { | |||
| this.defaultTarget = defaultTarget; | |||
| } | |||
| /** | |||
| * set the project description | |||
| * | |||
| * @param description text | |||
| */ | |||
| public void setDescription( String description ) | |||
| { | |||
| this.description = description; | |||
| } | |||
| /** | |||
| * set the ant.java.version property, also tests for unsupported JVM | |||
| * versions, prints the verbose log messages | |||
| @@ -265,18 +190,6 @@ public class Project | |||
| log( "Detected OS: " + System.getProperty( "os.name" ), MSG_VERBOSE ); | |||
| } | |||
| /** | |||
| * ant xml property. Set the project name as an attribute of this class, and | |||
| * of the property ant.project.name | |||
| * | |||
| * @param name The new Name value | |||
| */ | |||
| public void setName( String name ) | |||
| { | |||
| setUserProperty( "ant.project.name", name ); | |||
| this.name = name; | |||
| } | |||
| /** | |||
| * set a property. An existing property of the same name will not be | |||
| * overwritten. | |||
| @@ -297,65 +210,6 @@ public class Project | |||
| properties.put( name, value ); | |||
| } | |||
| /** | |||
| * set a property. Any existing property of the same name is overwritten, | |||
| * unless it is a user property. | |||
| * | |||
| * @param name name of property | |||
| * @param value new value of the property | |||
| */ | |||
| public void setProperty( String name, String value ) | |||
| { | |||
| // command line properties take precedence | |||
| if( null != userProperties.get( name ) ) | |||
| { | |||
| log( "Override ignored for user property " + name, MSG_VERBOSE ); | |||
| return; | |||
| } | |||
| if( null != properties.get( name ) ) | |||
| { | |||
| log( "Overriding previous definition of property " + name, | |||
| MSG_VERBOSE ); | |||
| } | |||
| log( "Setting project property: " + name + " -> " + | |||
| value, MSG_DEBUG ); | |||
| properties.put( name, value ); | |||
| } | |||
| /** | |||
| * turn all the system properties into ant properties. user properties still | |||
| * override these values | |||
| */ | |||
| public void setSystemProperties() | |||
| { | |||
| Properties systemP = System.getProperties(); | |||
| Enumeration e = systemP.keys(); | |||
| while( e.hasMoreElements() ) | |||
| { | |||
| Object name = e.nextElement(); | |||
| String value = systemP.get( name ).toString(); | |||
| this.setPropertyInternal( name.toString(), value ); | |||
| } | |||
| } | |||
| /** | |||
| * set a user property, which can not be overwritten by set/unset property | |||
| * calls | |||
| * | |||
| * @param name The new UserProperty value | |||
| * @param value The new UserProperty value | |||
| * @see #setProperty(String,String) | |||
| */ | |||
| public void setUserProperty( String name, String value ) | |||
| { | |||
| log( "Setting ro project property: " + name + " -> " + | |||
| value, MSG_DEBUG ); | |||
| userProperties.put( name, value ); | |||
| properties.put( name, value ); | |||
| } | |||
| /** | |||
| * get the base directory of the project as a file object | |||
| * | |||
| @@ -364,25 +218,9 @@ public class Project | |||
| */ | |||
| public File getBaseDir() | |||
| { | |||
| if( baseDir == null ) | |||
| { | |||
| try | |||
| { | |||
| setBasedir( "." ); | |||
| } | |||
| catch( TaskException ex ) | |||
| { | |||
| ex.printStackTrace(); | |||
| } | |||
| } | |||
| return baseDir; | |||
| } | |||
| public Vector getBuildListeners() | |||
| { | |||
| return listeners; | |||
| } | |||
| public ClassLoader getCoreLoader() | |||
| { | |||
| return coreLoader; | |||
| @@ -398,41 +236,11 @@ public class Project | |||
| return dataClassDefinitions; | |||
| } | |||
| /** | |||
| * get the default target of the project | |||
| * | |||
| * @return default target or null | |||
| */ | |||
| public String getDefaultTarget() | |||
| { | |||
| return defaultTarget; | |||
| } | |||
| /** | |||
| * get the project description | |||
| * | |||
| * @return description or null if no description has been set | |||
| */ | |||
| public String getDescription() | |||
| { | |||
| return description; | |||
| } | |||
| public FilterSet getGlobalFilterSet() | |||
| { | |||
| return globalFilterSet; | |||
| } | |||
| /** | |||
| * get the project name | |||
| * | |||
| * @return name string | |||
| */ | |||
| public String getName() | |||
| { | |||
| return name; | |||
| } | |||
| /** | |||
| * get a copy of the property hashtable | |||
| * | |||
| @@ -501,314 +309,11 @@ public class Project | |||
| return taskClassDefinitions; | |||
| } | |||
| /** | |||
| * get a copy of the user property hashtable | |||
| * | |||
| * @return the hashtable user properties only | |||
| */ | |||
| public Hashtable getUserProperties() | |||
| { | |||
| Hashtable propertiesCopy = new Hashtable(); | |||
| Enumeration e = userProperties.keys(); | |||
| while( e.hasMoreElements() ) | |||
| { | |||
| Object name = e.nextElement(); | |||
| Object value = properties.get( name ); | |||
| propertiesCopy.put( name, value ); | |||
| } | |||
| return propertiesCopy; | |||
| } | |||
| /** | |||
| * query a user property. | |||
| * | |||
| * @param name the name of the property | |||
| * @return the property value, or null for no match | |||
| */ | |||
| public String getUserProperty( String name ) | |||
| { | |||
| if( name == null ) | |||
| return null; | |||
| String property = (String)userProperties.get( name ); | |||
| return property; | |||
| } | |||
| /** | |||
| * Topologically sort a set of Targets. | |||
| * | |||
| * @param root is the (String) name of the root Target. The sort is created | |||
| * in such a way that the sequence of Targets uptil the root target is | |||
| * the minimum possible such sequence. | |||
| * @param targets is a Hashtable representing a "name to Target" mapping | |||
| * @return a Vector of Strings with the names of the targets in sorted | |||
| * order. | |||
| * @exception TaskException if there is a cyclic dependency among the | |||
| * Targets, or if a Target does not exist. | |||
| */ | |||
| public final Vector topoSort( String root, Hashtable targets ) | |||
| throws TaskException | |||
| { | |||
| Vector ret = new Vector(); | |||
| Hashtable state = new Hashtable(); | |||
| Stack visiting = new Stack(); | |||
| // We first run a DFS based sort using the root as the starting node. | |||
| // This creates the minimum sequence of Targets to the root node. | |||
| // We then do a sort on any remaining unVISITED targets. | |||
| // This is unnecessary for doing our build, but it catches | |||
| // circular dependencies or missing Targets on the entire | |||
| // dependency tree, not just on the Targets that depend on the | |||
| // build Target. | |||
| tsort( root, targets, state, visiting, ret ); | |||
| log( "Build sequence for target `" + root + "' is " + ret, MSG_VERBOSE ); | |||
| for( Enumeration en = targets.keys(); en.hasMoreElements(); ) | |||
| { | |||
| String curTarget = (String)( en.nextElement() ); | |||
| String st = (String)state.get( curTarget ); | |||
| if( st == null ) | |||
| { | |||
| tsort( curTarget, targets, state, visiting, ret ); | |||
| } | |||
| else if( st == VISITING ) | |||
| { | |||
| throw new RuntimeException( "Unexpected node in visiting state: " + curTarget ); | |||
| } | |||
| } | |||
| log( "Complete build sequence is " + ret, MSG_VERBOSE ); | |||
| return ret; | |||
| } | |||
| public void addBuildListener( BuildListener listener ) | |||
| { | |||
| listeners.addElement( listener ); | |||
| } | |||
| /** | |||
| * add a new datatype | |||
| * | |||
| * @param typeName name of the datatype | |||
| * @param typeClass full datatype classname | |||
| */ | |||
| public void addDataTypeDefinition( String typeName, Class typeClass ) | |||
| { | |||
| if( null != dataClassDefinitions.get( typeName ) ) | |||
| { | |||
| log( "Trying to override old definition of datatype " + typeName, | |||
| MSG_WARN ); | |||
| } | |||
| String msg = " +User datatype: " + typeName + " " + typeClass.getName(); | |||
| log( msg, MSG_DEBUG ); | |||
| dataClassDefinitions.put( typeName, typeClass ); | |||
| } | |||
| /** | |||
| * @param target is the Target to be added or replaced in the current | |||
| * Project. | |||
| */ | |||
| public void addOrReplaceTarget( Target target ) | |||
| { | |||
| addOrReplaceTarget( target.getName(), target ); | |||
| } | |||
| /** | |||
| * @param target is the Target to be added/replaced in the current Project. | |||
| * @param targetName is the name to use for the Target | |||
| */ | |||
| public void addOrReplaceTarget( String targetName, Target target ) | |||
| { | |||
| String msg = " +Target: " + targetName; | |||
| log( msg, MSG_DEBUG ); | |||
| target.setProject( this ); | |||
| targets.put( targetName, target ); | |||
| } | |||
| public void addReference( String name, Object value ) | |||
| { | |||
| if( null != references.get( name ) ) | |||
| { | |||
| log( "Overriding previous definition of reference to " + name, | |||
| MSG_WARN ); | |||
| } | |||
| log( "Adding reference: " + name + " -> " + value, MSG_DEBUG ); | |||
| references.put( name, value ); | |||
| } | |||
| /** | |||
| * This call expects to add a <em>new</em> Target. | |||
| * | |||
| * @param target is the Target to be added to the current Project. | |||
| * @see Project#addOrReplaceTarget to replace existing Targets. | |||
| */ | |||
| public void addTarget( Target target ) | |||
| throws TaskException | |||
| { | |||
| String name = target.getName(); | |||
| if( targets.get( name ) != null ) | |||
| { | |||
| throw new TaskException( "Duplicate target: `" + name + "'" ); | |||
| } | |||
| addOrReplaceTarget( name, target ); | |||
| } | |||
| /** | |||
| * This call expects to add a <em>new</em> Target. | |||
| * | |||
| * @param target is the Target to be added to the current Project. | |||
| * @param targetName is the name to use for the Target | |||
| * @exception TaskException if the Target already exists in the project. | |||
| * @see Project#addOrReplaceTarget to replace existing Targets. | |||
| */ | |||
| public void addTarget( String targetName, Target target ) | |||
| throws TaskException | |||
| { | |||
| if( targets.get( targetName ) != null ) | |||
| { | |||
| throw new TaskException( "Duplicate target: `" + targetName + "'" ); | |||
| } | |||
| addOrReplaceTarget( targetName, target ); | |||
| } | |||
| /** | |||
| * add a new task definition, complain if there is an overwrite attempt | |||
| * | |||
| * @param taskName name of the task | |||
| * @param taskClass full task classname | |||
| * @throws TaskException and logs as Project.MSG_ERR for conditions, that | |||
| * will cause the task execution to fail. | |||
| */ | |||
| public void addTaskDefinition( String taskName, Class taskClass ) | |||
| throws TaskException | |||
| { | |||
| Class old = (Class)taskClassDefinitions.get( taskName ); | |||
| if( null != old ) | |||
| { | |||
| if( old.equals( taskClass ) ) | |||
| { | |||
| log( "Ignoring override for task " + taskName | |||
| + ", it is already defined by the same class.", | |||
| MSG_VERBOSE ); | |||
| return; | |||
| } | |||
| else | |||
| { | |||
| log( "Trying to override old definition of task " + taskName, | |||
| MSG_WARN ); | |||
| } | |||
| } | |||
| String msg = " +User task: " + taskName + " " + taskClass.getName(); | |||
| log( msg, MSG_DEBUG ); | |||
| checkTaskClass( taskClass ); | |||
| taskClassDefinitions.put( taskName, taskClass ); | |||
| } | |||
| /** | |||
| * Checks a class, whether it is suitable for serving as ant task. | |||
| * | |||
| * @param taskClass Description of Parameter | |||
| * @throws TaskException and logs as Project.MSG_ERR for conditions, that | |||
| * will cause the task execution to fail. | |||
| */ | |||
| public void checkTaskClass( final Class taskClass ) | |||
| throws TaskException | |||
| { | |||
| if( !Modifier.isPublic( taskClass.getModifiers() ) ) | |||
| { | |||
| final String message = taskClass + " is not public"; | |||
| log( message, Project.MSG_ERR ); | |||
| throw new TaskException( message ); | |||
| } | |||
| if( Modifier.isAbstract( taskClass.getModifiers() ) ) | |||
| { | |||
| final String message = taskClass + " is abstract"; | |||
| log( message, Project.MSG_ERR ); | |||
| throw new TaskException( message ); | |||
| } | |||
| try | |||
| { | |||
| taskClass.getConstructor( null ); | |||
| // don't have to check for public, since | |||
| // getConstructor finds public constructors only. | |||
| } | |||
| catch( NoSuchMethodException e ) | |||
| { | |||
| final String message = "No public default constructor in " + taskClass; | |||
| log( message, Project.MSG_ERR ); | |||
| throw new TaskException( message ); | |||
| } | |||
| if( !Task.class.isAssignableFrom( taskClass ) ) | |||
| TaskAdapter.checkTaskClass( taskClass, this ); | |||
| } | |||
| /** | |||
| * create a new DataType instance | |||
| * | |||
| * @param typeName name of the datatype | |||
| * @return null if the datatype name is unknown | |||
| * @throws TaskException when datatype creation goes bad | |||
| */ | |||
| public Object createDataType( String typeName ) | |||
| throws TaskException | |||
| { | |||
| Class c = (Class)dataClassDefinitions.get( typeName ); | |||
| if( c == null ) | |||
| return null; | |||
| try | |||
| { | |||
| java.lang.reflect.Constructor ctor = null; | |||
| boolean noArg = false; | |||
| // DataType can have a "no arg" constructor or take a single | |||
| // Project argument. | |||
| try | |||
| { | |||
| ctor = c.getConstructor( new Class[ 0 ] ); | |||
| noArg = true; | |||
| } | |||
| catch( NoSuchMethodException nse ) | |||
| { | |||
| ctor = c.getConstructor( new Class[]{Project.class} ); | |||
| noArg = false; | |||
| } | |||
| Object o = null; | |||
| if( noArg ) | |||
| { | |||
| o = ctor.newInstance( new Object[ 0 ] ); | |||
| } | |||
| else | |||
| { | |||
| o = ctor.newInstance( new Object[]{this} ); | |||
| } | |||
| if( o instanceof ProjectComponent ) | |||
| { | |||
| ( (ProjectComponent)o ).setProject( this ); | |||
| } | |||
| String msg = " +DataType: " + typeName; | |||
| log( msg, MSG_DEBUG ); | |||
| return o; | |||
| } | |||
| catch( java.lang.reflect.InvocationTargetException ite ) | |||
| { | |||
| Throwable t = ite.getTargetException(); | |||
| String msg = "Could not create datatype of type: " | |||
| + typeName + " due to " + t; | |||
| throw new TaskException( msg, t ); | |||
| } | |||
| catch( Throwable t ) | |||
| { | |||
| String msg = "Could not create datatype of type: " | |||
| + typeName + " due to " + t; | |||
| throw new TaskException( msg, t ); | |||
| } | |||
| } | |||
| /** | |||
| * create a new task instance | |||
| * | |||
| @@ -819,40 +324,7 @@ public class Project | |||
| public Task createTask( String taskType ) | |||
| throws TaskException | |||
| { | |||
| Class c = (Class)taskClassDefinitions.get( taskType ); | |||
| if( c == null ) | |||
| return null; | |||
| try | |||
| { | |||
| Object o = c.newInstance(); | |||
| Task task = null; | |||
| if( o instanceof Task ) | |||
| { | |||
| task = (Task)o; | |||
| } | |||
| else | |||
| { | |||
| // "Generic" Bean - use the setter pattern | |||
| // and an Adapter | |||
| TaskAdapter taskA = new TaskAdapter(); | |||
| taskA.setProxy( o ); | |||
| task = taskA; | |||
| } | |||
| task.setProject( this ); | |||
| //task.setTaskType( taskType ); | |||
| String msg = " +Task: " + taskType; | |||
| log( msg, MSG_DEBUG ); | |||
| addCreatedTask( taskType, task ); | |||
| return task; | |||
| } | |||
| catch( Throwable t ) | |||
| { | |||
| String msg = "Could not create task of type: " | |||
| + taskType + " due to " + t; | |||
| throw new TaskException( msg, t ); | |||
| } | |||
| throw new TaskException( "Task needs reimplementing" ); | |||
| } | |||
| public void demuxOutput( String line, boolean isError ) | |||
| @@ -860,7 +332,7 @@ public class Project | |||
| Task task = (Task)threadTasks.get( Thread.currentThread() ); | |||
| if( task == null ) | |||
| { | |||
| fireMessageLogged( this, line, isError ? MSG_ERR : MSG_INFO ); | |||
| //fireMessageLogged( this, line, isError ? MSG_ERR : MSG_INFO ); | |||
| } | |||
| else | |||
| { | |||
| @@ -875,113 +347,11 @@ public class Project | |||
| } | |||
| } | |||
| /** | |||
| * execute the targets and any targets it depends on | |||
| * | |||
| * @param targetName the target to execute | |||
| * @throws TaskException if the build failed | |||
| */ | |||
| public void executeTarget( String targetName ) | |||
| throws TaskException | |||
| { | |||
| } | |||
| /** | |||
| * Initialise the project. This involves setting the default task | |||
| * definitions and loading the system properties. | |||
| * | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| public void init() | |||
| throws TaskException | |||
| { | |||
| setJavaVersionProperty(); | |||
| String defs = "/org/apache/tools/ant/taskdefs/defaults.properties"; | |||
| try | |||
| { | |||
| Properties props = new Properties(); | |||
| InputStream in = this.getClass().getResourceAsStream( defs ); | |||
| if( in == null ) | |||
| { | |||
| throw new TaskException( "Can't load default task list" ); | |||
| } | |||
| props.load( in ); | |||
| in.close(); | |||
| Enumeration enum = props.propertyNames(); | |||
| while( enum.hasMoreElements() ) | |||
| { | |||
| String key = (String)enum.nextElement(); | |||
| String value = props.getProperty( key ); | |||
| try | |||
| { | |||
| Class taskClass = Class.forName( value ); | |||
| addTaskDefinition( key, taskClass ); | |||
| } | |||
| catch( NoClassDefFoundError ncdfe ) | |||
| { | |||
| // ignore... | |||
| } | |||
| catch( ClassNotFoundException cnfe ) | |||
| { | |||
| // ignore... | |||
| } | |||
| } | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| throw new TaskException( "Can't load default task list" ); | |||
| } | |||
| String dataDefs = "/org/apache/tools/ant/types/defaults.properties"; | |||
| try | |||
| { | |||
| Properties props = new Properties(); | |||
| InputStream in = this.getClass().getResourceAsStream( dataDefs ); | |||
| if( in == null ) | |||
| { | |||
| throw new TaskException( "Can't load default datatype list" ); | |||
| } | |||
| props.load( in ); | |||
| in.close(); | |||
| Enumeration enum = props.propertyNames(); | |||
| while( enum.hasMoreElements() ) | |||
| { | |||
| String key = (String)enum.nextElement(); | |||
| String value = props.getProperty( key ); | |||
| try | |||
| { | |||
| Class dataClass = Class.forName( value ); | |||
| addDataTypeDefinition( key, dataClass ); | |||
| } | |||
| catch( NoClassDefFoundError ncdfe ) | |||
| { | |||
| // ignore... | |||
| } | |||
| catch( ClassNotFoundException cnfe ) | |||
| { | |||
| // ignore... | |||
| } | |||
| } | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| throw new TaskException( "Can't load default datatype list" ); | |||
| } | |||
| setSystemProperties(); | |||
| } | |||
| /** | |||
| * Output a message to the log with the default log level of MSG_INFO | |||
| * | |||
| * @param msg text to log | |||
| */ | |||
| public void log( String msg ) | |||
| { | |||
| log( msg, MSG_INFO ); | |||
| @@ -996,7 +366,6 @@ public class Project | |||
| */ | |||
| public void log( String msg, int msgLevel ) | |||
| { | |||
| fireMessageLogged( this, msg, msgLevel ); | |||
| } | |||
| /** | |||
| @@ -1009,7 +378,6 @@ public class Project | |||
| */ | |||
| public void log( Task task, String msg, int msgLevel ) | |||
| { | |||
| fireMessageLogged( task, msg, msgLevel ); | |||
| } | |||
| /** | |||
| @@ -1022,12 +390,6 @@ public class Project | |||
| */ | |||
| public void log( Target target, String msg, int msgLevel ) | |||
| { | |||
| fireMessageLogged( target, msg, msgLevel ); | |||
| } | |||
| public void removeBuildListener( BuildListener listener ) | |||
| { | |||
| listeners.removeElement( listener ); | |||
| } | |||
| /** | |||
| @@ -1142,111 +504,6 @@ public class Project | |||
| } | |||
| } | |||
| /** | |||
| * send build finished event to the listeners | |||
| * | |||
| * @param exception exception which indicates failure if not null | |||
| */ | |||
| protected void fireBuildFinished( Throwable exception ) | |||
| { | |||
| BuildEvent event = new BuildEvent( this ); | |||
| event.setException( exception ); | |||
| for( int i = 0; i < listeners.size(); i++ ) | |||
| { | |||
| BuildListener listener = (BuildListener)listeners.elementAt( i ); | |||
| listener.buildFinished( event ); | |||
| } | |||
| } | |||
| /** | |||
| * send build started event to the listeners | |||
| */ | |||
| protected void fireBuildStarted() | |||
| { | |||
| BuildEvent event = new BuildEvent( this ); | |||
| for( int i = 0; i < listeners.size(); i++ ) | |||
| { | |||
| BuildListener listener = (BuildListener)listeners.elementAt( i ); | |||
| listener.buildStarted( event ); | |||
| } | |||
| } | |||
| protected void fireMessageLogged( Project project, String message, int priority ) | |||
| { | |||
| BuildEvent event = new BuildEvent( project ); | |||
| fireMessageLoggedEvent( event, message, priority ); | |||
| } | |||
| protected void fireMessageLogged( Target target, String message, int priority ) | |||
| { | |||
| BuildEvent event = new BuildEvent( target ); | |||
| fireMessageLoggedEvent( event, message, priority ); | |||
| } | |||
| protected void fireMessageLogged( Task task, String message, int priority ) | |||
| { | |||
| BuildEvent event = new BuildEvent( task ); | |||
| fireMessageLoggedEvent( event, message, priority ); | |||
| } | |||
| /** | |||
| * send build finished event to the listeners | |||
| * | |||
| * @param exception exception which indicates failure if not null | |||
| * @param target Description of Parameter | |||
| */ | |||
| protected void fireTargetFinished( Target target, Throwable exception ) | |||
| { | |||
| BuildEvent event = new BuildEvent( target ); | |||
| event.setException( exception ); | |||
| for( int i = 0; i < listeners.size(); i++ ) | |||
| { | |||
| BuildListener listener = (BuildListener)listeners.elementAt( i ); | |||
| listener.targetFinished( event ); | |||
| } | |||
| } | |||
| /** | |||
| * send target started event to the listeners | |||
| * | |||
| * @param target Description of Parameter | |||
| */ | |||
| protected void fireTargetStarted( Target target ) | |||
| { | |||
| BuildEvent event = new BuildEvent( target ); | |||
| for( int i = 0; i < listeners.size(); i++ ) | |||
| { | |||
| BuildListener listener = (BuildListener)listeners.elementAt( i ); | |||
| listener.targetStarted( event ); | |||
| } | |||
| } | |||
| protected void fireTaskFinished( Task task, Throwable exception ) | |||
| { | |||
| threadTasks.remove( Thread.currentThread() ); | |||
| System.out.flush(); | |||
| System.err.flush(); | |||
| BuildEvent event = new BuildEvent( task ); | |||
| event.setException( exception ); | |||
| for( int i = 0; i < listeners.size(); i++ ) | |||
| { | |||
| BuildListener listener = (BuildListener)listeners.elementAt( i ); | |||
| listener.taskFinished( event ); | |||
| } | |||
| } | |||
| protected void fireTaskStarted( Task task ) | |||
| { | |||
| // register this as the current task on the current thread. | |||
| threadTasks.put( Thread.currentThread(), task ); | |||
| BuildEvent event = new BuildEvent( task ); | |||
| for( int i = 0; i < listeners.size(); i++ ) | |||
| { | |||
| BuildListener listener = (BuildListener)listeners.elementAt( i ); | |||
| listener.taskStarted( event ); | |||
| } | |||
| } | |||
| /** | |||
| * Allows Project and subclasses to set a property unless its already | |||
| * defined as a user property. There are a few cases internally to Project | |||
| @@ -1263,105 +520,4 @@ public class Project | |||
| } | |||
| properties.put( name, value ); | |||
| } | |||
| // one step in a recursive DFS traversal of the Target dependency tree. | |||
| // - The Hashtable "state" contains the state (VISITED or VISITING or null) | |||
| // of all the target names. | |||
| // - The Stack "visiting" contains a stack of target names that are | |||
| // currently on the DFS stack. (NB: the target names in "visiting" are | |||
| // exactly the target names in "state" that are in the VISITING state.) | |||
| // 1. Set the current target to the VISITING state, and push it onto | |||
| // the "visiting" stack. | |||
| // 2. Throw a TaskException if any child of the current node is | |||
| // in the VISITING state (implies there is a cycle.) It uses the | |||
| // "visiting" Stack to construct the cycle. | |||
| // 3. If any children have not been VISITED, tsort() the child. | |||
| // 4. Add the current target to the Vector "ret" after the children | |||
| // have been visited. Move the current target to the VISITED state. | |||
| // "ret" now contains the sorted sequence of Targets upto the current | |||
| // Target. | |||
| private final void tsort( String root, Hashtable targets, | |||
| Hashtable state, Stack visiting, | |||
| Vector ret ) | |||
| throws TaskException | |||
| { | |||
| state.put( root, VISITING ); | |||
| visiting.push( root ); | |||
| Target target = (Target)( targets.get( root ) ); | |||
| // Make sure we exist | |||
| if( target == null ) | |||
| { | |||
| StringBuffer sb = new StringBuffer( "Target `" ); | |||
| sb.append( root ); | |||
| sb.append( "' does not exist in this project. " ); | |||
| visiting.pop(); | |||
| if( !visiting.empty() ) | |||
| { | |||
| String parent = (String)visiting.peek(); | |||
| sb.append( "It is used from target `" ); | |||
| sb.append( parent ); | |||
| sb.append( "'." ); | |||
| } | |||
| throw new TaskException( new String( sb ) ); | |||
| } | |||
| for( Enumeration en = target.getDependencies(); en.hasMoreElements(); ) | |||
| { | |||
| String cur = (String)en.nextElement(); | |||
| String m = (String)state.get( cur ); | |||
| if( m == null ) | |||
| { | |||
| // Not been visited | |||
| tsort( cur, targets, state, visiting, ret ); | |||
| } | |||
| else if( m == VISITING ) | |||
| { | |||
| // Currently visiting this node, so have a cycle | |||
| throw makeCircularException( cur, visiting ); | |||
| } | |||
| } | |||
| String p = (String)visiting.pop(); | |||
| if( root != p ) | |||
| { | |||
| throw new RuntimeException( "Unexpected internal error: expected to pop " + root + " but got " + p ); | |||
| } | |||
| state.put( root, VISITED ); | |||
| ret.addElement( target ); | |||
| } | |||
| /** | |||
| * Keep a record of all tasks that have been created so that they can be | |||
| * invalidated if a taskdef overrides the definition. | |||
| * | |||
| * @param type The feature to be added to the CreatedTask attribute | |||
| * @param task The feature to be added to the CreatedTask attribute | |||
| */ | |||
| private void addCreatedTask( String type, Task task ) | |||
| { | |||
| synchronized( createdTasks ) | |||
| { | |||
| Vector v = (Vector)createdTasks.get( type ); | |||
| if( v == null ) | |||
| { | |||
| v = new Vector(); | |||
| createdTasks.put( type, v ); | |||
| } | |||
| v.addElement( task ); | |||
| } | |||
| } | |||
| private void fireMessageLoggedEvent( BuildEvent event, String message, int priority ) | |||
| { | |||
| event.setMessage( message, priority ); | |||
| for( int i = 0; i < listeners.size(); i++ ) | |||
| { | |||
| BuildListener listener = (BuildListener)listeners.elementAt( i ); | |||
| listener.messageLogged( event ); | |||
| } | |||
| } | |||
| } | |||
| @@ -8,12 +8,9 @@ | |||
| package org.apache.tools.ant; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.lang.reflect.Modifier; | |||
| import java.util.Enumeration; | |||
| import java.util.Hashtable; | |||
| import java.util.Properties; | |||
| import java.util.Stack; | |||
| import java.util.Vector; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| @@ -171,78 +168,6 @@ public class Project | |||
| return path.toString(); | |||
| } | |||
| private static TaskException makeCircularException( String end, Stack stk ) | |||
| { | |||
| StringBuffer sb = new StringBuffer( "Circular dependency: " ); | |||
| sb.append( end ); | |||
| String c; | |||
| do | |||
| { | |||
| c = (String)stk.pop(); | |||
| sb.append( " <- " ); | |||
| sb.append( c ); | |||
| } while( !c.equals( end ) ); | |||
| return new TaskException( new String( sb ) ); | |||
| } | |||
| /** | |||
| * set the base directory; XML attribute. checks for the directory existing | |||
| * and being a directory type | |||
| * | |||
| * @param baseDir project base directory. | |||
| * @throws TaskException if the directory was invalid | |||
| */ | |||
| public void setBaseDir( File baseDir ) | |||
| throws TaskException | |||
| { | |||
| baseDir = FileUtils.newFileUtils().normalize( baseDir.getAbsolutePath() ); | |||
| if( !baseDir.exists() ) | |||
| throw new TaskException( "Basedir " + baseDir.getAbsolutePath() + " does not exist" ); | |||
| if( !baseDir.isDirectory() ) | |||
| throw new TaskException( "Basedir " + baseDir.getAbsolutePath() + " is not a directory" ); | |||
| this.baseDir = baseDir; | |||
| setPropertyInternal( "basedir", this.baseDir.getPath() ); | |||
| String msg = "Project base dir set to: " + this.baseDir; | |||
| log( msg, MSG_VERBOSE ); | |||
| } | |||
| /** | |||
| * match basedir attribute in xml | |||
| * | |||
| * @param baseD project base directory. | |||
| * @throws TaskException if the directory was invalid | |||
| */ | |||
| public void setBasedir( String baseD ) | |||
| throws TaskException | |||
| { | |||
| setBaseDir( new File( baseD ) ); | |||
| } | |||
| public void setCoreLoader( ClassLoader coreLoader ) | |||
| { | |||
| this.coreLoader = coreLoader; | |||
| } | |||
| /** | |||
| * set the default target of the project XML attribute name. | |||
| * | |||
| * @param defaultTarget The new Default value | |||
| */ | |||
| public void setDefault( String defaultTarget ) | |||
| { | |||
| this.defaultTarget = defaultTarget; | |||
| } | |||
| /** | |||
| * set the project description | |||
| * | |||
| * @param description text | |||
| */ | |||
| public void setDescription( String description ) | |||
| { | |||
| this.description = description; | |||
| } | |||
| /** | |||
| * set the ant.java.version property, also tests for unsupported JVM | |||
| * versions, prints the verbose log messages | |||
| @@ -265,18 +190,6 @@ public class Project | |||
| log( "Detected OS: " + System.getProperty( "os.name" ), MSG_VERBOSE ); | |||
| } | |||
| /** | |||
| * ant xml property. Set the project name as an attribute of this class, and | |||
| * of the property ant.project.name | |||
| * | |||
| * @param name The new Name value | |||
| */ | |||
| public void setName( String name ) | |||
| { | |||
| setUserProperty( "ant.project.name", name ); | |||
| this.name = name; | |||
| } | |||
| /** | |||
| * set a property. An existing property of the same name will not be | |||
| * overwritten. | |||
| @@ -297,65 +210,6 @@ public class Project | |||
| properties.put( name, value ); | |||
| } | |||
| /** | |||
| * set a property. Any existing property of the same name is overwritten, | |||
| * unless it is a user property. | |||
| * | |||
| * @param name name of property | |||
| * @param value new value of the property | |||
| */ | |||
| public void setProperty( String name, String value ) | |||
| { | |||
| // command line properties take precedence | |||
| if( null != userProperties.get( name ) ) | |||
| { | |||
| log( "Override ignored for user property " + name, MSG_VERBOSE ); | |||
| return; | |||
| } | |||
| if( null != properties.get( name ) ) | |||
| { | |||
| log( "Overriding previous definition of property " + name, | |||
| MSG_VERBOSE ); | |||
| } | |||
| log( "Setting project property: " + name + " -> " + | |||
| value, MSG_DEBUG ); | |||
| properties.put( name, value ); | |||
| } | |||
| /** | |||
| * turn all the system properties into ant properties. user properties still | |||
| * override these values | |||
| */ | |||
| public void setSystemProperties() | |||
| { | |||
| Properties systemP = System.getProperties(); | |||
| Enumeration e = systemP.keys(); | |||
| while( e.hasMoreElements() ) | |||
| { | |||
| Object name = e.nextElement(); | |||
| String value = systemP.get( name ).toString(); | |||
| this.setPropertyInternal( name.toString(), value ); | |||
| } | |||
| } | |||
| /** | |||
| * set a user property, which can not be overwritten by set/unset property | |||
| * calls | |||
| * | |||
| * @param name The new UserProperty value | |||
| * @param value The new UserProperty value | |||
| * @see #setProperty(String,String) | |||
| */ | |||
| public void setUserProperty( String name, String value ) | |||
| { | |||
| log( "Setting ro project property: " + name + " -> " + | |||
| value, MSG_DEBUG ); | |||
| userProperties.put( name, value ); | |||
| properties.put( name, value ); | |||
| } | |||
| /** | |||
| * get the base directory of the project as a file object | |||
| * | |||
| @@ -364,25 +218,9 @@ public class Project | |||
| */ | |||
| public File getBaseDir() | |||
| { | |||
| if( baseDir == null ) | |||
| { | |||
| try | |||
| { | |||
| setBasedir( "." ); | |||
| } | |||
| catch( TaskException ex ) | |||
| { | |||
| ex.printStackTrace(); | |||
| } | |||
| } | |||
| return baseDir; | |||
| } | |||
| public Vector getBuildListeners() | |||
| { | |||
| return listeners; | |||
| } | |||
| public ClassLoader getCoreLoader() | |||
| { | |||
| return coreLoader; | |||
| @@ -398,41 +236,11 @@ public class Project | |||
| return dataClassDefinitions; | |||
| } | |||
| /** | |||
| * get the default target of the project | |||
| * | |||
| * @return default target or null | |||
| */ | |||
| public String getDefaultTarget() | |||
| { | |||
| return defaultTarget; | |||
| } | |||
| /** | |||
| * get the project description | |||
| * | |||
| * @return description or null if no description has been set | |||
| */ | |||
| public String getDescription() | |||
| { | |||
| return description; | |||
| } | |||
| public FilterSet getGlobalFilterSet() | |||
| { | |||
| return globalFilterSet; | |||
| } | |||
| /** | |||
| * get the project name | |||
| * | |||
| * @return name string | |||
| */ | |||
| public String getName() | |||
| { | |||
| return name; | |||
| } | |||
| /** | |||
| * get a copy of the property hashtable | |||
| * | |||
| @@ -501,314 +309,11 @@ public class Project | |||
| return taskClassDefinitions; | |||
| } | |||
| /** | |||
| * get a copy of the user property hashtable | |||
| * | |||
| * @return the hashtable user properties only | |||
| */ | |||
| public Hashtable getUserProperties() | |||
| { | |||
| Hashtable propertiesCopy = new Hashtable(); | |||
| Enumeration e = userProperties.keys(); | |||
| while( e.hasMoreElements() ) | |||
| { | |||
| Object name = e.nextElement(); | |||
| Object value = properties.get( name ); | |||
| propertiesCopy.put( name, value ); | |||
| } | |||
| return propertiesCopy; | |||
| } | |||
| /** | |||
| * query a user property. | |||
| * | |||
| * @param name the name of the property | |||
| * @return the property value, or null for no match | |||
| */ | |||
| public String getUserProperty( String name ) | |||
| { | |||
| if( name == null ) | |||
| return null; | |||
| String property = (String)userProperties.get( name ); | |||
| return property; | |||
| } | |||
| /** | |||
| * Topologically sort a set of Targets. | |||
| * | |||
| * @param root is the (String) name of the root Target. The sort is created | |||
| * in such a way that the sequence of Targets uptil the root target is | |||
| * the minimum possible such sequence. | |||
| * @param targets is a Hashtable representing a "name to Target" mapping | |||
| * @return a Vector of Strings with the names of the targets in sorted | |||
| * order. | |||
| * @exception TaskException if there is a cyclic dependency among the | |||
| * Targets, or if a Target does not exist. | |||
| */ | |||
| public final Vector topoSort( String root, Hashtable targets ) | |||
| throws TaskException | |||
| { | |||
| Vector ret = new Vector(); | |||
| Hashtable state = new Hashtable(); | |||
| Stack visiting = new Stack(); | |||
| // We first run a DFS based sort using the root as the starting node. | |||
| // This creates the minimum sequence of Targets to the root node. | |||
| // We then do a sort on any remaining unVISITED targets. | |||
| // This is unnecessary for doing our build, but it catches | |||
| // circular dependencies or missing Targets on the entire | |||
| // dependency tree, not just on the Targets that depend on the | |||
| // build Target. | |||
| tsort( root, targets, state, visiting, ret ); | |||
| log( "Build sequence for target `" + root + "' is " + ret, MSG_VERBOSE ); | |||
| for( Enumeration en = targets.keys(); en.hasMoreElements(); ) | |||
| { | |||
| String curTarget = (String)( en.nextElement() ); | |||
| String st = (String)state.get( curTarget ); | |||
| if( st == null ) | |||
| { | |||
| tsort( curTarget, targets, state, visiting, ret ); | |||
| } | |||
| else if( st == VISITING ) | |||
| { | |||
| throw new RuntimeException( "Unexpected node in visiting state: " + curTarget ); | |||
| } | |||
| } | |||
| log( "Complete build sequence is " + ret, MSG_VERBOSE ); | |||
| return ret; | |||
| } | |||
| public void addBuildListener( BuildListener listener ) | |||
| { | |||
| listeners.addElement( listener ); | |||
| } | |||
| /** | |||
| * add a new datatype | |||
| * | |||
| * @param typeName name of the datatype | |||
| * @param typeClass full datatype classname | |||
| */ | |||
| public void addDataTypeDefinition( String typeName, Class typeClass ) | |||
| { | |||
| if( null != dataClassDefinitions.get( typeName ) ) | |||
| { | |||
| log( "Trying to override old definition of datatype " + typeName, | |||
| MSG_WARN ); | |||
| } | |||
| String msg = " +User datatype: " + typeName + " " + typeClass.getName(); | |||
| log( msg, MSG_DEBUG ); | |||
| dataClassDefinitions.put( typeName, typeClass ); | |||
| } | |||
| /** | |||
| * @param target is the Target to be added or replaced in the current | |||
| * Project. | |||
| */ | |||
| public void addOrReplaceTarget( Target target ) | |||
| { | |||
| addOrReplaceTarget( target.getName(), target ); | |||
| } | |||
| /** | |||
| * @param target is the Target to be added/replaced in the current Project. | |||
| * @param targetName is the name to use for the Target | |||
| */ | |||
| public void addOrReplaceTarget( String targetName, Target target ) | |||
| { | |||
| String msg = " +Target: " + targetName; | |||
| log( msg, MSG_DEBUG ); | |||
| target.setProject( this ); | |||
| targets.put( targetName, target ); | |||
| } | |||
| public void addReference( String name, Object value ) | |||
| { | |||
| if( null != references.get( name ) ) | |||
| { | |||
| log( "Overriding previous definition of reference to " + name, | |||
| MSG_WARN ); | |||
| } | |||
| log( "Adding reference: " + name + " -> " + value, MSG_DEBUG ); | |||
| references.put( name, value ); | |||
| } | |||
| /** | |||
| * This call expects to add a <em>new</em> Target. | |||
| * | |||
| * @param target is the Target to be added to the current Project. | |||
| * @see Project#addOrReplaceTarget to replace existing Targets. | |||
| */ | |||
| public void addTarget( Target target ) | |||
| throws TaskException | |||
| { | |||
| String name = target.getName(); | |||
| if( targets.get( name ) != null ) | |||
| { | |||
| throw new TaskException( "Duplicate target: `" + name + "'" ); | |||
| } | |||
| addOrReplaceTarget( name, target ); | |||
| } | |||
| /** | |||
| * This call expects to add a <em>new</em> Target. | |||
| * | |||
| * @param target is the Target to be added to the current Project. | |||
| * @param targetName is the name to use for the Target | |||
| * @exception TaskException if the Target already exists in the project. | |||
| * @see Project#addOrReplaceTarget to replace existing Targets. | |||
| */ | |||
| public void addTarget( String targetName, Target target ) | |||
| throws TaskException | |||
| { | |||
| if( targets.get( targetName ) != null ) | |||
| { | |||
| throw new TaskException( "Duplicate target: `" + targetName + "'" ); | |||
| } | |||
| addOrReplaceTarget( targetName, target ); | |||
| } | |||
| /** | |||
| * add a new task definition, complain if there is an overwrite attempt | |||
| * | |||
| * @param taskName name of the task | |||
| * @param taskClass full task classname | |||
| * @throws TaskException and logs as Project.MSG_ERR for conditions, that | |||
| * will cause the task execution to fail. | |||
| */ | |||
| public void addTaskDefinition( String taskName, Class taskClass ) | |||
| throws TaskException | |||
| { | |||
| Class old = (Class)taskClassDefinitions.get( taskName ); | |||
| if( null != old ) | |||
| { | |||
| if( old.equals( taskClass ) ) | |||
| { | |||
| log( "Ignoring override for task " + taskName | |||
| + ", it is already defined by the same class.", | |||
| MSG_VERBOSE ); | |||
| return; | |||
| } | |||
| else | |||
| { | |||
| log( "Trying to override old definition of task " + taskName, | |||
| MSG_WARN ); | |||
| } | |||
| } | |||
| String msg = " +User task: " + taskName + " " + taskClass.getName(); | |||
| log( msg, MSG_DEBUG ); | |||
| checkTaskClass( taskClass ); | |||
| taskClassDefinitions.put( taskName, taskClass ); | |||
| } | |||
| /** | |||
| * Checks a class, whether it is suitable for serving as ant task. | |||
| * | |||
| * @param taskClass Description of Parameter | |||
| * @throws TaskException and logs as Project.MSG_ERR for conditions, that | |||
| * will cause the task execution to fail. | |||
| */ | |||
| public void checkTaskClass( final Class taskClass ) | |||
| throws TaskException | |||
| { | |||
| if( !Modifier.isPublic( taskClass.getModifiers() ) ) | |||
| { | |||
| final String message = taskClass + " is not public"; | |||
| log( message, Project.MSG_ERR ); | |||
| throw new TaskException( message ); | |||
| } | |||
| if( Modifier.isAbstract( taskClass.getModifiers() ) ) | |||
| { | |||
| final String message = taskClass + " is abstract"; | |||
| log( message, Project.MSG_ERR ); | |||
| throw new TaskException( message ); | |||
| } | |||
| try | |||
| { | |||
| taskClass.getConstructor( null ); | |||
| // don't have to check for public, since | |||
| // getConstructor finds public constructors only. | |||
| } | |||
| catch( NoSuchMethodException e ) | |||
| { | |||
| final String message = "No public default constructor in " + taskClass; | |||
| log( message, Project.MSG_ERR ); | |||
| throw new TaskException( message ); | |||
| } | |||
| if( !Task.class.isAssignableFrom( taskClass ) ) | |||
| TaskAdapter.checkTaskClass( taskClass, this ); | |||
| } | |||
| /** | |||
| * create a new DataType instance | |||
| * | |||
| * @param typeName name of the datatype | |||
| * @return null if the datatype name is unknown | |||
| * @throws TaskException when datatype creation goes bad | |||
| */ | |||
| public Object createDataType( String typeName ) | |||
| throws TaskException | |||
| { | |||
| Class c = (Class)dataClassDefinitions.get( typeName ); | |||
| if( c == null ) | |||
| return null; | |||
| try | |||
| { | |||
| java.lang.reflect.Constructor ctor = null; | |||
| boolean noArg = false; | |||
| // DataType can have a "no arg" constructor or take a single | |||
| // Project argument. | |||
| try | |||
| { | |||
| ctor = c.getConstructor( new Class[ 0 ] ); | |||
| noArg = true; | |||
| } | |||
| catch( NoSuchMethodException nse ) | |||
| { | |||
| ctor = c.getConstructor( new Class[]{Project.class} ); | |||
| noArg = false; | |||
| } | |||
| Object o = null; | |||
| if( noArg ) | |||
| { | |||
| o = ctor.newInstance( new Object[ 0 ] ); | |||
| } | |||
| else | |||
| { | |||
| o = ctor.newInstance( new Object[]{this} ); | |||
| } | |||
| if( o instanceof ProjectComponent ) | |||
| { | |||
| ( (ProjectComponent)o ).setProject( this ); | |||
| } | |||
| String msg = " +DataType: " + typeName; | |||
| log( msg, MSG_DEBUG ); | |||
| return o; | |||
| } | |||
| catch( java.lang.reflect.InvocationTargetException ite ) | |||
| { | |||
| Throwable t = ite.getTargetException(); | |||
| String msg = "Could not create datatype of type: " | |||
| + typeName + " due to " + t; | |||
| throw new TaskException( msg, t ); | |||
| } | |||
| catch( Throwable t ) | |||
| { | |||
| String msg = "Could not create datatype of type: " | |||
| + typeName + " due to " + t; | |||
| throw new TaskException( msg, t ); | |||
| } | |||
| } | |||
| /** | |||
| * create a new task instance | |||
| * | |||
| @@ -819,40 +324,7 @@ public class Project | |||
| public Task createTask( String taskType ) | |||
| throws TaskException | |||
| { | |||
| Class c = (Class)taskClassDefinitions.get( taskType ); | |||
| if( c == null ) | |||
| return null; | |||
| try | |||
| { | |||
| Object o = c.newInstance(); | |||
| Task task = null; | |||
| if( o instanceof Task ) | |||
| { | |||
| task = (Task)o; | |||
| } | |||
| else | |||
| { | |||
| // "Generic" Bean - use the setter pattern | |||
| // and an Adapter | |||
| TaskAdapter taskA = new TaskAdapter(); | |||
| taskA.setProxy( o ); | |||
| task = taskA; | |||
| } | |||
| task.setProject( this ); | |||
| //task.setTaskType( taskType ); | |||
| String msg = " +Task: " + taskType; | |||
| log( msg, MSG_DEBUG ); | |||
| addCreatedTask( taskType, task ); | |||
| return task; | |||
| } | |||
| catch( Throwable t ) | |||
| { | |||
| String msg = "Could not create task of type: " | |||
| + taskType + " due to " + t; | |||
| throw new TaskException( msg, t ); | |||
| } | |||
| throw new TaskException( "Task needs reimplementing" ); | |||
| } | |||
| public void demuxOutput( String line, boolean isError ) | |||
| @@ -860,7 +332,7 @@ public class Project | |||
| Task task = (Task)threadTasks.get( Thread.currentThread() ); | |||
| if( task == null ) | |||
| { | |||
| fireMessageLogged( this, line, isError ? MSG_ERR : MSG_INFO ); | |||
| //fireMessageLogged( this, line, isError ? MSG_ERR : MSG_INFO ); | |||
| } | |||
| else | |||
| { | |||
| @@ -875,113 +347,11 @@ public class Project | |||
| } | |||
| } | |||
| /** | |||
| * execute the targets and any targets it depends on | |||
| * | |||
| * @param targetName the target to execute | |||
| * @throws TaskException if the build failed | |||
| */ | |||
| public void executeTarget( String targetName ) | |||
| throws TaskException | |||
| { | |||
| } | |||
| /** | |||
| * Initialise the project. This involves setting the default task | |||
| * definitions and loading the system properties. | |||
| * | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| public void init() | |||
| throws TaskException | |||
| { | |||
| setJavaVersionProperty(); | |||
| String defs = "/org/apache/tools/ant/taskdefs/defaults.properties"; | |||
| try | |||
| { | |||
| Properties props = new Properties(); | |||
| InputStream in = this.getClass().getResourceAsStream( defs ); | |||
| if( in == null ) | |||
| { | |||
| throw new TaskException( "Can't load default task list" ); | |||
| } | |||
| props.load( in ); | |||
| in.close(); | |||
| Enumeration enum = props.propertyNames(); | |||
| while( enum.hasMoreElements() ) | |||
| { | |||
| String key = (String)enum.nextElement(); | |||
| String value = props.getProperty( key ); | |||
| try | |||
| { | |||
| Class taskClass = Class.forName( value ); | |||
| addTaskDefinition( key, taskClass ); | |||
| } | |||
| catch( NoClassDefFoundError ncdfe ) | |||
| { | |||
| // ignore... | |||
| } | |||
| catch( ClassNotFoundException cnfe ) | |||
| { | |||
| // ignore... | |||
| } | |||
| } | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| throw new TaskException( "Can't load default task list" ); | |||
| } | |||
| String dataDefs = "/org/apache/tools/ant/types/defaults.properties"; | |||
| try | |||
| { | |||
| Properties props = new Properties(); | |||
| InputStream in = this.getClass().getResourceAsStream( dataDefs ); | |||
| if( in == null ) | |||
| { | |||
| throw new TaskException( "Can't load default datatype list" ); | |||
| } | |||
| props.load( in ); | |||
| in.close(); | |||
| Enumeration enum = props.propertyNames(); | |||
| while( enum.hasMoreElements() ) | |||
| { | |||
| String key = (String)enum.nextElement(); | |||
| String value = props.getProperty( key ); | |||
| try | |||
| { | |||
| Class dataClass = Class.forName( value ); | |||
| addDataTypeDefinition( key, dataClass ); | |||
| } | |||
| catch( NoClassDefFoundError ncdfe ) | |||
| { | |||
| // ignore... | |||
| } | |||
| catch( ClassNotFoundException cnfe ) | |||
| { | |||
| // ignore... | |||
| } | |||
| } | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| throw new TaskException( "Can't load default datatype list" ); | |||
| } | |||
| setSystemProperties(); | |||
| } | |||
| /** | |||
| * Output a message to the log with the default log level of MSG_INFO | |||
| * | |||
| * @param msg text to log | |||
| */ | |||
| public void log( String msg ) | |||
| { | |||
| log( msg, MSG_INFO ); | |||
| @@ -996,7 +366,6 @@ public class Project | |||
| */ | |||
| public void log( String msg, int msgLevel ) | |||
| { | |||
| fireMessageLogged( this, msg, msgLevel ); | |||
| } | |||
| /** | |||
| @@ -1009,7 +378,6 @@ public class Project | |||
| */ | |||
| public void log( Task task, String msg, int msgLevel ) | |||
| { | |||
| fireMessageLogged( task, msg, msgLevel ); | |||
| } | |||
| /** | |||
| @@ -1022,12 +390,6 @@ public class Project | |||
| */ | |||
| public void log( Target target, String msg, int msgLevel ) | |||
| { | |||
| fireMessageLogged( target, msg, msgLevel ); | |||
| } | |||
| public void removeBuildListener( BuildListener listener ) | |||
| { | |||
| listeners.removeElement( listener ); | |||
| } | |||
| /** | |||
| @@ -1142,111 +504,6 @@ public class Project | |||
| } | |||
| } | |||
| /** | |||
| * send build finished event to the listeners | |||
| * | |||
| * @param exception exception which indicates failure if not null | |||
| */ | |||
| protected void fireBuildFinished( Throwable exception ) | |||
| { | |||
| BuildEvent event = new BuildEvent( this ); | |||
| event.setException( exception ); | |||
| for( int i = 0; i < listeners.size(); i++ ) | |||
| { | |||
| BuildListener listener = (BuildListener)listeners.elementAt( i ); | |||
| listener.buildFinished( event ); | |||
| } | |||
| } | |||
| /** | |||
| * send build started event to the listeners | |||
| */ | |||
| protected void fireBuildStarted() | |||
| { | |||
| BuildEvent event = new BuildEvent( this ); | |||
| for( int i = 0; i < listeners.size(); i++ ) | |||
| { | |||
| BuildListener listener = (BuildListener)listeners.elementAt( i ); | |||
| listener.buildStarted( event ); | |||
| } | |||
| } | |||
| protected void fireMessageLogged( Project project, String message, int priority ) | |||
| { | |||
| BuildEvent event = new BuildEvent( project ); | |||
| fireMessageLoggedEvent( event, message, priority ); | |||
| } | |||
| protected void fireMessageLogged( Target target, String message, int priority ) | |||
| { | |||
| BuildEvent event = new BuildEvent( target ); | |||
| fireMessageLoggedEvent( event, message, priority ); | |||
| } | |||
| protected void fireMessageLogged( Task task, String message, int priority ) | |||
| { | |||
| BuildEvent event = new BuildEvent( task ); | |||
| fireMessageLoggedEvent( event, message, priority ); | |||
| } | |||
| /** | |||
| * send build finished event to the listeners | |||
| * | |||
| * @param exception exception which indicates failure if not null | |||
| * @param target Description of Parameter | |||
| */ | |||
| protected void fireTargetFinished( Target target, Throwable exception ) | |||
| { | |||
| BuildEvent event = new BuildEvent( target ); | |||
| event.setException( exception ); | |||
| for( int i = 0; i < listeners.size(); i++ ) | |||
| { | |||
| BuildListener listener = (BuildListener)listeners.elementAt( i ); | |||
| listener.targetFinished( event ); | |||
| } | |||
| } | |||
| /** | |||
| * send target started event to the listeners | |||
| * | |||
| * @param target Description of Parameter | |||
| */ | |||
| protected void fireTargetStarted( Target target ) | |||
| { | |||
| BuildEvent event = new BuildEvent( target ); | |||
| for( int i = 0; i < listeners.size(); i++ ) | |||
| { | |||
| BuildListener listener = (BuildListener)listeners.elementAt( i ); | |||
| listener.targetStarted( event ); | |||
| } | |||
| } | |||
| protected void fireTaskFinished( Task task, Throwable exception ) | |||
| { | |||
| threadTasks.remove( Thread.currentThread() ); | |||
| System.out.flush(); | |||
| System.err.flush(); | |||
| BuildEvent event = new BuildEvent( task ); | |||
| event.setException( exception ); | |||
| for( int i = 0; i < listeners.size(); i++ ) | |||
| { | |||
| BuildListener listener = (BuildListener)listeners.elementAt( i ); | |||
| listener.taskFinished( event ); | |||
| } | |||
| } | |||
| protected void fireTaskStarted( Task task ) | |||
| { | |||
| // register this as the current task on the current thread. | |||
| threadTasks.put( Thread.currentThread(), task ); | |||
| BuildEvent event = new BuildEvent( task ); | |||
| for( int i = 0; i < listeners.size(); i++ ) | |||
| { | |||
| BuildListener listener = (BuildListener)listeners.elementAt( i ); | |||
| listener.taskStarted( event ); | |||
| } | |||
| } | |||
| /** | |||
| * Allows Project and subclasses to set a property unless its already | |||
| * defined as a user property. There are a few cases internally to Project | |||
| @@ -1263,105 +520,4 @@ public class Project | |||
| } | |||
| properties.put( name, value ); | |||
| } | |||
| // one step in a recursive DFS traversal of the Target dependency tree. | |||
| // - The Hashtable "state" contains the state (VISITED or VISITING or null) | |||
| // of all the target names. | |||
| // - The Stack "visiting" contains a stack of target names that are | |||
| // currently on the DFS stack. (NB: the target names in "visiting" are | |||
| // exactly the target names in "state" that are in the VISITING state.) | |||
| // 1. Set the current target to the VISITING state, and push it onto | |||
| // the "visiting" stack. | |||
| // 2. Throw a TaskException if any child of the current node is | |||
| // in the VISITING state (implies there is a cycle.) It uses the | |||
| // "visiting" Stack to construct the cycle. | |||
| // 3. If any children have not been VISITED, tsort() the child. | |||
| // 4. Add the current target to the Vector "ret" after the children | |||
| // have been visited. Move the current target to the VISITED state. | |||
| // "ret" now contains the sorted sequence of Targets upto the current | |||
| // Target. | |||
| private final void tsort( String root, Hashtable targets, | |||
| Hashtable state, Stack visiting, | |||
| Vector ret ) | |||
| throws TaskException | |||
| { | |||
| state.put( root, VISITING ); | |||
| visiting.push( root ); | |||
| Target target = (Target)( targets.get( root ) ); | |||
| // Make sure we exist | |||
| if( target == null ) | |||
| { | |||
| StringBuffer sb = new StringBuffer( "Target `" ); | |||
| sb.append( root ); | |||
| sb.append( "' does not exist in this project. " ); | |||
| visiting.pop(); | |||
| if( !visiting.empty() ) | |||
| { | |||
| String parent = (String)visiting.peek(); | |||
| sb.append( "It is used from target `" ); | |||
| sb.append( parent ); | |||
| sb.append( "'." ); | |||
| } | |||
| throw new TaskException( new String( sb ) ); | |||
| } | |||
| for( Enumeration en = target.getDependencies(); en.hasMoreElements(); ) | |||
| { | |||
| String cur = (String)en.nextElement(); | |||
| String m = (String)state.get( cur ); | |||
| if( m == null ) | |||
| { | |||
| // Not been visited | |||
| tsort( cur, targets, state, visiting, ret ); | |||
| } | |||
| else if( m == VISITING ) | |||
| { | |||
| // Currently visiting this node, so have a cycle | |||
| throw makeCircularException( cur, visiting ); | |||
| } | |||
| } | |||
| String p = (String)visiting.pop(); | |||
| if( root != p ) | |||
| { | |||
| throw new RuntimeException( "Unexpected internal error: expected to pop " + root + " but got " + p ); | |||
| } | |||
| state.put( root, VISITED ); | |||
| ret.addElement( target ); | |||
| } | |||
| /** | |||
| * Keep a record of all tasks that have been created so that they can be | |||
| * invalidated if a taskdef overrides the definition. | |||
| * | |||
| * @param type The feature to be added to the CreatedTask attribute | |||
| * @param task The feature to be added to the CreatedTask attribute | |||
| */ | |||
| private void addCreatedTask( String type, Task task ) | |||
| { | |||
| synchronized( createdTasks ) | |||
| { | |||
| Vector v = (Vector)createdTasks.get( type ); | |||
| if( v == null ) | |||
| { | |||
| v = new Vector(); | |||
| createdTasks.put( type, v ); | |||
| } | |||
| v.addElement( task ); | |||
| } | |||
| } | |||
| private void fireMessageLoggedEvent( BuildEvent event, String message, int priority ) | |||
| { | |||
| event.setMessage( message, priority ); | |||
| for( int i = 0; i < listeners.size(); i++ ) | |||
| { | |||
| BuildListener listener = (BuildListener)listeners.elementAt( i ); | |||
| listener.messageLogged( event ); | |||
| } | |||
| } | |||
| } | |||