Browse Source

* Added new task <ant-call> to core, which can execute a named target

in the current project, or any referenced project.
* <ant1.ant> now works by executing AntTask.
* Fixed minor bug in DefaultClassloaderManager which was causing NPEs
  in URLClassLoader.
* DefaultTaskContext now removes properties when they are set to null.
  (rather than throwing a NPE inside HashMap).


git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@272067 13f79535-47bb-0310-9956-ffa450edef68
master
Darrell DeBoer 23 years ago
parent
commit
d2c225e370
10 changed files with 603 additions and 140 deletions
  1. +2
    -0
      proposal/myrmidon/ant1compat.xml
  2. +4
    -2
      proposal/myrmidon/src/ant1compat/ant-descriptor.xml
  3. +300
    -0
      proposal/myrmidon/src/ant1compat/org/apache/tools/ant/taskdefs/Ant.java
  4. +179
    -0
      proposal/myrmidon/src/java/org/apache/antlib/core/AbstractAntTask.java
  5. +68
    -0
      proposal/myrmidon/src/java/org/apache/antlib/core/AntCallTask.java
  6. +11
    -135
      proposal/myrmidon/src/java/org/apache/antlib/core/AntTask.java
  7. +3
    -1
      proposal/myrmidon/src/java/org/apache/antlib/core/Resources.properties
  8. +1
    -1
      proposal/myrmidon/src/java/org/apache/myrmidon/components/classloader/DefaultClassLoaderManager.java
  9. +9
    -1
      proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultTaskContext.java
  10. +26
    -0
      proposal/myrmidon/src/make/sample.ant

+ 2
- 0
proposal/myrmidon/ant1compat.xml View File

@@ -63,6 +63,8 @@
<exclude name="${ant1.package}/ant/Main.class"/>
<exclude name="${ant1.package}/ant/Task.class"/>
<exclude name="${ant1.package}/ant/BuildException.class"/>
<exclude name="${ant1.package}/ant/taskdefs/Ant.class"/>
<exclude name="${ant1.package}/ant/taskdefs/CallTarget.class"/>
<exclude name="${ant1.package}/ant/types/Path.class"/>
</patternset>



+ 4
- 2
proposal/myrmidon/src/ant1compat/ant-descriptor.xml View File

@@ -12,13 +12,15 @@
<!-- TaskAdapter tasks -->
<task name="ant1.condition"
classname="org.apache.tools.ant.Ant1CompatTaskAdapter" />
<!-- Tasks specialised for myrmidon -->
<task name="ant1.ant"
classname="org.apache.tools.ant.taskdefs.Ant" />

<!-- Tasks not currently supported.

<task name="ant1.antcall"
classname="org.apache.tools.ant.taskdefs.CallTarget" />
<task name="ant1.ant"
classname="org.apache.tools.ant.taskdefs.Ant" />
-->

<!-- standard ant tasks -->


+ 300
- 0
proposal/myrmidon/src/ant1compat/org/apache/tools/ant/taskdefs/Ant.java View File

@@ -0,0 +1,300 @@
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-2002 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Ant", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/

package org.apache.tools.ant.taskdefs;

import org.apache.tools.ant.Task;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.util.FileUtils;
import org.apache.avalon.framework.configuration.DefaultConfiguration;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.myrmidon.interfaces.executor.Executor;
import org.apache.myrmidon.interfaces.executor.ExecutionFrame;
import org.apache.myrmidon.api.TaskException;
import java.io.File;
import java.util.Vector;
import java.util.Iterator;

