@@ -76,31 +76,62 @@ import javax.xml.parsers.SAXParser;
import javax.xml.parsers.ParserConfigurationException;
/**
* Configures a Project (complete with Targets and T asks) based on
* a XML build file.
* Configures a project (complete with targets and t asks) based on
* an XML build file.
*
* @author duncan@x180.com
*/
public class ProjectHelper {
/**
* Parser factory to use to create parsers.
* @see #getParserFactory
*/
private static SAXParserFactory parserFactory = null;
/**
* SAX 1 style parser used to parse the given file. This may
* in fact be a SAX 2 XMLReader wrapped in an XMLReaderAdapter.
*/
private org.xml.sax.Parser parser;
/** The project to configure. */
private Project project;
/** The configuration file to parse. */
private File buildFile;
/**
* Parent directory of the build file. Used for resolving entities
* and setting the project's base directory.
*/
private File buildFileParent;
/**
* Locator for the configuration file parser.
* Used for giving locations of errors etc.
*/
private Locator locator;
/**
* Configures the Project with the contents of the specified XML file.
* Configures the project with the contents of the specified XML file.
*
* @param project The project to configure. Must not be <code>null</code>.
* @param buildFile An XML file giving the project's configuration.
* Must not be <code>null</code>.
*
* @exception BuildException if the configuration is invalid or cannot
* be read
*/
public static void configureProject(Project project, File buildFile) throws BuildException {
new ProjectHelper(project, buildFile).parse();
}
/**
* Constructs a new Ant parser for the specified XML file.
* Constructs a new helper for the specified project and XML file.
*
* @param project The project for the resulting ProjectHelper to configure.
* Must not be <code>null</code>.
* @param buildFile An XML file giving the project's configuration.
* Must not be <code>null</code>.
*/
private ProjectHelper(Project project, File buildFile) {
this.project = project;
@@ -109,7 +140,10 @@ public class ProjectHelper {
}
/**
* Parses the project file.
* Parses the project file, configuring the project as it goes.
*
* @exception BuildException if the configuration is invalid or cannot
* be read
*/
private void parse() throws BuildException {
FileInputStream inputStream = null;
@@ -183,33 +217,71 @@ public class ProjectHelper {
}
/**
* The common superclass for all sax event handlers in Ant. Basically
* throws an exception in each method, so subclasses should override
* what they can handle.
* The common superclass for all SAX event handlers used to parse
* the configuration file. Each method just throws an exception,
* so subclasses should override what they can handle.
*
* Each type of xml element (task, target, etc) in ant will
* have its own subclass of AbstractHandler .
* Each type of XML element (task, target, etc.) in Ant has
* a specific subclass .
*
* In the constructor, this class takes over the handling of sax
* events from the parent handler, and returns
* In the constructor, this class takes over the handling of SAX
* events from the parent handler and returns
* control back to the parent in the endElement method.
*/
private class AbstractHandler extends HandlerBase {
/**
* Previous handler for the document.
* When the next element is finished, control returns
* to this handler.
*/
protected DocumentHandler parentHandler;
/**
* Creates a handler and sets the parser to use it
* for the current element.
*
* @param parentHandler The handler which should be restored to the
* parser at the end of the element.
* Must not be <code>null</code>.
*/
public AbstractHandler(DocumentHandler parentHandler) {
this.parentHandler = parentHandler;
// Start handling SAX events
parser.setDocumentHandler(this);
}
/**
* Handles the start of an element. This base implementation just
* throws an exception.
*
* @param tag The name of the element being started.
* Will not be <code>null</code>.
* @param attrs Attributes of the element being started.
* Will not be <code>null</code>.
*
* @exception SAXParseException if this method is not overridden, or in
* case of error in an overridden version
*/
public void startElement(String tag, AttributeList attrs) throws SAXParseException {
throw new SAXParseException("Unexpected element \"" + tag + "\"", locator);
}
public void characters(char[] buf, int start, int end) throws SAXParseException {
String s = new String(buf, start, end).trim();
/**
* Handles text within an element. This base implementation just
* throws an exception.
*
* @param buf A character array of the text within the element.
* Will not be <code>null</code>.
* @param start The start element in the array.
* @param count The number of characters to read from the array.
*
* @exception SAXParseException if this method is not overridden, or in
* case of error in an overridden version
*/
public void characters(char[] buf, int start, int count) throws SAXParseException {
String s = new String(buf, start, count).trim();
if (s.length() > 0) {
throw new SAXParseException("Unexpected text \"" + s + "\"", locator);
@@ -222,6 +294,19 @@ public class ProjectHelper {
*/
protected void finished() {}
/**
* Handles the end of an element. Any required clean-up is performed
* by the finished() method and then the original handler is restored to
* the parser.
*
* @param name The name of the element which is ending.
* Will not be <code>null</code>.
*
* @exception SAXException in case of error (not thrown in
* this implementation)
*
* @see #finished()
*/
public void endElement(String name) throws SAXException {
finished();
@@ -231,12 +316,18 @@ public class ProjectHelper {
}
/**
* Handler for the root element. It' s only child must be the "project" element.
* Handler for the root element. Its only child must be the "project" element.
*/
private class RootHandler extends HandlerBase {
/**
* resolve file: URIs as relative to the build file.
* Resolves file: URIs relative to the build file.
*
* @param publicId The public identifer, or <code>null</code>
* if none is available. Ignored in this
* implementation.
* @param systemId The system identifier provided in the XML
* document. Will not be <code>null</code>.
*/
public InputSource resolveEntity(String publicId,
String systemId) {
@@ -280,6 +371,18 @@ public class ProjectHelper {
return null;
}
/**
* Handles the start of a project element. A project handler is created
* and initialised with the element name and attributes.
*
* @param tag The name of the element being started.
* Will not be <code>null</code>.
* @param attrs Attributes of the element being started.
* Will not be <code>null</code>.
*
* @exception SAXParseException if the tag given is not
* <code>"project"</code>
*/
public void startElement(String tag, AttributeList attrs) throws SAXParseException {
if (tag.equals("project")) {
new ProjectHandler(this).init(tag, attrs);
@@ -288,6 +391,12 @@ public class ProjectHelper {
}
}
/**
* Sets the locator in the project helper for future reference.
*
* @param locator The locator used by the parser.
* Will not be <code>null</code>.
*/
public void setDocumentLocator(Locator locator) {
ProjectHelper.this.locator = locator;
}
@@ -297,10 +406,34 @@ public class ProjectHelper {
* Handler for the top level "project" element.
*/
private class ProjectHandler extends AbstractHandler {
/**
* Constructor which just delegates to the superconstructor.
*
* @param parentHandler The handler which should be restored to the
* parser at the end of the element.
* Must not be <code>null</code>.
*/
public ProjectHandler(DocumentHandler parentHandler) {
super(parentHandler);
}
/**
* Initialisation routine called after handler creation
* with the element name and attributes. The attributes which
* this handler can deal with are: <code>"default"</code>,
* <code>"name"</code>, <code>"id"</code> and <code>"basedir"</code>.
*
* @param tag Name of the element which caused this handler
* to be created. Should not be <code>null</code>.
* Ignored in this implementation.
* @param attrs Attributes of the element which caused this
* handler to be created. Must not be <code>null</code>.
*
* @exception SAXParseException if an unexpected attribute is
* encountered or if the <code>"default"</code> attribute
* is missing.
*/
public void init(String tag, AttributeList attrs) throws SAXParseException {
String def = null;
String name = null;
@@ -358,6 +491,21 @@ public class ProjectHelper {
}
/**
* Handles the start of a top-level element within the project. An
* appropriate handler is created and initialised with the details
* of the element.
*
* @param tag The name of the element being started.
* Will not be <code>null</code>.
* @param attrs Attributes of the element being started.
* Will not be <code>null</code>.
*
* @exception SAXParseException if the tag given is not
* <code>"taskdef"</code>, <code>"typedef"</code>,
* <code>"property"</code>, <code>"target"</code>
* or a data type definition
*/
public void startElement(String name, AttributeList attrs) throws SAXParseException {
if (name.equals("taskdef")) {
handleTaskdef(name, attrs);
@@ -373,23 +521,83 @@ public class ProjectHelper {
throw new SAXParseException("Unexpected element \"" + name + "\"", locator);
}
}
/**
* Handles a task defintion element by creating a task handler
* and initialising is with the details of the element.
*
* @param tag The name of the element to be handled.
* Will not be <code>null</code>.
* @param attrs Attributes of the element to be handled.
* Will not be <code>null</code>.
*
* @exception SAXParseException if an error occurs when initialising
* the task handler
*
*/
private void handleTaskdef(String name, AttributeList attrs) throws SAXParseException {
(new TaskHandler(this, null, null, null)).init(name, attrs);
}
/**
* Handles a type defintion element by creating a task handler
* and initialising is with the details of the element.
*
* @param tag The name of the element to be handled.
* Will not be <code>null</code>.
* @param attrs Attributes of the element to be handled.
* Will not be <code>null</code>.
*
* @exception SAXParseException if an error occurs initialising the
* handler
*/
private void handleTypedef(String name, AttributeList attrs) throws SAXParseException {
(new TaskHandler(this, null, null, null)).init(name, attrs);
}
/**
* Handles a property defintion element by creating a task handler
* and initialising is with the details of the element.
*
* @param tag The name of the element to be handled.
* Will not be <code>null</code>.
* @param attrs Attributes of the element to be handled.
* Will not be <code>null</code>.
*
* @exception SAXParseException if an error occurs initialising
* the handler
*/
private void handleProperty(String name, AttributeList attrs) throws SAXParseException {
(new TaskHandler(this, null, null, null)).init(name, attrs);
}
/**
* Handles a target defintion element by creating a target handler
* and initialising is with the details of the element.
*
* @param tag The name of the element to be handled.
* Will not be <code>null</code>.
* @param attrs Attributes of the element to be handled.
* Will not be <code>null</code>.
*
* @exception SAXParseException if an error occurs initialising
* the handler
*/
private void handleTarget(String tag, AttributeList attrs) throws SAXParseException {
new TargetHandler(this).init(tag, attrs);
}
/**
* Handles a data type defintion element by creating a data type
* handler and initialising is with the details of the element.
*
* @param tag The name of the element to be handled.
* Will not be <code>null</code>.
* @param attrs Attributes of the element to be handled.
* Will not be <code>null</code>.
*
* @exception SAXParseException if an error occurs initialising
* the handler
*/
private void handleDataType(String name, AttributeList attrs) throws SAXParseException {
new DataTypeHandler(this).init(name, attrs);
}
@@ -402,10 +610,34 @@ public class ProjectHelper {
private class TargetHandler extends AbstractHandler {
private Target target;
/**
* Constructor which just delegates to the superconstructor.
*
* @param parentHandler The handler which should be restored to the
* parser at the end of the element.
* Must not be <code>null</code>.
*/
public TargetHandler(DocumentHandler parentHandler) {
super(parentHandler);
}
/**
* Initialisation routine called after handler creation
* with the element name and attributes. The attributes which
* this handler can deal with are: <code>"name"</code>,
* <code>"depends"</code>, <code>"if"</code>,
* <code>"unless"</code>, <code>"id"</code> and
* <code>"description"</code>.
*
* @param tag Name of the element which caused this handler
* to be created. Should not be <code>null</code>.
* Ignored in this implementation.
* @param attrs Attributes of the element which caused this
* handler to be created. Must not be <code>null</code>.
*
* @exception SAXParseException if an unexpected attribute is encountered
* or if the <code>"name"</code> attribute is missing.
*/
public void init(String tag, AttributeList attrs) throws SAXParseException {
String name = null;
String depends = "";
@@ -457,6 +689,17 @@ public class ProjectHelper {
}
}
/**
* Handles the start of an element within a target.
*
* @param tag The name of the element being started.
* Will not be <code>null</code>.
* @param attrs Attributes of the element being started.
* Will not be <code>null</code>.
*
* @exception SAXParseException if an error occurs when initialising
* the appropriate child handler
*/
public void startElement(String name, AttributeList attrs) throws SAXParseException {
if (project.getDataTypeDefinitions().get(name) != null) {
new DataTypeHandler(this, target).init(name, attrs);
@@ -470,12 +713,51 @@ public class ProjectHelper {
* Handler for all task elements.
*/
private class TaskHandler extends AbstractHandler {
/** Containing target, if any. */
private Target target;
/**
* Container for the task, if any. If target is
* non-<code>null</code>, this must be too.
*/
private TaskContainer container;
/**
* Task created by this handler.
*/
private Task task;
/**
* Wrapper for the parent element, if any. The wrapper for this
* element will be added to this wrapper as a child.
*/
private RuntimeConfigurable parentWrapper;
/**
* Wrapper for this element which takes care of actually configuring
* the element, if this element is contained within a target.
* Otherwise the configuration is performed with the configure method.
* @see ProjectHelper#configure(Object,AttributeList,Project)
*/
private RuntimeConfigurable wrapper = null;
/**
* Constructor.
*
* @param parentHandler The handler which should be restored to the
* parser at the end of the element.
* Must not be <code>null</code>.
*
* @param container Container for the element.
* May be <code>null</code> if the target is
* <code>null</code> as well. If the
* target is <code>null</code>, this parameter
* is effectively ignored.
*
* @param parentWrapper Wrapper for the parent element, if any.
* May be <code>null</code>. If the
* target is <code>null</code>, this parameter
* is effectively ignored.
*
* @param target Target this element is part of.
* May be <code>null</code>.
*/
public TaskHandler(DocumentHandler parentHandler, TaskContainer container, RuntimeConfigurable parentWrapper, Target target) {
super(parentHandler);
this.container = container;
@@ -483,6 +765,22 @@ public class ProjectHelper {
this.target = target;
}
/**
* Initialisation routine called after handler creation
* with the element name and attributes. This configures
* the element with its attributes and sets it up with
* its parent container (if any). Nested elements are then
* added later as the parser encounters them.
*
* @param tag Name of the element which caused this handler
* to be created. Must not be <code>null</code>.
*
* @param attrs Attributes of the element which caused this
* handler to be created. Must not be <code>null</code>.
*
* @exception SAXParseException in case of error (not thrown in
* this implementation)
*/
public void init(String tag, AttributeList attrs) throws SAXParseException {
try {
task = project.createTask(tag);
@@ -517,24 +815,54 @@ public class ProjectHelper {
}
}
/**
* Executes the task if it is a top-level one.
*/
protected void finished() {
if (task != null && target == null) {
task.execute();
}
}
public void characters(char[] buf, int start, int end) throws SAXParseException {
/**
* Adds text to the task, using the wrapper if one is
* available (in other words if the task is within a target)
* or using addText otherwise.
*
* @param buf A character array of the text within the element.
* Will not be <code>null</code>.
* @param start The start element in the array.
* @param count The number of characters to read from the array.
*
* @exception SAXParseException if the element doesn't support text
*
* @see ProjectHelper#addText(Project,Object,char[],int,int)
*/
public void characters(char[] buf, int start, int count) throws SAXParseException {
if (wrapper == null) {
try {
addText(project, task, buf, start, end);
addText(project, task, buf, start, count );
} catch (BuildException exc) {
throw new SAXParseException(exc.getMessage(), locator, exc);
}
} else {
wrapper.addText(buf, start, end);
wrapper.addText(buf, start, count );
}
}
/**
* Handles the start of an element within a target. Task containers
* will always use another task handler, and all other tasks
* will always use a nested element handler.
*
* @param tag The name of the element being started.
* Will not be <code>null</code>.
* @param attrs Attributes of the element being started.
* Will not be <code>null</code>.
*
* @exception SAXParseException if an error occurs when initialising
* the appropriate child handler
*/
public void startElement(String name, AttributeList attrs) throws SAXParseException {
if (task instanceof TaskContainer) {
// task can contain other tasks - no other nested elements possible
@@ -550,12 +878,41 @@ public class ProjectHelper {
* Handler for all nested properties.
*/
private class NestedElementHandler extends AbstractHandler {
/** Parent object (task/data type/etc). */
private Object parent;
/** The nested element itself. */
private Object child;
/**
* Wrapper for the parent element, if any. The wrapper for this
* element will be added to this wrapper as a child.
*/
private RuntimeConfigurable parentWrapper;
/**
* Wrapper for this element which takes care of actually configuring
* the element, if a parent wrapper is provided.
* Otherwise the configuration is performed with the configure method.
* @see ProjectHelper#configure(Object,AttributeList,Project)
*/
private RuntimeConfigurable childWrapper = null;
/** Target this element is part of, if any. */
private Target target;
/**
* Constructor.
*
* @param parentHandler The handler which should be restored to the
* parser at the end of the element.
* Must not be <code>null</code>.
*
* @param parent Parent of this element (task/data type/etc).
* Must not be <code>null</code>.
*
* @param parentWrapper Wrapper for the parent element, if any.
* May be <code>null</code>.
*
* @param target Target this element is part of.
* May be <code>null</code>.
*/
public NestedElementHandler(DocumentHandler parentHandler,
Object parent,
RuntimeConfigurable parentWrapper,
@@ -571,6 +928,22 @@ public class ProjectHelper {
this.target = target;
}
/**
* Initialisation routine called after handler creation
* with the element name and attributes. This configures
* the element with its attributes and sets it up with
* its parent container (if any). Nested elements are then
* added later as the parser encounters them.
*
* @param tag Name of the element which caused this handler
* to be created. Must not be <code>null</code>.
*
* @param attrs Attributes of the element which caused this
* handler to be created. Must not be <code>null</code>.
*
* @exception SAXParseException in case of error, such as a
* BuildException being thrown during configuration.
*/
public void init(String propType, AttributeList attrs) throws SAXParseException {
Class parentClass = parent.getClass();
IntrospectionHelper ih =
@@ -602,18 +975,44 @@ public class ProjectHelper {
}
}
public void characters(char[] buf, int start, int end) throws SAXParseException {
/**
* Adds text to the element, using the wrapper if one is
* available or using addText otherwise.
*
* @param buf A character array of the text within the element.
* Will not be <code>null</code>.
* @param start The start element in the array.
* @param count The number of characters to read from the array.
*
* @exception SAXParseException if the element doesn't support text
*
* @see ProjectHelper#addText(Project,Object,char[],int,int)
*/
public void characters(char[] buf, int start, int count) throws SAXParseException {
if (parentWrapper == null) {
try {
addText(project, child, buf, start, end);
addText(project, child, buf, start, count );
} catch (BuildException exc) {
throw new SAXParseException(exc.getMessage(), locator, exc);
}
} else {
childWrapper.addText(buf, start, end);
childWrapper.addText(buf, start, count );
}
}
/**
* Handles the start of an element within this one. Task containers
* will always use a task handler, and all other elements
* will always use another nested element handler.
*
* @param tag The name of the element being started.
* Will not be <code>null</code>.
* @param attrs Attributes of the element being started.
* Will not be <code>null</code>.
*
* @exception SAXParseException if an error occurs when initialising
* the appropriate child handler
*/
public void startElement(String name, AttributeList attrs) throws SAXParseException {
if (child instanceof TaskContainer) {
// taskcontainer nested element can contain other tasks - no other
@@ -627,22 +1026,58 @@ public class ProjectHelper {
}
/**
* Handler for all data types at global level .
* Handler for all data types directly subordinate to project or target .
*/
private class DataTypeHandler extends AbstractHandler {
/** Parent target, if any. */
private Target target;
/** The element being configured. */
private Object element;
/** Wrapper for this element, if it's part of a target. */
private RuntimeConfigurable wrapper = null;
/**
* Constructor with no target specified.
*
* @param parentHandler The handler which should be restored to the
* parser at the end of the element.
* Must not be <code>null</code>.
*/
public DataTypeHandler(DocumentHandler parentHandler) {
this(parentHandler, null);
}
/**
* Constructor with a target specified.
*
* @param parentHandler The handler which should be restored to the
* parser at the end of the element.
* Must not be <code>null</code>.
*
* @param target The parent target of this element.
* May be <code>null</code>.
*/
public DataTypeHandler(DocumentHandler parentHandler, Target target) {
super(parentHandler);
this.target = target;
}
/**
* Initialisation routine called after handler creation
* with the element name and attributes. This configures
* the element with its attributes and sets it up with
* its parent container (if any). Nested elements are then
* added later as the parser encounters them.
*
* @param tag Name of the element which caused this handler
* to be created. Must not be <code>null</code>.
*
* @param attrs Attributes of the element which caused this
* handler to be created. Must not be <code>null</code>.
*
* @exception SAXParseException in case of error, such as a
* BuildException being thrown during configuration.
*/
public void init(String propType, AttributeList attrs) throws SAXParseException {
try {
element = project.createDataType(propType);
@@ -663,19 +1098,58 @@ public class ProjectHelper {
}
}
public void characters(char[] buf, int start, int end) throws SAXParseException {
// XXX: (Jon Skeet) Any reason why this doesn't use the wrapper
// if one is available, whereas NestedElementHandler.characters does?
/**
* Adds text to the element.
*
* @param buf A character array of the text within the element.
* Will not be <code>null</code>.
* @param start The start element in the array.
* @param count The number of characters to read from the array.
*
* @exception SAXParseException if the element doesn't support text
*
* @see ProjectHelper#addText(Project,Object,char[],int,int)
*/
public void characters(char[] buf, int start, int count) throws SAXParseException {
try {
addText(project, element, buf, start, end);
addText(project, element, buf, start, count );
} catch (BuildException exc) {
throw new SAXParseException(exc.getMessage(), locator, exc);
}
}
/**
* Handles the start of an element within this one.
* This will always use a nested element handler.
*
* @param tag The name of the element being started.
* Will not be <code>null</code>.
* @param attrs Attributes of the element being started.
* Will not be <code>null</code>.
*
* @exception SAXParseException if an error occurs when initialising
* the child handler
*/
public void startElement(String name, AttributeList attrs) throws SAXParseException {
new NestedElementHandler(this, element, wrapper, target).init(name, attrs);
}
}
/**
* Configures an object using an introspection handler.
*
* @param target The target object to be configured.
* Must not be <code>null</code>.
* @param attrs A list of attributes to configure within the target.
* Must not be <code>null</code>.
* @param project The project containing the target.
* Must not be <code>null</code>.
*
* @exception BuildException if any of the attributes can't be handled by
* the target
*/
public static void configure(Object target, AttributeList attrs,
Project project) throws BuildException {
if( target instanceof TaskAdapter ) {
@@ -706,14 +1180,35 @@ public class ProjectHelper {
/**
* Adds the content of #PCDATA sections to an element.
*
* @param project The project containing the target.
* Must not be <code>null</code>.
* @param target The target object to be configured.
* Must not be <code>null</code>.
* @param buf A character array of the text within the element.
* Will not be <code>null</code>.
* @param start The start element in the array.
* @param count The number of characters to read from the array.
*
* @exception BuildException if the target object doesn't accept text
*/
public static void addText(Project project, Object target, char[] buf, int start, int end)
public static void addText(Project project, Object target, char[] buf, int start, int count )
throws BuildException {
addText(project, target, new String(buf, start, end));
addText(project, target, new String(buf, start, count ));
}
/**
* Adds the content of #PCDATA sections to an element.
*
* @param project The project containing the target.
* Must not be <code>null</code>.
* @param target The target object to be configured.
* Must not be <code>null</code>.
* @param text Text to add to the target.
* May be <code>null</code>, in which case this
* method call is a no-op.
*
* @exception BuildException if the target object doesn't accept text
*/
public static void addText(Project project, Object target, String text)
throws BuildException {
@@ -730,7 +1225,17 @@ public class ProjectHelper {
}
/**
* Stores a configured child element into its parent object
* Stores a configured child element within its parent object.
*
* @param project Project containing the objects.
* May be <code>null</code>.
* @param parent Parent object to add child to.
* Must not be <code>null</code>.
* @param child Child object to store in parent.
* Should not be <code>null</code>.
* @param tag Name of element which generated the child.
* May be <code>null</code>, in which case
* the child is not stored.
*/
public static void storeChild(Project project, Object parent, Object child, String tag) {
IntrospectionHelper ih = IntrospectionHelper.getHelper(parent.getClass());
@@ -738,10 +1243,18 @@ public class ProjectHelper {
}
/**
* Replace ${} style constructions in the given value with the string value of
* the corresponding data types.
* Replaces <code>${xxx}</code> style constructions in the given value with
* the string value of the corresponding properties.
*
* @param value The string to be scanned for property references.
* May be <code>null</code>.
*
* @param value the string to be scanned for property references.
* @exception BuildException if the string contains an opening
* <code>${</code> without a closing
* <code>}</code>
* @return the original string with the properties replaced, or
* <code>null</code> if the original string is <code>null</code>.
*
* @since 1.5
*/
public static String replaceProperties(Project project, String value)
@@ -750,10 +1263,22 @@ public class ProjectHelper {
}
/**
* Replace ${} style constructions in the given value with the string value of
* the corresponding data types.
* Replaces <code> ${xxx }</code> style constructions in the given value
* with the string value of the corresponding data types.
*
* @param value the string to be scanned for property references.
* @param project The container project. This is used solely for
* logging purposes. Must not be <code>null</code>.
* @param value The string to be scanned for property references.
* May be <code>null</code>, in which case this
* method returns immediately with no effect.
* @param keys Mapping (String to String) of property names to their
* values. Must not be <code>null</code>.
*
* @exception BuildException if the string contains an opening
* <code>${</code> without a closing
* <code>}</code>
* @return the original string with the properties replaced, or
* <code>null</code> if the original string is <code>null</code>.
*/
public static String replaceProperties(Project project, String value, Hashtable keys)
throws BuildException {
@@ -785,11 +1310,21 @@ public class ProjectHelper {
}
/**
* This method will parse a string containing ${value} style
* property values into two lists. The first list is a collection
* of text fragments, while the other is a set of string property names
* null entries in the first list indicate a property reference from the
* second list.
* Parses a string containing <code>${xxx}</code> style property
* references into two lists. The first list is a collection
* of text fragments, while the other is a set of string property names.
* <code>null</code> entries in the first list indicate a property
* reference from the second list.
*
* @param value Text to parse. Must not be <code>null</code>.
* @param fragments List to add text fragments to.
* Must not be <code>null</code>.
* @param propertyRefs List to add property names to.
* Must not be <code>null</code>.
*
* @exception BuildException if the string contains an opening
* <code>${</code> without a closing
* <code>}</code>
*/
public static void parsePropertyString(String value, Vector fragments, Vector propertyRefs)
throws BuildException {
@@ -825,6 +1360,13 @@ public class ProjectHelper {
}
}
/**
* Returns the parser factory to use. Only one parser
* factory is ever created by this method (multi-threading
* issues aside) and is then cached for future use.
*
* @return a SAXParserFactory to use within this class
*/
private static SAXParserFactory getParserFactory() {
if (parserFactory == null) {
parserFactory = SAXParserFactory.newInstance();
@@ -834,11 +1376,14 @@ public class ProjectHelper {
}
/**
* Scan AttributeList for the id attribute and maybe add a
* reference to project.
*
* <p>Moved out of {@link #configure configure} to make it happen
* at parser time.</p>
* Scans an attribute list for the <code>id</code> attribute and
* stores a reference to the target object in the project if an
* id is found.
* <p>
* This method was moved out of the configure method to allow
* it to be executed at parse time.
*
* @see #configure(Object,AttributeList,Project)
*/
private void configureId(Object target, AttributeList attr) {
String id = attr.getValue("id");
@@ -846,5 +1391,4 @@ public class ProjectHelper {
project.addReference(id, target);
}
}
}