Browse Source

A small refactoring, getting to a more 'real' interface for the dynamic

properties.

This is not final, of course.

PropertyHelper will implement all property manipulation. Eventually in
ant1.6 the static methods in various places should just wrap and
call this. In 1.6 the property storage can also be migrated to this
class.

It should be possible by a task or embedding application to replace
the whole mechanism - no need for discovery on this one, it can be
done by a task.

The PropertyInterceptor will be used to plug different sources
for the property. I'm thinking to just have tasks/types implementing
this interface automatically get registered - it's the simpler
solution for tasks developers ( I think ).


git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@273107 13f79535-47bb-0310-9956-ffa450edef68
master
Costin Manolache 23 years ago
parent
commit
13c833611e
6 changed files with 330 additions and 121 deletions
  1. +4
    -4
      proposal/sandbox/embed/ProjectHelperImpl2.java
  2. +219
    -0
      proposal/sandbox/embed/PropertyHelper.java
  3. +95
    -0
      proposal/sandbox/embed/PropertyInterceptor.java
  4. +4
    -117
      proposal/sandbox/embed/RuntimeConfigurable2.java
  5. BIN
      proposal/sandbox/embed/ant-sax2.jar
  6. +8
    -0
      proposal/sandbox/embed/build.xml

+ 4
- 4
proposal/sandbox/embed/ProjectHelperImpl2.java View File

@@ -129,7 +129,7 @@ public class ProjectHelperImpl2 extends ProjectHelper {
ex.printStackTrace();
}
}
/**
* Parses the project file, configuring the project as it goes.
*
@@ -835,7 +835,7 @@ public class ProjectHelperImpl2 extends ProjectHelper {
}
} else {
task.init();
RuntimeConfigurable2.configure(task, attrs, context.project);
PropertyHelper.getPropertyHelper(context.project).configure(task, attrs, context.project);
}
}

@@ -999,7 +999,7 @@ public class ProjectHelperImpl2 extends ProjectHelper {
childWrapper.setAttributes2(attrs);
parentWrapper.addChild(childWrapper);
} else {
RuntimeConfigurable2.configure(child, attrs, context.project);
PropertyHelper.getPropertyHelper(context.project).configure(child, attrs, context.project);
ih.storeElement(context.project, parent, child, elementName);
}
} catch (BuildException exc) {
@@ -1117,7 +1117,7 @@ public class ProjectHelperImpl2 extends ProjectHelper {
wrapper.setAttributes2(attrs);
target.addDataType(wrapper);
} else {
RuntimeConfigurable2.configure(element, attrs, context.project);
PropertyHelper.getPropertyHelper(context.project).configure(element, attrs, context.project);
context.configureId(element, attrs);
}
} catch (BuildException exc) {


+ 219
- 0
proposal/sandbox/embed/PropertyHelper.java View File

@@ -0,0 +1,219 @@
/*
* 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;

import org.apache.tools.ant.helper.*;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Vector;
import java.util.Hashtable;
import org.xml.sax.AttributeList;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.AttributeListImpl;
import org.xml.sax.helpers.AttributesImpl;

/**
* Deals with properties - substitution, dynamic properties, etc.
*
* Eventually the static methods from ProjectHelper should be
* moved here ( with a wrapper for backward compat ).
*
* Also the property store ( Hashtable ) and all property manipulation
* logic could be moved here.
*
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
* @author Costin Manolache
*/
public class PropertyHelper {
Project project;
Vector propertyInterceptors=new Vector();
protected PropertyHelper() {
}

public void setProject(Project p ) {
this.project=p;
}

/** Factory method to create a property processor.
* Right now returns the singleton instance of PropertyHelper,
* in future it may use discovery of config to return a
* customized version, for integration in other apps.
*/
public static PropertyHelper getPropertyHelper(Project project) {
PropertyHelper ph=(PropertyHelper)project.getReference( "ant.PropertyHelper" );
if( ph!=null ) return ph;
ph=new PropertyHelper();
ph.setProject( project );

project.addReference( "ant.PropertyHelper",ph );
return ph;
}
public void addPropertyInterceptor( PropertyInterceptor pi ) {
propertyInterceptors.addElement( pi );
}

// public Vector getPropertyInterceptors() {
// return propertyInterceptors;
// }
/** Process an value, doing the replacements.
*/
public String replaceProperties( String value ) {
if (value == null) {
return null;
}

Vector fragments = new Vector();
Vector propertyRefs = new Vector();

// XXX Move the static method here - if this is accepted in the main
// branch.
ProjectHelper.parsePropertyString(value, fragments, propertyRefs);

StringBuffer sb = new StringBuffer();
Enumeration i = fragments.elements();
Enumeration j = propertyRefs.elements();
while (i.hasMoreElements()) {
String fragment = (String) i.nextElement();
if (fragment == null) {
String propertyName = (String) j.nextElement();

Object repl=processDynamic( project, propertyName);

if( repl==null) {
// default to the static property.
repl=project.getProperty( propertyName );
}
if (repl==null ) {
project.log("Property ${" + propertyName
+ "} has not been set", Project.MSG_VERBOSE);
fragment="${" + propertyName + "}";
} else {
fragment = (String) repl;
}
}
sb.append(fragment);
}
return sb.toString();
}

/** Use the reference table to generate values for ${} substitution.
* To preserve backward compat ( as much as possible ) we'll only process
* ids with a 'namespace-like' syntax.
*
* Currently we support:
* dom:idName:/xpath/like/syntax - the referenced node must be a DOM, we'll use
* XPath to extract a node. ( a simplified syntax is handled
* directly, XXX used for 'real' xpaths ).
* toString:idName - we use toString on the referenced object
* bean:idName.propertyName - we get the idName and call the getter for the property.
*/
Object processDynamic( Project project, String name ) {
for(int i=0; i<propertyInterceptors.size(); i++ ) {
PropertyInterceptor pi=(PropertyInterceptor)propertyInterceptors.elementAt( i );
Object o=pi.getProperty( project, null, name );
if( o!=null )
return o;
}

// experimental - will be removed.
if( name.startsWith( "toString:" )) {
name=name.substring( "toString:".length());
Object v=project.getReference( name );
if( v==null ) return null;
return v.toString();
}

return null;
}

/** Configure a component using SAX2 attributes.
*/
public void configure( Object target, Attributes attrs, Project project )
throws BuildException
{
if (target instanceof TaskAdapter) {
target = ((TaskAdapter) target).getProxy();
}
IntrospectionHelper ih =
IntrospectionHelper.getHelper(target.getClass());
project.addBuildListener(ih);
for (int i = 0; i < attrs.getLength(); i++) {
// reflect these into the target
String value = replaceProperties(attrs.getValue(i));
try {
ih.setAttribute(project, target,
attrs.getQName(i).toLowerCase(Locale.US), value);
} catch (BuildException be) {
// id attribute must be set externally
if (!attrs.getQName(i).equals("id")) {
throw be;
}
}
}
}

}