/**
* Call Ant in a sub-project.
*
* <pre>
* &lt;target name=&quot;foo&quot; depends=&quot;init&quot;&gt;
* &lt;ant antfile=&quot;build.xml&quot; target=&quot;bar&quot; &gt;
* &lt;property name=&quot;property1&quot; value=&quot;aaaaa&quot; /&gt;
* &lt;property name=&quot;foo&quot; value=&quot;baz&quot; /&gt;
* &lt;/ant&gt;</SPAN>
* &lt;/target&gt;</SPAN>
*
* &lt;target name=&quot;bar&quot; depends=&quot;init&quot;&gt;
* &lt;echo message=&quot;prop is ${property1} ${foo}&quot; /&gt;
* &lt;/target&gt;
* </pre>
*
*
* @author costin@dnt.ro
* @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a>
*/
public class Ant extends Task {

/** the basedir where is executed the build file */
private File dir = null;
/** the build.xml file (can be absolute) in this case dir will be ignored */
private String antFile = null;
/** the target to call if any */
private String target = null;
/** the output */
private String output = null;
/** should we inherit properties from the parent ? */
private boolean inheritAll = true;
/** should we inherit references from the parent ? */
private boolean inheritRefs = false;
/** the properties to pass to the new project */
private Vector properties = new Vector();
/** the references to pass to the new project */
private Vector references = new Vector();

/**
* If true, inherit all properties from parent Project
* If false, inherit only userProperties and those defined
* inside the ant call itself
*/
public void setInheritAll(boolean value) {
inheritAll = value;
}

/**
* If true, inherit all references from parent Project
* If false, inherit only those defined
* inside the ant call itself
*/
public void setInheritRefs(boolean value) {
inheritRefs = value;
}

/**
* ...
*/
public void setDir(File d) {
this.dir = d;
}

/**
* set the build file, it can be either absolute or relative.
* If it is absolute, <tt>dir</tt> will be ignored, if it is
* relative it will be resolved relative to <tt>dir</tt>.
*/
public void setAntfile(String s) {
// @note: it is a string and not a file to handle relative/absolute
// otherwise a relative file will be resolved based on the current
// basedir.
this.antFile = s;
}

/**
* set the target to execute. If none is defined it will
* execute the default target of the build file
*/
public void setTarget(String s) {
this.target = s;
}

public void setOutput(String s) {
this.output = s;
}

/** create a property to pass to the new project as a 'user property' */
public Property createProperty() {
Property p = new Property(true);
properties.addElement( p );
return p;
}

/**
* create a reference element that identifies a data type that
* should be carried over to the new project.
*/
public void addReference(Reference r) {
references.addElement(r);
}

/**
* Helper class that implements the nested &lt;reference&gt;
* element of &lt;ant&gt; and &lt;antcall&gt;.
*/
public static class Reference
extends org.apache.tools.ant.types.Reference {

public Reference() {super();}
private String targetid=null;
public void setToRefid(String targetid) { this.targetid=targetid; }
public String getToRefid() { return targetid; }
}

/**
* Called by the project to let the task do its work. This method may be
* called more than once, if the task is invoked more than once.
* For example,
* if target1 and target2 both depend on target3, then running
* "ant target1 target2" will run all tasks in target3 twice.
*
* @exception BuildException if something goes wrong with the build
*/
public void execute() throws BuildException
{
Object ant1project = unsetProject();

try
{
Configuration antConfig = buildAntTaskConfiguration();

executeTask( antConfig );
}
finally
{
resetProject( ant1project );
}
}

private void executeTask( Configuration antConfig )
{
try
{
Executor executor = (Executor) m_context.getService( Executor.class );
ExecutionFrame frame =
(ExecutionFrame) m_context.getService( ExecutionFrame.class );
executor.execute( antConfig, frame );
}
catch( TaskException e )
{
throw new BuildException( e );
}
}

private Configuration buildAntTaskConfiguration()
{
DefaultConfiguration antConfig = new DefaultConfiguration( "ant", "" );

antConfig.setAttribute( "inherit-all", String.valueOf( inheritAll ) );

// Ignore inheritRefs for now ( inheritAll == inheritRefs )

if ( target != null )
{
antConfig.setAttribute( "target", target );
}

// Get the "file" value.
if (antFile == null) {
antFile = "build.xml";
}

if ( dir == null )
{
dir = project.getBaseDir();
}

File file = FileUtils.newFileUtils().resolveFile(dir, antFile);
antFile = file.getAbsolutePath();

antConfig.setAttribute( "file", antFile );

// Add all of the properties.
Iterator iter = properties.iterator();
while( iter.hasNext() )
{
DefaultConfiguration param = new DefaultConfiguration( "param", "" );
Property property = (Property)iter.next();
param.setAttribute( "name", property.getName() );
param.setAttribute( "value", property.getValue() );
antConfig.addChild( param );
}
return antConfig;
}

private void resetProject( Object ant1project ) throws BuildException
{
try
{
m_context.setProperty( "ant1.project", ant1project );
}
catch( TaskException e )
{
throw new BuildException( e );
}
}

private Object unsetProject() throws BuildException
{
Object ant1project = null;
try
{
ant1project = m_context.getProperty( "ant1.project" );
m_context.setProperty( "ant1.project", null );
}
catch( TaskException e )
{
throw new BuildException( e );
}
return ant1project;
}
}

