0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: *
0017: */
0018:
0019: package org.apache.tools.ant.helper;
0020:
0021: import org.apache.tools.ant.BuildException;
0022: import org.apache.tools.ant.Location;
0023: import org.apache.tools.ant.Project;
0024: import org.apache.tools.ant.ProjectHelper;
0025: import org.apache.tools.ant.RuntimeConfigurable;
0026: import org.apache.tools.ant.Target;
0027: import org.apache.tools.ant.Task;
0028: import org.apache.tools.ant.UnknownElement;
0029: import org.apache.tools.ant.util.FileUtils;
0030: import org.apache.tools.ant.util.JAXPUtils;
0031: import org.xml.sax.Attributes;
0032: import org.xml.sax.InputSource;
0033: import org.xml.sax.Locator;
0034: import org.xml.sax.SAXException;
0035: import org.xml.sax.SAXParseException;
0036: import org.xml.sax.XMLReader;
0037: import org.xml.sax.helpers.DefaultHandler;
0038:
0039: import java.io.File;
0040: import java.io.FileInputStream;
0041: import java.io.FileNotFoundException;
0042: import java.io.IOException;
0043: import java.io.InputStream;
0044: import java.io.UnsupportedEncodingException;
0045: import java.net.URL;
0046: import java.util.HashMap;
0047: import java.util.Hashtable;
0048: import java.util.Map;
0049: import java.util.Stack;
0050:
0051: /**
0052: * Sax2 based project reader
0053: *
0054: */
0055: public class ProjectHelper2 extends ProjectHelper {
0056: /* Stateless */
0057:
0058: // singletons - since all state is in the context
0059: private static AntHandler elementHandler = new ElementHandler();
0060: private static AntHandler targetHandler = new TargetHandler();
0061: private static AntHandler mainHandler = new MainHandler();
0062: private static AntHandler projectHandler = new ProjectHandler();
0063:
0064: /**
0065: * helper for path -> URI and URI -> path conversions.
0066: */
0067: private static final FileUtils FILE_UTILS = FileUtils
0068: .getFileUtils();
0069:
0070: /**
0071: * Parse an unknown element from a url
0072: *
0073: * @param project the current project
0074: * @param source the url containing the task
0075: * @return a configured task
0076: * @exception BuildException if an error occurs
0077: */
0078: public UnknownElement parseUnknownElement(Project project,
0079: URL source) throws BuildException {
0080: Target dummyTarget = new Target();
0081: dummyTarget.setProject(project);
0082:
0083: AntXMLContext context = new AntXMLContext(project);
0084: context.addTarget(dummyTarget);
0085: context.setImplicitTarget(dummyTarget);
0086:
0087: parse(context.getProject(), source, new RootHandler(context,
0088: elementHandler));
0089: Task[] tasks = dummyTarget.getTasks();
0090: if (tasks.length != 1) {
0091: throw new BuildException("No tasks defined");
0092: }
0093: return (UnknownElement) tasks[0];
0094: }
0095:
0096: /**
0097: * Parse a source xml input.
0098: *
0099: * @param project the current project
0100: * @param source the xml source
0101: * @exception BuildException if an error occurs
0102: */
0103: public void parse(Project project, Object source)
0104: throws BuildException {
0105: getImportStack().addElement(source);
0106: //System.out.println("Adding " + source);
0107: AntXMLContext context = null;
0108: context = (AntXMLContext) project
0109: .getReference("ant.parsing.context");
0110: // System.out.println("Parsing " + getImportStack().size() + " " +
0111: // context+ " " + getImportStack() );
0112: if (context == null) {
0113: context = new AntXMLContext(project);
0114: project.addReference("ant.parsing.context", context);
0115: project.addReference("ant.targets", context.getTargets());
0116: }
0117:
0118: if (getImportStack().size() > 1) {
0119: // we are in an imported file.
0120: context.setIgnoreProjectTag(true);
0121: Target currentTarget = context.getCurrentTarget();
0122: Target currentImplicit = context.getImplicitTarget();
0123: Map currentTargets = context.getCurrentTargets();
0124: try {
0125: Target newCurrent = new Target();
0126: newCurrent.setProject(project);
0127: newCurrent.setName("");
0128: context.setCurrentTarget(newCurrent);
0129: context.setCurrentTargets(new HashMap());
0130: context.setImplicitTarget(newCurrent);
0131: parse(project, source, new RootHandler(context,
0132: mainHandler));
0133: newCurrent.execute();
0134: } finally {
0135: context.setCurrentTarget(currentTarget);
0136: context.setImplicitTarget(currentImplicit);
0137: context.setCurrentTargets(currentTargets);
0138: }
0139: } else {
0140: // top level file
0141: context.setCurrentTargets(new HashMap());
0142: parse(project, source,
0143: new RootHandler(context, mainHandler));
0144: // Execute the top-level target
0145: context.getImplicitTarget().execute();
0146: }
0147: }
0148:
0149: /**
0150: * Parses the project file, configuring the project as it goes.
0151: *
0152: * @param project the current project
0153: * @param source the xml source
0154: * @param handler the root handler to use (contains the current context)
0155: * @exception BuildException if the configuration is invalid or cannot
0156: * be read
0157: */
0158: public void parse(Project project, Object source,
0159: RootHandler handler) throws BuildException {
0160:
0161: AntXMLContext context = handler.context;
0162:
0163: File buildFile = null;
0164: URL url = null;
0165: String buildFileName = null;
0166:
0167: if (source instanceof File) {
0168: buildFile = (File) source;
0169: buildFile = FILE_UTILS.normalize(buildFile
0170: .getAbsolutePath());
0171: context.setBuildFile(buildFile);
0172: buildFileName = buildFile.toString();
0173: // } else if (source instanceof InputStream ) {
0174: } else if (source instanceof URL) {
0175: url = (URL) source;
0176: buildFileName = url.toString();
0177: // } else if (source instanceof InputSource ) {
0178: } else {
0179: throw new BuildException("Source "
0180: + source.getClass().getName()
0181: + " not supported by this plugin");
0182: }
0183:
0184: InputStream inputStream = null;
0185: InputSource inputSource = null;
0186:
0187: try {
0188: /**
0189: * SAX 2 style parser used to parse the given file.
0190: */
0191: XMLReader parser = JAXPUtils.getNamespaceXMLReader();
0192:
0193: String uri = null;
0194: if (buildFile != null) {
0195: uri = FILE_UTILS.toURI(buildFile.getAbsolutePath());
0196: inputStream = new FileInputStream(buildFile);
0197: } else {
0198: inputStream = url.openStream();
0199: uri = url.toString(); // ?? OK ??
0200: }
0201:
0202: inputSource = new InputSource(inputStream);
0203: if (uri != null) {
0204: inputSource.setSystemId(uri);
0205: }
0206: project.log("parsing buildfile " + buildFileName
0207: + " with URI = " + uri, Project.MSG_VERBOSE);
0208:
0209: DefaultHandler hb = handler;
0210:
0211: parser.setContentHandler(hb);
0212: parser.setEntityResolver(hb);
0213: parser.setErrorHandler(hb);
0214: parser.setDTDHandler(hb);
0215: parser.parse(inputSource);
0216: } catch (SAXParseException exc) {
0217: Location location = new Location(exc.getSystemId(), exc
0218: .getLineNumber(), exc.getColumnNumber());
0219:
0220: Throwable t = exc.getException();
0221: if (t instanceof BuildException) {
0222: BuildException be = (BuildException) t;
0223: if (be.getLocation() == Location.UNKNOWN_LOCATION) {
0224: be.setLocation(location);
0225: }
0226: throw be;
0227: } else if (t == null) {
0228: t = exc;
0229: }
0230:
0231: throw new BuildException(exc.getMessage(), t, location);
0232: } catch (SAXException exc) {
0233: Throwable t = exc.getException();
0234: if (t instanceof BuildException) {
0235: throw (BuildException) t;
0236: } else if (t == null) {
0237: t = exc;
0238: }
0239: throw new BuildException(exc.getMessage(), t);
0240: } catch (FileNotFoundException exc) {
0241: throw new BuildException(exc);
0242: } catch (UnsupportedEncodingException exc) {
0243: throw new BuildException("Encoding of project file "
0244: + buildFileName + " is invalid.", exc);
0245: } catch (IOException exc) {
0246: throw new BuildException("Error reading project file "
0247: + buildFileName + ": " + exc.getMessage(), exc);
0248: } finally {
0249: FileUtils.close(inputStream);
0250: }
0251: }
0252:
0253: /**
0254: * Returns main handler
0255: * @return main handler
0256: */
0257: protected static AntHandler getMainHandler() {
0258: return mainHandler;
0259: }
0260:
0261: /**
0262: * Sets main handler
0263: * @param handler new main handler
0264: */
0265: protected static void setMainHandler(AntHandler handler) {
0266: mainHandler = handler;
0267: }
0268:
0269: /**
0270: * Returns project handler
0271: * @return project handler
0272: */
0273: protected static AntHandler getProjectHandler() {
0274: return projectHandler;
0275: }
0276:
0277: /**
0278: * Sets project handler
0279: * @param handler new project handler
0280: */
0281: protected static void setProjectHandler(AntHandler handler) {
0282: projectHandler = handler;
0283: }
0284:
0285: /**
0286: * Returns target handler
0287: * @return target handler
0288: */
0289: protected static AntHandler getTargetHandler() {
0290: return targetHandler;
0291: }
0292:
0293: /**
0294: * Sets target handler
0295: * @param handler new target handler
0296: */
0297: protected static void setTargetHandler(AntHandler handler) {
0298: targetHandler = handler;
0299: }
0300:
0301: /**
0302: * Returns element handler
0303: * @return element handler
0304: */
0305: protected static AntHandler getElementHandler() {
0306: return elementHandler;
0307: }
0308:
0309: /**
0310: * Sets element handler
0311: * @param handler new element handler
0312: */
0313: protected static void setElementHandler(AntHandler handler) {
0314: elementHandler = handler;
0315: }
0316:
0317: /**
0318: * The common superclass for all SAX event handlers used to parse
0319: * the configuration file.
0320: *
0321: * The context will hold all state information. At each time
0322: * there is one active handler for the current element. It can
0323: * use onStartChild() to set an alternate handler for the child.
0324: */
0325: public static class AntHandler {
0326: /**
0327: * Handles the start of an element. This base implementation does
0328: * nothing.
0329: *
0330: * @param uri the namespace URI for the tag
0331: * @param tag The name of the element being started.
0332: * Will not be <code>null</code>.
0333: * @param qname The qualified name of the element.
0334: * @param attrs Attributes of the element being started.
0335: * Will not be <code>null</code>.
0336: * @param context The context that this element is in.
0337: *
0338: * @exception SAXParseException if this method is not overridden, or in
0339: * case of error in an overridden version
0340: */
0341: public void onStartElement(String uri, String tag,
0342: String qname, Attributes attrs, AntXMLContext context)
0343: throws SAXParseException {
0344: }
0345:
0346: /**
0347: * Handles the start of an element. This base implementation just
0348: * throws an exception - you must override this method if you expect
0349: * child elements.
0350: *
0351: * @param uri The namespace uri for this element.
0352: * @param tag The name of the element being started.
0353: * Will not be <code>null</code>.
0354: * @param qname The qualified name for this element.
0355: * @param attrs Attributes of the element being started.
0356: * Will not be <code>null</code>.
0357: * @param context The current context.
0358: * @return a handler (in the derived classes)
0359: *
0360: * @exception SAXParseException if this method is not overridden, or in
0361: * case of error in an overridden version
0362: */
0363: public AntHandler onStartChild(String uri, String tag,
0364: String qname, Attributes attrs, AntXMLContext context)
0365: throws SAXParseException {
0366: throw new SAXParseException("Unexpected element \"" + qname
0367: + " \"", context.getLocator());
0368: }
0369:
0370: /**
0371: * Handle the end of a element.
0372: *
0373: * @param uri the namespace uri of the element
0374: * @param tag the tag of the element
0375: * @param qname the qualified name of the element
0376: * @param context the current context
0377: * @exception SAXParseException if an error occurs
0378: */
0379: public void onEndChild(String uri, String tag, String qname,
0380: AntXMLContext context) throws SAXParseException {
0381: }
0382:
0383: /**
0384: * This method is called when this element and all elements nested into it have been
0385: * handled. I.e., this happens at the </end_tag_of_the_element>.
0386: * @param uri the namespace uri for this element
0387: * @param tag the element name
0388: * @param context the current context
0389: */
0390: public void onEndElement(String uri, String tag,
0391: AntXMLContext context) {
0392: }
0393:
0394: /**
0395: * Handles text within an element. This base implementation just
0396: * throws an exception, you must override it if you expect content.
0397: *
0398: * @param buf A character array of the text within the element.
0399: * Will not be <code>null</code>.
0400: * @param start The start element in the array.
0401: * @param count The number of characters to read from the array.
0402: * @param context The current context.
0403: *
0404: * @exception SAXParseException if this method is not overridden, or in
0405: * case of error in an overridden version
0406: */
0407: public void characters(char[] buf, int start, int count,
0408: AntXMLContext context) throws SAXParseException {
0409: String s = new String(buf, start, count).trim();
0410:
0411: if (s.length() > 0) {
0412: throw new SAXParseException("Unexpected text \"" + s
0413: + "\"", context.getLocator());
0414: }
0415: }
0416:
0417: /**
0418: * Will be called every time a namespace is reached.
0419: * It'll verify if the ns was processed, and if not load the task
0420: * definitions.
0421: * @param uri The namespace uri.
0422: */
0423: protected void checkNamespace(String uri) {
0424:
0425: }
0426: }
0427:
0428: /**
0429: * Handler for ant processing. Uses a stack of AntHandlers to
0430: * implement each element ( the original parser used a recursive behavior,
0431: * with the implicit execution stack )
0432: */
0433: public static class RootHandler extends DefaultHandler {
0434: private Stack antHandlers = new Stack();
0435: private AntHandler currentHandler = null;
0436: private AntXMLContext context;
0437:
0438: /**
0439: * Creates a new RootHandler instance.
0440: *
0441: * @param context The context for the handler.
0442: * @param rootHandler The handler for the root element.
0443: */
0444: public RootHandler(AntXMLContext context, AntHandler rootHandler) {
0445: currentHandler = rootHandler;
0446: antHandlers.push(currentHandler);
0447: this .context = context;
0448: }
0449:
0450: /**
0451: * Returns the current ant handler object.
0452: * @return the current ant handler.
0453: */
0454: public AntHandler getCurrentAntHandler() {
0455: return currentHandler;
0456: }
0457:
0458: /**
0459: * Resolves file: URIs relative to the build file.
0460: *
0461: * @param publicId The public identifier, or <code>null</code>
0462: * if none is available. Ignored in this
0463: * implementation.
0464: * @param systemId The system identifier provided in the XML
0465: * document. Will not be <code>null</code>.
0466: * @return an inputsource for this identifier
0467: */
0468: public InputSource resolveEntity(String publicId,
0469: String systemId) {
0470:
0471: context.getProject().log("resolving systemId: " + systemId,
0472: Project.MSG_VERBOSE);
0473:
0474: if (systemId.startsWith("file:")) {
0475: String path = FILE_UTILS.fromURI(systemId);
0476:
0477: File file = new File(path);
0478: if (!file.isAbsolute()) {
0479: file = FILE_UTILS.resolveFile(context
0480: .getBuildFileParent(), path);
0481: context
0482: .getProject()
0483: .log(
0484: "Warning: '"
0485: + systemId
0486: + "' in "
0487: + context.getBuildFile()
0488: + " should be expressed simply as '"
0489: + path.replace('\\', '/')
0490: + "' for compliance with other XML tools",
0491: Project.MSG_WARN);
0492: }
0493: context.getProject().log("file=" + file,
0494: Project.MSG_DEBUG);
0495: try {
0496: InputSource inputSource = new InputSource(
0497: new FileInputStream(file));
0498: inputSource.setSystemId(FILE_UTILS.toURI(file
0499: .getAbsolutePath()));
0500: return inputSource;
0501: } catch (FileNotFoundException fne) {
0502: context.getProject().log(
0503: file.getAbsolutePath()
0504: + " could not be found",
0505: Project.MSG_WARN);
0506: }
0507:
0508: }
0509: // use default if not file or file not found
0510: context.getProject().log("could not resolve systemId",
0511: Project.MSG_DEBUG);
0512: return null;
0513: }
0514:
0515: /**
0516: * Handles the start of a project element. A project handler is created
0517: * and initialised with the element name and attributes.
0518: *
0519: * @param uri The namespace uri for this element.
0520: * @param tag The name of the element being started.
0521: * Will not be <code>null</code>.
0522: * @param qname The qualified name for this element.
0523: * @param attrs Attributes of the element being started.
0524: * Will not be <code>null</code>.
0525: *
0526: * @exception org.xml.sax.SAXParseException if the tag given is not
0527: * <code>"project"</code>
0528: */
0529: public void startElement(String uri, String tag, String qname,
0530: Attributes attrs) throws SAXParseException {
0531: AntHandler next = currentHandler.onStartChild(uri, tag,
0532: qname, attrs, context);
0533: antHandlers.push(currentHandler);
0534: currentHandler = next;
0535: currentHandler.onStartElement(uri, tag, qname, attrs,
0536: context);
0537: }
0538:
0539: /**
0540: * Sets the locator in the project helper for future reference.
0541: *
0542: * @param locator The locator used by the parser.
0543: * Will not be <code>null</code>.
0544: */
0545: public void setDocumentLocator(Locator locator) {
0546: context.setLocator(locator);
0547: }
0548:
0549: /**
0550: * Handles the end of an element. Any required clean-up is performed
0551: * by the onEndElement() method and then the original handler
0552: * is restored to the parser.
0553: *
0554: * @param uri The namespace URI for this element.
0555: * @param name The name of the element which is ending.
0556: * Will not be <code>null</code>.
0557: * @param qName The qualified name for this element.
0558: *
0559: * @exception SAXException in case of error (not thrown in
0560: * this implementation)
0561: *
0562: */
0563: public void endElement(String uri, String name, String qName)
0564: throws SAXException {
0565: currentHandler.onEndElement(uri, name, context);
0566: AntHandler prev = (AntHandler) antHandlers.pop();
0567: currentHandler = prev;
0568: if (currentHandler != null) {
0569: currentHandler.onEndChild(uri, name, qName, context);
0570: }
0571: }
0572:
0573: /**
0574: * Handle text within an element, calls currentHandler.characters.
0575: *
0576: * @param buf A character array of the test.
0577: * @param start The start offset in the array.
0578: * @param count The number of characters to read.
0579: * @exception SAXParseException if an error occurs
0580: */
0581: public void characters(char[] buf, int start, int count)
0582: throws SAXParseException {
0583: currentHandler.characters(buf, start, count, context);
0584: }
0585:
0586: /**
0587: * Start a namespace prefix to uri mapping
0588: *
0589: * @param prefix the namespace prefix
0590: * @param uri the namespace uri
0591: */
0592: public void startPrefixMapping(String prefix, String uri) {
0593: context.startPrefixMapping(prefix, uri);
0594: }
0595:
0596: /**
0597: * End a namepace prefix to uri mapping
0598: *
0599: * @param prefix the prefix that is not mapped anymore
0600: */
0601: public void endPrefixMapping(String prefix) {
0602: context.endPrefixMapping(prefix);
0603: }
0604: }
0605:
0606: /**
0607: * The main handler - it handles the <project> tag.
0608: *
0609: * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler
0610: */
0611: public static class MainHandler extends AntHandler {
0612:
0613: /**
0614: * Handle the project tag
0615: *
0616: * @param uri The namespace uri.
0617: * @param name The element tag.
0618: * @param qname The element qualified name.
0619: * @param attrs The attributes of the element.
0620: * @param context The current context.
0621: * @return The project handler that handles subelements of project
0622: * @exception SAXParseException if the qualified name is not "project".
0623: */
0624: public AntHandler onStartChild(String uri, String name,
0625: String qname, Attributes attrs, AntXMLContext context)
0626: throws SAXParseException {
0627: if (name.equals("project")
0628: && (uri.equals("") || uri.equals(ANT_CORE_URI))) {
0629: return ProjectHelper2.projectHandler;
0630: } else {
0631: // if (context.importlevel > 0) {
0632: // // we are in an imported file. Allow top-level <target>.
0633: // if (qname.equals( "target" ) )
0634: // return ProjectHelper2.targetHandler;
0635: // }
0636: if (name.equals(qname)) {
0637: throw new SAXParseException(
0638: "Unexpected element \"{" + uri + "}" + name
0639: + "\" {" + ANT_CORE_URI + "}"
0640: + name, context.getLocator());
0641: } else {
0642: throw new SAXParseException("Unexpected element \""
0643: + qname + "\" " + name, context
0644: .getLocator());
0645: }
0646: }
0647: }
0648: }
0649:
0650: /**
0651: * Handler for the top level "project" element.
0652: */
0653: public static class ProjectHandler extends AntHandler {
0654:
0655: /**
0656: * Initialisation routine called after handler creation
0657: * with the element name and attributes. The attributes which
0658: * this handler can deal with are: <code>"default"</code>,
0659: * <code>"name"</code>, <code>"id"</code> and <code>"basedir"</code>.
0660: *
0661: * @param uri The namespace URI for this element.
0662: * @param tag Name of the element which caused this handler
0663: * to be created. Should not be <code>null</code>.
0664: * Ignored in this implementation.
0665: * @param qname The qualified name for this element.
0666: * @param attrs Attributes of the element which caused this
0667: * handler to be created. Must not be <code>null</code>.
0668: * @param context The current context.
0669: *
0670: * @exception SAXParseException if an unexpected attribute is
0671: * encountered or if the <code>"default"</code> attribute
0672: * is missing.
0673: */
0674: public void onStartElement(String uri, String tag,
0675: String qname, Attributes attrs, AntXMLContext context)
0676: throws SAXParseException {
0677: String baseDir = null;
0678: boolean nameAttributeSet = false;
0679:
0680: Project project = context.getProject();
0681: // Set the location of the implicit target associated with the project tag
0682: context.getImplicitTarget().setLocation(
0683: new Location(context.getLocator()));
0684:
0685: /** XXX I really don't like this - the XML processor is still
0686: * too 'involved' in the processing. A better solution (IMO)
0687: * would be to create UE for Project and Target too, and
0688: * then process the tree and have Project/Target deal with
0689: * its attributes ( similar with Description ).
0690: *
0691: * If we eventually switch to ( or add support for ) DOM,
0692: * things will work smoothly - UE can be avoided almost completely
0693: * ( it could still be created on demand, for backward compatibility )
0694: */
0695:
0696: for (int i = 0; i < attrs.getLength(); i++) {
0697: String attrUri = attrs.getURI(i);
0698: if (attrUri != null && !attrUri.equals("")
0699: && !attrUri.equals(uri)) {
0700: continue; // Ignore attributes from unknown uris
0701: }
0702: String key = attrs.getLocalName(i);
0703: String value = attrs.getValue(i);
0704:
0705: if (key.equals("default")) {
0706: if (value != null && !value.equals("")) {
0707: if (!context.isIgnoringProjectTag()) {
0708: project.setDefault(value);
0709: }
0710: }
0711: } else if (key.equals("name")) {
0712: if (value != null) {
0713: context.setCurrentProjectName(value);
0714: nameAttributeSet = true;
0715: if (!context.isIgnoringProjectTag()) {
0716: project.setName(value);
0717: project.addReference(value, project);
0718: }
0719: }
0720: } else if (key.equals("id")) {
0721: if (value != null) {
0722: // What's the difference between id and name ?
0723: if (!context.isIgnoringProjectTag()) {
0724: project.addReference(value, project);
0725: }
0726: }
0727: } else if (key.equals("basedir")) {
0728: if (!context.isIgnoringProjectTag()) {
0729: baseDir = value;
0730: }
0731: } else {
0732: // XXX ignore attributes in a different NS ( maybe store them ? )
0733: throw new SAXParseException(
0734: "Unexpected attribute \""
0735: + attrs.getQName(i) + "\"", context
0736: .getLocator());
0737: }
0738: }
0739:
0740: // XXX Move to Project ( so it is shared by all helpers )
0741: String antFileProp = "ant.file."
0742: + context.getCurrentProjectName();
0743: String dup = project.getProperty(antFileProp);
0744: if (dup != null && nameAttributeSet) {
0745: File dupFile = new File(dup);
0746: if (context.isIgnoringProjectTag()
0747: && !dupFile.equals(context.getBuildFile())) {
0748: project.log(
0749: "Duplicated project name in import. Project "
0750: + context.getCurrentProjectName()
0751: + " defined first in " + dup
0752: + " and again in "
0753: + context.getBuildFile(),
0754: Project.MSG_WARN);
0755: }
0756: }
0757:
0758: if (context.getBuildFile() != null && nameAttributeSet) {
0759: project.setUserProperty("ant.file."
0760: + context.getCurrentProjectName(), context
0761: .getBuildFile().toString());
0762: }
0763:
0764: if (context.isIgnoringProjectTag()) {
0765: // no further processing
0766: return;
0767: }
0768: // set explicitly before starting ?
0769: if (project.getProperty("basedir") != null) {
0770: project.setBasedir(project.getProperty("basedir"));
0771: } else {
0772: // Default for baseDir is the location of the build file.
0773: if (baseDir == null) {
0774: project.setBasedir(context.getBuildFileParent()
0775: .getAbsolutePath());
0776: } else {
0777: // check whether the user has specified an absolute path
0778: if ((new File(baseDir)).isAbsolute()) {
0779: project.setBasedir(baseDir);
0780: } else {
0781: project.setBaseDir(FILE_UTILS.resolveFile(
0782: context.getBuildFileParent(), baseDir));
0783: }
0784: }
0785: }
0786:
0787: project.addTarget("", context.getImplicitTarget());
0788: context.setCurrentTarget(context.getImplicitTarget());
0789: }
0790:
0791: /**
0792: * Handles the start of a top-level element within the project. An
0793: * appropriate handler is created and initialised with the details
0794: * of the element.
0795: *
0796: * @param uri The namespace URI for this element.
0797: * @param name The name of the element being started.
0798: * Will not be <code>null</code>.
0799: * @param qname The qualified name for this element.
0800: * @param attrs Attributes of the element being started.
0801: * Will not be <code>null</code>.
0802: * @param context The context for this element.
0803: * @return a target or an element handler.
0804: *
0805: * @exception org.xml.sax.SAXParseException if the tag given is not
0806: * <code>"taskdef"</code>, <code>"typedef"</code>,
0807: * <code>"property"</code>, <code>"target"</code>
0808: * or a data type definition
0809: */
0810: public AntHandler onStartChild(String uri, String name,
0811: String qname, Attributes attrs, AntXMLContext context)
0812: throws SAXParseException {
0813: if (name.equals("target")
0814: && (uri.equals("") || uri.equals(ANT_CORE_URI))) {
0815: return ProjectHelper2.targetHandler;
0816: } else {
0817: return ProjectHelper2.elementHandler;
0818: }
0819: }
0820:
0821: }
0822:
0823: /**
0824: * Handler for "target" elements.
0825: */
0826: public static class TargetHandler extends AntHandler {
0827:
0828: /**
0829: * Initialisation routine called after handler creation
0830: * with the element name and attributes. The attributes which
0831: * this handler can deal with are: <code>"name"</code>,
0832: * <code>"depends"</code>, <code>"if"</code>,
0833: * <code>"unless"</code>, <code>"id"</code> and
0834: * <code>"description"</code>.
0835: *
0836: * @param uri The namespace URI for this element.
0837: * @param tag Name of the element which caused this handler
0838: * to be created. Should not be <code>null</code>.
0839: * Ignored in this implementation.
0840: * @param qname The qualified name for this element.
0841: * @param attrs Attributes of the element which caused this
0842: * handler to be created. Must not be <code>null</code>.
0843: * @param context The current context.
0844: *
0845: * @exception SAXParseException if an unexpected attribute is encountered
0846: * or if the <code>"name"</code> attribute is missing.
0847: */
0848: public void onStartElement(String uri, String tag,
0849: String qname, Attributes attrs, AntXMLContext context)
0850: throws SAXParseException {
0851: String name = null;
0852: String depends = "";
0853:
0854: Project project = context.getProject();
0855: Target target = new Target();
0856: target.setProject(project);
0857: target.setLocation(new Location(context.getLocator()));
0858: context.addTarget(target);
0859:
0860: for (int i = 0; i < attrs.getLength(); i++) {
0861: String attrUri = attrs.getURI(i);
0862: if (attrUri != null && !attrUri.equals("")
0863: && !attrUri.equals(uri)) {
0864: continue; // Ignore attributes from unknown uris
0865: }
0866: String key = attrs.getLocalName(i);
0867: String value = attrs.getValue(i);
0868:
0869: if (key.equals("name")) {
0870: name = value;
0871: if ("".equals(name)) {
0872: throw new BuildException("name attribute must "
0873: + "not be empty");
0874: }
0875: } else if (key.equals("depends")) {
0876: depends = value;
0877: } else if (key.equals("if")) {
0878: target.setIf(value);
0879: } else if (key.equals("unless")) {
0880: target.setUnless(value);
0881: } else if (key.equals("id")) {
0882: if (value != null && !value.equals("")) {
0883: context.getProject()
0884: .addReference(value, target);
0885: }
0886: } else if (key.equals("description")) {
0887: target.setDescription(value);
0888: } else {
0889: throw new SAXParseException(
0890: "Unexpected attribute \"" + key + "\"",
0891: context.getLocator());
0892: }
0893: }
0894:
0895: if (name == null) {
0896: throw new SAXParseException(
0897: "target element appears without "
0898: + "a name attribute", context
0899: .getLocator());
0900: }
0901:
0902: // Check if this target is in the current build file
0903: if (context.getCurrentTargets().get(name) != null) {
0904: throw new BuildException("Duplicate target '" + name
0905: + "'", target.getLocation());
0906: }
0907:
0908: Hashtable projectTargets = project.getTargets();
0909: boolean usedTarget = false;
0910: // If the name has not already been defined define it
0911: if (projectTargets.containsKey(name)) {
0912: project
0913: .log(
0914: "Already defined in main or a previous import, "
0915: + "ignore " + name,
0916: Project.MSG_VERBOSE);
0917: } else {
0918: target.setName(name);
0919: context.getCurrentTargets().put(name, target);
0920: project.addOrReplaceTarget(name, target);
0921: usedTarget = true;
0922: }
0923:
0924: if (depends.length() > 0) {
0925: target.setDepends(depends);
0926: }
0927:
0928: if (context.isIgnoringProjectTag()
0929: && context.getCurrentProjectName() != null
0930: && context.getCurrentProjectName().length() != 0) {
0931: // In an impored file (and not completely
0932: // ignoring the project tag)
0933: String newName = context.getCurrentProjectName() + "."
0934: + name;
0935: Target newTarget = usedTarget ? new Target(target)
0936: : target;
0937: newTarget.setName(newName);
0938: context.getCurrentTargets().put(newName, newTarget);
0939: project.addOrReplaceTarget(newName, newTarget);
0940: }
0941: }
0942:
0943: /**
0944: * Handles the start of an element within a target.
0945: *
0946: * @param uri The namespace URI for this element.
0947: * @param name The name of the element being started.
0948: * Will not be <code>null</code>.
0949: * @param qname The qualified name for this element.
0950: * @param attrs Attributes of the element being started.
0951: * Will not be <code>null</code>.
0952: * @param context The current context.
0953: * @return an element handler.
0954: *
0955: * @exception SAXParseException if an error occurs when initialising
0956: * the appropriate child handler
0957: */
0958: public AntHandler onStartChild(String uri, String name,
0959: String qname, Attributes attrs, AntXMLContext context)
0960: throws SAXParseException {
0961: return ProjectHelper2.elementHandler;
0962: }
0963:
0964: /**
0965: * Handle the end of the project, sets the current target of the
0966: * context to be the implicit target.
0967: *
0968: * @param uri The namespace URI of the element.
0969: * @param tag The name of the element.
0970: * @param context The current context.
0971: */
0972: public void onEndElement(String uri, String tag,
0973: AntXMLContext context) {
0974: context.setCurrentTarget(context.getImplicitTarget());
0975: }
0976: }
0977:
0978: /**
0979: * Handler for all project elements ( tasks, data types )
0980: */
0981: public static class ElementHandler extends AntHandler {
0982:
0983: /**
0984: * Constructor.
0985: */
0986: public ElementHandler() {
0987: }
0988:
0989: /**
0990: * Initialisation routine called after handler creation
0991: * with the element name and attributes. This configures
0992: * the element with its attributes and sets it up with
0993: * its parent container (if any). Nested elements are then
0994: * added later as the parser encounters them.
0995: *
0996: * @param uri The namespace URI for this element.
0997: * @param tag Name of the element which caused this handler
0998: * to be created. Must not be <code>null</code>.
0999: * @param qname The qualified name for this element.
1000: * @param attrs Attributes of the element which caused this
1001: * handler to be created. Must not be <code>null</code>.
1002: * @param context The current context.
1003: *
1004: * @exception SAXParseException in case of error (not thrown in
1005: * this implementation)
1006: */
1007: public void onStartElement(String uri, String tag,
1008: String qname, Attributes attrs, AntXMLContext context)
1009: throws SAXParseException {
1010: RuntimeConfigurable parentWrapper = context
1011: .currentWrapper();
1012: Object parent = null;
1013:
1014: if (parentWrapper != null) {
1015: parent = parentWrapper.getProxy();
1016: }
1017:
1018: /* UnknownElement is used for tasks and data types - with
1019: delayed eval */
1020: UnknownElement task = new UnknownElement(tag);
1021: task.setProject(context.getProject());
1022: task.setNamespace(uri);
1023: task.setQName(qname);
1024: task.setTaskType(ProjectHelper.genComponentName(task
1025: .getNamespace(), tag));
1026: task.setTaskName(qname);
1027:
1028: Location location = new Location(context.getLocator()
1029: .getSystemId(), context.getLocator()
1030: .getLineNumber(), context.getLocator()
1031: .getColumnNumber());
1032: task.setLocation(location);
1033: task.setOwningTarget(context.getCurrentTarget());
1034:
1035: if (parent != null) {
1036: // Nested element
1037: ((UnknownElement) parent).addChild(task);
1038: } else {
1039: // Task included in a target ( including the default one ).
1040: context.getCurrentTarget().addTask(task);
1041: }
1042:
1043: context.configureId(task, attrs);
1044:
1045: // container.addTask(task);
1046: // This is a nop in UE: task.init();
1047:
1048: RuntimeConfigurable wrapper = new RuntimeConfigurable(task,
1049: task.getTaskName());
1050:
1051: for (int i = 0; i < attrs.getLength(); i++) {
1052: String name = attrs.getLocalName(i);
1053: String attrUri = attrs.getURI(i);
1054: if (attrUri != null && !attrUri.equals("")
1055: && !attrUri.equals(uri)) {
1056: name = attrUri + ":" + attrs.getQName(i);
1057: }
1058: String value = attrs.getValue(i);
1059: // PR: Hack for ant-type value
1060: // an ant-type is a component name which can
1061: // be namespaced, need to extract the name
1062: // and convert from qualified name to uri/name
1063: if (ANT_TYPE.equals(name)
1064: || (ANT_CORE_URI.equals(attrUri) && ANT_TYPE
1065: .equals(attrs.getLocalName(i)))) {
1066: name = ANT_TYPE;
1067: int index = value.indexOf(":");
1068: if (index != -1) {
1069: String prefix = value.substring(0, index);
1070: String mappedUri = context
1071: .getPrefixMapping(prefix);
1072: if (mappedUri == null) {
1073: throw new BuildException(
1074: "Unable to find XML NS prefix "
1075: + prefix);
1076: }
1077: value = ProjectHelper.genComponentName(
1078: mappedUri, value.substring(index + 1));
1079: }
1080: }
1081: wrapper.setAttribute(name, value);
1082: }
1083:
1084: if (parentWrapper != null) {
1085: parentWrapper.addChild(wrapper);
1086: }
1087:
1088: context.pushWrapper(wrapper);
1089: }
1090:
1091: /**
1092: * Adds text to the task, using the wrapper
1093: *
1094: * @param buf A character array of the text within the element.
1095: * Will not be <code>null</code>.
1096: * @param start The start element in the array.
1097: * @param count The number of characters to read from the array.
1098: * @param context The current context.
1099: *
1100: * @exception SAXParseException if the element doesn't support text
1101: *
1102: * @see ProjectHelper#addText(Project,java.lang.Object,char[],int,int)
1103: */
1104: public void characters(char[] buf, int start, int count,
1105: AntXMLContext context) throws SAXParseException {
1106: RuntimeConfigurable wrapper = context.currentWrapper();
1107: wrapper.addText(buf, start, count);
1108: }
1109:
1110: /**
1111: * Handles the start of an element within a target. Task containers
1112: * will always use another task handler, and all other tasks
1113: * will always use a nested element handler.
1114: *
1115: * @param uri The namespace URI for this element.
1116: * @param tag The name of the element being started.
1117: * Will not be <code>null</code>.
1118: * @param qname The qualified name for this element.
1119: * @param attrs Attributes of the element being started.
1120: * Will not be <code>null</code>.
1121: * @param context The current context.
1122: * @return The handler for elements.
1123: *
1124: * @exception SAXParseException if an error occurs when initialising
1125: * the appropriate child handler
1126: */
1127: public AntHandler onStartChild(String uri, String tag,
1128: String qname, Attributes attrs, AntXMLContext context)
1129: throws SAXParseException {
1130: return ProjectHelper2.elementHandler;
1131: }
1132:
1133: /**
1134: * Handles the end of the element. This pops the wrapper from
1135: * the context.
1136: *
1137: * @param uri The namespace URI for the element.
1138: * @param tag The name of the element.
1139: * @param context The current context.
1140: */
1141: public void onEndElement(String uri, String tag,
1142: AntXMLContext context) {
1143: context.popWrapper();
1144: }
1145: }
1146: }
|