/**
  * 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());
 }
  /**
   * 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];
  }
    /**
     * 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());
      }
    }
    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;
    }
    /**
     * 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;
    }
 /**
  * End a namepace prefix to uri mapping
  *
  * @param prefix the prefix that is not mapped anymore
  */
 public void endPrefixMapping(String prefix) {
   context.endPrefixMapping(prefix);
 }
 /**
  * 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);
 }
 /**
  * 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);
 }
  /**
   * 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 = (FileProvider) ((Resource) source).as(FileProvider.class);
      if (fp != null) {
        buildFile = fp.getFile();
      } else {
        URLProvider up = (URLProvider) ((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 {
          inputStream = url.openStream();
        }
      }

      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);
    }
  }
  /**
   * 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 currentTargets = context.getCurrentTargets();
      try {
        Target newCurrent = new Target();
        newCurrent.setProject(project);
        newCurrent.setName("");
        context.setCurrentTarget(newCurrent);
        context.setCurrentTargets(new HashMap());
        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());
      parse(project, source, new RootHandler(context, mainHandler));
      // Execute the top-level target
      context.getImplicitTarget().execute();

      // resolve extensionOf attributes
      for (Iterator i = getExtensionStack().iterator(); i.hasNext(); ) {
        String[] extensionInfo = (String[]) i.next();
        String tgName = extensionInfo[0];
        String name = extensionInfo[1];
        OnMissingExtensionPoint missingBehaviour =
            OnMissingExtensionPoint.valueOf(extensionInfo[2]);
        Hashtable projectTargets = project.getTargets();
        if (!projectTargets.containsKey(tgName)) {
          String message =
              "can't add target "
                  + name
                  + " to extension-point "
                  + tgName
                  + " because the extension-point is unknown.";
          if (missingBehaviour == OnMissingExtensionPoint.FAIL) {
            throw new BuildException(message);
          } else if (missingBehaviour == OnMissingExtensionPoint.WARN) {
            Target target = (Target) projectTargets.get(name);
            context.getProject().log(target, "Warning: " + message, Project.MSG_WARN);
          }
        } else {
          Target t = (Target) projectTargets.get(tgName);
          if (!(t instanceof ExtensionPoint)) {
            throw new BuildException("referenced target " + tgName + " is not an extension-point");
          }
          t.addDependency(name);
        }
      }
    }
  }
 /**
  * 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();
 }
 /**
  * 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);
 }
    /**
     * 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);
    }
 /**
  * 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());
 }
    /**
     * 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()));

      /**
       * XXX 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 ).
       *
       * <p>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().length() == 0)) {
                // help nested include tasks
                setCurrentTargetPrefix(value);
              }
            }
          }
        } 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 {
          // XXX ignore attributes in a different NS ( maybe store them ? )
          throw new SAXParseException(
              "Unexpected attribute \"" + attrs.getQName(i) + "\"", context.getLocator());
        }
      }

      // XXX 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 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());
 }
    /**
     * 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 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 (Iterator iter = Target.parseDepends(depends, name, "depends").iterator();
              iter.hasNext(); ) {
            target.addDependency(prefix + sep + iter.next());
          }
        }
      }
      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 = usedTarget ? new Target(target) : 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 (Iterator iter = Target.parseDepends(extensionPoint, name, "extensionOf").iterator();
            iter.hasNext(); ) {
          String tgName = (String) iter.next();
          if (isInIncludeMode()) {
            tgName = prefix + sep + tgName;
          }
          if (extensionPointMissing == null) {
            extensionPointMissing = OnMissingExtensionPoint.FAIL;
          }
          // defer extensionpoint resolution until the full
          // import stack has been processed
          helper.getExtensionStack().add(new String[] {tgName, name, extensionPointMissing.name()});
        }
      }
    }
Example #18
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);
    }
  }