+ 95
- 0
proposal/sandbox/embed/PropertyInterceptor.java View File

@@ -0,0 +1,95 @@
/*
* 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;

import org.apache.tools.ant.helper.*;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Vector;
import java.util.Hashtable;
import org.xml.sax.AttributeList;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.AttributeListImpl;
import org.xml.sax.helpers.AttributesImpl;

/**
* The new XML processor will use this interface to support
* dynamic properties.
*
* Any task/type that implements this interface will be registered
* and will receive notification of each property get operations
* executed by the processor.
*
* XXX In ant1.6+, tasks implementing the interface will also
* receive notification when a property is set.
*
* @author Costin Manolache
*/
public interface PropertyInterceptor {

/**
* Called for each ${} property. If the result is null the
* next PropertyInterceptor will be called. If all interceptors
* return null, the properties stored in Project are used.
*/
public Object getProperty( Project p, String ns, String name );

/**
* Called when a property/reference is recorded.
* XXX Not implemented yet.
*/
// public boolean setProperty( String ns, String name, Object value );

}

+ 4
- 117
proposal/sandbox/embed/RuntimeConfigurable2.java View File

@@ -176,7 +176,7 @@ public class RuntimeConfigurable2 extends RuntimeConfigurable {
* @return The child wrapper at position <code>index</code> within the
* list.
*/
RuntimeConfigurable getChild(int index) {
public RuntimeConfigurable getChild(int index) {
return (RuntimeConfigurable) children.elementAt(index);
}

@@ -234,7 +234,8 @@ public class RuntimeConfigurable2 extends RuntimeConfigurable {
String id = null;

if (attributes != null) {
configure(wrappedObject, attributes, p);
PropertyHelper ph=PropertyHelper.getPropertyHelper(p);
ph.configure(wrappedObject, attributes, p);
id = attributes.getValue("id");
attributes = null;
}
@@ -255,125 +256,11 @@ public class RuntimeConfigurable2 extends RuntimeConfigurable {
child.maybeConfigure(p);
}
ProjectHelper.storeChild(p, wrappedObject, child.wrappedObject,
child.getElementTag().toLowerCase(Locale.US));
child.getElementTag().toLowerCase(Locale.US));
}

if (id != null) {
p.addReference(id, wrappedObject);
}
}


