Пример #1
0
 /**
  * Resolves the relative or absolute pathname correctly in both Ant and command-line situations.
  * If Ant launched us, we should use the basedir of the current project to resolve relative paths.
  *
  * <p>See Bugzilla 35571.
  *
  * @param s The file
  * @return The file resolved
  */
 protected File resolveFile(final String s) {
   if (getProject() == null) {
     // Note FileUtils.getFileUtils replaces FileUtils.newFileUtils in Ant 1.6.3
     return FileUtils.getFileUtils().resolveFile(null, s);
   } else {
     return FileUtils.getFileUtils().resolveFile(getProject().getBaseDir(), s);
   }
 }
Пример #2
0
  /** Executes the task. */
  public void execute() throws BuildException {
    checkParameters();

    final FileUtils fUtils = FileUtils.getFileUtils();
    final Project project = getProject();
    for (FileSet fileset : filesets) {
      final DirectoryScanner scanner = fileset.getDirectoryScanner(project);

      final File fromDir = fileset.getDir(project);
      final String[] srcFiles = scanner.getIncludedFiles();

      for (int fIndex = 0; fIndex < srcFiles.length; fIndex++) {
        final File file = fUtils.resolveFile(fromDir, srcFiles[fIndex]);

        if (!file.isFile()) {
          continue;
        }

        if (false == forceAllFiles && false == file.getName().endsWith(".java")) {
          throw new BuildException(
              "File does not end with '.java'. Use 'force' attribute to override.");
        }

        try {
          checkLicense(file);
        } catch (IOException e) {
          throw new BuildException("Could not process file: " + file.getAbsolutePath(), e);
        }
      }
    }
  }
Пример #3
0
  /** Copy eligible files from the srcDir to destDir */
  private void copyFilesToDestination() {
    if (filecopyList.size() > 0) {
      log(
          "Copying "
              + filecopyList.size()
              + " file"
              + (filecopyList.size() == 1 ? "" : "s")
              + " to "
              + destDir.getAbsolutePath());

      Enumeration e = filecopyList.keys();

      while (e.hasMoreElements()) {
        String fromFile = (String) e.nextElement();
        String toFile = (String) filecopyList.get(fromFile);

        try {
          FileUtils.getFileUtils().copyFile(fromFile, toFile);
        } catch (IOException ioe) {
          String msg =
              "Failed to copy " + fromFile + " to " + toFile + " due to " + ioe.getMessage();

          throw new BuildException(msg, ioe);
        }
      }
    }
  }