+ 179
- 0
proposal/myrmidon/src/java/org/apache/antlib/core/AbstractAntTask.java View File

@@ -0,0 +1,179 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE.txt file.
*/
package org.apache.antlib.core;

import org.apache.myrmidon.api.AbstractTask;
import org.apache.myrmidon.api.TaskException;
import org.apache.myrmidon.interfaces.model.Project;
import org.apache.myrmidon.interfaces.workspace.Workspace;
import org.apache.myrmidon.interfaces.embeddor.Embeddor;
import org.apache.avalon.framework.parameters.Parameters;
import java.util.Map;
import java.util.Iterator;
import java.util.ArrayList;

/**
* Abstract base class for Tasks which execute targets.
*
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
* @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a>
* @version $Revision$ $Date$
*/
public abstract class AbstractAntTask extends AbstractTask
{
/**
* If true, inherit all properties from parent Project
* If false, inherit only userProperties and those defined
* inside the ant call itself
*/
private boolean m_inheritAll;
/**
* The target to process in build file. If not specified
* will use default in specified build file.
*/
private String m_target;
private final ArrayList m_parameters = new ArrayList();

/**
* Specify whether should inherit properties in sub-build.
*
* @param inheritAll true to inherit else false
*/
public void setInheritAll( final boolean inheritAll )
{
m_inheritAll = inheritAll;
}

/**
* set the target to process. If none is defined it will
* execute the default target of the build file
*/
public void setTarget( final String target )
{
m_target = target;
}

/**
* Add a parameter to processing of build file.
*
* @param param the parameter
*/
public void addParam( final AntParam param )
{
m_parameters.add( param );
}

/**
* Execute the specified build, with specified parameters.
*
* @throws TaskException if an error occurs.
*/
public void execute()
throws TaskException
{
try
{
Project project = getProject();

Embeddor embeddor = getEmbeddor();

final Workspace workspace =
embeddor.createWorkspace( buildParameters() );

workspace.addProjectListener( embeddor.createListener("default"));

if( null == m_target )
{
m_target = project.getDefaultTargetName();
}

workspace.executeProject( project, m_target );
}
catch( final Exception e )
{
throw new TaskException( e.toString(), e );
}
}

/**
* A convenience method for obtaining the Embeddor from the
* TaskContext.
* @return The Embeddor contained in the TaskContext
* @throws TaskException if the Embeddor could not be obtained.
*/
protected Embeddor getEmbeddor() throws TaskException
{
final Embeddor embeddor =
(Embeddor)getContext().getService( Embeddor.class );
return embeddor;
}

/**
* Get/create/build the project containing the target to be executed.
* Subclasses will override this method to provide different means
* of obtaining a project to execute.
* @return The project containing the target to execute.
* @throws Exception If a problem occurred building the project.
*/
protected abstract Project getProject() throws Exception;

/**
* Build the parameters to pass to sub-project.
* These include the current tasks properties
* (if inheritall=true) and any supplied by the user.
*
* @return the created parameters
*/
private Parameters buildParameters()
throws TaskException
{
final Parameters parameters = new Parameters();

if( m_inheritAll )
{
final Map properties = getContext().getProperties();
final Iterator keys = properties.keySet().iterator();
while( keys.hasNext() )
{
final String key = (String)keys.next();
final Object value = properties.get( key );
setProperty( parameters, key, value );
}
}

final int size = m_parameters.size();
for( int i = 0; i < size; i++ )
{
final AntParam param = (AntParam)m_parameters.get( i );
param.validate();
final String name = param.getName();
final String value = param.getValue().toString();
setProperty( parameters, name, value );
}

return parameters;
}

/**
* Utility method to add the property into parameters object.
*
* @param parameters where to put property
* @param name the property
* @param value the value of property
* @todo allow non-string params to be passed down
*/
private void setProperty( final Parameters parameters,
final String name,
final Object value )
{
if( !name.startsWith( "myrmidon." ) )
{
parameters.setParameter( name, value.toString() );
}
}
}

