diff options
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/helper/ProjectHelper2.java')
-rw-r--r-- | framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/helper/ProjectHelper2.java | 1238 |
1 files changed, 1238 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/helper/ProjectHelper2.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/helper/ProjectHelper2.java new file mode 100644 index 00000000..67e1decb --- /dev/null +++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/helper/ProjectHelper2.java @@ -0,0 +1,1238 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.tools.ant.helper; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.net.URLConnection; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; +import java.util.Stack; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.ExtensionPoint; +import org.apache.tools.ant.Location; +import org.apache.tools.ant.MagicNames; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.ProjectHelper; +import org.apache.tools.ant.RuntimeConfigurable; +import org.apache.tools.ant.Target; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.UnknownElement; +import org.apache.tools.ant.types.Resource; +import org.apache.tools.ant.types.resources.FileProvider; +import org.apache.tools.ant.types.resources.URLProvider; +import org.apache.tools.ant.util.FileUtils; +import org.apache.tools.ant.util.JAXPUtils; +import org.apache.tools.zip.ZipFile; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; + +/** + * Sax2 based project reader + * + */ +public class ProjectHelper2 extends ProjectHelper { + + /** Reference holding the (ordered) target Vector */ + public static final String REFID_TARGETS = "ant.targets"; + + /* Stateless */ + + // singletons - since all state is in the context + private static AntHandler elementHandler = new ElementHandler(); + private static AntHandler targetHandler = new TargetHandler(); + private static AntHandler mainHandler = new MainHandler(); + private static AntHandler projectHandler = new ProjectHandler(); + + /** Specific to ProjectHelper2 so not a true Ant "magic name:" */ + private static final String REFID_CONTEXT = "ant.parsing.context"; + + /** + * helper for path -> URI and URI -> path conversions. + */ + private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); + + /** + * Whether this instance of ProjectHelper can parse an Antlib + * descriptor given by the URL and return its content as an + * UnknownElement ready to be turned into an Antlib task. + * + * <p>This implementation returns true.</p> + * + * @since Ant 1.8.0 + */ + public boolean canParseAntlibDescriptor(Resource resource) { + return true; + } + + /** + * Parse the given URL as an antlib descriptor and return the + * content as something that can be turned into an Antlib task. + * + * <p>simply delegates to {@link #parseUnknownElement + * parseUnknownElement} if the resource provides an URL and throws + * an exception otherwise.</p> + * + * @since Ant 1.8.0 + */ + public UnknownElement parseAntlibDescriptor(Project containingProject, + Resource resource) { + URLProvider up = resource.as(URLProvider.class); + if (up == null) { + throw new BuildException("Unsupported resource type: " + resource); + } + return parseUnknownElement(containingProject, up.getURL()); + } + + /** + * Parse an unknown element from a url + * + * @param project the current project + * @param source the url containing the task + * @return a configured task + * @exception BuildException if an error occurs + */ + public UnknownElement parseUnknownElement(Project project, URL source) + throws BuildException { + Target dummyTarget = new Target(); + dummyTarget.setProject(project); + + AntXMLContext context = new AntXMLContext(project); + context.addTarget(dummyTarget); + context.setImplicitTarget(dummyTarget); + + parse(context.getProject(), source, new RootHandler(context, elementHandler)); + Task[] tasks = dummyTarget.getTasks(); + if (tasks.length != 1) { + throw new BuildException("No tasks defined"); + } + return (UnknownElement) tasks[0]; + } + + /** + * Parse a source xml input. + * + * @param project the current project + * @param source the xml source + * @exception BuildException if an error occurs + */ + public void parse(Project project, Object source) throws BuildException { + getImportStack().addElement(source); + AntXMLContext context = null; + context = (AntXMLContext) project.getReference(REFID_CONTEXT); + if (context == null) { + context = new AntXMLContext(project); + project.addReference(REFID_CONTEXT, context); + project.addReference(REFID_TARGETS, context.getTargets()); + } + if (getImportStack().size() > 1) { + // we are in an imported file. + context.setIgnoreProjectTag(true); + Target currentTarget = context.getCurrentTarget(); + Target currentImplicit = context.getImplicitTarget(); + Map<String, Target> currentTargets = context.getCurrentTargets(); + try { + Target newCurrent = new Target(); + newCurrent.setProject(project); + newCurrent.setName(""); + context.setCurrentTarget(newCurrent); + context.setCurrentTargets(new HashMap<String, Target>()); + context.setImplicitTarget(newCurrent); + parse(project, source, new RootHandler(context, mainHandler)); + newCurrent.execute(); + } finally { + context.setCurrentTarget(currentTarget); + context.setImplicitTarget(currentImplicit); + context.setCurrentTargets(currentTargets); + } + } else { + // top level file + context.setCurrentTargets(new HashMap<String, Target>()); + parse(project, source, new RootHandler(context, mainHandler)); + // Execute the top-level target + context.getImplicitTarget().execute(); + + // resolve extensionOf attributes + resolveExtensionOfAttributes(project); + } + } + + /** + * Parses the project file, configuring the project as it goes. + * + * @param project the current project + * @param source the xml source + * @param handler the root handler to use (contains the current context) + * @exception BuildException if the configuration is invalid or cannot + * be read + */ + public void parse(Project project, Object source, RootHandler handler) throws BuildException { + + AntXMLContext context = handler.context; + + File buildFile = null; + URL url = null; + String buildFileName = null; + + if (source instanceof File) { + buildFile = (File) source; + } else if (source instanceof URL) { + url = (URL) source; + } else if (source instanceof Resource) { + FileProvider fp = + ((Resource) source).as(FileProvider.class); + if (fp != null) { + buildFile = fp.getFile(); + } else { + URLProvider up = + ((Resource) source).as(URLProvider.class); + if (up != null) { + url = up.getURL(); + } + } + } + if (buildFile != null) { + buildFile = FILE_UTILS.normalize(buildFile.getAbsolutePath()); + context.setBuildFile(buildFile); + buildFileName = buildFile.toString(); + } else if (url != null) { + try { + context.setBuildFile((File) null); + context.setBuildFile(url); + } catch (java.net.MalformedURLException ex) { + throw new BuildException(ex); + } + buildFileName = url.toString(); + } else { + throw new BuildException("Source " + source.getClass().getName() + + " not supported by this plugin"); + } + InputStream inputStream = null; + InputSource inputSource = null; + ZipFile zf = null; + + try { + /** + * SAX 2 style parser used to parse the given file. + */ + XMLReader parser = JAXPUtils.getNamespaceXMLReader(); + + String uri = null; + if (buildFile != null) { + uri = FILE_UTILS.toURI(buildFile.getAbsolutePath()); + inputStream = new FileInputStream(buildFile); + } else { + uri = url.toString(); + int pling = -1; + if (uri.startsWith("jar:file") + && (pling = uri.indexOf("!/")) > -1) { + zf = new ZipFile(org.apache.tools.ant.launch.Locator + .fromJarURI(uri), "UTF-8"); + inputStream = + zf.getInputStream(zf.getEntry(uri.substring(pling + 1))); + } else { + URLConnection conn = url.openConnection(); + conn.setUseCaches(false); + inputStream = conn.getInputStream(); + } + } + + inputSource = new InputSource(inputStream); + if (uri != null) { + inputSource.setSystemId(uri); + } + project.log("parsing buildfile " + buildFileName + " with URI = " + + uri + (zf != null ? " from a zip file" : ""), + Project.MSG_VERBOSE); + + DefaultHandler hb = handler; + + parser.setContentHandler(hb); + parser.setEntityResolver(hb); + parser.setErrorHandler(hb); + parser.setDTDHandler(hb); + parser.parse(inputSource); + } catch (SAXParseException exc) { + Location location = new Location(exc.getSystemId(), exc.getLineNumber(), exc + .getColumnNumber()); + + Throwable t = exc.getException(); + if (t instanceof BuildException) { + BuildException be = (BuildException) t; + if (be.getLocation() == Location.UNKNOWN_LOCATION) { + be.setLocation(location); + } + throw be; + } + throw new BuildException(exc.getMessage(), t == null ? exc : t, location); + } catch (SAXException exc) { + Throwable t = exc.getException(); + if (t instanceof BuildException) { + throw (BuildException) t; + } + throw new BuildException(exc.getMessage(), t == null ? exc : t); + } catch (FileNotFoundException exc) { + throw new BuildException(exc); + } catch (UnsupportedEncodingException exc) { + throw new BuildException("Encoding of project file " + buildFileName + " is invalid.", + exc); + } catch (IOException exc) { + throw new BuildException("Error reading project file " + buildFileName + ": " + + exc.getMessage(), exc); + } finally { + FileUtils.close(inputStream); + ZipFile.closeQuietly(zf); + } + } + + /** + * Returns main handler + * @return main handler + */ + protected static AntHandler getMainHandler() { + return mainHandler; + } + + /** + * Sets main handler + * @param handler new main handler + */ + protected static void setMainHandler(AntHandler handler) { + mainHandler = handler; + } + + /** + * Returns project handler + * @return project handler + */ + protected static AntHandler getProjectHandler() { + return projectHandler; + } + + /** + * Sets project handler + * @param handler new project handler + */ + protected static void setProjectHandler(AntHandler handler) { + projectHandler = handler; + } + + /** + * Returns target handler + * @return target handler + */ + protected static AntHandler getTargetHandler() { + return targetHandler; + } + + /** + * Sets target handler + * @param handler new target handler + */ + protected static void setTargetHandler(AntHandler handler) { + targetHandler = handler; + } + + /** + * Returns element handler + * @return element handler + */ + protected static AntHandler getElementHandler() { + return elementHandler; + } + + /** + * Sets element handler + * @param handler new element handler + */ + protected static void setElementHandler(AntHandler handler) { + elementHandler = handler; + } + + /** + * The common superclass for all SAX event handlers used to parse + * the configuration file. + * + * The context will hold all state information. At each time + * there is one active handler for the current element. It can + * use onStartChild() to set an alternate handler for the child. + */ + public static class AntHandler { + /** + * Handles the start of an element. This base implementation does + * nothing. + * + * @param uri the namespace URI for the tag + * @param tag The name of the element being started. + * Will not be <code>null</code>. + * @param qname The qualified name of the element. + * @param attrs Attributes of the element being started. + * Will not be <code>null</code>. + * @param context The context that this element is in. + * + * @exception SAXParseException if this method is not overridden, or in + * case of error in an overridden version + */ + public void onStartElement(String uri, String tag, String qname, Attributes attrs, + AntXMLContext context) throws SAXParseException { + } + + /** + * Handles the start of an element. This base implementation just + * throws an exception - you must override this method if you expect + * child elements. + * + * @param uri The namespace uri for this element. + * @param tag The name of the element being started. + * Will not be <code>null</code>. + * @param qname The qualified name for this element. + * @param attrs Attributes of the element being started. + * Will not be <code>null</code>. + * @param context The current context. + * @return a handler (in the derived classes) + * + * @exception SAXParseException if this method is not overridden, or in + * case of error in an overridden version + */ + public AntHandler onStartChild(String uri, String tag, String qname, Attributes attrs, + AntXMLContext context) throws SAXParseException { + throw new SAXParseException("Unexpected element \"" + qname + " \"", context + .getLocator()); + } + + /** + * Handle the end of a element. + * + * @param uri the namespace uri of the element + * @param tag the tag of the element + * @param qname the qualified name of the element + * @param context the current context + * @exception SAXParseException if an error occurs + */ + public void onEndChild(String uri, String tag, String qname, AntXMLContext context) + throws SAXParseException { + } + + /** + * This method is called when this element and all elements nested into it have been + * handled. I.e., this happens at the </end_tag_of_the_element>. + * @param uri the namespace uri for this element + * @param tag the element name + * @param context the current context + */ + public void onEndElement(String uri, String tag, AntXMLContext context) { + } + + /** + * Handles text within an element. This base implementation just + * throws an exception, you must override it if you expect content. + * + * @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. + * @param context The current context. + * + * @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, AntXMLContext context) + throws SAXParseException { + String s = new String(buf, start, count).trim(); + + if (s.length() > 0) { + throw new SAXParseException("Unexpected text \"" + s + "\"", context.getLocator()); + } + } + + /** + * Will be called every time a namespace is reached. + * It'll verify if the ns was processed, and if not load the task definitions. + * @param uri The namespace uri. + */ + protected void checkNamespace(String uri) { + } + } + + /** + * Handler for ant processing. Uses a stack of AntHandlers to + * implement each element ( the original parser used a recursive behavior, + * with the implicit execution stack ) + */ + public static class RootHandler extends DefaultHandler { + private Stack<AntHandler> antHandlers = new Stack<AntHandler>(); + private AntHandler currentHandler = null; + private AntXMLContext context; + + /** + * Creates a new RootHandler instance. + * + * @param context The context for the handler. + * @param rootHandler The handler for the root element. + */ + public RootHandler(AntXMLContext context, AntHandler rootHandler) { + currentHandler = rootHandler; + antHandlers.push(currentHandler); + this.context = context; + } + + /** + * Returns the current ant handler object. + * @return the current ant handler. + */ + public AntHandler getCurrentAntHandler() { + return currentHandler; + } + + /** + * Resolves file: URIs relative to the build file. + * + * @param publicId The public identifier, 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>. + * @return an inputsource for this identifier + */ + public InputSource resolveEntity(String publicId, String systemId) { + + context.getProject().log("resolving systemId: " + systemId, Project.MSG_VERBOSE); + + if (systemId.startsWith("file:")) { + String path = FILE_UTILS.fromURI(systemId); + + File file = new File(path); + if (!file.isAbsolute()) { + file = FILE_UTILS.resolveFile(context.getBuildFileParent(), path); + context.getProject().log( + "Warning: '" + systemId + "' in " + context.getBuildFile() + + " should be expressed simply as '" + path.replace('\\', '/') + + "' for compliance with other XML tools", Project.MSG_WARN); + } + context.getProject().log("file=" + file, Project.MSG_DEBUG); + try { + InputSource inputSource = new InputSource(new FileInputStream(file)); + inputSource.setSystemId(FILE_UTILS.toURI(file.getAbsolutePath())); + return inputSource; + } catch (FileNotFoundException fne) { + context.getProject().log(file.getAbsolutePath() + " could not be found", + Project.MSG_WARN); + } + + } + // use default if not file or file not found + context.getProject().log("could not resolve systemId", Project.MSG_DEBUG); + return null; + } + + /** + * Handles the start of a project element. A project handler is created + * and initialised with the element name and attributes. + * + * @param uri The namespace uri for this element. + * @param tag The name of the element being started. + * Will not be <code>null</code>. + * @param qname The qualified name for this element. + * @param attrs Attributes of the element being started. + * Will not be <code>null</code>. + * + * @exception org.xml.sax.SAXParseException if the tag given is not + * <code>"project"</code> + */ + public void startElement(String uri, String tag, String qname, Attributes attrs) + throws SAXParseException { + AntHandler next = currentHandler.onStartChild(uri, tag, qname, attrs, context); + antHandlers.push(currentHandler); + currentHandler = next; + currentHandler.onStartElement(uri, tag, qname, attrs, context); + } + + /** + * 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) { + context.setLocator(locator); + } + + /** + * Handles the end of an element. Any required clean-up is performed + * by the onEndElement() method and then the original handler is restored to the parser. + * + * @param uri The namespace URI for this element. + * @param name The name of the element which is ending. + * Will not be <code>null</code>. + * @param qName The qualified name for this element. + * + * @exception SAXException in case of error (not thrown in this implementation) + */ + public void endElement(String uri, String name, String qName) throws SAXException { + currentHandler.onEndElement(uri, name, context); + AntHandler prev = (AntHandler) antHandlers.pop(); + currentHandler = prev; + if (currentHandler != null) { + currentHandler.onEndChild(uri, name, qName, context); + } + } + + /** + * Handle text within an element, calls currentHandler.characters. + * + * @param buf A character array of the test. + * @param start The start offset in the array. + * @param count The number of characters to read. + * @exception SAXParseException if an error occurs + */ + public void characters(char[] buf, int start, int count) throws SAXParseException { + currentHandler.characters(buf, start, count, context); + } + + /** + * Start a namespace prefix to uri mapping + * + * @param prefix the namespace prefix + * @param uri the namespace uri + */ + public void startPrefixMapping(String prefix, String uri) { + context.startPrefixMapping(prefix, uri); + } + + /** + * End a namespace prefix to uri mapping + * + * @param prefix the prefix that is not mapped anymore + */ + public void endPrefixMapping(String prefix) { + context.endPrefixMapping(prefix); + } + } + + /** + * The main handler - it handles the <project> tag. + * + * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler + */ + public static class MainHandler extends AntHandler { + + /** + * Handle the project tag + * + * @param uri The namespace uri. + * @param name The element tag. + * @param qname The element qualified name. + * @param attrs The attributes of the element. + * @param context The current context. + * @return The project handler that handles subelements of project + * @exception SAXParseException if the qualified name is not "project". + */ + public AntHandler onStartChild(String uri, String name, String qname, Attributes attrs, + AntXMLContext context) throws SAXParseException { + if (name.equals("project") + && (uri.equals("") || uri.equals(ANT_CORE_URI))) { + return ProjectHelper2.projectHandler; + } + if (name.equals(qname)) { + throw new SAXParseException("Unexpected element \"{" + uri + + "}" + name + "\" {" + ANT_CORE_URI + "}" + name, context.getLocator()); + } + throw new SAXParseException("Unexpected element \"" + qname + + "\" " + name, context.getLocator()); + } + } + + /** + * Handler for the top level "project" element. + */ + public static class ProjectHandler extends AntHandler { + + /** + * 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 uri The namespace URI for this element. + * @param tag Name of the element which caused this handler + * to be created. Should not be <code>null</code>. + * Ignored in this implementation. + * @param qname The qualified name for this element. + * @param attrs Attributes of the element which caused this + * handler to be created. Must not be <code>null</code>. + * @param context The current context. + * + * @exception SAXParseException if an unexpected attribute is + * encountered or if the <code>"default"</code> attribute + * is missing. + */ + public void onStartElement(String uri, String tag, String qname, Attributes attrs, + AntXMLContext context) throws SAXParseException { + String baseDir = null; + boolean nameAttributeSet = false; + + Project project = context.getProject(); + // Set the location of the implicit target associated with the project tag + context.getImplicitTarget().setLocation(new Location(context.getLocator())); + + /** TODO I really don't like this - the XML processor is still + * too 'involved' in the processing. A better solution (IMO) + * would be to create UE for Project and Target too, and + * then process the tree and have Project/Target deal with + * its attributes ( similar with Description ). + * + * If we eventually switch to ( or add support for ) DOM, + * things will work smoothly - UE can be avoided almost completely + * ( it could still be created on demand, for backward compatibility ) + */ + + for (int i = 0; i < attrs.getLength(); i++) { + String attrUri = attrs.getURI(i); + if (attrUri != null && !attrUri.equals("") && !attrUri.equals(uri)) { + continue; // Ignore attributes from unknown uris + } + String key = attrs.getLocalName(i); + String value = attrs.getValue(i); + + if (key.equals("default")) { + if (value != null && !value.equals("")) { + if (!context.isIgnoringProjectTag()) { + project.setDefault(value); + } + } + } else if (key.equals("name")) { + if (value != null) { + context.setCurrentProjectName(value); + nameAttributeSet = true; + if (!context.isIgnoringProjectTag()) { + project.setName(value); + project.addReference(value, project); + } else if (isInIncludeMode()) { + if (!"".equals(value) && getCurrentTargetPrefix()!= null && getCurrentTargetPrefix().endsWith(ProjectHelper.USE_PROJECT_NAME_AS_TARGET_PREFIX)) { + String newTargetPrefix = getCurrentTargetPrefix().replace(ProjectHelper.USE_PROJECT_NAME_AS_TARGET_PREFIX, value); + // help nested include tasks + setCurrentTargetPrefix(newTargetPrefix); + } + } + } + } else if (key.equals("id")) { + if (value != null) { + // What's the difference between id and name ? + if (!context.isIgnoringProjectTag()) { + project.addReference(value, project); + } + } + } else if (key.equals("basedir")) { + if (!context.isIgnoringProjectTag()) { + baseDir = value; + } + } else { + // TODO ignore attributes in a different NS ( maybe store them ? ) + throw new SAXParseException("Unexpected attribute \"" + attrs.getQName(i) + + "\"", context.getLocator()); + } + } + + // TODO Move to Project ( so it is shared by all helpers ) + String antFileProp = + MagicNames.ANT_FILE + "." + context.getCurrentProjectName(); + String dup = project.getProperty(antFileProp); + String typeProp = + MagicNames.ANT_FILE_TYPE + "." + context.getCurrentProjectName(); + String dupType = project.getProperty(typeProp); + if (dup != null && nameAttributeSet) { + Object dupFile = null; + Object contextFile = null; + if (MagicNames.ANT_FILE_TYPE_URL.equals(dupType)) { + try { + dupFile = new URL(dup); + } catch (java.net.MalformedURLException mue) { + throw new BuildException("failed to parse " + + dup + " as URL while looking" + + " at a duplicate project" + + " name.", mue); + } + contextFile = context.getBuildFileURL(); + } else { + dupFile = new File(dup); + contextFile = context.getBuildFile(); + } + + if (context.isIgnoringProjectTag() && !dupFile.equals(contextFile)) { + project.log("Duplicated project name in import. Project " + + context.getCurrentProjectName() + " defined first in " + dup + + " and again in " + contextFile, Project.MSG_WARN); + } + } + if (nameAttributeSet) { + if (context.getBuildFile() != null) { + project.setUserProperty(antFileProp, + context.getBuildFile().toString()); + project.setUserProperty(typeProp, + MagicNames.ANT_FILE_TYPE_FILE); + } else if (context.getBuildFileURL() != null) { + project.setUserProperty(antFileProp, + context.getBuildFileURL().toString()); + project.setUserProperty(typeProp, + MagicNames.ANT_FILE_TYPE_URL); + } + } + if (context.isIgnoringProjectTag()) { + // no further processing + return; + } + // set explicitly before starting ? + if (project.getProperty("basedir") != null) { + project.setBasedir(project.getProperty("basedir")); + } else { + // Default for baseDir is the location of the build file. + if (baseDir == null) { + project.setBasedir(context.getBuildFileParent().getAbsolutePath()); + } else { + // check whether the user has specified an absolute path + if ((new File(baseDir)).isAbsolute()) { + project.setBasedir(baseDir); + } else { + project.setBaseDir(FILE_UTILS.resolveFile(context.getBuildFileParent(), + baseDir)); + } + } + } + project.addTarget("", context.getImplicitTarget()); + context.setCurrentTarget(context.getImplicitTarget()); + } + + /** + * 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 uri The namespace URI for this element. + * @param name The name of the element being started. + * Will not be <code>null</code>. + * @param qname The qualified name for this element. + * @param attrs Attributes of the element being started. + * Will not be <code>null</code>. + * @param context The context for this element. + * @return a target or an element handler. + * + * @exception org.xml.sax.SAXParseException if the tag given is not + * <code>"taskdef"</code>, <code>"typedef"</code>, + * <code>"property"</code>, <code>"target"</code>, + * <code>"extension-point"</code> + * or a data type definition + */ + public AntHandler onStartChild(String uri, String name, String qname, Attributes attrs, + AntXMLContext context) throws SAXParseException { + return (name.equals("target") || name.equals("extension-point")) + && (uri.equals("") || uri.equals(ANT_CORE_URI)) + ? ProjectHelper2.targetHandler : ProjectHelper2.elementHandler; + } + } + + /** + * Handler for "target" and "extension-point" elements. + */ + public static class TargetHandler extends AntHandler { + + /** + * 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 uri The namespace URI for this element. + * @param tag Name of the element which caused this handler + * to be created. Should not be <code>null</code>. + * Ignored in this implementation. + * @param qname The qualified name for this element. + * @param attrs Attributes of the element which caused this + * handler to be created. Must not be <code>null</code>. + * @param context The current context. + * + * @exception SAXParseException if an unexpected attribute is encountered + * or if the <code>"name"</code> attribute is missing. + */ + public void onStartElement(String uri, String tag, String qname, Attributes attrs, + AntXMLContext context) throws SAXParseException { + String name = null; + String depends = ""; + String extensionPoint = null; + OnMissingExtensionPoint extensionPointMissing = null; + + Project project = context.getProject(); + Target target = "target".equals(tag) + ? new Target() : new ExtensionPoint(); + target.setProject(project); + target.setLocation(new Location(context.getLocator())); + context.addTarget(target); + + for (int i = 0; i < attrs.getLength(); i++) { + String attrUri = attrs.getURI(i); + if (attrUri != null && !attrUri.equals("") && !attrUri.equals(uri)) { + continue; // Ignore attributes from unknown uris + } + String key = attrs.getLocalName(i); + String value = attrs.getValue(i); + + if (key.equals("name")) { + name = value; + if ("".equals(name)) { + throw new BuildException("name attribute must " + "not be empty"); + } + } else if (key.equals("depends")) { + depends = value; + } else if (key.equals("if")) { + target.setIf(value); + } else if (key.equals("unless")) { + target.setUnless(value); + } else if (key.equals("id")) { + if (value != null && !value.equals("")) { + context.getProject().addReference(value, target); + } + } else if (key.equals("description")) { + target.setDescription(value); + } else if (key.equals("extensionOf")) { + extensionPoint = value; + } else if (key.equals("onMissingExtensionPoint")) { + try { + extensionPointMissing = OnMissingExtensionPoint.valueOf(value); + } catch (IllegalArgumentException e) { + throw new BuildException("Invalid onMissingExtensionPoint " + value); + } + } else { + throw new SAXParseException("Unexpected attribute \"" + key + "\"", context + .getLocator()); + } + } + + if (name == null) { + throw new SAXParseException("target element appears without a name attribute", + context.getLocator()); + } + + String prefix = null; + boolean isInIncludeMode = + context.isIgnoringProjectTag() && isInIncludeMode(); + String sep = getCurrentPrefixSeparator(); + + if (isInIncludeMode) { + prefix = getTargetPrefix(context); + if (prefix == null) { + throw new BuildException("can't include build file " + + context.getBuildFileURL() + + ", no as attribute has been given" + + " and the project tag doesn't" + + " specify a name attribute"); + } + name = prefix + sep + name; + } + + // Check if this target is in the current build file + if (context.getCurrentTargets().get(name) != null) { + throw new BuildException("Duplicate target '" + name + "'", + target.getLocation()); + } + Hashtable<String, Target> projectTargets = project.getTargets(); + boolean usedTarget = false; + // If the name has not already been defined define it + if (projectTargets.containsKey(name)) { + project.log("Already defined in main or a previous import, ignore " + name, + Project.MSG_VERBOSE); + } else { + target.setName(name); + context.getCurrentTargets().put(name, target); + project.addOrReplaceTarget(name, target); + usedTarget = true; + } + + if (depends.length() > 0) { + if (!isInIncludeMode) { + target.setDepends(depends); + } else { + for (String string : Target.parseDepends(depends, name, "depends")) { + target.addDependency(prefix + sep + string); + } + } + } + if (!isInIncludeMode && context.isIgnoringProjectTag() + && (prefix = getTargetPrefix(context)) != null) { + // In an imported file (and not completely + // ignoring the project tag or having a preconfigured prefix) + String newName = prefix + sep + name; + Target newTarget = target; + if (usedTarget) { + newTarget = "target".equals(tag) + ? new Target(target) : new ExtensionPoint(target); + } + newTarget.setName(newName); + context.getCurrentTargets().put(newName, newTarget); + project.addOrReplaceTarget(newName, newTarget); + } + if (extensionPointMissing != null && extensionPoint == null) { + throw new BuildException("onMissingExtensionPoint attribute cannot " + + "be specified unless extensionOf is specified", + target.getLocation()); + + } + if (extensionPoint != null) { + ProjectHelper helper = + (ProjectHelper) context.getProject(). + getReference(ProjectHelper.PROJECTHELPER_REFERENCE); + for (String extPointName : Target.parseDepends(extensionPoint, name, "extensionOf")) { + if (extensionPointMissing == null) { + extensionPointMissing = OnMissingExtensionPoint.FAIL; + } + // defer extensionpoint resolution until the full + // import stack has been processed + if (isInIncludeMode()) { + // if in include mode, provide prefix we're including by + // so that we can try and resolve extension point from + // the local file first + helper.getExtensionStack().add( + new String[] {extPointName, target.getName(), + extensionPointMissing.name(), prefix + sep}); + } else { + helper.getExtensionStack().add( + new String[] {extPointName, target.getName(), + extensionPointMissing.name()}); + } + } + } + } + + private String getTargetPrefix(AntXMLContext context) { + String configuredValue = getCurrentTargetPrefix(); + if (configuredValue != null && configuredValue.length() == 0) { + configuredValue = null; + } + if (configuredValue != null) { + return configuredValue; + } + + String projectName = context.getCurrentProjectName(); + if ("".equals(projectName)) { + projectName = null; + } + + return projectName; + } + + /** + * Handles the start of an element within a target. + * + * @param uri The namespace URI for this element. + * @param name The name of the element being started. + * Will not be <code>null</code>. + * @param qname The qualified name for this element. + * @param attrs Attributes of the element being started. + * Will not be <code>null</code>. + * @param context The current context. + * @return an element handler. + * + * @exception SAXParseException if an error occurs when initialising + * the appropriate child handler + */ + public AntHandler onStartChild(String uri, String name, String qname, Attributes attrs, + AntXMLContext context) throws SAXParseException { + return ProjectHelper2.elementHandler; + } + + /** + * Handle the end of the project, sets the current target of the + * context to be the implicit target. + * + * @param uri The namespace URI of the element. + * @param tag The name of the element. + * @param context The current context. + */ + public void onEndElement(String uri, String tag, AntXMLContext context) { + context.setCurrentTarget(context.getImplicitTarget()); + } + } + + /** + * Handler for all project elements ( tasks, data types ) + */ + public static class ElementHandler extends AntHandler { + + /** + * Constructor. + */ + public ElementHandler() { + } + + /** + * 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 uri The namespace URI for this element. + * @param tag Name of the element which caused this handler + * to be created. Must not be <code>null</code>. + * @param qname The qualified name for this element. + * @param attrs Attributes of the element which caused this + * handler to be created. Must not be <code>null</code>. + * @param context The current context. + * + * @exception SAXParseException in case of error (not thrown in + * this implementation) + */ + public void onStartElement(String uri, String tag, String qname, Attributes attrs, + AntXMLContext context) throws SAXParseException { + RuntimeConfigurable parentWrapper = context.currentWrapper(); + Object parent = null; + + if (parentWrapper != null) { + parent = parentWrapper.getProxy(); + } + + /* UnknownElement is used for tasks and data types - with + delayed eval */ + UnknownElement task = new UnknownElement(tag); + task.setProject(context.getProject()); + task.setNamespace(uri); + task.setQName(qname); + task.setTaskType(ProjectHelper.genComponentName(task.getNamespace(), tag)); + task.setTaskName(qname); + + Location location = new Location(context.getLocator().getSystemId(), context + .getLocator().getLineNumber(), context.getLocator().getColumnNumber()); + task.setLocation(location); + task.setOwningTarget(context.getCurrentTarget()); + + if (parent != null) { + // Nested element + ((UnknownElement) parent).addChild(task); + } else { + // Task included in a target ( including the default one ). + context.getCurrentTarget().addTask(task); + } + + context.configureId(task, attrs); + + // container.addTask(task); + // This is a nop in UE: task.init(); + + RuntimeConfigurable wrapper = new RuntimeConfigurable(task, task.getTaskName()); + + for (int i = 0; i < attrs.getLength(); i++) { + String name = attrs.getLocalName(i); + String attrUri = attrs.getURI(i); + if (attrUri != null && !attrUri.equals("") && !attrUri.equals(uri)) { + name = attrUri + ":" + attrs.getQName(i); + } + String value = attrs.getValue(i); + // PR: Hack for ant-type value + // an ant-type is a component name which can + // be namespaced, need to extract the name + // and convert from qualified name to uri/name + if (ANT_TYPE.equals(name) + || (ANT_CORE_URI.equals(attrUri) + && ANT_TYPE.equals(attrs.getLocalName(i)))) { + name = ANT_TYPE; + int index = value.indexOf(":"); + if (index >= 0) { + String prefix = value.substring(0, index); + String mappedUri = context.getPrefixMapping(prefix); + if (mappedUri == null) { + throw new BuildException("Unable to find XML NS prefix \"" + prefix + + "\""); + } + value = ProjectHelper.genComponentName(mappedUri, value + .substring(index + 1)); + } + } + wrapper.setAttribute(name, value); + } + if (parentWrapper != null) { + parentWrapper.addChild(wrapper); + } + context.pushWrapper(wrapper); + } + + /** + * Adds text to the task, using the wrapper + * + * @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. + * @param context The current context. + * + * @exception SAXParseException if the element doesn't support text + * + * @see ProjectHelper#addText(Project,java.lang.Object,char[],int,int) + */ + public void characters(char[] buf, int start, int count, + AntXMLContext context) throws SAXParseException { + RuntimeConfigurable wrapper = context.currentWrapper(); + 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 uri The namespace URI for this element. + * @param tag The name of the element being started. + * Will not be <code>null</code>. + * @param qname The qualified name for this element. + * @param attrs Attributes of the element being started. + * Will not be <code>null</code>. + * @param context The current context. + * @return The handler for elements. + * + * @exception SAXParseException if an error occurs when initialising + * the appropriate child handler + */ + public AntHandler onStartChild(String uri, String tag, String qname, Attributes attrs, + AntXMLContext context) throws SAXParseException { + return ProjectHelper2.elementHandler; + } + + /** + * Handles the end of the element. This pops the wrapper from + * the context. + * + * @param uri The namespace URI for the element. + * @param tag The name of the element. + * @param context The current context. + */ + public void onEndElement(String uri, String tag, AntXMLContext context) { + context.popWrapper(); + } + } +} |