Пример #4
0
 private void setLastModified(File localFile) throws JSchException {
   SftpATTRS fileAttributes = null;
   String remotePath = null;
   ChannelSftp channel = openSftpChannel();
   channel.connect();
   try {
     fileAttributes = channel.lstat(remoteDir(remoteFile) + localFile.getName());
   } catch (SftpException e) {
     throw new JSchException("failed to stat remote file", e);
   }
   FileUtils.getFileUtils()
       .setFileLastModified(localFile, ((long) fileAttributes.getMTime()) * 1000);
 }
 static {
   FILE_UTILS = FileUtils.getFileUtils();
   AntClassLoader.pathMap = Collections.synchronizedMap(new HashMap<String, String>());
   AntClassLoader.subClassToLoad = null;
   CONSTRUCTOR_ARGS = new Class[] {ClassLoader.class, Project.class, Path.class, Boolean.TYPE};
   if (JavaEnvUtils.isAtLeastJavaVersion("1.5")) {
     try {
       AntClassLoader.subClassToLoad =
           Class.forName("org.apache.tools.ant.loader.AntClassLoader5");
     } catch (ClassNotFoundException ex) {
     }
   }
 }
  private File createExtractedFiles() {
    final File userExtensionsJavascriptFile;
    final File userExtensions;
    final File coreDir;

    coreDir = new File(customProfileDir, "core");
    try {
      coreDir.mkdirs();
      ResourceExtractor.extractResourcePath(SafariFileBasedLauncher.class, "/core", coreDir);
      // custom user-extensions
      userExtensions = getConfiguration().getUserExtensions();
      if (userExtensions != null) {
        userExtensionsJavascriptFile = new File(coreDir, "scripts/user-extensions.js");
        FileUtils.getFileUtils().copyFile(userExtensions, userExtensionsJavascriptFile, null, true);
      }
      return new File(coreDir, "RemoteRunner.html");
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }
Пример #7
0
 /**
  * Implementation of ResourceSelector.isSelected().
  *
  * @param resource The resource to check
  * @return whether the resource is selected
  * @see ResourceSelector#isSelected(Resource)
  */
 public boolean isSelected(Resource resource) {
   if (resource.isFilesystemOnly()) {
     // We have a 'resourced' file, so reconvert it and use
     // the 'old' implementation.
     FileResource fileResource = (FileResource) resource;
     File file = fileResource.getFile();
     String filename = fileResource.getName();
     File basedir = fileResource.getBaseDir();
     return isSelected(basedir, filename, file);
   } else {
     try {
       // How to handle non-file-Resources? I copy temporarily the
       // resource to a file and use the file-implementation.
       FileUtils fu = FileUtils.getFileUtils();
       File tmpFile = fu.createTempFile("modified-", ".tmp", null, true, false);
       Resource tmpResource = new FileResource(tmpFile);
       ResourceUtils.copyResource(resource, tmpResource);
       boolean isSelected =
           isSelected(tmpFile.getParentFile(), tmpFile.getName(), resource.toLongString());
       tmpFile.delete();
       return isSelected;
     } catch (UnsupportedOperationException uoe) {
       log(
           "The resource '"
               + resource.getName()
               + "' does not provide an InputStream, so it is not checked. "
               + "Akkording to 'selres' attribute value it is "
               + ((selectResourcesWithoutInputStream) ? "" : " not")
               + "selected.",
           Project.MSG_INFO);
       return selectResourcesWithoutInputStream;
     } catch (Exception e) {
       throw new BuildException(e);
     }
   }
 }
  /**
   * Test case for setFollowLinks() and associated functionality. Only supports test on Linux at the
   * moment because Java has no real notion of symlinks built in, so an os-specfic call to
   * Runtime.exec() must be made to create a link to test against.
   */
  public void testSetFollowLinks() throws IOException {
    if (supportsSymlinks) {
      File linkFile = new File(System.getProperty("root"), "src/main/org/apache/tools/ThisIsALink");
      System.err.println("link exists pre-test? " + linkFile.exists());

      try {
        // add conditions and more commands as soon as the need arises
        String[] command = new String[] {"ln", "-s", "ant", linkFile.getAbsolutePath()};
        try {
          Runtime.getRuntime().exec(command);
          // give ourselves some time for the system call
          // to execute... tweak if you have a really over
          // loaded system.
          Thread.sleep(1000);
        } catch (IOException ioe) {
          fail("IOException making link " + ioe);
        } catch (InterruptedException ie) {
        }

        File dir = new File(System.getProperty("root"), "src/main/org/apache/tools");
        System.err.println("link exists after exec? " + linkFile.exists());
        System.err.println(
            "Ant knows it is a link? "
                + FileUtils.getFileUtils().isSymbolicLink(dir, "ThisIsALink"));

        DirectoryScanner ds = new DirectoryScanner();

        // followLinks should be true by default, but if this ever
        // changes we will need this line.
        ds.setFollowSymlinks(true);

        ds.setBasedir(dir);
        ds.setExcludes(new String[] {"ant/**"});
        ds.scan();

        boolean haveZipPackage = false;
        boolean haveTaskdefsPackage = false;

        String[] included = ds.getIncludedDirectories();
        for (int i = 0; i < included.length; i++) {
          if (included[i].equals("zip")) {
            haveZipPackage = true;
          } else if (included[i].equals("ThisIsALink" + File.separator + "taskdefs")) {
            haveTaskdefsPackage = true;
          }
        }

        // if we followed the symlink we just made we should
        // bypass the excludes.

        assertTrue("(1) zip package included", haveZipPackage);
        assertTrue("(1) taskdefs package included", haveTaskdefsPackage);

        ds = new DirectoryScanner();
        ds.setFollowSymlinks(false);

        ds.setBasedir(dir);
        ds.setExcludes(new String[] {"ant/**"});
        ds.scan();

        haveZipPackage = false;
        haveTaskdefsPackage = false;
        included = ds.getIncludedDirectories();
        for (int i = 0; i < included.length; i++) {
          if (included[i].equals("zip")) {
            haveZipPackage = true;
          } else if (included[i].equals("ThisIsALink" + File.separator + "taskdefs")) {
            haveTaskdefsPackage = true;
          }
        }
        assertTrue("(2) zip package included", haveZipPackage);
        assertTrue("(2) taskdefs package not included", !haveTaskdefsPackage);

      } finally {
        System.err.println("link exists pre-delete? " + linkFile.exists());
        if (!linkFile.delete()) {
          throw new RuntimeException("Failed to delete " + linkFile);
        }
        System.err.println("link exists post-delete? " + linkFile.exists());
      }
    }
  }
Пример #9
0
/**
 * Set the length of one or more files, as the intermittently available <code>truncate</code> Unix
 * utility/function.
 *
 * @since Ant 1.7.1
 */
public class Truncate extends Task {

  private static final int BUFFER_SIZE = 1024;

  private static final Long ZERO = new Long(0L);

  private static final String NO_CHILD = "No files specified.";

  private static final String INVALID_LENGTH = "Cannot truncate to length ";

  private static final String READ_WRITE = "rw";

  private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();

  private static final byte[] FILL_BUFFER = new byte[BUFFER_SIZE];

  private Path path;
  private boolean create = true;
  private boolean mkdirs = false;

  private Long length;
  private Long adjust;

  /**
   * Set a single target File.
   *
   * @param f the single File
   */
  public void setFile(File f) {
    add(new FileResource(f));
  }

  /**
   * Add a nested (filesystem-only) ResourceCollection.
   *
   * @param rc the ResourceCollection to add.
   */
  public void add(ResourceCollection rc) {
    getPath().add(rc);
  }

  /**
   * Set the amount by which files' lengths should be adjusted. It is permissible to append K / M /
   * G / T / P.
   *
   * @param adjust (positive or negative) adjustment amount.
   */
  public void setAdjust(Long adjust) {
    this.adjust = adjust;
  }

  /**
   * Set the length to which files should be set. It is permissible to append K / M / G / T / P.
   *
   * @param length (positive) adjustment amount.
   */
  public void setLength(Long length) {
    this.length = length;
    if (length != null && length.longValue() < 0) {
      throw new BuildException(INVALID_LENGTH + length);
    }
  }

  /**
   * Set whether to create nonexistent files.
   *
   * @param create boolean, default <code>true</code>.
   */
  public void setCreate(boolean create) {
    this.create = create;
  }

  /**
   * Set whether, when creating nonexistent files, nonexistent directories should also be created.
   *
   * @param mkdirs boolean, default <code>false</code>.
   */
  public void setMkdirs(boolean mkdirs) {
    this.mkdirs = mkdirs;
  }

  /** {@inheritDoc}. */
  public void execute() {
    if (length != null && adjust != null) {
      throw new BuildException("length and adjust are mutually exclusive options");
    }
    if (length == null && adjust == null) {
      length = ZERO;
    }
    if (path == null) {
      throw new BuildException(NO_CHILD);
    }
    for (Iterator it = path.iterator(); it.hasNext(); ) {
      Resource r = (Resource) it.next();
      File f = ((FileProvider) r.as(FileProvider.class)).getFile();
      if (shouldProcess(f)) {
        process(f);
      }
    }
  }

  private boolean shouldProcess(File f) {
    if (f.isFile()) {
      return true;
    }
    if (!create) {
      return false;
    }
    Exception exception = null;
    try {
      if (FILE_UTILS.createNewFile(f, mkdirs)) {
        return true;
      }
    } catch (IOException e) {
      exception = e;
    }
    String msg = "Unable to create " + f;
    if (exception == null) {
      log(msg, Project.MSG_WARN);
      return false;
    }
    throw new BuildException(msg, exception);
  }

  private void process(File f) {
    long len = f.length();
    long newLength = length == null ? len + adjust.longValue() : length.longValue();

    if (len == newLength) {
      // nothing to do!
      return;
    }
    RandomAccessFile raf = null;
    try {
      raf = new RandomAccessFile(f, READ_WRITE);
    } catch (Exception e) {
      throw new BuildException("Could not open " + f + " for writing", e);
    }
    try {
      if (newLength > len) {
        long pos = len;
        raf.seek(pos);
        while (pos < newLength) {
          long writeCount = Math.min(FILL_BUFFER.length, newLength - pos);
          raf.write(FILL_BUFFER, 0, (int) writeCount);
          pos += writeCount;
        }
      } else {
        raf.setLength(newLength);
      }
    } catch (IOException e) {
      throw new BuildException("Exception working with " + raf, e);
    } finally {
      try {
        raf.close();
      } catch (IOException e) {
        log("Caught " + e + " closing " + raf, Project.MSG_WARN);
      }
    }
  }

  private synchronized Path getPath() {
    if (path == null) {
      path = new Path(getProject());
    }
    return path;
  }
}
 protected void definePackage(
     final File container, final String packageName, final Manifest manifest) {
   final String sectionName = packageName.replace('.', '/') + "/";
   String specificationTitle = null;
   String specificationVendor = null;
   String specificationVersion = null;
   String implementationTitle = null;
   String implementationVendor = null;
   String implementationVersion = null;
   String sealedString = null;
   URL sealBase = null;
   final Attributes sectionAttributes = manifest.getAttributes(sectionName);
   if (sectionAttributes != null) {
     specificationTitle = sectionAttributes.getValue(Attributes.Name.SPECIFICATION_TITLE);
     specificationVendor = sectionAttributes.getValue(Attributes.Name.SPECIFICATION_VENDOR);
     specificationVersion = sectionAttributes.getValue(Attributes.Name.SPECIFICATION_VERSION);
     implementationTitle = sectionAttributes.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
     implementationVendor = sectionAttributes.getValue(Attributes.Name.IMPLEMENTATION_VENDOR);
     implementationVersion = sectionAttributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
     sealedString = sectionAttributes.getValue(Attributes.Name.SEALED);
   }
   final Attributes mainAttributes = manifest.getMainAttributes();
   if (mainAttributes != null) {
     if (specificationTitle == null) {
       specificationTitle = mainAttributes.getValue(Attributes.Name.SPECIFICATION_TITLE);
     }
     if (specificationVendor == null) {
       specificationVendor = mainAttributes.getValue(Attributes.Name.SPECIFICATION_VENDOR);
     }
     if (specificationVersion == null) {
       specificationVersion = mainAttributes.getValue(Attributes.Name.SPECIFICATION_VERSION);
     }
     if (implementationTitle == null) {
       implementationTitle = mainAttributes.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
     }
     if (implementationVendor == null) {
       implementationVendor = mainAttributes.getValue(Attributes.Name.IMPLEMENTATION_VENDOR);
     }
     if (implementationVersion == null) {
       implementationVersion = mainAttributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
     }
     if (sealedString == null) {
       sealedString = mainAttributes.getValue(Attributes.Name.SEALED);
     }
   }
   if (sealedString != null && sealedString.equalsIgnoreCase("true")) {
     try {
       sealBase = new URL(FileUtils.getFileUtils().toURI(container.getAbsolutePath()));
     } catch (MalformedURLException ex) {
     }
   }
   this.definePackage(
       packageName,
       specificationTitle,
       specificationVersion,
       specificationVendor,
       implementationTitle,
       implementationVersion,
       implementationVendor,
       sealBase);
 }
Пример #11
0
  public void execute() throws MojoExecutionException, MojoFailureException {
    if (skipNbm) {
      getLog().info("Skipping generation of NBM file.");
      return;
    }

    if ("pom".equals(project.getPackaging())) {
      getLog().info("Skipping " + project.getId() + ", no nbm:nbm execution for 'pom' packaging");
      return;
    }
    super.execute();

    // 3. generate nbm
    File nbmFile = new File(nbmBuildDir, finalName + ".nbm");
    MakeNBM nbmTask = (MakeNBM) antProject.createTask("makenbm");
    nbmTask.setFile(nbmFile);
    nbmTask.setProductDir(clusterDir);

    nbmTask.setModule("modules" + File.separator + moduleJarName + ".jar");
    boolean reqRestart = requiresRestart;
    if (!reqRestart && module.isRequiresRestart()) {
      reqRestart = module.isRequiresRestart();
      getLog()
          .warn(
              "Module descriptor's requiresRestart field is deprecated, use plugin's configuration in pom.xml");
    }
    nbmTask.setNeedsrestart(Boolean.toString(reqRestart));
    String moduleAuthor = author;
    if (module.getAuthor() != null) {
      moduleAuthor = module.getAuthor();
      getLog()
          .warn(
              "Module descriptor's requiresRestart field is deprecated, use plugin's configuration in pom.xml");
    }
    nbmTask.setModuleauthor(moduleAuthor);
    if (keystore != null && keystorealias != null && keystorepassword != null) {
      File ks = new File(keystore);
      if (!ks.exists()) {
        getLog().warn("Cannot find keystore file at " + ks.getAbsolutePath());
      } else {
        Signature sig = nbmTask.createSignature();
        sig.setKeystore(ks);
        sig.setAlias(keystorealias);
        sig.setStorepass(keystorepassword);
        getLog().debug("Setup the Ant task to sign the NBM file.");
      }
    } else if (keystore != null || keystorepassword != null || keystorealias != null) {
      getLog()
          .warn(
              "If you want to sign the nbm file, you need to define all three keystore related parameters.");
    }
    String licName = licenseName;
    File licFile = licenseFile;
    if (module.getLicenseName() != null) {
      licName = module.getLicenseName();
      getLog()
          .warn(
              "Module descriptor's licenseName field is deprecated, use plugin's configuration in pom.xml");
    }
    if (module.getLicenseFile() != null) {
      File lf = new File(project.getBasedir(), module.getLicenseFile());
      licFile = lf;
      getLog()
          .warn(
              "Module descriptor's licenseFile field is deprecated, use plugin's configuration in pom.xml");
    }
    if (licName != null && licFile != null) {
      if (!licFile.exists() || !licFile.isFile()) {
        getLog().warn("Cannot find license file at " + licFile.getAbsolutePath());
      } else {
        Blurb lb = nbmTask.createLicense();
        lb.setFile(licFile);
        lb.addText(licName);
      }
    } else if (licName != null || licFile != null) {
      getLog()
          .warn(
              "To set license for the nbm, you need to specify both licenseName and licenseFile parameters.");
    } else {
      Blurb lb = nbmTask.createLicense();
      lb.addText(createDefaultLicenseHeader());
      lb.addText(createDefaultLicenseText());
    }
    String hpUrl = homePageUrl;
    if (module.getHomepageUrl() != null) {
      getLog()
          .warn(
              "Module descriptor's homePageUrl field is deprecated, use plugin's configuration in pom.xml");
      hpUrl = module.getHomepageUrl();
    }
    if (hpUrl != null) {
      nbmTask.setHomepage(hpUrl);
    }
    String distribUrl = distributionUrl;
    if (module.getDistributionUrl() != null) {
      distribUrl = module.getDistributionUrl();
      getLog()
          .warn(
              "Module descriptor's distributionUrl field is deprecated, use plugin's configuration in pom.xml");
    }
    if (distribUrl != null) {
      ArtifactRepository distRepository =
          CreateUpdateSiteMojo.getDeploymentRepository(distribUrl, container, getLog());
      String dist = null;
      if (distRepository == null) {
        if (!distribUrl.contains("::")) {
          dist = distribUrl + (distribUrl.endsWith("/") ? "" : "/") + nbmFile.getName();
        }
      } else {
        Artifact art =
            artifactFactory.createArtifact(
                project.getGroupId(),
                project.getArtifactId(),
                project.getVersion(),
                null,
                "nbm-file");

        dist =
            distRepository.getUrl()
                + (distRepository.getUrl().endsWith("/") ? "" : "/")
                + distRepository.pathOf(art);
      }
      nbmTask.setDistribution(dist);
    } else {
      nbmTask.setDistribution(nbmFile.getName());
    }
    if (!"extra".equals(cluster)) {
      nbmTask.setTargetcluster(cluster);
    }
    // MNBMODULE-217 avoid using the static DATE_FORMAT variable in MavenNBM.java (in ant harness)
    nbmTask.setReleasedate(DATE_FORMAT.format(new Date(System.currentTimeMillis())));
    try {
      nbmTask.execute();
    } catch (BuildException e) {
      throw new MojoExecutionException("Cannot Generate nbm file:" + e.getMessage(), e);
    }
    try {
      File nbmfile = new File(buildDir, nbmFile.getName());
      FileUtils.getFileUtils().copyFile(nbmFile, nbmfile);
      projectHelper.attachArtifact(project, "nbm-file", null, nbmfile);
    } catch (IOException ex) {
      throw new MojoExecutionException("Cannot copy nbm to build directory", ex);
    }
  }
Пример #12
0
/**
 * Runs the rmic compiler against classes.
 *
 * <p>Rmic can be run on a single class (as specified with the classname attribute) or a number of
 * classes at once (all classes below base that are neither _Stub nor _Skel classes). If you want to
 * rmic a single class and this class is a class nested into another class, you have to specify the
 * classname in the form <code>Outer$$Inner</code> instead of <code>Outer.Inner</code>.
 *
 * <p>It is possible to refine the set of files that are being rmiced. This can be done with the
 * <i>includes</i>, <i>includesfile</i>, <i>excludes</i>, <i>excludesfile</i> and
 * <i>defaultexcludes</i> attributes. With the <i>includes</i> or <i>includesfile</i> attribute you
 * specify the files you want to have included by using patterns. The <i>exclude</i> or
 * <i>excludesfile</i> attribute is used to specify the files you want to have excluded. This is
 * also done with patterns. And finally with the <i>defaultexcludes</i> attribute, you can specify
 * whether you want to use default exclusions or not. See the section on directory based tasks, on
 * how the inclusion/exclusion of files works, and how to write patterns.
 *
 * <p>This task forms an implicit FileSet and supports all attributes of <code>&lt;fileset&gt;
 * </code> (<code>dir</code> becomes <code>base</code>) as well as the nested <code>&lt;include&gt;
 * </code>, <code>&lt;exclude&gt;</code> and <code>&lt;patternset&gt;</code> elements.
 *
 * <p>It is possible to use different compilers. This can be selected with the
 * &quot;build.rmic&quot; property or the <code>compiler</code> attribute. <a
 * name="compilervalues">There are three choices</a>:
 *
 * <ul>
 *   <li>sun (the standard compiler of the JDK)
 *   <li>kaffe (the standard compiler of {@link <a href="http://www.kaffe.org">Kaffe</a>})
 *   <li>weblogic
 * </ul>
 *
 * <p>The <a href="http://dione.zcu.cz/~toman40/miniRMI/">miniRMI</a> project contains a compiler
 * implementation for this task as well, please consult miniRMI's documentation to learn how to use
 * it.
 *
 * @since Ant 1.1
 * @ant.task category="java"
 */
public class Rmic extends MatchingTask {

  /** rmic failed message */
  public static final String ERROR_RMIC_FAILED =
      "Rmic failed; see the compiler error output for details.";

  private File baseDir;
  private File destDir;
  private String classname;
  private File sourceBase;
  private String stubVersion;
  private Path compileClasspath;
  private Path extDirs;
  private boolean verify = false;
  private boolean filtering = false;

  private boolean iiop = false;
  private String iiopOpts;
  private boolean idl = false;
  private String idlOpts;
  private boolean debug = false;
  private boolean includeAntRuntime = true;
  private boolean includeJavaRuntime = false;

  private Vector compileList = new Vector();

  private AntClassLoader loader = null;

  private FacadeTaskHelper facade;
  /** unable to verify message */
  public static final String ERROR_UNABLE_TO_VERIFY_CLASS = "Unable to verify class ";
  /** could not be found message */
  public static final String ERROR_NOT_FOUND = ". It could not be found.";
  /** not defined message */
  public static final String ERROR_NOT_DEFINED = ". It is not defined.";
  /** loaded error message */
  public static final String ERROR_LOADING_CAUSED_EXCEPTION = ". Loading caused Exception: ";
  /** base not exists message */
  public static final String ERROR_NO_BASE_EXISTS = "base or destdir does not exist: ";
  /** base not a directory message */
  public static final String ERROR_NOT_A_DIR = "base or destdir is not a directory:";
  /** base attribute not set message */
  public static final String ERROR_BASE_NOT_SET = "base or destdir attribute must be set!";

  private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();

  private String executable = null;

  private boolean listFiles = false;

  private RmicAdapter nestedAdapter = null;

  /** Constructor for Rmic. */
  public Rmic() {
    facade = new FacadeTaskHelper(RmicAdapterFactory.DEFAULT_COMPILER);
  }

  /**
   * Sets the location to store the compiled files; required
   *
   * @param base the location to store the compiled files
   */
  public void setBase(File base) {
    this.baseDir = base;
  }

  /**
   * Sets the base directory to output the generated files.
   *
   * @param destdir the base directory to output the generated files.
   * @since Ant 1.8.0
   */
  public void setDestdir(File destdir) {
    this.destDir = destdir;
  }

  /**
   * Gets the base directory to output the generated files.
   *
   * @return the base directory to output the generated files.
   * @since Ant 1.8.0
   */
  public File getDestdir() {
    return this.destDir;
  }

  /**
   * Gets the base directory to output the generated files, favoring destdir if set, otherwise
   * defaulting to basedir.
   *
   * @return the actual directory to output to (either destdir or basedir)
   * @since Ant 1.8.0
   */
  public File getOutputDir() {
    if (getDestdir() != null) {
      return getDestdir();
    }
    return getBase();
  }

  /**
   * Gets the base directory to output generated class.
   *
   * @return the location of the compiled files
   */
  public File getBase() {
    return this.baseDir;
  }

  /**
   * Sets the class to run <code>rmic</code> against; optional
   *
   * @param classname the name of the class for rmic to create code for
   */
  public void setClassname(String classname) {
    this.classname = classname;
  }

  /**
   * Gets the class name to compile.
   *
   * @return the name of the class to compile
   */
  public String getClassname() {
    return classname;
  }

  /**
   * optional directory to save generated source files to.
   *
   * @param sourceBase the directory to save source files to.
   */
  public void setSourceBase(File sourceBase) {
    this.sourceBase = sourceBase;
  }

  /**
   * Gets the source dirs to find the source java files.
   *
   * @return sourceBase the directory containing the source files.
   */
  public File getSourceBase() {
    return sourceBase;
  }

  /**
   * Specify the JDK version for the generated stub code. Specify &quot;1.1&quot; to pass the
   * &quot;-v1.1&quot; option to rmic.
   *
   * @param stubVersion the JDK version
   */
  public void setStubVersion(String stubVersion) {
    this.stubVersion = stubVersion;
  }

  /**
   * Gets the JDK version for the generated stub code.
   *
   * @return stubVersion
   */
  public String getStubVersion() {
    return stubVersion;
  }

  /**
   * Sets token filtering [optional], default=false
   *
   * @param filter turn on token filtering
   */
  public void setFiltering(boolean filter) {
    this.filtering = filter;
  }

  /**
   * Gets whether token filtering is set
   *
   * @return filtering
   */
  public boolean getFiltering() {
    return filtering;
  }

  /**
   * Generate debug info (passes -g to rmic); optional, defaults to false
   *
   * @param debug turn on debug info
   */
  public void setDebug(boolean debug) {
    this.debug = debug;
  }

  /**
   * Gets the debug flag.
   *
   * @return debug
   */
  public boolean getDebug() {
    return debug;
  }

  /**
   * Set the classpath to be used for this compilation.
   *
   * @param classpath the classpath used for this compilation
   */
  public synchronized void setClasspath(Path classpath) {
    if (compileClasspath == null) {
      compileClasspath = classpath;
    } else {
      compileClasspath.append(classpath);
    }
  }

  /**
   * Creates a nested classpath element.
   *
   * @return classpath
   */
  public synchronized Path createClasspath() {
    if (compileClasspath == null) {
      compileClasspath = new Path(getProject());
    }
    return compileClasspath.createPath();
  }

  /**
   * Adds to the classpath a reference to a &lt;path&gt; defined elsewhere.
   *
   * @param pathRef the reference to add to the classpath
   */
  public void setClasspathRef(Reference pathRef) {
    createClasspath().setRefid(pathRef);
  }

  /**
   * Gets the classpath.
   *
   * @return the classpath
   */
  public Path getClasspath() {
    return compileClasspath;
  }

  /**
   * Flag to enable verification so that the classes found by the directory match are checked to see
   * if they implement java.rmi.Remote. optional; This defaults to false if not set.
   *
   * @param verify turn on verification for classes
   */
  public void setVerify(boolean verify) {
    this.verify = verify;
  }

  /**
   * Get verify flag.
   *
   * @return verify
   */
  public boolean getVerify() {
    return verify;
  }

  /**
   * Indicates that IIOP compatible stubs should be generated; optional, defaults to false if not
   * set.
   *
   * @param iiop generate IIOP compatible stubs
   */
  public void setIiop(boolean iiop) {
    this.iiop = iiop;
  }

  /**
   * Gets iiop flags.
   *
   * @return iiop
   */
  public boolean getIiop() {
    return iiop;
  }

  /**
   * Set additional arguments for iiop
   *
   * @param iiopOpts additional arguments for iiop
   */
  public void setIiopopts(String iiopOpts) {
    this.iiopOpts = iiopOpts;
  }

  /**
   * Gets additional arguments for iiop.
   *
   * @return iiopOpts
   */
  public String getIiopopts() {
    return iiopOpts;
  }

  /**
   * Indicates that IDL output should be generated. This defaults to false if not set.
   *
   * @param idl generate IDL output
   */
  public void setIdl(boolean idl) {
    this.idl = idl;
  }

  /**
   * Gets IDL flags.
   *
   * @return the idl flag
   */
  public boolean getIdl() {
    return idl;
  }

  /**
   * pass additional arguments for IDL compile
   *
   * @param idlOpts additional IDL arguments
   */
  public void setIdlopts(String idlOpts) {
    this.idlOpts = idlOpts;
  }

  /**
   * Gets additional arguments for idl compile.
   *
   * @return the idl options
   */
  public String getIdlopts() {
    return idlOpts;
  }

  /**
   * Gets file list to compile.
   *
   * @return the list of files to compile.
   */
  public Vector getFileList() {
    return compileList;
  }

  /**
   * Sets whether or not to include ant's own classpath in this task's classpath. Optional; default
   * is <code>true</code>.
   *
   * @param include if true include ant's classpath
   */
  public void setIncludeantruntime(boolean include) {
    includeAntRuntime = include;
  }

  /**
   * Gets whether or not the ant classpath is to be included in the task's classpath.
   *
   * @return true if ant's classpath is to be included
   */
  public boolean getIncludeantruntime() {
    return includeAntRuntime;
  }

  /**
   * task's classpath. Enables or disables including the default run-time libraries from the
   * executing VM; optional, defaults to false
   *
   * @param include if true include default run-time libraries
   */
  public void setIncludejavaruntime(boolean include) {
    includeJavaRuntime = include;
  }

  /**
   * Gets whether or not the java runtime should be included in this task's classpath.
   *
   * @return true if default run-time libraries are included
   */
  public boolean getIncludejavaruntime() {
    return includeJavaRuntime;
  }

  /**
   * Sets the extension directories that will be used during the compilation; optional.
   *
   * @param extDirs the extension directories to be used
   */
  public synchronized void setExtdirs(Path extDirs) {
    if (this.extDirs == null) {
      this.extDirs = extDirs;
    } else {
      this.extDirs.append(extDirs);
    }
  }

  /**
   * Maybe creates a nested extdirs element.
   *
   * @return path object to be configured with the extension directories
   */
  public synchronized Path createExtdirs() {
    if (extDirs == null) {
      extDirs = new Path(getProject());
    }
    return extDirs.createPath();
  }

  /**
   * Gets the extension directories that will be used during the compilation.
   *
   * @return the extension directories to be used
   */
  public Path getExtdirs() {
    return extDirs;
  }

  /** @return the compile list. */
  public Vector getCompileList() {
    return compileList;
  }

  /**
   * Sets the compiler implementation to use; optional, defaults to the value of the <code>
   * build.rmic</code> property, or failing that, default compiler for the current VM
   *
   * @param compiler the compiler implementation to use
   * @since Ant 1.5
   */
  public void setCompiler(String compiler) {
    if (compiler.length() > 0) {
      facade.setImplementation(compiler);
    }
  }

  /**
   * get the name of the current compiler
   *
   * @return the name of the compiler
   * @since Ant 1.5
   */
  public String getCompiler() {
    facade.setMagicValue(getProject().getProperty("build.rmic"));
    return facade.getImplementation();
  }

  /**
   * Adds an implementation specific command line argument.
   *
   * @return an object to be configured with a command line argument
   * @since Ant 1.5
   */
  public ImplementationSpecificArgument createCompilerArg() {
    ImplementationSpecificArgument arg = new ImplementationSpecificArgument();
    facade.addImplementationArgument(arg);
    return arg;
  }

  /**
   * Get the additional implementation specific command line arguments.
   *
   * @return array of command line arguments, guaranteed to be non-null.
   * @since Ant 1.5
   */
  public String[] getCurrentCompilerArgs() {
    getCompiler();
    return facade.getArgs();
  }

  /**
   * Name of the executable to use when forking.
   *
   * @since Ant 1.8.0
   */
  public void setExecutable(String ex) {
    executable = ex;
  }

  /**
   * Explicitly specified name of the executable to use when forking - if any.
   *
   * @since Ant 1.8.0
   */
  public String getExecutable() {
    return executable;
  }

  /**
   * The classpath to use when loading the compiler implementation if it is not a built-in one.
   *
   * @since Ant 1.8.0
   */
  public Path createCompilerClasspath() {
    return facade.getImplementationClasspath(getProject());
  }

  /**
   * If true, list the source files being handed off to the compiler.
   *
   * @param list if true list the source files
   * @since Ant 1.8.0
   */
  public void setListfiles(boolean list) {
    listFiles = list;
  }

  /**
   * Set the compiler adapter explicitly.
   *
   * @since Ant 1.8.0
   */
  public void add(RmicAdapter adapter) {
    if (nestedAdapter != null) {
      throw new BuildException("Can't have more than one rmic adapter");
    }
    nestedAdapter = adapter;
  }

  /**
   * execute by creating an instance of an implementation class and getting to do the work
   *
   * @throws org.apache.tools.ant.BuildException if there's a problem with baseDir or RMIC
   */
  @Override
  public void execute() throws BuildException {
    try {
      compileList.clear();

      File outputDir = getOutputDir();
      if (outputDir == null) {
        throw new BuildException(ERROR_BASE_NOT_SET, getLocation());
      }
      if (!outputDir.exists()) {
        throw new BuildException(ERROR_NO_BASE_EXISTS + outputDir, getLocation());
      }
      if (!outputDir.isDirectory()) {
        throw new BuildException(ERROR_NOT_A_DIR + outputDir, getLocation());
      }
      if (verify) {
        log("Verify has been turned on.", Project.MSG_VERBOSE);
      }
      RmicAdapter adapter =
          nestedAdapter != null
              ? nestedAdapter
              : RmicAdapterFactory.getRmic(getCompiler(), this, createCompilerClasspath());

      // now we need to populate the compiler adapter
      adapter.setRmic(this);

      Path classpath = adapter.getClasspath();
      loader = getProject().createClassLoader(classpath);

      // scan base dirs to build up compile lists only if a
      // specific classname is not given
      if (classname == null) {
        DirectoryScanner ds = this.getDirectoryScanner(baseDir);
        String[] files = ds.getIncludedFiles();
        scanDir(baseDir, files, adapter.getMapper());
      } else {
        // otherwise perform a timestamp comparison - at least
        String path = classname.replace('.', File.separatorChar) + ".class";
        File f = new File(baseDir, path);
        if (f.isFile()) {
          scanDir(baseDir, new String[] {path}, adapter.getMapper());
        } else {
          // Does not exist, so checking whether it is up to
          // date makes no sense.  Compilation will fail
          // later anyway, but tests expect a certain
          // output.
          compileList.add(classname);
        }
      }
      int fileCount = compileList.size();
      if (fileCount > 0) {
        log(
            "RMI Compiling "
                + fileCount
                + " class"
                + (fileCount > 1 ? "es" : "")
                + " to "
                + outputDir,
            Project.MSG_INFO);

        if (listFiles) {
          for (int i = 0; i < fileCount; i++) {
            log(compileList.get(i).toString());
          }
        }

        // finally, lets execute the compiler!!
        if (!adapter.execute()) {
          throw new BuildException(ERROR_RMIC_FAILED, getLocation());
        }
      }
      /*
       * Move the generated source file to the base directory.  If
       * base directory and sourcebase are the same, the generated
       * sources are already in place.
       */
      if (null != sourceBase && !outputDir.equals(sourceBase) && fileCount > 0) {
        if (idl) {
          log("Cannot determine sourcefiles in idl mode, ", Project.MSG_WARN);
          log("sourcebase attribute will be ignored.", Project.MSG_WARN);
        } else {
          for (int j = 0; j < fileCount; j++) {
            moveGeneratedFile(outputDir, sourceBase, (String) compileList.elementAt(j), adapter);
          }
        }
      }
    } finally {
      cleanup();
    }
  }

  /**
   * Cleans up resources.
   *
   * @since Ant 1.8.0
   */
  protected void cleanup() {
    if (loader != null) {
      loader.cleanup();
      loader = null;
    }
  }

  /**
   * Move the generated source file(s) to the base directory
   *
   * @throws org.apache.tools.ant.BuildException When error copying/removing files.
   */
  private void moveGeneratedFile(
      File baseDir, File sourceBaseFile, String classname, RmicAdapter adapter)
      throws BuildException {
    String classFileName = classname.replace('.', File.separatorChar) + ".class";
    String[] generatedFiles = adapter.getMapper().mapFileName(classFileName);

    for (int i = 0; i < generatedFiles.length; i++) {
      final String generatedFile = generatedFiles[i];
      if (!generatedFile.endsWith(".class")) {
        // don't know how to handle that - a IDL file doesn't
        // have a corresponding Java source for example.
        continue;
      }
      String sourceFileName = StringUtils.removeSuffix(generatedFile, ".class") + ".java";

      File oldFile = new File(baseDir, sourceFileName);
      if (!oldFile.exists()) {
        // no source file generated, nothing to move
        continue;
      }

      File newFile = new File(sourceBaseFile, sourceFileName);
      try {
        if (filtering) {
          FILE_UTILS.copyFile(
              oldFile, newFile, new FilterSetCollection(getProject().getGlobalFilterSet()));
        } else {
          FILE_UTILS.copyFile(oldFile, newFile);
        }
        oldFile.delete();
      } catch (IOException ioe) {
        String msg = "Failed to copy " + oldFile + " to " + newFile + " due to " + ioe.getMessage();
        throw new BuildException(msg, ioe, getLocation());
      }
    }
  }

  /**
   * Scans the directory looking for class files to be compiled. The result is returned in the class
   * variable compileList.
   *
   * @param baseDir the base direction
   * @param files the list of files to scan
   * @param mapper the mapper of files to target files
   */
  protected void scanDir(File baseDir, String[] files, FileNameMapper mapper) {
    String[] newFiles = files;
    if (idl) {
      log("will leave uptodate test to rmic implementation in idl mode.", Project.MSG_VERBOSE);
    } else if (iiop && iiopOpts != null && iiopOpts.indexOf("-always") > -1) {
      log("no uptodate test as -always option has been specified", Project.MSG_VERBOSE);
    } else {
      SourceFileScanner sfs = new SourceFileScanner(this);
      newFiles = sfs.restrict(files, baseDir, getOutputDir(), mapper);
    }
    for (int i = 0; i < newFiles.length; i++) {
      String name = newFiles[i].replace(File.separatorChar, '.');
      name = name.substring(0, name.lastIndexOf(".class"));
      compileList.addElement(name);
    }
  }

  /**
   * Load named class and test whether it can be rmic'ed
   *
   * @param classname the name of the class to be tested
   * @return true if the class can be rmic'ed
   */
  public boolean isValidRmiRemote(String classname) {
    try {
      Class testClass = loader.loadClass(classname);
      // One cannot RMIC an interface for "classic" RMI (JRMP)
      if (testClass.isInterface() && !iiop && !idl) {
        return false;
      }
      return isValidRmiRemote(testClass);
    } catch (ClassNotFoundException e) {
      log(ERROR_UNABLE_TO_VERIFY_CLASS + classname + ERROR_NOT_FOUND, Project.MSG_WARN);
    } catch (NoClassDefFoundError e) {
      log(ERROR_UNABLE_TO_VERIFY_CLASS + classname + ERROR_NOT_DEFINED, Project.MSG_WARN);
    } catch (Throwable t) {
      log(
          ERROR_UNABLE_TO_VERIFY_CLASS
              + classname
              + ERROR_LOADING_CAUSED_EXCEPTION
              + t.getMessage(),
          Project.MSG_WARN);
    }
    // we only get here if an exception has been thrown
    return false;
  }

  /**
   * Returns the topmost interface that extends Remote for a given class - if one exists.
   *
   * @param testClass the class to be tested
   * @return the topmost interface that extends Remote, or null if there is none.
   */
  public Class getRemoteInterface(Class testClass) {
    if (Remote.class.isAssignableFrom(testClass)) {
      Class[] interfaces = testClass.getInterfaces();
      if (interfaces != null) {
        for (int i = 0; i < interfaces.length; i++) {
          if (Remote.class.isAssignableFrom(interfaces[i])) {
            return interfaces[i];
          }
        }
      }
    }
    return null;
  }

  /** Check to see if the class or (super)interfaces implement java.rmi.Remote. */
  private boolean isValidRmiRemote(Class testClass) {
    return getRemoteInterface(testClass) != null;
  }

  /**
   * Classloader for the user-specified classpath.
   *
   * @return the classloader
   */
  public ClassLoader getLoader() {
    return loader;
  }

  /**
   * Adds an "compiler" attribute to Commandline$Attribute used to filter command line attributes
   * based on the current implementation.
   */
  public class ImplementationSpecificArgument
      extends org.apache.tools.ant.util.facade.ImplementationSpecificArgument {
    /**
     * Only pass the specified argument if the chosen compiler implementation matches the value of
     * this attribute. Legal values are the same as those in the above list of valid compilers.)
     *
     * @param impl the compiler to be used.
     */
    public void setCompiler(String impl) {
      super.setImplementation(impl);
    }
  }
}
Пример #13
0
/** Invokes the ANTLR Translator generator on a grammar file. */
public class ANTLR extends Task {

  private CommandlineJava commandline = new CommandlineJava();

  /** the file to process */
  private File targetFile;

  /** where to output the result */
  private File outputDirectory;

  /** an optional super grammar file */
  private File superGrammar;

  /** optional flag to enable html output */
  private boolean html;

  /** optional flag to print out a diagnostic file */
  private boolean diagnostic;

  /** optional flag to add trace methods */
  private boolean trace;

  /** optional flag to add trace methods to the parser only */
  private boolean traceParser;

  /** optional flag to add trace methods to the lexer only */
  private boolean traceLexer;

  /** optional flag to add trace methods to the tree walker only */
  private boolean traceTreeWalker;

  /** working directory */
  private File workingdir = null;

  /** captures ANTLR's output */
  private ByteArrayOutputStream bos = new ByteArrayOutputStream();

  /** The debug attribute */
  private boolean debug;

  /** Instance of a utility class to use for file operations. */
  private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();

  /** Constructor for ANTLR task. */
  public ANTLR() {
    commandline.setVm(JavaEnvUtils.getJreExecutable("java"));
    commandline.setClassname("antlr.Tool");
  }

  /**
   * The grammar file to process.
   *
   * @param target the gramer file
   */
  public void setTarget(File target) {
    log("Setting target to: " + target.toString(), Project.MSG_VERBOSE);
    this.targetFile = target;
  }

  /**
   * The directory to write the generated files to.
   *
   * @param outputDirectory the output directory
   */
  public void setOutputdirectory(File outputDirectory) {
    log("Setting output directory to: " + outputDirectory.toString(), Project.MSG_VERBOSE);
    this.outputDirectory = outputDirectory;
  }

  /**
   * Sets an optional super grammar file. Use setGlib(File superGrammar) instead.
   *
   * @param superGrammar the super grammar filename
   * @deprecated since ant 1.6
   */
  public void setGlib(String superGrammar) {
    String sg = null;
    if (Os.isFamily("dos")) {
      sg = superGrammar.replace('\\', '/');
    } else {
      sg = superGrammar;
    }
    setGlib(FILE_UTILS.resolveFile(getProject().getBaseDir(), sg));
  }
  /**
   * Sets an optional super grammar file
   *
   * @param superGrammar the super grammar file
   * @since ant 1.6
   */
  public void setGlib(File superGrammar) {
    this.superGrammar = superGrammar;
  }
  /**
   * Sets a flag to enable ParseView debugging
   *
   * @param enable a <code>boolean</code> value
   */
  public void setDebug(boolean enable) {
    this.debug = enable;
  }

  /**
   * If true, emit html
   *
   * @param enable a <code>boolean</code> value
   */
  public void setHtml(boolean enable) {
    html = enable;
  }

  /**
   * Sets a flag to emit diagnostic text
   *
   * @param enable a <code>boolean</code> value
   */
  public void setDiagnostic(boolean enable) {
    diagnostic = enable;
  }

  /**
   * If true, enables all tracing.
   *
   * @param enable a <code>boolean</code> value
   */
  public void setTrace(boolean enable) {
    trace = enable;
  }

  /**
   * If true, enables parser tracing.
   *
   * @param enable a <code>boolean</code> value
   */
  public void setTraceParser(boolean enable) {
    traceParser = enable;
  }

  /**
   * If true, enables lexer tracing.
   *
   * @param enable a <code>boolean</code> value
   */
  public void setTraceLexer(boolean enable) {
    traceLexer = enable;
  }

  /**
   * Sets a flag to allow the user to enable tree walker tracing
   *
   * @param enable a <code>boolean</code> value
   */
  public void setTraceTreeWalker(boolean enable) {
    traceTreeWalker = enable;
  }

  // we are forced to fork ANTLR since there is a call
  // to System.exit() and there is nothing we can do
  // right now to avoid this. :-( (SBa)
  // I'm not removing this method to keep backward compatibility
  /**
   * @ant.attribute ignore="true"
   * @param s a <code>boolean</code> value
   */
  public void setFork(boolean s) {
    // this.fork = s;
  }

  /**
   * The working directory of the process
   *
   * @param d the working directory
   */
  public void setDir(File d) {
    this.workingdir = d;
  }

  /**
   * Adds a classpath to be set because a directory might be given for Antlr debug.
   *
   * @return a path to be configured
   */
  public Path createClasspath() {
    return commandline.createClasspath(getProject()).createPath();
  }

  /**
   * Adds a new JVM argument.
   *
   * @return create a new JVM argument so that any argument can be passed to the JVM.
   * @see #setFork(boolean)
   */
  public Commandline.Argument createJvmarg() {
    return commandline.createVmArgument();
  }

  /**
   * Adds the jars or directories containing Antlr this should make the forked JVM work without
   * having to specify it directly.
   *
   * @throws BuildException on error
   */
  public void init() throws BuildException {
    addClasspathEntry("/antlr/ANTLRGrammarParseBehavior.class");
  }

  /**
   * Search for the given resource and add the directory or archive that contains it to the
   * classpath.
   *
   * <p>Doesn't work for archives in JDK 1.1 as the URL returned by getResource doesn't contain the
   * name of the archive.
   *
   * @param resource the resource name to search for
   */
  protected void addClasspathEntry(String resource) {
    /*
     * pre Ant 1.6 this method used to call getClass().getResource
     * while Ant 1.6 will call ClassLoader.getResource().
     *
     * The difference is that Class.getResource expects a leading
     * slash for "absolute" resources and will strip it before
     * delegating to ClassLoader.getResource - so we now have to
     * emulate Class's behavior.
     */
    if (resource.startsWith("/")) {
      resource = resource.substring(1);
    } else {
      resource = "org/apache/tools/ant/taskdefs/optional/" + resource;
    }

    File f = LoaderUtils.getResourceSource(getClass().getClassLoader(), resource);
    if (f != null) {
      log("Found " + f.getAbsolutePath(), Project.MSG_DEBUG);
      createClasspath().setLocation(f);
    } else {
      log("Couldn\'t find " + resource, Project.MSG_VERBOSE);
    }
  }

  /**
   * Execute the task.
   *
   * @throws BuildException on error
   */
  public void execute() throws BuildException {
    validateAttributes();

    // TODO: use ANTLR to parse the grammar file to do this.
    File generatedFile = getGeneratedFile();
    boolean targetIsOutOfDate = targetFile.lastModified() > generatedFile.lastModified();
    boolean superGrammarIsOutOfDate =
        superGrammar != null && (superGrammar.lastModified() > generatedFile.lastModified());
    if (targetIsOutOfDate || superGrammarIsOutOfDate) {
      if (targetIsOutOfDate) {
        log(
            "Compiling " + targetFile + " as it is newer than " + generatedFile,
            Project.MSG_VERBOSE);
      } else {
        log(
            "Compiling " + targetFile + " as " + superGrammar + " is newer than " + generatedFile,
            Project.MSG_VERBOSE);
      }
      populateAttributes();
      commandline.createArgument().setValue(targetFile.toString());

      log(commandline.describeCommand(), Project.MSG_VERBOSE);
      int err = run(commandline.getCommandline());
      if (err != 0) {
        throw new BuildException("ANTLR returned: " + err, getLocation());
      } else {
        String output = bos.toString();
        if (output.indexOf("error:") > -1) {
          throw new BuildException("ANTLR signaled an error: " + output, getLocation());
        }
      }
    } else {
      log(
          "Skipped grammar file. Generated file " + generatedFile + " is newer.",
          Project.MSG_VERBOSE);
    }
  }

  /**
   * A refactored method for populating all the command line arguments based on the user-specified
   * attributes.
   */
  private void populateAttributes() {
    commandline.createArgument().setValue("-o");
    commandline.createArgument().setValue(outputDirectory.toString());
    if (superGrammar != null) {
      commandline.createArgument().setValue("-glib");
      commandline.createArgument().setValue(superGrammar.toString());
    }
    if (html) {
      commandline.createArgument().setValue("-html");
    }
    if (diagnostic) {
      commandline.createArgument().setValue("-diagnostic");
    }
    if (trace) {
      commandline.createArgument().setValue("-trace");
    }
    if (traceParser) {
      commandline.createArgument().setValue("-traceParser");
    }
    if (traceLexer) {
      commandline.createArgument().setValue("-traceLexer");
    }
    if (traceTreeWalker) {
      if (is272()) {
        commandline.createArgument().setValue("-traceTreeParser");
      } else {
        commandline.createArgument().setValue("-traceTreeWalker");
      }
    }
    if (debug) {
      commandline.createArgument().setValue("-debug");
    }
  }

  private void validateAttributes() throws BuildException {
    if (targetFile == null || !targetFile.isFile()) {
      throw new BuildException("Invalid target: " + targetFile);
    }

    // if no output directory is specified, used the target's directory
    if (outputDirectory == null) {
      setOutputdirectory(new File(targetFile.getParent()));
    }
    if (!outputDirectory.isDirectory()) {
      throw new BuildException("Invalid output directory: " + outputDirectory);
    }
  }

  private File getGeneratedFile() throws BuildException {
    String generatedFileName = null;
    try {
      BufferedReader in = new BufferedReader(new FileReader(targetFile));
      String line;
      while ((line = in.readLine()) != null) {
        int extendsIndex = line.indexOf(" extends ");
        if (line.startsWith("class ") && extendsIndex > -1) {
          generatedFileName = line.substring("class ".length(), extendsIndex).trim();
          break;
        }
      }
      in.close();
    } catch (Exception e) {
      throw new BuildException("Unable to determine generated class", e);
    }
    if (generatedFileName == null) {
      throw new BuildException("Unable to determine generated class");
    }
    return new File(outputDirectory, generatedFileName + (html ? ".html" : ".java"));
  }

  /** execute in a forked VM */
  private int run(String[] command) throws BuildException {
    PumpStreamHandler psh =
        new PumpStreamHandler(
            new LogOutputStream(this, Project.MSG_INFO),
            new TeeOutputStream(new LogOutputStream(this, Project.MSG_WARN), bos));
    Execute exe = new Execute(psh, null);
    exe.setAntRun(getProject());
    if (workingdir != null) {
      exe.setWorkingDirectory(workingdir);
    }
    exe.setCommandline(command);
    try {
      return exe.execute();
    } catch (IOException e) {
      throw new BuildException(e, getLocation());
    } finally {
      FileUtils.close(bos);
    }
  }

  /**
   * Whether the antlr version is 2.7.2 (or higher).
   *
   * @return true if the version of Antlr present is 2.7.2 or later.
   * @since Ant 1.6
   */
  protected boolean is272() {
    AntClassLoader l = null;
    try {
      l = getProject().createClassLoader(commandline.getClasspath());
      l.loadClass("antlr.Version");
      return true;
    } catch (ClassNotFoundException e) {
      return false;
    } finally {
      if (l != null) {
        l.cleanup();
      }
    }
  }
}
Пример #14
0
/** Create a CAB archive. */
public class Cab extends MatchingTask {
  private static final int DEFAULT_RESULT = -99;
  private File cabFile;
  private File baseDir;
  private Vector filesets = new Vector();
  private boolean doCompress = true;
  private boolean doVerbose = false;
  private String cmdOptions;

  // CheckStyle:VisibilityModifier OFF - bc
  protected String archiveType = "cab";
  // CheckStyle:VisibilityModifier ON

  private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();

  /**
   * The name/location of where to create the .cab file.
   *
   * @param cabFile the location of the cab file.
   */
  public void setCabfile(File cabFile) {
    this.cabFile = cabFile;
  }

  /**
   * Base directory to look in for files to CAB.
   *
   * @param baseDir base directory for files to cab.
   */
  public void setBasedir(File baseDir) {
    this.baseDir = baseDir;
  }

  /**
   * If true, compress the files otherwise only store them.
   *
   * @param compress a <code>boolean</code> value.
   */
  public void setCompress(boolean compress) {
    doCompress = compress;
  }

  /**
   * If true, display cabarc output.
   *
   * @param verbose a <code>boolean</code> value.
   */
  public void setVerbose(boolean verbose) {
    doVerbose = verbose;
  }

  /**
   * Sets additional cabarc options that are not supported directly.
   *
   * @param options cabarc command line options.
   */
  public void setOptions(String options) {
    cmdOptions = options;
  }

  /**
   * Adds a set of files to archive.
   *
   * @param set a set of files to archive.
   */
  public void addFileset(FileSet set) {
    if (filesets.size() > 0) {
      throw new BuildException("Only one nested fileset allowed");
    }
    filesets.addElement(set);
  }

  /*
   * I'm not fond of this pattern: "sub-method expected to throw
   * task-cancelling exceptions".  It feels too much like programming
   * for side-effects to me...
   */
  /**
   * Check if the attributes and nested elements are correct.
   *
   * @throws BuildException on error.
   */
  protected void checkConfiguration() throws BuildException {
    if (baseDir == null && filesets.size() == 0) {
      throw new BuildException(
          "basedir attribute or one " + "nested fileset is required!", getLocation());
    }
    if (baseDir != null && !baseDir.exists()) {
      throw new BuildException("basedir does not exist!", getLocation());
    }
    if (baseDir != null && filesets.size() > 0) {
      throw new BuildException("Both basedir attribute and a nested fileset is not allowed");
    }
    if (cabFile == null) {
      throw new BuildException("cabfile attribute must be set!", getLocation());
    }
  }

  /**
   * Create a new exec delegate. The delegate task is populated so that it appears in the logs to be
   * the same task as this one.
   *
   * @return the delegate.
   * @throws BuildException on error.
   */
  protected ExecTask createExec() throws BuildException {
    ExecTask exec = new ExecTask(this);
    return exec;
  }

  /**
   * Check to see if the target is up to date with respect to input files.
   *
   * @param files the list of files to check.
   * @return true if the cab file is newer than its dependents.
   */
  protected boolean isUpToDate(Vector files) {
    boolean upToDate = true;
    final int size = files.size();
    for (int i = 0; i < size && upToDate; i++) {
      String file = files.elementAt(i).toString();
      if (FILE_UTILS.resolveFile(baseDir, file).lastModified() > cabFile.lastModified()) {
        upToDate = false;
      }
    }
    return upToDate;
  }

  /**
   * Creates a list file. This temporary file contains a list of all files to be included in the
   * cab, one file per line.
   *
   * <p>This method expects to only be called on Windows and thus quotes the file names.
   *
   * @param files the list of files to use.
   * @return the list file created.
   * @throws IOException if there is an error.
   */
  protected File createListFile(Vector files) throws IOException {
    File listFile = FILE_UTILS.createTempFile("ant", "", null, true, true);

    BufferedWriter writer = null;
    try {
      writer = new BufferedWriter(new FileWriter(listFile));

      final int size = files.size();
      for (int i = 0; i < size; i++) {
        writer.write('\"' + files.elementAt(i).toString() + '\"');
        writer.newLine();
      }
    } finally {
      FileUtils.close(writer);
    }

    return listFile;
  }

  /**
   * Append all files found by a directory scanner to a vector.
   *
   * @param files the vector to append the files to.
   * @param ds the scanner to get the files from.
   */
  protected void appendFiles(Vector files, DirectoryScanner ds) {
    String[] dsfiles = ds.getIncludedFiles();

    for (int i = 0; i < dsfiles.length; i++) {
      files.addElement(dsfiles[i]);
    }
  }

  /**
   * Get the complete list of files to be included in the cab. Filenames are gathered from the
   * fileset if it has been added, otherwise from the traditional include parameters.
   *
   * @return the list of files.
   * @throws BuildException if there is an error.
   */
  protected Vector getFileList() throws BuildException {
    Vector files = new Vector();

    if (baseDir != null) {
      // get files from old methods - includes and nested include
      appendFiles(files, super.getDirectoryScanner(baseDir));
    } else {
      FileSet fs = (FileSet) filesets.elementAt(0);
      baseDir = fs.getDir();
      appendFiles(files, fs.getDirectoryScanner(getProject()));
    }

    return files;
  }

  /**
   * execute this task.
   *
   * @throws BuildException on error.
   */
  public void execute() throws BuildException {

    checkConfiguration();

    Vector files = getFileList();

    // quick exit if the target is up to date
    if (isUpToDate(files)) {
      return;
    }

    log("Building " + archiveType + ": " + cabFile.getAbsolutePath());

    if (!Os.isFamily("windows")) {
      log("Using listcab/libcabinet", Project.MSG_VERBOSE);

      StringBuffer sb = new StringBuffer();

      Enumeration fileEnum = files.elements();

      while (fileEnum.hasMoreElements()) {
        sb.append(fileEnum.nextElement()).append("\n");
      }
      sb.append("\n").append(cabFile.getAbsolutePath()).append("\n");

      try {
        Process p =
            Execute.launch(
                getProject(),
                new String[] {"listcab"},
                null,
                baseDir != null ? baseDir : getProject().getBaseDir(),
                true);
        OutputStream out = p.getOutputStream();

        // Create the stream pumpers to forward listcab's stdout and stderr to the log
        // note: listcab is an interactive program, and issues prompts for every new line.
        //       Therefore, make it show only with verbose logging turned on.
        LogOutputStream outLog = new LogOutputStream(this, Project.MSG_VERBOSE);
        LogOutputStream errLog = new LogOutputStream(this, Project.MSG_ERR);
        StreamPumper outPump = new StreamPumper(p.getInputStream(), outLog);
        StreamPumper errPump = new StreamPumper(p.getErrorStream(), errLog);

        // Pump streams asynchronously
        (new Thread(outPump)).start();
        (new Thread(errPump)).start();

        out.write(sb.toString().getBytes());
        out.flush();
        out.close();

        // A wild default for when the thread is interrupted
        int result = DEFAULT_RESULT;

        try {
          // Wait for the process to finish
          result = p.waitFor();

          // Wait for the end of output and error streams
          outPump.waitFor();
          outLog.close();
          errPump.waitFor();
          errLog.close();
        } catch (InterruptedException ie) {
          log("Thread interrupted: " + ie);
        }

        // Informative summary message in case of errors
        if (Execute.isFailure(result)) {
          log("Error executing listcab; error code: " + result);
        }
      } catch (IOException ex) {
        String msg = "Problem creating " + cabFile + " " + ex.getMessage();
        throw new BuildException(msg, getLocation());
      }
    } else {
      try {
        File listFile = createListFile(files);
        ExecTask exec = createExec();
        File outFile = null;

        // die if cabarc fails
        exec.setFailonerror(true);
        exec.setDir(baseDir);

        if (!doVerbose) {
          outFile = FILE_UTILS.createTempFile("ant", "", null, true, true);
          exec.setOutput(outFile);
        }

        exec.setExecutable("cabarc");
        exec.createArg().setValue("-r");
        exec.createArg().setValue("-p");

        if (!doCompress) {
          exec.createArg().setValue("-m");
          exec.createArg().setValue("none");
        }

        if (cmdOptions != null) {
          exec.createArg().setLine(cmdOptions);
        }

        exec.createArg().setValue("n");
        exec.createArg().setFile(cabFile);
        exec.createArg().setValue("@" + listFile.getAbsolutePath());

        exec.execute();

        if (outFile != null) {
          outFile.delete();
        }

        listFile.delete();
      } catch (IOException ioe) {
        String msg = "Problem creating " + cabFile + " " + ioe.getMessage();
        throw new BuildException(msg, getLocation());
      }
    }
  }
}
/** Sax2 based project reader */
public class ProjectHelper2 extends ProjectHelper {

  /** Reference holding the (ordered) target Vector */
  public static final String REFID_TARGETS = "ant.targets";

  /* Stateless */

  // singletons - since all state is in the context
  private static AntHandler elementHandler = new ElementHandler();
  private static AntHandler targetHandler = new TargetHandler();
  private static AntHandler mainHandler = new MainHandler();
  private static AntHandler projectHandler = new ProjectHandler();

  /** Specific to ProjectHelper2 so not a true Ant "magic name:" */
  private static final String REFID_CONTEXT = "ant.parsing.context";

  /** helper for path -> URI and URI -> path conversions. */
  private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();

  /**
   * Whether this instance of ProjectHelper can parse an Antlib descriptor given by the URL and
   * return its content as an UnknownElement ready to be turned into an Antlib task.
   *
   * <p>This implementation returns true.
   *
   * @since Ant 1.8.0
   */
  public boolean canParseAntlibDescriptor(Resource resource) {
    return true;
  }

  /**
   * Parse the given URL as an antlib descriptor an return the content as something that can be
   * turned into an Antlib task.
   *
   * <p>simply delegates to {@link #parseUnknownElement parseUnknownElement} if the resource
   * provides an URL and throws an exceptipn otherwise.
   *
   * @since Ant 1.8.0
   */
  public UnknownElement parseAntlibDescriptor(Project containingProject, Resource resource) {
    URLProvider up = (URLProvider) resource.as(URLProvider.class);
    if (up == null) {
      throw new BuildException("Unsupported resource type: " + resource);
    }
    return parseUnknownElement(containingProject, up.getURL());
  }

  /**
   * Parse an unknown element from a url
   *
   * @param project the current project
   * @param source the url containing the task
   * @return a configured task
   * @exception BuildException if an error occurs
   */
  public UnknownElement parseUnknownElement(Project project, URL source) throws BuildException {
    Target dummyTarget = new Target();
    dummyTarget.setProject(project);

    AntXMLContext context = new AntXMLContext(project);
    context.addTarget(dummyTarget);
    context.setImplicitTarget(dummyTarget);

    parse(context.getProject(), source, new RootHandler(context, elementHandler));
    Task[] tasks = dummyTarget.getTasks();
    if (tasks.length != 1) {
      throw new BuildException("No tasks defined");
    }
    return (UnknownElement) tasks[0];
  }

  /**
   * Parse a source xml input.
   *
   * @param project the current project
   * @param source the xml source
   * @exception BuildException if an error occurs
   */
  public void parse(Project project, Object source) throws BuildException {
    getImportStack().addElement(source);
    AntXMLContext context = null;
    context = (AntXMLContext) project.getReference(REFID_CONTEXT);
    if (context == null) {
      context = new AntXMLContext(project);
      project.addReference(REFID_CONTEXT, context);
      project.addReference(REFID_TARGETS, context.getTargets());
    }
    if (getImportStack().size() > 1) {
      // we are in an imported file.
      context.setIgnoreProjectTag(true);
      Target currentTarget = context.getCurrentTarget();
      Target currentImplicit = context.getImplicitTarget();
      Map 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);
        }
      }
    }
  }

  /**
   * 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);
    }
  }

  /**
   * Returns main handler
   *
   * @return main handler
   */
  protected static AntHandler getMainHandler() {
    return mainHandler;
  }

  /**
   * Sets main handler
   *
   * @param handler new main handler
   */
  protected static void setMainHandler(AntHandler handler) {
    mainHandler = handler;
  }

  /**
   * Returns project handler
   *
   * @return project handler
   */
  protected static AntHandler getProjectHandler() {
    return projectHandler;
  }

  /**
   * Sets project handler
   *
   * @param handler new project handler
   */
  protected static void setProjectHandler(AntHandler handler) {
    projectHandler = handler;
  }

  /**
   * Returns target handler
   *
   * @return target handler
   */
  protected static AntHandler getTargetHandler() {
    return targetHandler;
  }

  /**
   * Sets target handler
   *
   * @param handler new target handler
   */
  protected static void setTargetHandler(AntHandler handler) {
    targetHandler = handler;
  }

  /**
   * Returns element handler
   *
   * @return element handler
   */
  protected static AntHandler getElementHandler() {
    return elementHandler;
  }

  /**
   * Sets element handler
   *
   * @param handler new element handler
   */
  protected static void setElementHandler(AntHandler handler) {
    elementHandler = handler;
  }

  /**
   * The common superclass for all SAX event handlers used to parse the configuration file.
   *
   * <p>The context will hold all state information. At each time there is one active handler for
   * the current element. It can use onStartChild() to set an alternate handler for the child.
   */
  public static class AntHandler {
    /**
     * Handles the start of an element. This base implementation does nothing.
     *
     * @param uri the namespace URI for the tag
     * @param tag The name of the element being started. Will not be <code>null</code>.
     * @param qname The qualified name of the element.
     * @param attrs Attributes of the element being started. Will not be <code>null</code>.
     * @param context The context that this element is in.
     * @exception SAXParseException if this method is not overridden, or in case of error in an
     *     overridden version
     */
    public void onStartElement(
        String uri, String tag, String qname, Attributes attrs, AntXMLContext context)
        throws SAXParseException {}

    /**
     * Handles the start of an element. This base implementation just throws an exception - you must
     * override this method if you expect child elements.
     *
     * @param uri The namespace uri for this element.
     * @param tag The name of the element being started. Will not be <code>null</code>.
     * @param qname The qualified name for this element.
     * @param attrs Attributes of the element being started. Will not be <code>null</code>.
     * @param context The current context.
     * @return a handler (in the derived classes)
     * @exception SAXParseException if this method is not overridden, or in case of error in an
     *     overridden version
     */
    public AntHandler onStartChild(
        String uri, String tag, String qname, Attributes attrs, AntXMLContext context)
        throws SAXParseException {
      throw new SAXParseException("Unexpected element \"" + qname + " \"", context.getLocator());
    }

    /**
     * Handle the end of a element.
     *
     * @param uri the namespace uri of the element
     * @param tag the tag of the element
     * @param qname the qualified name of the element
     * @param context the current context
     * @exception SAXParseException if an error occurs
     */
    public void onEndChild(String uri, String tag, String qname, AntXMLContext context)
        throws SAXParseException {}

    /**
     * This method is called when this element and all elements nested into it have been handled.
     * I.e., this happens at the &lt;/end_tag_of_the_element&gt;.
     *
     * @param uri the namespace uri for this element
     * @param tag the element name
     * @param context the current context
     */
    public void onEndElement(String uri, String tag, AntXMLContext context) {}

    /**
     * Handles text within an element. This base implementation just throws an exception, you must
     * override it if you expect content.
     *
     * @param buf A character array of the text within the element. Will not be <code>null</code>.
     * @param start The start element in the array.
     * @param count The number of characters to read from the array.
     * @param context The current context.
     * @exception SAXParseException if this method is not overridden, or in case of error in an
     *     overridden version
     */
    public void characters(char[] buf, int start, int count, AntXMLContext context)
        throws SAXParseException {
      String s = new String(buf, start, count).trim();

      if (s.length() > 0) {
        throw new SAXParseException("Unexpected text \"" + s + "\"", context.getLocator());
      }
    }

    /**
     * Will be called every time a namespace is reached. It'll verify if the ns was processed, and
     * if not load the task definitions.
     *
     * @param uri The namespace uri.
     */
    protected void checkNamespace(String uri) {}
  }

  /**
   * Handler for ant processing. Uses a stack of AntHandlers to implement each element ( the
   * original parser used a recursive behavior, with the implicit execution stack )
   */
  public static class RootHandler extends DefaultHandler {
    private Stack antHandlers = new Stack();
    private AntHandler currentHandler = null;
    private AntXMLContext context;

    /**
     * Creates a new RootHandler instance.
     *
     * @param context The context for the handler.
     * @param rootHandler The handler for the root element.
     */
    public RootHandler(AntXMLContext context, AntHandler rootHandler) {
      currentHandler = rootHandler;
      antHandlers.push(currentHandler);
      this.context = context;
    }

    /**
     * Returns the current ant handler object.
     *
     * @return the current ant handler.
     */
    public AntHandler getCurrentAntHandler() {
      return currentHandler;
    }

    /**
     * Resolves file: URIs relative to the build file.
     *
     * @param publicId The public identifier, or <code>null</code> if none is available. Ignored in
     *     this implementation.
     * @param systemId The system identifier provided in the XML document. Will not be <code>null
     *     </code>.
     * @return an inputsource for this identifier
     */
    public InputSource resolveEntity(String publicId, String systemId) {

      context.getProject().log("resolving systemId: " + systemId, Project.MSG_VERBOSE);

      if (systemId.startsWith("file:")) {
        String path = FILE_UTILS.fromURI(systemId);

        File file = new File(path);
        if (!file.isAbsolute()) {
          file = FILE_UTILS.resolveFile(context.getBuildFileParent(), path);
          context
              .getProject()
              .log(
                  "Warning: '"
                      + systemId
                      + "' in "
                      + context.getBuildFile()
                      + " should be expressed simply as '"
                      + path.replace('\\', '/')
                      + "' for compliance with other XML tools",
                  Project.MSG_WARN);
        }
        context.getProject().log("file=" + file, Project.MSG_DEBUG);
        try {
          InputSource inputSource = new InputSource(new FileInputStream(file));
          inputSource.setSystemId(FILE_UTILS.toURI(file.getAbsolutePath()));
          return inputSource;
        } catch (FileNotFoundException fne) {
          context
              .getProject()
              .log(file.getAbsolutePath() + " could not be found", Project.MSG_WARN);
        }
      }
      // use default if not file or file not found
      context.getProject().log("could not resolve systemId", Project.MSG_DEBUG);
      return null;
    }

    /**
     * Handles the start of a project element. A project handler is created and initialised with the
     * element name and attributes.
     *
     * @param uri The namespace uri for this element.
     * @param tag The name of the element being started. Will not be <code>null</code>.
     * @param qname The qualified name for this element.
     * @param attrs Attributes of the element being started. Will not be <code>null</code>.
     * @exception org.xml.sax.SAXParseException if the tag given is not <code>"project"</code>
     */
    public void startElement(String uri, String tag, String qname, Attributes attrs)
        throws SAXParseException {
      AntHandler next = currentHandler.onStartChild(uri, tag, qname, attrs, context);
      antHandlers.push(currentHandler);
      currentHandler = next;
      currentHandler.onStartElement(uri, tag, qname, attrs, context);
    }

    /**
     * Sets the locator in the project helper for future reference.
     *
     * @param locator The locator used by the parser. Will not be <code>null</code>.
     */
    public void setDocumentLocator(Locator locator) {
      context.setLocator(locator);
    }

    /**
     * Handles the end of an element. Any required clean-up is performed by the onEndElement()
     * method and then the original handler is restored to the parser.
     *
     * @param uri The namespace URI for this element.
     * @param name The name of the element which is ending. Will not be <code>null</code>.
     * @param qName The qualified name for this element.
     * @exception SAXException in case of error (not thrown in this implementation)
     */
    public void endElement(String uri, String name, String qName) throws SAXException {
      currentHandler.onEndElement(uri, name, context);
      AntHandler prev = (AntHandler) antHandlers.pop();
      currentHandler = prev;
      if (currentHandler != null) {
        currentHandler.onEndChild(uri, name, qName, context);
      }
    }

    /**
     * Handle text within an element, calls currentHandler.characters.
     *
     * @param buf A character array of the test.
     * @param start The start offset in the array.
     * @param count The number of characters to read.
     * @exception SAXParseException if an error occurs
     */
    public void characters(char[] buf, int start, int count) throws SAXParseException {
      currentHandler.characters(buf, start, count, context);
    }

    /**
     * Start a namespace prefix to uri mapping
     *
     * @param prefix the namespace prefix
     * @param uri the namespace uri
     */
    public void startPrefixMapping(String prefix, String uri) {
      context.startPrefixMapping(prefix, uri);
    }

    /**
     * End a namepace prefix to uri mapping
     *
     * @param prefix the prefix that is not mapped anymore
     */
    public void endPrefixMapping(String prefix) {
      context.endPrefixMapping(prefix);
    }
  }

  /**
   * The main handler - it handles the &lt;project&gt; tag.
   *
   * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler
   */
  public static class MainHandler extends AntHandler {

    /**
     * Handle the project tag
     *
     * @param uri The namespace uri.
     * @param name The element tag.
     * @param qname The element qualified name.
     * @param attrs The attributes of the element.
     * @param context The current context.
     * @return The project handler that handles subelements of project
     * @exception SAXParseException if the qualified name is not "project".
     */
    public AntHandler onStartChild(
        String uri, String name, String qname, Attributes attrs, AntXMLContext context)
        throws SAXParseException {
      if (name.equals("project") && (uri.equals("") || uri.equals(ANT_CORE_URI))) {
        return ProjectHelper2.projectHandler;
      }
      if (name.equals(qname)) {
        throw new SAXParseException(
            "Unexpected element \"{" + uri + "}" + name + "\" {" + ANT_CORE_URI + "}" + name,
            context.getLocator());
      }
      throw new SAXParseException(
          "Unexpected element \"" + qname + "\" " + name, context.getLocator());
    }
  }

  /** Handler for the top level "project" element. */
  public static class ProjectHandler extends AntHandler {

    /**
     * Initialisation routine called after handler creation with the element name and attributes.
     * The attributes which this handler can deal with are: <code>"default"</code>, <code>"name"
     * </code>, <code>"id"</code> and <code>"basedir"</code>.
     *
     * @param uri The namespace URI for this element.
     * @param tag Name of the element which caused this handler to be created. Should not be <code>
     *     null</code>. Ignored in this implementation.
     * @param qname The qualified name for this element.
     * @param attrs Attributes of the element which caused this handler to be created. Must not be
     *     <code>null</code>.
     * @param context The current context.
     * @exception SAXParseException if an unexpected attribute is encountered or if the <code>
     *     "default"</code> attribute is missing.
     */
    public void onStartElement(
        String uri, String tag, String qname, Attributes attrs, AntXMLContext context)
        throws SAXParseException {
      String baseDir = null;
      boolean nameAttributeSet = false;

      Project project = context.getProject();
      // Set the location of the implicit target associated with the project tag
      context.getImplicitTarget().setLocation(new Location(context.getLocator()));

      /**
       * 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 a top-level element within the project. An appropriate handler is
     * created and initialised with the details of the element.
     *
     * @param uri The namespace URI for this element.
     * @param name The name of the element being started. Will not be <code>null</code>.
     * @param qname The qualified name for this element.
     * @param attrs Attributes of the element being started. Will not be <code>null</code>.
     * @param context The context for this element.
     * @return a target or an element handler.
     * @exception org.xml.sax.SAXParseException if the tag given is not <code>"taskdef"</code>,
     *     <code>"typedef"</code>, <code>"property"</code>, <code>"target"</code>, <code>
     *     "extension-point"</code> or a data type definition
     */
    public AntHandler onStartChild(
        String uri, String name, String qname, Attributes attrs, AntXMLContext context)
        throws SAXParseException {
      return (name.equals("target") || name.equals("extension-point"))
              && (uri.equals("") || uri.equals(ANT_CORE_URI))
          ? ProjectHelper2.targetHandler
          : ProjectHelper2.elementHandler;
    }
  }

  /** Handler for "target" and "extension-point" elements. */
  public static class TargetHandler extends AntHandler {

    /**
     * Initialisation routine called after handler creation with the element name and attributes.
     * The attributes which this handler can deal with are: <code>"name"</code>, <code>"depends"
     * </code>, <code>"if"</code>, <code>"unless"</code>, <code>"id"</code> and <code>"description"
     * </code>.
     *
     * @param uri The namespace URI for this element.
     * @param tag Name of the element which caused this handler to be created. Should not be <code>
     *     null</code>. Ignored in this implementation.
     * @param qname The qualified name for this element.
     * @param attrs Attributes of the element which caused this handler to be created. Must not be
     *     <code>null</code>.
     * @param context The current context.
     * @exception SAXParseException if an unexpected attribute is encountered or if the <code>"name"
     *     </code> attribute is missing.
     */
    public void onStartElement(
        String uri, String tag, String qname, Attributes attrs, AntXMLContext context)
        throws SAXParseException {
      String name = null;
      String depends = "";
      String extensionPoint = null;
      OnMissingExtensionPoint extensionPointMissing = null;

      Project project = context.getProject();
      Target target = "target".equals(tag) ? new Target() : new ExtensionPoint();
      target.setProject(project);
      target.setLocation(new Location(context.getLocator()));
      context.addTarget(target);

      for (int i = 0; i < attrs.getLength(); i++) {
        String attrUri = attrs.getURI(i);
        if (attrUri != null && !attrUri.equals("") && !attrUri.equals(uri)) {
          continue; // Ignore attributes from unknown uris
        }
        String key = attrs.getLocalName(i);
        String value = attrs.getValue(i);

        if (key.equals("name")) {
          name = value;
          if ("".equals(name)) {
            throw new BuildException("name attribute must " + "not be empty");
          }
        } else if (key.equals("depends")) {
          depends = value;
        } else if (key.equals("if")) {
          target.setIf(value);
        } else if (key.equals("unless")) {
          target.setUnless(value);
        } else if (key.equals("id")) {
          if (value != null && !value.equals("")) {
            context.getProject().addReference(value, target);
          }
        } else if (key.equals("description")) {
          target.setDescription(value);
        } else if (key.equals("extensionOf")) {
          extensionPoint = value;
        } else if (key.equals("onMissingExtensionPoint")) {
          try {
            extensionPointMissing = OnMissingExtensionPoint.valueOf(value);
          } catch (IllegalArgumentException e) {
            throw new BuildException("Invalid onMissingExtensionPoint " + value);
          }
        } else {
          throw new SAXParseException("Unexpected attribute \"" + key + "\"", context.getLocator());
        }
      }

      if (name == null) {
        throw new SAXParseException(
            "target element appears without a name attribute", context.getLocator());
      }

      String prefix = null;
      boolean isInIncludeMode = context.isIgnoringProjectTag() && isInIncludeMode();
      String sep = getCurrentPrefixSeparator();

      if (isInIncludeMode) {
        prefix = getTargetPrefix(context);
        if (prefix == null) {
          throw new BuildException(
              "can't include build file "
                  + context.getBuildFileURL()
                  + ", no as attribute has been given"
                  + " and the project tag doesn't"
                  + " specify a name attribute");
        }
        name = prefix + sep + name;
      }

      // Check if this target is in the current build file
      if (context.getCurrentTargets().get(name) != null) {
        throw new BuildException("Duplicate target '" + name + "'", target.getLocation());
      }
      Hashtable 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()});
        }
      }
    }

    private String getTargetPrefix(AntXMLContext context) {
      String configuredValue = getCurrentTargetPrefix();
      if (configuredValue != null && configuredValue.length() == 0) {
        configuredValue = null;
      }
      if (configuredValue != null) {
        return configuredValue;
      }

      String projectName = context.getCurrentProjectName();
      if ("".equals(projectName)) {
        projectName = null;
      }

      return projectName;
    }

    /**
     * Handles the start of an element within a target.
     *
     * @param uri The namespace URI for this element.
     * @param name The name of the element being started. Will not be <code>null</code>.
     * @param qname The qualified name for this element.
     * @param attrs Attributes of the element being started. Will not be <code>null</code>.
     * @param context The current context.
     * @return an element handler.
     * @exception SAXParseException if an error occurs when initialising the appropriate child
     *     handler
     */
    public AntHandler onStartChild(
        String uri, String name, String qname, Attributes attrs, AntXMLContext context)
        throws SAXParseException {
      return ProjectHelper2.elementHandler;
    }

    /**
     * Handle the end of the project, sets the current target of the context to be the implicit
     * target.
     *
     * @param uri The namespace URI of the element.
     * @param tag The name of the element.
     * @param context The current context.
     */
    public void onEndElement(String uri, String tag, AntXMLContext context) {
      context.setCurrentTarget(context.getImplicitTarget());
    }
  }

  /** Handler for all project elements ( tasks, data types ) */
  public static class ElementHandler extends AntHandler {

    /** Constructor. */
    public ElementHandler() {}

    /**
     * Initialisation routine called after handler creation with the element name and attributes.
     * This configures the element with its attributes and sets it up with its parent container (if
     * any). Nested elements are then added later as the parser encounters them.
     *
     * @param uri The namespace URI for this element.
     * @param tag Name of the element which caused this handler to be created. Must not be <code>
     *     null</code>.
     * @param qname The qualified name for this element.
     * @param attrs Attributes of the element which caused this handler to be created. Must not be
     *     <code>null</code>.
     * @param context The current context.
     * @exception SAXParseException in case of error (not thrown in this implementation)
     */
    public void onStartElement(
        String uri, String tag, String qname, Attributes attrs, AntXMLContext context)
        throws SAXParseException {
      RuntimeConfigurable parentWrapper = context.currentWrapper();
      Object parent = null;

      if (parentWrapper != null) {
        parent = parentWrapper.getProxy();
      }

      /* UnknownElement is used for tasks and data types - with
      delayed eval */
      UnknownElement task = new UnknownElement(tag);
      task.setProject(context.getProject());
      task.setNamespace(uri);
      task.setQName(qname);
      task.setTaskType(ProjectHelper.genComponentName(task.getNamespace(), tag));
      task.setTaskName(qname);

      Location location =
          new Location(
              context.getLocator().getSystemId(),
              context.getLocator().getLineNumber(),
              context.getLocator().getColumnNumber());
      task.setLocation(location);
      task.setOwningTarget(context.getCurrentTarget());

      if (parent != null) {
        // Nested element
        ((UnknownElement) parent).addChild(task);
      } else {
        // Task included in a target ( including the default one ).
        context.getCurrentTarget().addTask(task);
      }

      context.configureId(task, attrs);

      // container.addTask(task);
      // This is a nop in UE: task.init();

      RuntimeConfigurable wrapper = new RuntimeConfigurable(task, task.getTaskName());

      for (int i = 0; i < attrs.getLength(); i++) {
        String name = attrs.getLocalName(i);
        String attrUri = attrs.getURI(i);
        if (attrUri != null && !attrUri.equals("") && !attrUri.equals(uri)) {
          name = attrUri + ":" + attrs.getQName(i);
        }
        String value = attrs.getValue(i);
        // PR: Hack for ant-type value
        //  an ant-type is a component name which can
        // be namespaced, need to extract the name
        // and convert from qualified name to uri/name
        if (ANT_TYPE.equals(name)
            || (ANT_CORE_URI.equals(attrUri) && ANT_TYPE.equals(attrs.getLocalName(i)))) {
          name = ANT_TYPE;
          int index = value.indexOf(":");
          if (index >= 0) {
            String prefix = value.substring(0, index);
            String mappedUri = context.getPrefixMapping(prefix);
            if (mappedUri == null) {
              throw new BuildException("Unable to find XML NS prefix \"" + prefix + "\"");
            }
            value = ProjectHelper.genComponentName(mappedUri, value.substring(index + 1));
          }
        }
        wrapper.setAttribute(name, value);
      }
      if (parentWrapper != null) {
        parentWrapper.addChild(wrapper);
      }
      context.pushWrapper(wrapper);
    }

    /**
     * Adds text to the task, using the wrapper
     *
     * @param buf A character array of the text within the element. Will not be <code>null</code>.
     * @param start The start element in the array.
     * @param count The number of characters to read from the array.
     * @param context The current context.
     * @exception SAXParseException if the element doesn't support text
     * @see ProjectHelper#addText(Project,java.lang.Object,char[],int,int)
     */
    public void characters(char[] buf, int start, int count, AntXMLContext context)
        throws SAXParseException {
      RuntimeConfigurable wrapper = context.currentWrapper();
      wrapper.addText(buf, start, count);
    }

    /**
     * Handles the start of an element within a target. Task containers will always use another task
     * handler, and all other tasks will always use a nested element handler.
     *
     * @param uri The namespace URI for this element.
     * @param tag The name of the element being started. Will not be <code>null</code>.
     * @param qname The qualified name for this element.
     * @param attrs Attributes of the element being started. Will not be <code>null</code>.
     * @param context The current context.
     * @return The handler for elements.
     * @exception SAXParseException if an error occurs when initialising the appropriate child
     *     handler
     */
    public AntHandler onStartChild(
        String uri, String tag, String qname, Attributes attrs, AntXMLContext context)
        throws SAXParseException {
      return ProjectHelper2.elementHandler;
    }

    /**
     * Handles the end of the element. This pops the wrapper from the context.
     *
     * @param uri The namespace URI for the element.
     * @param tag The name of the element.
     * @param context The current context.
     */
    public void onEndElement(String uri, String tag, AntXMLContext context) {
      context.popWrapper();
    }
  }
}
Пример #16
0
 /** Resolve a filename with Project's help - if we know one that is. */
 private static File resolveFile(Project project, String relativeName) {
   return FileUtils.getFileUtils()
       .resolveFile((project == null) ? null : project.getBaseDir(), relativeName);
 }