+ 68
- 0
proposal/myrmidon/src/java/org/apache/antlib/core/AntCallTask.java View File

@@ -0,0 +1,68 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE.txt file.
*/
package org.apache.antlib.core;

import org.apache.avalon.excalibur.i18n.ResourceManager;
import org.apache.avalon.excalibur.i18n.Resources;
import org.apache.myrmidon.api.TaskException;
import org.apache.myrmidon.interfaces.model.Project;

/**
* A task which executes a target in the current project,
* or a referenced project.
*
* @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a>
* @version $Revision$ $Date$
* @ant.task name="ant-call"
*/
public class AntCallTask extends AbstractAntTask
{
private final static Resources REZ =
ResourceManager.getPackageResources( AntCallTask.class );

private String m_project;

/**
* Specifies the project to execute. If not specified, the current
* project is used.
* @param project the name of the Project to execute.
*/
public void setProject( String project )
{
m_project = project;
}

/**
* Get/create/build the project which will be executed.
* Subclasses will override this method to provide different means
* of obtaining a project to execute.
* @return The project containing the target to execute.
* @throws Exception If a problem occurred building the project.
*/
protected Project getProject() throws Exception
{
Project currentProject =
(Project)getContext().getService( Project.class );

// By default, use the current project.
Project referencedProject = currentProject;

if( m_project != null )
{
referencedProject = currentProject.getProject( m_project );
if( referencedProject == null )
{
final String message =
REZ.getString( "antcall.invalid-project.error" );
throw new TaskException( message );
}
}

return referencedProject;
}
}

+ 11
- 135
proposal/myrmidon/src/java/org/apache/antlib/core/AntTask.java View File

@@ -8,66 +8,35 @@
package org.apache.antlib.core;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.myrmidon.api.AbstractTask;
import org.apache.myrmidon.api.TaskException;
import org.apache.myrmidon.interfaces.embeddor.Embeddor;
import org.apache.myrmidon.interfaces.model.Project;
import org.apache.myrmidon.interfaces.workspace.Workspace;

/**
* Create a new Workspace and process a build in
* that new workspace.
* Executes a target in a named build file.
*
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
* @ant.task name="ant"
*/
public class AntTask
extends AbstractTask