public static void configure( Object target, Attributes attrs, Project project )
throws BuildException
{
if (target instanceof TaskAdapter) {
target = ((TaskAdapter) target).getProxy();
}
IntrospectionHelper ih =
IntrospectionHelper.getHelper(target.getClass());
project.addBuildListener(ih);
for (int i = 0; i < attrs.getLength(); i++) {
// reflect these into the target
String value = RuntimeConfigurable2.replaceProperties(project, attrs.getValue(i));
try {
ih.setAttribute(project, target,
attrs.getQName(i).toLowerCase(Locale.US), value);
} catch (BuildException be) {
// id attribute must be set externally
if (!attrs.getQName(i).equals("id")) {
throw be;
}
}
}
}

public static String replaceProperties( Project project ,String value ) {
if (value == null) {
return null;
}

Vector fragments = new Vector();
Vector propertyRefs = new Vector();

ProjectHelper.parsePropertyString(value, fragments, propertyRefs);

StringBuffer sb = new StringBuffer();
Enumeration i = fragments.elements();
Enumeration j = propertyRefs.elements();
while (i.hasMoreElements()) {
String fragment = (String) i.nextElement();
if (fragment == null) {
String propertyName = (String) j.nextElement();
Object repl=project.getProperty( propertyName );

if( repl==null) {
// Try a dynamic substitiution using ref
repl=processReference( project, propertyName );
}
if (repl==null ) {
project.log("Property ${" + propertyName
+ "} has not been set", Project.MSG_VERBOSE);
fragment="${" + propertyName + "}";
} else {
fragment = (String) repl;
}
}
sb.append(fragment);
}
return sb.toString();

}

static Hashtable propertySources=new Hashtable();

public static interface ProjectPropertySource {

public String getProperty( Project project, String key );
}
public static void addPropertySource( String ns, ProjectPropertySource src ) {
propertySources.put( ns, src );
}

/** Use the reference table to generate values for ${} substitution.
* To preserve backward compat ( as much as possible ) we'll only process
* ids with a 'namespace-like' syntax.
*
* Currently we support:
* dom:idName:/xpath/like/syntax - the referenced node must be a DOM, we'll use
* XPath to extract a node. ( a simplified syntax is handled
* directly, XXX used for 'real' xpaths ).
* toString:idName - we use toString on the referenced object
* bean:idName.propertyName - we get the idName and call the getter for the property.
*/
static String processReference( Project project, String name ) {
if( name.startsWith( "toString:" )) {
name=name.substring( "toString:".length());
Object v=project.getReference( name );
if( v==null ) return null;
return v.toString();
}

int idx=name.indexOf(":");
if( idx<0 ) return null;

String ns=name.substring( 0, idx );
String path=name.substring( idx );

ProjectPropertySource ps=(ProjectPropertySource)propertySources.get( ns );
if( ps == null )
return null;

return ps.getProperty( project, path );
}
}

BIN
proposal/sandbox/embed/ant-sax2.jar View File


+ 8
- 0
proposal/sandbox/embed/build.xml View File

@@ -8,6 +8,10 @@
todir="${ant.src}/src/main/org/apache/tools/ant/helper" />
<copy file="RuntimeConfigurable2.java"
todir="${ant.src}/src/main/org/apache/tools/ant" />
<copy file="PropertyInterceptor.java"
todir="${ant.src}/src/main/org/apache/tools/ant" />
<copy file="PropertyHelper.java"
todir="${ant.src}/src/main/org/apache/tools/ant" />

<echo message="${toString:test}" />

@@ -16,6 +20,8 @@
destdir="${ant.build}/classes" >
<classpath location="${ant.build}/classes" />
<include name="**/ProjectHelperImpl2.java" />
<include name="**/PropertyHelper.java" />
<include name="**/PropertyInterceptor.java" />
<include name="**/RuntimeConfigurable2.java" />
</javac>

@@ -28,6 +34,8 @@
<include name="META-INF/**" />
<include name="org/apache/tools/ant/helper/ProjectHelperImpl2*" />
<include name="org/apache/tools/ant/RuntimeConfigurable2*" />
<include name="org/apache/tools/ant/PropertyHelper*" />
<include name="org/apache/tools/ant/PropertyInterceptor*" />
</jar>

<copy file="ant-sax2.jar" todir="${ant.home}/lib" />


Loading…
Cancel
Save