Пример #17
0
/**
 * This task sets a property to the name of a temporary file. Unlike {@link File#createTempFile},
 * this task does not (by default) actually create the temporary file, but it does guarantee that
 * the file did not exist when the task was executed.
 *
 * <p>Examples
 *
 * <pre>&lt;tempfile property="temp.file" /&gt;</pre>
 *
 * create a temporary file
 *
 * <pre>&lt;tempfile property="temp.file" suffix=".xml" /&gt;</pre>
 *
 * create a temporary file with the .xml suffix.
 *
 * <pre>&lt;tempfile property="temp.file" destDir="build"/&gt;</pre>
 *
 * create a temp file in the build subdir
 *
 * @since Ant 1.5
 * @ant.task
 */
public class TempFile extends Task {

  private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();

  /** Name of property to set. */
  private String property;

  /** Directory to create the file in. Can be null. */
  private File destDir = null;

  /** Prefix for the file. */
  private String prefix;

  /** Suffix for the file. */
  private String suffix = "";

  /** deleteOnExit flag */
  private boolean deleteOnExit;

  /** createFile flag */
  private boolean createFile;

  /**
   * Sets the property you wish to assign the temporary file to.
   *
   * @param property The property to set
   * @ant.attribute group="required"
   */
  public void setProperty(String property) {
    this.property = property;
  }

