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