/** * 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); } }
/** 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); } } } }
/** 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); } } } }
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); } }
/** * 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()); } } }
/** * 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); }
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); } }
/** * 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><fileset> * </code> (<code>dir</code> becomes <code>base</code>) as well as the nested <code><include> * </code>, <code><exclude></code> and <code><patternset></code> elements. * * <p>It is possible to use different compilers. This can be selected with the * "build.rmic" 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 "1.1" to pass the * "-v1.1" 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 <path> 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); } } }
/** 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(); } } } }
/** 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 </end_tag_of_the_element>. * * @param uri the namespace uri for this element * @param tag the element name * @param context the current context */ public void onEndElement(String uri, String tag, AntXMLContext context) {} /** * Handles text within an element. This base implementation just throws an exception, you must * override it if you expect content. * * @param buf A character array of the text within the element. Will not be <code>null</code>. * @param start The start element in the array. * @param count The number of characters to read from the array. * @param context The current context. * @exception SAXParseException if this method is not overridden, or in case of error in an * overridden version */ public void characters(char[] buf, int start, int count, AntXMLContext context) throws SAXParseException { String s = new String(buf, start, count).trim(); if (s.length() > 0) { throw new SAXParseException("Unexpected text \"" + s + "\"", context.getLocator()); } } /** * Will be called every time a namespace is reached. It'll verify if the ns was processed, and * if not load the task definitions. * * @param uri The namespace uri. */ protected void checkNamespace(String uri) {} } /** * Handler for ant processing. Uses a stack of AntHandlers to implement each element ( the * original parser used a recursive behavior, with the implicit execution stack ) */ public static class RootHandler extends DefaultHandler { private Stack 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 <project> tag. * * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler */ public static class MainHandler extends AntHandler { /** * Handle the project tag * * @param uri The namespace uri. * @param name The element tag. * @param qname The element qualified name. * @param attrs The attributes of the element. * @param context The current context. * @return The project handler that handles subelements of project * @exception SAXParseException if the qualified name is not "project". */ public AntHandler onStartChild( String uri, String name, String qname, Attributes attrs, AntXMLContext context) throws SAXParseException { if (name.equals("project") && (uri.equals("") || uri.equals(ANT_CORE_URI))) { return ProjectHelper2.projectHandler; } if (name.equals(qname)) { throw new SAXParseException( "Unexpected element \"{" + uri + "}" + name + "\" {" + ANT_CORE_URI + "}" + name, context.getLocator()); } throw new SAXParseException( "Unexpected element \"" + qname + "\" " + name, context.getLocator()); } } /** Handler for the top level "project" element. */ public static class ProjectHandler extends AntHandler { /** * Initialisation routine called after handler creation with the element name and attributes. * The attributes which this handler can deal with are: <code>"default"</code>, <code>"name" * </code>, <code>"id"</code> and <code>"basedir"</code>. * * @param uri The namespace URI for this element. * @param tag Name of the element which caused this handler to be created. Should not be <code> * null</code>. Ignored in this implementation. * @param qname The qualified name for this element. * @param attrs Attributes of the element which caused this handler to be created. Must not be * <code>null</code>. * @param context The current context. * @exception SAXParseException if an unexpected attribute is encountered or if the <code> * "default"</code> attribute is missing. */ public void onStartElement( String uri, String tag, String qname, Attributes attrs, AntXMLContext context) throws SAXParseException { String baseDir = null; boolean nameAttributeSet = false; Project project = context.getProject(); // Set the location of the implicit target associated with the project tag context.getImplicitTarget().setLocation(new Location(context.getLocator())); /** * 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(); } } }
/** 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); }
/** * 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><tempfile property="temp.file" /></pre> * * create a temporary file * * <pre><tempfile property="temp.file" suffix=".xml" /></pre> * * create a temporary file with the .xml suffix. * * <pre><tempfile property="temp.file" destDir="build"/></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 <exec> 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) {} } }