  /**
   * Sets the destination directory. If not set, the basedir directory is used instead.
   *
   * @param destDir The new destDir value
   */
  public void setDestDir(File destDir) {
    this.destDir = destDir;
  }

  /**
   * Sets the optional prefix string for the temp file.
   *
   * @param prefix string to prepend to generated string
   */
  public void setPrefix(String prefix) {
    this.prefix = prefix;
  }

  /**
   * Sets the optional suffix string for the temp file.
   *
   * @param suffix suffix including any "." , e.g ".xml"
   */
  public void setSuffix(String suffix) {
    this.suffix = suffix;
  }

  /**
   * Set whether the tempfile created by this task should be set for deletion on normal VM exit.
   *
   * @param deleteOnExit boolean flag.
   */
  public void setDeleteOnExit(boolean deleteOnExit) {
    this.deleteOnExit = deleteOnExit;
  }

  /**
   * Learn whether deleteOnExit is set for this tempfile task.
   *
   * @return boolean deleteOnExit flag.
   */
  public boolean isDeleteOnExit() {
    return deleteOnExit;
  }

  /**
   * If set the file is actually created, if not just a name is created.
   *
   * @param createFile boolean flag.
   */
  public void setCreateFile(boolean createFile) {
    this.createFile = createFile;
  }