extends AbstractAntTask
{
/**
* Default build file.
*/
private static final String DEFAULT_BUILD_FILE = "build.ant";

/**
* If true, inherit all properties from parent Project
* If false, inherit only userProperties and those defined
* inside the ant call itself
*/
private boolean m_inheritAll;

/**
* The build file which to execute. If not set defaults to
* using "build.ant" in the basedir of current project.
*/
private File m_file;

/**
* The target to process in build file. If not specified
* will use default in specified build file.
*/
private String m_target;

/**
* The "type" of the build file. By default this is null which
* means the type will be determined by the build file extension.
*/
private String m_type;
private final ArrayList m_parameters = new ArrayList();

/**
* Specify whether should inherit properties in sub-build.
*
* @param inheritAll true to inherit else false
*/
public void setInheritAll( final boolean inheritAll )
{
m_inheritAll = inheritAll;
}

/**
* set the build file to process.
@@ -90,114 +59,21 @@ public class AntTask
}

/**
* set the target to process. If none is defined it will
* execute the default target of the build file
* @return The project containing the target to execute.
* @throws Exception If a problem occurred building the project.
*/
public void setTarget( final String target )
{
m_target = target;
}

/**
* Add a parameter to processing of build file.
*
* @param param the parameter
*/
public void addParam( final AntParam param )
{
m_parameters.add( param );
}

/**
* Execute the specified build, with specified parameters.
*
* @throws TaskException if an error occurs.
*/
public void execute()
throws TaskException
protected Project getProject() throws Exception
{
if( null == m_file )
{
m_file = getContext().resolveFile( DEFAULT_BUILD_FILE );
}

final Embeddor embeddor =
(Embeddor)getContext().getService( Embeddor.class );

try
{
final Project project =
embeddor.createProject( m_file.toString(),
m_type,
new Parameters() );
final Workspace workspace =
embeddor.createWorkspace( buildParameters() );

if( null == m_target )
{
m_target = project.getDefaultTargetName();
}

workspace.executeProject( project, m_target );
}
catch( final Exception e )
{
throw new TaskException( e.toString(), e );
}
}

/**
* Build the parameters to pass to sub-project.
* These include the current tasks properties
* (if inheritall=true) and any supplied by the user.
*
* @return the created parameters
*/
private Parameters buildParameters()
throws TaskException
{
final Parameters parameters = new Parameters();

if( m_inheritAll )
{
final Map properties = getContext().getProperties();
final Iterator keys = properties.keySet().iterator();
while( keys.hasNext() )
{
final String key = (String)keys.next();
final Object value = properties.get( key );
setProperty( parameters, key, value );
}
}

final int size = m_parameters.size();
for( int i = 0; i < size; i++ )
{
final AntParam param = (AntParam)m_parameters.get( i );
param.validate();
final String name = param.getName();
final String value = param.getValue().toString();
setProperty( parameters, name, value );
}

return parameters;
final Project project =
getEmbeddor().createProject( m_file.toString(),
m_type,
new Parameters() );
return project;
}

/**
* Utility method to add the property into parameters object.
*
* @param parameters where to put property
* @param name the property
* @param value the value of property
* @todo allow non-string params to be passed down
*/
private void setProperty( final Parameters parameters,
final String name,
final Object value )
{
if( !name.startsWith( "myrmidon." ) )
{
parameters.setParameter( name, value.toString() );
}
}
}

+ 3
- 1
proposal/myrmidon/src/java/org/apache/antlib/core/Resources.properties View File

@@ -34,4 +34,6 @@ filetokenset.not-a-file.error=File {0} does not exist, or is not a file.
filetokenset.read-tokens.error=Could not read tokens from {0}.

param.noname.error=Missing name from parameter.
param.novalue.error=Missing value from parameter "{0}".
param.novalue.error=Missing value from parameter "{0}".

antcall.invalid-project.error=Project-reference "{0}" not found.

+ 1
- 1
proposal/myrmidon/src/java/org/apache/myrmidon/components/classloader/DefaultClassLoaderManager.java View File

@@ -155,7 +155,7 @@ public class DefaultClassLoaderManager
private URL[] buildClasspath( final ArrayList files )
throws MalformedURLException
{
final URL[] urls = new URL[ files.size() + 1 ];
final URL[] urls = new URL[ files.size() ];
final int count = files.size();
for( int i = 0; i < count; i++ )
{


+ 9
- 1
proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultTaskContext.java View File

@@ -214,7 +214,15 @@ public class DefaultTaskContext
{
checkPropertyName( name );
checkPropertyValid( name, value );
m_contextData.put( name, value );

if ( value == null )
{
m_contextData.remove( name );
}
else
{
m_contextData.put( name, value );
}
}

/**


+ 26
- 0
proposal/myrmidon/src/make/sample.ant View File

@@ -279,6 +279,32 @@ Legal:
<ant/>
</target>

<target name="antcall-test">
<log message="Testing antcall task..."/>
<ant-call target="if-test"/>

<log message="Using params..."/>
<ant-call target="prop-print">
<param name="meep.meep" value="Meep!"/>
</ant-call>

<log message="Using params value-ref..."/>
<pattern id="meep.data" name="*.java" if="..." />
<ant-call target="prop-print">
<param name="meep.meep" value-ref="meep.data"/>
</ant-call>

<log message="Using inheritall..."/>
<pattern id="meep.meep" name="*.java" if="..." />
<ant-call target="prop-print" inherit-all="true"/>

<log message="Calling referenced project, default target..."/>
<ant-call project="prim"/>

<log message="Calling referenced project, named target..."/>
<ant-call project="prim" target="extensions-test"/>
</target>

<target name="prop-print">
<log message="Give me a property ... ${meep.meep}"/>
</target>


Loading…
Cancel
Save