  /**
   * Learn whether createFile flag is set for this tempfile task.
   *
   * @return the createFile flag.
   */
  public boolean isCreateFile() {
    return createFile;
  }

  /**
   * Creates the temporary file.
   *
   * @exception BuildException if something goes wrong with the build
   */
  public void execute() throws BuildException {
    if (property == null || property.length() == 0) {
      throw new BuildException("no property specified");
    }
    if (destDir == null) {
      destDir = getProject().resolveFile(".");
    }
    File tfile = FILE_UTILS.createTempFile(prefix, suffix, destDir, deleteOnExit, createFile);
    getProject().setNewProperty(property, tfile.toString());
  }
}
/**
 * Transform a JUnit xml report. The default transformation generates an html report in either
 * framed or non-framed style. The non-framed style is convenient to have a concise report via mail,
 * the framed report is much more convenient if you want to browse into different packages or
 * testcases since it is a Javadoc like report.
 */
public class AggregateTransformer {
  /** name of the frames format. */
  public static final String FRAMES = "frames";

  /** name of the no frames format. */
  public static final String NOFRAMES = "noframes";

  /** defines acceptable formats. */
  public static class Format extends EnumeratedAttribute {
    /**
     * list authorized values.
     *
     * @return authorized values.
     */
    public String[] getValues() {
      return new String[] {FRAMES, NOFRAMES};
    }
  }

  // CheckStyle:VisibilityModifier OFF - bc
  /** Task */
  protected Task task;

  /** the xml document to process */
  protected Document document;

  /** the style directory. XSLs should be read from here if necessary */
  protected File styleDir;

  /** the destination directory, this is the root from where html should be generated */
  protected File toDir;

  /**
   * The params that will be sent to the XSL transformation
   *
   * @since Ant 1.7
   */
  private List params;

  /**
   * Instance of a utility class to use for file operations.
   *
   * @since Ant 1.7
   */
  private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();

  /** Used to ensure the uniqueness of a property */
  private static int counter = 0;

  /** the format to use for the report. Must be <tt>FRAMES</tt> or <tt>NOFRAMES</tt> */
  protected String format = FRAMES;

  /** XML Parser factory */
  private static DocumentBuilderFactory privateDBFactory;

  /** XML Parser factory accessible to subclasses */
  protected static DocumentBuilderFactory dbfactory;

  static {
    privateDBFactory = DocumentBuilderFactory.newInstance();
    dbfactory = privateDBFactory;
  }
  // CheckStyle:VisibilityModifier ON

  /**
   * constructor creating the transformer from the junitreport task.
   *
   * @param task task delegating to this class
   */
  public AggregateTransformer(Task task) {
    this.task = task;
    params = new Vector();
  }

  /**
   * Get the Document Builder Factory
   *
   * @return the DocumentBuilderFactory instance in use
   */
  protected static DocumentBuilderFactory getDocumentBuilderFactory() {
    return privateDBFactory;
  }

  /**
   * sets the format.
   *
   * @param format Must be <tt>FRAMES</tt> or <tt>NOFRAMES</tt>
   */
  public void setFormat(Format format) {
    this.format = format.getValue();
  }

  /**
   * sets the input document.
   *
   * @param doc input dom tree
   */
  public void setXmlDocument(Document doc) {
    this.document = doc;
  }

  /**
   * Set the xml file to be processed. This is a helper if you want to set the file directly. Much
   * more for testing purposes.
   *
   * @param xmlfile xml file to be processed
   * @throws BuildException if the document cannot be parsed.
   */
  protected void setXmlfile(File xmlfile) throws BuildException {
    try {
      DocumentBuilder builder = privateDBFactory.newDocumentBuilder();
      InputStream in = new FileInputStream(xmlfile);
      try {
        Document doc = builder.parse(in);
        setXmlDocument(doc);
      } finally {
        in.close();
      }
    } catch (Exception e) {
      throw new BuildException("Error while parsing document: " + xmlfile, e);
    }
  }

  /**
   * set the style directory. It is optional and will override the default xsl used.
   *
   * @param styledir the directory containing the xsl files if the user would like to override with
   *     its own style.
   */
  public void setStyledir(File styledir) {
    this.styleDir = styledir;
  }

  /**
   * set the destination directory.
   *
   * @param todir the destination directory
   */
  public void setTodir(File todir) {
    this.toDir = todir;
  }

  /**
   * set the extension of the output files
   *
   * @param ext extension.
   */
  public void setExtension(String ext) {
    task.log("extension is not used anymore", Project.MSG_WARN);
  }

  /**
   * Create an instance of an XSL parameter for configuration by Ant.
   *
   * @return an instance of the Param class to be configured.
   * @since Ant 1.7
   */
  public XSLTProcess.Param createParam() {
    XSLTProcess.Param p = new XSLTProcess.Param();
    params.add(p);
    return p;
  }

  /**
   * transformation
   *
   * @throws BuildException exception if something goes wrong with the transformation.
   */
  public void transform() throws BuildException {
    checkOptions();
    Project project = task.getProject();

    TempFile tempFileTask = new TempFile();
    tempFileTask.bindToOwner(task);

    XSLTProcess xsltTask = new XSLTProcess();
    xsltTask.bindToOwner(task);

    xsltTask.setXslResource(getStylesheet());

    // acrobatic cast.
    xsltTask.setIn(((XMLResultAggregator) task).getDestinationFile());
    File outputFile = null;
    if (format.equals(FRAMES)) {
      String tempFileProperty = getClass().getName() + String.valueOf(counter++);
      File tmp =
          FILE_UTILS.resolveFile(project.getBaseDir(), project.getProperty("java.io.tmpdir"));
      tempFileTask.setDestDir(tmp);
      tempFileTask.setProperty(tempFileProperty);
      tempFileTask.execute();
      outputFile = new File(project.getProperty(tempFileProperty));
    } else {
      outputFile = new File(toDir, "junit-noframes.html");
    }
    xsltTask.setOut(outputFile);
    for (Iterator i = params.iterator(); i.hasNext(); ) {
      XSLTProcess.Param param = (XSLTProcess.Param) i.next();
      XSLTProcess.Param newParam = xsltTask.createParam();
      newParam.setProject(task.getProject());
      newParam.setName(param.getName());
      newParam.setExpression(param.getExpression());
    }
    XSLTProcess.Param paramx = xsltTask.createParam();
    paramx.setProject(task.getProject());
    paramx.setName("output.dir");
    paramx.setExpression(toDir.getAbsolutePath());
    final long t0 = System.currentTimeMillis();
    try {
      xsltTask.execute();
    } catch (Exception e) {
      throw new BuildException("Errors while applying transformations: " + e.getMessage(), e);
    }
    final long dt = System.currentTimeMillis() - t0;
    task.log("Transform time: " + dt + "ms");
    if (format.equals(FRAMES)) {
      Delete delete = new Delete();
      delete.bindToOwner(task);
      delete.setFile(outputFile);
      delete.execute();
    }
  }

  /**
   * access the stylesheet to be used as a resource.
   *
   * @return stylesheet as a resource
   */
  protected Resource getStylesheet() {
    String xslname = "junit-frames.xsl";
    if (NOFRAMES.equals(format)) {
      xslname = "junit-noframes.xsl";
    }
    if (styleDir == null) {
      // If style dir is not specified we have to retrieve
      // the stylesheet from the classloader
      URL stylesheetURL =
          getClass()
              .getClassLoader()
              .getResource("org/apache/tools/ant/taskdefs/optional/junit/xsl/" + xslname);
      return new URLResource(stylesheetURL);
    }
    // If we are here, then the style dir is here and we
    // should read the stylesheet from the filesystem
    return new FileResource(new File(styleDir, xslname));
  }

  /**
   * check for invalid options
   *
   * @throws BuildException if something goes wrong.
   */
  protected void checkOptions() throws BuildException {
    // set the destination directory relative from the project if needed.
    if (toDir == null) {
      toDir = task.getProject().resolveFile(".");
    } else if (!toDir.isAbsolute()) {
      toDir = task.getProject().resolveFile(toDir.getPath());
    }
  }

  /**
   * Get the systemid of the appropriate stylesheet based on its name and styledir. If no styledir
   * is defined it will load it as a java resource in the xsl child package, otherwise it will get
   * it from the given directory.
   *
   * @return system ID of the stylesheet.
   * @throws IOException thrown if the requested stylesheet does not exist.
   */
  protected String getStylesheetSystemId() throws IOException {
    String xslname = "junit-frames.xsl";
    if (NOFRAMES.equals(format)) {
      xslname = "junit-noframes.xsl";
    }
    if (styleDir == null) {
      URL url = getClass().getResource("xsl/" + xslname);
      if (url == null) {
        throw new FileNotFoundException("Could not find jar resource " + xslname);
      }
      return url.toExternalForm();
    }
    File file = new File(styleDir, xslname);
    if (!file.exists()) {
      throw new FileNotFoundException("Could not find file '" + file + "'");
    }
    return JAXPUtils.getSystemId(file);
  }
}
/** Unit test for the &lt;exec&gt; task. */
public class ExecTaskTest extends BuildFileTest {
  private static final String BUILD_PATH = "src/etc/testcases/taskdefs/exec/";
  private static final String BUILD_FILE = BUILD_PATH + "exec.xml";
  private static final int TIME_TO_WAIT = 1;
  /** maximum time allowed for the build in milliseconds */
  private static final int MAX_BUILD_TIME = 4000;

  private static final int SECURITY_MARGIN = 2000; // wait 2 second extras
  // the test failed with 100 ms of margin on cvs.apache.org on August 1st,
  // 2003

  /** Utilities used for file operations */
  private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();

  private File logFile;
  private MonitoredBuild myBuild = null;
  private volatile boolean buildFinished = false;

  public ExecTaskTest(String name) {
    super(name);
  }

  public void setUp() {
    configureProject(BUILD_FILE);
  }

  public void tearDown() {
    if (logFile != null && logFile.exists()) {
      getProject().setProperty("logFile", logFile.getAbsolutePath());
    }
    executeTarget("cleanup");
  }

  public void testspawn() {
    project.executeTarget("init");
    if (project.getProperty("test.can.run") == null) {
      return;
    }
    myBuild = new MonitoredBuild(new File(System.getProperty("root"), BUILD_FILE), "spawn");
    logFile = FILE_UTILS.createTempFile("spawn", "log", project.getBaseDir(), false, false);
    // this is guaranteed by FileUtils#createTempFile
    assertTrue("log file not existing", !logFile.exists());
    // make the spawned process run 4 seconds
    myBuild.setTimeToWait(TIME_TO_WAIT);
    myBuild.setLogFile(logFile.getAbsolutePath());
    myBuild.addBuildListener(new MonitoredBuildListener());
    myBuild.start();
    GregorianCalendar startwait = new GregorianCalendar();
    // this loop runs parallel to the build
    while (!buildFinished) {
      try {
        Thread.sleep(10);
      } catch (InterruptedException e) {
        System.out.println("my sleep was interrupted");
      }
      GregorianCalendar now = new GregorianCalendar();
      // security
      if (now.getTime().getTime() - startwait.getTime().getTime() > MAX_BUILD_TIME) {
        System.out.println(
            "aborting wait, too long "
                + (now.getTime().getTime() - startwait.getTime().getTime())
                + "milliseconds");
        break;
      }
    }
    // now wait until the spawned process is finished
    try {
      Thread.sleep((TIME_TO_WAIT) * 1000 + SECURITY_MARGIN);
    } catch (InterruptedException e) {
      System.out.println("my sleep was interrupted");
    }
    // time of the build in milli seconds
    long elapsed = myBuild.getTimeElapsed();
    assertTrue(
        "we waited more than the process lasted", TIME_TO_WAIT * 1000 + SECURITY_MARGIN > elapsed);
    logFile = new File(logFile.getAbsolutePath());
    assertTrue("log file found after spawn", logFile.exists());
  }

  private static class MonitoredBuild implements Runnable {
    private Thread worker;
    private File myBuildFile = null;
    private String target = null;
    private Project project = null;
    private int timeToWait = 0;
    private String logFile = null;
    private GregorianCalendar timeStarted = null;
    private GregorianCalendar timeFinished = null;

    public void setLogFile(String logFile) {
      this.logFile = logFile;
      project.setProperty("logFile", logFile);
    }

    public void setTimeToWait(int timeToWait) {
      this.timeToWait = timeToWait;
      project.setProperty("timeToWait", Long.toString(timeToWait));
    }

    public void addBuildListener(BuildListener bl) {
      project.addBuildListener(bl);
    }

    public MonitoredBuild(File buildFile, String target) {
      myBuildFile = buildFile;
      this.target = target;
      project = new Project();
      project = new Project();
      project.init();
      project.setUserProperty("ant.file", myBuildFile.getAbsolutePath());
      ProjectHelper.configureProject(project, myBuildFile);
    }

    /** @return time in millis of the build */
    public long getTimeElapsed() {
      return timeFinished.getTime().getTime() - timeStarted.getTime().getTime();
    }

    public void start() {
      worker = new Thread(this, myBuildFile.toString() + "/" + target);
      worker.start();
    }

    public void run() {
      startProject();
    }

    private void startProject() {
      timeStarted = new GregorianCalendar();
      project.executeTarget(target);
      timeFinished = new GregorianCalendar();
    }
  }

  private class MonitoredBuildListener implements BuildListener {
    public void buildStarted(BuildEvent event) {}

    public void buildFinished(BuildEvent event) {}

    public void targetStarted(BuildEvent event) {}

    public void targetFinished(BuildEvent event) {
      if (event.getTarget().getName().equals("spawn")) {
        buildFinished = true;
      }
    }

    public void taskStarted(BuildEvent event) {}

    public void taskFinished(BuildEvent event) {}

    public void messageLogged(BuildEvent event) {}
  }
}