git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@272460 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -1,197 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs; | |||
| import java.io.BufferedReader; | |||
| import java.io.File; | |||
| import java.io.FileReader; | |||
| import java.net.URL; | |||
| import org.apache.myrmidon.api.AbstractTask; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.java.ExecuteJava; | |||
| import org.apache.myrmidon.framework.nativelib.Argument; | |||
| import org.apache.myrmidon.framework.file.Path; | |||
| /** | |||
| * ANTLR task. | |||
| * | |||
| * @author <a href="mailto:emeade@geekfarm.org">Erik Meade</a> | |||
| * @author <a href="mailto:sbailliez@apache.org>Stephane Bailliez</a> | |||
| */ | |||
| public class ANTLR | |||
| extends AbstractTask | |||
| { | |||
| private final ExecuteJava m_exe = new ExecuteJava(); | |||
| /** | |||
| * where to output the result | |||
| */ | |||
| private File m_outputDirectory; | |||
| /** | |||
| * the file to process | |||
| */ | |||
| private File m_target; | |||
| /** | |||
| * The working directory of the process | |||
| * | |||
| * @param dir The new Dir value | |||
| */ | |||
| public void setDir( final File dir ) | |||
| { | |||
| m_exe.setWorkingDirectory( dir ); | |||
| } | |||
| public void setFork( final boolean fork ) | |||
| { | |||
| m_exe.setFork( fork ); | |||
| } | |||
| public void setOutputdirectory( final File outputDirectory ) | |||
| { | |||
| m_outputDirectory = outputDirectory; | |||
| } | |||
| public void setTarget( final File target ) | |||
| { | |||
| m_target = target; | |||
| } | |||
| /** | |||
| * <code><classpath></code> allows classpath to be set because a | |||
| * directory might be given for Antlr debug... | |||
| */ | |||
| public void addClasspath( final Path path ) | |||
| { | |||
| m_exe.getClassPath().add( path ); | |||
| } | |||
| /** | |||
| * Create a new JVM argument. Ignored if no JVM is forked. | |||
| * | |||
| * @see #setFork(boolean) | |||
| */ | |||
| public void addJvmarg( final Argument argument ) | |||
| { | |||
| m_exe.getVmArguments().addArgument( argument ); | |||
| } | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| //Adds the jars or directories containing Antlr this should make the forked | |||
| //JVM work without having to specify it directly. | |||
| addClasspathEntry( "/antlr/Tool.class" ); | |||
| validateAttributes(); | |||
| //TODO: use ANTLR to parse the grammer file to do this. | |||
| if( m_target.lastModified() <= getGeneratedFile().lastModified() ) | |||
| { | |||
| return; | |||
| } | |||
| m_exe.setClassName( "antlr.Tool" ); | |||
| m_exe.getArguments().addArgument( "-o" ); | |||
| m_exe.getArguments().addArgument( m_outputDirectory ); | |||
| m_exe.getArguments().addArgument( m_target ); | |||
| m_exe.execute( getContext() ); | |||
| } | |||
| /** | |||
| * 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.</p> | |||
| * | |||
| * @param resource The feature to be added to the ClasspathEntry attribute | |||
| */ | |||
| protected void addClasspathEntry( final String resource ) | |||
| { | |||
| URL url = getClass().getResource( resource ); | |||
| if( url != null ) | |||
| { | |||
| String u = url.toString(); | |||
| if( u.startsWith( "jar:file:" ) ) | |||
| { | |||
| int pling = u.indexOf( "!" ); | |||
| String jarName = u.substring( 9, pling ); | |||
| getContext().debug( "Implicitly adding " + jarName + " to classpath" ); | |||
| m_exe.getClassPath().addLocation( new File( jarName ) ); | |||
| } | |||
| else if( u.startsWith( "file:" ) ) | |||
| { | |||
| int tail = u.indexOf( resource ); | |||
| String dirName = u.substring( 5, tail ); | |||
| getContext().debug( "Implicitly adding " + dirName + " to classpath" ); | |||
| m_exe.getClassPath().addLocation( new File( dirName ) ); | |||
| } | |||
| else | |||
| { | |||
| getContext().debug( "Don\'t know how to handle resource URL " + u ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| getContext().debug( "Couldn\'t find " + resource ); | |||
| } | |||
| } | |||
| private File getGeneratedFile() | |||
| throws TaskException | |||
| { | |||
| String generatedFileName = null; | |||
| try | |||
| { | |||
| BufferedReader in = new BufferedReader( new FileReader( m_target ) ); | |||
| String line; | |||
| while( ( line = in.readLine() ) != null ) | |||
| { | |||
| int extendsIndex = line.indexOf( " extends " ); | |||
| if( line.startsWith( "class " ) && extendsIndex > -1 ) | |||
| { | |||
| generatedFileName = line.substring( 6, extendsIndex ).trim(); | |||
| break; | |||
| } | |||
| } | |||
| in.close(); | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| throw new TaskException( "Unable to determine generated class", e ); | |||
| } | |||
| if( generatedFileName == null ) | |||
| { | |||
| throw new TaskException( "Unable to determine generated class" ); | |||
| } | |||
| return new File( m_outputDirectory, generatedFileName + ".java" ); | |||
| } | |||
| private void validateAttributes() | |||
| throws TaskException | |||
| { | |||
| if( m_target == null || !m_target.isFile() ) | |||
| { | |||
| throw new TaskException( "Invalid target: " + m_target ); | |||
| } | |||
| // if no output directory is specified, used the target's directory | |||
| if( m_outputDirectory == null ) | |||
| { | |||
| m_outputDirectory = m_target.getParentFile(); | |||
| } | |||
| if( !m_outputDirectory.isDirectory() ) | |||
| { | |||
| throw new TaskException( "Invalid output directory: " + m_outputDirectory ); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,291 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs; | |||
| import java.io.File; | |||
| import java.io.FileOutputStream; | |||
| import java.io.IOException; | |||
| import java.io.OutputStream; | |||
| import java.io.PrintWriter; | |||
| import java.util.ArrayList; | |||
| import java.util.Iterator; | |||
| import org.apache.aut.nativelib.Os; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.nativelib.Execute; | |||
| import org.apache.myrmidon.framework.FileSet; | |||
| import org.apache.myrmidon.framework.nativelib.Commandline; | |||
| import org.apache.tools.todo.types.DirectoryScanner; | |||
| import org.apache.tools.todo.types.ScannerUtil; | |||
| /** | |||
| * Create a CAB archive. | |||
| * | |||
| * @author <a href="mailto:rvaughn@seaconinc.com">Roger Vaughn</a> | |||
| */ | |||
| public class Cab | |||
| extends MatchingTask | |||
| { | |||
| private ArrayList m_filesets = new ArrayList(); | |||
| private boolean m_compress = true; | |||
| private File m_baseDir; | |||
| private File m_cabFile; | |||
| private String m_options; | |||
| /** | |||
| * This is the base directory to look in for things to cab. | |||
| * | |||
| * @param baseDir The new Basedir value | |||
| */ | |||
| public void setBasedir( final File baseDir ) | |||
| { | |||
| m_baseDir = baseDir; | |||
| } | |||
| /** | |||
| * This is the name/location of where to create the .cab file. | |||
| * | |||
| * @param cabFile The new Cabfile value | |||
| */ | |||
| public void setCabfile( final File cabFile ) | |||
| { | |||
| m_cabFile = cabFile; | |||
| } | |||
| /** | |||
| * Sets whether we want to compress the files or only store them. | |||
| * | |||
| * @param compress The new Compress value | |||
| */ | |||
| public void setCompress( final boolean compress ) | |||
| { | |||
| m_compress = compress; | |||
| } | |||
| /** | |||
| * Sets additional cabarc options that aren't supported directly. | |||
| * | |||
| * @param options The new Options value | |||
| */ | |||
| public void setOptions( final String options ) | |||
| { | |||
| m_options = options; | |||
| } | |||
| /** | |||
| * Adds a set of files (nested fileset attribute). | |||
| * | |||
| * @param set The feature to be added to the Fileset attribute | |||
| */ | |||
| public void addFileset( final FileSet set ) | |||
| { | |||
| m_filesets.add( set ); | |||
| } | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| checkConfiguration(); | |||
| final ArrayList files = getFileList(); | |||
| // quick exit if the target is up to date | |||
| if( isUpToDate( files ) ) | |||
| { | |||
| return; | |||
| } | |||
| getContext().info( "Building cab: " + m_cabFile.getAbsolutePath() ); | |||
| if( !Os.isFamily( Os.OS_FAMILY_WINDOWS ) ) | |||
| { | |||
| getContext().debug( "Using listcab/libcabinet" ); | |||
| final StringBuffer sb = new StringBuffer(); | |||
| final Iterator e = files.iterator(); | |||
| while( e.hasNext() ) | |||
| { | |||
| sb.append( e.next() ).append( "\n" ); | |||
| } | |||
| sb.append( "\n" ).append( m_cabFile.getAbsolutePath() ).append( "\n" ); | |||
| try | |||
| { | |||
| Process p = Runtime.getRuntime().exec( "listcab" ); | |||
| OutputStream out = p.getOutputStream(); | |||
| out.write( sb.toString().getBytes() ); | |||
| out.flush(); | |||
| out.close(); | |||
| } | |||
| catch( IOException ex ) | |||
| { | |||
| String msg = "Problem creating " + m_cabFile + " " + ex.getMessage(); | |||
| throw new TaskException( msg ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| try | |||
| { | |||
| File listFile = createListFile( files ); | |||
| Execute exe = new Execute(); | |||
| exe.setWorkingDirectory( m_baseDir ); | |||
| createCommand( exe, listFile ); | |||
| exe.execute( getContext() ); | |||
| listFile.delete(); | |||
| } | |||
| catch( final IOException ioe ) | |||
| { | |||
| final String message = | |||
| "Problem creating " + m_cabFile + " " + ioe.getMessage(); | |||
| throw new TaskException( message ); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Get the complete list of files to be included in the cab. Filenames are | |||
| * gathered from filesets if any have been added, otherwise from the | |||
| * traditional include parameters. | |||
| */ | |||
| protected ArrayList getFileList() | |||
| throws TaskException | |||
| { | |||
| ArrayList files = new ArrayList(); | |||
| if( m_filesets.size() == 0 ) | |||
| { | |||
| // get files from old methods - includes and nested include | |||
| appendFiles( files, super.getDirectoryScanner( m_baseDir ) ); | |||
| } | |||
| else | |||
| { | |||
| // get files from filesets | |||
| for( int i = 0; i < m_filesets.size(); i++ ) | |||
| { | |||
| FileSet fs = (FileSet)m_filesets.get( i ); | |||
| if( fs != null ) | |||
| { | |||
| appendFiles( files, ScannerUtil.getDirectoryScanner( fs ) ); | |||
| } | |||
| } | |||
| } | |||
| return files; | |||
| } | |||
| /** | |||
| * Check to see if the target is up to date with respect to input files. | |||
| * | |||
| * @param files Description of Parameter | |||
| * @return true if the cab file is newer than its dependents. | |||
| */ | |||
| protected boolean isUpToDate( ArrayList files ) | |||
| { | |||
| boolean upToDate = true; | |||
| for( int i = 0; i < files.size() && upToDate; i++ ) | |||
| { | |||
| String file = files.get( i ).toString(); | |||
| if( new File( m_baseDir, file ).lastModified() > | |||
| m_cabFile.lastModified() ) | |||
| { | |||
| upToDate = false; | |||
| } | |||
| } | |||
| return upToDate; | |||
| } | |||
| /** | |||
| * Append all files found by a directory scanner to a vector. | |||
| * | |||
| * @param files Description of Parameter | |||
| * @param ds Description of Parameter | |||
| */ | |||
| protected void appendFiles( ArrayList files, DirectoryScanner ds ) | |||
| { | |||
| String[] dsfiles = ds.getIncludedFiles(); | |||
| for( int i = 0; i < dsfiles.length; i++ ) | |||
| { | |||
| files.add( dsfiles[ i ] ); | |||
| } | |||
| } | |||
| /* | |||
| * 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... | |||
| */ | |||
| protected void checkConfiguration() | |||
| throws TaskException | |||
| { | |||
| if( m_baseDir == null ) | |||
| { | |||
| throw new TaskException( "basedir attribute must be set!" ); | |||
| } | |||
| if( !m_baseDir.exists() ) | |||
| { | |||
| throw new TaskException( "basedir does not exist!" ); | |||
| } | |||
| if( m_cabFile == null ) | |||
| { | |||
| throw new TaskException( "cabfile attribute must be set!" ); | |||
| } | |||
| } | |||
| /** | |||
| * Create the cabarc command line to use. | |||
| */ | |||
| protected void createCommand( final Commandline cmd, final File listFile ) | |||
| throws TaskException | |||
| { | |||
| cmd.setExecutable( "cabarc" ); | |||
| cmd.addArgument( "-r" ); | |||
| cmd.addArgument( "-p" ); | |||
| if( !m_compress ) | |||
| { | |||
| cmd.addArgument( "-m" ); | |||
| cmd.addArgument( "none" ); | |||
| } | |||
| if( m_options != null ) | |||
| { | |||
| cmd.addLine( m_options ); | |||
| } | |||
| cmd.addArgument( "n" ); | |||
| cmd.addArgument( m_cabFile ); | |||
| cmd.addArgument( "@" + listFile.getAbsolutePath() ); | |||
| } | |||
| /** | |||
| * Creates a list file. This temporary file contains a list of all files to | |||
| * be included in the cab, one file per line. | |||
| * | |||
| * @param files Description of Parameter | |||
| * @return Description of the Returned Value | |||
| * @exception java.io.IOException Description of Exception | |||
| */ | |||
| protected File createListFile( ArrayList files ) | |||
| throws IOException | |||
| { | |||
| File listFile = File.createTempFile( "ant", "", getBaseDirectory() ); | |||
| PrintWriter writer = new PrintWriter( new FileOutputStream( listFile ) ); | |||
| for( int i = 0; i < files.size(); i++ ) | |||
| { | |||
| writer.println( files.get( i ).toString() ); | |||
| } | |||
| writer.close(); | |||
| return listFile; | |||
| } | |||
| } | |||
| @@ -1,23 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs; | |||
| public class ClassArgument | |||
| { | |||
| private String m_name; | |||
| public void setName( String name ) | |||
| { | |||
| m_name = name; | |||
| } | |||
| public String getName() | |||
| { | |||
| return m_name; | |||
| } | |||
| } | |||
| @@ -1,303 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs; | |||
| import java.io.File; | |||
| import java.util.ArrayList; | |||
| import java.util.Date; | |||
| import java.util.Iterator; | |||
| import org.apache.aut.nativelib.Os; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.FileSet; | |||
| import org.apache.tools.todo.types.DirectoryScanner; | |||
| import org.apache.tools.todo.types.ScannerUtil; | |||
| import org.apache.tools.todo.types.SimpleFileList; | |||
| /** | |||
| * A Task to record explicit dependencies. If any of the target files are out of | |||
| * date with respect to any of the source files, all target files are removed. | |||
| * This is useful where dependencies cannot be computed (for example, | |||
| * dynamically interpreted parameters or files that need to stay in synch but | |||
| * are not directly linked) or where the ant task in question could compute them | |||
| * but does not (for example, the linked DTD for an XML file using the style | |||
| * task). nested arguments: | |||
| * <ul> | |||
| * <li> srcfileset (fileset describing the source files to examine) | |||
| * <li> srcfilelist (filelist describing the source files to examine) | |||
| * <li> targetfileset (fileset describing the target files to examine) | |||
| * <li> targetfilelist (filelist describing the target files to examine) | |||
| * </ul> | |||
| * At least one instance of either a fileset or filelist for both source and | |||
| * target are required. <p> | |||
| * | |||
| * This task will examine each of the source files against each of the target | |||
| * files. If any target files are out of date with respect to any of the source | |||
| * files, all targets are removed. If any files named in a (src or target) | |||
| * filelist do not exist, all targets are removed. Hint: If missing files should | |||
| * be ignored, specify them as include patterns in filesets, rather than using | |||
| * filelists. </p> <p> | |||
| * | |||
| * This task attempts to optimize speed of dependency checking. It will stop | |||
| * after the first out of date file is found and remove all targets, rather than | |||
| * exhaustively checking every source vs target combination unnecessarily. </p> | |||
| * <p> | |||
| * | |||
| * Example uses: | |||
| * <ul> | |||
| * <li> Record the fact that an XML file must be up to date with respect to | |||
| * its XSD (Schema file), even though the XML file itself includes no | |||
| * reference to its XSD. </li> | |||
| * <li> Record the fact that an XSL stylesheet includes other sub-stylesheets | |||
| * </li> | |||
| * <li> Record the fact that java files must be recompiled if the ant build | |||
| * file changes </li> | |||
| * </ul> | |||
| * | |||
| * | |||
| * @author <a href="mailto:cstrong@arielpartners.com">Craeg Strong</a> | |||
| * @version $Revision$ $Date$ | |||
| */ | |||
| public class DependSet extends MatchingTask | |||
| { | |||
| private ArrayList sourceFileSets = new ArrayList(); | |||
| private ArrayList sourceFileLists = new ArrayList(); | |||
| private ArrayList targetFileSets = new ArrayList(); | |||
| private ArrayList targetFileLists = new ArrayList(); | |||
| /** | |||
| * Creates a new DependSet Task. | |||
| */ | |||
| public DependSet() | |||
| { | |||
| } | |||
| /** | |||
| * Nested <srcfilelist> element. | |||
| * | |||
| * @param fl The feature to be added to the Srcfilelist attribute | |||
| */ | |||
| public void addSrcfilelist( SimpleFileList fl ) | |||
| { | |||
| sourceFileLists.add( fl ); | |||
| }//-- DependSet | |||
| /** | |||
| * Nested <srcfileset> element. | |||
| * | |||
| * @param fs The feature to be added to the Srcfileset attribute | |||
| */ | |||
| public void addSrcfileset( FileSet fs ) | |||
| { | |||
| sourceFileSets.add( fs ); | |||
| } | |||
| /** | |||
| * Nested <targetfilelist> element. | |||
| * | |||
| * @param fl The feature to be added to the Targetfilelist attribute | |||
| */ | |||
| public void addTargetfilelist( SimpleFileList fl ) | |||
| { | |||
| targetFileLists.add( fl ); | |||
| } | |||
| /** | |||
| * Nested <targetfileset> element. | |||
| * | |||
| * @param fs The feature to be added to the Targetfileset attribute | |||
| */ | |||
| public void addTargetfileset( FileSet fs ) | |||
| { | |||
| targetFileSets.add( fs ); | |||
| } | |||
| /** | |||
| * Executes the task. | |||
| * | |||
| * @exception org.apache.myrmidon.api.TaskException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| if( ( sourceFileSets.size() == 0 ) && ( sourceFileLists.size() == 0 ) ) | |||
| { | |||
| throw new TaskException( "At least one <srcfileset> or <srcfilelist> element must be set" ); | |||
| } | |||
| if( ( targetFileSets.size() == 0 ) && ( targetFileLists.size() == 0 ) ) | |||
| { | |||
| throw new TaskException( "At least one <targetfileset> or <targetfilelist> element must be set" ); | |||
| } | |||
| long now = ( new Date() ).getTime(); | |||
| /* | |||
| * If we're on Windows, we have to munge the time up to 2 secs to | |||
| * be able to check file modification times. | |||
| * (Windows has a max resolution of two secs for modification times) | |||
| */ | |||
| if( Os.isFamily( Os.OS_FAMILY_WINDOWS ) ) | |||
| { | |||
| now += 2000; | |||
| } | |||
| // | |||
| // Grab all the target files specified via filesets | |||
| // | |||
| ArrayList allTargets = new ArrayList(); | |||
| Iterator enumTargetSets = targetFileSets.iterator(); | |||
| while( enumTargetSets.hasNext() ) | |||
| { | |||
| FileSet targetFS = (FileSet)enumTargetSets.next(); | |||
| DirectoryScanner targetDS = ScannerUtil.getDirectoryScanner( targetFS ); | |||
| String[] targetFiles = targetDS.getIncludedFiles(); | |||
| for( int i = 0; i < targetFiles.length; i++ ) | |||
| { | |||
| File dest = new File( targetFS.getDir(), targetFiles[ i ] ); | |||
| allTargets.add( dest ); | |||
| if( dest.lastModified() > now ) | |||
| { | |||
| getContext().warn( "Warning: " + targetFiles[ i ] + " modified in the future." ); | |||
| } | |||
| } | |||
| } | |||
| // | |||
| // Grab all the target files specified via filelists | |||
| // | |||
| boolean upToDate = true; | |||
| Iterator enumTargetLists = targetFileLists.iterator(); | |||
| while( enumTargetLists.hasNext() ) | |||
| { | |||
| SimpleFileList targetFL = (SimpleFileList)enumTargetLists.next(); | |||
| String[] targetFiles = targetFL.getFiles(); | |||
| for( int i = 0; i < targetFiles.length; i++ ) | |||
| { | |||
| File dest = new File( targetFL.getDir(), targetFiles[ i ] ); | |||
| if( !dest.exists() ) | |||
| { | |||
| getContext().debug( targetFiles[ i ] + " does not exist." ); | |||
| upToDate = false; | |||
| continue; | |||
| } | |||
| else | |||
| { | |||
| allTargets.add( dest ); | |||
| } | |||
| if( dest.lastModified() > now ) | |||
| { | |||
| getContext().warn( "Warning: " + targetFiles[ i ] + " modified in the future." ); | |||
| } | |||
| } | |||
| } | |||
| // | |||
| // Check targets vs source files specified via filesets | |||
| // | |||
| if( upToDate ) | |||
| { | |||
| Iterator enumSourceSets = sourceFileSets.iterator(); | |||
| while( upToDate && enumSourceSets.hasNext() ) | |||
| { | |||
| FileSet sourceFS = (FileSet)enumSourceSets.next(); | |||
| DirectoryScanner sourceDS = ScannerUtil.getDirectoryScanner( sourceFS ); | |||
| String[] sourceFiles = sourceDS.getIncludedFiles(); | |||
| for( int i = 0; upToDate && i < sourceFiles.length; i++ ) | |||
| { | |||
| File src = new File( sourceFS.getDir(), sourceFiles[ i ] ); | |||
| if( src.lastModified() > now ) | |||
| { | |||
| getContext().warn( "Warning: " + sourceFiles[ i ] + " modified in the future." ); | |||
| } | |||
| Iterator enumTargets = allTargets.iterator(); | |||
| while( upToDate && enumTargets.hasNext() ) | |||
| { | |||
| File dest = (File)enumTargets.next(); | |||
| if( src.lastModified() > dest.lastModified() ) | |||
| { | |||
| getContext().debug( dest.getPath() + " is out of date with respect to " + sourceFiles[ i ] ); | |||
| upToDate = false; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // | |||
| // Check targets vs source files specified via filelists | |||
| // | |||
| if( upToDate ) | |||
| { | |||
| Iterator enumSourceLists = sourceFileLists.iterator(); | |||
| while( upToDate && enumSourceLists.hasNext() ) | |||
| { | |||
| SimpleFileList sourceFL = (SimpleFileList)enumSourceLists.next(); | |||
| String[] sourceFiles = sourceFL.getFiles(); | |||
| int i = 0; | |||
| do | |||
| { | |||
| File src = new File( sourceFL.getDir(), sourceFiles[ i ] ); | |||
| if( src.lastModified() > now ) | |||
| { | |||
| getContext().warn( "Warning: " + sourceFiles[ i ] + " modified in the future." ); | |||
| } | |||
| if( !src.exists() ) | |||
| { | |||
| getContext().debug( sourceFiles[ i ] + " does not exist." ); | |||
| upToDate = false; | |||
| break; | |||
| } | |||
| Iterator enumTargets = allTargets.iterator(); | |||
| while( upToDate && enumTargets.hasNext() ) | |||
| { | |||
| File dest = (File)enumTargets.next(); | |||
| if( src.lastModified() > dest.lastModified() ) | |||
| { | |||
| getContext().debug( dest.getPath() + " is out of date with respect to " + sourceFiles[ i ] ); | |||
| upToDate = false; | |||
| } | |||
| } | |||
| } while( upToDate && ( ++i < sourceFiles.length ) ); | |||
| } | |||
| } | |||
| if( !upToDate ) | |||
| { | |||
| getContext().debug( "Deleting all target files. " ); | |||
| for( Iterator e = allTargets.iterator(); e.hasNext(); ) | |||
| { | |||
| File fileToRemove = (File)e.next(); | |||
| getContext().debug( "Deleting file " + fileToRemove.getAbsolutePath() ); | |||
| fileToRemove.delete(); | |||
| } | |||
| } | |||
| }//-- execute | |||
| }//-- DependSet.java | |||
| @@ -1,108 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs; | |||
| import java.io.File; | |||
| import java.io.FileWriter; | |||
| import java.io.IOException; | |||
| import org.apache.myrmidon.api.AbstractTask; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| /** | |||
| * Log | |||
| * | |||
| * @author costin@dnt.ro | |||
| */ | |||
| public class Echo | |||
| extends AbstractTask | |||
| { | |||
| private String m_message = "";// required | |||
| private File m_file; | |||
| private boolean m_append; | |||
| /** | |||
| * Shall we append to an existing file? | |||
| * | |||
| * @param append The new Append value | |||
| */ | |||
| public void setAppend( final boolean append ) | |||
| { | |||
| m_append = append; | |||
| } | |||
| /** | |||
| * Sets the file attribute. | |||
| * | |||
| * @param file The new File value | |||
| */ | |||
| public void setFile( final File file ) | |||
| { | |||
| m_file = file; | |||
| } | |||
| /** | |||
| * Sets the message variable. | |||
| * | |||
| * @param msg Sets the value for the message variable. | |||
| */ | |||
| public void setMessage( final String message ) | |||
| { | |||
| m_message = message; | |||
| } | |||
| /** | |||
| * Set a multiline message. | |||
| * | |||
| * @param msg The feature to be added to the Text attribute | |||
| */ | |||
| public void addContent( final String message ) | |||
| throws TaskException | |||
| { | |||
| m_message = message; | |||
| } | |||
| /** | |||
| * Does the work. | |||
| * | |||
| * @exception org.apache.myrmidon.api.TaskException if someting goes wrong with the build | |||
| */ | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| if( m_file == null ) | |||
| { | |||
| throw new TaskException( "Echo only used to write to files now !" ); | |||
| } | |||
| else | |||
| { | |||
| FileWriter out = null; | |||
| try | |||
| { | |||
| out = new FileWriter( m_file.getAbsolutePath(), m_append ); | |||
| out.write( m_message, 0, m_message.length() ); | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| throw new TaskException( "Error", ioe ); | |||
| } | |||
| finally | |||
| { | |||
| if( out != null ) | |||
| { | |||
| try | |||
| { | |||
| out.close(); | |||
| } | |||
| catch( IOException ioex ) | |||
| { | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -1,488 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs; | |||
| import java.text.DateFormat; | |||
| import java.text.DecimalFormat; | |||
| import java.text.ParseException; | |||
| import java.text.SimpleDateFormat; | |||
| import java.util.Calendar; | |||
| import java.util.Date; | |||
| import java.util.GregorianCalendar; | |||
| import java.util.Properties; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.tools.todo.types.EnumeratedAttribute; | |||
| /** | |||
| * Instance of this class represents nested elements of a task propertyfile. | |||
| */ | |||
| public class Entry | |||
| { | |||
| final static String NOW_VALUE_ = "now"; | |||
| final static String NULL_VALUE_ = "never"; | |||
| private final static int DEFAULT_INT_VALUE = 1; | |||
| private final static GregorianCalendar | |||
| DEFAULT_DATE_VALUE = new GregorianCalendar(); | |||
| private String m_key; | |||
| private int m_type = Type.STRING_TYPE; | |||
| private int m_operation = Operation.EQUALS_OPER; | |||
| private String m_value = ""; | |||
| private String m_default; | |||
| private String m_pattern; | |||
| public void setDefault( String value ) | |||
| { | |||
| this.m_default = value; | |||
| } | |||
| public void setKey( String value ) | |||
| { | |||
| this.m_key = value; | |||
| } | |||
| public void setOperation( Operation value ) | |||
| { | |||
| int newOperation = Operation.toOperation( value.getValue() ); | |||
| if( newOperation == Operation.NOW_VALUE ) | |||
| { | |||
| this.m_operation = Operation.EQUALS_OPER; | |||
| this.setValue( this.NOW_VALUE_ ); | |||
| } | |||
| else if( newOperation == Operation.NULL_VALUE ) | |||
| { | |||
| this.m_operation = Operation.EQUALS_OPER; | |||
| this.setValue( this.NULL_VALUE_ ); | |||
| } | |||
| else | |||
| { | |||
| this.m_operation = newOperation; | |||
| } | |||
| } | |||
| public void setPattern( String value ) | |||
| { | |||
| this.m_pattern = value; | |||
| } | |||
| public void setType( Type value ) | |||
| { | |||
| this.m_type = Type.toType( value.getValue() ); | |||
| } | |||
| public void setValue( String value ) | |||
| { | |||
| this.m_value = value; | |||
| } | |||
| protected void executeOn( Properties props ) | |||
| throws TaskException | |||
| { | |||
| checkParameters(); | |||
| // m_type may be null because it wasn't set | |||
| try | |||
| { | |||
| if( m_type == Type.INTEGER_TYPE ) | |||
| { | |||
| executeInteger( (String)props.get( m_key ) ); | |||
| } | |||
| else if( m_type == Type.DATE_TYPE ) | |||
| { | |||
| executeDate( (String)props.get( m_key ) ); | |||
| } | |||
| else if( m_type == Type.STRING_TYPE ) | |||
| { | |||
| executeString( (String)props.get( m_key ) ); | |||
| } | |||
| else | |||
| { | |||
| throw new TaskException( "Unknown operation type: " + m_type + "" ); | |||
| } | |||
| } | |||
| catch( NullPointerException npe ) | |||
| { | |||
| // Default to string type | |||
| // which means do nothing | |||
| npe.printStackTrace(); | |||
| } | |||
| // Insert as a string by default | |||
| props.put( m_key, m_value ); | |||
| } | |||
| /** | |||
| * Check if parameter combinations can be supported | |||
| * | |||
| * @exception org.apache.myrmidon.api.TaskException Description of Exception | |||
| */ | |||
| private void checkParameters() | |||
| throws TaskException | |||
| { | |||
| if( m_type == Type.STRING_TYPE && | |||
| m_operation == Operation.DECREMENT_OPER ) | |||
| { | |||
| throw new TaskException( "- is not suported for string properties (key:" + m_key + ")" ); | |||
| } | |||
| if( m_value == null && m_default == null ) | |||
| { | |||
| throw new TaskException( "value and/or default must be specified (key:" + m_key + ")" ); | |||
| } | |||
| if( m_key == null ) | |||
| { | |||
| throw new TaskException( "key is mandatory" ); | |||
| } | |||
| if( m_type == Type.STRING_TYPE && | |||
| m_pattern != null ) | |||
| { | |||
| throw new TaskException( "pattern is not suported for string properties (key:" + m_key + ")" ); | |||
| } | |||
| } | |||
| /** | |||
| * Handle operations for type <code>date</code>. | |||
| * | |||
| * @param oldValue the current value read from the property file or | |||
| * <code>null</code> if the <code>key</code> was not contained in | |||
| * the property file. | |||
| * @exception org.apache.myrmidon.api.TaskException Description of Exception | |||
| */ | |||
| private void executeDate( String oldValue ) | |||
| throws TaskException | |||
| { | |||
| GregorianCalendar value = new GregorianCalendar(); | |||
| GregorianCalendar newValue = new GregorianCalendar(); | |||
| if( m_pattern == null ) | |||
| { | |||
| m_pattern = "yyyy/MM/dd HH:mm"; | |||
| } | |||
| DateFormat fmt = new SimpleDateFormat( m_pattern ); | |||
| // special case | |||
| if( m_default != null && | |||
| NOW_VALUE_.equals( m_default.toLowerCase() ) && | |||
| ( m_operation == Operation.INCREMENT_OPER || | |||
| m_operation == Operation.DECREMENT_OPER ) ) | |||
| { | |||
| oldValue = null; | |||
| } | |||
| if( oldValue != null ) | |||
| { | |||
| try | |||
| { | |||
| value.setTime( fmt.parse( oldValue ) ); | |||
| } | |||
| catch( ParseException pe ) | |||
| { | |||
| /* | |||
| * swollow | |||
| */ | |||
| } | |||
| } | |||
| if( m_value != null ) | |||
| { | |||
| if( NOW_VALUE_.equals( m_value.toLowerCase() ) ) | |||
| { | |||
| value.setTime( new Date() ); | |||
| } | |||
| else if( NULL_VALUE_.equals( m_value.toLowerCase() ) ) | |||
| { | |||
| value = null; | |||
| } | |||
| else | |||
| { | |||
| try | |||
| { | |||
| value.setTime( fmt.parse( m_value ) ); | |||
| } | |||
| catch( Exception ex ) | |||
| { | |||
| // obviously not a date, try a simple int | |||
| try | |||
| { | |||
| int offset = Integer.parseInt( m_value ); | |||
| value.clear(); | |||
| value.set( Calendar.DAY_OF_YEAR, offset ); | |||
| } | |||
| catch( Exception ex_ ) | |||
| { | |||
| value.clear(); | |||
| value.set( Calendar.DAY_OF_YEAR, 1 ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| if( m_default != null && oldValue == null ) | |||
| { | |||
| if( NOW_VALUE_.equals( m_default.toLowerCase() ) ) | |||
| { | |||
| value.setTime( new Date() ); | |||
| } | |||
| else if( NULL_VALUE_.equals( m_default.toLowerCase() ) ) | |||
| { | |||
| value = null; | |||
| } | |||
| else | |||
| { | |||
| try | |||
| { | |||
| value.setTime( fmt.parse( m_default ) ); | |||
| } | |||
| catch( ParseException pe ) | |||
| { | |||
| /* | |||
| * swollow | |||
| */ | |||
| } | |||
| } | |||
| } | |||
| if( m_operation == Operation.EQUALS_OPER ) | |||
| { | |||
| newValue = value; | |||
| } | |||
| else if( m_operation == Operation.INCREMENT_OPER ) | |||
| { | |||
| newValue.add( Calendar.SECOND, value.get( Calendar.SECOND ) ); | |||
| newValue.add( Calendar.MINUTE, value.get( Calendar.MINUTE ) ); | |||
| newValue.add( Calendar.HOUR_OF_DAY, value.get( Calendar.HOUR_OF_DAY ) ); | |||
| newValue.add( Calendar.DAY_OF_YEAR, value.get( Calendar.DAY_OF_YEAR ) ); | |||
| } | |||
| else if( m_operation == Operation.DECREMENT_OPER ) | |||
| { | |||
| newValue.add( Calendar.SECOND, -1 * value.get( Calendar.SECOND ) ); | |||
| newValue.add( Calendar.MINUTE, -1 * value.get( Calendar.MINUTE ) ); | |||
| newValue.add( Calendar.HOUR_OF_DAY, -1 * value.get( Calendar.HOUR_OF_DAY ) ); | |||
| newValue.add( Calendar.DAY_OF_YEAR, -1 * value.get( Calendar.DAY_OF_YEAR ) ); | |||
| } | |||
| if( newValue != null ) | |||
| { | |||
| m_value = fmt.format( newValue.getTime() ); | |||
| } | |||
| else | |||
| { | |||
| m_value = ""; | |||
| } | |||
| } | |||
| /** | |||
| * Handle operations for type <code>int</code>. | |||
| * | |||
| * @param oldValue the current value read from the property file or | |||
| * <code>null</code> if the <code>key</code> was not contained in | |||
| * the property file. | |||
| * @exception org.apache.myrmidon.api.TaskException Description of Exception | |||
| */ | |||
| private void executeInteger( String oldValue ) | |||
| throws TaskException | |||
| { | |||
| int value = 0; | |||
| int newValue = 0; | |||
| DecimalFormat fmt = ( m_pattern != null ) ? new DecimalFormat( m_pattern ) | |||
| : new DecimalFormat(); | |||
| if( oldValue != null ) | |||
| { | |||
| try | |||
| { | |||
| value = fmt.parse( oldValue ).intValue(); | |||
| } | |||
| catch( NumberFormatException nfe ) | |||
| { | |||
| /* | |||
| * swollow | |||
| */ | |||
| } | |||
| catch( ParseException pe ) | |||
| { | |||
| /* | |||
| * swollow | |||
| */ | |||
| } | |||
| } | |||
| if( m_value != null ) | |||
| { | |||
| try | |||
| { | |||
| value = fmt.parse( m_value ).intValue(); | |||
| } | |||
| catch( NumberFormatException nfe ) | |||
| { | |||
| /* | |||
| * swollow | |||
| */ | |||
| } | |||
| catch( ParseException pe ) | |||
| { | |||
| /* | |||
| * swollow | |||
| */ | |||
| } | |||
| } | |||
| if( m_default != null && oldValue == null ) | |||
| { | |||
| try | |||
| { | |||
| value = fmt.parse( m_default ).intValue(); | |||
| } | |||
| catch( NumberFormatException nfe ) | |||
| { | |||
| /* | |||
| * swollow | |||
| */ | |||
| } | |||
| catch( ParseException pe ) | |||
| { | |||
| /* | |||
| * swollow | |||
| */ | |||
| } | |||
| } | |||
| if( m_operation == Operation.EQUALS_OPER ) | |||
| { | |||
| newValue = value; | |||
| } | |||
| else if( m_operation == Operation.INCREMENT_OPER ) | |||
| { | |||
| newValue = ++value; | |||
| } | |||
| else if( m_operation == Operation.DECREMENT_OPER ) | |||
| { | |||
| newValue = --value; | |||
| } | |||
| m_value = fmt.format( newValue ); | |||
| } | |||
| /** | |||
| * Handle operations for type <code>string</code>. | |||
| * | |||
| * @param oldValue the current value read from the property file or | |||
| * <code>null</code> if the <code>key</code> was not contained in | |||
| * the property file. | |||
| * @exception org.apache.myrmidon.api.TaskException Description of Exception | |||
| */ | |||
| private void executeString( String oldValue ) | |||
| throws TaskException | |||
| { | |||
| String value = ""; | |||
| String newValue = ""; | |||
| // the order of events is, of course, very important here | |||
| // default initially to the old value | |||
| if( oldValue != null ) | |||
| { | |||
| value = oldValue; | |||
| } | |||
| // but if a value is specified, use it | |||
| if( m_value != null ) | |||
| { | |||
| value = m_value; | |||
| } | |||
| // even if value is specified, ignore it and set to the default | |||
| // value if it is specified and there is no previous value | |||
| if( m_default != null && oldValue == null ) | |||
| { | |||
| value = m_default; | |||
| } | |||
| if( m_operation == Operation.EQUALS_OPER ) | |||
| { | |||
| newValue = value; | |||
| } | |||
| else if( m_operation == Operation.INCREMENT_OPER ) | |||
| { | |||
| newValue += value; | |||
| } | |||
| m_value = newValue; | |||
| } | |||
| /** | |||
| * Enumerated attribute with the values "+", "-", "=", "now" and | |||
| * "never". | |||
| * | |||
| * @author RT | |||
| */ | |||
| public static class Operation extends EnumeratedAttribute | |||
| { | |||
| // Property type operations | |||
| public final static int INCREMENT_OPER = 0; | |||
| public final static int DECREMENT_OPER = 1; | |||
| public final static int EQUALS_OPER = 2; | |||
| // Special values | |||
| public final static int NOW_VALUE = 3; | |||
| public final static int NULL_VALUE = 4; | |||
| public static int toOperation( String oper ) | |||
| { | |||
| if( "+".equals( oper ) ) | |||
| { | |||
| return INCREMENT_OPER; | |||
| } | |||
| else if( "-".equals( oper ) ) | |||
| { | |||
| return DECREMENT_OPER; | |||
| } | |||
| else if( NOW_VALUE_.equals( oper ) ) | |||
| { | |||
| return NOW_VALUE; | |||
| } | |||
| else if( NULL_VALUE_.equals( oper ) ) | |||
| { | |||
| return NULL_VALUE; | |||
| } | |||
| return EQUALS_OPER; | |||
| } | |||
| public String[] getValues() | |||
| { | |||
| return new String[]{"+", "-", "=", NOW_VALUE_, NULL_VALUE_}; | |||
| } | |||
| } | |||
| /** | |||
| * Enumerated attribute with the values "int", "date" and "string". | |||
| * | |||
| * @author RT | |||
| */ | |||
| public static class Type extends EnumeratedAttribute | |||
| { | |||
| // Property types | |||
| public final static int INTEGER_TYPE = 0; | |||
| public final static int DATE_TYPE = 1; | |||
| public final static int STRING_TYPE = 2; | |||
| public static int toType( String type ) | |||
| { | |||
| if( "int".equals( type ) ) | |||
| { | |||
| return INTEGER_TYPE; | |||
| } | |||
| else if( "date".equals( type ) ) | |||
| { | |||
| return DATE_TYPE; | |||
| } | |||
| return STRING_TYPE; | |||
| } | |||
| public String[] getValues() | |||
| { | |||
| return new String[]{"int", "date", "string"}; | |||
| } | |||
| } | |||
| } | |||
| @@ -1,36 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs; | |||
| import org.apache.tools.todo.types.EnumeratedAttribute; | |||
| public class FileDir | |||
| extends EnumeratedAttribute | |||
| { | |||
| private final static String[] values = {"file", "dir"}; | |||
| public String[] getValues() | |||
| { | |||
| return values; | |||
| } | |||
| public boolean isDir() | |||
| { | |||
| return "dir".equalsIgnoreCase( getValue() ); | |||
| } | |||
| public boolean isFile() | |||
| { | |||
| return "file".equalsIgnoreCase( getValue() ); | |||
| } | |||
| public String toString() | |||
| { | |||
| return getValue(); | |||
| } | |||
| } | |||
| @@ -1,381 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs; | |||
| import java.io.File; | |||
| import java.io.FileOutputStream; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.net.HttpURLConnection; | |||
| import java.net.URL; | |||
| import java.net.URLConnection; | |||
| import java.util.Date; | |||
| import org.apache.myrmidon.api.AbstractTask; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.api.TaskContext; | |||
| /** | |||
| * Get a particular file from a URL source. Options include verbose reporting, | |||
| * timestamp based fetches and controlling actions on failures. NB: access | |||
| * through a firewall only works if the whole Java runtime is correctly | |||
| * configured. | |||
| * | |||
| * @author costin@dnt.ro | |||
| * @author gg@grtmail.com (Added Java 1.1 style HTTP basic auth) | |||
| */ | |||
| public class Get extends AbstractTask | |||
| {// required | |||
| private boolean verbose = false; | |||
| private boolean useTimestamp = false;//off by default | |||
| private boolean ignoreErrors = false; | |||
| private String uname = null; | |||
| private String pword = null;// required | |||
| private File dest; | |||
| private URL source; | |||
| /** | |||
| * Where to copy the source file. | |||
| * | |||
| * @param dest Path to file. | |||
| */ | |||
| public void setDest( File dest ) | |||
| { | |||
| this.dest = dest; | |||
| } | |||
| /** | |||
| * Don't stop if get fails if set to "<CODE>true</CODE>". | |||
| * | |||
| * @param v if "true" then don't report download errors up to ant | |||
| */ | |||
| public void setIgnoreErrors( boolean v ) | |||
| { | |||
| ignoreErrors = v; | |||
| } | |||
| /** | |||
| * password for the basic auth. | |||
| * | |||
| * @param p password for authentication | |||
| */ | |||
| public void setPassword( String p ) | |||
| { | |||
| this.pword = p; | |||
| } | |||
| /** | |||
| * Set the URL. | |||
| * | |||
| * @param u URL for the file. | |||
| */ | |||
| public void setSrc( URL u ) | |||
| { | |||
| this.source = u; | |||
| } | |||
| /** | |||
| * Use timestamps, if set to "<CODE>true</CODE>". <p> | |||
| * | |||
| * In this situation, the if-modified-since header is set so that the file | |||
| * is only fetched if it is newer than the local file (or there is no local | |||
| * file) This flag is only valid on HTTP connections, it is ignored in other | |||
| * cases. When the flag is set, the local copy of the downloaded file will | |||
| * also have its timestamp set to the remote file time. <br> | |||
| * Note that remote files of date 1/1/1970 (GMT) are treated as 'no | |||
| * timestamp', and web servers often serve files with a timestamp in the | |||
| * future by replacing their timestamp with that of the current time. Also, | |||
| * inter-computer clock differences can cause no end of grief. | |||
| * | |||
| * @param v "true" to enable file time fetching | |||
| */ | |||
| public void setUseTimestamp( boolean v ) | |||
| { | |||
| useTimestamp = v; | |||
| } | |||
| /** | |||
| * Username for basic auth. | |||
| * | |||
| * @param u username for authentication | |||
| */ | |||
| public void setUsername( String u ) | |||
| { | |||
| this.uname = u; | |||
| } | |||
| /** | |||
| * Be verbose, if set to "<CODE>true</CODE>". | |||
| * | |||
| * @param v if "true" then be verbose | |||
| */ | |||
| public void setVerbose( boolean v ) | |||
| { | |||
| verbose = v; | |||
| } | |||
| /** | |||
| * Does the work. | |||
| * | |||
| * @exception org.apache.myrmidon.api.TaskException Thrown in unrecoverable error. | |||
| */ | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| if( source == null ) | |||
| { | |||
| throw new TaskException( "src attribute is required" ); | |||
| } | |||
| if( dest == null ) | |||
| { | |||
| throw new TaskException( "dest attribute is required" ); | |||
| } | |||
| if( dest.exists() && dest.isDirectory() ) | |||
| { | |||
| throw new TaskException( "The specified destination is a directory" ); | |||
| } | |||
| if( dest.exists() && !dest.canWrite() ) | |||
| { | |||
| throw new TaskException( "Can't write to " + dest.getAbsolutePath() ); | |||
| } | |||
| try | |||
| { | |||
| getContext().info( "Getting: " + source ); | |||
| //set the timestamp to the file date. | |||
| long timestamp = 0; | |||
| boolean hasTimestamp = false; | |||
| if( useTimestamp && dest.exists() ) | |||
| { | |||
| timestamp = dest.lastModified(); | |||
| if( verbose ) | |||
| { | |||
| Date t = new Date( timestamp ); | |||
| getContext().verbose( "local file date : " + t.toString() ); | |||
| } | |||
| hasTimestamp = true; | |||
| } | |||
| //set up the URL connection | |||
| URLConnection connection = source.openConnection(); | |||
| //modify the headers | |||
| //NB: things like user authentication could go in here too. | |||
| if( useTimestamp && hasTimestamp ) | |||
| { | |||
| connection.setIfModifiedSince( timestamp ); | |||
| } | |||
| // prepare Java 1.1 style credentials | |||
| if( uname != null || pword != null ) | |||
| { | |||
| String up = uname + ":" + pword; | |||
| String encoding; | |||
| // check to see if sun's Base64 encoder is available. | |||
| try | |||
| { | |||
| sun.misc.BASE64Encoder encoder = | |||
| (sun.misc.BASE64Encoder)Class.forName( "sun.misc.BASE64Encoder" ).newInstance(); | |||
| encoding = encoder.encode( up.getBytes() ); | |||
| } | |||
| catch( Exception ex ) | |||
| {// sun's base64 encoder isn't available | |||
| Base64Converter encoder = new Base64Converter(); | |||
| encoding = encoder.encode( up.getBytes() ); | |||
| } | |||
| connection.setRequestProperty( "Authorization", "Basic " + encoding ); | |||
| } | |||
| //connect to the remote site (may take some time) | |||
| connection.connect(); | |||
| //next test for a 304 result (HTTP only) | |||
| if( connection instanceof HttpURLConnection ) | |||
| { | |||
| HttpURLConnection httpConnection = (HttpURLConnection)connection; | |||
| if( httpConnection.getResponseCode() == HttpURLConnection.HTTP_NOT_MODIFIED ) | |||
| { | |||
| //not modified so no file download. just return instead | |||
| //and trace out something so the user doesn't think that the | |||
| //download happened when it didnt | |||
| getContext().verbose( "Not modified - so not downloaded" ); | |||
| return; | |||
| } | |||
| // test for 401 result (HTTP only) | |||
| if( httpConnection.getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED ) | |||
| { | |||
| getContext().info( "Not authorized - check " + dest + " for details" ); | |||
| return; | |||
| } | |||
| } | |||
| //REVISIT: at this point even non HTTP connections may support the if-modified-since | |||
| //behaviour -we just check the date of the content and skip the write if it is not | |||
| //newer. Some protocols (FTP) dont include dates, of course. | |||
| FileOutputStream fos = new FileOutputStream( dest ); | |||
| InputStream is = null; | |||
| for( int i = 0; i < 3; i++ ) | |||
| { | |||
| try | |||
| { | |||
| is = connection.getInputStream(); | |||
| break; | |||
| } | |||
| catch( IOException ex ) | |||
| { | |||
| getContext().info( "Error opening connection " + ex ); | |||
| } | |||
| } | |||
| if( is == null ) | |||
| { | |||
| getContext().info( "Can't get " + source + " to " + dest ); | |||
| if( ignoreErrors ) | |||
| { | |||
| return; | |||
| } | |||
| throw new TaskException( "Can't get " + source + " to " + dest ); | |||
| } | |||
| byte[] buffer = new byte[ 100 * 1024 ]; | |||
| int length; | |||
| while( ( length = is.read( buffer ) ) >= 0 ) | |||
| { | |||
| fos.write( buffer, 0, length ); | |||
| if( verbose ) | |||
| { | |||
| System.out.print( "." ); | |||
| } | |||
| } | |||
| if( verbose ) | |||
| { | |||
| System.out.println(); | |||
| } | |||
| fos.close(); | |||
| is.close(); | |||
| //if (and only if) the use file time option is set, then the | |||
| //saved file now has its timestamp set to that of the downloaded file | |||
| if( useTimestamp ) | |||
| { | |||
| long remoteTimestamp = connection.getLastModified(); | |||
| if( verbose ) | |||
| { | |||
| Date t = new Date( remoteTimestamp ); | |||
| getContext().verbose( "last modified = " + t.toString() | |||
| + ( ( remoteTimestamp == 0 ) ? " - using current time instead" : "" ) ); | |||
| } | |||
| if( remoteTimestamp != 0 ) | |||
| { | |||
| dest.setLastModified( remoteTimestamp ); | |||
| } | |||
| } | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| getContext().info( "Error getting " + source + " to " + dest ); | |||
| if( ignoreErrors ) | |||
| { | |||
| return; | |||
| } | |||
| throw new TaskException( "Error", ioe ); | |||
| } | |||
| } | |||
| /** | |||
| * BASE 64 encoding of a String or an array of bytes. Based on RFC 1421. | |||
| * | |||
| * @author Unknown | |||
| * @author <a HREF="gg@grtmail.com">Gautam Guliani</a> | |||
| */ | |||
| class Base64Converter | |||
| { | |||
| public final char[] alphabet = { | |||
| 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 0 to 7 | |||
| 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 8 to 15 | |||
| 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 16 to 23 | |||
| 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', // 24 to 31 | |||
| 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 32 to 39 | |||
| 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 40 to 47 | |||
| 'w', 'x', 'y', 'z', '0', '1', '2', '3', // 48 to 55 | |||
| '4', '5', '6', '7', '8', '9', '+', '/'};// 56 to 63 | |||
| public String encode( String s ) | |||
| { | |||
| return encode( s.getBytes() ); | |||
| } | |||
| public String encode( byte[] octetString ) | |||
| { | |||
| int bits24; | |||
| int bits6; | |||
| char[] out | |||
| = new char[ ( ( octetString.length - 1 ) / 3 + 1 ) * 4 ]; | |||
| int outIndex = 0; | |||
| int i = 0; | |||
| while( ( i + 3 ) <= octetString.length ) | |||
| { | |||
| // store the octets | |||
| bits24 = ( octetString[ i++ ] & 0xFF ) << 16; | |||
| bits24 |= ( octetString[ i++ ] & 0xFF ) << 8; | |||
| bits6 = ( bits24 & 0x00FC0000 ) >> 18; | |||
| out[ outIndex++ ] = alphabet[ bits6 ]; | |||
| bits6 = ( bits24 & 0x0003F000 ) >> 12; | |||
| out[ outIndex++ ] = alphabet[ bits6 ]; | |||
| bits6 = ( bits24 & 0x00000FC0 ) >> 6; | |||
| out[ outIndex++ ] = alphabet[ bits6 ]; | |||
| bits6 = ( bits24 & 0x0000003F ); | |||
| out[ outIndex++ ] = alphabet[ bits6 ]; | |||
| } | |||
| if( octetString.length - i == 2 ) | |||
| { | |||
| // store the octets | |||
| bits24 = ( octetString[ i ] & 0xFF ) << 16; | |||
| bits24 |= ( octetString[ i + 1 ] & 0xFF ) << 8; | |||
| bits6 = ( bits24 & 0x00FC0000 ) >> 18; | |||
| out[ outIndex++ ] = alphabet[ bits6 ]; | |||
| bits6 = ( bits24 & 0x0003F000 ) >> 12; | |||
| out[ outIndex++ ] = alphabet[ bits6 ]; | |||
| bits6 = ( bits24 & 0x00000FC0 ) >> 6; | |||
| out[ outIndex++ ] = alphabet[ bits6 ]; | |||
| // padding | |||
| out[ outIndex++ ] = '='; | |||
| } | |||
| else if( octetString.length - i == 1 ) | |||
| { | |||
| // store the octets | |||
| bits24 = ( octetString[ i ] & 0xFF ) << 16; | |||
| bits6 = ( bits24 & 0x00FC0000 ) >> 18; | |||
| out[ outIndex++ ] = alphabet[ bits6 ]; | |||
| bits6 = ( bits24 & 0x0003F000 ) >> 12; | |||
| out[ outIndex++ ] = alphabet[ bits6 ]; | |||
| // padding | |||
| out[ outIndex++ ] = '='; | |||
| out[ outIndex++ ] = '='; | |||
| } | |||
| return new String( out ); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,358 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs; | |||
| import java.io.File; | |||
| import java.util.ArrayList; | |||
| import java.util.Iterator; | |||
| import java.util.StringTokenizer; | |||
| import org.apache.avalon.excalibur.util.StringUtil; | |||
| import org.apache.myrmidon.api.AbstractTask; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.file.FileListUtil; | |||
| import org.apache.myrmidon.framework.file.Path; | |||
| import org.apache.myrmidon.framework.nativelib.ArgumentList; | |||
| import org.apache.tools.todo.util.FileUtils; | |||
| /** | |||
| * Task to generate JNI header files using javah. This task can take the | |||
| * following arguments: | |||
| * <ul> | |||
| * <li> classname - the fully-qualified name of a class</li> | |||
| * <li> outputFile - Concatenates the resulting header or source files for all | |||
| * the classes listed into this file</li> | |||
| * <li> destdir - Sets the directory where javah saves the header files or the | |||
| * stub files</li> | |||
| * <li> classpath</li> | |||
| * <li> bootclasspath</li> | |||
| * <li> force - Specifies that output files should always be written (JDK1.2 | |||
| * only)</li> | |||
| * <li> old - Specifies that old JDK1.0-style header files should be generated | |||
| * (otherwise output file contain JNI-style native method function prototypes) | |||
| * (JDK1.2 only)</li> | |||
| * <li> stubs - generate C declarations from the Java object file (used with | |||
| * old)</li> | |||
| * <li> verbose - causes javah to print a message to stdout concerning the | |||
| * status of the generated files</li> | |||
| * <li> extdirs - Override location of installed extensions</li> | |||
| * </ul> | |||
| * Of these arguments, either <b>outputFile</b> or <b>destdir</b> is required, | |||
| * but not both. More than one classname may be specified, using a | |||
| * comma-separated list or by using <code><class name="xxx"></code> | |||
| * elements within the task. <p> | |||
| * | |||
| * When this task executes, it will generate C header and source files that are | |||
| * needed to implement native methods. | |||
| * | |||
| * @author Rick Beton <a href="mailto:richard.beton@physics.org"> | |||
| * richard.beton@physics.org</a> | |||
| */ | |||
| public class Javah | |||
| extends AbstractTask | |||
| { | |||
| private final static String FAIL_MSG = "Compile failed, messages should have been provided."; | |||
| private ArrayList m_classes = new ArrayList( 2 ); | |||
| private Path m_classpath; | |||
| private File m_outputFile; | |||
| private boolean m_verbose; | |||
| private boolean m_force; | |||
| private boolean m_old; | |||
| private boolean m_stubs; | |||
| private Path m_bootclasspath; | |||
| private String m_cls; | |||
| private File m_destDir; | |||
| /** | |||
| * Adds an element to the bootclasspath. | |||
| */ | |||
| public void addBootclasspath( final Path bootclasspath ) | |||
| { | |||
| if( m_bootclasspath == null ) | |||
| { | |||
| m_bootclasspath = bootclasspath; | |||
| } | |||
| else | |||
| { | |||
| m_bootclasspath.add( bootclasspath ); | |||
| } | |||
| } | |||
| public void setClass( final String cls ) | |||
| { | |||
| m_cls = cls; | |||
| } | |||
| /** | |||
| * Adds an element to the classpath. | |||
| */ | |||
| public void addClasspath( final Path classpath ) | |||
| throws TaskException | |||
| { | |||
| if( m_classpath == null ) | |||
| { | |||
| m_classpath = classpath; | |||
| } | |||
| else | |||
| { | |||
| m_classpath.add( classpath ); | |||
| } | |||
| } | |||
| /** | |||
| * Set the destination directory into which the Java source files should be | |||
| * compiled. | |||
| * | |||
| * @param destDir The new Destdir value | |||
| */ | |||
| public void setDestdir( final File destDir ) | |||
| { | |||
| m_destDir = destDir; | |||
| } | |||
| /** | |||
| * Set the force-write flag. | |||
| */ | |||
| public void setForce( final boolean force ) | |||
| { | |||
| m_force = force; | |||
| } | |||
| /** | |||
| * Set the old flag. | |||
| */ | |||
| public void setOld( final boolean old ) | |||
| { | |||
| m_old = old; | |||
| } | |||
| /** | |||
| * Set the output file name. | |||
| */ | |||
| public void setOutputFile( final File outputFile ) | |||
| { | |||
| m_outputFile = outputFile; | |||
| } | |||
| /** | |||
| * Set the stubs flag. | |||
| */ | |||
| public void setStubs( final boolean stubs ) | |||
| { | |||
| m_stubs = stubs; | |||
| } | |||
| /** | |||
| * Set the verbose flag. | |||
| */ | |||
| public void setVerbose( final boolean verbose ) | |||
| { | |||
| m_verbose = verbose; | |||
| } | |||
| public ClassArgument createClass() | |||
| { | |||
| final ClassArgument ga = new ClassArgument(); | |||
| m_classes.add( ga ); | |||
| return ga; | |||
| } | |||
| /** | |||
| * Executes the task. | |||
| */ | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| validate(); | |||
| doClassicCompile(); | |||
| } | |||
| private void validate() throws TaskException | |||
| { | |||
| if( ( m_cls == null ) && ( m_classes.size() == 0 ) ) | |||
| { | |||
| final String message = "class attribute must be set!"; | |||
| throw new TaskException( message ); | |||
| } | |||
| if( ( m_cls != null ) && ( m_classes.size() > 0 ) ) | |||
| { | |||
| final String message = "set class attribute or class element, not both."; | |||
| throw new TaskException( message ); | |||
| } | |||
| if( m_destDir != null ) | |||
| { | |||
| if( !m_destDir.isDirectory() ) | |||
| { | |||
| final String message = "destination directory \"" + m_destDir + | |||
| "\" does not exist or is not a directory"; | |||
| throw new TaskException( message ); | |||
| } | |||
| if( m_outputFile != null ) | |||
| { | |||
| final String message = "destdir and outputFile are mutually exclusive"; | |||
| throw new TaskException( message ); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Logs the compilation parameters, adds the files to compile and logs the | |||
| * &qout;niceSourceList" | |||
| */ | |||
| private void logAndAddFilesToCompile( final ArgumentList cmd ) | |||
| throws TaskException | |||
| { | |||
| final String[] args = cmd.getArguments(); | |||
| getContext().debug( "Compilation args: " + FileUtils.formatCommandLine( args ) ); | |||
| int n = 0; | |||
| StringBuffer niceClassList = new StringBuffer(); | |||
| if( m_cls != null ) | |||
| { | |||
| final StringTokenizer tok = new StringTokenizer( m_cls, ",", false ); | |||
| while( tok.hasMoreTokens() ) | |||
| { | |||
| final String aClass = tok.nextToken().trim(); | |||
| cmd.addArgument( aClass ); | |||
| niceClassList.append( " " + aClass + StringUtil.LINE_SEPARATOR ); | |||
| n++; | |||
| } | |||
| } | |||
| final Iterator enum = m_classes.iterator(); | |||
| while( enum.hasNext() ) | |||
| { | |||
| final ClassArgument arg = (ClassArgument)enum.next(); | |||
| final String aClass = arg.getName(); | |||
| cmd.addArgument( aClass ); | |||
| niceClassList.append( " " + aClass + StringUtil.LINE_SEPARATOR ); | |||
| n++; | |||
| } | |||
| final StringBuffer prefix = new StringBuffer( "Class" ); | |||
| if( n > 1 ) | |||
| { | |||
| prefix.append( "es" ); | |||
| } | |||
| prefix.append( " to be compiled:" ); | |||
| prefix.append( StringUtil.LINE_SEPARATOR ); | |||
| getContext().debug( prefix.toString() + niceClassList.toString() ); | |||
| } | |||
| /** | |||
| * Does the command line argument processing common to classic and modern. | |||
| */ | |||
| private ArgumentList setupJavahCommand() | |||
| throws TaskException | |||
| { | |||
| final ArgumentList cmd = new ArgumentList(); | |||
| if( m_destDir != null ) | |||
| { | |||
| cmd.addArgument( "-d" ); | |||
| cmd.addArgument( m_destDir ); | |||
| } | |||
| if( m_outputFile != null ) | |||
| { | |||
| cmd.addArgument( "-o" ); | |||
| cmd.addArgument( m_outputFile ); | |||
| } | |||
| if( m_classpath != null ) | |||
| { | |||
| cmd.addArgument( "-classpath" ); | |||
| cmd.addArgument( FileListUtil.formatPath( m_classpath, getContext() ) ); | |||
| } | |||
| if( m_verbose ) | |||
| { | |||
| cmd.addArgument( "-verbose" ); | |||
| } | |||
| if( m_old ) | |||
| { | |||
| cmd.addArgument( "-old" ); | |||
| } | |||
| if( m_force ) | |||
| { | |||
| cmd.addArgument( "-force" ); | |||
| } | |||
| if( m_stubs ) | |||
| { | |||
| if( !m_old ) | |||
| { | |||
| final String message = "stubs only available in old mode."; | |||
| throw new TaskException( message ); | |||
| } | |||
| cmd.addArgument( "-stubs" ); | |||
| } | |||
| if( m_bootclasspath != null ) | |||
| { | |||
| cmd.addArgument( "-bootclasspath" ); | |||
| cmd.addArgument( FileListUtil.formatPath( m_bootclasspath, getContext() ) ); | |||
| } | |||
| logAndAddFilesToCompile( cmd ); | |||
| return cmd; | |||
| } | |||
| /** | |||
| * Peforms a compile using the classic compiler that shipped with JDK 1.1 | |||
| * and 1.2. | |||
| * | |||
| * @exception org.apache.myrmidon.api.TaskException Description of Exception | |||
| */ | |||
| private void doClassicCompile() | |||
| throws TaskException | |||
| { | |||
| ArgumentList cmd = setupJavahCommand(); | |||
| // Use reflection to be able to build on all JDKs | |||
| /* | |||
| * / provide the compiler a different message sink - namely our own | |||
| * sun.tools.javac.Main compiler = | |||
| * new sun.tools.javac.Main(new LogOutputStream(this, Project.MSG_WARN), "javac"); | |||
| * if (!compiler.compile(cmd.getArguments())) { | |||
| * throw new TaskException("Compile failed"); | |||
| * } | |||
| */ | |||
| try | |||
| { | |||
| // Javac uses logstr to change the output stream and calls | |||
| // the constructor's invoke method to create a compiler instance | |||
| // dynamically. However, javah has a different interface and this | |||
| // makes it harder, so here's a simple alternative. | |||
| //------------------------------------------------------------------ | |||
| com.sun.tools.javah.Main main = new com.sun.tools.javah.Main( cmd.getArguments() ); | |||
| main.run(); | |||
| } | |||
| //catch (ClassNotFoundException ex) { | |||
| // throw new TaskException("Cannot use javah because it is not available"+ | |||
| // " A common solution is to set the environment variable"+ | |||
| // " JAVA_HOME to your jdk directory.", location); | |||
| //} | |||
| catch( Exception ex ) | |||
| { | |||
| if( ex instanceof TaskException ) | |||
| { | |||
| throw (TaskException)ex; | |||
| } | |||
| else | |||
| { | |||
| throw new TaskException( "Error starting javah: ", ex ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -1,101 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs; | |||
| import java.io.File; | |||
| import org.apache.myrmidon.api.AbstractTask; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.Pattern; | |||
| import org.apache.myrmidon.framework.PatternSet; | |||
| import org.apache.myrmidon.framework.FileSet; | |||
| import org.apache.tools.todo.types.DirectoryScanner; | |||
| import org.apache.tools.todo.types.ScannerUtil; | |||
| /** | |||
| * This is an abstract task that should be used by all those tasks that require | |||
| * to include or exclude files based on pattern matching. | |||
| * | |||
| * @author <a href="mailto:ajkuiper@wxs.nl">Arnout J. Kuiper</a> | |||
| * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a> | |||
| * @author <a href="mailto:rubys@us.ibm.com">Sam Ruby</a> | |||
| * @author <a href="mailto:jon@clearink.com">Jon S. Stevens</a> | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| */ | |||
| public abstract class MatchingTask | |||
| extends AbstractTask | |||
| { | |||
| private FileSet m_fileset = new FileSet(); | |||
| /** | |||
| * Sets whether default exclusions should be used or not. | |||
| */ | |||
| public void setDefaultexcludes( final boolean useDefaultExcludes ) | |||
| { | |||
| m_fileset.setDefaultExcludes( useDefaultExcludes ); | |||
| } | |||
| /** | |||
| * Sets the set of exclude patterns. Patterns may be separated by a comma or | |||
| * a space. | |||
| * | |||
| * @param excludes the string containing the exclude patterns | |||
| */ | |||
| public void setExcludes( final String excludes ) | |||
| { | |||
| m_fileset.setExcludes( excludes ); | |||
| } | |||
| /** | |||
| * Sets the set of include patterns. Patterns may be separated by a comma or | |||
| * a space. | |||
| * | |||
| * @param includes the string containing the include patterns | |||
| */ | |||
| public void setIncludes( final String includes ) | |||
| { | |||
| m_fileset.setIncludes( includes ); | |||
| } | |||
| /** | |||
| * add a name entry on the exclude list | |||
| */ | |||
| public void addExclude( final Pattern pattern ) | |||
| { | |||
| m_fileset.addExclude( pattern ); | |||
| } | |||
| /** | |||
| * add a name entry on the include list | |||
| */ | |||
| public void addInclude( final Pattern pattern ) | |||
| throws TaskException | |||
| { | |||
| m_fileset.addInclude( pattern ); | |||
| } | |||
| /** | |||
| * add a set of patterns | |||
| */ | |||
| public void addPatternSet( final PatternSet set ) | |||
| { | |||
| m_fileset.addPatternSet( set ); | |||
| } | |||
| /** | |||
| * Returns the directory scanner needed to access the files to process. | |||
| * | |||
| * @param baseDir Description of Parameter | |||
| * @return The DirectoryScanner value | |||
| */ | |||
| protected DirectoryScanner getDirectoryScanner( final File baseDir ) | |||
| throws TaskException | |||
| { | |||
| m_fileset.setDir( baseDir ); | |||
| return ScannerUtil.getDirectoryScanner( m_fileset ); | |||
| } | |||
| } | |||
| @@ -1,770 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import java.io.PrintWriter; | |||
| import java.io.StringWriter; | |||
| import java.util.ArrayList; | |||
| import java.util.Hashtable; | |||
| import java.util.Iterator; | |||
| import java.util.Properties; | |||
| import java.util.StringTokenizer; | |||
| import netrexx.lang.Rexx; | |||
| import org.apache.avalon.excalibur.io.FileUtil; | |||
| import org.apache.avalon.excalibur.util.StringUtil; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.api.AbstractTask; | |||
| import org.apache.myrmidon.api.TaskContext; | |||
| import org.apache.tools.todo.taskdefs.MatchingTask; | |||
| import org.apache.tools.todo.types.DirectoryScanner; | |||
| /** | |||
| * Task to compile NetRexx source files. This task can take the following | |||
| * arguments: | |||
| * <ul> | |||
| * <li> binary</li> | |||
| * <li> classpath</li> | |||
| * <li> comments</li> | |||
| * <li> compile</li> | |||
| * <li> console</li> | |||
| * <li> crossref</li> | |||
| * <li> decimal</li> | |||
| * <li> destdir</li> | |||
| * <li> diag</li> | |||
| * <li> explicit</li> | |||
| * <li> format</li> | |||
| * <li> keep</li> | |||
| * <li> logo</li> | |||
| * <li> replace</li> | |||
| * <li> savelog</li> | |||
| * <li> srcdir</li> | |||
| * <li> sourcedir</li> | |||
| * <li> strictargs</li> | |||
| * <li> strictassign</li> | |||
| * <li> strictcase</li> | |||
| * <li> strictimport</li> | |||
| * <li> symbols</li> | |||
| * <li> time</li> | |||
| * <li> trace</li> | |||
| * <li> utf8</li> | |||
| * <li> verbose</li> | |||
| * </ul> | |||
| * Of these arguments, the <b>srcdir</b> argument is required. <p> | |||
| * | |||
| * When this task executes, it will recursively scan the srcdir looking for | |||
| * NetRexx source files to compile. This task makes its compile decision based | |||
| * on timestamp. <p> | |||
| * | |||
| * Before files are compiled they and any other file in the srcdir will be | |||
| * copied to the destdir allowing support files to be located properly in the | |||
| * classpath. The reason for copying the source files before the compile is that | |||
| * NetRexxC has only two destinations for classfiles: | |||
| * <ol> | |||
| * <li> The current directory, and,</li> | |||
| * <li> The directory the source is in (see sourcedir option) | |||
| * </ol> | |||
| * | |||
| * | |||
| * @author dIon Gillard <a href="mailto:dion@multitask.com.au"> | |||
| * dion@multitask.com.au</a> | |||
| */ | |||
| public class NetRexxC extends MatchingTask | |||
| { | |||
| private boolean compile = true; | |||
| private boolean decimal = true; | |||
| private boolean logo = true; | |||
| private boolean sourcedir = true; | |||
| private String trace = "trace2"; | |||
| private String verbose = "verbose3"; | |||
| // other implementation variables | |||
| private ArrayList compileList = new ArrayList(); | |||
| private Hashtable filecopyList = new Hashtable(); | |||
| private String oldClasspath = System.getProperty( "java.class.path" ); | |||
| // variables to hold arguments | |||
| private boolean binary; | |||
| private String classpath; | |||
| private boolean comments; | |||
| private boolean compact; | |||
| private boolean console; | |||
| private boolean crossref; | |||
| private File destDir; | |||
| private boolean diag; | |||
| private boolean explicit; | |||
| private boolean format; | |||
| private boolean java; | |||
| private boolean keep; | |||
| private boolean replace; | |||
| private boolean savelog; | |||
| private File srcDir;// ?? Should this be the default for ant? | |||
| private boolean strictargs; | |||
| private boolean strictassign; | |||
| private boolean strictcase; | |||
| private boolean strictimport; | |||
| private boolean strictprops; | |||
| private boolean strictsignal; | |||
| private boolean symbols; | |||
| private boolean time; | |||
| private boolean utf8; | |||
| /** | |||
| * Set whether literals are treated as binary, rather than NetRexx types | |||
| * | |||
| * @param binary The new Binary value | |||
| */ | |||
| public void setBinary( boolean binary ) | |||
| { | |||
| this.binary = binary; | |||
| } | |||
| /** | |||
| * Set the classpath used for NetRexx compilation | |||
| * | |||
| * @param classpath The new Classpath value | |||
| */ | |||
| public void setClasspath( String classpath ) | |||
| { | |||
| this.classpath = classpath; | |||
| } | |||
| /** | |||
| * Set whether comments are passed through to the generated java source. | |||
| * Valid true values are "on" or "true". Anything else sets the flag to | |||
| * false. The default value is false | |||
| * | |||
| * @param comments The new Comments value | |||
| */ | |||
| public void setComments( boolean comments ) | |||
| { | |||
| this.comments = comments; | |||
| } | |||
| /** | |||
| * Set whether error messages come out in compact or verbose format. Valid | |||
| * true values are "on" or "true". Anything else sets the flag to false. The | |||
| * default value is false | |||
| * | |||
| * @param compact The new Compact value | |||
| */ | |||
| public void setCompact( boolean compact ) | |||
| { | |||
| this.compact = compact; | |||
| } | |||
| /** | |||
| * Set whether the NetRexx compiler should compile the generated java code | |||
| * Valid true values are "on" or "true". Anything else sets the flag to | |||
| * false. The default value is true. Setting this flag to false, will | |||
| * automatically set the keep flag to true. | |||
| * | |||
| * @param compile The new Compile value | |||
| */ | |||
| public void setCompile( boolean compile ) | |||
| { | |||
| this.compile = compile; | |||
| if( !this.compile && !this.keep ) | |||
| { | |||
| this.keep = true; | |||
| } | |||
| } | |||
| /** | |||
| * Set whether or not messages should be displayed on the 'console' Valid | |||
| * true values are "on" or "true". Anything else sets the flag to false. The | |||
| * default value is true. | |||
| * | |||
| * @param console The new Console value | |||
| */ | |||
| public void setConsole( boolean console ) | |||
| { | |||
| this.console = console; | |||
| } | |||
| /** | |||
| * Whether variable cross references are generated | |||
| * | |||
| * @param crossref The new Crossref value | |||
| */ | |||
| public void setCrossref( boolean crossref ) | |||
| { | |||
| this.crossref = crossref; | |||
| } | |||
| /** | |||
| * Set whether decimal arithmetic should be used for the netrexx code. | |||
| * Binary arithmetic is used when this flag is turned off. Valid true values | |||
| * are "on" or "true". Anything else sets the flag to false. The default | |||
| * value is true. | |||
| * | |||
| * @param decimal The new Decimal value | |||
| */ | |||
| public void setDecimal( boolean decimal ) | |||
| { | |||
| this.decimal = decimal; | |||
| } | |||
| /** | |||
| * Set the destination directory into which the NetRexx source files should | |||
| * be copied and then compiled. | |||
| * | |||
| * @param destDirName The new DestDir value | |||
| */ | |||
| public void setDestDir( File destDirName ) | |||
| { | |||
| destDir = destDirName; | |||
| } | |||
| /** | |||
| * Whether diagnostic information about the compile is generated | |||
| * | |||
| * @param diag The new Diag value | |||
| */ | |||
| public void setDiag( boolean diag ) | |||
| { | |||
| this.diag = diag; | |||
| } | |||
| /** | |||
| * Sets whether variables must be declared explicitly before use. Valid true | |||
| * values are "on" or "true". Anything else sets the flag to false. The | |||
| * default value is false. | |||
| * | |||
| * @param explicit The new Explicit value | |||
| */ | |||
| public void setExplicit( boolean explicit ) | |||
| { | |||
| this.explicit = explicit; | |||
| } | |||
| /** | |||
| * Whether the generated java code is formatted nicely or left to match | |||
| * NetRexx line numbers for call stack debugging | |||
| * | |||
| * @param format The new Format value | |||
| */ | |||
| public void setFormat( boolean format ) | |||
| { | |||
| this.format = format; | |||
| } | |||
| /** | |||
| * Whether the generated java code is produced Valid true values are "on" or | |||
| * "true". Anything else sets the flag to false. The default value is false. | |||
| * | |||
| * @param java The new Java value | |||
| */ | |||
| public void setJava( boolean java ) | |||
| { | |||
| this.java = java; | |||
| } | |||
| /** | |||
| * Sets whether the generated java source file should be kept after | |||
| * compilation. The generated files will have an extension of .java.keep, | |||
| * <b>not</b> .java Valid true values are "on" or "true". Anything else sets | |||
| * the flag to false. The default value is false. | |||
| * | |||
| * @param keep The new Keep value | |||
| */ | |||
| public void setKeep( boolean keep ) | |||
| { | |||
| this.keep = keep; | |||
| } | |||
| /** | |||
| * Whether the compiler text logo is displayed when compiling | |||
| * | |||
| * @param logo The new Logo value | |||
| */ | |||
| public void setLogo( boolean logo ) | |||
| { | |||
| this.logo = logo; | |||
| } | |||
| /** | |||
| * Whether the generated .java file should be replaced when compiling Valid | |||
| * true values are "on" or "true". Anything else sets the flag to false. The | |||
| * default value is false. | |||
| * | |||
| * @param replace The new Replace value | |||
| */ | |||
| public void setReplace( boolean replace ) | |||
| { | |||
| this.replace = replace; | |||
| } | |||
| /** | |||
| * Sets whether the compiler messages will be written to NetRexxC.log as | |||
| * well as to the console Valid true values are "on" or "true". Anything | |||
| * else sets the flag to false. The default value is false. | |||
| * | |||
| * @param savelog The new Savelog value | |||
| */ | |||
| public void setSavelog( boolean savelog ) | |||
| { | |||
| this.savelog = savelog; | |||
| } | |||
| /** | |||
| * Tells the NetRexx compiler to store the class files in the same directory | |||
| * as the source files. The alternative is the working directory Valid true | |||
| * values are "on" or "true". Anything else sets the flag to false. The | |||
| * default value is true. | |||
| * | |||
| * @param sourcedir The new Sourcedir value | |||
| */ | |||
| public void setSourcedir( boolean sourcedir ) | |||
| { | |||
| this.sourcedir = sourcedir; | |||
| } | |||
| /** | |||
| * Set the source dir to find the source Java files. | |||
| * | |||
| * @param srcDirName The new SrcDir value | |||
| */ | |||
| public void setSrcDir( File srcDirName ) | |||
| { | |||
| srcDir = srcDirName; | |||
| } | |||
| /** | |||
| * Tells the NetRexx compiler that method calls always need parentheses, | |||
| * even if no arguments are needed, e.g. <code>aStringVar.getBytes</code> | |||
| * vs. <code>aStringVar.getBytes()</code> Valid true values are "on" or | |||
| * "true". Anything else sets the flag to false. The default value is false. | |||
| * | |||
| * @param strictargs The new Strictargs value | |||
| */ | |||
| public void setStrictargs( boolean strictargs ) | |||
| { | |||
| this.strictargs = strictargs; | |||
| } | |||
| /** | |||
| * Tells the NetRexx compile that assignments must match exactly on type | |||
| * | |||
| * @param strictassign The new Strictassign value | |||
| */ | |||
| public void setStrictassign( boolean strictassign ) | |||
| { | |||
| this.strictassign = strictassign; | |||
| } | |||
| /** | |||
| * Specifies whether the NetRexx compiler should be case sensitive or not | |||
| * | |||
| * @param strictcase The new Strictcase value | |||
| */ | |||
| public void setStrictcase( boolean strictcase ) | |||
| { | |||
| this.strictcase = strictcase; | |||
| } | |||
| /** | |||
| * Sets whether classes need to be imported explicitly using an <code>import</code> | |||
| * statement. By default the NetRexx compiler will import certain packages | |||
| * automatically Valid true values are "on" or "true". Anything else sets | |||
| * the flag to false. The default value is false. | |||
| * | |||
| * @param strictimport The new Strictimport value | |||
| */ | |||
| public void setStrictimport( boolean strictimport ) | |||
| { | |||
| this.strictimport = strictimport; | |||
| } | |||
| /** | |||
| * Sets whether local properties need to be qualified explicitly using | |||
| * <code>this</code> Valid true values are "on" or "true". Anything else | |||
| * sets the flag to false. The default value is false. | |||
| * | |||
| * @param strictprops The new Strictprops value | |||
| */ | |||
| public void setStrictprops( boolean strictprops ) | |||
| { | |||
| this.strictprops = strictprops; | |||
| } | |||
| /** | |||
| * Whether the compiler should force catching of exceptions by explicitly | |||
| * named types | |||
| * | |||
| * @param strictsignal The new Strictsignal value | |||
| */ | |||
| public void setStrictsignal( boolean strictsignal ) | |||
| { | |||
| this.strictsignal = strictsignal; | |||
| } | |||
| /** | |||
| * Sets whether debug symbols should be generated into the class file Valid | |||
| * true values are "on" or "true". Anything else sets the flag to false. The | |||
| * default value is false. | |||
| * | |||
| * @param symbols The new Symbols value | |||
| */ | |||
| public void setSymbols( boolean symbols ) | |||
| { | |||
| this.symbols = symbols; | |||
| } | |||
| /** | |||
| * Asks the NetRexx compiler to print compilation times to the console Valid | |||
| * true values are "on" or "true". Anything else sets the flag to false. The | |||
| * default value is false. | |||
| * | |||
| * @param time The new Time value | |||
| */ | |||
| public void setTime( boolean time ) | |||
| { | |||
| this.time = time; | |||
| } | |||
| /** | |||
| * Turns on or off tracing and directs the resultant trace output Valid | |||
| * values are: "trace", "trace1", "trace2" and "notrace". "trace" and | |||
| * "trace2" | |||
| * | |||
| * @param trace The new Trace value | |||
| */ | |||
| public void setTrace( String trace ) | |||
| { | |||
| if( trace.equalsIgnoreCase( "trace" ) | |||
| || trace.equalsIgnoreCase( "trace1" ) | |||
| || trace.equalsIgnoreCase( "trace2" ) | |||
| || trace.equalsIgnoreCase( "notrace" ) ) | |||
| { | |||
| this.trace = trace; | |||
| } | |||
| else | |||
| { | |||
| throw new TaskException( "Unknown trace value specified: '" + trace + "'" ); | |||
| } | |||
| } | |||
| /** | |||
| * Tells the NetRexx compiler that the source is in UTF8 Valid true values | |||
| * are "on" or "true". Anything else sets the flag to false. The default | |||
| * value is false. | |||
| * | |||
| * @param utf8 The new Utf8 value | |||
| */ | |||
| public void setUtf8( boolean utf8 ) | |||
| { | |||
| this.utf8 = utf8; | |||
| } | |||
| /** | |||
| * Whether lots of warnings and error messages should be generated | |||
| * | |||
| * @param verbose The new Verbose value | |||
| */ | |||
| public void setVerbose( String verbose ) | |||
| { | |||
| this.verbose = verbose; | |||
| } | |||
| /** | |||
| * Executes the task, i.e. does the actual compiler call | |||
| * | |||
| * @exception org.apache.myrmidon.api.TaskException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| // first off, make sure that we've got a srcdir and destdir | |||
| if( srcDir == null || destDir == null ) | |||
| { | |||
| throw new TaskException( "srcDir and destDir attributes must be set!" ); | |||
| } | |||
| // scan source and dest dirs to build up both copy lists and | |||
| // compile lists | |||
| // scanDir(srcDir, destDir); | |||
| DirectoryScanner ds = getDirectoryScanner( srcDir ); | |||
| String[] files = ds.getIncludedFiles(); | |||
| scanDir( srcDir, destDir, files ); | |||
| // copy the source and support files | |||
| copyFilesToDestination(); | |||
| // compile the source files | |||
| if( compileList.size() > 0 ) | |||
| { | |||
| getContext().info( "Compiling " + compileList.size() + " source file" | |||
| + ( compileList.size() == 1 ? "" : "s" ) | |||
| + " to " + destDir ); | |||
| doNetRexxCompile(); | |||
| } | |||
| } | |||
| /** | |||
| * Builds the compilation classpath. | |||
| * | |||
| * @return The CompileClasspath value | |||
| */ | |||
| private String getCompileClasspath() | |||
| throws TaskException | |||
| { | |||
| StringBuffer classpath = new StringBuffer(); | |||
| // add dest dir to classpath so that previously compiled and | |||
| // untouched classes are on classpath | |||
| classpath.append( destDir.getAbsolutePath() ); | |||
| // add our classpath to the mix | |||
| if( this.classpath != null ) | |||
| { | |||
| addExistingToClasspath( classpath, this.classpath ); | |||
| } | |||
| // add the system classpath | |||
| // addExistingToClasspath(classpath,System.getProperty("java.class.path")); | |||
| return classpath.toString(); | |||
| } | |||
| /** | |||
| * This | |||
| * | |||
| * @return The CompileOptionsAsArray value | |||
| */ | |||
| private String[] getCompileOptionsAsArray() | |||
| { | |||
| ArrayList options = new ArrayList(); | |||
| options.add( binary ? "-binary" : "-nobinary" ); | |||
| options.add( comments ? "-comments" : "-nocomments" ); | |||
| options.add( compile ? "-compile" : "-nocompile" ); | |||
| options.add( compact ? "-compact" : "-nocompact" ); | |||
| options.add( console ? "-console" : "-noconsole" ); | |||
| options.add( crossref ? "-crossref" : "-nocrossref" ); | |||
| options.add( decimal ? "-decimal" : "-nodecimal" ); | |||
| options.add( diag ? "-diag" : "-nodiag" ); | |||
| options.add( explicit ? "-explicit" : "-noexplicit" ); | |||
| options.add( format ? "-format" : "-noformat" ); | |||
| options.add( keep ? "-keep" : "-nokeep" ); | |||
| options.add( logo ? "-logo" : "-nologo" ); | |||
| options.add( replace ? "-replace" : "-noreplace" ); | |||
| options.add( savelog ? "-savelog" : "-nosavelog" ); | |||
| options.add( sourcedir ? "-sourcedir" : "-nosourcedir" ); | |||
| options.add( strictargs ? "-strictargs" : "-nostrictargs" ); | |||
| options.add( strictassign ? "-strictassign" : "-nostrictassign" ); | |||
| options.add( strictcase ? "-strictcase" : "-nostrictcase" ); | |||
| options.add( strictimport ? "-strictimport" : "-nostrictimport" ); | |||
| options.add( strictprops ? "-strictprops" : "-nostrictprops" ); | |||
| options.add( strictsignal ? "-strictsignal" : "-nostrictsignal" ); | |||
| options.add( symbols ? "-symbols" : "-nosymbols" ); | |||
| options.add( time ? "-time" : "-notime" ); | |||
| options.add( "-" + trace ); | |||
| options.add( utf8 ? "-utf8" : "-noutf8" ); | |||
| options.add( "-" + verbose ); | |||
| String[] results = new String[ options.size() ]; | |||
| options.copyInto( results ); | |||
| return results; | |||
| } | |||
| /** | |||
| * Takes a classpath-like string, and adds each element of this string to a | |||
| * new classpath, if the components exist. Components that don't exist, | |||
| * aren't added. We do this, because jikes issues warnings for non-existant | |||
| * files/dirs in his classpath, and these warnings are pretty annoying. | |||
| * | |||
| * @param target - target classpath | |||
| * @param source - source classpath to get file objects. | |||
| */ | |||
| private void addExistingToClasspath( StringBuffer target, String source ) | |||
| throws TaskException | |||
| { | |||
| final StringTokenizer tok = new StringTokenizer( source, | |||
| System.getProperty( "path.separator" ), false ); | |||
| while( tok.hasMoreTokens() ) | |||
| { | |||
| File f = getContext().resolveFile( tok.nextToken() ); | |||
| if( f.exists() ) | |||
| { | |||
| target.append( File.pathSeparator ); | |||
| target.append( f.getAbsolutePath() ); | |||
| } | |||
| else | |||
| { | |||
| getContext().debug( "Dropping from classpath: " + f.getAbsolutePath() ); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Copy eligible files from the srcDir to destDir | |||
| */ | |||
| private void copyFilesToDestination() | |||
| { | |||
| //FIXME: This should be zapped no ? | |||
| if( filecopyList.size() > 0 ) | |||
| { | |||
| getContext().info( "Copying " + filecopyList.size() + " file" | |||
| + ( filecopyList.size() == 1 ? "" : "s" ) | |||
| + " to " + destDir.getAbsolutePath() ); | |||
| Iterator enum = filecopyList.keySet().iterator(); | |||
| while( enum.hasNext() ) | |||
| { | |||
| String fromFile = (String)enum.next(); | |||
| String toFile = (String)filecopyList.get( fromFile ); | |||
| try | |||
| { | |||
| FileUtil.copyFile( new File( fromFile ), new File( toFile ) ); | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| String msg = "Failed to copy " + fromFile + " to " + toFile | |||
| + " due to " + ioe.getMessage(); | |||
| throw new TaskException( msg, ioe ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Peforms a copmile using the NetRexx 1.1.x compiler | |||
| * | |||
| * @exception org.apache.myrmidon.api.TaskException Description of Exception | |||
| */ | |||
| private void doNetRexxCompile() | |||
| throws TaskException | |||
| { | |||
| getContext().debug( "Using NetRexx compiler" ); | |||
| String classpath = getCompileClasspath(); | |||
| StringBuffer compileOptions = new StringBuffer(); | |||
| StringBuffer fileList = new StringBuffer(); | |||
| // create an array of strings for input to the compiler: one array | |||
| // comes from the compile options, the other from the compileList | |||
| String[] compileOptionsArray = getCompileOptionsAsArray(); | |||
| String[] fileListArray = new String[ compileList.size() ]; | |||
| Iterator e = compileList.iterator(); | |||
| int j = 0; | |||
| while( e.hasNext() ) | |||
| { | |||
| fileListArray[ j ] = (String)e.next(); | |||
| j++; | |||
| } | |||
| // create a single array of arguments for the compiler | |||
| String compileArgs[] = new String[ compileOptionsArray.length + fileListArray.length ]; | |||
| for( int i = 0; i < compileOptionsArray.length; i++ ) | |||
| { | |||
| compileArgs[ i ] = compileOptionsArray[ i ]; | |||
| } | |||
| for( int i = 0; i < fileListArray.length; i++ ) | |||
| { | |||
| compileArgs[ i + compileOptionsArray.length ] = fileListArray[ i ]; | |||
| } | |||
| // print nice output about what we are doing for the log | |||
| compileOptions.append( "Compilation args: " ); | |||
| for( int i = 0; i < compileOptionsArray.length; i++ ) | |||
| { | |||
| compileOptions.append( compileOptionsArray[ i ] ); | |||
| compileOptions.append( " " ); | |||
| } | |||
| getContext().debug( compileOptions.toString() ); | |||
| StringBuffer niceSourceList = new StringBuffer( "Files to be compiled:" + StringUtil.LINE_SEPARATOR ); | |||
| for( int i = 0; i < compileList.size(); i++ ) | |||
| { | |||
| niceSourceList.append( " " ); | |||
| niceSourceList.append( compileList.get( i ).toString() ); | |||
| niceSourceList.append( StringUtil.LINE_SEPARATOR ); | |||
| } | |||
| getContext().debug( niceSourceList.toString() ); | |||
| // need to set java.class.path property and restore it later | |||
| // since the NetRexx compiler has no option for the classpath | |||
| String currentClassPath = System.getProperty( "java.class.path" ); | |||
| Properties currentProperties = System.getProperties(); | |||
| currentProperties.put( "java.class.path", classpath ); | |||
| try | |||
| { | |||
| StringWriter out = new StringWriter(); | |||
| int rc = | |||
| COM.ibm.netrexx.process.NetRexxC.main( new Rexx( compileArgs ), new PrintWriter( out ) ); | |||
| if( rc > 1 ) | |||
| {// 1 is warnings from real NetRexxC | |||
| getContext().error( out.toString() ); | |||
| String msg = "Compile failed, messages should have been provided."; | |||
| throw new TaskException( msg ); | |||
| } | |||
| else if( rc == 1 ) | |||
| { | |||
| getContext().warn( out.toString() ); | |||
| } | |||
| else | |||
| { | |||
| getContext().info( out.toString() ); | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| // need to reset java.class.path property | |||
| // since the NetRexx compiler has no option for the classpath | |||
| currentProperties = System.getProperties(); | |||
| currentProperties.put( "java.class.path", currentClassPath ); | |||
| } | |||
| } | |||
| /** | |||
| * Scans the directory looking for source files to be compiled and support | |||
| * files to be copied. | |||
| * | |||
| * @param srcDir Description of Parameter | |||
| * @param destDir Description of Parameter | |||
| * @param files Description of Parameter | |||
| */ | |||
| private void scanDir( File srcDir, File destDir, String[] files ) | |||
| { | |||
| for( int i = 0; i < files.length; i++ ) | |||
| { | |||
| File srcFile = new File( srcDir, files[ i ] ); | |||
| File destFile = new File( destDir, files[ i ] ); | |||
| String filename = files[ i ]; | |||
| // if it's a non source file, copy it if a later date than the | |||
| // dest | |||
| // if it's a source file, see if the destination class file | |||
| // needs to be recreated via compilation | |||
| if( filename.toLowerCase().endsWith( ".nrx" ) ) | |||
| { | |||
| File classFile = | |||
| new File( destDir, | |||
| filename.substring( 0, filename.lastIndexOf( '.' ) ) + ".class" ); | |||
| if( !compile || srcFile.lastModified() > classFile.lastModified() ) | |||
| { | |||
| filecopyList.put( srcFile.getAbsolutePath(), destFile.getAbsolutePath() ); | |||
| compileList.add( destFile.getAbsolutePath() ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| if( srcFile.lastModified() > destFile.lastModified() ) | |||
| { | |||
| filecopyList.put( srcFile.getAbsolutePath(), destFile.getAbsolutePath() ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -1,323 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs; | |||
| import java.io.File; | |||
| import java.util.ArrayList; | |||
| import org.apache.aut.nativelib.Os; | |||
| import org.apache.myrmidon.api.AbstractTask; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.file.Path; | |||
| /** | |||
| * This task converts path and classpath information to a specific target OS | |||
| * format. The resulting formatted path is placed into a specified property. <p> | |||
| * | |||
| * LIMITATION: Currently this implementation groups all machines into one of two | |||
| * types: Unix or Windows. Unix is defined as NOT windows. | |||
| * | |||
| * @author Larry Streepy <a href="mailto:streepy@healthlanguage.com"> | |||
| * streepy@healthlanguage.com</a> | |||
| */ | |||
| public class PathConvert extends AbstractTask | |||
| { | |||
| private Path m_path;// Path to be converted | |||
| private String m_targetOS;// The target OS type | |||
| private boolean m_targetWindows;// Set when targetOS is set | |||
| private boolean m_onWindows;// Set if we're running on windows | |||
| private String m_property;// The property to receive the results | |||
| private ArrayList m_prefixMap = new ArrayList();// Path prefix map | |||
| private String m_pathSep;// User override on path sep char | |||
| private String m_dirSep; | |||
| /** | |||
| * Override the default directory separator string for the target os | |||
| */ | |||
| public void setDirSep( final String dirSep ) | |||
| { | |||
| m_dirSep = dirSep; | |||
| } | |||
| /** | |||
| * Override the default path separator string for the target os | |||
| * | |||
| * @param pathSep The new PathSep value | |||
| */ | |||
| public void setPathSep( final String pathSep ) | |||
| { | |||
| m_pathSep = pathSep; | |||
| } | |||
| /** | |||
| * Set the value of the proprty attribute - this is the property into which | |||
| * our converted path will be placed. | |||
| */ | |||
| public void setProperty( final String property ) | |||
| { | |||
| m_property = property; | |||
| } | |||
| /** | |||
| * Set the value of the targetos attribute | |||
| * | |||
| * @param targetOS The new Targetos value | |||
| */ | |||
| public void setTargetos( String targetOS ) | |||
| throws TaskException | |||
| { | |||
| m_targetOS = targetOS.toLowerCase(); | |||
| if( !m_targetOS.equals( "windows" ) && !targetOS.equals( "unix" ) && | |||
| !m_targetOS.equals( "netware" ) ) | |||
| { | |||
| throw new TaskException( "targetos must be one of 'unix', 'netware', or 'windows'" ); | |||
| } | |||
| // Currently, we deal with only two path formats: Unix and Windows | |||
| // And Unix is everything that is not Windows | |||
| // for NetWare, piggy-back on Windows, since in the validateSetup code, | |||
| // the same assumptions can be made as with windows - | |||
| // that ; is the path separator | |||
| m_targetWindows = ( m_targetOS.equals( "windows" ) || m_targetOS.equals( "netware" ) ); | |||
| } | |||
| /** | |||
| * Create a nested MAP element | |||
| */ | |||
| public void addMap( final MapEntry entry ) | |||
| { | |||
| m_prefixMap.add( entry ); | |||
| } | |||
| /** | |||
| * Adds a PATH element | |||
| */ | |||
| public void addPath( Path path ) | |||
| throws TaskException | |||
| { | |||
| if( m_path == null ) | |||
| { | |||
| m_path = path; | |||
| } | |||
| else | |||
| { | |||
| m_path.add( path ); | |||
| } | |||
| } | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| // If we are a reference, the create a Path from the reference | |||
| validate();// validate our setup | |||
| // Currently, we deal with only two path formats: Unix and Windows | |||
| // And Unix is everything that is not Windows | |||
| // (with the exception for NetWare below) | |||
| // for NetWare, piggy-back on Windows, since here and in the | |||
| // apply code, the same assumptions can be made as with windows - | |||
| // that \\ is an OK separator, and do comparisons case-insensitive. | |||
| m_onWindows = ( Os.isFamily( Os.OS_FAMILY_WINDOWS ) || Os.isFamily( Os.OS_FAMILY_NETWARE ) ); | |||
| // Determine the from/to char mappings for dir sep | |||
| char fromDirSep = m_onWindows ? '\\' : '/'; | |||
| char toDirSep = m_dirSep.charAt( 0 ); | |||
| StringBuffer rslt = new StringBuffer( 100 ); | |||
| // Get the list of path components in canonical form | |||
| String[] elems = m_path.listFiles( getContext() ); | |||
| for( int i = 0; i < elems.length; i++ ) | |||
| { | |||
| String elem = elems[ i ]; | |||
| elem = mapElement( elem );// Apply the path prefix map | |||
| // Now convert the path and file separator characters from the | |||
| // current os to the target os. | |||
| elem = elem.replace( fromDirSep, toDirSep ); | |||
| if( i != 0 ) | |||
| { | |||
| rslt.append( m_pathSep ); | |||
| } | |||
| rslt.append( elem ); | |||
| } | |||
| // Place the result into the specified property | |||
| final String value = rslt.toString(); | |||
| getContext().debug( "Set property " + m_property + " = " + value ); | |||
| final String name = m_property; | |||
| getContext().setProperty( name, value ); | |||
| } | |||
| /** | |||
| * Apply the configured map to a path element. The map is used to convert | |||
| * between Windows drive letters and Unix paths. If no map is configured, | |||
| * then the input string is returned unchanged. | |||
| * | |||
| * @param elem The path element to apply the map to | |||
| * @return String Updated element | |||
| */ | |||
| private String mapElement( String elem ) | |||
| throws TaskException | |||
| { | |||
| int size = m_prefixMap.size(); | |||
| if( size != 0 ) | |||
| { | |||
| // Iterate over the map entries and apply each one. Stop when one of the | |||
| // entries actually changes the element | |||
| for( int i = 0; i < size; i++ ) | |||
| { | |||
| MapEntry entry = (MapEntry)m_prefixMap.get( i ); | |||
| String newElem = entry.apply( elem ); | |||
| // Note I'm using "!=" to see if we got a new object back from | |||
| // the apply method. | |||
| if( newElem != elem ) | |||
| { | |||
| elem = newElem; | |||
| break;// We applied one, so we're done | |||
| } | |||
| } | |||
| } | |||
| return elem; | |||
| } | |||
| /** | |||
| * Validate that all our parameters have been properly initialized. | |||
| * | |||
| * @throws org.apache.myrmidon.api.TaskException if something is not setup properly | |||
| */ | |||
| private void validate() | |||
| throws TaskException | |||
| { | |||
| if( m_path == null ) | |||
| { | |||
| throw new TaskException( "You must specify a path to convert" ); | |||
| } | |||
| if( m_property == null ) | |||
| { | |||
| throw new TaskException( "You must specify a property" ); | |||
| } | |||
| // Must either have a target OS or both a dirSep and pathSep | |||
| if( m_targetOS == null && m_pathSep == null && m_dirSep == null ) | |||
| { | |||
| throw new TaskException( "You must specify at least one of targetOS, dirSep, or pathSep" ); | |||
| } | |||
| // Determine the separator strings. The dirsep and pathsep attributes | |||
| // override the targetOS settings. | |||
| String dsep = File.separator; | |||
| String psep = File.pathSeparator; | |||
| if( m_targetOS != null ) | |||
| { | |||
| psep = m_targetWindows ? ";" : ":"; | |||
| dsep = m_targetWindows ? "\\" : "/"; | |||
| } | |||
| if( m_pathSep != null ) | |||
| {// override with pathsep= | |||
| psep = m_pathSep; | |||
| } | |||
| if( m_dirSep != null ) | |||
| {// override with dirsep= | |||
| dsep = m_dirSep; | |||
| } | |||
| m_pathSep = psep; | |||
| m_dirSep = dsep; | |||
| } | |||
| /** | |||
| * Helper class, holds the nested <map> values. Elements will look like | |||
| * this: <map from="d:" to="/foo"/> <p> | |||
| * | |||
| * When running on windows, the prefix comparison will be case insensitive. | |||
| */ | |||
| public class MapEntry | |||
| { | |||
| private String m_from; | |||
| private String m_to; | |||
| /** | |||
| * Set the "from" attribute of the map entry | |||
| * | |||
| * @param from The new From value | |||
| */ | |||
| public void setFrom( final String from ) | |||
| { | |||
| m_from = from; | |||
| } | |||
| /** | |||
| * Set the "to" attribute of the map entry | |||
| * | |||
| * @param to The new To value | |||
| */ | |||
| public void setTo( final String to ) | |||
| { | |||
| m_to = to; | |||
| } | |||
| /** | |||
| * Apply this map entry to a given path element | |||
| * | |||
| * @param elem Path element to process | |||
| * @return String Updated path element after mapping | |||
| */ | |||
| public String apply( String elem ) | |||
| throws TaskException | |||
| { | |||
| if( m_from == null || m_to == null ) | |||
| { | |||
| throw new TaskException( "Both 'from' and 'to' must be set in a map entry" ); | |||
| } | |||
| // If we're on windows, then do the comparison ignoring case | |||
| final String cmpElem = m_onWindows ? elem.toLowerCase() : elem; | |||
| final String cmpFrom = m_onWindows ? m_from.toLowerCase() : m_from; | |||
| // If the element starts with the configured prefix, then convert the prefix | |||
| // to the configured 'to' value. | |||
| if( cmpElem.startsWith( cmpFrom ) ) | |||
| { | |||
| final int len = m_from.length(); | |||
| if( len >= elem.length() ) | |||
| { | |||
| elem = m_to; | |||
| } | |||
| else | |||
| { | |||
| elem = m_to + elem.substring( len ); | |||
| } | |||
| } | |||
| return elem; | |||
| } | |||
| } | |||
| } | |||
| @@ -1,141 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.util.Iterator; | |||
| import java.util.Properties; | |||
| import org.apache.myrmidon.api.AbstractTask; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.file.Path; | |||
| import org.apache.myrmidon.framework.file.FileListUtil; | |||
| /** | |||
| * Will set a Project property. Used to be a hack in ProjectHelper Will not | |||
| * override values set by the command line or parent projects. | |||
| * | |||
| * @author costin@dnt.ro | |||
| * @author <a href="mailto:rubys@us.ibm.com">Sam Ruby</a> | |||
| * @author <a href="mailto:glennm@ca.ibm.com">Glenn McAllister</a> | |||
| */ | |||
| public class Property | |||
| extends AbstractTask | |||
| { | |||
| private Path m_classpath = new Path(); | |||
| private String m_name; | |||
| private String m_resource; | |||
| private String m_value; | |||
| public void addClasspath( final Path classpath ) | |||
| throws TaskException | |||
| { | |||
| m_classpath.add( classpath ); | |||
| } | |||
| public void setLocation( File location ) | |||
| { | |||
| setValue( location.getAbsolutePath() ); | |||
| } | |||
| public void setName( String name ) | |||
| { | |||
| m_name = name; | |||
| } | |||
| public void setResource( String resource ) | |||
| { | |||
| m_resource = resource; | |||
| } | |||
| public void setValue( String value ) | |||
| { | |||
| m_value = value; | |||
| } | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| validate(); | |||
| if( ( m_name != null ) && ( m_value != null ) ) | |||
| { | |||
| final String name = m_name; | |||
| final Object value = m_value; | |||
| getContext().setProperty( name, value ); | |||
| } | |||
| if( m_resource != null ) | |||
| { | |||
| loadResource( m_resource ); | |||
| } | |||
| } | |||
| private void validate() throws TaskException | |||
| { | |||
| if( m_name != null ) | |||
| { | |||
| if( m_value == null ) | |||
| { | |||
| throw new TaskException( "You must specify value, location or refid with the name attribute" ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| if( m_resource == null ) | |||
| { | |||
| throw new TaskException( "You must specify resource when not using the name attribute" ); | |||
| } | |||
| } | |||
| } | |||
| public String toString() | |||
| { | |||
| return m_value == null ? "" : m_value; | |||
| } | |||
| protected void addProperties( Properties props ) | |||
| throws TaskException | |||
| { | |||
| final Iterator e = props.keySet().iterator(); | |||
| while( e.hasNext() ) | |||
| { | |||
| final String name = (String)e.next(); | |||
| final String value = (String)props.getProperty( name ); | |||
| getContext().setProperty( name, value ); | |||
| } | |||
| } | |||
| protected void loadResource( String name ) | |||
| throws TaskException | |||
| { | |||
| Properties props = new Properties(); | |||
| getContext().debug( "Resource Loading " + name ); | |||
| try | |||
| { | |||
| final ClassLoader classLoader = FileListUtil.createClassLoader( m_classpath, getContext() ); | |||
| final InputStream is = classLoader.getResourceAsStream( name ); | |||
| if( is != null ) | |||
| { | |||
| props.load( is ); | |||
| addProperties( props ); | |||
| } | |||
| else | |||
| { | |||
| getContext().warn( "Unable to find resource " + name ); | |||
| } | |||
| } | |||
| catch( IOException ex ) | |||
| { | |||
| throw new TaskException( "Error", ex ); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,128 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs; | |||
| import java.io.File; | |||
| import org.apache.myrmidon.api.AbstractTask; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.nativelib.Execute; | |||
| import org.apache.myrmidon.framework.nativelib.Commandline; | |||
| /** | |||
| * @author lucas@collab.net | |||
| */ | |||
| public class Rpm | |||
| extends AbstractTask | |||
| { | |||
| /** | |||
| * the rpm command to use | |||
| */ | |||
| private String m_command = "-bb"; | |||
| /** | |||
| * clean BUILD directory | |||
| */ | |||
| private boolean m_cleanBuildDir; | |||
| /** | |||
| * remove spec file | |||
| */ | |||
| private boolean m_removeSpec; | |||
| /** | |||
| * remove sources | |||
| */ | |||
| private boolean m_removeSource; | |||
| /** | |||
| * the spec file | |||
| */ | |||
| private String m_specFile; | |||
| /** | |||
| * the rpm top dir | |||
| */ | |||
| private File m_topDir; | |||
| public void setCleanBuildDir( boolean cleanBuildDir ) | |||
| { | |||
| m_cleanBuildDir = cleanBuildDir; | |||
| } | |||
| public void setCommand( final String command ) | |||
| { | |||
| m_command = command; | |||
| } | |||
| public void setRemoveSource( final boolean removeSource ) | |||
| { | |||
| m_removeSource = removeSource; | |||
| } | |||
| public void setRemoveSpec( final boolean removeSpec ) | |||
| { | |||
| m_removeSpec = removeSpec; | |||
| } | |||
| public void setSpecFile( final String specFile ) | |||
| throws TaskException | |||
| { | |||
| if( ( specFile == null ) || ( specFile.trim().equals( "" ) ) ) | |||
| { | |||
| throw new TaskException( "You must specify a spec file" ); | |||
| } | |||
| m_specFile = specFile; | |||
| } | |||
| public void setTopDir( final File topDir ) | |||
| { | |||
| m_topDir = topDir; | |||
| } | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| final Execute exe = createCommand(); | |||
| exe.setWorkingDirectory( m_topDir ); | |||
| final String message = "Building the RPM based on the " + m_specFile + " file"; | |||
| getContext().info( message ); | |||
| exe.execute( getContext() ); | |||
| } | |||
| private Execute createCommand() | |||
| throws TaskException | |||
| { | |||
| final Execute cmd = new Execute(); | |||
| cmd.setExecutable( "rpm" ); | |||
| if( m_topDir != null ) | |||
| { | |||
| cmd.addArgument( "--define" ); | |||
| cmd.addArgument( "_topdir" + m_topDir ); | |||
| } | |||
| cmd.addLine( m_command ); | |||
| if( m_cleanBuildDir ) | |||
| { | |||
| cmd.addArgument( "--clean" ); | |||
| } | |||
| if( m_removeSpec ) | |||
| { | |||
| cmd.addArgument( "--rmspec" ); | |||
| } | |||
| if( m_removeSource ) | |||
| { | |||
| cmd.addArgument( "--rmsource" ); | |||
| } | |||
| cmd.addArgument( "SPECS/" + m_specFile ); | |||
| return cmd; | |||
| } | |||
| } | |||
| @@ -1,836 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs; | |||
| import java.io.BufferedOutputStream; | |||
| import java.io.BufferedReader; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.FileOutputStream; | |||
| import java.io.FileReader; | |||
| import java.io.IOException; | |||
| import java.io.InputStreamReader; | |||
| import java.io.PrintStream; | |||
| import java.io.Reader; | |||
| import java.io.StringReader; | |||
| import java.sql.Connection; | |||
| import java.sql.DatabaseMetaData; | |||
| import java.sql.Driver; | |||
| import java.sql.ResultSet; | |||
| import java.sql.ResultSetMetaData; | |||
| import java.sql.SQLException; | |||
| import java.sql.SQLWarning; | |||
| import java.sql.Statement; | |||
| import java.util.ArrayList; | |||
| import java.util.Iterator; | |||
| import java.util.Properties; | |||
| import java.util.StringTokenizer; | |||
| import org.apache.myrmidon.api.AbstractTask; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.file.Path; | |||
| import org.apache.myrmidon.framework.file.FileListUtil; | |||
| import org.apache.myrmidon.framework.FileSet; | |||
| import org.apache.tools.todo.types.DirectoryScanner; | |||
| import org.apache.tools.todo.types.EnumeratedAttribute; | |||
| import org.apache.tools.todo.types.ScannerUtil; | |||
| /** | |||
| * Reads in a text file containing SQL statements seperated with semicolons and | |||
| * executes it in a given db. Comments may be created with REM -- or //. | |||
| * | |||
| * @author <a href="mailto:jeff@custommonkey.org">Jeff Martin</a> | |||
| * @author <A href="mailto:gholam@xtra.co.nz">Michael McCallum</A> | |||
| * @author <A href="mailto:tim.stephenson@sybase.com">Tim Stephenson</A> | |||
| */ | |||
| public class SQLExec | |||
| extends AbstractTask | |||
| { | |||
| private int goodSql = 0, totalSql = 0; | |||
| private ArrayList filesets = new ArrayList(); | |||
| /** | |||
| * Database connection | |||
| */ | |||
| private Connection conn; | |||
| /** | |||
| * Autocommit flag. Default value is false | |||
| */ | |||
| private boolean autocommit; | |||
| /** | |||
| * SQL statement | |||
| */ | |||
| private Statement statement; | |||
| /** | |||
| * DB driver. | |||
| */ | |||
| private String driver; | |||
| /** | |||
| * DB url. | |||
| */ | |||
| private String url; | |||
| /** | |||
| * User name. | |||
| */ | |||
| private String userId; | |||
| /** | |||
| * Password | |||
| */ | |||
| private String password; | |||
| /** | |||
| * SQL input file | |||
| */ | |||
| private File srcFile; | |||
| /** | |||
| * SQL input command | |||
| */ | |||
| private String sqlCommand = ""; | |||
| /** | |||
| * SQL transactions to perform | |||
| */ | |||
| private ArrayList transactions = new ArrayList(); | |||
| /** | |||
| * SQL Statement delimiter | |||
| */ | |||
| private String delimiter = ";"; | |||
| /** | |||
| * The delimiter type indicating whether the delimiter will only be | |||
| * recognized on a line by itself | |||
| */ | |||
| private String delimiterType = DelimiterType.NORMAL; | |||
| /** | |||
| * Print SQL results. | |||
| */ | |||
| private boolean print; | |||
| /** | |||
| * Print header columns. | |||
| */ | |||
| private boolean showheaders = true; | |||
| /** | |||
| * Results Output file. | |||
| */ | |||
| private File output; | |||
| /** | |||
| * RDBMS Product needed for this SQL. | |||
| */ | |||
| private String rdbms; | |||
| /** | |||
| * RDBMS Version needed for this SQL. | |||
| */ | |||
| private String version; | |||
| /** | |||
| * Action to perform if an error is found | |||
| */ | |||
| private String onError = "abort"; | |||
| /** | |||
| * Encoding to use when reading SQL statements from a file | |||
| */ | |||
| private String encoding; | |||
| private Path classpath = new Path(); | |||
| /** | |||
| * Set the autocommit flag for the DB connection. | |||
| * | |||
| * @param autocommit The new Autocommit value | |||
| */ | |||
| public void setAutocommit( boolean autocommit ) | |||
| { | |||
| this.autocommit = autocommit; | |||
| } | |||
| /** | |||
| * Adds an element to the classpath for loading the driver. | |||
| * | |||
| * @param classpath The new Classpath value | |||
| */ | |||
| public void addClasspath( final Path classpath ) | |||
| throws TaskException | |||
| { | |||
| this.classpath.add( classpath ); | |||
| } | |||
| /** | |||
| * Set the statement delimiter. <p> | |||
| * | |||
| * For example, set this to "go" and delimitertype to "ROW" for Sybase ASE | |||
| * or MS SQL Server.</p> | |||
| * | |||
| * @param delimiter The new Delimiter value | |||
| */ | |||
| public void setDelimiter( String delimiter ) | |||
| { | |||
| this.delimiter = delimiter; | |||
| } | |||
| /** | |||
| * Set the Delimiter type for this sql task. The delimiter type takes two | |||
| * values - normal and row. Normal means that any occurence of the delimiter | |||
| * terminate the SQL command whereas with row, only a line containing just | |||
| * the delimiter is recognized as the end of the command. | |||
| * | |||
| * @param delimiterType The new DelimiterType value | |||
| */ | |||
| public void setDelimiterType( DelimiterType delimiterType ) | |||
| { | |||
| this.delimiterType = delimiterType.getValue(); | |||
| } | |||
| /** | |||
| * Set the JDBC driver to be used. | |||
| * | |||
| * @param driver The new Driver value | |||
| */ | |||
| public void setDriver( String driver ) | |||
| { | |||
| this.driver = driver; | |||
| } | |||
| /** | |||
| * Set the file encoding to use on the sql files read in | |||
| * | |||
| * @param encoding the encoding to use on the files | |||
| */ | |||
| public void setEncoding( String encoding ) | |||
| { | |||
| this.encoding = encoding; | |||
| } | |||
| /** | |||
| * Set the action to perform onerror | |||
| * | |||
| * @param action The new Onerror value | |||
| */ | |||
| public void setOnerror( OnError action ) | |||
| { | |||
| this.onError = action.getValue(); | |||
| } | |||
| /** | |||
| * Set the output file. | |||
| * | |||
| * @param output The new Output value | |||
| */ | |||
| public void setOutput( File output ) | |||
| { | |||
| this.output = output; | |||
| } | |||
| /** | |||
| * Set the password for the DB connection. | |||
| * | |||
| * @param password The new Password value | |||
| */ | |||
| public void setPassword( String password ) | |||
| { | |||
| this.password = password; | |||
| } | |||
| /** | |||
| * Set the print flag. | |||
| * | |||
| * @param print The new Print value | |||
| */ | |||
| public void setPrint( boolean print ) | |||
| { | |||
| this.print = print; | |||
| } | |||
| /** | |||
| * Set the rdbms required | |||
| * | |||
| * @param vendor The new Rdbms value | |||
| */ | |||
| public void setRdbms( String vendor ) | |||
| { | |||
| this.rdbms = vendor.toLowerCase(); | |||
| } | |||
| /** | |||
| * Set the showheaders flag. | |||
| * | |||
| * @param showheaders The new Showheaders value | |||
| */ | |||
| public void setShowheaders( boolean showheaders ) | |||
| { | |||
| this.showheaders = showheaders; | |||
| } | |||
| /** | |||
| * Set the name of the sql file to be run. | |||
| * | |||
| * @param srcFile The new Src value | |||
| */ | |||
| public void setSrc( File srcFile ) | |||
| { | |||
| this.srcFile = srcFile; | |||
| } | |||
| /** | |||
| * Set the DB connection url. | |||
| * | |||
| * @param url The new Url value | |||
| */ | |||
| public void setUrl( String url ) | |||
| { | |||
| this.url = url; | |||
| } | |||
| /** | |||
| * Set the user name for the DB connection. | |||
| * | |||
| * @param userId The new Userid value | |||
| */ | |||
| public void setUserid( String userId ) | |||
| { | |||
| this.userId = userId; | |||
| } | |||
| /** | |||
| * Set the version required | |||
| * | |||
| * @param version The new Version value | |||
| */ | |||
| public void setVersion( String version ) | |||
| { | |||
| this.version = version.toLowerCase(); | |||
| } | |||
| /** | |||
| * Adds a set of files (nested fileset attribute). | |||
| * | |||
| * @param set The feature to be added to the Fileset attribute | |||
| */ | |||
| public void addFileset( FileSet set ) | |||
| { | |||
| filesets.add( set ); | |||
| } | |||
| /** | |||
| * Set the sql command to execute | |||
| * | |||
| * @param sql The feature to be added to the Text attribute | |||
| */ | |||
| public void addContent( String sql ) | |||
| { | |||
| this.sqlCommand += sql; | |||
| } | |||
| /** | |||
| * Set the sql command to execute | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public Transaction createTransaction() | |||
| { | |||
| Transaction t = new Transaction(); | |||
| transactions.add( t ); | |||
| return t; | |||
| } | |||
| /** | |||
| * Load the sql file and then execute it | |||
| * | |||
| * @exception org.apache.myrmidon.api.TaskException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| sqlCommand = sqlCommand.trim(); | |||
| if( srcFile == null && sqlCommand.length() == 0 && filesets.isEmpty() ) | |||
| { | |||
| if( transactions.size() == 0 ) | |||
| { | |||
| throw new TaskException( "Source file or fileset, transactions or sql statement must be set!" ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| // deal with the filesets | |||
| for( int i = 0; i < filesets.size(); i++ ) | |||
| { | |||
| FileSet fs = (FileSet)filesets.get( i ); | |||
| DirectoryScanner ds = ScannerUtil.getDirectoryScanner( fs ); | |||
| File srcDir = fs.getDir(); | |||
| String[] srcFiles = ds.getIncludedFiles(); | |||
| // Make a transaction for each file | |||
| for( int j = 0; j < srcFiles.length; j++ ) | |||
| { | |||
| Transaction t = createTransaction(); | |||
| t.setSrc( new File( srcDir, srcFiles[ j ] ) ); | |||
| } | |||
| } | |||
| // Make a transaction group for the outer command | |||
| Transaction t = createTransaction(); | |||
| t.setSrc( srcFile ); | |||
| t.addContent( sqlCommand ); | |||
| } | |||
| if( driver == null ) | |||
| { | |||
| throw new TaskException( "Driver attribute must be set!" ); | |||
| } | |||
| if( userId == null ) | |||
| { | |||
| throw new TaskException( "User Id attribute must be set!" ); | |||
| } | |||
| if( password == null ) | |||
| { | |||
| throw new TaskException( "Password attribute must be set!" ); | |||
| } | |||
| if( url == null ) | |||
| { | |||
| throw new TaskException( "Url attribute must be set!" ); | |||
| } | |||
| if( srcFile != null && !srcFile.exists() ) | |||
| { | |||
| throw new TaskException( "Source file does not exist!" ); | |||
| } | |||
| Driver driverInstance = null; | |||
| // Load the driver using the | |||
| try | |||
| { | |||
| final ClassLoader classLoader = FileListUtil.createClassLoader( classpath, getContext() ); | |||
| final Class dc = classLoader.loadClass( driver ); | |||
| driverInstance = (Driver)dc.newInstance(); | |||
| } | |||
| catch( ClassNotFoundException e ) | |||
| { | |||
| throw new TaskException( "Class Not Found: JDBC driver " + driver + " could not be loaded" ); | |||
| } | |||
| catch( IllegalAccessException e ) | |||
| { | |||
| throw new TaskException( "Illegal Access: JDBC driver " + driver + " could not be loaded" ); | |||
| } | |||
| catch( InstantiationException e ) | |||
| { | |||
| throw new TaskException( "Instantiation Exception: JDBC driver " + driver + " could not be loaded" ); | |||
| } | |||
| try | |||
| { | |||
| getContext().debug( "connecting to " + url ); | |||
| Properties info = new Properties(); | |||
| info.put( "user", userId ); | |||
| info.put( "password", password ); | |||
| conn = driverInstance.connect( url, info ); | |||
| if( conn == null ) | |||
| { | |||
| // Driver doesn't understand the URL | |||
| throw new SQLException( "No suitable Driver for " + url ); | |||
| } | |||
| if( !isValidRdbms( conn ) ) | |||
| { | |||
| return; | |||
| } | |||
| conn.setAutoCommit( autocommit ); | |||
| statement = conn.createStatement(); | |||
| PrintStream out = System.out; | |||
| try | |||
| { | |||
| if( output != null ) | |||
| { | |||
| getContext().debug( "Opening PrintStream to output file " + output ); | |||
| out = new PrintStream( new BufferedOutputStream( new FileOutputStream( output ) ) ); | |||
| } | |||
| // Process all transactions | |||
| for( Iterator e = transactions.iterator(); | |||
| e.hasNext(); ) | |||
| { | |||
| ( (Transaction)e.next() ).runTransaction( out ); | |||
| if( !autocommit ) | |||
| { | |||
| getContext().debug( "Commiting transaction" ); | |||
| conn.commit(); | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| if( out != null && out != System.out ) | |||
| { | |||
| out.close(); | |||
| } | |||
| } | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| if( !autocommit && conn != null && onError.equals( "abort" ) ) | |||
| { | |||
| try | |||
| { | |||
| conn.rollback(); | |||
| } | |||
| catch( SQLException ex ) | |||
| { | |||
| } | |||
| } | |||
| throw new TaskException( "Error", e ); | |||
| } | |||
| catch( SQLException e ) | |||
| { | |||
| if( !autocommit && conn != null && onError.equals( "abort" ) ) | |||
| { | |||
| try | |||
| { | |||
| conn.rollback(); | |||
| } | |||
| catch( SQLException ex ) | |||
| { | |||
| } | |||
| } | |||
| throw new TaskException( "Error", e ); | |||
| } | |||
| finally | |||
| { | |||
| try | |||
| { | |||
| if( statement != null ) | |||
| { | |||
| statement.close(); | |||
| } | |||
| if( conn != null ) | |||
| { | |||
| conn.close(); | |||
| } | |||
| } | |||
| catch( SQLException e ) | |||
| { | |||
| } | |||
| } | |||
| getContext().info( goodSql + " of " + totalSql + | |||
| " SQL statements executed successfully" ); | |||
| } | |||
| /** | |||
| * Verify if connected to the correct RDBMS | |||
| * | |||
| * @param conn Description of Parameter | |||
| * @return The ValidRdbms value | |||
| */ | |||
| protected boolean isValidRdbms( Connection conn ) | |||
| { | |||
| if( rdbms == null && version == null ) | |||
| { | |||
| return true; | |||
| } | |||
| try | |||
| { | |||
| DatabaseMetaData dmd = conn.getMetaData(); | |||
| if( rdbms != null ) | |||
| { | |||
| String theVendor = dmd.getDatabaseProductName().toLowerCase(); | |||
| getContext().debug( "RDBMS = " + theVendor ); | |||
| if( theVendor == null || theVendor.indexOf( rdbms ) < 0 ) | |||
| { | |||
| getContext().debug( "Not the required RDBMS: " + rdbms ); | |||
| return false; | |||
| } | |||
| } | |||
| if( version != null ) | |||
| { | |||
| String theVersion = dmd.getDatabaseProductVersion().toLowerCase(); | |||
| getContext().debug( "Version = " + theVersion ); | |||
| if( theVersion == null || | |||
| !( theVersion.startsWith( version ) || | |||
| theVersion.indexOf( " " + version ) >= 0 ) ) | |||
| { | |||
| getContext().debug( "Not the required version: \"" + version + "\"" ); | |||
| return false; | |||
| } | |||
| } | |||
| } | |||
| catch( SQLException e ) | |||
| { | |||
| // Could not get the required information | |||
| getContext().error( "Failed to obtain required RDBMS information" ); | |||
| return false; | |||
| } | |||
| return true; | |||
| } | |||
| /** | |||
| * Exec the sql statement. | |||
| * | |||
| * @param sql Description of Parameter | |||
| * @param out Description of Parameter | |||
| * @exception java.sql.SQLException Description of Exception | |||
| */ | |||
| protected void execSQL( String sql, PrintStream out ) | |||
| throws SQLException | |||
| { | |||
| // Check and ignore empty statements | |||
| if( "".equals( sql.trim() ) ) | |||
| { | |||
| return; | |||
| } | |||
| try | |||
| { | |||
| totalSql++; | |||
| if( !statement.execute( sql ) ) | |||
| { | |||
| getContext().debug( statement.getUpdateCount() + " rows affected" ); | |||
| } | |||
| else | |||
| { | |||
| if( print ) | |||
| { | |||
| printResults( out ); | |||
| } | |||
| } | |||
| SQLWarning warning = conn.getWarnings(); | |||
| while( warning != null ) | |||
| { | |||
| getContext().debug( warning + " sql warning" ); | |||
| warning = warning.getNextWarning(); | |||
| } | |||
| conn.clearWarnings(); | |||
| goodSql++; | |||
| } | |||
| catch( SQLException e ) | |||
| { | |||
| getContext().error( "Failed to execute: " + sql ); | |||
| if( !onError.equals( "continue" ) ) | |||
| { | |||
| throw e; | |||
| } | |||
| getContext().error( e.toString() ); | |||
| } | |||
| } | |||
| /** | |||
| * print any results in the statement. | |||
| * | |||
| * @param out Description of Parameter | |||
| * @exception java.sql.SQLException Description of Exception | |||
| */ | |||
| protected void printResults( PrintStream out ) | |||
| throws java.sql.SQLException | |||
| { | |||
| ResultSet rs = null; | |||
| do | |||
| { | |||
| rs = statement.getResultSet(); | |||
| if( rs != null ) | |||
| { | |||
| getContext().debug( "Processing new result set." ); | |||
| ResultSetMetaData md = rs.getMetaData(); | |||
| int columnCount = md.getColumnCount(); | |||
| StringBuffer line = new StringBuffer(); | |||
| if( showheaders ) | |||
| { | |||
| for( int col = 1; col < columnCount; col++ ) | |||
| { | |||
| line.append( md.getColumnName( col ) ); | |||
| line.append( "," ); | |||
| } | |||
| line.append( md.getColumnName( columnCount ) ); | |||
| out.println( line ); | |||
| line.setLength( 0 ); | |||
| } | |||
| while( rs.next() ) | |||
| { | |||
| boolean first = true; | |||
| for( int col = 1; col <= columnCount; col++ ) | |||
| { | |||
| String columnValue = rs.getString( col ); | |||
| if( columnValue != null ) | |||
| { | |||
| columnValue = columnValue.trim(); | |||
| } | |||
| if( first ) | |||
| { | |||
| first = false; | |||
| } | |||
| else | |||
| { | |||
| line.append( "," ); | |||
| } | |||
| line.append( columnValue ); | |||
| } | |||
| out.println( line ); | |||
| line.setLength( 0 ); | |||
| } | |||
| } | |||
| } while( statement.getMoreResults() ); | |||
| out.println(); | |||
| } | |||
| protected void runStatements( Reader reader, PrintStream out ) | |||
| throws SQLException, IOException, TaskException | |||
| { | |||
| String sql = ""; | |||
| String line = ""; | |||
| BufferedReader in = new BufferedReader( reader ); | |||
| try | |||
| { | |||
| while( ( line = in.readLine() ) != null ) | |||
| { | |||
| line = line.trim(); | |||
| final String value = line; | |||
| line = "" + getContext().resolveValue( value ); | |||
| if( line.startsWith( "//" ) ) | |||
| { | |||
| continue; | |||
| } | |||
| if( line.startsWith( "--" ) ) | |||
| { | |||
| continue; | |||
| } | |||
| StringTokenizer st = new StringTokenizer( line ); | |||
| if( st.hasMoreTokens() ) | |||
| { | |||
| String token = st.nextToken(); | |||
| if( "REM".equalsIgnoreCase( token ) ) | |||
| { | |||
| continue; | |||
| } | |||
| } | |||
| sql += " " + line; | |||
| sql = sql.trim(); | |||
| // SQL defines "--" as a comment to EOL | |||
| // and in Oracle it may contain a hint | |||
| // so we cannot just remove it, instead we must end it | |||
| if( line.indexOf( "--" ) >= 0 ) | |||
| { | |||
| sql += "\n"; | |||
| } | |||
| if( delimiterType.equals( DelimiterType.NORMAL ) && sql.endsWith( delimiter ) || | |||
| delimiterType.equals( DelimiterType.ROW ) && line.equals( delimiter ) ) | |||
| { | |||
| getContext().debug( "SQL: " + sql ); | |||
| execSQL( sql.substring( 0, sql.length() - delimiter.length() ), out ); | |||
| sql = ""; | |||
| } | |||
| } | |||
| // Catch any statements not followed by ; | |||
| if( !sql.equals( "" ) ) | |||
| { | |||
| execSQL( sql, out ); | |||
| } | |||
| } | |||
| catch( SQLException e ) | |||
| { | |||
| throw e; | |||
| } | |||
| } | |||
| public static class DelimiterType extends EnumeratedAttribute | |||
| { | |||
| public final static String NORMAL = "normal"; | |||
| public final static String ROW = "row"; | |||
| public String[] getValues() | |||
| { | |||
| return new String[]{NORMAL, ROW}; | |||
| } | |||
| } | |||
| /** | |||
| * Enumerated attribute with the values "continue", "stop" and "abort" for | |||
| * the onerror attribute. | |||
| * | |||
| * @author RT | |||
| */ | |||
| public static class OnError extends EnumeratedAttribute | |||
| { | |||
| public String[] getValues() | |||
| { | |||
| return new String[]{"continue", "stop", "abort"}; | |||
| } | |||
| } | |||
| /** | |||
| * Contains the definition of a new transaction element. Transactions allow | |||
| * several files or blocks of statements to be executed using the same JDBC | |||
| * connection and commit operation in between. | |||
| * | |||
| * @author RT | |||
| */ | |||
| public class Transaction | |||
| { | |||
| private File tSrcFile = null; | |||
| private String tSqlCommand = ""; | |||
| public void setSrc( File src ) | |||
| { | |||
| this.tSrcFile = src; | |||
| } | |||
| public void addContent( String sql ) | |||
| { | |||
| this.tSqlCommand += sql; | |||
| } | |||
| private void runTransaction( PrintStream out ) | |||
| throws IOException, SQLException, TaskException | |||
| { | |||
| if( tSqlCommand.length() != 0 ) | |||
| { | |||
| getContext().info( "Executing commands" ); | |||
| runStatements( new StringReader( tSqlCommand ), out ); | |||
| } | |||
| if( tSrcFile != null ) | |||
| { | |||
| getContext().info( "Executing file: " + tSrcFile.getAbsolutePath() ); | |||
| Reader reader = ( encoding == null ) ? new FileReader( tSrcFile ) | |||
| : new InputStreamReader( new FileInputStream( tSrcFile ), encoding ); | |||
| runStatements( reader, out ); | |||
| reader.close(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -1,155 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs; | |||
| import com.ibm.bsf.BSFException; | |||
| import com.ibm.bsf.BSFManager; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.IOException; | |||
| import java.util.Hashtable; | |||
| import java.util.Iterator; | |||
| import org.apache.myrmidon.api.AbstractTask; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| /** | |||
| * Execute a script | |||
| * | |||
| * @author Sam Ruby <a href="mailto:rubys@us.ibm.com">rubys@us.ibm.com</a> | |||
| */ | |||
| public class Script extends AbstractTask | |||
| { | |||
| private String script = ""; | |||
| private Hashtable beans = new Hashtable(); | |||
| private String language; | |||
| /** | |||
| * Defines the language (required). | |||
| * | |||
| * @param language The new Language value | |||
| */ | |||
| public void setLanguage( String language ) | |||
| { | |||
| this.language = language; | |||
| } | |||
| /** | |||
| * Load the script from an external file | |||
| * | |||
| * @param fileName The new Src value | |||
| */ | |||
| public void setSrc( String fileName ) | |||
| { | |||
| File file = new File( fileName ); | |||
| if( !file.exists() ) | |||
| { | |||
| throw new TaskException( "file " + fileName + " not found." ); | |||
| } | |||
| int count = (int)file.length(); | |||
| byte data[] = new byte[ count ]; | |||
| try | |||
| { | |||
| FileInputStream inStream = new FileInputStream( file ); | |||
| inStream.read( data ); | |||
| inStream.close(); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| throw new TaskException( "Error", e ); | |||
| } | |||
| script += new String( data ); | |||
| } | |||
| /** | |||
| * Defines the script. | |||
| * | |||
| * @param text The feature to be added to the Text attribute | |||
| */ | |||
| public void addContent( String text ) | |||
| { | |||
| this.script += text; | |||
| } | |||
| /** | |||
| * Do the work. | |||
| * | |||
| * @exception org.apache.myrmidon.api.TaskException if someting goes wrong with the build | |||
| */ | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| try | |||
| { | |||
| addBeans( getContext().getProperties() ); | |||
| //In Ant2 there is no difference between properties and references | |||
| //addBeans( getProject().getReferences() ); | |||
| beans.put( "context", getContext() ); | |||
| beans.put( "self", this ); | |||
| BSFManager manager = new BSFManager(); | |||
| for( Iterator e = beans.keys(); e.hasNext(); ) | |||
| { | |||
| String key = (String)e.next(); | |||
| Object value = beans.get( key ); | |||
| manager.declareBean( key, value, value.getClass() ); | |||
| } | |||
| // execute the script | |||
| manager.exec( language, "<ANT>", 0, 0, script ); | |||
| } | |||
| catch( BSFException be ) | |||
| { | |||
| Throwable t = be; | |||
| Throwable te = be.getTargetException(); | |||
| if( te != null ) | |||
| { | |||
| if( te instanceof TaskException ) | |||
| { | |||
| throw (TaskException)te; | |||
| } | |||
| else | |||
| { | |||
| t = te; | |||
| } | |||
| } | |||
| throw new TaskException( "Error", t ); | |||
| } | |||
| } | |||
| /** | |||
| * Add a list of named objects to the list to be exported to the script | |||
| * | |||
| * @param dictionary The feature to be added to the Beans attribute | |||
| */ | |||
| private void addBeans( Hashtable dictionary ) | |||
| { | |||
| for( Iterator e = dictionary.keys(); e.hasNext(); ) | |||
| { | |||
| String key = (String)e.next(); | |||
| boolean isValid = key.length() > 0 && | |||
| Character.isJavaIdentifierStart( key.charAt( 0 ) ); | |||
| for( int i = 1; isValid && i < key.length(); i++ ) | |||
| { | |||
| isValid = Character.isJavaIdentifierPart( key.charAt( i ) ); | |||
| } | |||
| if( isValid ) | |||
| { | |||
| beans.put( key, dictionary.get( key ) ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -1,256 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs; | |||
| import java.text.SimpleDateFormat; | |||
| import java.util.ArrayList; | |||
| import java.util.Calendar; | |||
| import java.util.Date; | |||
| import java.util.Hashtable; | |||
| import java.util.Iterator; | |||
| import java.util.Locale; | |||
| import java.util.NoSuchElementException; | |||
| import java.util.StringTokenizer; | |||
| import java.util.TimeZone; | |||
| import org.apache.myrmidon.api.AbstractTask; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.tools.todo.types.EnumeratedAttribute; | |||
| /** | |||
| * Sets TSTAMP, DSTAMP and TODAY | |||
| * | |||
| * @author costin@dnt.ro | |||
| * @author stefano@apache.org | |||
| * @author roxspring@yahoo.com | |||
| * @author Conor MacNeill | |||
| * @author <a href="mailto:umagesh@apache.org">Magesh Umasankar</a> | |||
| */ | |||
| public class Tstamp | |||
| extends AbstractTask | |||
| { | |||
| private ArrayList customFormats = new ArrayList(); | |||
| private String m_prefix = ""; | |||
| public void setPrefix( String prefix ) | |||
| { | |||
| this.m_prefix = prefix; | |||
| if( !this.m_prefix.endsWith( "." ) ) | |||
| { | |||
| this.m_prefix += "."; | |||
| } | |||
| } | |||
| public CustomFormat createFormat() | |||
| { | |||
| CustomFormat cts = new CustomFormat( m_prefix ); | |||
| customFormats.add( cts ); | |||
| return cts; | |||
| } | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| try | |||
| { | |||
| Date d = new Date(); | |||
| SimpleDateFormat dstamp = new SimpleDateFormat( "yyyyMMdd" ); | |||
| final String name = m_prefix + "DSTAMP"; | |||
| final Object value = dstamp.format( d ); | |||
| getContext().setProperty( name, value ); | |||
| SimpleDateFormat tstamp = new SimpleDateFormat( "HHmm" ); | |||
| final String name1 = m_prefix + "TSTAMP"; | |||
| final Object value1 = tstamp.format( d ); | |||
| getContext().setProperty( name1, value1 ); | |||
| SimpleDateFormat today = new SimpleDateFormat( "MMMM d yyyy", Locale.US ); | |||
| final String name2 = m_prefix + "TODAY"; | |||
| final Object value2 = today.format( d ); | |||
| getContext().setProperty( name2, value2 ); | |||
| Iterator i = customFormats.iterator(); | |||
| while( i.hasNext() ) | |||
| { | |||
| CustomFormat cts = (CustomFormat)i.next(); | |||
| cts.execute( d ); | |||
| } | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| throw new TaskException( "Error", e ); | |||
| } | |||
| } | |||
| public static class Unit extends EnumeratedAttribute | |||
| { | |||
| private final static String MILLISECOND = "millisecond"; | |||
| private final static String SECOND = "second"; | |||
| private final static String MINUTE = "minute"; | |||
| private final static String HOUR = "hour"; | |||
| private final static String DAY = "day"; | |||
| private final static String WEEK = "week"; | |||
| private final static String MONTH = "month"; | |||
| private final static String YEAR = "year"; | |||
| private final static String[] units = { | |||
| MILLISECOND, | |||
| SECOND, | |||
| MINUTE, | |||
| HOUR, | |||
| DAY, | |||
| WEEK, | |||
| MONTH, | |||
| YEAR | |||
| }; | |||
| private Hashtable calendarFields = new Hashtable(); | |||
| public Unit() | |||
| { | |||
| calendarFields.put( MILLISECOND, | |||
| new Integer( Calendar.MILLISECOND ) ); | |||
| calendarFields.put( SECOND, new Integer( Calendar.SECOND ) ); | |||
| calendarFields.put( MINUTE, new Integer( Calendar.MINUTE ) ); | |||
| calendarFields.put( HOUR, new Integer( Calendar.HOUR_OF_DAY ) ); | |||
| calendarFields.put( DAY, new Integer( Calendar.DATE ) ); | |||
| calendarFields.put( WEEK, new Integer( Calendar.WEEK_OF_YEAR ) ); | |||
| calendarFields.put( MONTH, new Integer( Calendar.MONTH ) ); | |||
| calendarFields.put( YEAR, new Integer( Calendar.YEAR ) ); | |||
| } | |||
| public int getCalendarField() | |||
| { | |||
| String key = getValue().toLowerCase(); | |||
| Integer i = (Integer)calendarFields.get( key ); | |||
| return i.intValue(); | |||
| } | |||
| public String[] getValues() | |||
| { | |||
| return units; | |||
| } | |||
| } | |||
| public class CustomFormat | |||
| { | |||
| private int offset = 0; | |||
| private int field = Calendar.DATE; | |||
| private String prefix = ""; | |||
| private String country; | |||
| private String language; | |||
| private String pattern; | |||
| private String propertyName; | |||
| private TimeZone timeZone; | |||
| private String variant; | |||
| public CustomFormat( String prefix ) | |||
| { | |||
| this.prefix = prefix; | |||
| } | |||
| public void setLocale( String locale ) | |||
| throws TaskException | |||
| { | |||
| StringTokenizer st = new StringTokenizer( locale, " \t\n\r\f," ); | |||
| try | |||
| { | |||
| language = st.nextToken(); | |||
| if( st.hasMoreElements() ) | |||
| { | |||
| country = st.nextToken(); | |||
| if( st.hasMoreElements() ) | |||
| { | |||
| country = st.nextToken(); | |||
| if( st.hasMoreElements() ) | |||
| { | |||
| throw new TaskException( "bad locale format" ); | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| country = ""; | |||
| } | |||
| } | |||
| catch( NoSuchElementException e ) | |||
| { | |||
| throw new TaskException( "bad locale format", e ); | |||
| } | |||
| } | |||
| public void setOffset( int offset ) | |||
| { | |||
| this.offset = offset; | |||
| } | |||
| public void setPattern( String pattern ) | |||
| { | |||
| this.pattern = pattern; | |||
| } | |||
| public void setProperty( String propertyName ) | |||
| { | |||
| this.propertyName = prefix + propertyName; | |||
| } | |||
| public void setTimezone( String id ) | |||
| { | |||
| timeZone = TimeZone.getTimeZone( id ); | |||
| } | |||
| public void setUnit( Unit unit ) | |||
| { | |||
| field = unit.getCalendarField(); | |||
| } | |||
| public void execute( final Date date ) | |||
| throws TaskException | |||
| { | |||
| if( propertyName == null ) | |||
| { | |||
| throw new TaskException( "property attribute must be provided" ); | |||
| } | |||
| if( pattern == null ) | |||
| { | |||
| throw new TaskException( "pattern attribute must be provided" ); | |||
| } | |||
| SimpleDateFormat sdf; | |||
| if( language == null ) | |||
| { | |||
| sdf = new SimpleDateFormat( pattern ); | |||
| } | |||
| else if( variant == null ) | |||
| { | |||
| sdf = new SimpleDateFormat( pattern, new Locale( language, country ) ); | |||
| } | |||
| else | |||
| { | |||
| sdf = new SimpleDateFormat( pattern, new Locale( language, country, variant ) ); | |||
| } | |||
| Date time = date; | |||
| if( offset != 0 ) | |||
| { | |||
| final Calendar calendar = Calendar.getInstance(); | |||
| calendar.setTime( time ); | |||
| calendar.add( field, offset ); | |||
| time = calendar.getTime(); | |||
| } | |||
| if( timeZone != null ) | |||
| { | |||
| sdf.setTimeZone( timeZone ); | |||
| } | |||
| getContext().setProperty( propertyName, sdf.format( time ) ); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,181 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs; | |||
| import java.util.Hashtable; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.api.AbstractTask; | |||
| import org.apache.myrmidon.framework.conditions.AndCondition; | |||
| import org.apache.myrmidon.framework.conditions.Condition; | |||
| import org.apache.tools.todo.types.EnumeratedAttribute; | |||
| /** | |||
| * Wait for an external event to occur. Wait for an external process to start or | |||
| * to complete some task. This is useful with the <code>parallel</code> task to | |||
| * syncronize the execution of tests with server startup. The following | |||
| * attributes can be specified on a waitfor task: | |||
| * <ul> | |||
| * <li> maxwait - maximum length of time to wait before giving up</li> | |||
| * <li> maxwaitunit - The unit to be used to interpret maxwait attribute</li> | |||
| * | |||
| * <li> checkevery - amount of time to sleep between each check</li> | |||
| * <li> checkeveryunit - The unit to be used to interpret checkevery attribute | |||
| * </li> | |||
| * <li> timeoutproperty - name of a property to set if maxwait has been | |||
| * exceeded.</li> | |||
| * </ul> | |||
| * The maxwaitunit and checkeveryunit are allowed to have the following values: | |||
| * millesond, second, minute, hour, day and week. The default is millisecond. | |||
| * | |||
| * @author <a href="mailto:denis@network365.com">Denis Hennessy</a> | |||
| * @author <a href="mailto:umagesh@apache.org">Magesh Umasankar</a> | |||
| */ | |||
| public class WaitFor | |||
| extends AbstractTask | |||
| { | |||
| private long maxWaitMillis = 1000l * 60l * 3l;// default max wait time | |||
| private long maxWaitMultiplier = 1l; | |||
| private long checkEveryMillis = 500l; | |||
| private long checkEveryMultiplier = 1l; | |||
| private String timeoutProperty; | |||
| private AndCondition m_condition = new AndCondition(); | |||
| /** | |||
| * Adds a condition. | |||
| */ | |||
| public void add( final Condition condition ) | |||
| { | |||
| m_condition.add( condition ); | |||
| } | |||
| /** | |||
| * Set the time between each check | |||
| * | |||
| * @param time The new CheckEvery value | |||
| */ | |||
| public void setCheckEvery( long time ) | |||
| { | |||
| checkEveryMillis = time; | |||
| } | |||
| /** | |||
| * Set the check every time unit | |||
| * | |||
| * @param unit The new CheckEveryUnit value | |||
| */ | |||
| public void setCheckEveryUnit( Unit unit ) | |||
| { | |||
| checkEveryMultiplier = unit.getMultiplier(); | |||
| } | |||
| /** | |||
| * Set the maximum length of time to wait | |||
| * | |||
| * @param time The new MaxWait value | |||
| */ | |||
| public void setMaxWait( long time ) | |||
| { | |||
| maxWaitMillis = time; | |||
| } | |||
| /** | |||
| * Set the max wait time unit | |||
| * | |||
| * @param unit The new MaxWaitUnit value | |||
| */ | |||
| public void setMaxWaitUnit( Unit unit ) | |||
| { | |||
| maxWaitMultiplier = unit.getMultiplier(); | |||
| } | |||
| /** | |||
| * Set the timeout property. | |||
| * | |||
| * @param p The new TimeoutProperty value | |||
| */ | |||
| public void setTimeoutProperty( String p ) | |||
| { | |||
| timeoutProperty = p; | |||
| } | |||
| /** | |||
| * Check repeatedly for the specified conditions until they become true or | |||
| * the timeout expires. | |||
| * | |||
| * @exception org.apache.myrmidon.api.TaskException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| maxWaitMillis *= maxWaitMultiplier; | |||
| checkEveryMillis *= checkEveryMultiplier; | |||
| long start = System.currentTimeMillis(); | |||
| long end = start + maxWaitMillis; | |||
| while( System.currentTimeMillis() < end ) | |||
| { | |||
| if( m_condition.evaluate( getContext() ) ) | |||
| { | |||
| return; | |||
| } | |||
| try | |||
| { | |||
| Thread.sleep( checkEveryMillis ); | |||
| } | |||
| catch( InterruptedException e ) | |||
| { | |||
| } | |||
| } | |||
| if( timeoutProperty != null ) | |||
| { | |||
| final String name = timeoutProperty; | |||
| getContext().setProperty( name, "true" ); | |||
| } | |||
| } | |||
| public static class Unit extends EnumeratedAttribute | |||
| { | |||
| private final static String MILLISECOND = "millisecond"; | |||
| private final static String SECOND = "second"; | |||
| private final static String MINUTE = "minute"; | |||
| private final static String HOUR = "hour"; | |||
| private final static String DAY = "day"; | |||
| private final static String WEEK = "week"; | |||
| private final static String[] units = { | |||
| MILLISECOND, SECOND, MINUTE, HOUR, DAY, WEEK | |||
| }; | |||
| private Hashtable timeTable = new Hashtable(); | |||
| public Unit() | |||
| { | |||
| timeTable.put( MILLISECOND, new Long( 1l ) ); | |||
| timeTable.put( SECOND, new Long( 1000l ) ); | |||
| timeTable.put( MINUTE, new Long( 1000l * 60l ) ); | |||
| timeTable.put( HOUR, new Long( 1000l * 60l * 60l ) ); | |||
| timeTable.put( DAY, new Long( 1000l * 60l * 60l * 24l ) ); | |||
| timeTable.put( WEEK, new Long( 1000l * 60l * 60l * 24l * 7l ) ); | |||
| } | |||
| public long getMultiplier() | |||
| { | |||
| String key = getValue().toLowerCase(); | |||
| Long l = (Long)timeTable.get( key ); | |||
| return l.longValue(); | |||
| } | |||
| public String[] getValues() | |||
| { | |||
| return units; | |||
| } | |||
| } | |||
| } | |||
| @@ -1,97 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.archive; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import org.apache.excalibur.zip.ZipOutputStream; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| /** | |||
| * Creates a EAR archive. Based on WAR task | |||
| * | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:leslie.hughes@rubus.com">Les Hughes</a> | |||
| */ | |||
| public class Ear | |||
| extends Jar | |||
| { | |||
| private File m_appxml; | |||
| private boolean m_descriptorAdded; | |||
| public Ear() | |||
| { | |||
| m_archiveType = "ear"; | |||
| m_emptyBehavior = "create"; | |||
| } | |||
| public void setAppxml( final File appxml ) | |||
| throws TaskException | |||
| { | |||
| m_appxml = appxml; | |||
| if( !m_appxml.exists() ) | |||
| { | |||
| final String message = "Deployment descriptor: " + | |||
| m_appxml + " does not exist."; | |||
| throw new TaskException( message ); | |||
| } | |||
| addFileAs( m_appxml, "META-INF/application.xml" ); | |||
| } | |||
| public void addArchives( ZipFileSet fs ) | |||
| { | |||
| // We just set the prefix for this fileset, and pass it up. | |||
| // Do we need to do this? LH | |||
| getContext().debug( "addArchives called" ); | |||
| fs.setPrefix( "/" ); | |||
| super.addFileset( fs ); | |||
| } | |||
| protected void initZipOutputStream( final ZipOutputStream zOut ) | |||
| throws IOException, TaskException | |||
| { | |||
| if( m_appxml == null && !isInUpdateMode() ) | |||
| { | |||
| final String message = "appxml attribute is required"; | |||
| throw new TaskException( message ); | |||
| } | |||
| super.initZipOutputStream( zOut ); | |||
| } | |||
| protected void zipFile( File file, ZipOutputStream zOut, String vPath ) | |||
| throws IOException, TaskException | |||
| { | |||
| // If the file being added is WEB-INF/web.xml, we warn if it's not the | |||
| // one specified in the "webxml" attribute - or if it's being added twice, | |||
| // meaning the same file is specified by the "webxml" attribute and in | |||
| // a <fileset> element. | |||
| if( vPath.equalsIgnoreCase( "META-INF/aplication.xml" ) ) | |||
| { | |||
| if( m_appxml == null || | |||
| !m_appxml.equals( file ) || | |||
| m_descriptorAdded ) | |||
| { | |||
| final String message = "Warning: selected " + m_archiveType + | |||
| " files include a META-INF/application.xml which will be ignored " + | |||
| "(please use appxml attribute to " + m_archiveType + " task)"; | |||
| getContext().warn( message ); | |||
| } | |||
| else | |||
| { | |||
| super.zipFile( file, zOut, vPath ); | |||
| m_descriptorAdded = true; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| super.zipFile( file, zOut, vPath ); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,286 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.archive; | |||
| import java.io.File; | |||
| import java.io.FileNotFoundException; | |||
| import java.io.FileOutputStream; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.util.ArrayList; | |||
| import java.util.Date; | |||
| import org.apache.avalon.excalibur.io.FileUtil; | |||
| import org.apache.avalon.excalibur.io.IOUtil; | |||
| import org.apache.myrmidon.api.TaskContext; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.FileSet; | |||
| import org.apache.myrmidon.framework.PatternSet; | |||
| import org.apache.myrmidon.framework.PatternUtil; | |||
| import org.apache.tools.todo.taskdefs.MatchingTask; | |||
| import org.apache.tools.todo.types.DirectoryScanner; | |||
| import org.apache.tools.todo.types.ScannerUtil; | |||
| /** | |||
| * Unzip a file. | |||
| * | |||
| * @author costin@dnt.ro | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a> | |||
| */ | |||
| public abstract class Expand | |||
| extends MatchingTask | |||
| { | |||
| private boolean m_overwrite = true; | |||
| private ArrayList m_patternsets = new ArrayList(); | |||
| private ArrayList m_filesets = new ArrayList(); | |||
| private File m_dest;//req | |||
| private File m_src; | |||
| /** | |||
| * Set the destination directory. File will be unzipped into the destination | |||
| * directory. | |||
| * | |||
| * @param dest Path to the directory. | |||
| */ | |||
| public void setDest( final File dest ) | |||
| { | |||
| m_dest = dest; | |||
| } | |||
| /** | |||
| * Should we overwrite files in dest, even if they are newer than the | |||
| * corresponding entries in the archive? | |||
| * | |||
| * @param overwrite The new Overwrite value | |||
| */ | |||
| public void setOverwrite( final boolean overwrite ) | |||
| { | |||
| m_overwrite = overwrite; | |||
| } | |||
| /** | |||
| * Set the path to zip-file. | |||
| * | |||
| * @param src Path to zip-file. | |||
| */ | |||
| public void setSrc( final File src ) | |||
| { | |||
| m_src = src; | |||
| } | |||
| /** | |||
| * Add a fileset | |||
| * | |||
| * @param set The feature to be added to the Fileset attribute | |||
| */ | |||
| public void addFileset( final FileSet set ) | |||
| { | |||
| m_filesets.add( set ); | |||
| } | |||
| /** | |||
| * Add a patternset | |||
| * | |||
| * @param set The feature to be added to the Patternset attribute | |||
| */ | |||
| public void addPatternset( final PatternSet set ) | |||
| { | |||
| m_patternsets.add( set ); | |||
| } | |||
| /** | |||
| * Do the work. | |||
| * | |||
| * @exception org.apache.myrmidon.api.TaskException Thrown in unrecoverable error. | |||
| */ | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| validate(); | |||
| if( m_src != null ) | |||
| { | |||
| expandFile( m_src, m_dest ); | |||
| } | |||
| final int size = m_filesets.size(); | |||
| if( size > 0 ) | |||
| { | |||
| for( int j = 0; j < size; j++ ) | |||
| { | |||
| final FileSet fileSet = (FileSet)m_filesets.get( j ); | |||
| final DirectoryScanner scanner = ScannerUtil.getDirectoryScanner( fileSet ); | |||
| final File fromDir = fileSet.getDir(); | |||
| final String[] files = scanner.getIncludedFiles(); | |||
| for( int i = 0; i < files.length; ++i ) | |||
| { | |||
| final File file = new File( fromDir, files[ i ] ); | |||
| expandFile( file, m_dest ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| private void validate() | |||
| throws TaskException | |||
| { | |||
| if( m_src == null && m_filesets.size() == 0 ) | |||
| { | |||
| final String message = "src attribute and/or filesets must be specified"; | |||
| throw new TaskException( message ); | |||
| } | |||
| if( m_dest == null ) | |||
| { | |||
| final String message = "Dest attribute must be specified"; | |||
| throw new TaskException( message ); | |||
| } | |||
| if( m_dest.exists() && !m_dest.isDirectory() ) | |||
| { | |||
| final String message = "Dest must be a directory."; | |||
| throw new TaskException( message ); | |||
| } | |||
| if( m_src != null && m_src.isDirectory() ) | |||
| { | |||
| final String message = "Src must not be a directory." + | |||
| " Use nested filesets instead."; | |||
| throw new TaskException( message ); | |||
| } | |||
| } | |||
| /* | |||
| * This method is to be overridden by extending unarchival tasks. | |||
| */ | |||
| protected void expandFile( final File src, final File dir ) | |||
| throws TaskException | |||
| { | |||
| if( getContext().isInfoEnabled() ) | |||
| { | |||
| final String message = "Expanding: " + src + " into " + dir; | |||
| getContext().info( message ); | |||
| } | |||
| try | |||
| { | |||
| expandArchive( src, dir ); | |||
| } | |||
| catch( final IOException ioe ) | |||
| { | |||
| final String message = "Error while expanding " + src.getPath(); | |||
| throw new TaskException( message, ioe ); | |||
| } | |||
| if( getContext().isDebugEnabled() ) | |||
| { | |||
| final String message = "expand complete"; | |||
| getContext().debug( message ); | |||
| } | |||
| } | |||
| protected abstract void expandArchive( final File src, final File dir ) | |||
| throws IOException, TaskException; | |||
| protected void extractFile( final File dir, | |||
| final InputStream input, | |||
| final String entryName, | |||
| final Date date, | |||
| final boolean isDirectory ) | |||
| throws IOException, TaskException | |||
| { | |||
| final int size = m_patternsets.size(); | |||
| if( m_patternsets != null && size > 0 ) | |||
| { | |||
| boolean included = false; | |||
| for( int i = 0; i < size; i++ ) | |||
| { | |||
| PatternSet p = (PatternSet)m_patternsets.get( i ); | |||
| final TaskContext context = getContext(); | |||
| String[] incls = PatternUtil.getIncludePatterns( p, context ); | |||
| if( incls != null ) | |||
| { | |||
| for( int j = 0; j < incls.length; j++ ) | |||
| { | |||
| boolean isIncl = ScannerUtil.match( incls[ j ], entryName ); | |||
| if( isIncl ) | |||
| { | |||
| included = true; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| final TaskContext context1 = getContext(); | |||
| String[] excls = PatternUtil.getExcludePatterns( p, context1 ); | |||
| if( excls != null ) | |||
| { | |||
| for( int j = 0; j < excls.length; j++ ) | |||
| { | |||
| boolean isExcl = ScannerUtil.match( excls[ j ], entryName ); | |||
| if( isExcl ) | |||
| { | |||
| included = false; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| if( !included ) | |||
| { | |||
| //Do not process this file | |||
| return; | |||
| } | |||
| } | |||
| final File file = FileUtil.resolveFile( dir, entryName ); | |||
| try | |||
| { | |||
| if( !m_overwrite && file.exists() && | |||
| file.lastModified() >= date.getTime() ) | |||
| { | |||
| final String message = "Skipping " + file + " as it is up-to-date"; | |||
| getContext().debug( message ); | |||
| return; | |||
| } | |||
| getContext().debug( "expanding " + entryName + " to " + file ); | |||
| // create intermediary directories - sometimes zip don't add them | |||
| final File parent = file.getParentFile(); | |||
| parent.mkdirs(); | |||
| if( isDirectory ) | |||
| { | |||
| file.mkdirs(); | |||
| } | |||
| else | |||
| { | |||
| FileOutputStream fos = null; | |||
| try | |||
| { | |||
| fos = new FileOutputStream( file ); | |||
| IOUtil.copy( input, fos ); | |||
| } | |||
| finally | |||
| { | |||
| IOUtil.shutdownStream( fos ); | |||
| } | |||
| } | |||
| file.setLastModified( date.getTime() ); | |||
| } | |||
| catch( final FileNotFoundException fnfe ) | |||
| { | |||
| final String message = "Unable to expand to file " + file.getPath(); | |||
| getContext().warn( message ); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,395 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.archive; | |||
| import java.io.ByteArrayInputStream; | |||
| import java.io.ByteArrayOutputStream; | |||
| import java.io.File; | |||
| import java.io.FileReader; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.io.InputStreamReader; | |||
| import java.io.OutputStreamWriter; | |||
| import java.io.PrintWriter; | |||
| import java.io.Reader; | |||
| import java.util.Enumeration; | |||
| import java.util.zip.ZipFile; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.tools.todo.taskdefs.manifest.Manifest; | |||
| import org.apache.tools.todo.taskdefs.manifest.ManifestException; | |||
| import org.apache.tools.todo.taskdefs.manifest.ManifestUtil; | |||
| import org.apache.tools.todo.types.FileScanner; | |||
| import org.apache.excalibur.zip.ZipOutputStream; | |||
| /** | |||
| * Creates a JAR archive. | |||
| * | |||
| * @author James Davidson <a href="mailto:duncan@x180.com">duncan@x180.com</a> | |||
| */ | |||
| public class Jar | |||
| extends Zip | |||
| { | |||
| /** | |||
| * The index file name. | |||
| */ | |||
| private final static String INDEX_NAME = "META-INF/INDEX.LIST"; | |||
| /** | |||
| * true if a manifest has been specified in the task | |||
| */ | |||
| private boolean buildFileManifest; | |||
| /** | |||
| * jar index is JDK 1.3+ only | |||
| */ | |||
| private boolean m_index; | |||
| private Manifest m_execManifest; | |||
| private Manifest m_manifest; | |||
| private File m_manifestFile; | |||
| /** | |||
| * constructor | |||
| */ | |||
| public Jar() | |||
| { | |||
| super(); | |||
| m_archiveType = "jar"; | |||
| m_emptyBehavior = "create"; | |||
| setEncoding( "UTF8" ); | |||
| } | |||
| /** | |||
| * Set whether or not to create an index list for classes to speed up | |||
| * classloading. | |||
| * | |||
| * @param flag The new Index value | |||
| */ | |||
| public void setIndex( boolean flag ) | |||
| { | |||
| m_index = flag; | |||
| } | |||
| public void setManifest( File manifestFile ) | |||
| throws TaskException | |||
| { | |||
| if( !manifestFile.exists() ) | |||
| { | |||
| final String message = "Manifest file: " + manifestFile + " does not exist."; | |||
| throw new TaskException( message ); | |||
| } | |||
| this.m_manifestFile = manifestFile; | |||
| Reader r = null; | |||
| try | |||
| { | |||
| r = new FileReader( manifestFile ); | |||
| Manifest newManifest = ManifestUtil.buildManifest( r ); | |||
| if( m_manifest == null ) | |||
| { | |||
| m_manifest = ManifestUtil.getDefaultManifest(); | |||
| } | |||
| m_manifest.merge( newManifest ); | |||
| } | |||
| catch( ManifestException e ) | |||
| { | |||
| final String message = "Manifest " + manifestFile + " is invalid: " + e.getMessage(); | |||
| getContext().error( message ); | |||
| throw new TaskException( message, e ); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| final String message = "Unable to read manifest file: " + manifestFile; | |||
| throw new TaskException( message, e ); | |||
| } | |||
| finally | |||
| { | |||
| if( r != null ) | |||
| { | |||
| try | |||
| { | |||
| r.close(); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| // do nothing | |||
| } | |||
| } | |||
| } | |||
| } | |||
| public void setWhenempty( WhenEmpty we ) | |||
| { | |||
| final String message = "JARs are never empty, they contain at least a manifest file"; | |||
| getContext().warn( message ); | |||
| } | |||
| public void addManifest( Manifest newManifest ) | |||
| throws ManifestException, TaskException | |||
| { | |||
| if( m_manifest == null ) | |||
| { | |||
| m_manifest = ManifestUtil.getDefaultManifest(); | |||
| } | |||
| m_manifest.merge( newManifest ); | |||
| buildFileManifest = true; | |||
| } | |||
| public void addMetainf( ZipFileSet fs ) | |||
| { | |||
| // We just set the prefix for this fileset, and pass it up. | |||
| fs.setPrefix( "META-INF/" ); | |||
| super.addFileset( fs ); | |||
| } | |||
| /** | |||
| * Check whether the archive is up-to-date; | |||
| * | |||
| * @param scanners list of prepared scanners containing files to archive | |||
| * @param zipFile intended archive file (may or may not exist) | |||
| * @return true if nothing need be done (may have done something already); | |||
| * false if archive creation should proceed | |||
| * @exception org.apache.myrmidon.api.TaskException if it likes | |||
| */ | |||
| protected boolean isUpToDate( FileScanner[] scanners, File zipFile ) | |||
| throws TaskException | |||
| { | |||
| // need to handle manifest as a special check | |||
| if( buildFileManifest || m_manifestFile == null ) | |||
| { | |||
| java.util.zip.ZipFile theZipFile = null; | |||
| try | |||
| { | |||
| theZipFile = new ZipFile( zipFile ); | |||
| java.util.zip.ZipEntry entry = theZipFile.getEntry( "META-INF/MANIFEST.MF" ); | |||
| if( entry == null ) | |||
| { | |||
| getContext().debug( "Updating jar since the current jar has no manifest" ); | |||
| return false; | |||
| } | |||
| Manifest currentManifest = ManifestUtil.buildManifest( new InputStreamReader( theZipFile.getInputStream( entry ) ) ); | |||
| if( m_manifest == null ) | |||
| { | |||
| m_manifest = ManifestUtil.getDefaultManifest(); | |||
| } | |||
| if( !currentManifest.equals( m_manifest ) ) | |||
| { | |||
| getContext().debug( "Updating jar since jar manifest has changed" ); | |||
| return false; | |||
| } | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| // any problems and we will rebuild | |||
| getContext().debug( "Updating jar since cannot read current jar manifest: " + e.getClass().getName() + e.getMessage() ); | |||
| return false; | |||
| } | |||
| finally | |||
| { | |||
| if( theZipFile != null ) | |||
| { | |||
| try | |||
| { | |||
| theZipFile.close(); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| //ignore | |||
| } | |||
| } | |||
| } | |||
| } | |||
| else if( m_manifestFile.lastModified() > zipFile.lastModified() ) | |||
| { | |||
| return false; | |||
| } | |||
| return super.isUpToDate( scanners, zipFile ); | |||
| } | |||
| protected boolean createEmptyZip( File zipFile ) | |||
| { | |||
| // Jar files always contain a manifest and can never be empty | |||
| return false; | |||
| } | |||
| protected void finalizeZipOutputStream( ZipOutputStream zOut ) | |||
| throws IOException, TaskException | |||
| { | |||
| if( m_index ) | |||
| { | |||
| createIndexList( zOut ); | |||
| } | |||
| } | |||
| protected void initZipOutputStream( ZipOutputStream zOut ) | |||
| throws IOException, TaskException | |||
| { | |||
| try | |||
| { | |||
| m_execManifest = ManifestUtil.getDefaultManifest(); | |||
| if( m_manifest != null ) | |||
| { | |||
| m_execManifest.merge( m_manifest ); | |||
| } | |||
| /* | |||
| for( Iterator e = m_execManifest.getWarnings(); e.hasNext(); ) | |||
| { | |||
| getLogger().warn( "Manifest warning: " + (String)e.next() ); | |||
| } | |||
| */ | |||
| zipDir( null, zOut, "META-INF/" ); | |||
| // time to write the manifest | |||
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |||
| PrintWriter writer = new PrintWriter( baos ); | |||
| Manifest manifest = m_execManifest; | |||
| ManifestUtil.write( manifest, writer ); | |||
| writer.flush(); | |||
| ByteArrayInputStream bais = new ByteArrayInputStream( baos.toByteArray() ); | |||
| super.zipFile( bais, zOut, "META-INF/MANIFEST.MF", System.currentTimeMillis() ); | |||
| super.initZipOutputStream( zOut ); | |||
| } | |||
| catch( ManifestException e ) | |||
| { | |||
| getContext().error( "Manifest is invalid: " + e.getMessage() ); | |||
| throw new TaskException( "Invalid Manifest", e ); | |||
| } | |||
| } | |||
| protected void zipFile( File file, ZipOutputStream zOut, String vPath ) | |||
| throws IOException, TaskException | |||
| { | |||
| // If the file being added is META-INF/MANIFEST.MF, we warn if it's not the | |||
| // one specified in the "manifest" attribute - or if it's being added twice, | |||
| // meaning the same file is specified by the "manifeset" attribute and in | |||
| // a <fileset> element. | |||
| if( vPath.equalsIgnoreCase( "META-INF/MANIFEST.MF" ) ) | |||
| { | |||
| final String message = "Warning: selected " + m_archiveType + | |||
| " files include a META-INF/MANIFEST.MF which will be ignored " + | |||
| "(please use manifest attribute to " + m_archiveType + " task)"; | |||
| getContext().warn( message ); | |||
| } | |||
| else | |||
| { | |||
| super.zipFile( file, zOut, vPath ); | |||
| } | |||
| } | |||
| protected void zipFile( InputStream is, ZipOutputStream zOut, String vPath, long lastModified ) | |||
| throws IOException, TaskException | |||
| { | |||
| // If the file being added is META-INF/MANIFEST.MF, we merge it with the | |||
| // current manifest | |||
| if( vPath.equalsIgnoreCase( "META-INF/MANIFEST.MF" ) ) | |||
| { | |||
| try | |||
| { | |||
| zipManifestEntry( is ); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| throw new TaskException( "Unable to read manifest file: ", e ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| super.zipFile( is, zOut, vPath, lastModified ); | |||
| } | |||
| } | |||
| /** | |||
| * Create the index list to speed up classloading. This is a JDK 1.3+ | |||
| * specific feature and is enabled by default. {@link | |||
| * http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#JAR%20Index} | |||
| * | |||
| * @param zOut the zip stream representing the jar being built. | |||
| * @throws java.io.IOException thrown if there is an error while creating the index | |||
| * and adding it to the zip stream. | |||
| */ | |||
| private void createIndexList( ZipOutputStream zOut ) | |||
| throws IOException, TaskException | |||
| { | |||
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |||
| // encoding must be UTF8 as specified in the specs. | |||
| PrintWriter writer = new PrintWriter( new OutputStreamWriter( baos, "UTF8" ) ); | |||
| // version-info blankline | |||
| writer.println( "JarIndex-Version: 1.0" ); | |||
| writer.println(); | |||
| // header newline | |||
| writer.println( m_file.getName() ); | |||
| // JarIndex is sorting the directories by ascending order. | |||
| // it's painful to do in JDK 1.1 and it has no value but cosmetic | |||
| // since it will be read into a hashtable by the classloader. | |||
| Enumeration enum = m_addedDirs.keys(); | |||
| while( enum.hasMoreElements() ) | |||
| { | |||
| String dir = (String)enum.nextElement(); | |||
| // try to be smart, not to be fooled by a weird directory name | |||
| // @fixme do we need to check for directories starting by ./ ? | |||
| dir = dir.replace( '\\', '/' ); | |||
| int pos = dir.lastIndexOf( '/' ); | |||
| if( pos != -1 ) | |||
| { | |||
| dir = dir.substring( 0, pos ); | |||
| } | |||
| // looks like nothing from META-INF should be added | |||
| // and the check is not case insensitive. | |||
| // see sun.misc.JarIndex | |||
| if( dir.startsWith( "META-INF" ) ) | |||
| { | |||
| continue; | |||
| } | |||
| // name newline | |||
| writer.println( dir ); | |||
| } | |||
| writer.flush(); | |||
| ByteArrayInputStream bais = new ByteArrayInputStream( baos.toByteArray() ); | |||
| super.zipFile( bais, zOut, INDEX_NAME, System.currentTimeMillis() ); | |||
| } | |||
| /** | |||
| * Handle situation when we encounter a manifest file If we haven't been | |||
| * given one, we use this one. If we have, we merge the manifest in, | |||
| * provided it is a new file and not the old one from the JAR we are | |||
| * updating | |||
| * | |||
| * @param is Description of Parameter | |||
| * @exception java.io.IOException Description of Exception | |||
| */ | |||
| private void zipManifestEntry( InputStream is ) | |||
| throws IOException, TaskException | |||
| { | |||
| try | |||
| { | |||
| if( m_execManifest == null ) | |||
| { | |||
| m_execManifest = ManifestUtil.buildManifest( new InputStreamReader( is ) ); | |||
| } | |||
| else if( isAddingNewFiles() ) | |||
| { | |||
| final Manifest other = ManifestUtil.buildManifest( new InputStreamReader( is ) ); | |||
| m_execManifest.merge( other ); | |||
| } | |||
| } | |||
| catch( ManifestException e ) | |||
| { | |||
| getContext().error( "Manifest is invalid: " + e.getMessage() ); | |||
| throw new TaskException( "Invalid Manifest", e ); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,306 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.archive; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.FileOutputStream; | |||
| import java.io.IOException; | |||
| import java.util.ArrayList; | |||
| import java.util.Iterator; | |||
| import org.apache.avalon.excalibur.io.IOUtil; | |||
| import org.apache.excalibur.tar.TarEntry; | |||
| import org.apache.excalibur.tar.TarOutputStream; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.tools.todo.taskdefs.MatchingTask; | |||
| import org.apache.tools.todo.types.ScannerUtil; | |||
| import org.apache.tools.todo.types.SourceFileScanner; | |||
| import org.apache.tools.todo.util.mappers.MergingMapper; | |||
| /** | |||
| * Creates a TAR archive. | |||
| * | |||
| * @author Stefano Mazzocchi <a href="mailto:stefano@apache.org"> | |||
| * stefano@apache.org</a> | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:umagesh@apache.org">Magesh Umasankar</a> | |||
| */ | |||
| public class Tar | |||
| extends MatchingTask | |||
| { | |||
| private TarLongFileMode longFileMode = createMode(); | |||
| private TarLongFileMode createMode() | |||
| { | |||
| try | |||
| { | |||
| return new TarLongFileMode(); | |||
| } | |||
| catch( TaskException e ) | |||
| { | |||
| throw new IllegalStateException( e.getMessage() ); | |||
| } | |||
| } | |||
| ArrayList filesets = new ArrayList(); | |||
| ArrayList fileSetFiles = new ArrayList(); | |||
| /** | |||
| * Indicates whether the user has been warned about long files already. | |||
| */ | |||
| private boolean longWarningGiven = false; | |||
| File baseDir; | |||
| File tarFile; | |||
| /** | |||
| * This is the base directory to look in for things to tar. | |||
| * | |||
| * @param baseDir The new Basedir value | |||
| */ | |||
| public void setBasedir( File baseDir ) | |||
| { | |||
| this.baseDir = baseDir; | |||
| } | |||
| /** | |||
| * Set how to handle long files. Allowable values are truncate - paths are | |||
| * truncated to the maximum length fail - paths greater than the maximim | |||
| * cause a build exception warn - paths greater than the maximum cause a | |||
| * warning and GNU is used gnu - GNU extensions are used for any paths | |||
| * greater than the maximum. omit - paths greater than the maximum are | |||
| * omitted from the archive | |||
| * | |||
| * @param mode The new Longfile value | |||
| */ | |||
| public void setLongfile( TarLongFileMode mode ) | |||
| { | |||
| this.longFileMode = mode; | |||
| } | |||
| /** | |||
| * This is the name/location of where to create the tar file. | |||
| * | |||
| * @param tarFile The new Tarfile value | |||
| */ | |||
| public void setTarfile( File tarFile ) | |||
| { | |||
| this.tarFile = tarFile; | |||
| } | |||
| public TarFileSet createTarFileSet() | |||
| { | |||
| TarFileSet fileset = new TarFileSet(); | |||
| filesets.add( fileset ); | |||
| return fileset; | |||
| } | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| if( tarFile == null ) | |||
| { | |||
| throw new TaskException( "tarfile attribute must be set!" ); | |||
| } | |||
| if( tarFile.exists() && tarFile.isDirectory() ) | |||
| { | |||
| throw new TaskException( "tarfile is a directory!" ); | |||
| } | |||
| if( tarFile.exists() && !tarFile.canWrite() ) | |||
| { | |||
| throw new TaskException( "Can not write to the specified tarfile!" ); | |||
| } | |||
| if( baseDir != null ) | |||
| { | |||
| if( !baseDir.exists() ) | |||
| { | |||
| throw new TaskException( "basedir does not exist!" ); | |||
| } | |||
| // add the main fileset to the list of filesets to process. | |||
| final TarFileSet mainFileSet = new TarFileSet( /*fileset*/ ); | |||
| mainFileSet.setDir( baseDir ); | |||
| filesets.add( mainFileSet ); | |||
| } | |||
| if( filesets.size() == 0 ) | |||
| { | |||
| throw new TaskException( "You must supply either a basdir attribute or some nested filesets." ); | |||
| } | |||
| // check if tr is out of date with respect to each | |||
| // fileset | |||
| boolean upToDate = true; | |||
| for( Iterator e = filesets.iterator(); e.hasNext(); ) | |||
| { | |||
| TarFileSet fs = (TarFileSet)e.next(); | |||
| String[] files = ScannerUtil.getFiles( fs ); | |||
| if( !archiveIsUpToDate( files ) ) | |||
| { | |||
| upToDate = false; | |||
| } | |||
| for( int i = 0; i < files.length; ++i ) | |||
| { | |||
| if( tarFile.equals( new File( fs.getDir(), files[ i ] ) ) ) | |||
| { | |||
| throw new TaskException( "A tar file cannot include itself" ); | |||
| } | |||
| } | |||
| } | |||
| if( upToDate ) | |||
| { | |||
| getContext().info( "Nothing to do: " + tarFile.getAbsolutePath() + " is up to date." ); | |||
| return; | |||
| } | |||
| getContext().info( "Building tar: " + tarFile.getAbsolutePath() ); | |||
| TarOutputStream tOut = null; | |||
| try | |||
| { | |||
| tOut = new TarOutputStream( new FileOutputStream( tarFile ) ); | |||
| if( longFileMode.isTruncateMode() ) | |||
| { | |||
| tOut.setLongFileMode( TarOutputStream.LONGFILE_TRUNCATE ); | |||
| } | |||
| else if( longFileMode.isFailMode() || | |||
| longFileMode.isOmitMode() ) | |||
| { | |||
| tOut.setLongFileMode( TarOutputStream.LONGFILE_ERROR ); | |||
| } | |||
| else | |||
| { | |||
| // warn or GNU | |||
| tOut.setLongFileMode( TarOutputStream.LONGFILE_GNU ); | |||
| } | |||
| longWarningGiven = false; | |||
| for( Iterator e = filesets.iterator(); e.hasNext(); ) | |||
| { | |||
| TarFileSet fs = (TarFileSet)e.next(); | |||
| String[] files = ScannerUtil.getFiles( fs ); | |||
| for( int i = 0; i < files.length; i++ ) | |||
| { | |||
| File f = new File( fs.getDir(), files[ i ] ); | |||
| String name = files[ i ].replace( File.separatorChar, '/' ); | |||
| tarFile( f, tOut, name, fs ); | |||
| } | |||
| } | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| String msg = "Problem creating TAR: " + ioe.getMessage(); | |||
| throw new TaskException( msg, ioe ); | |||
| } | |||
| finally | |||
| { | |||
| if( tOut != null ) | |||
| { | |||
| try | |||
| { | |||
| // close up | |||
| tOut.close(); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| } | |||
| } | |||
| } | |||
| } | |||
| private boolean archiveIsUpToDate( final String[] files ) | |||
| throws TaskException | |||
| { | |||
| final SourceFileScanner scanner = new SourceFileScanner(); | |||
| final MergingMapper mapper = new MergingMapper(); | |||
| mapper.setTo( tarFile.getAbsolutePath() ); | |||
| return scanner.restrict( files, baseDir, null, mapper, getContext() ).length == 0; | |||
| } | |||
| private void tarFile( final File file, | |||
| final TarOutputStream output, | |||
| final String path, | |||
| final TarFileSet tarFileSet ) | |||
| throws IOException, TaskException | |||
| { | |||
| String storedPath = path; | |||
| // don't add "" to the archive | |||
| if( storedPath.length() <= 0 ) | |||
| { | |||
| return; | |||
| } | |||
| if( file.isDirectory() && !storedPath.endsWith( "/" ) ) | |||
| { | |||
| storedPath += "/"; | |||
| } | |||
| if( storedPath.length() >= TarEntry.NAMELEN ) | |||
| { | |||
| if( longFileMode.isOmitMode() ) | |||
| { | |||
| final String message = "Omitting: " + storedPath; | |||
| getContext().info( message ); | |||
| return; | |||
| } | |||
| else if( longFileMode.isWarnMode() ) | |||
| { | |||
| final String message = "Entry: " + storedPath + " longer than " + | |||
| TarEntry.NAMELEN + " characters."; | |||
| getContext().warn( message ); | |||
| if( !longWarningGiven ) | |||
| { | |||
| final String message2 = "Resulting tar file can only be processed successfully" | |||
| + " by GNU compatible tar commands"; | |||
| getContext().warn( message2 ); | |||
| longWarningGiven = true; | |||
| } | |||
| } | |||
| else if( longFileMode.isFailMode() ) | |||
| { | |||
| final String message = "Entry: " + storedPath + " longer than " + | |||
| TarEntry.NAMELEN + "characters."; | |||
| throw new TaskException( message ); | |||
| } | |||
| } | |||
| FileInputStream input = null; | |||
| try | |||
| { | |||
| final TarEntry entry = new TarEntry( storedPath ); | |||
| entry.setModTime( file.lastModified() ); | |||
| if( !file.isDirectory() ) | |||
| { | |||
| entry.setSize( file.length() ); | |||
| entry.setMode( tarFileSet.getMode() ); | |||
| } | |||
| entry.setUserName( tarFileSet.getUserName() ); | |||
| entry.setGroupName( tarFileSet.getGroup() ); | |||
| output.putNextEntry( entry ); | |||
| if( !file.isDirectory() ) | |||
| { | |||
| input = new FileInputStream( file ); | |||
| IOUtil.copy( input, output ); | |||
| } | |||
| output.closeEntry(); | |||
| } | |||
| finally | |||
| { | |||
| IOUtil.shutdownStream( input ); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,48 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.archive; | |||
| import org.apache.myrmidon.framework.FileSet; | |||
| public class TarFileSet | |||
| extends FileSet | |||
| { | |||
| private int m_mode = 0100644; | |||
| private String m_userName = ""; | |||
| private String m_groupName = ""; | |||
| public void setGroup( final String groupName ) | |||
| { | |||
| m_groupName = groupName; | |||
| } | |||
| public void setMode( final String octalString ) | |||
| { | |||
| m_mode = 0100000 | Integer.parseInt( octalString, 8 ); | |||
| } | |||
| public void setUserName( final String userName ) | |||
| { | |||
| m_userName = userName; | |||
| } | |||
| protected String getGroup() | |||
| { | |||
| return m_groupName; | |||
| } | |||
| protected int getMode() | |||
| { | |||
| return m_mode; | |||
| } | |||
| protected String getUserName() | |||
| { | |||
| return m_userName; | |||
| } | |||
| } | |||
| @@ -1,66 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.archive; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.tools.todo.types.EnumeratedAttribute; | |||
| /** | |||
| * Valid Modes for LongFile attribute to Tar Task | |||
| * | |||
| * @author <a href="mailto:umagesh@apache.org">Magesh Umasankar</a> | |||
| */ | |||
| public class TarLongFileMode | |||
| extends EnumeratedAttribute | |||
| { | |||
| // permissable values for longfile attribute | |||
| public final static String WARN = "warn"; | |||
| public final static String FAIL = "fail"; | |||
| public final static String TRUNCATE = "truncate"; | |||
| public final static String GNU = "gnu"; | |||
| public final static String OMIT = "omit"; | |||
| private final String[] validModes = {WARN, FAIL, TRUNCATE, GNU, OMIT}; | |||
| public TarLongFileMode() | |||
| throws TaskException | |||
| { | |||
| super(); | |||
| setValue( WARN ); | |||
| } | |||
| public String[] getValues() | |||
| { | |||
| return validModes; | |||
| } | |||
| public boolean isFailMode() | |||
| { | |||
| return FAIL.equalsIgnoreCase( getValue() ); | |||
| } | |||
| public boolean isGnuMode() | |||
| { | |||
| return GNU.equalsIgnoreCase( getValue() ); | |||
| } | |||
| public boolean isOmitMode() | |||
| { | |||
| return OMIT.equalsIgnoreCase( getValue() ); | |||
| } | |||
| public boolean isTruncateMode() | |||
| { | |||
| return TRUNCATE.equalsIgnoreCase( getValue() ); | |||
| } | |||
| public boolean isWarnMode() | |||
| { | |||
| return WARN.equalsIgnoreCase( getValue() ); | |||
| } | |||
| } | |||
| @@ -1,53 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.archive; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.IOException; | |||
| import org.apache.avalon.excalibur.io.IOUtil; | |||
| import org.apache.excalibur.tar.TarEntry; | |||
| import org.apache.excalibur.tar.TarInputStream; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| /** | |||
| * Untar a file. Heavily based on the Expand task. | |||
| * | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a> | |||
| */ | |||
| public class Untar | |||
| extends Expand | |||
| { | |||
| protected void expandArchive( final File src, final File dir ) | |||
| throws IOException, TaskException | |||
| { | |||
| TarInputStream input = null; | |||
| FileInputStream fileInput = null; | |||
| try | |||
| { | |||
| fileInput = new FileInputStream( src ); | |||
| input = new TarInputStream( fileInput ); | |||
| TarEntry entry = null; | |||
| while( ( entry = input.getNextEntry() ) != null ) | |||
| { | |||
| extractFile( dir, | |||
| input, | |||
| entry.getName(), | |||
| entry.getModTime(), | |||
| entry.isDirectory() ); | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| IOUtil.shutdownStream( fileInput ); | |||
| IOUtil.shutdownStream( input ); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,54 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.archive; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.IOException; | |||
| import java.util.Date; | |||
| import java.util.zip.ZipEntry; | |||
| import java.util.zip.ZipInputStream; | |||
| import org.apache.avalon.excalibur.io.IOUtil; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.tools.todo.taskdefs.archive.Expand; | |||
| /** | |||
| * Untar a file. Heavily based on the Expand task. | |||
| * | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a> | |||
| */ | |||
| public class Unzip | |||
| extends Expand | |||
| { | |||
| protected void expandArchive( final File src, final File dir ) | |||
| throws IOException, TaskException | |||
| { | |||
| ZipInputStream zis = null; | |||
| try | |||
| { | |||
| // code from WarExpand | |||
| zis = new ZipInputStream( new FileInputStream( src ) ); | |||
| ZipEntry ze = null; | |||
| while( ( ze = zis.getNextEntry() ) != null ) | |||
| { | |||
| final Date date = new Date( ze.getTime() ); | |||
| extractFile( dir, | |||
| zis, | |||
| ze.getName(), | |||
| date, | |||
| ze.isDirectory() ); | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| IOUtil.shutdownStream( zis ); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,109 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.archive; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.excalibur.zip.ZipOutputStream; | |||
| /** | |||
| * Creates a WAR archive. | |||
| * | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| */ | |||
| public class War | |||
| extends Jar | |||
| { | |||
| private File m_webxml; | |||
| private boolean m_descriptorAdded; | |||
| public War() | |||
| { | |||
| super(); | |||
| m_archiveType = "war"; | |||
| m_emptyBehavior = "create"; | |||
| } | |||
| public void setWebxml( final File descr ) | |||
| throws TaskException | |||
| { | |||
| m_webxml = descr; | |||
| if( !m_webxml.exists() ) | |||
| { | |||
| final String message = "Deployment descriptor: " + | |||
| m_webxml + " does not exist."; | |||
| throw new TaskException( message ); | |||
| } | |||
| addFileAs( descr, "WEB-INF/web.xml" ); | |||
| } | |||
| public void addClasses( final ZipFileSet fs ) | |||
| { | |||
| // We just set the prefix for this fileset, and pass it up. | |||
| fs.setPrefix( "WEB-INF/classes/" ); | |||
| super.addFileset( fs ); | |||
| } | |||
| public void addLib( final ZipFileSet fs ) | |||
| { | |||
| // We just set the prefix for this fileset, and pass it up. | |||
| fs.setPrefix( "WEB-INF/lib/" ); | |||
| super.addFileset( fs ); | |||
| } | |||
| public void addWebinf( final ZipFileSet fs ) | |||
| { | |||
| // We just set the prefix for this fileset, and pass it up. | |||
| fs.setPrefix( "WEB-INF/" ); | |||
| super.addFileset( fs ); | |||
| } | |||
| protected void initZipOutputStream( final ZipOutputStream zOut ) | |||
| throws IOException, TaskException | |||
| { | |||
| // If no webxml file is specified, it's an error. | |||
| if( m_webxml == null && !isInUpdateMode() ) | |||
| { | |||
| throw new TaskException( "webxml attribute is required" ); | |||
| } | |||
| super.initZipOutputStream( zOut ); | |||
| } | |||
| protected void zipFile( final File file, | |||
| final ZipOutputStream zOut, | |||
| final String vPath ) | |||
| throws IOException, TaskException | |||
| { | |||
| // If the file being added is WEB-INF/web.xml, we warn if it's not the | |||
| // one specified in the "webxml" attribute - or if it's being added twice, | |||
| // meaning the same file is specified by the "webxml" attribute and in | |||
| // a <fileset> element. | |||
| if( vPath.equalsIgnoreCase( "WEB-INF/web.xml" ) ) | |||
| { | |||
| if( m_webxml == null || !m_webxml.equals( file ) || m_descriptorAdded ) | |||
| { | |||
| final String message = "Warning: selected " + m_archiveType + | |||
| " files include a WEB-INF/web.xml which will be ignored " + | |||
| "(please use webxml attribute to " + m_archiveType + " task)"; | |||
| getContext().warn( message ); | |||
| } | |||
| else | |||
| { | |||
| super.zipFile( file, zOut, vPath ); | |||
| m_descriptorAdded = true; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| super.zipFile( file, zOut, vPath ); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,22 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.archive; | |||
| import org.apache.tools.todo.types.EnumeratedAttribute; | |||
| /** | |||
| * Possible behaviors when there are no matching files for the task. | |||
| */ | |||
| public class WhenEmpty | |||
| extends EnumeratedAttribute | |||
| { | |||
| public String[] getValues() | |||
| { | |||
| return new String[]{"fail", "skip", "create"}; | |||
| } | |||
| } | |||
| @@ -1,895 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.archive; | |||
| import java.io.ByteArrayInputStream; | |||
| import java.io.ByteArrayOutputStream; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.FileOutputStream; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.io.OutputStream; | |||
| import java.util.ArrayList; | |||
| import java.util.Hashtable; | |||
| import java.util.Stack; | |||
| import java.util.zip.CRC32; | |||
| import java.util.zip.ZipInputStream; | |||
| import org.apache.avalon.excalibur.io.IOUtil; | |||
| import org.apache.excalibur.zip.ZipEntry; | |||
| import org.apache.excalibur.zip.ZipOutputStream; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.FileSet; | |||
| import org.apache.tools.todo.taskdefs.MatchingTask; | |||
| import org.apache.tools.todo.types.DirectoryScanner; | |||
| import org.apache.tools.todo.types.FileScanner; | |||
| import org.apache.tools.todo.types.ScannerUtil; | |||
| import org.apache.tools.todo.types.SourceFileScanner; | |||
| import org.apache.tools.todo.util.mappers.MergingMapper; | |||
| /** | |||
| * Create a ZIP archive. | |||
| * | |||
| * @author James Davidson <a href="mailto:duncan@x180.com">duncan@x180.com</a> | |||
| * @author Jon S. Stevens <a href="mailto:jon@clearink.com">jon@clearink.com</a> | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| */ | |||
| public class Zip | |||
| extends MatchingTask | |||
| { | |||
| // For directories: | |||
| private final static long EMPTY_CRC = new CRC32().getValue(); | |||
| private boolean m_compress = true; | |||
| private boolean m_update; | |||
| private boolean m_filesonly; | |||
| protected String m_archiveType = "zip"; | |||
| protected String m_emptyBehavior = "skip"; | |||
| private ArrayList m_filesets = new ArrayList(); | |||
| protected Hashtable m_addedDirs = new Hashtable(); | |||
| private ArrayList m_addedFiles = new ArrayList(); | |||
| protected File m_file; | |||
| /** | |||
| * true when we are adding new files into the Zip file, as opposed to adding | |||
| * back the unchanged files | |||
| */ | |||
| private boolean m_addingNewFiles; | |||
| private File m_baseDir; | |||
| /** | |||
| * Encoding to use for filenames, defaults to the platform's default | |||
| * encoding. | |||
| */ | |||
| private String m_encoding; | |||
| private static String[][] grabFileNames( final FileScanner[] scanners ) | |||
| throws TaskException | |||
| { | |||
| String[][] result = new String[ scanners.length ][]; | |||
| for( int i = 0; i < scanners.length; i++ ) | |||
| { | |||
| String[] files = scanners[ i ].getIncludedFiles(); | |||
| String[] dirs = scanners[ i ].getIncludedDirectories(); | |||
| result[ i ] = new String[ files.length + dirs.length ]; | |||
| System.arraycopy( files, 0, result[ i ], 0, files.length ); | |||
| System.arraycopy( dirs, 0, result[ i ], files.length, dirs.length ); | |||
| } | |||
| return result; | |||
| } | |||
| private static File[] grabFiles( final FileScanner[] scanners, | |||
| final String[][] filenames ) | |||
| { | |||
| final ArrayList files = new ArrayList(); | |||
| for( int i = 0; i < filenames.length; i++ ) | |||
| { | |||
| final File baseDir = scanners[ i ].getBasedir(); | |||
| for( int j = 0; j < filenames[ i ].length; j++ ) | |||
| { | |||
| files.add( new File( baseDir, filenames[ i ][ j ] ) ); | |||
| } | |||
| } | |||
| final File[] toret = new File[ files.size() ]; | |||
| return (File[])files.toArray( toret ); | |||
| } | |||
| /** | |||
| * This is the base directory to look in for things to zip. | |||
| * | |||
| * @param baseDir The new Basedir value | |||
| */ | |||
| public void setBasedir( final File baseDir ) | |||
| { | |||
| m_baseDir = baseDir; | |||
| } | |||
| /** | |||
| * Sets whether we want to compress the files or only store them. | |||
| * | |||
| * @param compress The new Compress value | |||
| */ | |||
| public void setCompress( final boolean compress ) | |||
| { | |||
| m_compress = compress; | |||
| } | |||
| /** | |||
| * Encoding to use for filenames, defaults to the platform's default | |||
| * encoding. <p> | |||
| * | |||
| * For a list of possible values see <a | |||
| * href="http://java.sun.com/products/jdk/1.2/docs/guide/internat/encoding.doc.html"> | |||
| * http://java.sun.com/products/jdk/1.2/docs/guide/internat/encoding.doc.html | |||
| * </a>.</p> | |||
| * | |||
| * @param encoding The new Encoding value | |||
| */ | |||
| public void setEncoding( final String encoding ) | |||
| { | |||
| m_encoding = encoding; | |||
| } | |||
| /** | |||
| * This is the name/location of where to create the .zip file. | |||
| * | |||
| * @param file The new File value | |||
| */ | |||
| public void setFile( final File file ) | |||
| { | |||
| m_file = file; | |||
| } | |||
| /** | |||
| * Emulate Sun's jar utility by not adding parent dirs | |||
| */ | |||
| public void setFilesonly( final boolean filesonly ) | |||
| { | |||
| m_filesonly = filesonly; | |||
| } | |||
| /** | |||
| * Sets whether we want to update the file (if it exists) or create a new | |||
| * one. | |||
| */ | |||
| public void setUpdate( final boolean update ) | |||
| { | |||
| m_update = update; | |||
| } | |||
| /** | |||
| * Sets behavior of the task when no files match. Possible values are: | |||
| * <code>fail</code> (throw an exception and halt the build); <code>skip</code> | |||
| * (do not create any archive, but issue a warning); <code>create</code> | |||
| * (make an archive with no entries). Default for zip tasks is <code>skip</code> | |||
| * ; for jar tasks, <code>create</code>. | |||
| * | |||
| * @param we The new Whenempty value | |||
| */ | |||
| public void setWhenempty( final WhenEmpty we ) | |||
| { | |||
| m_emptyBehavior = we.getValue(); | |||
| } | |||
| /** | |||
| * Are we updating an existing archive? | |||
| * | |||
| * @return The InUpdateMode value | |||
| */ | |||
| protected final boolean isInUpdateMode() | |||
| { | |||
| return m_update; | |||
| } | |||
| /** | |||
| * Adds a set of files (nested fileset attribute). | |||
| */ | |||
| public void addFileset( final FileSet set ) | |||
| { | |||
| m_filesets.add( set ); | |||
| } | |||
| /** | |||
| * Adds a set of files (nested zipfileset attribute) that can be read from | |||
| * an archive and be given a prefix/fullpath. | |||
| * | |||
| * @param set The feature to be added to the Zipfileset attribute | |||
| */ | |||
| public void addZipfileset( final ZipFileSet set ) | |||
| { | |||
| m_filesets.add( set ); | |||
| } | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| if( m_baseDir == null && m_filesets.size() == 0 && | |||
| "zip".equals( m_archiveType ) ) | |||
| { | |||
| final String message = "basedir attribute must be set, or at least " + | |||
| "one fileset must be given!"; | |||
| throw new TaskException( message ); | |||
| } | |||
| if( m_file == null ) | |||
| { | |||
| final String message = "You must specify the " + | |||
| m_archiveType + " file to create!"; | |||
| throw new TaskException( message ); | |||
| } | |||
| // Renamed version of original file, if it exists | |||
| File renamedFile = null; | |||
| // Whether or not an actual update is required - | |||
| // we don't need to update if the original file doesn't exist | |||
| m_addingNewFiles = true; | |||
| m_update = m_update && m_file.exists(); | |||
| if( m_update ) | |||
| { | |||
| try | |||
| { | |||
| renamedFile = File.createTempFile( "zip", ".tmp", | |||
| m_file.getParentFile() ); | |||
| } | |||
| catch( final IOException ioe ) | |||
| { | |||
| throw new TaskException( ioe.toString(), ioe ); | |||
| } | |||
| try | |||
| { | |||
| if( !m_file.renameTo( renamedFile ) ) | |||
| { | |||
| throw new TaskException( "Unable to rename old file to temporary file" ); | |||
| } | |||
| } | |||
| catch( SecurityException e ) | |||
| { | |||
| throw new TaskException( "Not allowed to rename old file to temporary file" ); | |||
| } | |||
| } | |||
| // Create the scanners to pass to isUpToDate(). | |||
| ArrayList dss = new ArrayList(); | |||
| if( m_baseDir != null ) | |||
| { | |||
| dss.add( getDirectoryScanner( m_baseDir ) ); | |||
| } | |||
| final int size = m_filesets.size(); | |||
| for( int i = 0; i < size; i++ ) | |||
| { | |||
| final FileSet fileSet = (FileSet)m_filesets.get( i ); | |||
| final DirectoryScanner scanner = getScanner( fileSet ); | |||
| dss.add( scanner ); | |||
| } | |||
| int dssSize = dss.size(); | |||
| FileScanner[] scanners = new FileScanner[ dssSize ]; | |||
| scanners = (FileScanner[])dss.toArray( scanners ); | |||
| // quick exit if the target is up to date | |||
| // can also handle empty archives | |||
| if( isUpToDate( scanners, m_file ) ) | |||
| { | |||
| return; | |||
| } | |||
| String action = m_update ? "Updating " : "Building "; | |||
| getContext().info( action + m_archiveType + ": " + m_file.getAbsolutePath() ); | |||
| boolean success = false; | |||
| try | |||
| { | |||
| ZipOutputStream zOut = | |||
| new ZipOutputStream( new FileOutputStream( m_file ) ); | |||
| zOut.setEncoding( m_encoding ); | |||
| try | |||
| { | |||
| if( m_compress ) | |||
| { | |||
| zOut.setMethod( ZipOutputStream.DEFLATED ); | |||
| } | |||
| else | |||
| { | |||
| zOut.setMethod( ZipOutputStream.STORED ); | |||
| } | |||
| initZipOutputStream( zOut ); | |||
| // Add the implicit fileset to the archive. | |||
| if( m_baseDir != null ) | |||
| { | |||
| addFiles( getDirectoryScanner( m_baseDir ), zOut, "", "" ); | |||
| } | |||
| // Add the explicit filesets to the archive. | |||
| addFiles( m_filesets, zOut ); | |||
| if( m_update ) | |||
| { | |||
| m_addingNewFiles = false; | |||
| ZipFileSet oldFiles = new ZipFileSet(); | |||
| oldFiles.setSrc( renamedFile ); | |||
| StringBuffer exclusionPattern = new StringBuffer(); | |||
| final int addedFilesCount = m_addedFiles.size(); | |||
| for( int i = 0; i < addedFilesCount; i++ ) | |||
| { | |||
| if( i != 0 ) | |||
| { | |||
| exclusionPattern.append( "," ); | |||
| } | |||
| exclusionPattern.append( (String)m_addedFiles.get( i ) ); | |||
| } | |||
| oldFiles.setExcludes( exclusionPattern.toString() ); | |||
| ArrayList tmp = new ArrayList(); | |||
| tmp.add( oldFiles ); | |||
| addFiles( tmp, zOut ); | |||
| } | |||
| finalizeZipOutputStream( zOut ); | |||
| success = true; | |||
| } | |||
| finally | |||
| { | |||
| // Close the output stream. | |||
| try | |||
| { | |||
| if( zOut != null ) | |||
| { | |||
| zOut.close(); | |||
| } | |||
| } | |||
| catch( IOException ex ) | |||
| { | |||
| // If we're in this finally clause because of an exception, we don't | |||
| // really care if there's an exception when closing the stream. E.g. if it | |||
| // throws "ZIP file must have at least one entry", because an exception happened | |||
| // before we added any files, then we must swallow this exception. Otherwise, | |||
| // the error that's reported will be the close() error, which is not the real | |||
| // cause of the problem. | |||
| if( success ) | |||
| { | |||
| throw ex; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| String msg = "Problem creating " + m_archiveType + ": " + ioe.getMessage(); | |||
| // delete a bogus ZIP file | |||
| if( !m_file.delete() ) | |||
| { | |||
| msg += " (and the archive is probably corrupt but I could not delete it)"; | |||
| } | |||
| if( m_update ) | |||
| { | |||
| if( !renamedFile.renameTo( m_file ) ) | |||
| { | |||
| msg += " (and I couldn't rename the temporary file " + | |||
| renamedFile.getName() + " back)"; | |||
| } | |||
| } | |||
| throw new TaskException( msg, ioe ); | |||
| } | |||
| // If we've been successful on an update, delete the temporary file | |||
| if( success && m_update ) | |||
| { | |||
| if( !renamedFile.delete() ) | |||
| { | |||
| final String message = "Warning: unable to delete temporary file " + | |||
| renamedFile.getName(); | |||
| getContext().warn( message ); | |||
| } | |||
| } | |||
| } | |||
| private DirectoryScanner getScanner( final FileSet fileSet ) | |||
| throws TaskException | |||
| { | |||
| if( fileSet instanceof ZipFileSet ) | |||
| { | |||
| final ZipFileSet zipFileSet = (ZipFileSet)fileSet; | |||
| return ScannerUtil.getZipScanner( zipFileSet ); | |||
| } | |||
| else | |||
| { | |||
| return ScannerUtil.getDirectoryScanner( fileSet ); | |||
| } | |||
| } | |||
| protected void addFileAs( final File file, final String name ) | |||
| throws TaskException | |||
| { | |||
| // Create a ZipFileSet for this file, and pass it up. | |||
| final ZipFileSet fs = new ZipFileSet(); | |||
| fs.setDir( file.getParentFile() ); | |||
| fs.setIncludes( file.getName() ); | |||
| fs.setFullpath( name ); | |||
| addFileset( fs ); | |||
| } | |||
| /** | |||
| * Indicates if the task is adding new files into the archive as opposed to | |||
| * copying back unchanged files from the backup copy | |||
| * | |||
| * @return The AddingNewFiles value | |||
| */ | |||
| protected final boolean isAddingNewFiles() | |||
| { | |||
| return m_addingNewFiles; | |||
| } | |||
| /** | |||
| * Check whether the archive is up-to-date; and handle behavior for empty | |||
| * archives. | |||
| * | |||
| * @param scanners list of prepared scanners containing files to archive | |||
| * @param zipFile intended archive file (may or may not exist) | |||
| * @return true if nothing need be done (may have done something already); | |||
| * false if archive creation should proceed | |||
| * @exception org.apache.myrmidon.api.TaskException if it likes | |||
| */ | |||
| protected boolean isUpToDate( FileScanner[] scanners, File zipFile ) | |||
| throws TaskException | |||
| { | |||
| String[][] fileNames = grabFileNames( scanners ); | |||
| File[] files = grabFiles( scanners, fileNames ); | |||
| if( files.length == 0 ) | |||
| { | |||
| if( m_emptyBehavior.equals( "skip" ) ) | |||
| { | |||
| final String message = "Warning: skipping " + m_archiveType + " archive " + zipFile + | |||
| " because no files were included."; | |||
| getContext().warn( message ); | |||
| return true; | |||
| } | |||
| else if( m_emptyBehavior.equals( "fail" ) ) | |||
| { | |||
| throw new TaskException( "Cannot create " + m_archiveType + " archive " + zipFile + | |||
| ": no files were included." ); | |||
| } | |||
| else | |||
| { | |||
| // Create. | |||
| return createEmptyZip( zipFile ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| for( int i = 0; i < files.length; ++i ) | |||
| { | |||
| if( files[ i ].equals( zipFile ) ) | |||
| { | |||
| throw new TaskException( "A zip file cannot include itself" ); | |||
| } | |||
| } | |||
| if( !zipFile.exists() ) | |||
| { | |||
| return false; | |||
| } | |||
| final SourceFileScanner scanner = new SourceFileScanner(); | |||
| MergingMapper mm = new MergingMapper(); | |||
| mm.setTo( zipFile.getAbsolutePath() ); | |||
| for( int i = 0; i < scanners.length; i++ ) | |||
| { | |||
| if( scanner.restrict( fileNames[ i ], scanners[ i ].getBasedir(), null, | |||
| mm, getContext() ).length > 0 ) | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| } | |||
| /** | |||
| * Add all files of the given FileScanner to the ZipOutputStream prependig | |||
| * the given prefix to each filename. <p> | |||
| * | |||
| * Ensure parent directories have been added as well. | |||
| * | |||
| * @param scanner The feature to be added to the Files attribute | |||
| * @param zOut The feature to be added to the Files attribute | |||
| * @param prefix The feature to be added to the Files attribute | |||
| * @param fullpath The feature to be added to the Files attribute | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| protected void addFiles( FileScanner scanner, ZipOutputStream zOut, | |||
| String prefix, String fullpath ) | |||
| throws IOException, TaskException | |||
| { | |||
| if( prefix.length() > 0 && fullpath.length() > 0 ) | |||
| { | |||
| throw new TaskException( "Both prefix and fullpath attributes may not be set on the same fileset." ); | |||
| } | |||
| File thisBaseDir = scanner.getBasedir(); | |||
| // directories that matched include patterns | |||
| String[] dirs = scanner.getIncludedDirectories(); | |||
| if( dirs.length > 0 && fullpath.length() > 0 ) | |||
| { | |||
| throw new TaskException( "fullpath attribute may only be specified for filesets that specify a single file." ); | |||
| } | |||
| for( int i = 0; i < dirs.length; i++ ) | |||
| { | |||
| final String dir = dirs[ i ]; | |||
| if( "".equals( dir ) ) | |||
| { | |||
| continue; | |||
| } | |||
| final String name = getName( dir ); | |||
| addParentDirs( thisBaseDir, name, zOut, prefix ); | |||
| } | |||
| // files that matched include patterns | |||
| String[] files = scanner.getIncludedFiles(); | |||
| if( files.length > 1 && fullpath.length() > 0 ) | |||
| { | |||
| throw new TaskException( "fullpath attribute may only be specified for filesets that specify a single file." ); | |||
| } | |||
| for( int i = 0; i < files.length; i++ ) | |||
| { | |||
| File f = new File( thisBaseDir, files[ i ] ); | |||
| if( fullpath.length() > 0 ) | |||
| { | |||
| // Add this file at the specified location. | |||
| addParentDirs( null, fullpath, zOut, "" ); | |||
| zipFile( f, zOut, fullpath ); | |||
| } | |||
| else | |||
| { | |||
| // Add this file with the specified prefix. | |||
| String name = files[ i ].replace( File.separatorChar, '/' ); | |||
| addParentDirs( thisBaseDir, name, zOut, prefix ); | |||
| zipFile( f, zOut, prefix + name ); | |||
| } | |||
| } | |||
| } | |||
| private String getName( final String dir ) | |||
| { | |||
| String name = dir.replace( File.separatorChar, '/' ); | |||
| if( !name.endsWith( "/" ) ) | |||
| { | |||
| name += "/"; | |||
| } | |||
| return name; | |||
| } | |||
| /** | |||
| * Iterate over the given ArrayList of (zip)filesets and add all files to the | |||
| * ZipOutputStream using the given prefix or fullpath. | |||
| * | |||
| * @param filesets The feature to be added to the Files attribute | |||
| * @param zOut The feature to be added to the Files attribute | |||
| * @exception java.io.IOException Description of Exception | |||
| */ | |||
| protected void addFiles( ArrayList filesets, ZipOutputStream zOut ) | |||
| throws IOException, TaskException | |||
| { | |||
| // Add each fileset in the ArrayList. | |||
| final int size = filesets.size(); | |||
| for( int i = 0; i < size; i++ ) | |||
| { | |||
| FileSet fs = (FileSet)filesets.get( i ); | |||
| DirectoryScanner ds = getScanner( fs ); | |||
| String prefix = ""; | |||
| String fullpath = ""; | |||
| if( fs instanceof ZipFileSet ) | |||
| { | |||
| ZipFileSet zfs = (ZipFileSet)fs; | |||
| prefix = getPrefix( zfs.getPrefix() ); | |||
| fullpath = zfs.getFullpath(); | |||
| } | |||
| // Need to manually add either fullpath's parent directory, or | |||
| // the prefix directory, to the archive. | |||
| if( prefix.length() > 0 ) | |||
| { | |||
| addParentDirs( null, prefix, zOut, "" ); | |||
| zipDir( null, zOut, prefix ); | |||
| } | |||
| else if( fullpath.length() > 0 ) | |||
| { | |||
| addParentDirs( null, fullpath, zOut, "" ); | |||
| } | |||
| if( fs instanceof ZipFileSet | |||
| && ( (ZipFileSet)fs ).getSrc() != null ) | |||
| { | |||
| addZipEntries( (ZipFileSet)fs, ds, zOut, prefix, fullpath ); | |||
| } | |||
| else | |||
| { | |||
| // Add the fileset. | |||
| addFiles( ds, zOut, prefix, fullpath ); | |||
| } | |||
| } | |||
| } | |||
| private String getPrefix( final String prefix ) | |||
| { | |||
| String result = prefix; | |||
| if( result.length() > 0 | |||
| && !result.endsWith( "/" ) | |||
| && !result.endsWith( "\\" ) ) | |||
| { | |||
| result += "/"; | |||
| } | |||
| return result; | |||
| } | |||
| /** | |||
| * Ensure all parent dirs of a given entry have been added. | |||
| * | |||
| * @param baseDir The feature to be added to the ParentDirs attribute | |||
| * @param entry The feature to be added to the ParentDirs attribute | |||
| * @param zOut The feature to be added to the ParentDirs attribute | |||
| * @param prefix The feature to be added to the ParentDirs attribute | |||
| * @exception java.io.IOException Description of Exception | |||
| */ | |||
| protected void addParentDirs( File baseDir, String entry, | |||
| ZipOutputStream zOut, String prefix ) | |||
| throws IOException | |||
| { | |||
| if( !m_filesonly ) | |||
| { | |||
| Stack directories = new Stack(); | |||
| int slashPos = entry.length(); | |||
| while( ( slashPos = entry.lastIndexOf( '/', slashPos - 1 ) ) != -1 ) | |||
| { | |||
| String dir = entry.substring( 0, slashPos + 1 ); | |||
| if( m_addedDirs.get( prefix + dir ) != null ) | |||
| { | |||
| break; | |||
| } | |||
| directories.push( dir ); | |||
| } | |||
| while( !directories.isEmpty() ) | |||
| { | |||
| String dir = (String)directories.pop(); | |||
| File f = null; | |||
| if( baseDir != null ) | |||
| { | |||
| f = new File( baseDir, dir ); | |||
| } | |||
| else | |||
| { | |||
| f = new File( dir ); | |||
| } | |||
| zipDir( f, zOut, prefix + dir ); | |||
| } | |||
| } | |||
| } | |||
| protected void addZipEntries( ZipFileSet fs, DirectoryScanner ds, | |||
| ZipOutputStream zOut, String prefix, String fullpath ) | |||
| throws IOException, TaskException | |||
| { | |||
| if( prefix.length() > 0 && fullpath.length() > 0 ) | |||
| { | |||
| throw new TaskException( "Both prefix and fullpath attributes may not be set on the same fileset." ); | |||
| } | |||
| ZipScanner zipScanner = (ZipScanner)ds; | |||
| File zipSrc = fs.getSrc(); | |||
| ZipEntry entry; | |||
| java.util.zip.ZipEntry origEntry; | |||
| ZipInputStream in = null; | |||
| try | |||
| { | |||
| in = new ZipInputStream( new FileInputStream( zipSrc ) ); | |||
| while( ( origEntry = in.getNextEntry() ) != null ) | |||
| { | |||
| entry = new ZipEntry( origEntry ); | |||
| String vPath = entry.getName(); | |||
| if( zipScanner.match( vPath ) ) | |||
| { | |||
| if( fullpath.length() > 0 ) | |||
| { | |||
| addParentDirs( null, fullpath, zOut, "" ); | |||
| zipFile( in, zOut, fullpath, entry.getTime() ); | |||
| } | |||
| else | |||
| { | |||
| addParentDirs( null, vPath, zOut, prefix ); | |||
| if( !entry.isDirectory() ) | |||
| { | |||
| zipFile( in, zOut, prefix + vPath, entry.getTime() ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| if( in != null ) | |||
| { | |||
| in.close(); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Create an empty zip file | |||
| * | |||
| * @param zipFile Description of Parameter | |||
| * @return true if the file is then considered up to date. | |||
| */ | |||
| protected boolean createEmptyZip( File zipFile ) | |||
| throws TaskException | |||
| { | |||
| // In this case using java.util.zip will not work | |||
| // because it does not permit a zero-entry archive. | |||
| // Must create it manually. | |||
| getContext().info( "Note: creating empty " + m_archiveType + " archive " + zipFile ); | |||
| try | |||
| { | |||
| OutputStream os = new FileOutputStream( zipFile ); | |||
| try | |||
| { | |||
| // Cf. PKZIP specification. | |||
| byte[] empty = new byte[ 22 ]; | |||
| empty[ 0 ] = 80;// P | |||
| empty[ 1 ] = 75;// K | |||
| empty[ 2 ] = 5; | |||
| empty[ 3 ] = 6; | |||
| // remainder zeros | |||
| os.write( empty ); | |||
| } | |||
| finally | |||
| { | |||
| os.close(); | |||
| } | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| throw new TaskException( "Could not create empty ZIP archive", ioe ); | |||
| } | |||
| return true; | |||
| } | |||
| protected void finalizeZipOutputStream( ZipOutputStream zOut ) | |||
| throws IOException, TaskException | |||
| { | |||
| } | |||
| protected void initZipOutputStream( ZipOutputStream zOut ) | |||
| throws IOException, TaskException | |||
| { | |||
| } | |||
| protected void zipDir( File dir, ZipOutputStream zOut, String vPath ) | |||
| throws IOException | |||
| { | |||
| if( m_addedDirs.get( vPath ) != null ) | |||
| { | |||
| // don't add directories we've already added. | |||
| // no warning if we try, it is harmless in and of itself | |||
| return; | |||
| } | |||
| m_addedDirs.put( vPath, vPath ); | |||
| ZipEntry ze = new ZipEntry( vPath ); | |||
| if( dir != null && dir.exists() ) | |||
| { | |||
| ze.setTime( dir.lastModified() ); | |||
| } | |||
| else | |||
| { | |||
| ze.setTime( System.currentTimeMillis() ); | |||
| } | |||
| ze.setSize( 0 ); | |||
| ze.setMethod( ZipEntry.STORED ); | |||
| // This is faintly ridiculous: | |||
| ze.setCrc( EMPTY_CRC ); | |||
| // this is 040775 | MS-DOS directory flag in reverse byte order | |||
| ze.setExternalAttributes( 0x41FD0010L ); | |||
| zOut.putNextEntry( ze ); | |||
| } | |||
| protected void zipFile( final InputStream input, | |||
| final ZipOutputStream output, | |||
| final String path, | |||
| final long lastModified ) | |||
| throws IOException, TaskException | |||
| { | |||
| final ZipEntry entry = new ZipEntry( path ); | |||
| entry.setTime( lastModified ); | |||
| /* | |||
| * XXX ZipOutputStream.putEntry expects the ZipEntry to know its | |||
| * size and the CRC sum before you start writing the data when using | |||
| * STORED mode. | |||
| * | |||
| * This forces us to process the data twice. | |||
| * | |||
| * I couldn't find any documentation on this, just found out by try | |||
| * and error. | |||
| */ | |||
| InputStream inputToStore = input; | |||
| if( !m_compress ) | |||
| { | |||
| final CRC32 crc = new CRC32(); | |||
| long size = 0; | |||
| if( !inputToStore.markSupported() ) | |||
| { | |||
| // Store data into a byte[] | |||
| ByteArrayOutputStream bos = new ByteArrayOutputStream(); | |||
| byte[] buffer = new byte[ 8 * 1024 ]; | |||
| int count = 0; | |||
| do | |||
| { | |||
| size += count; | |||
| crc.update( buffer, 0, count ); | |||
| bos.write( buffer, 0, count ); | |||
| count = inputToStore.read( buffer, 0, buffer.length ); | |||
| } while( count != -1 ); | |||
| inputToStore = new ByteArrayInputStream( bos.toByteArray() ); | |||
| } | |||
| else | |||
| { | |||
| inputToStore.mark( Integer.MAX_VALUE ); | |||
| byte[] buffer = new byte[ 8 * 1024 ]; | |||
| int count = 0; | |||
| do | |||
| { | |||
| size += count; | |||
| crc.update( buffer, 0, count ); | |||
| count = inputToStore.read( buffer, 0, buffer.length ); | |||
| } while( count != -1 ); | |||
| inputToStore.reset(); | |||
| } | |||
| entry.setSize( size ); | |||
| entry.setCrc( crc.getValue() ); | |||
| } | |||
| output.putNextEntry( entry ); | |||
| IOUtil.copy( inputToStore, output ); | |||
| m_addedFiles.add( path ); | |||
| } | |||
| protected void zipFile( final File file, | |||
| final ZipOutputStream zOut, | |||
| final String vPath ) | |||
| throws IOException, TaskException | |||
| { | |||
| if( file.equals( m_file ) ) | |||
| { | |||
| final String message = "A zip file cannot include itself"; | |||
| throw new TaskException( message ); | |||
| } | |||
| final FileInputStream fIn = new FileInputStream( file ); | |||
| try | |||
| { | |||
| zipFile( fIn, zOut, vPath, file.lastModified() ); | |||
| } | |||
| finally | |||
| { | |||
| IOUtil.shutdownStream( fIn ); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,98 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.archive; | |||
| import java.io.File; | |||
| import org.apache.myrmidon.framework.FileSet; | |||
| /** | |||
| * A ZipFileSet is a FileSet with extra attributes useful in the context of | |||
| * Zip/Jar tasks. A ZipFileSet extends FileSets with the ability to extract a | |||
| * subset of the entries of a Zip file for inclusion in another Zip file. It | |||
| * also includes a prefix attribute which is prepended to each entry in the | |||
| * output Zip file. At present, ZipFileSets are not surfaced in the public API. | |||
| * FileSets nested in a Zip task are instantiated as ZipFileSets, and their | |||
| * attributes are only recognized in the context of the the Zip task. It is not | |||
| * possible to define a ZipFileSet outside of the Zip task and refer to it via a | |||
| * refid. However a standard FileSet may be included by reference in the Zip | |||
| * task, and attributes in the refering ZipFileSet can augment FileSet | |||
| * definition. | |||
| * | |||
| * @author <a href="mailto:don@bea.com">Don Ferguson</a> | |||
| */ | |||
| public class ZipFileSet | |||
| extends FileSet | |||
| { | |||
| private File m_src; | |||
| private String m_prefix = ""; | |||
| private String m_fullpath = ""; | |||
| /** | |||
| * Set the full pathname of the single entry in this fileset. | |||
| * | |||
| * @param fullpath The new Fullpath value | |||
| */ | |||
| public void setFullpath( final String fullpath ) | |||
| { | |||
| m_fullpath = fullpath; | |||
| } | |||
| /** | |||
| * Prepend this prefix to the path for each zip entry. Does not perform | |||
| * reference test; the referenced file set can be augmented with a prefix. | |||
| * | |||
| * @param prefix The prefix to prepend to entries in the zip file. | |||
| */ | |||
| public void setPrefix( final String prefix ) | |||
| { | |||
| m_prefix = prefix; | |||
| } | |||
| /** | |||
| * Set the source Zip file for the zipfileset. Prevents both "dir" and "src" | |||
| * from being specified. | |||
| * | |||
| * @param src The zip file from which to extract entries. | |||
| */ | |||
| public void setSrc( final File src ) | |||
| { | |||
| m_src = src; | |||
| } | |||
| /** | |||
| * Return the full pathname of the single entry in this fileset. | |||
| * | |||
| * @return The Fullpath value | |||
| */ | |||
| public String getFullpath() | |||
| { | |||
| return m_fullpath; | |||
| } | |||
| /** | |||
| * Return the prefix prepended to entries in the zip file. | |||
| * | |||
| * @return The Prefix value | |||
| */ | |||
| public String getPrefix() | |||
| { | |||
| return m_prefix; | |||
| } | |||
| /** | |||
| * Get the zip file from which entries will be extracted. References are not | |||
| * followed, since it is not possible to have a reference to a ZipFileSet, | |||
| * only to a FileSet. | |||
| * | |||
| * @return The Src value | |||
| */ | |||
| public File getSrc() | |||
| { | |||
| return m_src; | |||
| } | |||
| } | |||
| @@ -1,98 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.archive; | |||
| import java.io.File; | |||
| import org.apache.tools.todo.types.DirectoryScanner; | |||
| /** | |||
| * ZipScanner accesses the pattern matching algorithm in DirectoryScanner, which | |||
| * are protected methods that can only be accessed by subclassing. This | |||
| * implementation of FileScanner defines getIncludedFiles to return only the Zip | |||
| * File which is being scanned, not the matching Zip entries. Arguably, it | |||
| * should return the matching entries, however this would complicate existing | |||
| * code which assumes that FileScanners return a set of file system files that | |||
| * can be accessed directly. | |||
| * | |||
| * @author Don Ferguson <a href="mailto:don@bea.com">don@bea.com</a> | |||
| */ | |||
| public class ZipScanner | |||
| extends DirectoryScanner | |||
| { | |||
| /** | |||
| * The zip file which should be scanned. | |||
| */ | |||
| private File m_src; | |||
| /** | |||
| * Sets the srcFile for scanning. This is the jar or zip file that is | |||
| * scanned for matching entries. | |||
| * | |||
| * @param srcFile the (non-null) zip file name for scanning | |||
| */ | |||
| public void setSrc( final File srcFile ) | |||
| { | |||
| m_src = srcFile; | |||
| } | |||
| /** | |||
| * Returns an empty list of directories to create. | |||
| * | |||
| * @return The IncludedDirectories value | |||
| */ | |||
| public String[] getIncludedDirectories() | |||
| { | |||
| return new String[ 0 ]; | |||
| } | |||
| /** | |||
| * Returns the zip file itself, not the matching entries within the zip | |||
| * file. This keeps the uptodate test in the Zip task simple; otherwise we'd | |||
| * need to treat zip filesets specially. | |||
| * | |||
| * @return the source file from which entries will be extracted. | |||
| */ | |||
| public String[] getIncludedFiles() | |||
| { | |||
| final String[] result = new String[ 1 ]; | |||
| result[ 0 ] = m_src.getAbsolutePath(); | |||
| return result; | |||
| } | |||
| /** | |||
| * Initialize DirectoryScanner data structures. | |||
| */ | |||
| public void init() | |||
| { | |||
| if( getIncludes() == null ) | |||
| { | |||
| // No includes supplied, so set it to 'matches all' | |||
| setIncludes( new String[ 1 ] ); | |||
| getIncludes()[ 0 ] = "**"; | |||
| } | |||
| if( getExcludes() == null ) | |||
| { | |||
| setExcludes( new String[ 0 ] ); | |||
| } | |||
| } | |||
| /** | |||
| * Matches a jar entry against the includes/excludes list, normalizing the | |||
| * path separator. | |||
| * | |||
| * @param path the (non-null) path name to test for inclusion | |||
| * @return <code>true</code> if the path should be included <code>false</code> | |||
| * otherwise. | |||
| */ | |||
| public boolean match( String path ) | |||
| { | |||
| final String vpath = | |||
| path.replace( '/', File.separatorChar ).replace( '\\', File.separatorChar ); | |||
| return isIncluded( vpath ) && !isExcluded( vpath ); | |||
| } | |||
| } | |||
| @@ -1,79 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.conditions; | |||
| import java.net.HttpURLConnection; | |||
| import java.net.MalformedURLException; | |||
| import java.net.URL; | |||
| import java.net.URLConnection; | |||
| import org.apache.myrmidon.api.TaskContext; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.conditions.Condition; | |||
| /** | |||
| * Condition to wait for a HTTP request to succeed. Its attribute(s) are: url - | |||
| * the URL of the request. | |||
| * | |||
| * @author <a href="mailto:denis@network365.com">Denis Hennessy</a> | |||
| * | |||
| * @ant.type type="condition" name="http" | |||
| */ | |||
| public class Http | |||
| implements Condition | |||
| { | |||
| String spec = null; | |||
| public void setUrl( String url ) | |||
| { | |||
| spec = url; | |||
| } | |||
| /** | |||
| * Evaluates this condition. | |||
| */ | |||
| public boolean evaluate( final TaskContext context ) | |||
| throws TaskException | |||
| { | |||
| if( spec == null ) | |||
| { | |||
| throw new TaskException( "No url specified in HTTP task" ); | |||
| } | |||
| context.debug( "Checking for " + spec ); | |||
| try | |||
| { | |||
| URL url = new URL( spec ); | |||
| try | |||
| { | |||
| URLConnection conn = url.openConnection(); | |||
| if( conn instanceof HttpURLConnection ) | |||
| { | |||
| HttpURLConnection http = (HttpURLConnection)conn; | |||
| int code = http.getResponseCode(); | |||
| context.debug( "Result code for " + spec + " was " + code ); | |||
| if( code > 0 && code < 500 ) | |||
| { | |||
| return true; | |||
| } | |||
| else | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| } | |||
| catch( java.io.IOException e ) | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| catch( MalformedURLException e ) | |||
| { | |||
| throw new TaskException( "Badly formed URL: " + spec, e ); | |||
| } | |||
| return true; | |||
| } | |||
| } | |||
| @@ -1,66 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.conditions; | |||
| import java.io.IOException; | |||
| import org.apache.myrmidon.api.TaskContext; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.conditions.Condition; | |||
| /** | |||
| * Condition to wait for a TCP/IP socket to have a listener. Its attribute(s) | |||
| * are: server - the name of the server. port - the port number of the socket. | |||
| * | |||
| * @author <a href="mailto:denis@network365.com">Denis Hennessy</a> | |||
| * | |||
| * @ant.type type="condition" name="socket" | |||
| */ | |||
| public class Socket | |||
| implements Condition | |||
| { | |||
| String server = null; | |||
| int port = 0; | |||
| public void setPort( int port ) | |||
| { | |||
| this.port = port; | |||
| } | |||
| public void setServer( String server ) | |||
| { | |||
| this.server = server; | |||
| } | |||
| /** | |||
| * Evaluates this condition. | |||
| */ | |||
| public boolean evaluate( TaskContext context ) | |||
| throws TaskException | |||
| { | |||
| if( server == null ) | |||
| { | |||
| throw new TaskException( "No server specified in Socket task" ); | |||
| } | |||
| if( port == 0 ) | |||
| { | |||
| throw new TaskException( "No port specified in Socket task" ); | |||
| } | |||
| context.debug( "Checking for listener at " + server + ":" + port ); | |||
| try | |||
| { | |||
| java.net.Socket socket = new java.net.Socket( server, port ); | |||
| socket.close(); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| return false; | |||
| } | |||
| return true; | |||
| } | |||
| } | |||
| @@ -1,64 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.exec; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.io.OutputStream; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| /** | |||
| * Used by <code>Execute</code> to handle input and output stream of | |||
| * subprocesses. | |||
| * | |||
| * @author thomas.haas@softwired-inc.com | |||
| */ | |||
| public interface ExecuteStreamHandler | |||
| { | |||
| /** | |||
| * Install a handler for the input stream of the subprocess. | |||
| * | |||
| * @param os output stream to write to the standard input stream of the | |||
| * subprocess | |||
| * @exception java.io.IOException Description of Exception | |||
| */ | |||
| void setProcessInputStream( OutputStream os ) | |||
| throws IOException; | |||
| /** | |||
| * Install a handler for the error stream of the subprocess. | |||
| * | |||
| * @param is input stream to read from the error stream from the subprocess | |||
| * @exception java.io.IOException Description of Exception | |||
| */ | |||
| void setProcessErrorStream( InputStream is ) | |||
| throws IOException; | |||
| /** | |||
| * Install a handler for the output stream of the subprocess. | |||
| * | |||
| * @param is input stream to read from the error stream from the subprocess | |||
| * @exception java.io.IOException Description of Exception | |||
| */ | |||
| void setProcessOutputStream( InputStream is ) | |||
| throws TaskException, IOException; | |||
| /** | |||
| * Start handling of the streams. | |||
| * | |||
| * @exception java.io.IOException Description of Exception | |||
| */ | |||
| void start() | |||
| throws IOException; | |||
| /** | |||
| * Stop handling of the streams - will not be restarted. | |||
| */ | |||
| void stop() | |||
| throws TaskException; | |||
| } | |||
| @@ -1,635 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.i18n; | |||
| import java.io.BufferedReader; | |||
| import java.io.BufferedWriter; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.FileOutputStream; | |||
| import java.io.IOException; | |||
| import java.io.InputStreamReader; | |||
| import java.io.OutputStreamWriter; | |||
| import java.util.ArrayList; | |||
| import java.util.Hashtable; | |||
| import java.util.Locale; | |||
| import org.apache.avalon.excalibur.io.FileUtil; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.FileSet; | |||
| import org.apache.tools.todo.taskdefs.MatchingTask; | |||
| import org.apache.tools.todo.types.DirectoryScanner; | |||
| import org.apache.tools.todo.types.ScannerUtil; | |||
| /** | |||
| * Translates text embedded in files using Resource Bundle files. | |||
| * | |||
| * @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a> | |||
| */ | |||
| public class Translate | |||
| extends MatchingTask | |||
| { | |||
| /** | |||
| * ArrayList to hold source file sets. | |||
| */ | |||
| private ArrayList filesets = new ArrayList(); | |||
| /** | |||
| * Holds key value pairs loaded from resource bundle file | |||
| */ | |||
| private Hashtable resourceMap = new Hashtable(); | |||
| /** | |||
| * Last Modified Timestamp of resource bundle file being used. | |||
| */ | |||
| private long[] bundleLastModified = new long[ 7 ]; | |||
| /** | |||
| * Has at least one file from the bundle been loaded? | |||
| */ | |||
| private boolean loaded = false; | |||
| /** | |||
| * Family name of resource bundle | |||
| */ | |||
| private String bundle; | |||
| /** | |||
| * Locale specific country of the resource bundle | |||
| */ | |||
| private String bundleCountry; | |||
| /** | |||
| * Resource Bundle file encoding scheme, defaults to srcEncoding | |||
| */ | |||
| private String bundleEncoding; | |||
| /** | |||
| * Locale specific language of the resource bundle | |||
| */ | |||
| private String bundleLanguage; | |||
| /** | |||
| * Locale specific variant of the resource bundle | |||
| */ | |||
| private String bundleVariant; | |||
| /** | |||
| * Destination file encoding scheme | |||
| */ | |||
| private String destEncoding; | |||
| /** | |||
| * Last Modified Timestamp of destination file being used. | |||
| */ | |||
| private long destLastModified; | |||
| /** | |||
| * Ending token to identify keys | |||
| */ | |||
| private String endToken; | |||
| /** | |||
| * Create new destination file? Defaults to false. | |||
| */ | |||
| private boolean forceOverwrite; | |||
| /** | |||
| * Source file encoding scheme | |||
| */ | |||
| private String srcEncoding; | |||
| /** | |||
| * Last Modified Timestamp of source file being used. | |||
| */ | |||
| private long srcLastModified; | |||
| /** | |||
| * Starting token to identify keys | |||
| */ | |||
| private String startToken; | |||
| /** | |||
| * Destination directory | |||
| */ | |||
| private File toDir; | |||
| /** | |||
| * Sets Family name of resource bundle | |||
| * | |||
| * @param bundle The new Bundle value | |||
| */ | |||
| public void setBundle( String bundle ) | |||
| { | |||
| this.bundle = bundle; | |||
| } | |||
| /** | |||
| * Sets locale specific country of resource bundle | |||
| * | |||
| * @param bundleCountry The new BundleCountry value | |||
| */ | |||
| public void setBundleCountry( String bundleCountry ) | |||
| { | |||
| this.bundleCountry = bundleCountry; | |||
| } | |||
| /** | |||
| * Sets Resource Bundle file encoding scheme | |||
| * | |||
| * @param bundleEncoding The new BundleEncoding value | |||
| */ | |||
| public void setBundleEncoding( String bundleEncoding ) | |||
| { | |||
| this.bundleEncoding = bundleEncoding; | |||
| } | |||
| /** | |||
| * Sets locale specific language of resource bundle | |||
| * | |||
| * @param bundleLanguage The new BundleLanguage value | |||
| */ | |||
| public void setBundleLanguage( String bundleLanguage ) | |||
| { | |||
| this.bundleLanguage = bundleLanguage; | |||
| } | |||
| /** | |||
| * Sets locale specific variant of resource bundle | |||
| * | |||
| * @param bundleVariant The new BundleVariant value | |||
| */ | |||
| public void setBundleVariant( String bundleVariant ) | |||
| { | |||
| this.bundleVariant = bundleVariant; | |||
| } | |||
| /** | |||
| * Sets destination file encoding scheme. Defaults to source file encoding | |||
| * | |||
| * @param destEncoding The new DestEncoding value | |||
| */ | |||
| public void setDestEncoding( String destEncoding ) | |||
| { | |||
| this.destEncoding = destEncoding; | |||
| } | |||
| /** | |||
| * Sets ending token to identify keys | |||
| * | |||
| * @param endToken The new EndToken value | |||
| */ | |||
| public void setEndToken( String endToken ) | |||
| { | |||
| this.endToken = endToken; | |||
| } | |||
| /** | |||
| * Overwrite existing file irrespective of whether it is newer than the | |||
| * source file as well as the resource bundle file? Defaults to false. | |||
| * | |||
| * @param forceOverwrite The new ForceOverwrite value | |||
| */ | |||
| public void setForceOverwrite( boolean forceOverwrite ) | |||
| { | |||
| this.forceOverwrite = forceOverwrite; | |||
| } | |||
| /** | |||
| * Sets source file encoding scheme | |||
| * | |||
| * @param srcEncoding The new SrcEncoding value | |||
| */ | |||
| public void setSrcEncoding( String srcEncoding ) | |||
| { | |||
| this.srcEncoding = srcEncoding; | |||
| } | |||
| /** | |||
| * Sets starting token to identify keys | |||
| * | |||
| * @param startToken The new StartToken value | |||
| */ | |||
| public void setStartToken( String startToken ) | |||
| { | |||
| this.startToken = startToken; | |||
| } | |||
| /** | |||
| * Sets Destination directory | |||
| * | |||
| * @param toDir The new ToDir value | |||
| */ | |||
| public void setToDir( File toDir ) | |||
| { | |||
| this.toDir = toDir; | |||
| } | |||
| /** | |||
| * Adds a set of files (nested fileset attribute). | |||
| * | |||
| * @param set The feature to be added to the Fileset attribute | |||
| */ | |||
| public void addFileset( FileSet set ) | |||
| { | |||
| filesets.add( set ); | |||
| } | |||
| /** | |||
| * Check attributes values, load resource map and translate | |||
| * | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| if( bundle == null ) | |||
| { | |||
| throw new TaskException( "The bundle attribute must be set." ); | |||
| } | |||
| if( startToken == null ) | |||
| { | |||
| throw new TaskException( "The starttoken attribute must be set." ); | |||
| } | |||
| if( startToken.length() != 1 ) | |||
| { | |||
| throw new TaskException( | |||
| "The starttoken attribute must be a single character." ); | |||
| } | |||
| if( endToken == null ) | |||
| { | |||
| throw new TaskException( "The endtoken attribute must be set." ); | |||
| } | |||
| if( endToken.length() != 1 ) | |||
| { | |||
| throw new TaskException( | |||
| "The endtoken attribute must be a single character." ); | |||
| } | |||
| if( bundleLanguage == null ) | |||
| { | |||
| Locale l = Locale.getDefault(); | |||
| bundleLanguage = l.getLanguage(); | |||
| } | |||
| if( bundleCountry == null ) | |||
| { | |||
| bundleCountry = Locale.getDefault().getCountry(); | |||
| } | |||
| if( bundleVariant == null ) | |||
| { | |||
| Locale l = new Locale( bundleLanguage, bundleCountry ); | |||
| bundleVariant = l.getVariant(); | |||
| } | |||
| if( toDir == null ) | |||
| { | |||
| throw new TaskException( "The todir attribute must be set." ); | |||
| } | |||
| if( !toDir.exists() ) | |||
| { | |||
| toDir.mkdirs(); | |||
| } | |||
| else | |||
| { | |||
| if( toDir.isFile() ) | |||
| { | |||
| throw new TaskException( toDir + " is not a directory" ); | |||
| } | |||
| } | |||
| if( srcEncoding == null ) | |||
| { | |||
| srcEncoding = System.getProperty( "file.encoding" ); | |||
| } | |||
| if( destEncoding == null ) | |||
| { | |||
| destEncoding = srcEncoding; | |||
| } | |||
| if( bundleEncoding == null ) | |||
| { | |||
| bundleEncoding = srcEncoding; | |||
| } | |||
| loadResourceMaps(); | |||
| translate(); | |||
| } | |||
| /** | |||
| * Load resourceMap with key value pairs. Values of existing keys are not | |||
| * overwritten. Bundle's encoding scheme is used. | |||
| * | |||
| * @param ins Description of Parameter | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| private void loadResourceMap( FileInputStream ins ) | |||
| throws TaskException | |||
| { | |||
| try | |||
| { | |||
| BufferedReader in = null; | |||
| InputStreamReader isr = new InputStreamReader( ins, bundleEncoding ); | |||
| in = new BufferedReader( isr ); | |||
| String line = null; | |||
| while( ( line = in.readLine() ) != null ) | |||
| { | |||
| //So long as the line isn't empty and isn't a comment... | |||
| if( line.trim().length() > 1 && | |||
| ( '#' != line.charAt( 0 ) || '!' != line.charAt( 0 ) ) ) | |||
| { | |||
| //Legal Key-Value separators are :, = and white space. | |||
| int sepIndex = line.indexOf( '=' ); | |||
| if( -1 == sepIndex ) | |||
| { | |||
| sepIndex = line.indexOf( ':' ); | |||
| } | |||
| if( -1 == sepIndex ) | |||
| { | |||
| for( int k = 0; k < line.length(); k++ ) | |||
| { | |||
| if( Character.isSpaceChar( line.charAt( k ) ) ) | |||
| { | |||
| sepIndex = k; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| //Only if we do have a key is there going to be a value | |||
| if( -1 != sepIndex ) | |||
| { | |||
| String key = line.substring( 0, sepIndex ).trim(); | |||
| String value = line.substring( sepIndex + 1 ).trim(); | |||
| //Handle line continuations, if any | |||
| while( value.endsWith( "\\" ) ) | |||
| { | |||
| value = value.substring( 0, value.length() - 1 ); | |||
| if( ( line = in.readLine() ) != null ) | |||
| { | |||
| value = value + line.trim(); | |||
| } | |||
| else | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| if( key.length() > 0 ) | |||
| { | |||
| //Has key already been loaded into resourceMap? | |||
| if( resourceMap.get( key ) == null ) | |||
| { | |||
| resourceMap.put( key, value ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| if( in != null ) | |||
| { | |||
| in.close(); | |||
| } | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| throw new TaskException( ioe.getMessage() ); | |||
| } | |||
| } | |||
| /** | |||
| * Load resource maps based on resource bundle encoding scheme. The resource | |||
| * bundle lookup searches for resource files with various suffixes on the | |||
| * basis of (1) the desired locale and (2) the default locale | |||
| * (basebundlename), in the following order from lower-level (more specific) | |||
| * to parent-level (less specific): basebundlename + "_" + language1 + "_" + | |||
| * country1 + "_" + variant1 basebundlename + "_" + language1 + "_" + | |||
| * country1 basebundlename + "_" + language1 basebundlename basebundlename + | |||
| * "_" + language2 + "_" + country2 + "_" + variant2 basebundlename + "_" + | |||
| * language2 + "_" + country2 basebundlename + "_" + language2 To the | |||
| * generated name, a ".properties" string is appeneded and once this file is | |||
| * located, it is treated just like a properties file but with bundle | |||
| * encoding also considered while loading. | |||
| * | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| private void loadResourceMaps() | |||
| throws TaskException | |||
| { | |||
| Locale locale = new Locale( bundleLanguage, | |||
| bundleCountry, | |||
| bundleVariant ); | |||
| String language = locale.getLanguage().length() > 0 ? | |||
| "_" + locale.getLanguage() : | |||
| ""; | |||
| String country = locale.getCountry().length() > 0 ? | |||
| "_" + locale.getCountry() : | |||
| ""; | |||
| String variant = locale.getVariant().length() > 0 ? | |||
| "_" + locale.getVariant() : | |||
| ""; | |||
| String bundleFile = bundle + language + country + variant; | |||
| processBundle( bundleFile, 0, false ); | |||
| bundleFile = bundle + language + country; | |||
| processBundle( bundleFile, 1, false ); | |||
| bundleFile = bundle + language; | |||
| processBundle( bundleFile, 2, false ); | |||
| bundleFile = bundle; | |||
| processBundle( bundleFile, 3, false ); | |||
| //Load default locale bundle files | |||
| //using default file encoding scheme. | |||
| locale = Locale.getDefault(); | |||
| language = locale.getLanguage().length() > 0 ? | |||
| "_" + locale.getLanguage() : | |||
| ""; | |||
| country = locale.getCountry().length() > 0 ? | |||
| "_" + locale.getCountry() : | |||
| ""; | |||
| variant = locale.getVariant().length() > 0 ? | |||
| "_" + locale.getVariant() : | |||
| ""; | |||
| bundleEncoding = System.getProperty( "file.encoding" ); | |||
| bundleFile = bundle + language + country + variant; | |||
| processBundle( bundleFile, 4, false ); | |||
| bundleFile = bundle + language + country; | |||
| processBundle( bundleFile, 5, false ); | |||
| bundleFile = bundle + language; | |||
| processBundle( bundleFile, 6, true ); | |||
| } | |||
| /** | |||
| * Process each file that makes up this bundle. | |||
| * | |||
| * @param bundleFile Description of Parameter | |||
| * @param i Description of Parameter | |||
| * @param checkLoaded Description of Parameter | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| private void processBundle( String bundleFile, int i, | |||
| boolean checkLoaded ) | |||
| throws TaskException | |||
| { | |||
| bundleFile += ".properties"; | |||
| FileInputStream ins = null; | |||
| try | |||
| { | |||
| ins = new FileInputStream( bundleFile ); | |||
| loaded = true; | |||
| bundleLastModified[ i ] = new File( bundleFile ).lastModified(); | |||
| getContext().debug( "Using " + bundleFile ); | |||
| loadResourceMap( ins ); | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| getContext().debug( bundleFile + " not found." ); | |||
| //if all resource files associated with this bundle | |||
| //have been scanned for and still not able to | |||
| //find a single resrouce file, throw exception | |||
| if( !loaded && checkLoaded ) | |||
| { | |||
| throw new TaskException( ioe.getMessage() ); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Reads source file line by line using the source encoding and searches for | |||
| * keys that are sandwiched between the startToken and endToken. The values | |||
| * for these keys are looked up from the hashtable and substituted. If the | |||
| * hashtable doesn't contain the key, they key itself is used as the value. | |||
| * Detination files and directories are created as needed. The destination | |||
| * file is overwritten only if the forceoverwritten attribute is set to true | |||
| * if the source file or any associated bundle resource file is newer than | |||
| * the destination file. | |||
| * | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| private void translate() | |||
| throws TaskException | |||
| { | |||
| for( int i = 0; i < filesets.size(); i++ ) | |||
| { | |||
| FileSet fs = (FileSet)filesets.get( i ); | |||
| DirectoryScanner ds = ScannerUtil.getDirectoryScanner( fs ); | |||
| String[] srcFiles = ds.getIncludedFiles(); | |||
| for( int j = 0; j < srcFiles.length; j++ ) | |||
| { | |||
| try | |||
| { | |||
| File dest = FileUtil.resolveFile( toDir, srcFiles[ j ] ); | |||
| //Make sure parent dirs exist, else, create them. | |||
| try | |||
| { | |||
| File destDir = new File( dest.getParent() ); | |||
| if( !destDir.exists() ) | |||
| { | |||
| destDir.mkdirs(); | |||
| } | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| getContext().debug( "Exception occured while trying to check/create " + " parent directory. " + e.getMessage() ); | |||
| } | |||
| destLastModified = dest.lastModified(); | |||
| srcLastModified = new File( srcFiles[ i ] ).lastModified(); | |||
| //Check to see if dest file has to be recreated | |||
| if( forceOverwrite | |||
| || destLastModified < srcLastModified | |||
| || destLastModified < bundleLastModified[ 0 ] | |||
| || destLastModified < bundleLastModified[ 1 ] | |||
| || destLastModified < bundleLastModified[ 2 ] | |||
| || destLastModified < bundleLastModified[ 3 ] | |||
| || destLastModified < bundleLastModified[ 4 ] | |||
| || destLastModified < bundleLastModified[ 5 ] | |||
| || destLastModified < bundleLastModified[ 6 ] ) | |||
| { | |||
| getContext().debug( "Processing " + srcFiles[ j ] ); | |||
| FileOutputStream fos = new FileOutputStream( dest ); | |||
| BufferedWriter out = new BufferedWriter( | |||
| new OutputStreamWriter( fos, | |||
| destEncoding ) ); | |||
| FileInputStream fis = new FileInputStream( srcFiles[ j ] ); | |||
| BufferedReader in = new BufferedReader( | |||
| new InputStreamReader( fis, | |||
| srcEncoding ) ); | |||
| String line; | |||
| while( ( line = in.readLine() ) != null ) | |||
| { | |||
| int startIndex = -1; | |||
| int endIndex = -1; | |||
| outer : | |||
| while( true ) | |||
| { | |||
| startIndex = line.indexOf( startToken, endIndex + 1 ); | |||
| if( startIndex < 0 || | |||
| startIndex + 1 >= line.length() ) | |||
| { | |||
| break; | |||
| } | |||
| endIndex = line.indexOf( endToken, startIndex + 1 ); | |||
| if( endIndex < 0 ) | |||
| { | |||
| break; | |||
| } | |||
| String matches = line.substring( startIndex + 1, | |||
| endIndex ); | |||
| //If there is a white space or = or :, then | |||
| //it isn't to be treated as a valid key. | |||
| for( int k = 0; k < matches.length(); k++ ) | |||
| { | |||
| char c = matches.charAt( k ); | |||
| if( c == ':' || | |||
| c == '=' || | |||
| Character.isSpaceChar( c ) ) | |||
| { | |||
| endIndex = endIndex - 1; | |||
| continue outer; | |||
| } | |||
| } | |||
| String replace = null; | |||
| replace = (String)resourceMap.get( matches ); | |||
| //If the key hasn't been loaded into resourceMap, | |||
| //use the key itself as the value also. | |||
| if( replace == null ) | |||
| { | |||
| getContext().debug( "Warning: The key: " + matches + " hasn't been defined." ); | |||
| replace = matches; | |||
| } | |||
| line = line.substring( 0, startIndex ) | |||
| + replace | |||
| + line.substring( endIndex + 1 ); | |||
| endIndex = startIndex + replace.length() + 1; | |||
| if( endIndex + 1 >= line.length() ) | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| out.write( line ); | |||
| out.newLine(); | |||
| } | |||
| if( in != null ) | |||
| { | |||
| in.close(); | |||
| } | |||
| if( out != null ) | |||
| { | |||
| out.close(); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| getContext().debug( "Skipping " + srcFiles[ j ] + " as destination file is up to date" ); | |||
| } | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| throw new TaskException( ioe.getMessage() ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -1,45 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.javac; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.api.TaskContext; | |||
| /** | |||
| * The interface that all compiler adapters must adher to. <p> | |||
| * | |||
| * A compiler adapter is an adapter that interprets the javac's parameters in | |||
| * preperation to be passed off to the compier this adapter represents. As all | |||
| * the necessary values are stored in the Javac task itself, the only thing all | |||
| * adapters need is the javac task, the execute command and a parameterless | |||
| * constructor (for reflection).</p> | |||
| * | |||
| * @author Jay Dickon Glanville <a href="mailto:jayglanville@home.com"> | |||
| * jayglanville@home.com</a> | |||
| */ | |||
| public interface CompilerAdapter | |||
| { | |||
| void setTaskContext( TaskContext context ); | |||
| /** | |||
| * Sets the compiler attributes, which are stored in the Javac task. | |||
| * | |||
| * @param attributes The new Javac value | |||
| */ | |||
| void setJavac( Javac attributes ); | |||
| /** | |||
| * Executes the task. | |||
| * | |||
| * @return has the compilation been successful | |||
| * @exception org.apache.myrmidon.api.TaskException Description of Exception | |||
| */ | |||
| boolean execute() | |||
| throws TaskException; | |||
| } | |||
| @@ -1,155 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.javac; | |||
| import org.apache.myrmidon.api.TaskContext; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.tools.todo.taskdefs.javac.CompilerAdapter; | |||
| /** | |||
| * Creates the necessary compiler adapter, given basic criteria. | |||
| * | |||
| * @author <a href="mailto:jayglanville@home.com">J D Glanville</a> | |||
| */ | |||
| public class CompilerAdapterFactory | |||
| { | |||
| /** | |||
| * This is a singlton -- can't create instances!! | |||
| */ | |||
| private CompilerAdapterFactory() | |||
| { | |||
| } | |||
| /** | |||
| * Based on the parameter passed in, this method creates the necessary | |||
| * factory desired. The current mapping for compiler names are as follows: | |||
| * | |||
| * <ul> | |||
| * <li> jikes = jikes compiler | |||
| * <li> classic, javac1.1, javac1.2 = the standard compiler from JDK | |||
| * 1.1/1.2 | |||
| * <li> modern, javac1.3 = the new compiler of JDK 1.3 | |||
| * <li> jvc, microsoft = the command line compiler from Microsoft's SDK | |||
| * for Java / Visual J++ | |||
| * <li> kjc = the kopi compiler</li> | |||
| * <li> gcj = the gcj compiler from gcc</li> | |||
| * <li> <i>a fully quallified classname</i> = the name of a compiler | |||
| * adapter | |||
| * </ul> | |||
| * | |||
| * | |||
| * @param compilerType either the name of the desired compiler, or the full | |||
| * classname of the compiler's adapter. | |||
| * @return The Compiler value | |||
| * @throws org.apache.myrmidon.api.TaskException if the compiler type could not be resolved into a | |||
| * compiler adapter. | |||
| */ | |||
| public static CompilerAdapter getCompiler( String compilerType, | |||
| TaskContext context ) | |||
| throws TaskException | |||
| { | |||
| final CompilerAdapter adaptor = createAdaptor( compilerType, context ); | |||
| adaptor.setTaskContext( context ); | |||
| return adaptor; | |||
| } | |||
| private static CompilerAdapter createAdaptor( String compilerType, TaskContext context ) throws TaskException | |||
| { | |||
| /* | |||
| * If I've done things right, this should be the extent of the | |||
| * conditional statements required. | |||
| */ | |||
| if( compilerType.equalsIgnoreCase( "jikes" ) ) | |||
| { | |||
| return new Jikes(); | |||
| } | |||
| if( compilerType.equalsIgnoreCase( "extJavac" ) ) | |||
| { | |||
| return new JavacExternal(); | |||
| } | |||
| if( compilerType.equalsIgnoreCase( "classic" ) || | |||
| compilerType.equalsIgnoreCase( "javac1.1" ) || | |||
| compilerType.equalsIgnoreCase( "javac1.2" ) ) | |||
| { | |||
| return new Javac12(); | |||
| } | |||
| if( compilerType.equalsIgnoreCase( "modern" ) || | |||
| compilerType.equalsIgnoreCase( "javac1.3" ) || | |||
| compilerType.equalsIgnoreCase( "javac1.4" ) ) | |||
| { | |||
| // does the modern compiler exist? | |||
| try | |||
| { | |||
| Class.forName( "com.sun.tools.javac.Main" ); | |||
| } | |||
| catch( ClassNotFoundException cnfe ) | |||
| { | |||
| final String message = "Modern compiler is not available - using " | |||
| + "classic compiler"; | |||
| context.warn( message ); | |||
| return new Javac12(); | |||
| } | |||
| return new Javac13(); | |||
| } | |||
| if( compilerType.equalsIgnoreCase( "jvc" ) || | |||
| compilerType.equalsIgnoreCase( "microsoft" ) ) | |||
| { | |||
| return new Jvc(); | |||
| } | |||
| if( compilerType.equalsIgnoreCase( "kjc" ) ) | |||
| { | |||
| return new Kjc(); | |||
| } | |||
| if( compilerType.equalsIgnoreCase( "gcj" ) ) | |||
| { | |||
| return new Gcj(); | |||
| } | |||
| if( compilerType.equalsIgnoreCase( "sj" ) || | |||
| compilerType.equalsIgnoreCase( "symantec" ) ) | |||
| { | |||
| return new Sj(); | |||
| } | |||
| return resolveClassName( compilerType ); | |||
| } | |||
| /** | |||
| * Tries to resolve the given classname into a compiler adapter. Throws a | |||
| * fit if it can't. | |||
| * | |||
| * @param className The fully qualified classname to be created. | |||
| * @return Description of the Returned Value | |||
| * @throws org.apache.myrmidon.api.TaskException This is the fit that is thrown if className isn't | |||
| * an instance of CompilerAdapter. | |||
| */ | |||
| private static CompilerAdapter resolveClassName( String className ) | |||
| throws TaskException | |||
| { | |||
| try | |||
| { | |||
| Class c = Class.forName( className ); | |||
| Object o = c.newInstance(); | |||
| return (CompilerAdapter)o; | |||
| } | |||
| catch( ClassNotFoundException cnfe ) | |||
| { | |||
| throw new TaskException( className + " can\'t be found.", cnfe ); | |||
| } | |||
| catch( ClassCastException cce ) | |||
| { | |||
| throw new TaskException( className + " isn\'t the classname of " | |||
| + "a compiler adapter.", cce ); | |||
| } | |||
| catch( Throwable t ) | |||
| { | |||
| // for all other possibilities | |||
| throw new TaskException( className + " caused an interesting " | |||
| + "exception.", t ); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,468 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.javac; | |||
| import java.io.File; | |||
| import java.io.FileWriter; | |||
| import java.io.IOException; | |||
| import java.io.PrintWriter; | |||
| import org.apache.avalon.excalibur.io.IOUtil; | |||
| import org.apache.avalon.excalibur.util.StringUtil; | |||
| import org.apache.myrmidon.api.TaskContext; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.nativelib.Execute; | |||
| import org.apache.myrmidon.framework.FileSet; | |||
| import org.apache.myrmidon.framework.nativelib.Commandline; | |||
| import org.apache.myrmidon.framework.nativelib.ArgumentList; | |||
| import org.apache.myrmidon.framework.file.Path; | |||
| import org.apache.myrmidon.framework.file.FileListUtil; | |||
| import org.apache.tools.todo.util.FileUtils; | |||
| import org.apache.aut.nativelib.PathUtil; | |||
| /** | |||
| * This is the default implementation for the CompilerAdapter interface. | |||
| * Currently, this is a cut-and-paste of the original javac task. | |||
| * | |||
| * @author James Davidson <a href="mailto:duncan@x180.com">duncan@x180.com</a> | |||
| * @author Robin Green <a href="mailto:greenrd@hotmail.com">greenrd@hotmail.com | |||
| * </a> | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:jayglanville@home.com">J D Glanville</a> | |||
| */ | |||
| public abstract class DefaultCompilerAdapter | |||
| implements CompilerAdapter | |||
| { | |||
| protected boolean m_debug; | |||
| protected boolean m_optimize; | |||
| protected boolean m_deprecation; | |||
| protected boolean m_depend; | |||
| protected boolean m_verbose; | |||
| protected Javac m_attributes; | |||
| protected Path m_bootclasspath; | |||
| protected Path m_compileClasspath; | |||
| protected File[] m_compileList; | |||
| protected File m_destDir; | |||
| protected String m_encoding; | |||
| protected Path m_extdirs; | |||
| protected boolean m_includeAntRuntime; | |||
| protected boolean m_includeJavaRuntime; | |||
| protected String m_memoryInitialSize; | |||
| protected String m_memoryMaximumSize; | |||
| /* | |||
| * jdg - TODO - all these attributes are currently protected, but they | |||
| * should probably be private in the near future. | |||
| */ | |||
| protected Path src; | |||
| protected String target; | |||
| private TaskContext m_taskContext; | |||
| public void setTaskContext( final TaskContext context ) | |||
| { | |||
| m_taskContext = context; | |||
| } | |||
| protected final TaskContext getTaskContext() | |||
| { | |||
| return m_taskContext; | |||
| } | |||
| public void setJavac( Javac attributes ) | |||
| { | |||
| m_attributes = attributes; | |||
| src = attributes.getSrcdir(); | |||
| m_destDir = attributes.getDestdir(); | |||
| m_encoding = attributes.getEncoding(); | |||
| m_debug = attributes.getDebug(); | |||
| m_optimize = attributes.isOptimize(); | |||
| m_deprecation = attributes.getDeprecation(); | |||
| m_depend = attributes.getDepend(); | |||
| m_verbose = attributes.getVerbose(); | |||
| target = attributes.getTarget(); | |||
| m_bootclasspath = attributes.getBootclasspath(); | |||
| m_extdirs = attributes.getExtdirs(); | |||
| m_compileList = attributes.getFileList(); | |||
| m_compileClasspath = attributes.getClasspath(); | |||
| m_memoryInitialSize = attributes.getMemoryInitialSize(); | |||
| m_memoryMaximumSize = attributes.getMemoryMaximumSize(); | |||
| } | |||
| public Javac getJavac() | |||
| { | |||
| return m_attributes; | |||
| } | |||
| protected ArgumentList setupJavacCommand() | |||
| throws TaskException | |||
| { | |||
| return setupJavacCommand( false ); | |||
| } | |||
| /** | |||
| * Does the command line argument processing for classic and adds the files | |||
| * to compile as well. | |||
| * | |||
| * @param debugLevelCheck Description of Parameter | |||
| * @return Description of the Returned Value | |||
| */ | |||
| protected ArgumentList setupJavacCommand( boolean debugLevelCheck ) | |||
| throws TaskException | |||
| { | |||
| ArgumentList cmd = new ArgumentList(); | |||
| setupJavacCommandlineSwitches( cmd, debugLevelCheck ); | |||
| logFilesToCompile( cmd ); | |||
| addFilesToCompile( cmd ); | |||
| return cmd; | |||
| } | |||
| /** | |||
| * Does the command line argument processing common to classic and modern. | |||
| * Doesn't add the files to compile. | |||
| * | |||
| * @param cmd Description of Parameter | |||
| * @param useDebugLevel Description of Parameter | |||
| * @return Description of the Returned Value | |||
| */ | |||
| protected ArgumentList setupJavacCommandlineSwitches( ArgumentList cmd, | |||
| boolean useDebugLevel ) | |||
| throws TaskException | |||
| { | |||
| Path classpath = new Path(); | |||
| addCompileClasspath( classpath ); | |||
| String memoryParameterPrefix = "-J-X"; | |||
| if( m_memoryInitialSize != null ) | |||
| { | |||
| if( !m_attributes.isForkedJavac() ) | |||
| { | |||
| final String message = "Since fork is false, ignoring memoryInitialSize setting."; | |||
| getTaskContext().warn( message ); | |||
| } | |||
| else | |||
| { | |||
| cmd.addArgument( memoryParameterPrefix + "ms" + m_memoryInitialSize ); | |||
| } | |||
| } | |||
| if( m_memoryMaximumSize != null ) | |||
| { | |||
| if( !m_attributes.isForkedJavac() ) | |||
| { | |||
| final String message = "Since fork is false, ignoring memoryMaximumSize setting."; | |||
| getTaskContext().warn( message ); | |||
| } | |||
| else | |||
| { | |||
| cmd.addArgument( memoryParameterPrefix + "mx" + m_memoryMaximumSize ); | |||
| } | |||
| } | |||
| if( m_attributes.getNowarn() ) | |||
| { | |||
| cmd.addArgument( "-nowarn" ); | |||
| } | |||
| if( m_deprecation == true ) | |||
| { | |||
| cmd.addArgument( "-deprecation" ); | |||
| } | |||
| if( m_destDir != null ) | |||
| { | |||
| cmd.addArgument( "-d" ); | |||
| cmd.addArgument( m_destDir ); | |||
| } | |||
| cmd.addArgument( "-classpath" ); | |||
| cmd.addArgument( FileListUtil.formatPath( classpath, getTaskContext() ) ); | |||
| cmd.addArgument( "-sourcepath" ); | |||
| cmd.addArgument( FileListUtil.formatPath( src, getTaskContext() ) ); | |||
| if( target != null ) | |||
| { | |||
| cmd.addArgument( "-target" ); | |||
| cmd.addArgument( target ); | |||
| } | |||
| final String[] bootclasspath = m_bootclasspath.listFiles( getTaskContext() ); | |||
| if( bootclasspath.length > 0 ) | |||
| { | |||
| cmd.addArgument( "-bootclasspath" ); | |||
| cmd.addArgument( PathUtil.formatPath( bootclasspath ) ); | |||
| } | |||
| if( m_extdirs != null ) | |||
| { | |||
| cmd.addArgument( "-extdirs" ); | |||
| cmd.addArgument( FileListUtil.formatPath( m_extdirs, getTaskContext() ) ); | |||
| } | |||
| if( m_encoding != null ) | |||
| { | |||
| cmd.addArgument( "-encoding" ); | |||
| cmd.addArgument( m_encoding ); | |||
| } | |||
| if( m_debug ) | |||
| { | |||
| if( useDebugLevel ) | |||
| { | |||
| String debugLevel = m_attributes.getDebugLevel(); | |||
| if( debugLevel != null ) | |||
| { | |||
| cmd.addArgument( "-g:" + debugLevel ); | |||
| } | |||
| else | |||
| { | |||
| cmd.addArgument( "-g" ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| cmd.addArgument( "-g" ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| cmd.addArgument( "-g:none" ); | |||
| } | |||
| if( m_optimize ) | |||
| { | |||
| cmd.addArgument( "-O" ); | |||
| } | |||
| if( m_verbose ) | |||
| { | |||
| cmd.addArgument( "-verbose" ); | |||
| } | |||
| addCurrentCompilerArgs( cmd ); | |||
| return cmd; | |||
| } | |||
| /** | |||
| * Does the command line argument processing for modern and adds the files | |||
| * to compile as well. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| protected ArgumentList setupModernJavacCommand() | |||
| throws TaskException | |||
| { | |||
| ArgumentList cmd = new ArgumentList(); | |||
| setupModernJavacCommandlineSwitches( cmd ); | |||
| logFilesToCompile( cmd ); | |||
| addFilesToCompile( cmd ); | |||
| return cmd; | |||
| } | |||
| /** | |||
| * Does the command line argument processing for modern. Doesn't add the | |||
| * files to compile. | |||
| * | |||
| * @param cmd Description of Parameter | |||
| * @return Description of the Returned Value | |||
| */ | |||
| protected ArgumentList setupModernJavacCommandlineSwitches( ArgumentList cmd ) | |||
| throws TaskException | |||
| { | |||
| setupJavacCommandlineSwitches( cmd, true ); | |||
| if( m_attributes.getSource() != null ) | |||
| { | |||
| cmd.addArgument( "-source" ); | |||
| cmd.addArgument( m_attributes.getSource() ); | |||
| } | |||
| return cmd; | |||
| } | |||
| /** | |||
| * Adds the compilation classpath to a path. | |||
| */ | |||
| protected void addCompileClasspath( final Path classpath ) | |||
| throws TaskException | |||
| { | |||
| // add dest dir to classpath so that previously compiled and | |||
| // untouched classes are on classpath | |||
| if( m_destDir != null ) | |||
| { | |||
| classpath.addLocation( m_destDir ); | |||
| } | |||
| // add the classpath | |||
| if( m_compileClasspath != null ) | |||
| { | |||
| classpath.add( m_compileClasspath ); | |||
| } | |||
| } | |||
| /** | |||
| * Adds the command line arguments specifc to the current implementation. | |||
| * | |||
| * @param cmd The feature to be added to the CurrentCompilerArgs attribute | |||
| */ | |||
| protected void addCurrentCompilerArgs( ArgumentList cmd ) | |||
| { | |||
| cmd.addArguments( getJavac().getCurrentCompilerArgs() ); | |||
| } | |||
| /** | |||
| * Do the compile with the specified arguments. | |||
| * | |||
| * @param cmd - the command line, to which the names of the files to | |||
| * compile are added. | |||
| */ | |||
| protected boolean executeExternalCompile( final Commandline cmd ) | |||
| throws TaskException | |||
| { | |||
| logFilesToCompile( cmd ); | |||
| File tmpFile = null; | |||
| try | |||
| { | |||
| /* | |||
| * Many system have been reported to get into trouble with | |||
| * long command lines - no, not only Windows ;-). | |||
| * | |||
| * POSIX seems to define a lower limit of 4k, so use a temporary | |||
| * file. | |||
| */ | |||
| try | |||
| { | |||
| tmpFile = File.createTempFile( "javac", "", new File( "." ) ); | |||
| final FileWriter fout = new FileWriter( tmpFile ); | |||
| try | |||
| { | |||
| final PrintWriter out = new PrintWriter( fout ); | |||
| for( int i = 0; i < m_compileList.length; i++ ) | |||
| { | |||
| File file = m_compileList[i ]; | |||
| out.println( file.getAbsolutePath() ); | |||
| } | |||
| out.close(); | |||
| } | |||
| finally | |||
| { | |||
| IOUtil.shutdownWriter( fout ); | |||
| } | |||
| } | |||
| catch( final IOException ioe ) | |||
| { | |||
| throw new TaskException( "Error creating temporary file", ioe ); | |||
| } | |||
| cmd.addArgument( "@" + tmpFile.getAbsolutePath() ); | |||
| final Execute exe = new Execute(); | |||
| exe.setIgnoreReturnCode( true ); | |||
| exe.setCommandline( cmd ); | |||
| return exe.execute( getTaskContext() ) == 0; | |||
| } | |||
| finally | |||
| { | |||
| if( tmpFile != null ) | |||
| { | |||
| tmpFile.delete(); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Logs the compilation parameters, adds the files to compile and logs the | |||
| * &qout;niceSourceList" | |||
| * | |||
| * @param cmd Description of Parameter | |||
| */ | |||
| protected void logFilesToCompile( final ArgumentList cmd ) | |||
| throws TaskException | |||
| { | |||
| final String[] cmdline = cmd.getArguments(); | |||
| getTaskContext().debug( "Compilation args: " + FileUtils.formatCommandLine( cmdline ) ); | |||
| StringBuffer niceSourceList = new StringBuffer( "File" ); | |||
| if( m_compileList.length != 1 ) | |||
| { | |||
| niceSourceList.append( "s" ); | |||
| } | |||
| niceSourceList.append( " to be compiled:" ); | |||
| niceSourceList.append( StringUtil.LINE_SEPARATOR ); | |||
| for( int i = 0; i < m_compileList.length; i++ ) | |||
| { | |||
| String arg = m_compileList[ i ].getAbsolutePath(); | |||
| niceSourceList.append( " " + arg + StringUtil.LINE_SEPARATOR ); | |||
| } | |||
| getTaskContext().debug( niceSourceList.toString() ); | |||
| } | |||
| /** | |||
| * Adds the files to compile to a command-line | |||
| */ | |||
| protected void addFilesToCompile( final ArgumentList cmd ) | |||
| { | |||
| for( int i = 0; i < m_compileList.length; i++ ) | |||
| { | |||
| File file = m_compileList[i ]; | |||
| cmd.addArgument( file ); | |||
| } | |||
| } | |||
| /** | |||
| * Emulation of extdirs feature in java >= 1.2. This method adds all files | |||
| * in the given directories (but not in sub-directories!) to the classpath, | |||
| * so that you don't have to specify them all one by one. | |||
| */ | |||
| protected void addExtdirs( Path path ) | |||
| throws TaskException | |||
| { | |||
| if( m_extdirs == null ) | |||
| { | |||
| String extProp = System.getProperty( "java.ext.dirs" ); | |||
| if( extProp != null ) | |||
| { | |||
| m_extdirs = new Path( extProp ); | |||
| } | |||
| else | |||
| { | |||
| return; | |||
| } | |||
| } | |||
| addExtdirs( path, m_extdirs, getTaskContext() ); | |||
| } | |||
| /** | |||
| * Adds the contents of a set of directories to a path. | |||
| */ | |||
| public static void addExtdirs( final Path toPath, | |||
| final Path extDirs, | |||
| final TaskContext context ) | |||
| throws TaskException | |||
| { | |||
| final String[] dirs = extDirs.listFiles( context ); | |||
| for( int i = 0; i < dirs.length; i++ ) | |||
| { | |||
| final File dir = new File( dirs[ i ] ); | |||
| if( dir.exists() && dir.isDirectory() ) | |||
| { | |||
| final FileSet fileSet = new FileSet(); | |||
| fileSet.setDir( dir ); | |||
| fileSet.setIncludes( "*" ); | |||
| toPath.addFileset( fileSet ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -1,107 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.javac; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.nativelib.Commandline; | |||
| import org.apache.myrmidon.framework.file.Path; | |||
| import org.apache.myrmidon.framework.file.FileListUtil; | |||
| /** | |||
| * The implementation of the gcj compiler. This is primarily a cut-and-paste | |||
| * from the jikes. | |||
| * | |||
| * @author <a href="mailto:tora@debian.org">Takashi Okamoto</a> | |||
| * @author tora@debian.org | |||
| */ | |||
| public class Gcj extends DefaultCompilerAdapter | |||
| { | |||
| /** | |||
| * Performs a compile using the gcj compiler. | |||
| * | |||
| * @return Description of the Returned Value | |||
| * @exception org.apache.myrmidon.api.TaskException Description of Exception | |||
| */ | |||
| public boolean execute() | |||
| throws TaskException | |||
| { | |||
| Commandline cmd; | |||
| getTaskContext().debug( "Using gcj compiler" ); | |||
| cmd = setupGCJCommand(); | |||
| return executeExternalCompile( cmd ); | |||
| } | |||
| protected Commandline setupGCJCommand() | |||
| throws TaskException | |||
| { | |||
| Commandline cmd = new Commandline(); | |||
| Path classpath = new Path(); | |||
| // gcj doesn't support bootclasspath dir (-bootclasspath) | |||
| // so we'll emulate it for compatibility and convenience. | |||
| final String[] bootclasspath = m_bootclasspath.listFiles( getTaskContext() ); | |||
| classpath.add( bootclasspath ); | |||
| // gcj doesn't support an extension dir (-extdir) | |||
| // so we'll emulate it for compatibility and convenience. | |||
| addExtdirs( classpath ); | |||
| if( bootclasspath.length == 0 ) | |||
| { | |||
| // no bootclasspath, therefore, get one from the java runtime | |||
| m_includeJavaRuntime = true; | |||
| } | |||
| addCompileClasspath( classpath ); | |||
| // Gcj has no option for source-path so we | |||
| // will add it to classpath. | |||
| classpath.add( src ); | |||
| cmd.setExecutable( "gcj" ); | |||
| if( m_destDir != null ) | |||
| { | |||
| cmd.addArgument( "-d" ); | |||
| cmd.addArgument( m_destDir ); | |||
| if( m_destDir.mkdirs() ) | |||
| { | |||
| throw new TaskException( "Can't make output directories. Maybe permission is wrong. " ); | |||
| } | |||
| ; | |||
| } | |||
| cmd.addArgument( "-classpath" ); | |||
| cmd.addArgument( FileListUtil.formatPath( classpath, getTaskContext() ) ); | |||
| if( m_encoding != null ) | |||
| { | |||
| cmd.addArgument( "--encoding=" + m_encoding ); | |||
| } | |||
| if( m_debug ) | |||
| { | |||
| cmd.addArgument( "-g1" ); | |||
| } | |||
| if( m_optimize ) | |||
| { | |||
| cmd.addArgument( "-O" ); | |||
| } | |||
| /** | |||
| * gcj should be set for generate class. | |||
| */ | |||
| cmd.addArgument( "-C" ); | |||
| addCurrentCompilerArgs( cmd ); | |||
| return cmd; | |||
| } | |||
| } | |||
| @@ -1,43 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.javac; | |||
| import org.apache.myrmidon.framework.nativelib.Argument; | |||
| /** | |||
| * Adds an "implementation" attribute to Commandline$Attribute used to | |||
| * filter command line attributes based on the current implementation. | |||
| */ | |||
| public class ImplementationSpecificArgument | |||
| extends Argument | |||
| { | |||
| private String m_impl; | |||
| private Javac m_javac; | |||
| public ImplementationSpecificArgument( Javac javac ) | |||
| { | |||
| m_javac = javac; | |||
| } | |||
| public void setImplementation( String impl ) | |||
| { | |||
| this.m_impl = impl; | |||
| } | |||
| public String[] getParts() | |||
| { | |||
| if( m_impl == null || m_impl.equals( m_javac.determineCompiler() ) ) | |||
| { | |||
| return super.getParts(); | |||
| } | |||
| else | |||
| { | |||
| return new String[ 0 ]; | |||
| } | |||
| } | |||
| } | |||
| @@ -1,753 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.javac; | |||
| import java.io.File; | |||
| import java.util.ArrayList; | |||
| import java.util.Iterator; | |||
| import org.apache.aut.nativelib.Os; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.JavaVersion; | |||
| import org.apache.tools.todo.taskdefs.MatchingTask; | |||
| import org.apache.tools.todo.types.DirectoryScanner; | |||
| import org.apache.myrmidon.framework.file.Path; | |||
| import org.apache.tools.todo.types.SourceFileScanner; | |||
| import org.apache.tools.todo.util.mappers.GlobPatternMapper; | |||
| /** | |||
| * Task to compile Java source files. This task can take the following | |||
| * arguments: | |||
| * <ul> | |||
| * <li> sourcedir | |||
| * <li> destdir | |||
| * <li> deprecation | |||
| * <li> classpath | |||
| * <li> bootclasspath | |||
| * <li> extdirs | |||
| * <li> optimize | |||
| * <li> debug | |||
| * <li> encoding | |||
| * <li> target | |||
| * <li> depend | |||
| * <li> vebose | |||
| * <li> failonerror | |||
| * <li> includeantruntime | |||
| * <li> includejavaruntime | |||
| * <li> source | |||
| * </ul> | |||
| * Of these arguments, the <b>sourcedir</b> and <b>destdir</b> are required. <p> | |||
| * | |||
| * When this task executes, it will recursively scan the sourcedir and destdir | |||
| * looking for Java source files to compile. This task makes its compile | |||
| * decision based on timestamp. | |||
| * | |||
| * @author James Davidson <a href="mailto:duncan@x180.com">duncan@x180.com</a> | |||
| * @author Robin Green <a href="mailto:greenrd@hotmail.com">greenrd@hotmail.com | |||
| * </a> | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:jayglanville@home.com">J D Glanville</a> | |||
| */ | |||
| public class Javac | |||
| extends MatchingTask | |||
| { | |||
| private final static String FAIL_MSG | |||
| = "Compile failed, messages should have been provided."; | |||
| private boolean m_debug; | |||
| private boolean m_optimize; | |||
| private boolean m_deprecation; | |||
| private boolean m_depend; | |||
| private boolean m_verbose; | |||
| private boolean m_includeAntRuntime = true; | |||
| private boolean m_includeJavaRuntime; | |||
| private boolean m_fork; | |||
| private String m_forkedExecutable; | |||
| private boolean m_nowarn; | |||
| private ArrayList m_implementationSpecificArgs = new ArrayList(); | |||
| protected File[] m_compileList = new File[ 0 ]; | |||
| private Path m_bootclasspath = new Path(); | |||
| private Path m_compileClasspath; | |||
| private String m_debugLevel; | |||
| private File m_destDir; | |||
| private String m_encoding; | |||
| private Path m_extdirs; | |||
| private String m_memoryInitialSize; | |||
| private String m_memoryMaximumSize; | |||
| private String m_source; | |||
| private Path m_src; | |||
| private String m_target; | |||
| /** | |||
| * Adds an element to the bootclasspath that will be used to compile the | |||
| * classes against. | |||
| */ | |||
| public void addBootclasspath( final Path bootclasspath ) | |||
| { | |||
| m_bootclasspath.add( bootclasspath ); | |||
| } | |||
| /** | |||
| * Adds an element to the classpath to be used for this compilation. | |||
| */ | |||
| public void addClasspath( Path classpath ) | |||
| { | |||
| if( m_compileClasspath == null ) | |||
| { | |||
| m_compileClasspath = classpath; | |||
| } | |||
| else | |||
| { | |||
| m_compileClasspath.add( classpath ); | |||
| } | |||
| } | |||
| /** | |||
| * Set the debug flag. | |||
| */ | |||
| public void setDebug( final boolean debug ) | |||
| { | |||
| m_debug = debug; | |||
| } | |||
| /** | |||
| * Set the value of debugLevel. | |||
| * | |||
| * @param v Value to assign to debugLevel. | |||
| */ | |||
| public void setDebugLevel( String v ) | |||
| { | |||
| m_debugLevel = v; | |||
| } | |||
| /** | |||
| * Set the depend flag. | |||
| * | |||
| * @param depend The new Depend value | |||
| */ | |||
| public void setDepend( boolean depend ) | |||
| { | |||
| m_depend = depend; | |||
| } | |||
| /** | |||
| * Set the deprecation flag. | |||
| * | |||
| * @param deprecation The new Deprecation value | |||
| */ | |||
| public void setDeprecation( boolean deprecation ) | |||
| { | |||
| m_deprecation = deprecation; | |||
| } | |||
| /** | |||
| * Set the destination directory into which the Java source files should be | |||
| * compiled. | |||
| * | |||
| * @param destDir The new Destdir value | |||
| */ | |||
| public void setDestdir( File destDir ) | |||
| { | |||
| m_destDir = destDir; | |||
| } | |||
| /** | |||
| * Set the Java source file encoding name. | |||
| * | |||
| * @param encoding The new Encoding value | |||
| */ | |||
| public void setEncoding( String encoding ) | |||
| { | |||
| m_encoding = encoding; | |||
| } | |||
| /** | |||
| * Adds an element to the extension directories that will be used during | |||
| * the compilation. | |||
| * | |||
| * @param extdirs The new Extdirs value | |||
| */ | |||
| public void addExtdirs( Path extdirs ) | |||
| throws TaskException | |||
| { | |||
| if( m_extdirs == null ) | |||
| { | |||
| m_extdirs = extdirs; | |||
| } | |||
| else | |||
| { | |||
| m_extdirs.add( extdirs ); | |||
| } | |||
| } | |||
| /** | |||
| * Sets whether to fork the javac compiler. | |||
| */ | |||
| public void setFork( final boolean fork ) | |||
| { | |||
| m_fork = fork; | |||
| if( fork ) | |||
| { | |||
| m_forkedExecutable = getSystemJavac(); | |||
| } | |||
| } | |||
| /** | |||
| * Include ant's own classpath in this task's classpath? | |||
| * | |||
| * @param include The new Includeantruntime value | |||
| */ | |||
| public void setIncludeantruntime( boolean include ) | |||
| { | |||
| m_includeAntRuntime = include; | |||
| } | |||
| /** | |||
| * Sets whether or not to include the java runtime libraries to this task's | |||
| * classpath. | |||
| * | |||
| * @param include The new Includejavaruntime value | |||
| */ | |||
| public void setIncludejavaruntime( boolean include ) | |||
| { | |||
| m_includeJavaRuntime = include; | |||
| } | |||
| /** | |||
| * Set the memoryInitialSize flag. | |||
| * | |||
| * @param memoryInitialSize The new MemoryInitialSize value | |||
| */ | |||
| public void setMemoryInitialSize( String memoryInitialSize ) | |||
| { | |||
| m_memoryInitialSize = memoryInitialSize; | |||
| } | |||
| /** | |||
| * Set the memoryMaximumSize flag. | |||
| * | |||
| * @param memoryMaximumSize The new MemoryMaximumSize value | |||
| */ | |||
| public void setMemoryMaximumSize( String memoryMaximumSize ) | |||
| { | |||
| m_memoryMaximumSize = memoryMaximumSize; | |||
| } | |||
| /** | |||
| * Sets whether the -nowarn option should be used. | |||
| * | |||
| * @param flag The new Nowarn value | |||
| */ | |||
| public void setNowarn( boolean flag ) | |||
| { | |||
| m_nowarn = flag; | |||
| } | |||
| /** | |||
| * Set the optimize flag. | |||
| * | |||
| * @param optimize The new Optimize value | |||
| */ | |||
| public void setOptimize( boolean optimize ) | |||
| { | |||
| m_optimize = optimize; | |||
| } | |||
| /** | |||
| * Set the value of source. | |||
| * | |||
| * @param v Value to assign to source. | |||
| */ | |||
| public void setSource( String v ) | |||
| { | |||
| m_source = v; | |||
| } | |||
| /** | |||
| * Adds an element to the source dirs to find the source Java files. | |||
| * | |||
| * @param srcDir The new Srcdir value | |||
| */ | |||
| public void addSrcdir( Path srcDir ) | |||
| throws TaskException | |||
| { | |||
| if( m_src == null ) | |||
| { | |||
| m_src = srcDir; | |||
| } | |||
| else | |||
| { | |||
| m_src.add( srcDir ); | |||
| } | |||
| } | |||
| /** | |||
| * Sets the target VM that the classes will be compiled for. Valid strings | |||
| * are "1.1", "1.2", and "1.3". | |||
| * | |||
| * @param target The new Target value | |||
| */ | |||
| public void setTarget( String target ) | |||
| { | |||
| m_target = target; | |||
| } | |||
| /** | |||
| * Set the verbose flag. | |||
| * | |||
| * @param verbose The new Verbose value | |||
| */ | |||
| public void setVerbose( boolean verbose ) | |||
| { | |||
| m_verbose = verbose; | |||
| } | |||
| /** | |||
| * Gets the bootclasspath that will be used to compile the classes against. | |||
| * | |||
| * @return The Bootclasspath value | |||
| */ | |||
| public Path getBootclasspath() | |||
| { | |||
| return m_bootclasspath; | |||
| } | |||
| /** | |||
| * Gets the classpath to be used for this compilation. | |||
| * | |||
| * @return The Classpath value | |||
| */ | |||
| public Path getClasspath() | |||
| { | |||
| return m_compileClasspath; | |||
| } | |||
| protected File getBaseDir() | |||
| { | |||
| return getBaseDirectory(); | |||
| } | |||
| /** | |||
| * Get the additional implementation specific command line arguments. | |||
| * | |||
| * @return array of command line arguments, guaranteed to be non-null. | |||
| */ | |||
| public String[] getCurrentCompilerArgs() | |||
| { | |||
| ArrayList args = new ArrayList(); | |||
| for( Iterator enum = m_implementationSpecificArgs.iterator(); | |||
| enum.hasNext(); | |||
| ) | |||
| { | |||
| String[] curr = | |||
| ( (ImplementationSpecificArgument)enum.next() ).getParts(); | |||
| for( int i = 0; i < curr.length; i++ ) | |||
| { | |||
| args.add( curr[ i ] ); | |||
| } | |||
| } | |||
| final String[] res = new String[ args.size() ]; | |||
| return (String[])args.toArray( res ); | |||
| } | |||
| /** | |||
| * Gets the debug flag. | |||
| * | |||
| * @return The Debug value | |||
| */ | |||
| public boolean getDebug() | |||
| { | |||
| return m_debug; | |||
| } | |||
| /** | |||
| * Get the value of debugLevel. | |||
| * | |||
| * @return value of debugLevel. | |||
| */ | |||
| public String getDebugLevel() | |||
| { | |||
| return m_debugLevel; | |||
| } | |||
| /** | |||
| * Gets the depend flag. | |||
| * | |||
| * @return The Depend value | |||
| */ | |||
| public boolean getDepend() | |||
| { | |||
| return m_depend; | |||
| } | |||
| /** | |||
| * Gets the deprecation flag. | |||
| * | |||
| * @return The Deprecation value | |||
| */ | |||
| public boolean getDeprecation() | |||
| { | |||
| return m_deprecation; | |||
| } | |||
| /** | |||
| * Gets the destination directory into which the java source files should be | |||
| * compiled. | |||
| * | |||
| * @return The Destdir value | |||
| */ | |||
| public File getDestdir() | |||
| { | |||
| return m_destDir; | |||
| } | |||
| /** | |||
| * Gets the java source file encoding name. | |||
| * | |||
| * @return The Encoding value | |||
| */ | |||
| public String getEncoding() | |||
| { | |||
| return m_encoding; | |||
| } | |||
| /** | |||
| * Gets the extension directories that will be used during the compilation. | |||
| * | |||
| * @return The Extdirs value | |||
| */ | |||
| public Path getExtdirs() | |||
| { | |||
| return m_extdirs; | |||
| } | |||
| /** | |||
| * Gets the list of files to be compiled. | |||
| * | |||
| * @return The FileList value | |||
| */ | |||
| public File[] getFileList() | |||
| { | |||
| return m_compileList; | |||
| } | |||
| /** | |||
| * Gets whether or not the ant classpath is to be included in the task's | |||
| * classpath. | |||
| * | |||
| * @return The Includeantruntime value | |||
| */ | |||
| public boolean getIncludeantruntime() | |||
| { | |||
| return m_includeAntRuntime; | |||
| } | |||
| /** | |||
| * Gets whether or not the java runtime should be included in this task's | |||
| * classpath. | |||
| * | |||
| * @return The Includejavaruntime value | |||
| */ | |||
| public boolean getIncludejavaruntime() | |||
| { | |||
| return m_includeJavaRuntime; | |||
| } | |||
| /** | |||
| * The name of the javac executable to use in fork-mode. | |||
| * | |||
| * @return The JavacExecutable value | |||
| */ | |||
| public String getJavacExecutable() | |||
| { | |||
| if( m_forkedExecutable == null && isForkedJavac() ) | |||
| { | |||
| m_forkedExecutable = getSystemJavac(); | |||
| } | |||
| else if( m_forkedExecutable != null && !isForkedJavac() ) | |||
| { | |||
| m_forkedExecutable = null; | |||
| } | |||
| return m_forkedExecutable; | |||
| } | |||
| /** | |||
| * Gets the memoryInitialSize flag. | |||
| * | |||
| * @return The MemoryInitialSize value | |||
| */ | |||
| public String getMemoryInitialSize() | |||
| { | |||
| return m_memoryInitialSize; | |||
| } | |||
| /** | |||
| * Gets the memoryMaximumSize flag. | |||
| * | |||
| * @return The MemoryMaximumSize value | |||
| */ | |||
| public String getMemoryMaximumSize() | |||
| { | |||
| return m_memoryMaximumSize; | |||
| } | |||
| /** | |||
| * Should the -nowarn option be used. | |||
| * | |||
| * @return The Nowarn value | |||
| */ | |||
| public boolean getNowarn() | |||
| { | |||
| return m_nowarn; | |||
| } | |||
| /** | |||
| * Gets the optimize flag. | |||
| * | |||
| * @return The Optimize value | |||
| */ | |||
| public boolean isOptimize() | |||
| { | |||
| return m_optimize; | |||
| } | |||
| /** | |||
| * Get the value of source. | |||
| * | |||
| * @return value of source. | |||
| */ | |||
| public String getSource() | |||
| { | |||
| return m_source; | |||
| } | |||
| /** | |||
| * Gets the source dirs to find the source java files. | |||
| * | |||
| * @return The Srcdir value | |||
| */ | |||
| public Path getSrcdir() | |||
| { | |||
| return m_src; | |||
| } | |||
| /** | |||
| * Gets the target VM that the classes will be compiled for. | |||
| * | |||
| * @return The Target value | |||
| */ | |||
| public String getTarget() | |||
| { | |||
| return m_target; | |||
| } | |||
| /** | |||
| * Gets the verbose flag. | |||
| * | |||
| * @return The Verbose value | |||
| */ | |||
| public boolean getVerbose() | |||
| { | |||
| return m_verbose; | |||
| } | |||
| /** | |||
| * Is this a forked invocation of JDK's javac? | |||
| * | |||
| * @return The ForkedJavac value | |||
| */ | |||
| public boolean isForkedJavac() | |||
| { | |||
| return m_fork; | |||
| } | |||
| /** | |||
| * Adds an implementation specific command line argument. | |||
| */ | |||
| public ImplementationSpecificArgument createCompilerArg() | |||
| { | |||
| final ImplementationSpecificArgument arg = new ImplementationSpecificArgument( this ); | |||
| m_implementationSpecificArgs.add( arg ); | |||
| return arg; | |||
| } | |||
| /** | |||
| * Executes the task. | |||
| * | |||
| * @exception org.apache.myrmidon.api.TaskException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| // first off, make sure that we've got a srcdir | |||
| if( m_src == null ) | |||
| { | |||
| throw new TaskException( "srcdir attribute must be set!" ); | |||
| } | |||
| String[] list = m_src.listFiles( getContext() ); | |||
| if( list.length == 0 ) | |||
| { | |||
| throw new TaskException( "srcdir attribute must be set!" ); | |||
| } | |||
| if( m_destDir != null && !m_destDir.isDirectory() ) | |||
| { | |||
| throw new TaskException( "destination directory \"" + m_destDir + "\" does not exist or is not a directory" ); | |||
| } | |||
| // scan source directories and dest directory to build up | |||
| // compile lists | |||
| resetFileLists(); | |||
| for( int i = 0; i < list.length; i++ ) | |||
| { | |||
| final String filename = list[ i ]; | |||
| File srcDir = (File)getContext().resolveFile( filename ); | |||
| if( !srcDir.exists() ) | |||
| { | |||
| throw new TaskException( "srcdir \"" + srcDir.getPath() + "\" does not exist!" ); | |||
| } | |||
| DirectoryScanner ds = getDirectoryScanner( srcDir ); | |||
| String[] files = ds.getIncludedFiles(); | |||
| scanDir( srcDir, m_destDir != null ? m_destDir : srcDir, files ); | |||
| } | |||
| // compile the source files | |||
| String compiler = determineCompiler(); | |||
| if( m_compileList.length > 0 ) | |||
| { | |||
| CompilerAdapter adapter = | |||
| CompilerAdapterFactory.getCompiler( compiler, getContext() ); | |||
| final String message = "Compiling " + m_compileList.length + " source file" + | |||
| ( m_compileList.length == 1 ? "" : "s" ) + | |||
| ( m_destDir != null ? " to " + m_destDir : "" ); | |||
| getContext().info( message ); | |||
| // now we need to populate the compiler adapter | |||
| adapter.setJavac( this ); | |||
| // finally, lets execute the compiler!! | |||
| if( !adapter.execute() ) | |||
| { | |||
| throw new TaskException( FAIL_MSG ); | |||
| } | |||
| } | |||
| } | |||
| protected String getSystemJavac() | |||
| { | |||
| // This is the most common extension case - exe for windows and OS/2, | |||
| // nothing for *nix. | |||
| String extension = Os.isFamily( Os.OS_FAMILY_DOS ) ? ".exe" : ""; | |||
| // Look for java in the java.home/../bin directory. Unfortunately | |||
| // on Windows java.home doesn't always refer to the correct location, | |||
| // so we need to fall back to assuming java is somewhere on the | |||
| // PATH. | |||
| File jExecutable = | |||
| new File( System.getProperty( "java.home" ) + | |||
| "/../bin/javac" + extension ); | |||
| if( jExecutable.exists() && !Os.isFamily( Os.OS_FAMILY_NETWARE ) ) | |||
| { | |||
| return jExecutable.getAbsolutePath(); | |||
| } | |||
| else | |||
| { | |||
| return "javac"; | |||
| } | |||
| } | |||
| protected boolean isJdkCompiler( String compiler ) | |||
| { | |||
| return "modern".equals( compiler ) || | |||
| "classic".equals( compiler ) || | |||
| "javac1.1".equals( compiler ) || | |||
| "javac1.2".equals( compiler ) || | |||
| "javac1.3".equals( compiler ) || | |||
| "javac1.4".equals( compiler ); | |||
| } | |||
| /** | |||
| * Clear the list of files to be compiled and copied.. | |||
| */ | |||
| protected void resetFileLists() | |||
| { | |||
| m_compileList = new File[ 0 ]; | |||
| } | |||
| /** | |||
| * Scans the directory looking for source files to be compiled. The results | |||
| * are returned in the class variable compileList | |||
| * | |||
| * @param srcDir Description of Parameter | |||
| * @param destDir Description of Parameter | |||
| * @param files Description of Parameter | |||
| */ | |||
| protected void scanDir( File srcDir, File destDir, String files[] ) | |||
| throws TaskException | |||
| { | |||
| GlobPatternMapper m = new GlobPatternMapper(); | |||
| m.setFrom( "*.java" ); | |||
| m.setTo( "*.class" ); | |||
| SourceFileScanner sfs = new SourceFileScanner(); | |||
| File[] newFiles = sfs.restrictAsFiles( files, srcDir, destDir, m, getContext() ); | |||
| if( newFiles.length > 0 ) | |||
| { | |||
| File[] newCompileList = new File[ m_compileList.length + | |||
| newFiles.length ]; | |||
| System.arraycopy( m_compileList, 0, newCompileList, 0, | |||
| m_compileList.length ); | |||
| System.arraycopy( newFiles, 0, newCompileList, | |||
| m_compileList.length, newFiles.length ); | |||
| m_compileList = newCompileList; | |||
| } | |||
| } | |||
| protected String determineCompiler() | |||
| { | |||
| Object compiler = getContext().getProperty( "build.compiler" ); | |||
| if( compiler != null ) | |||
| { | |||
| if( isJdkCompiler( compiler.toString() ) ) | |||
| { | |||
| final String message = "Since fork is true, ignoring build.compiler setting."; | |||
| getContext().warn( message ); | |||
| compiler = "extJavac"; | |||
| } | |||
| else | |||
| { | |||
| getContext().warn( "Since build.compiler setting isn't classic or modern, ignoring fork setting." ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| compiler = "extJavac"; | |||
| } | |||
| if( compiler == null ) | |||
| { | |||
| if( JavaVersion.JAVA1_2 != JavaVersion.getCurrentJavaVersion() ) | |||
| { | |||
| compiler = "modern"; | |||
| } | |||
| else | |||
| { | |||
| compiler = "classic"; | |||
| } | |||
| } | |||
| return compiler.toString(); | |||
| } | |||
| } | |||
| @@ -1,69 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.javac; | |||
| import java.io.OutputStream; | |||
| import java.lang.reflect.Constructor; | |||
| import java.lang.reflect.Method; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.api.TaskContext; | |||
| import org.apache.myrmidon.framework.nativelib.Commandline; | |||
| import org.apache.myrmidon.framework.nativelib.ArgumentList; | |||
| import org.apache.tools.todo.taskdefs.javac.DefaultCompilerAdapter; | |||
| /** | |||
| * The implementation of the javac compiler for JDK 1.2 This is primarily a | |||
| * cut-and-paste from the original javac task before it was refactored. | |||
| * | |||
| * @author James Davidson <a href="mailto:duncan@x180.com">duncan@x180.com</a> | |||
| * @author Robin Green <a href="mailto:greenrd@hotmail.com">greenrd@hotmail.com | |||
| * </a> | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:jayglanville@home.com">J D Glanville</a> | |||
| */ | |||
| public class Javac12 extends DefaultCompilerAdapter | |||
| { | |||
| public boolean execute() | |||
| throws TaskException | |||
| { | |||
| getTaskContext().debug( "Using classic compiler" ); | |||
| ArgumentList cmd = setupJavacCommand( true ); | |||
| try | |||
| { | |||
| // Create an instance of the compiler, redirecting output to | |||
| // the project log | |||
| Class c = Class.forName( "sun.tools.javac.Main" ); | |||
| Constructor cons = c.getConstructor( new Class[]{OutputStream.class, String.class} ); | |||
| Object compiler = cons.newInstance( new Object[]{System.out, "javac"} ); | |||
| // Call the compile() method | |||
| Method compile = c.getMethod( "compile", new Class[]{String[].class} ); | |||
| Boolean ok = (Boolean)compile.invoke( compiler, new Object[]{cmd.getArguments()} ); | |||
| return ok.booleanValue(); | |||
| } | |||
| catch( ClassNotFoundException ex ) | |||
| { | |||
| throw new TaskException( "Cannot use classic compiler, as it is not available" + | |||
| " A common solution is to set the environment variable" + | |||
| " JAVA_HOME to your jdk directory." ); | |||
| } | |||
| catch( Exception ex ) | |||
| { | |||
| if( ex instanceof TaskException ) | |||
| { | |||
| throw (TaskException)ex; | |||
| } | |||
| else | |||
| { | |||
| throw new TaskException( "Error starting classic compiler: ", ex ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -1,64 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.javac; | |||
| import java.lang.reflect.Method; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.api.TaskContext; | |||
| import org.apache.myrmidon.framework.nativelib.Commandline; | |||
| import org.apache.myrmidon.framework.nativelib.ArgumentList; | |||
| import org.apache.tools.todo.taskdefs.javac.DefaultCompilerAdapter; | |||
| /** | |||
| * The implementation of the javac compiler for JDK 1.3 This is primarily a | |||
| * cut-and-paste from the original javac task before it was refactored. | |||
| * | |||
| * @author James Davidson <a href="mailto:duncan@x180.com">duncan@x180.com</a> | |||
| * @author Robin Green <a href="mailto:greenrd@hotmail.com">greenrd@hotmail.com | |||
| * </a> | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:jayglanville@home.com">J D Glanville</a> | |||
| */ | |||
| public class Javac13 extends DefaultCompilerAdapter | |||
| { | |||
| /** | |||
| * Integer returned by the "Modern" jdk1.3 compiler to indicate success. | |||
| */ | |||
| private final static int MODERN_COMPILER_SUCCESS = 0; | |||
| public boolean execute() | |||
| throws TaskException | |||
| { | |||
| getTaskContext().debug( "Using modern compiler" ); | |||
| ArgumentList cmd = setupModernJavacCommand(); | |||
| // Use reflection to be able to build on all JDKs >= 1.1: | |||
| try | |||
| { | |||
| Class c = Class.forName( "com.sun.tools.javac.Main" ); | |||
| Object compiler = c.newInstance(); | |||
| Method compile = c.getMethod( "compile", | |||
| new Class[]{( new String[]{} ).getClass()} ); | |||
| int result = ( (Integer)compile.invoke | |||
| ( compiler, new Object[]{cmd.getArguments()} ) ).intValue(); | |||
| return ( result == MODERN_COMPILER_SUCCESS ); | |||
| } | |||
| catch( Exception ex ) | |||
| { | |||
| if( ex instanceof TaskException ) | |||
| { | |||
| throw (TaskException)ex; | |||
| } | |||
| else | |||
| { | |||
| throw new TaskException( "Error starting modern compiler", ex ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -1,42 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.javac; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.api.TaskContext; | |||
| import org.apache.myrmidon.framework.nativelib.Commandline; | |||
| import org.apache.tools.todo.taskdefs.javac.DefaultCompilerAdapter; | |||
| /** | |||
| * Performs a compile using javac externally. | |||
| * | |||
| * @author Brian Deitte | |||
| */ | |||
| public class JavacExternal extends DefaultCompilerAdapter | |||
| { | |||
| /** | |||
| * Performs a compile using the Javac externally. | |||
| * | |||
| * @return Description of the Returned Value | |||
| * @exception org.apache.myrmidon.api.TaskException Description of Exception | |||
| */ | |||
| public boolean execute() | |||
| throws TaskException | |||
| { | |||
| getTaskContext().debug( "Using external javac compiler" ); | |||
| Commandline cmd = new Commandline(); | |||
| cmd.setExecutable( getJavac().getJavacExecutable() ); | |||
| setupModernJavacCommandlineSwitches( cmd ); | |||
| return executeExternalCompile( cmd ); | |||
| } | |||
| } | |||
| @@ -1,134 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.javac; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.nativelib.Commandline; | |||
| import org.apache.myrmidon.framework.file.Path; | |||
| import org.apache.myrmidon.framework.file.FileListUtil; | |||
| /** | |||
| * The implementation of the jikes compiler. This is primarily a cut-and-paste | |||
| * from the original javac task before it was refactored. | |||
| * | |||
| * @author James Davidson <a href="mailto:duncan@x180.com">duncan@x180.com</a> | |||
| * @author Robin Green <a href="mailto:greenrd@hotmail.com">greenrd@hotmail.com | |||
| * </a> | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:jayglanville@home.com">J D Glanville</a> | |||
| * @author skanthak@muehlheim.de | |||
| */ | |||
| public class Jikes | |||
| extends DefaultCompilerAdapter | |||
| { | |||
| /** | |||
| * Performs a compile using the Jikes compiler from IBM.. Mostly of this | |||
| * code is identical to doClassicCompile() However, it does not support all | |||
| * options like bootclasspath, extdirs, deprecation and so on, because there | |||
| * is no option in jikes and I don't understand what they should do. It has | |||
| * been successfully tested with jikes >1.10 | |||
| * | |||
| * @return Description of the Returned Value | |||
| * @exception org.apache.myrmidon.api.TaskException Description of Exception | |||
| */ | |||
| public boolean execute() | |||
| throws TaskException | |||
| { | |||
| getTaskContext().debug( "Using jikes compiler" ); | |||
| Path classpath = new Path(); | |||
| // Jikes doesn't support bootclasspath dir (-bootclasspath) | |||
| // so we'll emulate it for compatibility and convenience. | |||
| final String[] bootclasspath = m_bootclasspath.listFiles( getTaskContext() ); | |||
| classpath.add( bootclasspath ); | |||
| // Jikes doesn't support an extension dir (-extdir) | |||
| // so we'll emulate it for compatibility and convenience. | |||
| addExtdirs( classpath ); | |||
| if( bootclasspath.length == 0 ) | |||
| { | |||
| // no bootclasspath, therefore, get one from the java runtime | |||
| m_includeJavaRuntime = true; | |||
| } | |||
| // Else, there is a bootclasspath stated. By default, the | |||
| // includeJavaRuntime is false. If the user has stated a | |||
| // bootclasspath and said to include the java runtime, it's on | |||
| // their head! | |||
| addCompileClasspath( classpath ); | |||
| // Jikes has no option for source-path so we | |||
| // will add it to classpath. | |||
| classpath.add( src ); | |||
| // if the user has set JIKESPATH we should add the contents as well | |||
| String jikesPath = System.getProperty( "jikes.class.path" ); | |||
| if( jikesPath != null ) | |||
| { | |||
| classpath.add( jikesPath ); | |||
| } | |||
| Commandline cmd = new Commandline(); | |||
| cmd.setExecutable( "jikes" ); | |||
| if( m_deprecation == true ) | |||
| { | |||
| cmd.addArgument( "-deprecation" ); | |||
| } | |||
| if( m_destDir != null ) | |||
| { | |||
| cmd.addArgument( "-d" ); | |||
| cmd.addArgument( m_destDir ); | |||
| } | |||
| cmd.addArgument( "-classpath" ); | |||
| cmd.addArgument( FileListUtil.formatPath( classpath, getTaskContext() ) ); | |||
| if( m_encoding != null ) | |||
| { | |||
| cmd.addArgument( "-encoding" ); | |||
| cmd.addArgument( m_encoding ); | |||
| } | |||
| if( m_debug ) | |||
| { | |||
| cmd.addArgument( "-g" ); | |||
| } | |||
| if( m_optimize ) | |||
| { | |||
| cmd.addArgument( "-O" ); | |||
| } | |||
| if( m_verbose ) | |||
| { | |||
| cmd.addArgument( "-verbose" ); | |||
| } | |||
| if( m_depend ) | |||
| { | |||
| cmd.addArgument( "-depend" ); | |||
| } | |||
| if( m_attributes.getNowarn() ) | |||
| { | |||
| /* | |||
| * FIXME later | |||
| * | |||
| * let the magic property win over the attribute for backwards | |||
| * compatibility | |||
| */ | |||
| cmd.addArgument( "-nowarn" ); | |||
| } | |||
| addCurrentCompilerArgs( cmd ); | |||
| return executeExternalCompile( cmd ); | |||
| } | |||
| } | |||
| @@ -1,97 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.javac; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.nativelib.Commandline; | |||
| import org.apache.myrmidon.framework.file.Path; | |||
| import org.apache.myrmidon.framework.file.FileListUtil; | |||
| /** | |||
| * The implementation of the jvc compiler from microsoft. This is primarily a | |||
| * cut-and-paste from the original javac task before it was refactored. | |||
| * | |||
| * @author James Davidson <a href="mailto:duncan@x180.com">duncan@x180.com</a> | |||
| * @author Robin Green <a href="mailto:greenrd@hotmail.com">greenrd@hotmail.com | |||
| * </a> | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:jayglanville@home.com">J D Glanville</a> | |||
| */ | |||
| public class Jvc extends DefaultCompilerAdapter | |||
| { | |||
| public boolean execute() | |||
| throws TaskException | |||
| { | |||
| getTaskContext().debug( "Using jvc compiler" ); | |||
| Path classpath = new Path(); | |||
| // jvc doesn't support bootclasspath dir (-bootclasspath) | |||
| // so we'll emulate it for compatibility and convenience. | |||
| final String[] bootclasspath = m_bootclasspath.listFiles( getTaskContext() ); | |||
| classpath.add( bootclasspath ); | |||
| // jvc doesn't support an extension dir (-extdir) | |||
| // so we'll emulate it for compatibility and convenience. | |||
| addExtdirs( classpath ); | |||
| if( bootclasspath.length == 0 ) | |||
| { | |||
| // no bootclasspath, therefore, get one from the java runtime | |||
| m_includeJavaRuntime = true; | |||
| } | |||
| // Else, there is a bootclasspath stated. By default, the | |||
| // includeJavaRuntime is false. If the user has stated a | |||
| // bootclasspath and said to include the java runtime, it's on | |||
| // their head! | |||
| addCompileClasspath( classpath ); | |||
| // jvc has no option for source-path so we | |||
| // will add it to classpath. | |||
| classpath.add( src ); | |||
| Commandline cmd = new Commandline(); | |||
| cmd.setExecutable( "jvc" ); | |||
| if( m_destDir != null ) | |||
| { | |||
| cmd.addArgument( "/d" ); | |||
| cmd.addArgument( m_destDir ); | |||
| } | |||
| // Add the Classpath before the "internal" one. | |||
| cmd.addArgument( "/cp:p" ); | |||
| cmd.addArgument( FileListUtil.formatPath( classpath, getTaskContext() ) ); | |||
| // Enable MS-Extensions and ... | |||
| cmd.addArgument( "/x-" ); | |||
| // ... do not display a Message about this. | |||
| cmd.addArgument( "/nomessage" ); | |||
| // Do not display Logo | |||
| cmd.addArgument( "/nologo" ); | |||
| if( m_debug ) | |||
| { | |||
| cmd.addArgument( "/g" ); | |||
| } | |||
| if( m_optimize ) | |||
| { | |||
| cmd.addArgument( "/O" ); | |||
| } | |||
| if( m_verbose ) | |||
| { | |||
| cmd.addArgument( "/verbose" ); | |||
| } | |||
| addCurrentCompilerArgs( cmd ); | |||
| return executeExternalCompile( cmd ); | |||
| } | |||
| } | |||
| @@ -1,135 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.javac; | |||
| import java.lang.reflect.Method; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.nativelib.Commandline; | |||
| import org.apache.myrmidon.framework.nativelib.ArgumentList; | |||
| import org.apache.myrmidon.framework.file.Path; | |||
| import org.apache.myrmidon.framework.file.FileListUtil; | |||
| /** | |||
| * The implementation of the Java compiler for KJC. This is primarily a | |||
| * cut-and-paste from Jikes.java and DefaultCompilerAdapter. | |||
| * | |||
| * @author <a href="mailto:tora@debian.org">Takashi Okamoto</a> + | |||
| */ | |||
| public class Kjc extends DefaultCompilerAdapter | |||
| { | |||
| public boolean execute() | |||
| throws TaskException | |||
| { | |||
| getTaskContext().debug( "Using kjc compiler" ); | |||
| ArgumentList cmd = setupKjcCommand(); | |||
| try | |||
| { | |||
| Class c = Class.forName( "at.dms.kjc.Main" ); | |||
| // Call the compile() method | |||
| Method compile = c.getMethod( "compile", | |||
| new Class[]{String[].class} ); | |||
| Boolean ok = (Boolean)compile.invoke( null, | |||
| new Object[]{cmd.getArguments()} ); | |||
| return ok.booleanValue(); | |||
| } | |||
| catch( ClassNotFoundException ex ) | |||
| { | |||
| throw new TaskException( "Cannot use kjc compiler, as it is not available" + | |||
| " A common solution is to set the environment variable" + | |||
| " CLASSPATH to your kjc archive (kjc.jar)." ); | |||
| } | |||
| catch( Exception ex ) | |||
| { | |||
| if( ex instanceof TaskException ) | |||
| { | |||
| throw (TaskException)ex; | |||
| } | |||
| else | |||
| { | |||
| throw new TaskException( "Error starting kjc compiler: ", ex ); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * setup kjc command arguments. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| protected ArgumentList setupKjcCommand() | |||
| throws TaskException | |||
| { | |||
| ArgumentList cmd = new Commandline(); | |||
| // generate classpath, because kjc does't support sourcepath. | |||
| Path classpath = new Path(); | |||
| addCompileClasspath( classpath ); | |||
| if( m_deprecation == true ) | |||
| { | |||
| cmd.addArgument( "-deprecation" ); | |||
| } | |||
| if( m_destDir != null ) | |||
| { | |||
| cmd.addArgument( "-d" ); | |||
| cmd.addArgument( m_destDir ); | |||
| } | |||
| // generate the clsspath | |||
| cmd.addArgument( "-classpath" ); | |||
| Path cp = new Path(); | |||
| // kjc don't have bootclasspath option. | |||
| cp.add( m_bootclasspath ); | |||
| if( m_extdirs != null ) | |||
| { | |||
| addExtdirs( cp ); | |||
| } | |||
| cp.add( classpath ); | |||
| cp.add( src ); | |||
| cmd.addArgument( FileListUtil.formatPath( cp, getTaskContext() ) ); | |||
| // kjc-1.5A doesn't support -encoding option now. | |||
| // but it will be supported near the feature. | |||
| if( m_encoding != null ) | |||
| { | |||
| cmd.addArgument( "-encoding" ); | |||
| cmd.addArgument( m_encoding ); | |||
| } | |||
| if( m_debug ) | |||
| { | |||
| cmd.addArgument( "-g" ); | |||
| } | |||
| if( m_optimize ) | |||
| { | |||
| cmd.addArgument( "-O2" ); | |||
| } | |||
| if( m_verbose ) | |||
| { | |||
| cmd.addArgument( "-verbose" ); | |||
| } | |||
| addCurrentCompilerArgs( cmd ); | |||
| logFilesToCompile( cmd ); | |||
| addFilesToCompile( cmd ); | |||
| return cmd; | |||
| } | |||
| } | |||
| @@ -1,44 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.javac; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.api.TaskContext; | |||
| import org.apache.myrmidon.framework.nativelib.Commandline; | |||
| import org.apache.tools.todo.taskdefs.javac.DefaultCompilerAdapter; | |||
| /** | |||
| * The implementation of the sj compiler. Uses the defaults for | |||
| * DefaultCompilerAdapter | |||
| * | |||
| * @author <a href="mailto:don@bea.com">Don Ferguson</a> | |||
| */ | |||
| public class Sj extends DefaultCompilerAdapter | |||
| { | |||
| /** | |||
| * Performs a compile using the sj compiler from Symantec. | |||
| * | |||
| * @return Description of the Returned Value | |||
| * @exception org.apache.myrmidon.api.TaskException Description of Exception | |||
| * @author don@bea.com | |||
| */ | |||
| public boolean execute() | |||
| throws TaskException | |||
| { | |||
| getTaskContext().debug( "Using symantec java compiler" ); | |||
| Commandline cmd = new Commandline(); | |||
| setupJavacCommandlineSwitches( cmd, false ); | |||
| cmd.setExecutable( "sj" ); | |||
| return executeExternalCompile( cmd ); | |||
| } | |||
| } | |||
| @@ -1,175 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.javacc; | |||
| import java.io.File; | |||
| import java.util.Enumeration; | |||
| import java.util.Hashtable; | |||
| import org.apache.myrmidon.api.AbstractTask; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.java.ExecuteJava; | |||
| import org.apache.myrmidon.framework.file.Path; | |||
| /** | |||
| * Taskdef for the JJTree compiler compiler. | |||
| * | |||
| * @author thomas.haas@softwired-inc.com | |||
| * @author Michael Saunders <a href="mailto:michael@amtec.com">michael@amtec.com | |||
| * </a> | |||
| */ | |||
| public class JJTree | |||
| extends AbstractTask | |||
| { | |||
| // keys to optional attributes | |||
| private final static String BUILD_NODE_FILES = "BUILD_NODE_FILES"; | |||
| private final static String MULTI = "MULTI"; | |||
| private final static String NODE_DEFAULT_VOID = "NODE_DEFAULT_VOID"; | |||
| private final static String NODE_FACTORY = "NODE_FACTORY"; | |||
| private final static String NODE_SCOPE_HOOK = "NODE_SCOPE_HOOK"; | |||
| private final static String NODE_USES_PARSER = "NODE_USES_PARSER"; | |||
| private final static String STATIC = "STATIC"; | |||
| private final static String VISITOR = "VISITOR"; | |||
| private final static String NODE_PACKAGE = "NODE_PACKAGE"; | |||
| private final static String VISITOR_EXCEPTION = "VISITOR_EXCEPTION"; | |||
| private final static String NODE_PREFIX = "NODE_PREFIX"; | |||
| private final Hashtable optionalAttrs = new Hashtable(); | |||
| // required attributes | |||
| private File outputDirectory = null; | |||
| private File target = null; | |||
| private File javaccHome = null; | |||
| public void setBuildnodefiles( boolean buildNodeFiles ) | |||
| { | |||
| optionalAttrs.put( BUILD_NODE_FILES, new Boolean( buildNodeFiles ) ); | |||
| } | |||
| public void setJavacchome( File javaccHome ) | |||
| { | |||
| this.javaccHome = javaccHome; | |||
| } | |||
| public void setMulti( boolean multi ) | |||
| { | |||
| optionalAttrs.put( MULTI, new Boolean( multi ) ); | |||
| } | |||
| public void setNodedefaultvoid( boolean nodeDefaultVoid ) | |||
| { | |||
| optionalAttrs.put( NODE_DEFAULT_VOID, new Boolean( nodeDefaultVoid ) ); | |||
| } | |||
| public void setNodefactory( boolean nodeFactory ) | |||
| { | |||
| optionalAttrs.put( NODE_FACTORY, new Boolean( nodeFactory ) ); | |||
| } | |||
| public void setNodepackage( String nodePackage ) | |||
| { | |||
| optionalAttrs.put( NODE_PACKAGE, new String( nodePackage ) ); | |||
| } | |||
| public void setNodeprefix( String nodePrefix ) | |||
| { | |||
| optionalAttrs.put( NODE_PREFIX, new String( nodePrefix ) ); | |||
| } | |||
| public void setNodescopehook( boolean nodeScopeHook ) | |||
| { | |||
| optionalAttrs.put( NODE_SCOPE_HOOK, new Boolean( nodeScopeHook ) ); | |||
| } | |||
| public void setNodeusesparser( boolean nodeUsesParser ) | |||
| { | |||
| optionalAttrs.put( NODE_USES_PARSER, new Boolean( nodeUsesParser ) ); | |||
| } | |||
| public void setOutputdirectory( File outputDirectory ) | |||
| { | |||
| this.outputDirectory = outputDirectory; | |||
| } | |||
| public void setStatic( boolean staticParser ) | |||
| { | |||
| optionalAttrs.put( STATIC, new Boolean( staticParser ) ); | |||
| } | |||
| public void setTarget( File target ) | |||
| { | |||
| this.target = target; | |||
| } | |||
| public void setVisitor( boolean visitor ) | |||
| { | |||
| optionalAttrs.put( VISITOR, new Boolean( visitor ) ); | |||
| } | |||
| public void setVisitorException( String visitorException ) | |||
| { | |||
| optionalAttrs.put( VISITOR_EXCEPTION, new String( visitorException ) ); | |||
| } | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| final ExecuteJava exe = new ExecuteJava(); | |||
| exe.setClassName( "COM.sun.labs.jjtree.Main" ); | |||
| // load command line with optional attributes | |||
| Enumeration iter = optionalAttrs.keys(); | |||
| while( iter.hasMoreElements() ) | |||
| { | |||
| String name = (String)iter.nextElement(); | |||
| Object value = optionalAttrs.get( name ); | |||
| exe.getArguments().addArgument( "-" + name + ":" + value.toString() ); | |||
| } | |||
| if( target == null || !target.isFile() ) | |||
| { | |||
| throw new TaskException( "Invalid target: " + target ); | |||
| } | |||
| // use the directory containing the target as the output directory | |||
| if( outputDirectory == null ) | |||
| { | |||
| outputDirectory = target.getParentFile(); | |||
| } | |||
| if( !outputDirectory.isDirectory() ) | |||
| { | |||
| throw new TaskException( "'outputdirectory' " + outputDirectory + " is not a directory." ); | |||
| } | |||
| // convert backslashes to slashes, otherwise jjtree will put this as | |||
| // comments and this seems to confuse javacc | |||
| exe.getArguments().addArgument( "-OUTPUT_DIRECTORY:" + outputDirectory.getAbsolutePath().replace( '\\', '/' ) ); | |||
| String targetName = target.getName(); | |||
| final File javaFile = new File( outputDirectory, | |||
| targetName.substring( 0, targetName.indexOf( ".jjt" ) ) + ".jj" ); | |||
| if( javaFile.exists() && target.lastModified() < javaFile.lastModified() ) | |||
| { | |||
| getContext().verbose( "Target is already built - skipping (" + target + ")" ); | |||
| return; | |||
| } | |||
| exe.getArguments().addArgument( target ); | |||
| if( javaccHome == null || !javaccHome.isDirectory() ) | |||
| { | |||
| throw new TaskException( "Javacchome not set." ); | |||
| } | |||
| final Path classpath = exe.getClassPath(); | |||
| classpath.addLocation( new File( javaccHome, "JavaCC.zip" ) ); | |||
| exe.setMaxMemory( "140M" ); | |||
| exe.getSysProperties().addVariable( "install.root", javaccHome.getAbsolutePath() ); | |||
| exe.executeForked( getContext() ); | |||
| } | |||
| } | |||
| @@ -1,269 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.javacc; | |||
| import java.io.File; | |||
| import java.util.Enumeration; | |||
| import java.util.Hashtable; | |||
| import org.apache.myrmidon.api.AbstractTask; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.java.ExecuteJava; | |||
| import org.apache.myrmidon.framework.file.Path; | |||
| /** | |||
| * Taskdef for the JavaCC compiler compiler. | |||
| * | |||
| * @author thomas.haas@softwired-inc.com | |||
| * @author Michael Saunders <a href="mailto:michael@amtec.com">michael@amtec.com | |||
| * </a> | |||
| */ | |||
| public class JavaCC | |||
| extends AbstractTask | |||
| { | |||
| // keys to optional attributes | |||
| private final static String LOOKAHEAD = "LOOKAHEAD"; | |||
| private final static String CHOICE_AMBIGUITY_CHECK = "CHOICE_AMBIGUITY_CHECK"; | |||
| private final static String OTHER_AMBIGUITY_CHECK = "OTHER_AMBIGUITY_CHECK"; | |||
| private final static String STATIC = "STATIC"; | |||
| private final static String DEBUG_PARSER = "DEBUG_PARSER"; | |||
| private final static String DEBUG_LOOKAHEAD = "DEBUG_LOOKAHEAD"; | |||
| private final static String DEBUG_TOKEN_MANAGER = "DEBUG_TOKEN_MANAGER"; | |||
| private final static String OPTIMIZE_TOKEN_MANAGER = "OPTIMIZE_TOKEN_MANAGER"; | |||
| private final static String ERROR_REPORTING = "ERROR_REPORTING"; | |||
| private final static String JAVA_UNICODE_ESCAPE = "JAVA_UNICODE_ESCAPE"; | |||
| private final static String UNICODE_INPUT = "UNICODE_INPUT"; | |||
| private final static String IGNORE_CASE = "IGNORE_CASE"; | |||
| private final static String COMMON_TOKEN_ACTION = "COMMON_TOKEN_ACTION"; | |||
| private final static String USER_TOKEN_MANAGER = "USER_TOKEN_MANAGER"; | |||
| private final static String USER_CHAR_STREAM = "USER_CHAR_STREAM"; | |||
| private final static String BUILD_PARSER = "BUILD_PARSER"; | |||
| private final static String BUILD_TOKEN_MANAGER = "BUILD_TOKEN_MANAGER"; | |||
| private final static String SANITY_CHECK = "SANITY_CHECK"; | |||
| private final static String FORCE_LA_CHECK = "FORCE_LA_CHECK"; | |||
| private final static String CACHE_TOKENS = "CACHE_TOKENS"; | |||
| private final Hashtable optionalAttrs = new Hashtable(); | |||
| // required attributes | |||
| private File outputDirectory = null; | |||
| private File target = null; | |||
| private File javaccHome = null; | |||
| public void setBuildparser( boolean buildParser ) | |||
| { | |||
| optionalAttrs.put( BUILD_PARSER, new Boolean( buildParser ) ); | |||
| } | |||
| public void setBuildtokenmanager( boolean buildTokenManager ) | |||
| { | |||
| optionalAttrs.put( BUILD_TOKEN_MANAGER, new Boolean( buildTokenManager ) ); | |||
| } | |||
| public void setCachetokens( boolean cacheTokens ) | |||
| { | |||
| optionalAttrs.put( CACHE_TOKENS, new Boolean( cacheTokens ) ); | |||
| } | |||
| public void setChoiceambiguitycheck( int choiceAmbiguityCheck ) | |||
| { | |||
| optionalAttrs.put( CHOICE_AMBIGUITY_CHECK, new Integer( choiceAmbiguityCheck ) ); | |||
| } | |||
| public void setCommontokenaction( boolean commonTokenAction ) | |||
| { | |||
| optionalAttrs.put( COMMON_TOKEN_ACTION, new Boolean( commonTokenAction ) ); | |||
| } | |||
| public void setDebuglookahead( boolean debugLookahead ) | |||
| { | |||
| optionalAttrs.put( DEBUG_LOOKAHEAD, new Boolean( debugLookahead ) ); | |||
| } | |||
| public void setDebugparser( boolean debugParser ) | |||
| { | |||
| optionalAttrs.put( DEBUG_PARSER, new Boolean( debugParser ) ); | |||
| } | |||
| public void setDebugtokenmanager( boolean debugTokenManager ) | |||
| { | |||
| optionalAttrs.put( DEBUG_TOKEN_MANAGER, new Boolean( debugTokenManager ) ); | |||
| } | |||
| public void setErrorreporting( boolean errorReporting ) | |||
| { | |||
| optionalAttrs.put( ERROR_REPORTING, new Boolean( errorReporting ) ); | |||
| } | |||
| public void setForcelacheck( boolean forceLACheck ) | |||
| { | |||
| optionalAttrs.put( FORCE_LA_CHECK, new Boolean( forceLACheck ) ); | |||
| } | |||
| public void setIgnorecase( boolean ignoreCase ) | |||
| { | |||
| optionalAttrs.put( IGNORE_CASE, new Boolean( ignoreCase ) ); | |||
| } | |||
| public void setJavacchome( File javaccHome ) | |||
| { | |||
| this.javaccHome = javaccHome; | |||
| } | |||
| public void setJavaunicodeescape( boolean javaUnicodeEscape ) | |||
| { | |||
| optionalAttrs.put( JAVA_UNICODE_ESCAPE, new Boolean( javaUnicodeEscape ) ); | |||
| } | |||
| public void setLookahead( int lookahead ) | |||
| { | |||
| optionalAttrs.put( LOOKAHEAD, new Integer( lookahead ) ); | |||
| } | |||
| public void setOptimizetokenmanager( boolean optimizeTokenManager ) | |||
| { | |||
| optionalAttrs.put( OPTIMIZE_TOKEN_MANAGER, new Boolean( optimizeTokenManager ) ); | |||
| } | |||
| public void setOtherambiguityCheck( int otherAmbiguityCheck ) | |||
| { | |||
| optionalAttrs.put( OTHER_AMBIGUITY_CHECK, new Integer( otherAmbiguityCheck ) ); | |||
| } | |||
| public void setOutputdirectory( File outputDirectory ) | |||
| { | |||
| this.outputDirectory = outputDirectory; | |||
| } | |||
| public void setSanitycheck( boolean sanityCheck ) | |||
| { | |||
| optionalAttrs.put( SANITY_CHECK, new Boolean( sanityCheck ) ); | |||
| } | |||
| public void setStatic( boolean staticParser ) | |||
| { | |||
| optionalAttrs.put( STATIC, new Boolean( staticParser ) ); | |||
| } | |||
| public void setTarget( File target ) | |||
| { | |||
| this.target = target; | |||
| } | |||
| public void setUnicodeinput( boolean unicodeInput ) | |||
| { | |||
| optionalAttrs.put( UNICODE_INPUT, new Boolean( unicodeInput ) ); | |||
| } | |||
| public void setUsercharstream( boolean userCharStream ) | |||
| { | |||
| optionalAttrs.put( USER_CHAR_STREAM, new Boolean( userCharStream ) ); | |||
| } | |||
| public void setUsertokenmanager( boolean userTokenManager ) | |||
| { | |||
| optionalAttrs.put( USER_TOKEN_MANAGER, new Boolean( userTokenManager ) ); | |||
| } | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| // check the target is a file | |||
| if( target == null || !target.isFile() ) | |||
| { | |||
| throw new TaskException( "Invalid target: " + target ); | |||
| } | |||
| // use the directory containing the target as the output directory | |||
| if( outputDirectory == null ) | |||
| { | |||
| outputDirectory = target.getParentFile(); | |||
| } | |||
| if( !outputDirectory.isDirectory() ) | |||
| { | |||
| throw new TaskException( "Outputdir not a directory." ); | |||
| } | |||
| if( javaccHome == null || !javaccHome.isDirectory() ) | |||
| { | |||
| throw new TaskException( "Javacchome not set." ); | |||
| } | |||
| // determine if the generated java file is up-to-date | |||
| final File javaFile = getOutputJavaFile( outputDirectory, target ); | |||
| if( javaFile.exists() && target.lastModified() < javaFile.lastModified() ) | |||
| { | |||
| getContext().debug( "Target is already built - skipping (" + target + ")" ); | |||
| return; | |||
| } | |||
| ExecuteJava exe = new ExecuteJava(); | |||
| exe.setClassName( "COM.sun.labs.javacc.Main" ); | |||
| // load command line with optional attributes | |||
| Enumeration iter = optionalAttrs.keys(); | |||
| while( iter.hasMoreElements() ) | |||
| { | |||
| String name = (String)iter.nextElement(); | |||
| Object value = optionalAttrs.get( name ); | |||
| exe.getArguments().addArgument( "-" + name + ":" + value.toString() ); | |||
| } | |||
| exe.getArguments().addArgument( "-OUTPUT_DIRECTORY:" + outputDirectory.getAbsolutePath() ); | |||
| exe.getArguments().addArgument( target ); | |||
| final Path classpath = exe.getClassPath(); | |||
| classpath.addLocation( new File( javaccHome, "JavaCC.zip" ) ); | |||
| exe.setMaxMemory( "140M" ); | |||
| exe.getSysProperties().addVariable( "install.root", javaccHome.getAbsolutePath() ); | |||
| exe.executeForked( getContext() ); | |||
| } | |||
| /** | |||
| * Determines the output Java file to be generated by the given grammar | |||
| * file. | |||
| * | |||
| * @param outputdir Description of Parameter | |||
| * @param srcfile Description of Parameter | |||
| * @return The OutputJavaFile value | |||
| */ | |||
| private File getOutputJavaFile( File outputdir, File srcfile ) | |||
| { | |||
| String path = srcfile.getPath(); | |||
| // Extract file's base-name | |||
| int startBasename = path.lastIndexOf( File.separator ); | |||
| if( startBasename != -1 ) | |||
| { | |||
| path = path.substring( startBasename + 1 ); | |||
| } | |||
| // Replace the file's extension with '.java' | |||
| int startExtn = path.lastIndexOf( '.' ); | |||
| if( startExtn != -1 ) | |||
| { | |||
| path = path.substring( 0, startExtn ) + ".java"; | |||
| } | |||
| else | |||
| { | |||
| path += ".java"; | |||
| } | |||
| // Change the directory | |||
| if( outputdir != null ) | |||
| { | |||
| path = outputdir + File.separator + path; | |||
| } | |||
| return new File( path ); | |||
| } | |||
| } | |||
| @@ -1,21 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.javadoc; | |||
| import org.apache.tools.todo.types.EnumeratedAttribute; | |||
| public class AccessType | |||
| extends EnumeratedAttribute | |||
| { | |||
| public String[] getValues() | |||
| { | |||
| // Protected first so if any GUI tool offers a default | |||
| // based on enum #0, it will be right. | |||
| return new String[]{"protected", "public", "package", "private"}; | |||
| } | |||
| } | |||
| @@ -1,73 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.javadoc; | |||
| import java.util.ArrayList; | |||
| import java.util.Iterator; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.file.Path; | |||
| public class DocletInfo | |||
| { | |||
| private ArrayList m_params = new ArrayList(); | |||
| private String m_name; | |||
| private Path m_path; | |||
| public void setName( final String name ) | |||
| { | |||
| m_name = name; | |||
| } | |||
| public void setPath( final Path path ) | |||
| throws TaskException | |||
| { | |||
| if( m_path == null ) | |||
| { | |||
| m_path = path; | |||
| } | |||
| else | |||
| { | |||
| m_path.add( path ); | |||
| } | |||
| } | |||
| public String getName() | |||
| { | |||
| return m_name; | |||
| } | |||
| public Iterator getParams() | |||
| { | |||
| return m_params.iterator(); | |||
| } | |||
| public Path getPath() | |||
| { | |||
| return m_path; | |||
| } | |||
| public DocletParam createParam() | |||
| { | |||
| final DocletParam param = new DocletParam(); | |||
| m_params.add( param ); | |||
| return param; | |||
| } | |||
| public Path createPath() | |||
| throws TaskException | |||
| { | |||
| if( m_path == null ) | |||
| { | |||
| m_path = new Path(); | |||
| } | |||
| Path path1 = m_path; | |||
| final Path path = new Path(); | |||
| path1.add( path ); | |||
| return path; | |||
| } | |||
| } | |||
| @@ -1,34 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.javadoc; | |||
| public class DocletParam | |||
| { | |||
| private String m_name; | |||
| private String m_value; | |||
| public void setName( final String name ) | |||
| { | |||
| this.m_name = name; | |||
| } | |||
| public void setValue( final String value ) | |||
| { | |||
| this.m_value = value; | |||
| } | |||
| public String getName() | |||
| { | |||
| return m_name; | |||
| } | |||
| public String getValue() | |||
| { | |||
| return m_value; | |||
| } | |||
| } | |||
| @@ -1,65 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.javadoc; | |||
| import java.util.ArrayList; | |||
| import java.util.StringTokenizer; | |||
| public class GroupArgument | |||
| { | |||
| private ArrayList m_packages = new ArrayList( 3 ); | |||
| private Html m_title; | |||
| public void setPackages( final String src ) | |||
| { | |||
| final StringTokenizer tok = new StringTokenizer( src, "," ); | |||
| while( tok.hasMoreTokens() ) | |||
| { | |||
| final String p = tok.nextToken(); | |||
| final PackageName pn = new PackageName(); | |||
| pn.setName( p ); | |||
| addPackage( pn ); | |||
| } | |||
| } | |||
| public void setTitle( final String src ) | |||
| { | |||
| final Html h = new Html(); | |||
| h.addContent( src ); | |||
| addTitle( h ); | |||
| } | |||
| public String getPackages() | |||
| { | |||
| final StringBuffer p = new StringBuffer(); | |||
| for( int i = 0; i < m_packages.size(); i++ ) | |||
| { | |||
| if( i > 0 ) | |||
| { | |||
| p.append( ":" ); | |||
| } | |||
| p.append( m_packages.get( i ).toString() ); | |||
| } | |||
| return p.toString(); | |||
| } | |||
| public String getTitle() | |||
| { | |||
| return m_title != null ? m_title.getText() : null; | |||
| } | |||
| public void addPackage( final PackageName pn ) | |||
| { | |||
| m_packages.add( pn ); | |||
| } | |||
| public void addTitle( final Html text ) | |||
| { | |||
| m_title = text; | |||
| } | |||
| } | |||
| @@ -1,23 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.javadoc; | |||
| public class Html | |||
| { | |||
| private StringBuffer m_text = new StringBuffer(); | |||
| public String getText() | |||
| { | |||
| return m_text.toString(); | |||
| } | |||
| public void addContent( final String text ) | |||
| { | |||
| m_text.append( text ); | |||
| } | |||
| } | |||
| @@ -1,47 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.javadoc; | |||
| import java.io.File; | |||
| public class LinkArgument | |||
| { | |||
| private boolean m_offline; | |||
| private String m_href; | |||
| private File m_packagelistLoc; | |||
| public void setHref( String hr ) | |||
| { | |||
| m_href = hr; | |||
| } | |||
| public void setOffline( boolean offline ) | |||
| { | |||
| this.m_offline = offline; | |||
| } | |||
| public void setPackagelistLoc( File src ) | |||
| { | |||
| m_packagelistLoc = src; | |||
| } | |||
| public String getHref() | |||
| { | |||
| return m_href; | |||
| } | |||
| public File getPackagelistLoc() | |||
| { | |||
| return m_packagelistLoc; | |||
| } | |||
| public boolean isLinkOffline() | |||
| { | |||
| return m_offline; | |||
| } | |||
| } | |||
| @@ -1,28 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.javadoc; | |||
| public class PackageName | |||
| { | |||
| private String m_name; | |||
| public void setName( final String name ) | |||
| { | |||
| m_name = name; | |||
| } | |||
| public String getName() | |||
| { | |||
| return m_name; | |||
| } | |||
| public String toString() | |||
| { | |||
| return getName(); | |||
| } | |||
| } | |||
| @@ -1,25 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.javadoc; | |||
| import java.io.File; | |||
| public class SourceFile | |||
| { | |||
| private File m_file; | |||
| public void setFile( File file ) | |||
| { | |||
| this.m_file = file; | |||
| } | |||
| public File getFile() | |||
| { | |||
| return m_file; | |||
| } | |||
| } | |||
| @@ -1,21 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.jdepend; | |||
| import org.apache.tools.todo.types.EnumeratedAttribute; | |||
| public class FormatAttribute | |||
| extends EnumeratedAttribute | |||
| { | |||
| private String[] m_formats = new String[]{"xml", "text"}; | |||
| public String[] getValues() | |||
| { | |||
| return m_formats; | |||
| } | |||
| } | |||
| @@ -1,261 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.jdepend; | |||
| import java.io.File; | |||
| import java.io.FileWriter; | |||
| import java.io.IOException; | |||
| import java.io.PrintWriter; | |||
| import org.apache.myrmidon.api.AbstractTask; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.java.ExecuteJava; | |||
| import org.apache.myrmidon.framework.file.Path; | |||
| /** | |||
| * Ant task to run JDepend tests. <p> | |||
| * | |||
| * JDepend is a tool to generate design quality metrics for each Java package. | |||
| * It has been initially created by Mike Clark. JDepend can be found at <a | |||
| * href="http://www.clarkware.com/software/JDepend.html"> | |||
| * http://www.clarkware.com/software/JDepend.html</a> . The current | |||
| * implementation spawn a new Java VM. | |||
| * | |||
| * @author <a href="mailto:Jerome@jeromelacoste.com">Jerome Lacoste</a> | |||
| * @author <a href="mailto:roxspring@yahoo.com">Rob Oxspring</a> | |||
| */ | |||
| public class JDependTask | |||
| extends AbstractTask | |||
| { | |||
| private boolean m_fork; | |||
| private String m_jvm; | |||
| private String m_format = "text"; | |||
| private Path m_compileClasspath = new Path(); | |||
| private File m_dir; | |||
| private File m_outputFile; | |||
| private Path m_sourcesPath; | |||
| /** | |||
| * Set the classpath to be used for this compilation. | |||
| */ | |||
| public void setClasspath( final Path classpath ) | |||
| throws TaskException | |||
| { | |||
| addClasspath( classpath ); | |||
| } | |||
| /** | |||
| * The directory to invoke the VM in. Ignored if no JVM is forked. | |||
| * | |||
| * @param dir the directory to invoke the JVM from. | |||
| * @see #setFork(boolean) | |||
| */ | |||
| public void setDir( final File dir ) | |||
| { | |||
| m_dir = dir; | |||
| } | |||
| /** | |||
| * Tells whether a JVM should be forked for the task. Default: false. | |||
| * | |||
| * @param fork <tt>true</tt> if a JVM should be forked, otherwise <tt>false | |||
| * <tt> | |||
| */ | |||
| public void setFork( final boolean fork ) | |||
| { | |||
| m_fork = fork; | |||
| } | |||
| public void setFormat( final FormatAttribute format ) | |||
| { | |||
| m_format = format.getValue(); | |||
| } | |||
| /** | |||
| * Set a new VM to execute the task. Default is <tt>java</tt> . Ignored if | |||
| * no JVM is forked. | |||
| * | |||
| * @param jvm the new VM to use instead of <tt>java</tt> | |||
| * @see #setFork(boolean) | |||
| */ | |||
| public void setJvm( final String jvm ) | |||
| { | |||
| m_jvm = jvm; | |||
| } | |||
| /* | |||
| * public void setTimeout(Integer value) { | |||
| * _timeout = value; | |||
| * } | |||
| * public Integer getTimeout() { | |||
| * return _timeout; | |||
| * } | |||
| */ | |||
| public void setOutputFile( final File outputFile ) | |||
| { | |||
| m_outputFile = outputFile; | |||
| } | |||
| /** | |||
| * Adds a nested classpath element. | |||
| */ | |||
| public void addClasspath( final Path path ) | |||
| { | |||
| m_compileClasspath.add( path ); | |||
| } | |||
| /** | |||
| * Maybe creates a nested classpath element. | |||
| */ | |||
| public Path createSourcespath() | |||
| { | |||
| if( m_sourcesPath == null ) | |||
| { | |||
| m_sourcesPath = new Path(); | |||
| } | |||
| Path path1 = m_sourcesPath; | |||
| final Path path = new Path(); | |||
| path1.add( path ); | |||
| return path; | |||
| } | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| if( m_sourcesPath == null ) | |||
| { | |||
| throw new TaskException( "Missing Sourcepath required argument" ); | |||
| } | |||
| // execute the test and get the return code | |||
| if( !m_fork ) | |||
| { | |||
| executeInVM(); | |||
| } | |||
| else | |||
| { | |||
| executeAsForked(); | |||
| } | |||
| } | |||
| /** | |||
| * Execute the task by forking a new JVM. The command will block until it | |||
| * finishes. To know if the process was destroyed or not, use the <tt> | |||
| * killedProcess()</tt> method of the watchdog class. | |||
| */ | |||
| // JL: comment extracted from JUnitTask (and slightly modified) | |||
| private void executeAsForked() | |||
| throws TaskException | |||
| { | |||
| final ExecuteJava exe = new ExecuteJava(); | |||
| exe.setWorkingDirectory( m_dir ); | |||
| if( "text".equals( m_format ) ) | |||
| { | |||
| exe.setClassName( "jdepend.textui.JDepend" ); | |||
| } | |||
| else | |||
| { | |||
| exe.setClassName( "jdepend.xmlui.JDepend" ); | |||
| } | |||
| if( m_jvm != null ) | |||
| { | |||
| exe.setJvm( m_jvm ); | |||
| } | |||
| exe.getClassPath().add( m_compileClasspath ); | |||
| if( m_outputFile != null ) | |||
| { | |||
| // having a space between the file and its path causes commandline to add quotes " | |||
| // around the argument thus making JDepend not taking it into account. Thus we split it in two | |||
| exe.getArguments().addArgument( "-file" ); | |||
| exe.getArguments().addArgument( m_outputFile ); | |||
| getContext().info( "Output to be stored in " + m_outputFile.getPath() ); | |||
| } | |||
| final String[] elements = m_sourcesPath.listFiles( getContext() ); | |||
| for( int i = 0; i < elements.length; i++ ) | |||
| { | |||
| File f = new File( elements[ i ] ); | |||
| // not necessary as JDepend would fail, but why loose some time? | |||
| if( !f.exists() || !f.isDirectory() ) | |||
| { | |||
| throw new TaskException( "\"" + f.getPath() + "\" does not represent a valid directory. JDepend would fail." ); | |||
| } | |||
| exe.getArguments().addArgument( f ); | |||
| } | |||
| exe.executeForked( getContext() ); | |||
| } | |||
| // this comment extract from JUnit Task may also apply here | |||
| // "in VM is not very nice since it could probably hang the | |||
| // whole build. IMHO this method should be avoided and it would be best | |||
| // to remove it in future versions. TBD. (SBa)" | |||
| /** | |||
| * Execute inside VM. | |||
| */ | |||
| private void executeInVM() | |||
| throws TaskException | |||
| { | |||
| jdepend.textui.JDepend jdepend; | |||
| if( "xml".equals( m_format ) ) | |||
| { | |||
| jdepend = new jdepend.xmlui.JDepend(); | |||
| } | |||
| else | |||
| { | |||
| jdepend = new jdepend.textui.JDepend(); | |||
| } | |||
| if( m_outputFile != null ) | |||
| { | |||
| FileWriter fw; | |||
| try | |||
| { | |||
| fw = new FileWriter( m_outputFile.getPath() ); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| String msg = "JDepend Failed when creating the output file: " + e.getMessage(); | |||
| throw new TaskException( msg ); | |||
| } | |||
| jdepend.setWriter( new PrintWriter( fw ) ); | |||
| getContext().info( "Output to be stored in " + m_outputFile.getPath() ); | |||
| } | |||
| final String[] elements = m_sourcesPath.listFiles( getContext() ); | |||
| for( int i = 0; i < elements.length; i++ ) | |||
| { | |||
| File f = new File( elements[ i ] ); | |||
| // not necessary as JDepend would fail, but why loose some time? | |||
| if( !f.exists() || !f.isDirectory() ) | |||
| { | |||
| String msg = "\"" + f.getPath() + "\" does not represent a valid directory. JDepend would fail."; | |||
| throw new TaskException( msg ); | |||
| } | |||
| try | |||
| { | |||
| jdepend.addDirectory( f.getPath() ); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| String msg = "JDepend Failed when adding a source directory: " + e.getMessage(); | |||
| throw new TaskException( msg ); | |||
| } | |||
| } | |||
| jdepend.analyze(); | |||
| } | |||
| } | |||
| @@ -1,484 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.jsp; | |||
| import java.io.File; | |||
| import java.util.ArrayList; | |||
| import java.util.Date; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.tools.todo.taskdefs.MatchingTask; | |||
| import org.apache.tools.todo.taskdefs.jsp.compilers.CompilerAdapter; | |||
| import org.apache.tools.todo.taskdefs.jsp.compilers.CompilerAdapterFactory; | |||
| import org.apache.tools.todo.types.DirectoryScanner; | |||
| import org.apache.myrmidon.framework.file.Path; | |||
| /** | |||
| * Ant task to run the jsp compiler. <p> | |||
| * | |||
| * This task takes the given jsp files and compiles them into java files. It is | |||
| * then up to the user to compile the java files into classes. <p> | |||
| * | |||
| * The task requires the srcdir and destdir attributes to be set. This Task is a | |||
| * MatchingTask, so the files to be compiled can be specified using | |||
| * includes/excludes attributes or nested include/exclude elements. Optional | |||
| * attributes are verbose (set the verbosity level passed to jasper), package | |||
| * (name of the destination package for generated java classes and classpath | |||
| * (the classpath to use when running the jsp compiler). <p> | |||
| * | |||
| * This task supports the nested elements classpath (A Path) and classpathref (A | |||
| * Reference) which can be used in preference to the attribute classpath, if the | |||
| * jsp compiler is not already in the ant classpath. <p> | |||
| * | |||
| * <h4>Notes</h4> <p> | |||
| * | |||
| * At present, this task only supports the jasper compiler. In future, other | |||
| * compilers will be supported by setting the jsp.compiler property. <p> | |||
| * | |||
| * <h4>Usage</h4> <pre> | |||
| * <jspc srcdir="${basedir}/src/war" | |||
| * destdir="${basedir}/gensrc" | |||
| * package="com.i3sp.jsp" | |||
| * verbose="9"> | |||
| * <include name="**\/*.jsp" /> | |||
| * </jspc> | |||
| * </pre> | |||
| * | |||
| * @author <a href="mailto:mattw@i3sp.com">Matthew Watson</a> <p> | |||
| * | |||
| * Large Amount of cutting and pasting from the Javac task... | |||
| * @author James Davidson <a href="mailto:duncan@x180.com">duncan@x180.com</a> | |||
| * @author Robin Green <a href="mailto:greenrd@hotmail.com">greenrd@hotmail.com | |||
| * </a> | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:jayglanville@home.com">J D Glanville</a> | |||
| * @version $Revision$ $Date$ | |||
| */ | |||
| public class JspC extends MatchingTask | |||
| { | |||
| private final static String FAIL_MSG | |||
| = "Compile failed, messages should have been provided."; | |||
| private int verbose = 0; | |||
| protected ArrayList compileList = new ArrayList(); | |||
| protected boolean failOnError = true; | |||
| /* | |||
| * ------------------------------------------------------------ | |||
| */ | |||
| private Path classpath; | |||
| private File destDir; | |||
| private String iepluginid; | |||
| private boolean mapped; | |||
| private String packageName; | |||
| private Path src; | |||
| /** | |||
| * -uribase <dir>The uri directory compilations should be relative to | |||
| * (Default is "/") | |||
| */ | |||
| private File uribase; | |||
| /** | |||
| * -uriroot <dir>The root directory that uri files should be resolved | |||
| * against, | |||
| */ | |||
| private File uriroot; | |||
| /* | |||
| * ------------------------------------------------------------ | |||
| */ | |||
| /** | |||
| * Set the classpath to be used for this compilation | |||
| * | |||
| * @param cp The new Classpath value | |||
| */ | |||
| public void setClasspath( Path cp ) | |||
| throws TaskException | |||
| { | |||
| if( classpath == null ) | |||
| { | |||
| classpath = cp; | |||
| } | |||
| else | |||
| { | |||
| classpath.add( cp ); | |||
| } | |||
| } | |||
| /** | |||
| * Set the destination directory into which the JSP source files should be | |||
| * compiled. | |||
| * | |||
| * @param destDir The new Destdir value | |||
| */ | |||
| public void setDestdir( File destDir ) | |||
| { | |||
| this.destDir = destDir; | |||
| } | |||
| /* | |||
| * ------------------------------------------------------------ | |||
| */ | |||
| /** | |||
| * Throw a TaskException if compilation fails | |||
| * | |||
| * @param fail The new Failonerror value | |||
| */ | |||
| public void setFailonerror( boolean fail ) | |||
| { | |||
| failOnError = fail; | |||
| } | |||
| /** | |||
| * Set the ieplugin id | |||
| * | |||
| * @param iepluginid_ The new Ieplugin value | |||
| */ | |||
| public void setIeplugin( String iepluginid_ ) | |||
| { | |||
| iepluginid = iepluginid_; | |||
| } | |||
| /** | |||
| * set the mapped flag | |||
| * | |||
| * @param mapped_ The new Mapped value | |||
| */ | |||
| public void setMapped( boolean mapped_ ) | |||
| { | |||
| mapped = mapped_; | |||
| } | |||
| /* | |||
| * ------------------------------------------------------------ | |||
| */ | |||
| /** | |||
| * Set the name of the package the compiled jsp files should be in | |||
| * | |||
| * @param pkg The new Package value | |||
| */ | |||
| public void setPackage( String pkg ) | |||
| { | |||
| this.packageName = pkg; | |||
| } | |||
| /* | |||
| * ------------------------------------------------------------ | |||
| */ | |||
| /** | |||
| * Set the source dirs to find the source JSP files. | |||
| * | |||
| * @param srcDir The new Srcdir value | |||
| */ | |||
| public void setSrcdir( Path srcDir ) | |||
| throws TaskException | |||
| { | |||
| if( src == null ) | |||
| { | |||
| src = srcDir; | |||
| } | |||
| else | |||
| { | |||
| src.add( srcDir ); | |||
| } | |||
| } | |||
| /** | |||
| * -uribase. the uri context of relative URI references in the JSP pages. If | |||
| * it does not exist then it is derived from the location of the file | |||
| * relative to the declared or derived value of -uriroot. | |||
| * | |||
| * @param uribase The new Uribase value | |||
| */ | |||
| public void setUribase( File uribase ) | |||
| { | |||
| this.uribase = uribase; | |||
| } | |||
| /** | |||
| * -uriroot <dir>The root directory that uri files should be resolved | |||
| * against, (Default is the directory jspc is invoked from) | |||
| * | |||
| * @param uriroot The new Uribase value | |||
| */ | |||
| public void setUriroot( File uriroot ) | |||
| { | |||
| this.uriroot = uriroot; | |||
| } | |||
| /* | |||
| * ------------------------------------------------------------ | |||
| */ | |||
| /** | |||
| * Set the verbose level of the compiler | |||
| * | |||
| * @param i The new Verbose value | |||
| */ | |||
| public void setVerbose( int i ) | |||
| { | |||
| verbose = i; | |||
| } | |||
| public Path getClasspath() | |||
| { | |||
| return classpath; | |||
| } | |||
| /* | |||
| * ------------------------------------------------------------ | |||
| */ | |||
| public ArrayList getCompileList() | |||
| { | |||
| return compileList; | |||
| } | |||
| public File getDestdir() | |||
| { | |||
| return destDir; | |||
| } | |||
| /** | |||
| * Gets the failonerror flag. | |||
| * | |||
| * @return The Failonerror value | |||
| */ | |||
| public boolean getFailonerror() | |||
| { | |||
| return failOnError; | |||
| } | |||
| /* | |||
| * ------------------------------------------------------------ | |||
| */ | |||
| public String getIeplugin() | |||
| { | |||
| return iepluginid; | |||
| } | |||
| public String getPackage() | |||
| { | |||
| return packageName; | |||
| } | |||
| public Path getSrcDir() | |||
| { | |||
| return src; | |||
| } | |||
| public File getUribase() | |||
| { | |||
| return uriroot; | |||
| } | |||
| public File getUriroot() | |||
| { | |||
| return uriroot; | |||
| } | |||
| public int getVerbose() | |||
| { | |||
| return verbose; | |||
| } | |||
| /* | |||
| * ------------------------------------------------------------ | |||
| */ | |||
| public boolean isMapped() | |||
| { | |||
| return mapped; | |||
| } | |||
| /** | |||
| * Maybe creates a nested classpath element. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public Path createClasspath() | |||
| throws TaskException | |||
| { | |||
| if( classpath == null ) | |||
| { | |||
| classpath = new Path(); | |||
| } | |||
| Path path1 = classpath; | |||
| final Path path = new Path(); | |||
| path1.add( path ); | |||
| return path; | |||
| } | |||
| /* | |||
| * ------------------------------------------------------------ | |||
| */ | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| // first off, make sure that we've got a srcdir | |||
| if( src == null ) | |||
| { | |||
| throw new TaskException( "srcdir attribute must be set!" ); | |||
| } | |||
| String[] list = src.listFiles( getContext() ); | |||
| if( list.length == 0 ) | |||
| { | |||
| throw new TaskException( "srcdir attribute must be set!" ); | |||
| } | |||
| if( destDir != null && !destDir.isDirectory() ) | |||
| { | |||
| throw new | |||
| TaskException( "destination directory \"" + destDir + | |||
| "\" does not exist or is not a directory" ); | |||
| } | |||
| // calculate where the files will end up: | |||
| File dest = null; | |||
| if( packageName == null ) | |||
| { | |||
| dest = destDir; | |||
| } | |||
| else | |||
| { | |||
| String path = destDir.getPath() + File.separatorChar + | |||
| packageName.replace( '.', File.separatorChar ); | |||
| dest = new File( path ); | |||
| } | |||
| // scan source directories and dest directory to build up both copy | |||
| // lists and compile lists | |||
| resetFileLists(); | |||
| int filecount = 0; | |||
| for( int i = 0; i < list.length; i++ ) | |||
| { | |||
| final String filename = list[ i ]; | |||
| File srcDir = (File)getContext().resolveFile( filename ); | |||
| if( !srcDir.exists() ) | |||
| { | |||
| throw new TaskException( "srcdir \"" + srcDir.getPath() + | |||
| "\" does not exist!" ); | |||
| } | |||
| DirectoryScanner ds = this.getDirectoryScanner( srcDir ); | |||
| String[] files = ds.getIncludedFiles(); | |||
| filecount = files.length; | |||
| scanDir( srcDir, dest, files ); | |||
| } | |||
| // compile the source files | |||
| Object compiler = getContext().getProperty( "jsp.compiler" ); | |||
| if( compiler == null ) | |||
| { | |||
| compiler = "jasper"; | |||
| } | |||
| getContext().debug( "compiling " + compileList.size() + " files" ); | |||
| if( compileList.size() > 0 ) | |||
| { | |||
| CompilerAdapter adapter = | |||
| CompilerAdapterFactory.getCompiler( compiler.toString(), getContext() ); | |||
| getContext().info( "Compiling " + compileList.size() + | |||
| " source file" | |||
| + ( compileList.size() == 1 ? "" : "s" ) | |||
| + ( destDir != null ? " to " + destDir : "" ) ); | |||
| // now we need to populate the compiler adapter | |||
| adapter.setJspc( this ); | |||
| // finally, lets execute the compiler!! | |||
| if( !adapter.execute() ) | |||
| { | |||
| if( failOnError ) | |||
| { | |||
| throw new TaskException( FAIL_MSG ); | |||
| } | |||
| else | |||
| { | |||
| getContext().error( FAIL_MSG ); | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| if( filecount == 0 ) | |||
| { | |||
| getContext().verbose( "there were no files to compile" ); | |||
| } | |||
| else | |||
| { | |||
| getContext().verbose( "all files are up to date" ); | |||
| } | |||
| } | |||
| } | |||
| /* | |||
| * ------------------------------------------------------------ | |||
| */ | |||
| /** | |||
| * Clear the list of files to be compiled and copied.. | |||
| */ | |||
| protected void resetFileLists() | |||
| { | |||
| compileList.clear(); | |||
| } | |||
| /* | |||
| * ------------------------------------------------------------ | |||
| */ | |||
| /** | |||
| * Scans the directory looking for source files to be compiled. The results | |||
| * are returned in the class variable compileList | |||
| * | |||
| * @param srcDir Description of Parameter | |||
| * @param destDir Description of Parameter | |||
| * @param files Description of Parameter | |||
| */ | |||
| protected void scanDir( File srcDir, File destDir, String files[] ) | |||
| { | |||
| long now = ( new Date() ).getTime(); | |||
| for( int i = 0; i < files.length; i++ ) | |||
| { | |||
| File srcFile = new File( srcDir, files[ i ] ); | |||
| if( files[ i ].endsWith( ".jsp" ) ) | |||
| { | |||
| // drop leading path (if any) | |||
| int fileStart = | |||
| files[ i ].lastIndexOf( File.separatorChar ) + 1; | |||
| File javaFile = new File( destDir, files[ i ].substring( fileStart, | |||
| files[ i ].indexOf( ".jsp" ) ) + ".java" ); | |||
| if( srcFile.lastModified() > now ) | |||
| { | |||
| final String message = | |||
| "Warning: file modified in the future: " + files[ i ]; | |||
| getContext().warn( message ); | |||
| } | |||
| if( !javaFile.exists() || | |||
| srcFile.lastModified() > javaFile.lastModified() ) | |||
| { | |||
| if( !javaFile.exists() ) | |||
| { | |||
| getContext().debug( "Compiling " + srcFile.getPath() + " because java file " + javaFile.getPath() + " does not exist" ); | |||
| } | |||
| else | |||
| { | |||
| getContext().debug( "Compiling " + srcFile.getPath() + " because it is out of date with respect to " + javaFile.getPath() ); | |||
| } | |||
| compileList.add( srcFile.getAbsolutePath() ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| /* | |||
| * ------------------------------------------------------------ | |||
| */ | |||
| } | |||
| @@ -1,294 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.jsp;//java imports | |||
| import java.io.File; | |||
| import java.util.ArrayList; | |||
| import java.util.Date; | |||
| import java.util.StringTokenizer; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.java.ExecuteJava; | |||
| import org.apache.tools.todo.taskdefs.MatchingTask; | |||
| import org.apache.tools.todo.types.DirectoryScanner; | |||
| import org.apache.myrmidon.framework.file.Path; | |||
| import org.apache.myrmidon.framework.file.FileListUtil; | |||
| /** | |||
| * Class to precompile JSP's using weblogic's jsp compiler (weblogic.jspc) | |||
| * | |||
| * @author <a href="mailto:avik@aviksengupta.com">Avik Sengupta</a> | |||
| * http://www.webteksoftware.com Tested only on Weblogic 4.5.1 - NT4.0 and | |||
| * Solaris 5.7 required attributes src : root of source tree for JSP, ie, | |||
| * the document root for your weblogic server dest : root of destination | |||
| * directory, what you have set as WorkingDir in the weblogic properties | |||
| * package : start package name under which your JSP's would be compiled | |||
| * other attributes classpath A classpath should be set which contains the | |||
| * weblogic classes as well as all application classes referenced by the | |||
| * JSP. The system classpath is also appended when the jspc is called, so | |||
| * you may choose to put everything in the classpath while calling Ant. | |||
| * However, since presumably the JSP's will reference classes being build | |||
| * by Ant, it would be better to explicitly add the classpath in the task | |||
| * The task checks timestamps on the JSP's and the generated classes, and | |||
| * compiles only those files that have changed. It follows the weblogic | |||
| * naming convention of putting classes in <b> _dirName/_fileName.class for | |||
| * dirname/fileName.jsp </b> Limitation: It compiles the files thru the | |||
| * Classic compiler only. Limitation: Since it is my experience that | |||
| * weblogic jspc throws out of memory error on being given too many files | |||
| * at one go, it is called multiple times with one jsp file each. <pre> | |||
| * example | |||
| * <target name="jspcompile" depends="compile"> | |||
| * <wljspc src="c:\\weblogic\\myserver\\public_html" dest="c:\\weblogic\\myserver\\serverclasses" package="myapp.jsp"> | |||
| * <classpath> | |||
| * <pathelement location="${weblogic.classpath}" /> | |||
| * <pathelement path="${compile.dest}" /> | |||
| * </classpath> | |||
| * | |||
| * </wljspc> | |||
| * </target> | |||
| * </pre> | |||
| */ | |||
| public class WLJspc extends MatchingTask | |||
| {//classpath used to compile the jsp files. | |||
| //private String compilerPath; //fully qualified name for the compiler executable | |||
| private String pathToPackage = ""; | |||
| private ArrayList filesToDo = new ArrayList();//package under which resultant classes will reside | |||
| private Path compileClasspath; | |||
| //TODO Test on other versions of weblogic | |||
| //TODO add more attributes to the task, to take care of all jspc options | |||
| //TODO Test on Unix | |||
| private File destinationDirectory;// root of source files tree | |||
| private String destinationPackage;//root of compiled files tree | |||
| private File sourceDirectory; | |||
| /** | |||
| * Set the classpath to be used for this compilation. | |||
| * | |||
| * @param classpath The new Classpath value | |||
| */ | |||
| public void setClasspath( Path classpath ) | |||
| throws TaskException | |||
| { | |||
| if( compileClasspath == null ) | |||
| { | |||
| compileClasspath = classpath; | |||
| } | |||
| else | |||
| { | |||
| compileClasspath.add( classpath ); | |||
| } | |||
| } | |||
| /** | |||
| * Set the directory containing the source jsp's | |||
| * | |||
| * @param dirName the directory containg the source jsp's | |||
| */ | |||
| public void setDest( File dirName ) | |||
| { | |||
| destinationDirectory = dirName; | |||
| } | |||
| /** | |||
| * Set the package under which the compiled classes go | |||
| * | |||
| * @param packageName the package name for the clases | |||
| */ | |||
| public void setPackage( String packageName ) | |||
| { | |||
| destinationPackage = packageName; | |||
| } | |||
| /** | |||
| * Set the directory containing the source jsp's | |||
| * | |||
| * @param dirName the directory containg the source jsp's | |||
| */ | |||
| public void setSrc( File dirName ) | |||
| { | |||
| sourceDirectory = dirName; | |||
| } | |||
| /** | |||
| * Maybe creates a nested classpath element. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public Path createClasspath() | |||
| { | |||
| if( compileClasspath == null ) | |||
| { | |||
| compileClasspath = new Path(); | |||
| } | |||
| return compileClasspath; | |||
| } | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| if( !destinationDirectory.isDirectory() ) | |||
| { | |||
| throw new TaskException( "destination directory " + destinationDirectory.getPath() + | |||
| " is not valid" ); | |||
| } | |||
| if( !sourceDirectory.isDirectory() ) | |||
| { | |||
| throw new TaskException( "src directory " + sourceDirectory.getPath() + | |||
| " is not valid" ); | |||
| } | |||
| if( destinationPackage == null ) | |||
| { | |||
| throw new TaskException( "package attribute must be present." ); | |||
| } | |||
| pathToPackage = this.destinationPackage.replace( '.', File.separatorChar ); | |||
| // get all the files in the sourceDirectory | |||
| DirectoryScanner ds = super.getDirectoryScanner( sourceDirectory ); | |||
| //use the systemclasspath as well, to include the ant jar | |||
| if( compileClasspath == null ) | |||
| { | |||
| compileClasspath = new Path(); | |||
| } | |||
| // TODO - make sure tools.jar ends up in the classpath | |||
| //compileClasspath.append( Path.systemClasspath ); | |||
| String[] files = ds.getIncludedFiles(); | |||
| //Weblogic.jspc calls System.exit() ... have to fork | |||
| // Therefore, takes loads of time | |||
| // Can pass directories at a time (*.jsp) but easily runs out of memory on hefty dirs | |||
| // (even on a Sun) | |||
| String[] args = new String[ 12 ]; | |||
| File jspFile = null; | |||
| String parents = ""; | |||
| int j = 0; | |||
| //XXX this array stuff is a remnant of prev trials.. gotta remove. | |||
| args[ j++ ] = "-d"; | |||
| args[ j++ ] = destinationDirectory.getAbsolutePath().trim(); | |||
| args[ j++ ] = "-docroot"; | |||
| args[ j++ ] = sourceDirectory.getAbsolutePath().trim(); | |||
| args[ j++ ] = "-keepgenerated";//TODO: Parameterise ?? | |||
| //Call compiler as class... dont want to fork again | |||
| //Use classic compiler -- can be parameterised? | |||
| args[ j++ ] = "-compilerclass"; | |||
| args[ j++ ] = "sun.tools.javac.Main"; | |||
| //Weblogic jspc does not seem to work unless u explicitly set this... | |||
| // Does not take the classpath from the env.... | |||
| // Am i missing something about the Java task?? | |||
| args[ j++ ] = "-classpath"; | |||
| args[ j++ ] = FileListUtil.formatPath( compileClasspath, getContext() ); | |||
| this.scanDir( files ); | |||
| getContext().info( "Compiling " + filesToDo.size() + " JSP files" ); | |||
| for( int i = 0; i < filesToDo.size(); i++ ) | |||
| { | |||
| //XXX | |||
| // All this to get package according to weblogic standards | |||
| // Can be written better... this is too hacky! | |||
| // Careful.. similar code in scanDir , but slightly different!! | |||
| jspFile = new File( (String)filesToDo.get( i ) ); | |||
| args[ j ] = "-package"; | |||
| parents = jspFile.getParent(); | |||
| if( ( parents != null ) && ( !( "" ).equals( parents ) ) ) | |||
| { | |||
| parents = this.replaceString( parents, File.separator, "_." ); | |||
| args[ j + 1 ] = destinationPackage + "." + "_" + parents; | |||
| } | |||
| else | |||
| { | |||
| args[ j + 1 ] = destinationPackage; | |||
| } | |||
| args[ j + 2 ] = sourceDirectory + File.separator + (String)filesToDo.get( i ); | |||
| ExecuteJava helperTask = new ExecuteJava(); | |||
| helperTask.setClassName( "weblogic.jspc" ); | |||
| helperTask.getArguments().addArguments( args ); | |||
| helperTask.getClassPath().add( compileClasspath ); | |||
| helperTask.executeForked( getContext() ); | |||
| } | |||
| } | |||
| protected String replaceString( String inpString, String escapeChars, String replaceChars ) | |||
| { | |||
| String localString = ""; | |||
| int numTokens = 0; | |||
| StringTokenizer st = new StringTokenizer( inpString, escapeChars, true ); | |||
| numTokens = st.countTokens(); | |||
| for( int i = 0; i < numTokens; i++ ) | |||
| { | |||
| String test = st.nextToken(); | |||
| test = ( test.equals( escapeChars ) ? replaceChars : test ); | |||
| localString += test; | |||
| } | |||
| return localString; | |||
| } | |||
| protected void scanDir( String files[] ) | |||
| { | |||
| long now = ( new Date() ).getTime(); | |||
| File jspFile = null; | |||
| String parents = null; | |||
| String pack = ""; | |||
| for( int i = 0; i < files.length; i++ ) | |||
| { | |||
| File srcFile = new File( this.sourceDirectory, files[ i ] ); | |||
| //XXX | |||
| // All this to convert source to destination directory according to weblogic standards | |||
| // Can be written better... this is too hacky! | |||
| jspFile = new File( files[ i ] ); | |||
| parents = jspFile.getParent(); | |||
| if( ( parents != null ) && ( !( "" ).equals( parents ) ) ) | |||
| { | |||
| parents = this.replaceString( parents, File.separator, "_/" ); | |||
| pack = pathToPackage + File.separator + "_" + parents; | |||
| } | |||
| else | |||
| { | |||
| pack = pathToPackage; | |||
| } | |||
| String filePath = pack + File.separator + "_"; | |||
| int startingIndex | |||
| = files[ i ].lastIndexOf( File.separator ) != -1 ? files[ i ].lastIndexOf( File.separator ) + 1 : 0; | |||
| int endingIndex = files[ i ].indexOf( ".jsp" ); | |||
| if( endingIndex == -1 ) | |||
| { | |||
| break; | |||
| } | |||
| filePath += files[ i ].substring( startingIndex, endingIndex ); | |||
| filePath += ".class"; | |||
| File classFile = new File( this.destinationDirectory, filePath ); | |||
| if( srcFile.lastModified() > now ) | |||
| { | |||
| final String message = "Warning: file modified in the future: " + files[ i ]; | |||
| getContext().warn( message ); | |||
| } | |||
| if( srcFile.lastModified() > classFile.lastModified() ) | |||
| { | |||
| //log("Files are" + srcFile.getAbsolutePath()+" " +classFile.getAbsolutePath()); | |||
| filesToDo.add( files[ i ] ); | |||
| getContext().debug( "Recompiling File " + files[ i ] ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -1,46 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.jsp.compilers; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.api.TaskContext; | |||
| import org.apache.tools.todo.taskdefs.jsp.JspC; | |||
| /** | |||
| * The interface that all jsp compiler adapters must adher to. <p> | |||
| * | |||
| * A compiler adapter is an adapter that interprets the jspc's parameters in | |||
| * preperation to be passed off to the compier this adapter represents. As all | |||
| * the necessary values are stored in the Jspc task itself, the only thing all | |||
| * adapters need is the jsp task, the execute command and a parameterless | |||
| * constructor (for reflection).</p> | |||
| * | |||
| * @author Jay Dickon Glanville <a href="mailto:jayglanville@home.com"> | |||
| * jayglanville@home.com</a> | |||
| * @author Matthew Watson <a href="mailto:mattw@i3sp.com">mattw@i3sp.com</a> | |||
| */ | |||
| public interface CompilerAdapter | |||
| { | |||
| void setTaskContext( TaskContext context ); | |||
| /** | |||
| * Sets the compiler attributes, which are stored in the Jspc task. | |||
| * | |||
| * @param attributes The new Jspc value | |||
| */ | |||
| void setJspc( JspC attributes ); | |||
| /** | |||
| * Executes the task. | |||
| * | |||
| * @return has the compilation been successful | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| boolean execute() | |||
| throws TaskException; | |||
| } | |||
| @@ -1,103 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.jsp.compilers; | |||
| import org.apache.myrmidon.api.AbstractTask; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.api.TaskContext; | |||
| /** | |||
| * Creates the necessary compiler adapter, given basic criteria. | |||
| * | |||
| * @author <a href="mailto:jayglanville@home.com">J D Glanville</a> | |||
| * @author Matthew Watson <a href="mailto:mattw@i3sp.com">mattw@i3sp.com</a> | |||
| */ | |||
| public class CompilerAdapterFactory | |||
| { | |||
| /** | |||
| * This is a singlton -- can't create instances!! | |||
| */ | |||
| private CompilerAdapterFactory() | |||
| { | |||
| } | |||
| /** | |||
| * Based on the parameter passed in, this method creates the necessary | |||
| * factory desired. The current mapping for compiler names are as follows: | |||
| * | |||
| * <ul> | |||
| * <li> jasper = jasper compiler (the default) | |||
| * <li> <i>a fully quallified classname</i> = the name of a jsp compiler | |||
| * adapter | |||
| * </ul> | |||
| * | |||
| * | |||
| * @param compilerType either the name of the desired compiler, or the full | |||
| * classname of the compiler's adapter. | |||
| * @return The Compiler value | |||
| * @throws TaskException if the compiler type could not be resolved into a | |||
| * compiler adapter. | |||
| */ | |||
| public static CompilerAdapter getCompiler( String compilerType, TaskContext context ) | |||
| throws TaskException | |||
| { | |||
| final CompilerAdapter adapter = createAdapter( compilerType ); | |||
| adapter.setTaskContext( context ); | |||
| return adapter; | |||
| } | |||
| private static CompilerAdapter createAdapter( String compilerType ) | |||
| throws TaskException | |||
| { | |||
| /* | |||
| * If I've done things right, this should be the extent of the | |||
| * conditional statements required. | |||
| */ | |||
| if( compilerType.equalsIgnoreCase( "jasper" ) ) | |||
| { | |||
| return new JasperC(); | |||
| } | |||
| return resolveClassName( compilerType ); | |||
| } | |||
| /** | |||
| * Tries to resolve the given classname into a compiler adapter. Throws a | |||
| * fit if it can't. | |||
| * | |||
| * @param className The fully qualified classname to be created. | |||
| * @return Description of the Returned Value | |||
| * @throws TaskException This is the fit that is thrown if className isn't | |||
| * an instance of CompilerAdapter. | |||
| */ | |||
| private static CompilerAdapter resolveClassName( String className ) | |||
| throws TaskException | |||
| { | |||
| try | |||
| { | |||
| Class c = Class.forName( className ); | |||
| Object o = c.newInstance(); | |||
| return (CompilerAdapter)o; | |||
| } | |||
| catch( ClassNotFoundException cnfe ) | |||
| { | |||
| throw new TaskException( className + " can\'t be found.", cnfe ); | |||
| } | |||
| catch( ClassCastException cce ) | |||
| { | |||
| throw new TaskException( className + " isn\'t the classname of " | |||
| + "a compiler adapter.", cce ); | |||
| } | |||
| catch( Throwable t ) | |||
| { | |||
| // for all other possibilities | |||
| throw new TaskException( className + " caused an interesting " | |||
| + "exception.", t ); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,91 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.jsp.compilers; | |||
| import java.util.ArrayList; | |||
| import java.util.Iterator; | |||
| import org.apache.avalon.excalibur.util.StringUtil; | |||
| import org.apache.myrmidon.api.TaskContext; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.tools.todo.taskdefs.jsp.JspC; | |||
| import org.apache.myrmidon.framework.nativelib.Commandline; | |||
| import org.apache.myrmidon.framework.nativelib.ArgumentList; | |||
| import org.apache.tools.todo.util.FileUtils; | |||
| /** | |||
| * This is the default implementation for the CompilerAdapter interface. This is | |||
| * currently very light on the ground since only one compiler type is supported. | |||
| * | |||
| * @author Matthew Watson <a href="mailto:mattw@i3sp.com">mattw@i3sp.com</a> | |||
| */ | |||
| public abstract class DefaultCompilerAdapter | |||
| implements CompilerAdapter | |||
| { | |||
| private JspC m_attributes; | |||
| private TaskContext m_taskContext; | |||
| public void setTaskContext( final TaskContext context ) | |||
| { | |||
| m_taskContext = context; | |||
| } | |||
| protected final TaskContext getTaskContext() | |||
| { | |||
| return m_taskContext; | |||
| } | |||
| public void setJspc( final JspC attributes ) | |||
| { | |||
| this.m_attributes = attributes; | |||
| } | |||
| public JspC getJspc() | |||
| { | |||
| return m_attributes; | |||
| } | |||
| /* | |||
| * ------------------------------------------------------------ | |||
| */ | |||
| /** | |||
| * Logs the compilation parameters, adds the files to compile and logs the | |||
| * &qout;niceSourceList" | |||
| * | |||
| * @param jspc Description of Parameter | |||
| * @param compileList Description of Parameter | |||
| * @param cmd Description of Parameter | |||
| */ | |||
| protected void logAndAddFilesToCompile( JspC jspc, | |||
| ArrayList compileList, | |||
| ArgumentList cmd ) | |||
| throws TaskException | |||
| { | |||
| final String[] args = cmd.getArguments(); | |||
| getTaskContext().debug( "Compilation args: " + FileUtils.formatCommandLine( args ) ); | |||
| StringBuffer niceSourceList = new StringBuffer( "File" ); | |||
| if( compileList.size() != 1 ) | |||
| { | |||
| niceSourceList.append( "s" ); | |||
| } | |||
| niceSourceList.append( " to be compiled:" ); | |||
| niceSourceList.append( StringUtil.LINE_SEPARATOR ); | |||
| Iterator enum = compileList.iterator(); | |||
| while( enum.hasNext() ) | |||
| { | |||
| String arg = (String)enum.next(); | |||
| cmd.addArgument( arg ); | |||
| niceSourceList.append( " " + arg + StringUtil.LINE_SEPARATOR ); | |||
| } | |||
| getTaskContext().debug( niceSourceList.toString() ); | |||
| } | |||
| } | |||
| @@ -1,90 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.jsp.compilers; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.java.ExecuteJava; | |||
| import org.apache.tools.todo.taskdefs.jsp.JspC; | |||
| import org.apache.myrmidon.framework.nativelib.Commandline; | |||
| import org.apache.myrmidon.framework.nativelib.ArgumentList; | |||
| /** | |||
| * The implementation of the jasper compiler. This is a cut-and-paste of the | |||
| * original Jspc task. | |||
| * | |||
| * @author Matthew Watson <a href="mailto:mattw@i3sp.com">mattw@i3sp.com</a> | |||
| */ | |||
| public class JasperC | |||
| extends DefaultCompilerAdapter | |||
| { | |||
| /* | |||
| * ------------------------------------------------------------ | |||
| */ | |||
| public boolean execute() | |||
| throws TaskException | |||
| { | |||
| getTaskContext().debug( "Using jasper compiler" ); | |||
| final ExecuteJava exe = new ExecuteJava(); | |||
| exe.setClassName( "org.apache.jasper.JspC" ); | |||
| if( getJspc().getClasspath() != null ) | |||
| { | |||
| exe.getClassPath().add( getJspc().getClasspath() ); | |||
| } | |||
| setupJasperCommand( exe.getArguments() ); | |||
| // Create an instance of the compiler, redirecting output to | |||
| // the project log | |||
| exe.execute( getTaskContext() ); | |||
| return true; | |||
| } | |||
| /* | |||
| * ------------------------------------------------------------ | |||
| */ | |||
| private void setupJasperCommand( final ArgumentList cmd ) | |||
| throws TaskException | |||
| { | |||
| JspC jspc = getJspc(); | |||
| if( jspc.getDestdir() != null ) | |||
| { | |||
| cmd.addArgument( "-d" ); | |||
| cmd.addArgument( jspc.getDestdir() ); | |||
| } | |||
| if( jspc.getPackage() != null ) | |||
| { | |||
| cmd.addArgument( "-p" ); | |||
| cmd.addArgument( jspc.getPackage() ); | |||
| } | |||
| if( jspc.getVerbose() != 0 ) | |||
| { | |||
| cmd.addArgument( "-v" + jspc.getVerbose() ); | |||
| } | |||
| if( jspc.isMapped() ) | |||
| { | |||
| cmd.addArgument( "-mapped" ); | |||
| } | |||
| if( jspc.getIeplugin() != null ) | |||
| { | |||
| cmd.addArgument( "-ieplugin" ); | |||
| cmd.addArgument( jspc.getIeplugin() ); | |||
| } | |||
| if( jspc.getUriroot() != null ) | |||
| { | |||
| cmd.addArgument( "-uriroot" ); | |||
| cmd.addArgument( jspc.getUriroot().toString() ); | |||
| } | |||
| if( jspc.getUribase() != null ) | |||
| { | |||
| cmd.addArgument( "-uribase" ); | |||
| cmd.addArgument( jspc.getUribase().toString() ); | |||
| } | |||
| logAndAddFilesToCompile( getJspc(), getJspc().getCompileList(), cmd ); | |||
| } | |||
| } | |||
| @@ -1,230 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.junit; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.FileNotFoundException; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.net.URL; | |||
| import javax.xml.parsers.DocumentBuilder; | |||
| import javax.xml.parsers.DocumentBuilderFactory; | |||
| import org.apache.avalon.excalibur.io.FileUtil; | |||
| import org.apache.myrmidon.api.TaskContext; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.tools.todo.types.EnumeratedAttribute; | |||
| import org.w3c.dom.Document; | |||
| /** | |||
| * 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. | |||
| * | |||
| * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a> | |||
| */ | |||
| public class AggregateTransformer | |||
| { | |||
| public final static String FRAMES = "frames"; | |||
| public final static String NOFRAMES = "noframes"; | |||
| /** | |||
| * XML Parser factory | |||
| */ | |||
| private final static DocumentBuilderFactory c_dbfactory = DocumentBuilderFactory.newInstance(); | |||
| /** | |||
| * the xml document to process | |||
| */ | |||
| private Document m_document; | |||
| /** | |||
| * the format to use for the report. Must be <tt>FRAMES</tt> or <tt>NOFRAMES | |||
| * </tt> | |||
| */ | |||
| private String m_format; | |||
| /** | |||
| * the style directory. XSLs should be read from here if necessary | |||
| */ | |||
| private File m_styleDir; | |||
| private TaskContext m_context; | |||
| /** | |||
| * the destination directory, this is the root from where html should be | |||
| * generated | |||
| */ | |||
| private File m_toDir; | |||
| public AggregateTransformer( TaskContext context ) | |||
| { | |||
| m_context = context; | |||
| } | |||
| public void setFormat( Format format ) | |||
| { | |||
| m_format = format.getValue(); | |||
| } | |||
| /** | |||
| * 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 ) | |||
| { | |||
| m_styleDir = styledir; | |||
| } | |||
| /** | |||
| * set the destination directory | |||
| * | |||
| * @param todir The new Todir value | |||
| */ | |||
| public void setTodir( File todir ) | |||
| { | |||
| m_toDir = todir; | |||
| } | |||
| public void setXmlDocument( Document doc ) | |||
| { | |||
| m_document = doc; | |||
| } | |||
| public void transform() | |||
| throws TaskException | |||
| { | |||
| checkOptions(); | |||
| try | |||
| { | |||
| XalanExecutor executor = XalanExecutor.newInstance( this ); | |||
| executor.execute(); | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| throw new TaskException( "Errors while applying transformations", e ); | |||
| } | |||
| //task.getLogger().info( "Transform time: " + dt + "ms" ); | |||
| } | |||
| /** | |||
| * 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 | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| protected void setXmlfile( File xmlfile ) | |||
| throws TaskException | |||
| { | |||
| try | |||
| { | |||
| DocumentBuilder builder = c_dbfactory.newDocumentBuilder(); | |||
| InputStream in = new FileInputStream( xmlfile ); | |||
| try | |||
| { | |||
| Document doc = builder.parse( in ); | |||
| setXmlDocument( doc ); | |||
| } | |||
| finally | |||
| { | |||
| in.close(); | |||
| } | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| throw new TaskException( "Error while parsing document: " + xmlfile, e ); | |||
| } | |||
| } | |||
| /** | |||
| * 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 The StylesheetSystemId value | |||
| * @throws IOException thrown if the requested stylesheet does not exist. | |||
| */ | |||
| protected String getStylesheetSystemId() | |||
| throws IOException | |||
| { | |||
| String xslname = "junit-frames.xsl"; | |||
| if( NOFRAMES.equals( m_format ) ) | |||
| { | |||
| xslname = "junit-noframes.xsl"; | |||
| } | |||
| URL url = null; | |||
| if( m_styleDir == null ) | |||
| { | |||
| url = getClass().getResource( "xsl/" + xslname ); | |||
| if( url == null ) | |||
| { | |||
| throw new FileNotFoundException( "Could not find jar resource " + xslname ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| File file = new File( m_styleDir, xslname ); | |||
| if( !file.exists() ) | |||
| { | |||
| throw new FileNotFoundException( "Could not find file '" + file + "'" ); | |||
| } | |||
| url = new URL( "file", "", file.getAbsolutePath() ); | |||
| } | |||
| return url.toExternalForm(); | |||
| } | |||
| /** | |||
| * check for invalid options | |||
| * | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| protected void checkOptions() | |||
| throws TaskException | |||
| { | |||
| // set the destination directory relative from the project if needed. | |||
| if( m_toDir == null ) | |||
| { | |||
| m_toDir = FileUtil.resolveFile( m_context.getBaseDirectory(), "." ); | |||
| } | |||
| else if( !m_toDir.isAbsolute() ) | |||
| { | |||
| m_toDir = FileUtil.resolveFile( m_context.getBaseDirectory(), m_toDir.getPath() ); | |||
| } | |||
| } | |||
| protected Document getDocument() | |||
| { | |||
| return m_document; | |||
| } | |||
| protected String getFormat() | |||
| { | |||
| return m_format; | |||
| } | |||
| protected File getToDir() | |||
| { | |||
| return m_toDir; | |||
| } | |||
| public static class Format extends EnumeratedAttribute | |||
| { | |||
| public String[] getValues() | |||
| { | |||
| return new String[]{FRAMES, NOFRAMES}; | |||
| } | |||
| } | |||
| } | |||
| @@ -1,133 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.junit; | |||
| import java.io.File; | |||
| import java.util.ArrayList; | |||
| /** | |||
| * Baseclass for BatchTest and JUnitTest. | |||
| * | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:sbailliez@imediation.com">Stephane Bailliez</a> | |||
| */ | |||
| public abstract class BaseTest | |||
| { | |||
| protected boolean m_haltOnError = false; | |||
| protected boolean m_haltOnFail = false; | |||
| protected boolean m_filtertrace = true; | |||
| protected boolean fork = false; | |||
| protected String ifProperty = null; | |||
| protected String unlessProperty = null; | |||
| protected ArrayList formatters = new ArrayList(); | |||
| /** | |||
| * destination directory | |||
| */ | |||
| protected File destDir = null; | |||
| protected String errorProperty; | |||
| protected String failureProperty; | |||
| public void setErrorProperty( String errorProperty ) | |||
| { | |||
| this.errorProperty = errorProperty; | |||
| } | |||
| public void setFailureProperty( String failureProperty ) | |||
| { | |||
| this.failureProperty = failureProperty; | |||
| } | |||
| public void setFiltertrace( boolean value ) | |||
| { | |||
| m_filtertrace = value; | |||
| } | |||
| public void setFork( boolean value ) | |||
| { | |||
| fork = value; | |||
| } | |||
| public void setHaltonerror( boolean value ) | |||
| { | |||
| m_haltOnError = value; | |||
| } | |||
| public void setHaltonfailure( boolean value ) | |||
| { | |||
| m_haltOnFail = value; | |||
| } | |||
| public void setIf( String propertyName ) | |||
| { | |||
| ifProperty = propertyName; | |||
| } | |||
| /** | |||
| * Sets the destination directory. | |||
| * | |||
| * @param destDir The new Todir value | |||
| */ | |||
| public void setTodir( File destDir ) | |||
| { | |||
| this.destDir = destDir; | |||
| } | |||
| public void setUnless( String propertyName ) | |||
| { | |||
| unlessProperty = propertyName; | |||
| } | |||
| public java.lang.String getErrorProperty() | |||
| { | |||
| return errorProperty; | |||
| } | |||
| public java.lang.String getFailureProperty() | |||
| { | |||
| return failureProperty; | |||
| } | |||
| public boolean getFiltertrace() | |||
| { | |||
| return m_filtertrace; | |||
| } | |||
| public boolean getFork() | |||
| { | |||
| return fork; | |||
| } | |||
| public boolean getHaltonerror() | |||
| { | |||
| return m_haltOnError; | |||
| } | |||
| public boolean getHaltonfailure() | |||
| { | |||
| return m_haltOnFail; | |||
| } | |||
| /** | |||
| * @return the destination directory as an absolute path if it exists | |||
| * otherwise return <tt>null</tt> | |||
| */ | |||
| public String getTodir() | |||
| { | |||
| if( destDir != null ) | |||
| { | |||
| return destDir.getAbsolutePath(); | |||
| } | |||
| return null; | |||
| } | |||
| public void addFormatter( FormatterElement elem ) | |||
| { | |||
| formatters.add( elem ); | |||
| } | |||
| } | |||
| @@ -1,187 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.junit; | |||
| import java.io.File; | |||
| import java.util.ArrayList; | |||
| import java.util.Arrays; | |||
| import java.util.Iterator; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.FileSet; | |||
| import org.apache.tools.todo.types.DirectoryScanner; | |||
| import org.apache.tools.todo.types.ScannerUtil; | |||
| /** | |||
| * <p> | |||
| * | |||
| * Create then run <code>JUnitTest</code>'s based on the list of files given by | |||
| * the fileset attribute. <p> | |||
| * | |||
| * Every <code>.java</code> or <code>.class</code> file in the fileset is | |||
| * assumed to be a testcase. A <code>JUnitTest</code> is created for each of | |||
| * these named classes with basic setup inherited from the parent <code>BatchTest</code> | |||
| * . | |||
| * | |||
| * @author <a href="mailto:jeff.martin@synamic.co.uk">Jeff Martin</a> | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:sbailliez@imediation.com">Stephane Bailliez</a> | |||
| * @see JUnitTest | |||
| */ | |||
| public final class BatchTest extends BaseTest | |||
| { | |||
| /** | |||
| * the list of filesets containing the testcase filename rules | |||
| */ | |||
| private ArrayList filesets = new ArrayList(); | |||
| /** | |||
| * Convenient method to convert a pathname without extension to a fully | |||
| * qualified classname. For example <tt>org/apache/Whatever</tt> will be | |||
| * converted to <tt>org.apache.Whatever</tt> | |||
| * | |||
| * @param filename the filename to "convert" to a classname. | |||
| * @return the classname matching the filename. | |||
| */ | |||
| public static final String javaToClass( String filename ) | |||
| { | |||
| return filename.replace( File.separatorChar, '.' ); | |||
| } | |||
| /** | |||
| * Return all <tt>JUnitTest</tt> instances obtain by applying the fileset | |||
| * rules. | |||
| * | |||
| * @return an enumeration of all elements of this batchtest that are a <tt> | |||
| * JUnitTest</tt> instance. | |||
| */ | |||
| public final Iterator iterator() | |||
| throws TaskException | |||
| { | |||
| final JUnitTest[] tests = createAllJUnitTest(); | |||
| return Arrays.asList( tests ).iterator(); | |||
| } | |||
| /** | |||
| * Add a new fileset instance to this batchtest. Whatever the fileset is, | |||
| * only filename that are <tt>.java</tt> or <tt>.class</tt> will be | |||
| * considered as 'candidates'. | |||
| * | |||
| * @param fs the new fileset containing the rules to get the testcases. | |||
| */ | |||
| public void addFileSet( FileSet fs ) | |||
| { | |||
| filesets.add( fs ); | |||
| } | |||
| /** | |||
| * Convenient method to merge the <tt>JUnitTest</tt> s of this batchtest to | |||
| * a <tt>ArrayList</tt> . | |||
| * | |||
| * @param v the vector to which should be added all individual tests of this | |||
| * batch test. | |||
| */ | |||
| final void addTestsTo( ArrayList v ) | |||
| throws TaskException | |||
| { | |||
| final JUnitTest[] tests = createAllJUnitTest(); | |||
| v.ensureCapacity( v.size() + tests.length ); | |||
| for( int i = 0; i < tests.length; i++ ) | |||
| { | |||
| v.add( tests[ i ] ); | |||
| } | |||
| } | |||
| /** | |||
| * Iterate over all filesets and return the filename of all files that end | |||
| * with <tt>.java</tt> or <tt>.class</tt> . This is to avoid wrapping a <tt> | |||
| * JUnitTest</tt> over an xml file for example. A Testcase is obviously a | |||
| * java file (compiled or not). | |||
| * | |||
| * @return an array of filenames without their extension. As they should | |||
| * normally be taken from their root, filenames should match their | |||
| * fully qualified class name (If it is not the case it will fail when | |||
| * running the test). For the class <tt>org/apache/Whatever.class</tt> | |||
| * it will return <tt>org/apache/Whatever</tt> . | |||
| */ | |||
| private String[] getFilenames() | |||
| throws TaskException | |||
| { | |||
| ArrayList v = new ArrayList(); | |||
| final int size = this.filesets.size(); | |||
| for( int j = 0; j < size; j++ ) | |||
| { | |||
| FileSet fs = (FileSet)filesets.get( j ); | |||
| DirectoryScanner ds = ScannerUtil.getDirectoryScanner( fs ); | |||
| ds.scan(); | |||
| String[] f = ds.getIncludedFiles(); | |||
| for( int k = 0; k < f.length; k++ ) | |||
| { | |||
| String pathname = f[ k ]; | |||
| if( pathname.endsWith( ".java" ) ) | |||
| { | |||
| v.add( pathname.substring( 0, pathname.length() - ".java".length() ) ); | |||
| } | |||
| else if( pathname.endsWith( ".class" ) ) | |||
| { | |||
| v.add( pathname.substring( 0, pathname.length() - ".class".length() ) ); | |||
| } | |||
| } | |||
| } | |||
| return (String[])v.toArray( new String[ v.size() ] ); | |||
| } | |||
| /** | |||
| * Create all <tt>JUnitTest</tt> s based on the filesets. Each instance is | |||
| * configured to match this instance properties. | |||
| * | |||
| * @return the array of all <tt>JUnitTest</tt> s that belongs to this batch. | |||
| */ | |||
| private JUnitTest[] createAllJUnitTest() | |||
| throws TaskException | |||
| { | |||
| String[] filenames = getFilenames(); | |||
| JUnitTest[] tests = new JUnitTest[ filenames.length ]; | |||
| for( int i = 0; i < tests.length; i++ ) | |||
| { | |||
| String classname = javaToClass( filenames[ i ] ); | |||
| tests[ i ] = createJUnitTest( classname ); | |||
| } | |||
| return tests; | |||
| } | |||
| /** | |||
| * Create a <tt>JUnitTest</tt> that has the same property as this <tt> | |||
| * BatchTest</tt> instance. | |||
| * | |||
| * @param classname the name of the class that should be run as a <tt> | |||
| * JUnitTest</tt> . It must be a fully qualified name. | |||
| * @return the <tt>JUnitTest</tt> over the given classname. | |||
| */ | |||
| private JUnitTest createJUnitTest( String classname ) | |||
| { | |||
| JUnitTest test = new JUnitTest(); | |||
| test.setName( classname ); | |||
| test.setHaltonerror( this.m_haltOnError ); | |||
| test.setHaltonfailure( this.m_haltOnFail ); | |||
| test.setFiltertrace( this.m_filtertrace ); | |||
| test.setFork( this.fork ); | |||
| test.setIf( this.ifProperty ); | |||
| test.setUnless( this.unlessProperty ); | |||
| test.setTodir( this.destDir ); | |||
| test.setFailureProperty( failureProperty ); | |||
| test.setErrorProperty( errorProperty ); | |||
| Iterator list = this.formatters.iterator(); | |||
| while( list.hasNext() ) | |||
| { | |||
| test.addFormatter( (FormatterElement)list.next() ); | |||
| } | |||
| return test; | |||
| } | |||
| } | |||
| @@ -1,272 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.junit; | |||
| import junit.framework.AssertionFailedError; | |||
| import junit.framework.Test; | |||
| import org.apache.avalon.excalibur.util.StringUtil; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| /** | |||
| * Prints plain text output of the test to a specified Writer. Inspired by the | |||
| * PlainJUnitResultFormatter. | |||
| * | |||
| * @author <a href="mailto:robertdw@bigpond.net.au">Robert Watkins</a> | |||
| * @see FormatterElement | |||
| * @see PlainJUnitResultFormatter | |||
| */ | |||
| public class BriefJUnitResultFormatter implements JUnitResultFormatter | |||
| { | |||
| /** | |||
| * Formatter for timings. | |||
| */ | |||
| private java.text.NumberFormat m_numberFormat = java.text.NumberFormat.getInstance(); | |||
| /** | |||
| * Output suite has written to System.out | |||
| */ | |||
| private String systemOutput = null; | |||
| /** | |||
| * Output suite has written to System.err | |||
| */ | |||
| private String systemError = null; | |||
| /** | |||
| * Where to write the log to. | |||
| */ | |||
| private java.io.OutputStream m_out; | |||
| /** | |||
| * Used for writing the results. | |||
| */ | |||
| private java.io.PrintWriter m_output; | |||
| /** | |||
| * Used for writing formatted results to. | |||
| */ | |||
| private java.io.PrintWriter m_resultWriter; | |||
| /** | |||
| * Used as part of formatting the results. | |||
| */ | |||
| private java.io.StringWriter m_results; | |||
| public BriefJUnitResultFormatter() | |||
| { | |||
| m_results = new java.io.StringWriter(); | |||
| m_resultWriter = new java.io.PrintWriter( m_results ); | |||
| } | |||
| /** | |||
| * Sets the stream the formatter is supposed to write its results to. | |||
| * | |||
| * @param out The new Output value | |||
| */ | |||
| public void setOutput( java.io.OutputStream out ) | |||
| { | |||
| m_out = out; | |||
| m_output = new java.io.PrintWriter( out ); | |||
| } | |||
| public void setSystemError( String err ) | |||
| { | |||
| systemError = err; | |||
| } | |||
| public void setSystemOutput( String out ) | |||
| { | |||
| systemOutput = out; | |||
| } | |||
| /** | |||
| * A test caused an error. | |||
| * | |||
| * @param test The feature to be added to the Error attribute | |||
| * @param error The feature to be added to the Error attribute | |||
| */ | |||
| public void addError( Test test, Throwable error ) | |||
| { | |||
| formatError( "\tCaused an ERROR", test, error ); | |||
| } | |||
| /** | |||
| * Interface TestListener for JUnit <= 3.4. <p> | |||
| * | |||
| * A Test failed. | |||
| * | |||
| * @param test The feature to be added to the Failure attribute | |||
| * @param t The feature to be added to the Failure attribute | |||
| */ | |||
| public void addFailure( Test test, Throwable t ) | |||
| { | |||
| formatError( "\tFAILED", test, t ); | |||
| } | |||
| /** | |||
| * Interface TestListener for JUnit > 3.4. <p> | |||
| * | |||
| * A Test failed. | |||
| * | |||
| * @param test The feature to be added to the Failure attribute | |||
| * @param t The feature to be added to the Failure attribute | |||
| */ | |||
| public void addFailure( Test test, AssertionFailedError t ) | |||
| { | |||
| addFailure( test, (Throwable)t ); | |||
| } | |||
| /** | |||
| * A test ended. | |||
| * | |||
| * @param test Description of Parameter | |||
| */ | |||
| public void endTest( Test test ) | |||
| { | |||
| } | |||
| /** | |||
| * The whole testsuite ended. | |||
| * | |||
| * @param suite Description of Parameter | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| public void endTestSuite( JUnitTest suite ) | |||
| throws TaskException | |||
| { | |||
| final StringBuffer sb = new StringBuffer( "Testsuite: " ); | |||
| sb.append( suite.getName() ); | |||
| sb.append( StringUtil.LINE_SEPARATOR ); | |||
| sb.append( "Tests run: " ); | |||
| sb.append( suite.runCount() ); | |||
| sb.append( ", Failures: " ); | |||
| sb.append( suite.failureCount() ); | |||
| sb.append( ", Errors: " ); | |||
| sb.append( suite.errorCount() ); | |||
| sb.append( ", Time elapsed: " ); | |||
| sb.append( m_numberFormat.format( suite.getRunTime() / 1000.0 ) ); | |||
| sb.append( " sec" ); | |||
| sb.append( StringUtil.LINE_SEPARATOR ); | |||
| sb.append( StringUtil.LINE_SEPARATOR ); | |||
| // append the err and output streams to the log | |||
| if( systemOutput != null && systemOutput.length() > 0 ) | |||
| { | |||
| sb.append( "------------- Standard Output ---------------" ) | |||
| .append( StringUtil.LINE_SEPARATOR ) | |||
| .append( systemOutput ) | |||
| .append( "------------- ---------------- ---------------" ) | |||
| .append( StringUtil.LINE_SEPARATOR ); | |||
| } | |||
| if( systemError != null && systemError.length() > 0 ) | |||
| { | |||
| sb.append( "------------- Standard Error -----------------" ) | |||
| .append( StringUtil.LINE_SEPARATOR ) | |||
| .append( systemError ) | |||
| .append( "------------- ---------------- ---------------" ) | |||
| .append( StringUtil.LINE_SEPARATOR ); | |||
| } | |||
| if( output() != null ) | |||
| { | |||
| try | |||
| { | |||
| output().write( sb.toString() ); | |||
| resultWriter().close(); | |||
| output().write( m_results.toString() ); | |||
| output().flush(); | |||
| } | |||
| finally | |||
| { | |||
| if( m_out != (Object)System.out && | |||
| m_out != (Object)System.err ) | |||
| { | |||
| try | |||
| { | |||
| m_out.close(); | |||
| } | |||
| catch( java.io.IOException e ) | |||
| { | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * A test started. | |||
| * | |||
| * @param test Description of Parameter | |||
| */ | |||
| public void startTest( Test test ) | |||
| { | |||
| } | |||
| /** | |||
| * The whole testsuite started. | |||
| * | |||
| * @param suite Description of Parameter | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| public void startTestSuite( JUnitTest suite ) | |||
| throws TaskException | |||
| { | |||
| } | |||
| /** | |||
| * Format an error and print it. | |||
| * | |||
| * @param type Description of Parameter | |||
| * @param test Description of Parameter | |||
| * @param error Description of Parameter | |||
| */ | |||
| protected synchronized void formatError( String type, Test test, | |||
| Throwable error ) | |||
| { | |||
| if( test != null ) | |||
| { | |||
| endTest( test ); | |||
| } | |||
| resultWriter().println( formatTest( test ) + type ); | |||
| resultWriter().println( error.getMessage() ); | |||
| String strace = JUnitTestRunner.getFilteredTrace( error ); | |||
| resultWriter().println( strace ); | |||
| resultWriter().println( "" ); | |||
| } | |||
| /** | |||
| * Format the test for printing.. | |||
| * | |||
| * @param test Description of Parameter | |||
| * @return Description of the Returned Value | |||
| */ | |||
| protected String formatTest( Test test ) | |||
| { | |||
| if( test == null ) | |||
| { | |||
| return "Null Test: "; | |||
| } | |||
| else | |||
| { | |||
| return "Testcase: " + test.toString() + ":"; | |||
| } | |||
| } | |||
| protected java.io.PrintWriter output() | |||
| { | |||
| return m_output; | |||
| } | |||
| protected java.io.PrintWriter resultWriter() | |||
| { | |||
| return m_resultWriter; | |||
| } | |||
| } | |||
| @@ -1,100 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.junit; | |||
| import java.util.Iterator; | |||
| import java.util.NoSuchElementException; | |||
| /** | |||
| * Convenient enumeration over an array of enumeration. For example: <pre> | |||
| * Iterator e1 = v1.iterator(); | |||
| * while (e1.hasNext()){ | |||
| * // do something | |||
| * } | |||
| * Iterator e2 = v2.iterator(); | |||
| * while (e2.hasNext()){ | |||
| * // do the same thing | |||
| * } | |||
| * </pre> can be written as: <pre> | |||
| * Iterator[] enums = { v1.iterator(), v2.iterator() }; | |||
| * Iterator e = Iterators.fromCompound(enums); | |||
| * while (e.hasNext()){ | |||
| * // do something | |||
| * } | |||
| * </pre> Note that the enumeration will skip null elements in the array. The | |||
| * following is thus possible: <pre> | |||
| * Iterator[] enums = { v1.iterator(), null, v2.iterator() }; // a null enumeration in the array | |||
| * Iterator e = Iterators.fromCompound(enums); | |||
| * while (e.hasNext()){ | |||
| * // do something | |||
| * } | |||
| * </pre> | |||
| * | |||
| * @author <a href="mailto:sbailliez@imediation.com">Stephane Bailliez</a> | |||
| */ | |||
| class CompoundIterator | |||
| implements Iterator | |||
| { | |||
| /** | |||
| * index in the enums array | |||
| */ | |||
| private int index = 0; | |||
| /** | |||
| * enumeration array | |||
| */ | |||
| private Iterator[] enumArray; | |||
| public CompoundIterator( Iterator[] enumarray ) | |||
| { | |||
| this.enumArray = enumarray; | |||
| } | |||
| /** | |||
| * Tests if this enumeration contains more elements. | |||
| * | |||
| * @return <code>true</code> if and only if this enumeration object contains | |||
| * at least one more element to provide; <code>false</code> otherwise. | |||
| */ | |||
| public boolean hasNext() | |||
| { | |||
| while( index < enumArray.length ) | |||
| { | |||
| if( enumArray[ index ] != null && enumArray[ index ].hasNext() ) | |||
| { | |||
| return true; | |||
| } | |||
| index++; | |||
| } | |||
| return false; | |||
| } | |||
| /** | |||
| * Returns the next element of this enumeration if this enumeration object | |||
| * has at least one more element to provide. | |||
| * | |||
| * @return the next element of this enumeration. | |||
| * @throws NoSuchElementException if no more elements exist. | |||
| */ | |||
| public Object next() | |||
| throws NoSuchElementException | |||
| { | |||
| if( hasNext() ) | |||
| { | |||
| return enumArray[ index ].next(); | |||
| } | |||
| throw new NoSuchElementException(); | |||
| } | |||
| public void remove() | |||
| throws UnsupportedOperationException | |||
| { | |||
| throw new UnsupportedOperationException(); | |||
| } | |||
| } | |||
| @@ -1,239 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.junit; | |||
| import java.io.IOException; | |||
| import java.io.Writer; | |||
| import org.apache.avalon.excalibur.util.StringUtil; | |||
| import org.w3c.dom.Attr; | |||
| import org.w3c.dom.Element; | |||
| import org.w3c.dom.NamedNodeMap; | |||
| import org.w3c.dom.Node; | |||
| import org.w3c.dom.NodeList; | |||
| import org.w3c.dom.Text; | |||
| /** | |||
| * Writes a DOM tree to a given Writer. <p> | |||
| * | |||
| * Utility class used by {@link org.apache.tools.ant.XmlLogger XmlLogger} and | |||
| * org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter | |||
| * XMLJUnitResultFormatter}.</p> | |||
| * | |||
| * @author The original author of XmlLogger | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:sbailliez@imediation.com">Stephane Bailliez</tt> | |||
| */ | |||
| public class DOMElementWriter | |||
| { | |||
| private StringBuffer sb = new StringBuffer(); | |||
| /** | |||
| * Don't try to be too smart but at least recognize the predefined entities. | |||
| */ | |||
| protected String[] knownEntities = {"gt", "amp", "lt", "apos", "quot"}; | |||
| /** | |||
| * Is the given argument a character or entity reference? | |||
| * | |||
| * @param ent Description of Parameter | |||
| * @return The Reference value | |||
| */ | |||
| public boolean isReference( String ent ) | |||
| { | |||
| if( !( ent.charAt( 0 ) == '&' ) || !ent.endsWith( ";" ) ) | |||
| { | |||
| return false; | |||
| } | |||
| if( ent.charAt( 1 ) == '#' ) | |||
| { | |||
| if( ent.charAt( 2 ) == 'x' ) | |||
| { | |||
| try | |||
| { | |||
| Integer.parseInt( ent.substring( 3, ent.length() - 1 ), 16 ); | |||
| return true; | |||
| } | |||
| catch( NumberFormatException nfe ) | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| try | |||
| { | |||
| Integer.parseInt( ent.substring( 2, ent.length() - 1 ) ); | |||
| return true; | |||
| } | |||
| catch( NumberFormatException nfe ) | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| } | |||
| String name = ent.substring( 1, ent.length() - 1 ); | |||
| for( int i = 0; i < knownEntities.length; i++ ) | |||
| { | |||
| if( name.equals( knownEntities[ i ] ) ) | |||
| { | |||
| return true; | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| /** | |||
| * Escape <, > & ' and " as their entities. | |||
| * | |||
| * @param value Description of Parameter | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public String encode( String value ) | |||
| { | |||
| sb.setLength( 0 ); | |||
| for( int i = 0; i < value.length(); i++ ) | |||
| { | |||
| char c = value.charAt( i ); | |||
| switch( c ) | |||
| { | |||
| case '<': | |||
| sb.append( "<" ); | |||
| break; | |||
| case '>': | |||
| sb.append( ">" ); | |||
| break; | |||
| case '\'': | |||
| sb.append( "'" ); | |||
| break; | |||
| case '\"': | |||
| sb.append( """ ); | |||
| break; | |||
| case '&': | |||
| int nextSemi = value.indexOf( ";", i ); | |||
| if( nextSemi < 0 | |||
| || !isReference( value.substring( i, nextSemi + 1 ) ) ) | |||
| { | |||
| sb.append( "&" ); | |||
| } | |||
| else | |||
| { | |||
| sb.append( '&' ); | |||
| } | |||
| break; | |||
| default: | |||
| sb.append( c ); | |||
| break; | |||
| } | |||
| } | |||
| return sb.toString(); | |||
| } | |||
| /** | |||
| * Writes a DOM tree to a stream. | |||
| * | |||
| * @param element the Root DOM element of the tree | |||
| * @param out where to send the output | |||
| * @param indent number of | |||
| * @param indentWith strings, that should be used to indent the | |||
| * corresponding tag. | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| public void write( Element element, Writer out, int indent, | |||
| String indentWith ) | |||
| throws IOException | |||
| { | |||
| // Write indent characters | |||
| for( int i = 0; i < indent; i++ ) | |||
| { | |||
| out.write( indentWith ); | |||
| } | |||
| // Write element | |||
| out.write( "<" ); | |||
| out.write( element.getTagName() ); | |||
| // Write attributes | |||
| NamedNodeMap attrs = element.getAttributes(); | |||
| for( int i = 0; i < attrs.getLength(); i++ ) | |||
| { | |||
| Attr attr = (Attr)attrs.item( i ); | |||
| out.write( " " ); | |||
| out.write( attr.getName() ); | |||
| out.write( "=\"" ); | |||
| out.write( encode( attr.getValue() ) ); | |||
| out.write( "\"" ); | |||
| } | |||
| out.write( ">" ); | |||
| // Write child elements and text | |||
| boolean hasChildren = false; | |||
| NodeList children = element.getChildNodes(); | |||
| for( int i = 0; i < children.getLength(); i++ ) | |||
| { | |||
| Node child = children.item( i ); | |||
| switch( child.getNodeType() ) | |||
| { | |||
| case Node.ELEMENT_NODE: | |||
| if( !hasChildren ) | |||
| { | |||
| out.write( StringUtil.LINE_SEPARATOR ); | |||
| hasChildren = true; | |||
| } | |||
| write( (Element)child, out, indent + 1, indentWith ); | |||
| break; | |||
| case Node.TEXT_NODE: | |||
| out.write( encode( child.getNodeValue() ) ); | |||
| break; | |||
| case Node.CDATA_SECTION_NODE: | |||
| out.write( "<![CDATA[" ); | |||
| out.write( ( (Text)child ).getData() ); | |||
| out.write( "]]>" ); | |||
| break; | |||
| case Node.ENTITY_REFERENCE_NODE: | |||
| out.write( '&' ); | |||
| out.write( child.getNodeName() ); | |||
| out.write( ';' ); | |||
| break; | |||
| case Node.PROCESSING_INSTRUCTION_NODE: | |||
| out.write( "<?" ); | |||
| out.write( child.getNodeName() ); | |||
| String data = child.getNodeValue(); | |||
| if( data != null && data.length() > 0 ) | |||
| { | |||
| out.write( ' ' ); | |||
| out.write( data ); | |||
| } | |||
| out.write( "?>" ); | |||
| break; | |||
| } | |||
| } | |||
| // If we had child elements, we need to indent before we close | |||
| // the element, otherwise we're on the same line and don't need | |||
| // to indent | |||
| if( hasChildren ) | |||
| { | |||
| for( int i = 0; i < indent; i++ ) | |||
| { | |||
| out.write( indentWith ); | |||
| } | |||
| } | |||
| // Write element close | |||
| out.write( "</" ); | |||
| out.write( element.getTagName() ); | |||
| out.write( ">" ); | |||
| out.write( StringUtil.LINE_SEPARATOR ); | |||
| out.flush(); | |||
| } | |||
| } | |||
| @@ -1,226 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.junit; | |||
| import org.w3c.dom.Attr; | |||
| import org.w3c.dom.CDATASection; | |||
| import org.w3c.dom.Comment; | |||
| import org.w3c.dom.DOMException; | |||
| import org.w3c.dom.Document; | |||
| import org.w3c.dom.Element; | |||
| import org.w3c.dom.NamedNodeMap; | |||
| import org.w3c.dom.Node; | |||
| import org.w3c.dom.NodeList; | |||
| import org.w3c.dom.ProcessingInstruction; | |||
| import org.w3c.dom.Text; | |||
| /** | |||
| * Some utilities that might be useful when manipulating DOM trees. | |||
| * | |||
| * @author <a href="bailliez@noos.fr">Stephane Bailliez</a> | |||
| */ | |||
| public final class DOMUtil | |||
| { | |||
| /** | |||
| * unused constructor | |||
| */ | |||
| private DOMUtil() | |||
| { | |||
| } | |||
| /** | |||
| * Iterate over the children of a given node and return the first node that | |||
| * has a specific name. | |||
| * | |||
| * @param parent the node to search child from. Can be <tt>null</tt> . | |||
| * @param tagname the child name we are looking for. Cannot be <tt>null</tt> | |||
| * . | |||
| * @return the first child that matches the given name or <tt>null</tt> if | |||
| * the parent is <tt>null</tt> or if a child does not match the given | |||
| * name. | |||
| */ | |||
| public static Element getChildByTagName( Node parent, String tagname ) | |||
| { | |||
| if( parent == null ) | |||
| { | |||
| return null; | |||
| } | |||
| NodeList childList = parent.getChildNodes(); | |||
| final int len = childList.getLength(); | |||
| for( int i = 0; i < len; i++ ) | |||
| { | |||
| Node child = childList.item( i ); | |||
| if( child != null && child.getNodeType() == Node.ELEMENT_NODE && | |||
| child.getNodeName().equals( tagname ) ) | |||
| { | |||
| return (Element)child; | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| /** | |||
| * return the attribute value of an element. | |||
| * | |||
| * @param node the node to get the attribute from. | |||
| * @param name the name of the attribute we are looking for the value. | |||
| * @return the value of the requested attribute or <tt>null</tt> if the | |||
| * attribute was not found or if <tt>node</tt> is not an <tt>Element | |||
| * </tt>. | |||
| */ | |||
| public static String getNodeAttribute( Node node, String name ) | |||
| { | |||
| if( node instanceof Element ) | |||
| { | |||
| Element element = (Element)node; | |||
| return element.getAttribute( name ); | |||
| } | |||
| return null; | |||
| } | |||
| /** | |||
| * Simple tree walker that will clone recursively a node. This is to avoid | |||
| * using parser-specific API such as Sun's <tt>changeNodeOwner</tt> when we | |||
| * are dealing with DOM L1 implementations since <tt>cloneNode(boolean)</tt> | |||
| * will not change the owner document. <tt>changeNodeOwner</tt> is much | |||
| * faster and avoid the costly cloning process. <tt>importNode</tt> is in | |||
| * the DOM L2 interface. | |||
| * | |||
| * @param parent the node parent to which we should do the import to. | |||
| * @param child the node to clone recursively. Its clone will be appended to | |||
| * <tt>parent</tt> . | |||
| * @return the cloned node that is appended to <tt>parent</tt> | |||
| */ | |||
| public static final Node importNode( Node parent, Node child ) | |||
| { | |||
| Node copy = null; | |||
| final Document doc = parent.getOwnerDocument(); | |||
| switch( child.getNodeType() ) | |||
| { | |||
| case Node.CDATA_SECTION_NODE: | |||
| copy = doc.createCDATASection( ( (CDATASection)child ).getData() ); | |||
| break; | |||
| case Node.COMMENT_NODE: | |||
| copy = doc.createComment( ( (Comment)child ).getData() ); | |||
| break; | |||
| case Node.DOCUMENT_FRAGMENT_NODE: | |||
| copy = doc.createDocumentFragment(); | |||
| break; | |||
| case Node.ELEMENT_NODE: | |||
| final Element elem = doc.createElement( ( (Element)child ).getTagName() ); | |||
| copy = elem; | |||
| final NamedNodeMap attributes = child.getAttributes(); | |||
| if( attributes != null ) | |||
| { | |||
| final int size = attributes.getLength(); | |||
| for( int i = 0; i < size; i++ ) | |||
| { | |||
| final Attr attr = (Attr)attributes.item( i ); | |||
| elem.setAttribute( attr.getName(), attr.getValue() ); | |||
| } | |||
| } | |||
| break; | |||
| case Node.ENTITY_REFERENCE_NODE: | |||
| copy = doc.createEntityReference( child.getNodeName() ); | |||
| break; | |||
| case Node.PROCESSING_INSTRUCTION_NODE: | |||
| final ProcessingInstruction pi = (ProcessingInstruction)child; | |||
| copy = doc.createProcessingInstruction( pi.getTarget(), pi.getData() ); | |||
| break; | |||
| case Node.TEXT_NODE: | |||
| copy = doc.createTextNode( ( (Text)child ).getData() ); | |||
| break; | |||
| default: | |||
| // this should never happen | |||
| throw new IllegalStateException( "Invalid node type: " + child.getNodeType() ); | |||
| } | |||
| // okay we have a copy of the child, now the child becomes the parent | |||
| // and we are iterating recursively over its children. | |||
| try | |||
| { | |||
| final NodeList children = child.getChildNodes(); | |||
| if( children != null ) | |||
| { | |||
| final int size = children.getLength(); | |||
| for( int i = 0; i < size; i++ ) | |||
| { | |||
| final Node newChild = children.item( i ); | |||
| if( newChild != null ) | |||
| { | |||
| importNode( copy, newChild ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| catch( DOMException ignored ) | |||
| { | |||
| } | |||
| // bingo append it. (this should normally not be done here) | |||
| parent.appendChild( copy ); | |||
| return copy; | |||
| } | |||
| /** | |||
| * list a set of node that match a specific filter. The list can be made | |||
| * recursively or not. | |||
| * | |||
| * @param parent the parent node to search from | |||
| * @param filter the filter that children should match. | |||
| * @param recurse <tt>true</tt> if you want the list to be made recursively | |||
| * otherwise <tt>false</tt> . | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public static NodeList listChildNodes( Node parent, NodeFilter filter, boolean recurse ) | |||
| { | |||
| NodeListImpl matches = new NodeListImpl(); | |||
| NodeList children = parent.getChildNodes(); | |||
| if( children != null ) | |||
| { | |||
| final int len = children.getLength(); | |||
| for( int i = 0; i < len; i++ ) | |||
| { | |||
| Node child = children.item( i ); | |||
| if( filter.accept( child ) ) | |||
| { | |||
| matches.add( child ); | |||
| } | |||
| if( recurse ) | |||
| { | |||
| NodeList recmatches = listChildNodes( child, filter, recurse ); | |||
| final int reclength = matches.getLength(); | |||
| for( int j = 0; j < reclength; j++ ) | |||
| { | |||
| matches.add( recmatches.item( i ) ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| return matches; | |||
| } | |||
| /** | |||
| * Filter interface to be applied when iterating over a DOM tree. Just think | |||
| * of it like a <tt>FileFilter</tt> clone. | |||
| * | |||
| * @author RT | |||
| */ | |||
| public interface NodeFilter | |||
| { | |||
| /** | |||
| * @param node the node to check for acceptance. | |||
| * @return <tt>true</tt> if the node is accepted by this filter, | |||
| * otherwise <tt>false</tt> | |||
| */ | |||
| boolean accept( Node node ); | |||
| } | |||
| } | |||
| @@ -1,244 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.junit; | |||
| import java.io.File; | |||
| import java.io.FileOutputStream; | |||
| import java.io.OutputStream; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.tools.todo.types.EnumeratedAttribute; | |||
| /** | |||
| * <p> | |||
| * | |||
| * A wrapper for the implementations of <code>JUnitResultFormatter</code>. In | |||
| * particular, used as a nested <code><formatter></code> element in a | |||
| * <code><junit></code> task. <p> | |||
| * | |||
| * For example, <code><pre> | |||
| * <junit printsummary="no" haltonfailure="yes" fork="false"> | |||
| * <formatter type="plain" usefile="false" /> | |||
| * <test name="org.apache.ecs.InternationalCharTest" /> | |||
| * </junit></pre></code> adds a <code>plain</code> type | |||
| * implementation (<code>PlainJUnitResultFormatter</code>) to display the | |||
| * results of the test. <p> | |||
| * | |||
| * Either the <code>type</code> or the <code>classname</code> attribute must be | |||
| * set. | |||
| * | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @see JUnitTask | |||
| * @see XMLJUnitResultFormatter | |||
| * @see BriefJUnitResultFormatter | |||
| * @see PlainJUnitResultFormatter | |||
| * @see JUnitResultFormatter | |||
| */ | |||
| public class FormatterElement | |||
| { | |||
| private OutputStream out = System.out; | |||
| private boolean useFile = true; | |||
| private String classname; | |||
| private String extension; | |||
| private File outFile; | |||
| /** | |||
| * <p> | |||
| * | |||
| * Set name of class to be used as the formatter. <p> | |||
| * | |||
| * This class must implement <code>JUnitResultFormatter</code> | |||
| * | |||
| * @param classname The new Classname value | |||
| */ | |||
| public void setClassname( String classname ) | |||
| { | |||
| this.classname = classname; | |||
| } | |||
| public void setExtension( String ext ) | |||
| { | |||
| this.extension = ext; | |||
| } | |||
| /** | |||
| * <p> | |||
| * | |||
| * Set output stream for formatter to use. <p> | |||
| * | |||
| * Defaults to standard out. | |||
| * | |||
| * @param out The new Output value | |||
| */ | |||
| public void setOutput( OutputStream out ) | |||
| { | |||
| this.out = out; | |||
| } | |||
| /** | |||
| * <p> | |||
| * | |||
| * Quick way to use a standard formatter. <p> | |||
| * | |||
| * At the moment, there are three supported standard formatters. | |||
| * <ul> | |||
| * <li> The <code>xml</code> type uses a <code>XMLJUnitResultFormatter</code> | |||
| * . | |||
| * <li> The <code>brief</code> type uses a <code>BriefJUnitResultFormatter</code> | |||
| * . | |||
| * <li> The <code>plain</code> type (the default) uses a <code>PlainJUnitResultFormatter</code> | |||
| * . | |||
| * </ul> | |||
| * <p> | |||
| * | |||
| * Sets <code>classname</code> attribute - so you can't use that attribute | |||
| * if you use this one. | |||
| * | |||
| * @param type The new Type value | |||
| */ | |||
| public void setType( TypeAttribute type ) | |||
| { | |||
| if( "xml".equals( type.getValue() ) ) | |||
| { | |||
| setClassname( "org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter" ); | |||
| setExtension( ".xml" ); | |||
| } | |||
| else | |||
| { | |||
| if( "brief".equals( type.getValue() ) ) | |||
| { | |||
| setClassname( "org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter" ); | |||
| } | |||
| else | |||
| {// must be plain, ensured by TypeAttribute | |||
| setClassname( "org.apache.tools.ant.taskdefs.optional.junit.PlainJUnitResultFormatter" ); | |||
| } | |||
| setExtension( ".txt" ); | |||
| } | |||
| } | |||
| /** | |||
| * Set whether the formatter should log to file. | |||
| * | |||
| * @param useFile The new UseFile value | |||
| */ | |||
| public void setUseFile( boolean useFile ) | |||
| { | |||
| this.useFile = useFile; | |||
| } | |||
| /** | |||
| * Get name of class to be used as the formatter. | |||
| * | |||
| * @return The Classname value | |||
| */ | |||
| public String getClassname() | |||
| { | |||
| return classname; | |||
| } | |||
| public String getExtension() | |||
| { | |||
| return extension; | |||
| } | |||
| /** | |||
| * <p> | |||
| * | |||
| * Set the file which the formatte should log to. <p> | |||
| * | |||
| * Note that logging to file must be enabled . | |||
| * | |||
| * @param out The new Outfile value | |||
| */ | |||
| void setOutfile( File out ) | |||
| { | |||
| this.outFile = out; | |||
| } | |||
| /** | |||
| * Get whether the formatter should log to file. | |||
| * | |||
| * @return The UseFile value | |||
| */ | |||
| boolean getUseFile() | |||
| { | |||
| return useFile; | |||
| } | |||
| JUnitResultFormatter createFormatter() | |||
| throws TaskException | |||
| { | |||
| if( classname == null ) | |||
| { | |||
| throw new TaskException( "you must specify type or classname" ); | |||
| } | |||
| Class f = null; | |||
| try | |||
| { | |||
| f = Class.forName( classname ); | |||
| } | |||
| catch( ClassNotFoundException e ) | |||
| { | |||
| throw new TaskException( "Error", e ); | |||
| } | |||
| Object o = null; | |||
| try | |||
| { | |||
| o = f.newInstance(); | |||
| } | |||
| catch( InstantiationException e ) | |||
| { | |||
| throw new TaskException( "Error", e ); | |||
| } | |||
| catch( IllegalAccessException e ) | |||
| { | |||
| throw new TaskException( "Error", e ); | |||
| } | |||
| if( !( o instanceof JUnitResultFormatter ) ) | |||
| { | |||
| throw new TaskException( classname + " is not a JUnitResultFormatter" ); | |||
| } | |||
| JUnitResultFormatter r = (JUnitResultFormatter)o; | |||
| if( useFile && outFile != null ) | |||
| { | |||
| try | |||
| { | |||
| out = new FileOutputStream( outFile ); | |||
| } | |||
| catch( java.io.IOException e ) | |||
| { | |||
| throw new TaskException( "Error", e ); | |||
| } | |||
| } | |||
| r.setOutput( out ); | |||
| return r; | |||
| } | |||
| /** | |||
| * <p> | |||
| * | |||
| * Enumerated attribute with the values "plain", "xml" and "brief". <p> | |||
| * | |||
| * Use to enumerate options for <code>type</code> attribute. | |||
| * | |||
| * @author RT | |||
| */ | |||
| public static class TypeAttribute extends EnumeratedAttribute | |||
| { | |||
| public String[] getValues() | |||
| { | |||
| return new String[]{"plain", "xml", "brief"}; | |||
| } | |||
| } | |||
| } | |||
| @@ -1,59 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.junit; | |||
| import java.io.OutputStream; | |||
| import junit.framework.TestListener; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| /** | |||
| * This Interface describes classes that format the results of a JUnit testrun. | |||
| * | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| */ | |||
| public interface JUnitResultFormatter extends TestListener | |||
| { | |||
| /** | |||
| * The whole testsuite started. | |||
| * | |||
| * @param suite Description of Parameter | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| void startTestSuite( JUnitTest suite ) | |||
| throws TaskException; | |||
| /** | |||
| * The whole testsuite ended. | |||
| * | |||
| * @param suite Description of Parameter | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| void endTestSuite( JUnitTest suite ) | |||
| throws TaskException; | |||
| /** | |||
| * Sets the stream the formatter is supposed to write its results to. | |||
| * | |||
| * @param out The new Output value | |||
| */ | |||
| void setOutput( OutputStream out ); | |||
| /** | |||
| * This is what the test has written to System.out | |||
| * | |||
| * @param out The new SystemOutput value | |||
| */ | |||
| void setSystemOutput( String out ); | |||
| /** | |||
| * This is what the test has written to System.err | |||
| * | |||
| * @param err The new SystemError value | |||
| */ | |||
| void setSystemError( String err ); | |||
| } | |||
| @@ -1,717 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.junit; | |||
| import java.io.File; | |||
| import java.io.FileOutputStream; | |||
| import java.io.IOException; | |||
| import java.net.URL; | |||
| import java.util.ArrayList; | |||
| import java.util.Iterator; | |||
| import java.util.Properties; | |||
| import java.util.Random; | |||
| import org.apache.myrmidon.api.AbstractTask; | |||
| import org.apache.myrmidon.api.TaskContext; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.framework.file.Path; | |||
| import org.apache.myrmidon.framework.file.FileListUtil; | |||
| import org.apache.myrmidon.framework.java.ExecuteJava; | |||
| import org.apache.myrmidon.framework.nativelib.Argument; | |||
| import org.apache.myrmidon.framework.nativelib.Commandline; | |||
| import org.apache.tools.todo.types.EnumeratedAttribute; | |||
| import org.apache.myrmidon.framework.nativelib.EnvironmentData; | |||
| import org.apache.myrmidon.framework.nativelib.EnvironmentVariable; | |||
| import org.apache.tools.todo.types.SysProperties; | |||
| import org.apache.myrmidon.framework.nativelib.ArgumentList; | |||
| /** | |||
| * Ant task to run JUnit tests. <p> | |||
| * | |||
| * JUnit is a framework to create unit test. It has been initially created by | |||
| * Erich Gamma and Kent Beck. JUnit can be found at <a | |||
| * href="http://www.junit.org">http://www.junit.org</a> . <p> | |||
| * | |||
| * <code>JUnitTask</code> can run a single specific <code>JUnitTest</code> using | |||
| * the <code>test</code> element. For example, the following target <code><pre> | |||
| * <target name="test-int-chars" depends="jar-test"> | |||
| * <echo message="testing international characters"/> | |||
| * <junit printsummary="no" haltonfailure="yes" fork="false"> | |||
| * <classpath refid="classpath"/> | |||
| * <formatter type="plain" usefile="false" /> | |||
| * <test name="org.apache.ecs.InternationalCharTest" /> | |||
| * </junit> | |||
| * </target> | |||
| * </pre></code> runs a single junit test (<code>org.apache.ecs.InternationalCharTest</code> | |||
| * ) in the current VM using the path with id <code>classpath</code> as | |||
| * classpath and presents the results formatted using the standard <code>plain</code> | |||
| * formatter on the command line. <p> | |||
| * | |||
| * This task can also run batches of tests. The <code>batchtest</code> element | |||
| * creates a <code>BatchTest</code> based on a fileset. This allows, for | |||
| * example, all classes found in directory to be run as testcases. For example, | |||
| * <code><pre> | |||
| * <target name="run-tests" depends="dump-info,compile-tests" if="junit.present"> | |||
| * <junit printsummary="no" haltonfailure="yes" fork="${junit.fork}"> | |||
| * <jvmarg value="-classic"/> | |||
| * <classpath refid="tests-classpath"/> | |||
| * <sysproperty key="build.tests" value="${build.tests}"/> | |||
| * <formatter type="brief" usefile="false" /> | |||
| * <batchtest> | |||
| * <fileset dir="${tests.dir}"> | |||
| * <include name="**/*Test*" /> | |||
| * </fileset> | |||
| * </batchtest> | |||
| * </junit> | |||
| * </target> | |||
| * </pre></code> this target finds any classes with a <code>test</code> | |||
| * directory anywhere in their path (under the top <code>${tests.dir}</code>, of | |||
| * course) and creates <code>JUnitTest</code>'s for each one. <p> | |||
| * | |||
| * Of course, <code><junit></code> and <code><batch></code> elements | |||
| * can be combined for more complex tests. For an example, see the ant <code>build.xml</code> | |||
| * target <code>run-tests</code> (the second example is an edited version). <p> | |||
| * | |||
| * To spawn a new Java VM to prevent interferences between different testcases, | |||
| * you need to enable <code>fork</code>. A number of attributes and elements | |||
| * allow you to set up how this JVM runs. | |||
| * <ul> | |||
| * <li> {@link #setTimeout} property sets the maximum time allowed before a | |||
| * test is 'timed out' | |||
| * <li> {@link #setMaxmemory} property sets memory assignment for the forked | |||
| * jvm | |||
| * <li> {@link #setJvm} property allows the jvm to be specified | |||
| * <li> The <code><jvmarg></code> element sets arguements to be passed | |||
| * to the forked jvm | |||
| * </ul> | |||
| * | |||
| * | |||
| * @author Thomas Haas | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:sbailliez@imediation.com">Stephane Bailliez</a> | |||
| * @author <a href="mailto:Gerrit.Riessen@web.de">Gerrit Riessen</a> | |||
| * @author <a href="mailto:ehatcher@apache.org">Erik Hatcher</a> | |||
| * @see JUnitTest | |||
| * @see BatchTest | |||
| */ | |||
| public class JUnitTask extends AbstractTask | |||
| { | |||
| private ArrayList tests = new ArrayList(); | |||
| private ArrayList batchTests = new ArrayList(); | |||
| private ArrayList formatters = new ArrayList(); | |||
| private Integer timeout = null; | |||
| private boolean summary = false; | |||
| private String summaryValue = ""; | |||
| private JUnitTestRunner runner = null; | |||
| private File dir; | |||
| private String jvm; | |||
| private String maxMem; | |||
| private EnvironmentData sysProperties = new EnvironmentData(); | |||
| private Path classPath = new Path(); | |||
| private ArgumentList vmArgs = new Commandline(); | |||
| /** | |||
| * The directory to invoke the VM in. Ignored if no JVM is forked. | |||
| * | |||
| * @param dir the directory to invoke the JVM from. | |||
| * @see #setFork(boolean) | |||
| */ | |||
| public void setDir( final File dir ) | |||
| { | |||
| this.dir = dir; | |||
| } | |||
| /** | |||
| * Tells this task to set the named property to "true" when there is a error | |||
| * in a test. This property is applied on all BatchTest (batchtest) and | |||
| * JUnitTest (test), however, it can possibly be overriden by their own | |||
| * properties. | |||
| * | |||
| * @param propertyName The new ErrorProperty value | |||
| */ | |||
| public void setErrorProperty( String propertyName ) | |||
| { | |||
| Iterator enum = allTests(); | |||
| while( enum.hasNext() ) | |||
| { | |||
| BaseTest test = (BaseTest)enum.next(); | |||
| test.setErrorProperty( propertyName ); | |||
| } | |||
| } | |||
| /** | |||
| * Tells this task to set the named property to "true" when there is a | |||
| * failure in a test. This property is applied on all BatchTest (batchtest) | |||
| * and JUnitTest (test), however, it can possibly be overriden by their own | |||
| * properties. | |||
| * | |||
| * @param propertyName The new FailureProperty value | |||
| */ | |||
| public void setFailureProperty( String propertyName ) | |||
| { | |||
| Iterator enum = allTests(); | |||
| while( enum.hasNext() ) | |||
| { | |||
| BaseTest test = (BaseTest)enum.next(); | |||
| test.setFailureProperty( propertyName ); | |||
| } | |||
| } | |||
| /** | |||
| * Tells this task whether to smartly filter the stack frames of JUnit | |||
| * testcase errors and failures before reporting them. This property is | |||
| * applied on all BatchTest (batchtest) and JUnitTest (test) however it can | |||
| * possibly be overridden by their own properties. | |||
| * | |||
| * @param value <tt>false</tt> if it should not filter, otherwise <tt>true | |||
| * <tt> | |||
| */ | |||
| public void setFiltertrace( boolean value ) | |||
| { | |||
| Iterator enum = allTests(); | |||
| while( enum.hasNext() ) | |||
| { | |||
| BaseTest test = (BaseTest)enum.next(); | |||
| test.setFiltertrace( value ); | |||
| } | |||
| } | |||
| /** | |||
| * Tells whether a JVM should be forked for each testcase. It avoids | |||
| * interference between testcases and possibly avoids hanging the build. | |||
| * this property is applied on all BatchTest (batchtest) and JUnitTest | |||
| * (test) however it can possibly be overridden by their own properties. | |||
| * | |||
| * @param value <tt>true</tt> if a JVM should be forked, otherwise <tt>false | |||
| * </tt> | |||
| * @see #setTimeout | |||
| */ | |||
| public void setFork( boolean value ) | |||
| { | |||
| Iterator enum = allTests(); | |||
| while( enum.hasNext() ) | |||
| { | |||
| BaseTest test = (BaseTest)enum.next(); | |||
| test.setFork( value ); | |||
| } | |||
| } | |||
| /** | |||
| * Tells this task to halt when there is an error in a test. this property | |||
| * is applied on all BatchTest (batchtest) and JUnitTest (test) however it | |||
| * can possibly be overridden by their own properties. | |||
| * | |||
| * @param value <tt>true</tt> if it should halt, otherwise <tt>false</tt> | |||
| */ | |||
| public void setHaltonerror( boolean value ) | |||
| { | |||
| Iterator enum = allTests(); | |||
| while( enum.hasNext() ) | |||
| { | |||
| BaseTest test = (BaseTest)enum.next(); | |||
| test.setHaltonerror( value ); | |||
| } | |||
| } | |||
| /** | |||
| * Tells this task to halt when there is a failure in a test. this property | |||
| * is applied on all BatchTest (batchtest) and JUnitTest (test) however it | |||
| * can possibly be overridden by their own properties. | |||
| * | |||
| * @param value <tt>true</tt> if it should halt, otherwise <tt>false</tt> | |||
| */ | |||
| public void setHaltonfailure( boolean value ) | |||
| { | |||
| Iterator enum = allTests(); | |||
| while( enum.hasNext() ) | |||
| { | |||
| BaseTest test = (BaseTest)enum.next(); | |||
| test.setHaltonfailure( value ); | |||
| } | |||
| } | |||
| /** | |||
| * Set a new VM to execute the testcase. Default is <tt>java</tt> . Ignored | |||
| * if no JVM is forked. | |||
| * | |||
| * @param value the new VM to use instead of <tt>java</tt> | |||
| * @see #setFork(boolean) | |||
| */ | |||
| public void setJvm( final String value ) | |||
| { | |||
| jvm = value; | |||
| } | |||
| /** | |||
| * Set the maximum memory to be used by all forked JVMs. | |||
| * | |||
| * @param max the value as defined by <tt>-mx</tt> or <tt>-Xmx</tt> in the | |||
| * java command line options. | |||
| */ | |||
| public void setMaxmemory( final String max ) | |||
| { | |||
| maxMem = max; | |||
| } | |||
| /** | |||
| * Tells whether the task should print a short summary of the task. | |||
| * | |||
| * @param value <tt>true</tt> to print a summary, <tt>withOutAndErr</tt> to | |||
| * include the test's output as well, <tt>false</tt> otherwise. | |||
| * @see SummaryJUnitResultFormatter | |||
| */ | |||
| public void setPrintsummary( SummaryAttribute value ) | |||
| { | |||
| summaryValue = value.getValue(); | |||
| summary = value.asBoolean(); | |||
| } | |||
| /** | |||
| * Set the timeout value (in milliseconds). If the test is running for more | |||
| * than this value, the test will be canceled. (works only when in 'fork' | |||
| * mode). | |||
| * | |||
| * @param value the maximum time (in milliseconds) allowed before declaring | |||
| * the test as 'timed-out' | |||
| * @see #setFork(boolean) | |||
| */ | |||
| public void setTimeout( Integer value ) | |||
| { | |||
| timeout = value; | |||
| } | |||
| /** | |||
| * Add a new formatter to all tests of this task. | |||
| * | |||
| * @param fe The feature to be added to the Formatter attribute | |||
| */ | |||
| public void addFormatter( FormatterElement fe ) | |||
| { | |||
| formatters.add( fe ); | |||
| } | |||
| /** | |||
| * Add a nested sysproperty element. This might be useful to tranfer Ant | |||
| * properties to the testcases when JVM forking is not enabled. | |||
| * | |||
| * @param sysp The feature to be added to the Sysproperty attribute | |||
| */ | |||
| public void addSysproperty( EnvironmentVariable sysp ) | |||
| { | |||
| sysProperties.addVariable( sysp ); | |||
| } | |||
| /** | |||
| * Add a new single testcase. | |||
| * | |||
| * @param test a new single testcase | |||
| * @see JUnitTest | |||
| */ | |||
| public void addTest( JUnitTest test ) | |||
| { | |||
| tests.add( test ); | |||
| } | |||
| /** | |||
| * Create a new set of testcases (also called ..batchtest) and add it to the | |||
| * list. | |||
| */ | |||
| public void addBatchTest( final BatchTest test ) | |||
| { | |||
| batchTests.add( test ); | |||
| } | |||
| /** | |||
| * <code><classpath></code> allows classpath to be set for tests. | |||
| */ | |||
| public void addClasspath( final Path path ) | |||
| { | |||
| classPath.add( path ); | |||
| } | |||
| /** | |||
| * Create a new JVM argument. Ignored if no JVM is forked. | |||
| * | |||
| * @see #setFork(boolean) | |||
| */ | |||
| public void addJvmarg( final Argument argument ) | |||
| { | |||
| vmArgs.addArgument( argument ); | |||
| } | |||
| /** | |||
| * Runs the testcase. | |||
| * | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| /* | |||
| * Adds the jars or directories containing Ant, this task and JUnit to the | |||
| * classpath - this should make the forked JVM work without having to | |||
| * specify them directly. | |||
| */ | |||
| addClasspathEntry( "/junit/framework/TestCase.class" ); | |||
| addClasspathEntry( "/org/apache/tools/ant/Task.class" ); | |||
| addClasspathEntry( "/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.class" ); | |||
| Iterator list = getIndividualTests(); | |||
| while( list.hasNext() ) | |||
| { | |||
| JUnitTest test = (JUnitTest)list.next(); | |||
| final TaskContext context = getContext(); | |||
| if( test.shouldRun( context ) ) | |||
| { | |||
| execute( test ); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Merge all individual tests from the batchtest with all individual tests | |||
| * and return an enumeration over all <tt>JUnitTest</tt> . | |||
| * | |||
| * @return The IndividualTests value | |||
| */ | |||
| protected Iterator getIndividualTests() | |||
| throws TaskException | |||
| { | |||
| Iterator[] enums = new Iterator[ batchTests.size() + 1 ]; | |||
| for( int i = 0; i < batchTests.size(); i++ ) | |||
| { | |||
| BatchTest batchtest = (BatchTest)batchTests.get( i ); | |||
| enums[ i ] = batchtest.iterator(); | |||
| } | |||
| enums[ enums.length - 1 ] = tests.iterator(); | |||
| return new CompoundIterator( enums ); | |||
| } | |||
| /** | |||
| * return the file or null if does not use a file | |||
| * | |||
| * @param fe Description of Parameter | |||
| * @param test Description of Parameter | |||
| * @return The Output value | |||
| */ | |||
| protected File getOutput( FormatterElement fe, JUnitTest test ) | |||
| throws TaskException | |||
| { | |||
| if( fe.getUseFile() ) | |||
| { | |||
| String filename = test.getOutfile() + fe.getExtension(); | |||
| File destFile = new File( test.getTodir(), filename ); | |||
| final String absFilename = destFile.getAbsolutePath(); | |||
| return getContext().resolveFile( absFilename ); | |||
| } | |||
| return null; | |||
| } | |||
| /** | |||
| * 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.</p> | |||
| * | |||
| * @param resource The feature to be added to the ClasspathEntry attribute | |||
| */ | |||
| protected void addClasspathEntry( String resource ) | |||
| { | |||
| URL url = getClass().getResource( resource ); | |||
| if( url != null ) | |||
| { | |||
| String u = url.toString(); | |||
| if( u.startsWith( "jar:file:" ) ) | |||
| { | |||
| int pling = u.indexOf( "!" ); | |||
| String jarName = u.substring( 9, pling ); | |||
| getContext().debug( "Implicitly adding " + jarName + " to classpath" ); | |||
| classPath.addLocation( new File( jarName ) ); | |||
| } | |||
| else if( u.startsWith( "file:" ) ) | |||
| { | |||
| int tail = u.indexOf( resource ); | |||
| String dirName = u.substring( 5, tail ); | |||
| getContext().debug( "Implicitly adding " + dirName + " to classpath" ); | |||
| classPath.addLocation( new File( dirName ) ); | |||
| } | |||
| else | |||
| { | |||
| getContext().debug( "Don\'t know how to handle resource URL " + u ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| getContext().debug( "Couldn\'t find " + resource ); | |||
| } | |||
| } | |||
| protected Iterator allTests() | |||
| { | |||
| Iterator[] enums = {tests.iterator(), batchTests.iterator()}; | |||
| return new CompoundIterator( enums ); | |||
| } | |||
| /** | |||
| * Run the tests. | |||
| * | |||
| * @param test Description of Parameter | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| protected void execute( final JUnitTest test ) | |||
| throws TaskException | |||
| { | |||
| // set the default values if not specified | |||
| //@todo should be moved to the test class instead. | |||
| if( test.getTodir() == null ) | |||
| { | |||
| test.setTodir( getBaseDirectory() ); | |||
| } | |||
| if( test.getOutfile() == null ) | |||
| { | |||
| test.setOutfile( "TEST-" + test.getName() ); | |||
| } | |||
| // execute the test and get the return code | |||
| int exitValue = JUnitTestRunner.ERRORS; | |||
| boolean wasKilled = false; | |||
| if( !test.getFork() ) | |||
| { | |||
| exitValue = executeInVM( test ); | |||
| } | |||
| else | |||
| { | |||
| exitValue = executeAsForked( test ); | |||
| } | |||
| // if there is an error/failure and that it should halt, stop everything otherwise | |||
| // just log a statement | |||
| boolean errorOccurredHere = exitValue == JUnitTestRunner.ERRORS; | |||
| boolean failureOccurredHere = exitValue != JUnitTestRunner.SUCCESS; | |||
| if( errorOccurredHere || failureOccurredHere ) | |||
| { | |||
| if( errorOccurredHere && test.getHaltonerror() | |||
| || failureOccurredHere && test.getHaltonfailure() ) | |||
| { | |||
| throw new TaskException( "Test " + test.getName() + " failed" | |||
| + ( wasKilled ? " (timeout)" : "" ) ); | |||
| } | |||
| else | |||
| { | |||
| final String message = "TEST " + test.getName() + " FAILED" + | |||
| ( wasKilled ? " (timeout)" : "" ); | |||
| getContext().error( message ); | |||
| if( errorOccurredHere && test.getErrorProperty() != null ) | |||
| { | |||
| final String name = test.getErrorProperty(); | |||
| getContext().setProperty( name, "true" ); | |||
| } | |||
| if( failureOccurredHere && test.getFailureProperty() != null ) | |||
| { | |||
| final String name = test.getFailureProperty(); | |||
| getContext().setProperty( name, "true" ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| protected void handleErrorOutput( String line ) | |||
| { | |||
| if( runner != null ) | |||
| { | |||
| runner.handleErrorOutput( line ); | |||
| } | |||
| else | |||
| { | |||
| //super.handleErrorOutput( line ); | |||
| } | |||
| } | |||
| // in VM is not very nice since it could probably hang the | |||
| // whole build. IMHO this method should be avoided and it would be best | |||
| // to remove it in future versions. TBD. (SBa) | |||
| protected void handleOutput( String line ) | |||
| { | |||
| if( runner != null ) | |||
| { | |||
| runner.handleOutput( line ); | |||
| } | |||
| else | |||
| { | |||
| //super.handleOutput( line ); | |||
| } | |||
| } | |||
| /** | |||
| * Execute a testcase by forking a new JVM. The command will block until it | |||
| * finishes. To know if the process was destroyed or not, use the <tt> | |||
| * killedProcess()</tt> method of the watchdog class. | |||
| * | |||
| * @param test the testcase to execute. | |||
| */ | |||
| private int executeAsForked( JUnitTest test ) | |||
| throws TaskException | |||
| { | |||
| ExecuteJava cmd = new ExecuteJava(); | |||
| cmd.setJvm( jvm ); | |||
| cmd.setIgnoreReturnCode( true ); | |||
| cmd.setWorkingDirectory( dir ); | |||
| cmd.setMaxMemory( maxMem ); | |||
| cmd.getClassPath().add( classPath ); | |||
| cmd.getVmArguments().addArguments( vmArgs ); | |||
| cmd.getSysProperties().addVariables( sysProperties ); | |||
| cmd.setClassName( "org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner" ); | |||
| cmd.getArguments().addArgument( test.getName() ); | |||
| cmd.getArguments().addArgument( "filtertrace=" + test.getFiltertrace() ); | |||
| cmd.getArguments().addArgument( "haltOnError=" + test.getHaltonerror() ); | |||
| cmd.getArguments().addArgument( "haltOnFailure=" + test.getHaltonfailure() ); | |||
| if( summary ) | |||
| { | |||
| getContext().info( "Running " + test.getName() ); | |||
| cmd.getArguments().addArgument( "formatter=org.apache.tools.ant.taskdefs.optional.junit.SummaryJUnitResultFormatter" ); | |||
| } | |||
| StringBuffer formatterArg = new StringBuffer( 128 ); | |||
| final FormatterElement[] feArray = mergeFormatters( test ); | |||
| for( int i = 0; i < feArray.length; i++ ) | |||
| { | |||
| FormatterElement fe = feArray[ i ]; | |||
| formatterArg.append( "formatter=" ); | |||
| formatterArg.append( fe.getClassname() ); | |||
| File outFile = getOutput( fe, test ); | |||
| if( outFile != null ) | |||
| { | |||
| formatterArg.append( "," ); | |||
| formatterArg.append( outFile ); | |||
| } | |||
| cmd.getArguments().addArgument( formatterArg.toString() ); | |||
| formatterArg.setLength( 0 ); | |||
| } | |||
| // Create a temporary file to pass the Ant properties to the forked test | |||
| File propsFile = new File( "junit" + ( new Random( System.currentTimeMillis() ) ).nextLong() + ".properties" ); | |||
| cmd.getArguments().addArgument( "propsfile=" + propsFile.getAbsolutePath() ); | |||
| Properties props = new Properties(); | |||
| props.putAll( getContext().getProperties() ); | |||
| try | |||
| { | |||
| final FileOutputStream outstream = new FileOutputStream( propsFile ); | |||
| props.store( outstream, "Ant JUnitTask generated properties file" ); | |||
| outstream.close(); | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| throw new TaskException( "Error creating temporary properties file.", ioe ); | |||
| } | |||
| try | |||
| { | |||
| return cmd.executeForked( getContext() ); | |||
| } | |||
| finally | |||
| { | |||
| if( !propsFile.delete() ) | |||
| { | |||
| throw new TaskException( "Could not delete temporary properties file." ); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Execute inside VM. | |||
| */ | |||
| private int executeInVM( JUnitTest test ) | |||
| throws TaskException | |||
| { | |||
| test.setProperties( getContext().getProperties() ); | |||
| SysProperties.setSystem( sysProperties ); | |||
| try | |||
| { | |||
| getContext().debug( "Using System properties " + System.getProperties() ); | |||
| final ClassLoader classLoader = FileListUtil.createClassLoader( classPath, getContext() ); | |||
| runner = new JUnitTestRunner( test, | |||
| test.getHaltonerror(), | |||
| test.getFiltertrace(), | |||
| test.getHaltonfailure(), | |||
| classLoader ); | |||
| if( summary ) | |||
| { | |||
| getContext().info( "Running " + test.getName() ); | |||
| SummaryJUnitResultFormatter f = | |||
| new SummaryJUnitResultFormatter(); | |||
| f.setWithOutAndErr( "withoutanderr".equalsIgnoreCase( summaryValue ) ); | |||
| f.setOutput( System.out ); | |||
| runner.addFormatter( f ); | |||
| } | |||
| final FormatterElement[] feArray = mergeFormatters( test ); | |||
| for( int i = 0; i < feArray.length; i++ ) | |||
| { | |||
| FormatterElement fe = feArray[ i ]; | |||
| File outFile = getOutput( fe, test ); | |||
| if( outFile != null ) | |||
| { | |||
| fe.setOutfile( outFile ); | |||
| } | |||
| else | |||
| { | |||
| fe.setOutput( System.out ); | |||
| } | |||
| runner.addFormatter( fe.createFormatter() ); | |||
| } | |||
| runner.run(); | |||
| return runner.getRetCode(); | |||
| } | |||
| finally | |||
| { | |||
| SysProperties.restoreSystem(); | |||
| } | |||
| } | |||
| private FormatterElement[] mergeFormatters( JUnitTest test ) | |||
| { | |||
| final ArrayList feArrayList = (ArrayList)formatters.clone(); | |||
| test.addFormattersTo( feArrayList ); | |||
| return (FormatterElement[])feArrayList.toArray( new FormatterElement[ feArrayList.size() ] ); | |||
| } | |||
| /** | |||
| * Print summary enumeration values. | |||
| * | |||
| * @author RT | |||
| */ | |||
| public static class SummaryAttribute extends EnumeratedAttribute | |||
| { | |||
| public String[] getValues() | |||
| { | |||
| return new String[]{"true", "yes", "false", "no", | |||
| "on", "off", "withOutAndErr"}; | |||
| } | |||
| public boolean asBoolean() | |||
| { | |||
| final String value = getValue(); | |||
| return "true".equals( value ) || | |||
| "on".equals( value ) || | |||
| "yes".equals( value ) || | |||
| "withOutAndErr".equals( value ); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,186 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.junit; | |||
| import java.util.ArrayList; | |||
| import java.util.Iterator; | |||
| import java.util.Map; | |||
| import java.util.Properties; | |||
| import org.apache.myrmidon.api.TaskContext; | |||
| /** | |||
| * <p> | |||
| * | |||
| * Run a single JUnit test. <p> | |||
| * | |||
| * The JUnit test is actually run by {@link JUnitTestRunner}. So read the doc | |||
| * comments for that class :) | |||
| * | |||
| * @author Thomas Haas | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> , | |||
| * @author <a href="mailto:sbailliez@imediation.com">Stephane Bailliez</a> | |||
| * @see JUnitTask | |||
| * @see JUnitTestRunner | |||
| */ | |||
| public class JUnitTest extends BaseTest | |||
| { | |||
| /** | |||
| * the name of the test case | |||
| */ | |||
| private String m_name; | |||
| /** | |||
| * the name of the result file | |||
| */ | |||
| private String m_outfile; | |||
| // Snapshot of the system properties | |||
| private Properties m_props; | |||
| private long m_runTime; | |||
| // @todo this is duplicating TestResult information. Only the time is not | |||
| // part of the result. So we'd better derive a new class from TestResult | |||
| // and deal with it. (SB) | |||
| private long m_runs; | |||
| private long m_failures; | |||
| private long m_errors; | |||
| public JUnitTest() | |||
| { | |||
| } | |||
| public JUnitTest( String name ) | |||
| { | |||
| m_name = name; | |||
| } | |||
| public JUnitTest( final String name, | |||
| final boolean haltOnError, | |||
| final boolean haltOnFailure, | |||
| final boolean filtertrace ) | |||
| { | |||
| m_name = name; | |||
| m_haltOnError = haltOnError; | |||
| m_haltOnFail = haltOnFailure; | |||
| m_filtertrace = filtertrace; | |||
| } | |||
| public void setCounts( long runs, long failures, long errors ) | |||
| { | |||
| m_runs = runs; | |||
| m_failures = failures; | |||
| m_errors = errors; | |||
| } | |||
| /** | |||
| * Set the name of the test class. | |||
| */ | |||
| public void setName( final String value ) | |||
| { | |||
| m_name = value; | |||
| } | |||
| /** | |||
| * Set the name of the output file. | |||
| */ | |||
| public void setOutfile( final String value ) | |||
| { | |||
| m_outfile = value; | |||
| } | |||
| public void setProperties( final Map properties ) | |||
| { | |||
| m_props = new Properties(); | |||
| final Iterator enum = properties.keySet().iterator(); | |||
| while( enum.hasNext() ) | |||
| { | |||
| final Object key = enum.next(); | |||
| final Object value = properties.get( key ); | |||
| m_props.put( key, value ); | |||
| } | |||
| } | |||
| public void setRunTime( final long runTime ) | |||
| { | |||
| m_runTime = runTime; | |||
| } | |||
| public FormatterElement[] getFormatters() | |||
| { | |||
| return (FormatterElement[])formatters.toArray( new FormatterElement[ formatters.size() ] ); | |||
| } | |||
| /** | |||
| * Get the name of the test class. | |||
| * | |||
| * @return The Name value | |||
| */ | |||
| public String getName() | |||
| { | |||
| return m_name; | |||
| } | |||
| /** | |||
| * Get the name of the output file | |||
| * | |||
| * @return the name of the output file. | |||
| */ | |||
| public String getOutfile() | |||
| { | |||
| return m_outfile; | |||
| } | |||
| public Properties getProperties() | |||
| { | |||
| return m_props; | |||
| } | |||
| public long getRunTime() | |||
| { | |||
| return m_runTime; | |||
| } | |||
| public long errorCount() | |||
| { | |||
| return m_errors; | |||
| } | |||
| public long failureCount() | |||
| { | |||
| return m_failures; | |||
| } | |||
| public long runCount() | |||
| { | |||
| return m_runs; | |||
| } | |||
| public boolean shouldRun( final TaskContext context ) | |||
| { | |||
| if( ifProperty != null && context.getProperty( ifProperty ) == null ) | |||
| { | |||
| return false; | |||
| } | |||
| else if( unlessProperty != null && | |||
| context.getProperty( unlessProperty ) != null ) | |||
| { | |||
| return false; | |||
| } | |||
| return true; | |||
| } | |||
| /** | |||
| * Convenient method to add formatters to a vector | |||
| */ | |||
| void addFormattersTo( ArrayList v ) | |||
| { | |||
| v.addAll( formatters ); | |||
| } | |||
| } | |||
| @@ -1,643 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.junit; | |||
| import java.io.BufferedReader; | |||
| import java.io.ByteArrayOutputStream; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.IOException; | |||
| import java.io.PrintStream; | |||
| import java.io.PrintWriter; | |||
| import java.io.StringReader; | |||
| import java.io.StringWriter; | |||
| import java.lang.reflect.Method; | |||
| import java.util.ArrayList; | |||
| import java.util.Hashtable; | |||
| import java.util.Properties; | |||
| import junit.framework.AssertionFailedError; | |||
| import junit.framework.Test; | |||
| import junit.framework.TestListener; | |||
| import junit.framework.TestResult; | |||
| import junit.framework.TestSuite; | |||
| import org.apache.avalon.framework.ExceptionUtil; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| /** | |||
| * Simple Testrunner for JUnit that runs all tests of a testsuite. <p> | |||
| * | |||
| * This TestRunner expects a name of a TestCase class as its argument. If this | |||
| * class provides a static suite() method it will be called and the resulting | |||
| * Test will be run. So, the signature should be <pre><code> | |||
| * public static junit.framework.Test suite() | |||
| * </code></pre> <p> | |||
| * | |||
| * If no such method exists, all public methods starting with "test" and taking | |||
| * no argument will be run. <p> | |||
| * | |||
| * Summary output is generated at the end. | |||
| * | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:ehatcher@apache.org">Erik Hatcher</a> | |||
| */ | |||
| public class JUnitTestRunner | |||
| implements TestListener | |||
| { | |||
| /** | |||
| * No problems with this test. | |||
| */ | |||
| public final static int SUCCESS = 0; | |||
| /** | |||
| * Some tests failed. | |||
| */ | |||
| public final static int FAILURES = 1; | |||
| /** | |||
| * An error occured. | |||
| */ | |||
| public final static int ERRORS = 2; | |||
| /** | |||
| * Do we filter junit.*.* stack frames out of failure and error exceptions. | |||
| */ | |||
| private static boolean filtertrace = true; | |||
| private final static String[] DEFAULT_TRACE_FILTERS = new String[] | |||
| { | |||
| "junit.framework.TestCase", | |||
| "junit.framework.TestResult", | |||
| "junit.framework.TestSuite", | |||
| "junit.framework.Assert.", // don't filter AssertionFailure | |||
| "junit.swingui.TestRunner", | |||
| "junit.awtui.TestRunner", | |||
| "junit.textui.TestRunner", | |||
| "java.lang.reflect.Method.invoke(", | |||
| "org.apache.tools.ant." | |||
| }; | |||
| private static ArrayList m_fromCmdLine = new ArrayList(); | |||
| /** | |||
| * Holds the registered formatters. | |||
| */ | |||
| private ArrayList m_formatters = new ArrayList(); | |||
| /** | |||
| * Do we stop on errors. | |||
| */ | |||
| private boolean m_haltOnError; | |||
| /** | |||
| * Do we stop on test failures. | |||
| */ | |||
| private boolean m_haltOnFailure; | |||
| /** | |||
| * The corresponding testsuite. | |||
| */ | |||
| private Test m_suite; | |||
| /** | |||
| * Returncode | |||
| */ | |||
| private int m_retCode = SUCCESS; | |||
| /** | |||
| * Exception caught in constructor. | |||
| */ | |||
| private Exception m_exception; | |||
| /** | |||
| * The TestSuite we are currently running. | |||
| */ | |||
| private JUnitTest m_junitTest; | |||
| /** | |||
| * Collects TestResults. | |||
| */ | |||
| private TestResult m_res; | |||
| /** | |||
| * output written during the test | |||
| */ | |||
| private PrintStream m_systemError; | |||
| /** | |||
| * Error output during the test | |||
| */ | |||
| private PrintStream m_systemOut; | |||
| /** | |||
| * Constructor for fork=true or when the user hasn't specified a classpath. | |||
| * | |||
| * @param test Description of Parameter | |||
| * @param haltOnError Description of Parameter | |||
| * @param filtertrace Description of Parameter | |||
| * @param haltOnFailure Description of Parameter | |||
| */ | |||
| public JUnitTestRunner( final JUnitTest test, | |||
| final boolean haltOnError, | |||
| final boolean filtertrace, | |||
| final boolean haltOnFailure ) | |||
| { | |||
| this( test, haltOnError, filtertrace, haltOnFailure, null ); | |||
| } | |||
| /** | |||
| * Constructor to use when the user has specified a classpath. | |||
| * | |||
| * @param test Description of Parameter | |||
| * @param haltOnError Description of Parameter | |||
| * @param filtertrace Description of Parameter | |||
| * @param haltOnFailure Description of Parameter | |||
| * @param loader Description of Parameter | |||
| */ | |||
| public JUnitTestRunner( JUnitTest test, boolean haltOnError, boolean filtertrace, | |||
| boolean haltOnFailure, ClassLoader loader ) | |||
| { | |||
| //JUnitTestRunner.filtertrace = filtertrace; | |||
| this.filtertrace = filtertrace; | |||
| this.m_junitTest = test; | |||
| this.m_haltOnError = haltOnError; | |||
| this.m_haltOnFailure = haltOnFailure; | |||
| try | |||
| { | |||
| Class testClass = null; | |||
| if( loader == null ) | |||
| { | |||
| testClass = Class.forName( test.getName() ); | |||
| } | |||
| else | |||
| { | |||
| testClass = loader.loadClass( test.getName() ); | |||
| } | |||
| Method suiteMethod = null; | |||
| try | |||
| { | |||
| // check if there is a suite method | |||
| suiteMethod = testClass.getMethod( "suite", new Class[ 0 ] ); | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| // no appropriate suite method found. We don't report any | |||
| // error here since it might be perfectly normal. We don't | |||
| // know exactly what is the cause, but we're doing exactly | |||
| // the same as JUnit TestRunner do. We swallow the exceptions. | |||
| } | |||
| if( suiteMethod != null ) | |||
| { | |||
| // if there is a suite method available, then try | |||
| // to extract the suite from it. If there is an error | |||
| // here it will be caught below and reported. | |||
| m_suite = (Test)suiteMethod.invoke( null, new Class[ 0 ] ); | |||
| } | |||
| else | |||
| { | |||
| // try to extract a test suite automatically | |||
| // this will generate warnings if the class is no suitable Test | |||
| m_suite = new TestSuite( testClass ); | |||
| } | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| m_retCode = ERRORS; | |||
| m_exception = e; | |||
| } | |||
| } | |||
| /** | |||
| * Returns a filtered stack trace. This is ripped out of | |||
| * junit.runner.BaseTestRunner. Scott M. Stirling. | |||
| * | |||
| * @param t Description of Parameter | |||
| * @return The FilteredTrace value | |||
| */ | |||
| public static String getFilteredTrace( Throwable t ) | |||
| { | |||
| final String trace = ExceptionUtil.printStackTrace( t ); | |||
| return JUnitTestRunner.filterStack( trace ); | |||
| } | |||
| /** | |||
| * Filters stack frames from internal JUnit and Ant classes | |||
| * | |||
| * @param stack Description of Parameter | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public static String filterStack( String stack ) | |||
| { | |||
| if( !filtertrace ) | |||
| { | |||
| return stack; | |||
| } | |||
| StringWriter sw = new StringWriter(); | |||
| PrintWriter pw = new PrintWriter( sw ); | |||
| StringReader sr = new StringReader( stack ); | |||
| BufferedReader br = new BufferedReader( sr ); | |||
| String line; | |||
| try | |||
| { | |||
| while( ( line = br.readLine() ) != null ) | |||
| { | |||
| if( !filterLine( line ) ) | |||
| { | |||
| pw.println( line ); | |||
| } | |||
| } | |||
| } | |||
| catch( Exception IOException ) | |||
| { | |||
| return stack;// return the stack unfiltered | |||
| } | |||
| return sw.toString(); | |||
| } | |||
| /** | |||
| * Entry point for standalone (forked) mode. Parameters: testcaseclassname | |||
| * plus parameters in the format key=value, none of which is required. | |||
| * | |||
| * <tablecols="4" border="1"> | |||
| * | |||
| * <tr> | |||
| * | |||
| * <th> | |||
| * key | |||
| * </th> | |||
| * | |||
| * <th> | |||
| * description | |||
| * </th> | |||
| * | |||
| * <th> | |||
| * default value | |||
| * </th> | |||
| * | |||
| * </tr> | |||
| * | |||
| * <tr> | |||
| * | |||
| * <td> | |||
| * haltOnError | |||
| * </td> | |||
| * | |||
| * <td> | |||
| * halt test on errors? | |||
| * </td> | |||
| * | |||
| * <td> | |||
| * false | |||
| * </td> | |||
| * | |||
| * </tr> | |||
| * | |||
| * <tr> | |||
| * | |||
| * <td> | |||
| * haltOnFailure | |||
| * </td> | |||
| * | |||
| * <td> | |||
| * halt test on failures? | |||
| * </td> | |||
| * | |||
| * <td> | |||
| * false | |||
| * </td> | |||
| * | |||
| * </tr> | |||
| * | |||
| * <tr> | |||
| * | |||
| * <td> | |||
| * formatter | |||
| * </td> | |||
| * | |||
| * <td> | |||
| * A JUnitResultFormatter given as classname,filename. If filename is | |||
| * ommitted, System.out is assumed. | |||
| * </td> | |||
| * | |||
| * <td> | |||
| * none | |||
| * </td> | |||
| * | |||
| * </tr> | |||
| * | |||
| * </table> | |||
| * | |||
| * | |||
| * @param args The command line arguments | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| public static void main( String[] args ) | |||
| throws IOException, TaskException | |||
| { | |||
| boolean exitAtEnd = true; | |||
| boolean haltError = false; | |||
| boolean haltFail = false; | |||
| boolean stackfilter = true; | |||
| Properties props = new Properties(); | |||
| if( args.length == 0 ) | |||
| { | |||
| System.err.println( "required argument TestClassName missing" ); | |||
| System.exit( ERRORS ); | |||
| } | |||
| for( int i = 1; i < args.length; i++ ) | |||
| { | |||
| if( args[ i ].startsWith( "haltOnError=" ) ) | |||
| { | |||
| haltError = "true".equals( args[ i ].substring( 12 ) ); | |||
| } | |||
| else if( args[ i ].startsWith( "haltOnFailure=" ) ) | |||
| { | |||
| haltFail = "true".equals( args[ i ].substring( 14 ) ); | |||
| } | |||
| else if( args[ i ].startsWith( "filtertrace=" ) ) | |||
| { | |||
| stackfilter = "true".equals( args[ i ].substring( 12 ) ); | |||
| } | |||
| else if( args[ i ].startsWith( "formatter=" ) ) | |||
| { | |||
| try | |||
| { | |||
| createAndStoreFormatter( args[ i ].substring( 10 ) ); | |||
| } | |||
| catch( TaskException be ) | |||
| { | |||
| System.err.println( be.getMessage() ); | |||
| System.exit( ERRORS ); | |||
| } | |||
| } | |||
| else if( args[ i ].startsWith( "propsfile=" ) ) | |||
| { | |||
| FileInputStream in = new FileInputStream( args[ i ].substring( 10 ) ); | |||
| props.load( in ); | |||
| in.close(); | |||
| } | |||
| } | |||
| JUnitTest t = new JUnitTest( args[ 0 ] ); | |||
| // Add/overlay system properties on the properties from the Ant project | |||
| Hashtable p = System.getProperties(); | |||
| props.putAll( p ); | |||
| t.setProperties( props ); | |||
| JUnitTestRunner runner = new JUnitTestRunner( t, haltError, stackfilter, haltFail ); | |||
| transferFormatters( runner ); | |||
| runner.run(); | |||
| System.exit( runner.getRetCode() ); | |||
| } | |||
| /** | |||
| * Line format is: formatter=<classname>(,<pathname> | |||
| * | |||
| * )? | |||
| * | |||
| * @param line Description of Parameter | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| private static void createAndStoreFormatter( String line ) | |||
| throws TaskException | |||
| { | |||
| FormatterElement fe = new FormatterElement(); | |||
| int pos = line.indexOf( ',' ); | |||
| if( pos == -1 ) | |||
| { | |||
| fe.setClassname( line ); | |||
| } | |||
| else | |||
| { | |||
| fe.setClassname( line.substring( 0, pos ) ); | |||
| fe.setOutfile( new File( line.substring( pos + 1 ) ) ); | |||
| } | |||
| m_fromCmdLine.add( fe.createFormatter() ); | |||
| } | |||
| private static boolean filterLine( String line ) | |||
| { | |||
| for( int i = 0; i < DEFAULT_TRACE_FILTERS.length; i++ ) | |||
| { | |||
| if( line.indexOf( DEFAULT_TRACE_FILTERS[ i ] ) > 0 ) | |||
| { | |||
| return true; | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| private static void transferFormatters( JUnitTestRunner runner ) | |||
| { | |||
| for( int i = 0; i < m_fromCmdLine.size(); i++ ) | |||
| { | |||
| runner.addFormatter( (JUnitResultFormatter)m_fromCmdLine.get( i ) ); | |||
| } | |||
| } | |||
| /** | |||
| * Returns what System.exit() would return in the standalone version. | |||
| * | |||
| * @return 2 if errors occurred, 1 if tests failed else 0. | |||
| */ | |||
| public int getRetCode() | |||
| { | |||
| return m_retCode; | |||
| } | |||
| /** | |||
| * Interface TestListener. <p> | |||
| * | |||
| * An error occured while running the test. | |||
| * | |||
| * @param test The feature to be added to the Error attribute | |||
| * @param t The feature to be added to the Error attribute | |||
| */ | |||
| public void addError( Test test, Throwable t ) | |||
| { | |||
| if( m_haltOnError ) | |||
| { | |||
| m_res.stop(); | |||
| } | |||
| } | |||
| /** | |||
| * Interface TestListener for JUnit <= 3.4. <p> | |||
| * | |||
| * A Test failed. | |||
| * | |||
| * @param test The feature to be added to the Failure attribute | |||
| * @param t The feature to be added to the Failure attribute | |||
| */ | |||
| public void addFailure( Test test, Throwable t ) | |||
| { | |||
| if( m_haltOnFailure ) | |||
| { | |||
| m_res.stop(); | |||
| } | |||
| } | |||
| /** | |||
| * Interface TestListener for JUnit > 3.4. <p> | |||
| * | |||
| * A Test failed. | |||
| * | |||
| * @param test The feature to be added to the Failure attribute | |||
| * @param t The feature to be added to the Failure attribute | |||
| */ | |||
| public void addFailure( Test test, AssertionFailedError t ) | |||
| { | |||
| addFailure( test, (Throwable)t ); | |||
| } | |||
| public void addFormatter( JUnitResultFormatter f ) | |||
| { | |||
| m_formatters.add( f ); | |||
| } | |||
| /** | |||
| * Interface TestListener. <p> | |||
| * | |||
| * A Test is finished. | |||
| * | |||
| * @param test Description of Parameter | |||
| */ | |||
| public void endTest( Test test ) | |||
| { | |||
| } | |||
| public void run() | |||
| throws TaskException | |||
| { | |||
| m_res = new TestResult(); | |||
| m_res.addListener( this ); | |||
| for( int i = 0; i < m_formatters.size(); i++ ) | |||
| { | |||
| final TestListener listener = (TestListener)m_formatters.get( i ); | |||
| m_res.addListener( listener ); | |||
| } | |||
| long start = System.currentTimeMillis(); | |||
| fireStartTestSuite(); | |||
| if( m_exception != null ) | |||
| {// had an exception in the constructor | |||
| for( int i = 0; i < m_formatters.size(); i++ ) | |||
| { | |||
| ( (TestListener)m_formatters.get( i ) ).addError( null, | |||
| m_exception ); | |||
| } | |||
| m_junitTest.setCounts( 1, 0, 1 ); | |||
| m_junitTest.setRunTime( 0 ); | |||
| } | |||
| else | |||
| { | |||
| ByteArrayOutputStream errStrm = new ByteArrayOutputStream(); | |||
| m_systemError = new PrintStream( errStrm ); | |||
| ByteArrayOutputStream outStrm = new ByteArrayOutputStream(); | |||
| m_systemOut = new PrintStream( outStrm ); | |||
| try | |||
| { | |||
| m_suite.run( m_res ); | |||
| } | |||
| finally | |||
| { | |||
| m_systemError.close(); | |||
| m_systemError = null; | |||
| m_systemOut.close(); | |||
| m_systemOut = null; | |||
| sendOutAndErr( new String( outStrm.toByteArray() ), | |||
| new String( errStrm.toByteArray() ) ); | |||
| m_junitTest.setCounts( m_res.runCount(), m_res.failureCount(), | |||
| m_res.errorCount() ); | |||
| m_junitTest.setRunTime( System.currentTimeMillis() - start ); | |||
| } | |||
| } | |||
| fireEndTestSuite(); | |||
| if( m_retCode != SUCCESS || m_res.errorCount() != 0 ) | |||
| { | |||
| m_retCode = ERRORS; | |||
| } | |||
| else if( m_res.failureCount() != 0 ) | |||
| { | |||
| m_retCode = FAILURES; | |||
| } | |||
| } | |||
| /** | |||
| * Interface TestListener. <p> | |||
| * | |||
| * A new Test is started. | |||
| */ | |||
| public void startTest( Test t ) | |||
| { | |||
| } | |||
| protected void handleErrorOutput( String line ) | |||
| { | |||
| if( m_systemError != null ) | |||
| { | |||
| m_systemError.println( line ); | |||
| } | |||
| } | |||
| protected void handleOutput( String line ) | |||
| { | |||
| if( m_systemOut != null ) | |||
| { | |||
| m_systemOut.println( line ); | |||
| } | |||
| } | |||
| private void fireEndTestSuite() | |||
| throws TaskException | |||
| { | |||
| final int size = m_formatters.size(); | |||
| for( int i = 0; i < size; i++ ) | |||
| { | |||
| final JUnitResultFormatter formatter = | |||
| (JUnitResultFormatter)m_formatters.get( i ); | |||
| formatter.endTestSuite( m_junitTest ); | |||
| } | |||
| } | |||
| private void fireStartTestSuite() | |||
| throws TaskException | |||
| { | |||
| final int size = m_formatters.size(); | |||
| for( int i = 0; i < size; i++ ) | |||
| { | |||
| final JUnitResultFormatter formatter = (JUnitResultFormatter)m_formatters.get( i ); | |||
| formatter.startTestSuite( m_junitTest ); | |||
| } | |||
| } | |||
| private void sendOutAndErr( String out, String err ) | |||
| { | |||
| final int size = m_formatters.size(); | |||
| for( int i = 0; i < size; i++ ) | |||
| { | |||
| final JUnitResultFormatter formatter = | |||
| (JUnitResultFormatter)m_formatters.get( i ); | |||
| formatter.setSystemOutput( out ); | |||
| formatter.setSystemError( err ); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,69 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.junit; | |||
| import java.lang.reflect.Method; | |||
| import junit.framework.Test; | |||
| import junit.framework.TestCase; | |||
| /** | |||
| * Work around for some changes to the public JUnit API between different JUnit | |||
| * releases. | |||
| * | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @version $Revision$ | |||
| */ | |||
| public class JUnitVersionHelper | |||
| { | |||
| private static Method testCaseName = null; | |||
| static | |||
| { | |||
| try | |||
| { | |||
| testCaseName = TestCase.class.getMethod( "getName", new Class[ 0 ] ); | |||
| } | |||
| catch( NoSuchMethodException e ) | |||
| { | |||
| // pre JUnit 3.7 | |||
| try | |||
| { | |||
| testCaseName = TestCase.class.getMethod( "name", new Class[ 0 ] ); | |||
| } | |||
| catch( NoSuchMethodException e2 ) | |||
| { | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * JUnit 3.7 introduces TestCase.getName() and subsequent versions of JUnit | |||
| * remove the old name() method. This method provides access to the name of | |||
| * a TestCase via reflection that is supposed to work with version before | |||
| * and after JUnit 3.7. | |||
| * | |||
| * @param t Description of Parameter | |||
| * @return The TestCaseName value | |||
| */ | |||
| public static String getTestCaseName( Test t ) | |||
| { | |||
| if( t instanceof TestCase && testCaseName != null ) | |||
| { | |||
| try | |||
| { | |||
| return (String)testCaseName.invoke( t, new Object[ 0 ] ); | |||
| } | |||
| catch( Throwable e ) | |||
| { | |||
| } | |||
| } | |||
| return "unknown"; | |||
| } | |||
| } | |||
| @@ -1,37 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.junit; | |||
| import java.util.ArrayList; | |||
| import org.w3c.dom.Node; | |||
| import org.w3c.dom.NodeList; | |||
| /** | |||
| * custom implementation of a nodelist | |||
| */ | |||
| public class NodeListImpl | |||
| extends ArrayList | |||
| implements NodeList | |||
| { | |||
| public int getLength() | |||
| { | |||
| return size(); | |||
| } | |||
| public Node item( final int i ) | |||
| { | |||
| try | |||
| { | |||
| return (Node)get( i ); | |||
| } | |||
| catch( final ArrayIndexOutOfBoundsException aioobe ) | |||
| { | |||
| return null;// conforming to NodeList interface | |||
| } | |||
| } | |||
| } | |||
| @@ -1,253 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.junit; | |||
| import java.io.IOException; | |||
| import java.io.OutputStream; | |||
| import java.io.PrintWriter; | |||
| import java.io.StringWriter; | |||
| import java.text.NumberFormat; | |||
| import java.util.Hashtable; | |||
| import junit.framework.AssertionFailedError; | |||
| import junit.framework.Test; | |||
| import org.apache.avalon.excalibur.util.StringUtil; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| /** | |||
| * Prints plain text output of the test to a specified Writer. | |||
| * | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| */ | |||
| public class PlainJUnitResultFormatter implements JUnitResultFormatter | |||
| { | |||
| /** | |||
| * Formatter for timings. | |||
| */ | |||
| private NumberFormat nf = NumberFormat.getInstance(); | |||
| /** | |||
| * Timing helper. | |||
| */ | |||
| private Hashtable testStarts = new Hashtable(); | |||
| /** | |||
| * Suppress endTest if testcase failed. | |||
| */ | |||
| private Hashtable failed = new Hashtable(); | |||
| private String systemOutput = null; | |||
| private String systemError = null; | |||
| /** | |||
| * Helper to store intermediate output. | |||
| */ | |||
| private StringWriter inner; | |||
| /** | |||
| * Where to write the log to. | |||
| */ | |||
| private OutputStream out; | |||
| /** | |||
| * Convenience layer on top of {@link #inner inner}. | |||
| */ | |||
| private PrintWriter wri; | |||
| public PlainJUnitResultFormatter() | |||
| { | |||
| inner = new StringWriter(); | |||
| wri = new PrintWriter( inner ); | |||
| } | |||
| public void setOutput( OutputStream out ) | |||
| { | |||
| this.out = out; | |||
| } | |||
| public void setSystemError( String err ) | |||
| { | |||
| systemError = err; | |||
| } | |||
| public void setSystemOutput( String out ) | |||
| { | |||
| systemOutput = out; | |||
| } | |||
| /** | |||
| * Interface TestListener. <p> | |||
| * | |||
| * An error occured while running the test. | |||
| * | |||
| * @param test The feature to be added to the Error attribute | |||
| * @param t The feature to be added to the Error attribute | |||
| */ | |||
| public void addError( Test test, Throwable t ) | |||
| { | |||
| formatError( "\tCaused an ERROR", test, t ); | |||
| } | |||
| /** | |||
| * Interface TestListener for JUnit <= 3.4. <p> | |||
| * | |||
| * A Test failed. | |||
| * | |||
| * @param test The feature to be added to the Failure attribute | |||
| * @param t The feature to be added to the Failure attribute | |||
| */ | |||
| public void addFailure( Test test, Throwable t ) | |||
| { | |||
| formatError( "\tFAILED", test, t ); | |||
| } | |||
| /** | |||
| * Interface TestListener for JUnit > 3.4. <p> | |||
| * | |||
| * A Test failed. | |||
| * | |||
| * @param test The feature to be added to the Failure attribute | |||
| * @param t The feature to be added to the Failure attribute | |||
| */ | |||
| public void addFailure( Test test, AssertionFailedError t ) | |||
| { | |||
| addFailure( test, (Throwable)t ); | |||
| } | |||
| /** | |||
| * Interface TestListener. <p> | |||
| * | |||
| * A Test is finished. | |||
| * | |||
| * @param test Description of Parameter | |||
| */ | |||
| public void endTest( Test test ) | |||
| { | |||
| synchronized( wri ) | |||
| { | |||
| wri.print( "Testcase: " | |||
| + JUnitVersionHelper.getTestCaseName( test ) ); | |||
| if( Boolean.TRUE.equals( failed.get( test ) ) ) | |||
| { | |||
| return; | |||
| } | |||
| Long l = (Long)testStarts.get( test ); | |||
| wri.println( " took " | |||
| + nf.format( ( System.currentTimeMillis() - l.longValue() ) | |||
| / 1000.0 ) | |||
| + " sec" ); | |||
| } | |||
| } | |||
| /** | |||
| * The whole testsuite ended. | |||
| */ | |||
| public void endTestSuite( JUnitTest suite ) | |||
| throws TaskException | |||
| { | |||
| StringBuffer sb = new StringBuffer( "Testsuite: " ); | |||
| sb.append( suite.getName() ); | |||
| sb.append( StringUtil.LINE_SEPARATOR ); | |||
| sb.append( "Tests run: " ); | |||
| sb.append( suite.runCount() ); | |||
| sb.append( ", Failures: " ); | |||
| sb.append( suite.failureCount() ); | |||
| sb.append( ", Errors: " ); | |||
| sb.append( suite.errorCount() ); | |||
| sb.append( ", Time elapsed: " ); | |||
| sb.append( nf.format( suite.getRunTime() / 1000.0 ) ); | |||
| sb.append( " sec" ); | |||
| sb.append( StringUtil.LINE_SEPARATOR ); | |||
| // append the err and output streams to the log | |||
| if( systemOutput != null && systemOutput.length() > 0 ) | |||
| { | |||
| sb.append( "------------- Standard Output ---------------" ) | |||
| .append( StringUtil.LINE_SEPARATOR ) | |||
| .append( systemOutput ) | |||
| .append( "------------- ---------------- ---------------" ) | |||
| .append( StringUtil.LINE_SEPARATOR ); | |||
| } | |||
| if( systemError != null && systemError.length() > 0 ) | |||
| { | |||
| sb.append( "------------- Standard Error -----------------" ) | |||
| .append( StringUtil.LINE_SEPARATOR ) | |||
| .append( systemError ) | |||
| .append( "------------- ---------------- ---------------" ) | |||
| .append( StringUtil.LINE_SEPARATOR ); | |||
| } | |||
| sb.append( StringUtil.LINE_SEPARATOR ); | |||
| if( out != null ) | |||
| { | |||
| try | |||
| { | |||
| out.write( sb.toString().getBytes() ); | |||
| wri.close(); | |||
| out.write( inner.toString().getBytes() ); | |||
| out.flush(); | |||
| } | |||
| catch( IOException ioex ) | |||
| { | |||
| throw new TaskException( "Unable to write output", ioex ); | |||
| } | |||
| finally | |||
| { | |||
| if( out != System.out && out != System.err ) | |||
| { | |||
| try | |||
| { | |||
| out.close(); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Interface TestListener. <p> | |||
| * | |||
| * A new Test is started. | |||
| * | |||
| * @param t Description of Parameter | |||
| */ | |||
| public void startTest( Test t ) | |||
| { | |||
| testStarts.put( t, new Long( System.currentTimeMillis() ) ); | |||
| failed.put( t, Boolean.FALSE ); | |||
| } | |||
| /** | |||
| * Empty. | |||
| * | |||
| * @param suite Description of Parameter | |||
| */ | |||
| public void startTestSuite( JUnitTest suite ) | |||
| { | |||
| } | |||
| private void formatError( String type, Test test, Throwable t ) | |||
| { | |||
| synchronized( wri ) | |||
| { | |||
| if( test != null ) | |||
| { | |||
| endTest( test ); | |||
| failed.put( test, Boolean.TRUE ); | |||
| } | |||
| wri.println( type ); | |||
| wri.println( t.getMessage() ); | |||
| String strace = JUnitTestRunner.getFilteredTrace( t ); | |||
| wri.print( strace ); | |||
| wri.println( "" ); | |||
| } | |||
| } | |||
| }// PlainJUnitResultFormatter | |||
| @@ -1,190 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.junit; | |||
| import java.io.IOException; | |||
| import java.io.OutputStream; | |||
| import java.text.NumberFormat; | |||
| import junit.framework.AssertionFailedError; | |||
| import junit.framework.Test; | |||
| import org.apache.avalon.excalibur.util.StringUtil; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| /** | |||
| * Prints short summary output of the test to Ant's logging system. | |||
| * | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| */ | |||
| public class SummaryJUnitResultFormatter implements JUnitResultFormatter | |||
| { | |||
| /** | |||
| * Formatter for timings. | |||
| */ | |||
| private NumberFormat nf = NumberFormat.getInstance(); | |||
| private boolean withOutAndErr = false; | |||
| private String systemOutput = null; | |||
| private String systemError = null; | |||
| /** | |||
| * OutputStream to write to. | |||
| */ | |||
| private OutputStream out; | |||
| /** | |||
| * Empty | |||
| */ | |||
| public SummaryJUnitResultFormatter() | |||
| { | |||
| } | |||
| public void setOutput( OutputStream out ) | |||
| { | |||
| this.out = out; | |||
| } | |||
| public void setSystemError( String err ) | |||
| { | |||
| systemError = err; | |||
| } | |||
| public void setSystemOutput( String out ) | |||
| { | |||
| systemOutput = out; | |||
| } | |||
| /** | |||
| * Should the output to System.out and System.err be written to the summary. | |||
| * | |||
| * @param value The new WithOutAndErr value | |||
| */ | |||
| public void setWithOutAndErr( boolean value ) | |||
| { | |||
| withOutAndErr = value; | |||
| } | |||
| /** | |||
| * Empty | |||
| * | |||
| * @param test The feature to be added to the Error attribute | |||
| * @param t The feature to be added to the Error attribute | |||
| */ | |||
| public void addError( Test test, Throwable t ) | |||
| { | |||
| } | |||
| /** | |||
| * Empty | |||
| * | |||
| * @param test The feature to be added to the Failure attribute | |||
| * @param t The feature to be added to the Failure attribute | |||
| */ | |||
| public void addFailure( Test test, Throwable t ) | |||
| { | |||
| } | |||
| /** | |||
| * Interface TestListener for JUnit > 3.4. <p> | |||
| * | |||
| * A Test failed. | |||
| * | |||
| * @param test The feature to be added to the Failure attribute | |||
| * @param t The feature to be added to the Failure attribute | |||
| */ | |||
| public void addFailure( Test test, AssertionFailedError t ) | |||
| { | |||
| addFailure( test, (Throwable)t ); | |||
| } | |||
| /** | |||
| * Empty | |||
| * | |||
| * @param test Description of Parameter | |||
| */ | |||
| public void endTest( Test test ) | |||
| { | |||
| } | |||
| /** | |||
| * The whole testsuite ended. | |||
| * | |||
| * @param suite Description of Parameter | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| public void endTestSuite( JUnitTest suite ) | |||
| throws TaskException | |||
| { | |||
| StringBuffer sb = new StringBuffer( "Tests run: " ); | |||
| sb.append( suite.runCount() ); | |||
| sb.append( ", Failures: " ); | |||
| sb.append( suite.failureCount() ); | |||
| sb.append( ", Errors: " ); | |||
| sb.append( suite.errorCount() ); | |||
| sb.append( ", Time elapsed: " ); | |||
| sb.append( nf.format( suite.getRunTime() / 1000.0 ) ); | |||
| sb.append( " sec" ); | |||
| sb.append( StringUtil.LINE_SEPARATOR ); | |||
| if( withOutAndErr ) | |||
| { | |||
| if( systemOutput != null && systemOutput.length() > 0 ) | |||
| { | |||
| sb.append( "Output:" ).append( StringUtil.LINE_SEPARATOR ).append( systemOutput ) | |||
| .append( StringUtil.LINE_SEPARATOR ); | |||
| } | |||
| if( systemError != null && systemError.length() > 0 ) | |||
| { | |||
| sb.append( "Error: " ).append( StringUtil.LINE_SEPARATOR ).append( systemError ) | |||
| .append( StringUtil.LINE_SEPARATOR ); | |||
| } | |||
| } | |||
| try | |||
| { | |||
| out.write( sb.toString().getBytes() ); | |||
| out.flush(); | |||
| } | |||
| catch( IOException ioex ) | |||
| { | |||
| throw new TaskException( "Unable to write summary output", ioex ); | |||
| } | |||
| finally | |||
| { | |||
| if( out != System.out && out != System.err ) | |||
| { | |||
| try | |||
| { | |||
| out.close(); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| } | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Empty | |||
| * | |||
| * @param t Description of Parameter | |||
| */ | |||
| public void startTest( Test t ) | |||
| { | |||
| } | |||
| /** | |||
| * Empty | |||
| * | |||
| * @param suite Description of Parameter | |||
| */ | |||
| public void startTestSuite( JUnitTest suite ) | |||
| { | |||
| } | |||
| } | |||
| @@ -1,115 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.junit; | |||
| /** | |||
| * <p> | |||
| * | |||
| * Interface groups XML constants. Interface that groups all constants used | |||
| * throughout the <tt>XML</tt> documents that are generated by the <tt> | |||
| * XMLJUnitResultFormatter</tt> As of now the DTD is: <code><pre> | |||
| * <----------------- | |||
| * | |||
| * @author <a href="mailto:sbailliez@imediation.com">Stephane Bailliez</a> | |||
| * @see XMLJUnitResultFormatter | |||
| * @see XMLResultAggregator | |||
| * @todo describe DTDs ----------------------> </pre></code> | |||
| */ | |||
| public interface XMLConstants | |||
| { | |||
| /** | |||
| * the testsuites element for the aggregate document | |||
| */ | |||
| String TESTSUITES = "testsuites"; | |||
| /** | |||
| * the testsuite element | |||
| */ | |||
| String TESTSUITE = "testsuite"; | |||
| /** | |||
| * the testcase element | |||
| */ | |||
| String TESTCASE = "testcase"; | |||
| /** | |||
| * the error element | |||
| */ | |||
| String ERROR = "error"; | |||
| /** | |||
| * the failure element | |||
| */ | |||
| String FAILURE = "failure"; | |||
| /** | |||
| * the system-err element | |||
| */ | |||
| String SYSTEM_ERR = "system-err"; | |||
| /** | |||
| * the system-out element | |||
| */ | |||
| String SYSTEM_OUT = "system-out"; | |||
| /** | |||
| * package attribute for the aggregate document | |||
| */ | |||
| String ATTR_PACKAGE = "package"; | |||
| /** | |||
| * name attribute for property, testcase and testsuite elements | |||
| */ | |||
| String ATTR_NAME = "name"; | |||
| /** | |||
| * time attribute for testcase and testsuite elements | |||
| */ | |||
| String ATTR_TIME = "time"; | |||
| /** | |||
| * errors attribute for testsuite elements | |||
| */ | |||
| String ATTR_ERRORS = "errors"; | |||
| /** | |||
| * failures attribute for testsuite elements | |||
| */ | |||
| String ATTR_FAILURES = "failures"; | |||
| /** | |||
| * tests attribute for testsuite elements | |||
| */ | |||
| String ATTR_TESTS = "tests"; | |||
| /** | |||
| * type attribute for failure and error elements | |||
| */ | |||
| String ATTR_TYPE = "type"; | |||
| /** | |||
| * message attribute for failure elements | |||
| */ | |||
| String ATTR_MESSAGE = "message"; | |||
| /** | |||
| * the properties element | |||
| */ | |||
| String PROPERTIES = "properties"; | |||
| /** | |||
| * the property element | |||
| */ | |||
| String PROPERTY = "property"; | |||
| /** | |||
| * value attribute for property elements | |||
| */ | |||
| String ATTR_VALUE = "value"; | |||
| } | |||
| @@ -1,278 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.junit; | |||
| import java.io.IOException; | |||
| import java.io.OutputStream; | |||
| import java.io.OutputStreamWriter; | |||
| import java.io.Writer; | |||
| import java.util.Hashtable; | |||
| import java.util.Iterator; | |||
| import java.util.Properties; | |||
| import javax.xml.parsers.DocumentBuilder; | |||
| import javax.xml.parsers.DocumentBuilderFactory; | |||
| import junit.framework.AssertionFailedError; | |||
| import junit.framework.Test; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.w3c.dom.Document; | |||
| import org.w3c.dom.Element; | |||
| import org.w3c.dom.Text; | |||
| /** | |||
| * Prints XML output of the test to a specified Writer. | |||
| * | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:ehatcher@apache.org">Erik Hatcher</a> | |||
| * @see FormatterElement | |||
| */ | |||
| public class XMLJUnitResultFormatter implements JUnitResultFormatter, XMLConstants | |||
| { | |||
| /** | |||
| * Element for the current test. | |||
| */ | |||
| private Hashtable testElements = new Hashtable(); | |||
| /** | |||
| * Timing helper. | |||
| */ | |||
| private Hashtable testStarts = new Hashtable(); | |||
| /** | |||
| * The XML document. | |||
| */ | |||
| private Document doc; | |||
| /** | |||
| * Where to write the log to. | |||
| */ | |||
| private OutputStream out; | |||
| /** | |||
| * The wrapper for the whole testsuite. | |||
| */ | |||
| private Element rootElement; | |||
| public XMLJUnitResultFormatter() | |||
| { | |||
| } | |||
| private static DocumentBuilder getDocumentBuilder() | |||
| { | |||
| try | |||
| { | |||
| return DocumentBuilderFactory.newInstance().newDocumentBuilder(); | |||
| } | |||
| catch( Exception exc ) | |||
| { | |||
| throw new ExceptionInInitializerError( exc ); | |||
| } | |||
| } | |||
| public void setOutput( OutputStream out ) | |||
| { | |||
| this.out = out; | |||
| } | |||
| public void setSystemError( String out ) | |||
| { | |||
| formatOutput( SYSTEM_ERR, out ); | |||
| } | |||
| public void setSystemOutput( String out ) | |||
| { | |||
| formatOutput( SYSTEM_OUT, out ); | |||
| } | |||
| /** | |||
| * Interface TestListener. <p> | |||
| * | |||
| * An error occured while running the test. | |||
| * | |||
| * @param test The feature to be added to the Error attribute | |||
| * @param t The feature to be added to the Error attribute | |||
| */ | |||
| public void addError( Test test, Throwable t ) | |||
| { | |||
| formatError( ERROR, test, t ); | |||
| } | |||
| /** | |||
| * Interface TestListener for JUnit <= 3.4. <p> | |||
| * | |||
| * A Test failed. | |||
| * | |||
| * @param test The feature to be added to the Failure attribute | |||
| * @param t The feature to be added to the Failure attribute | |||
| */ | |||
| public void addFailure( Test test, Throwable t ) | |||
| { | |||
| formatError( FAILURE, test, t ); | |||
| } | |||
| /** | |||
| * Interface TestListener for JUnit > 3.4. <p> | |||
| * | |||
| * A Test failed. | |||
| * | |||
| * @param test The feature to be added to the Failure attribute | |||
| * @param t The feature to be added to the Failure attribute | |||
| */ | |||
| public void addFailure( Test test, AssertionFailedError t ) | |||
| { | |||
| addFailure( test, (Throwable)t ); | |||
| } | |||
| /** | |||
| * Interface TestListener. <p> | |||
| * | |||
| * A Test is finished. | |||
| * | |||
| * @param test Description of Parameter | |||
| */ | |||
| public void endTest( Test test ) | |||
| { | |||
| Element currentTest = (Element)testElements.get( test ); | |||
| Long l = (Long)testStarts.get( test ); | |||
| currentTest.setAttribute( ATTR_TIME, | |||
| "" + ( ( System.currentTimeMillis() - l.longValue() ) | |||
| / 1000.0 ) ); | |||
| } | |||
| /** | |||
| * The whole testsuite ended. | |||
| * | |||
| * @param suite Description of Parameter | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| public void endTestSuite( JUnitTest suite ) | |||
| throws TaskException | |||
| { | |||
| rootElement.setAttribute( ATTR_TESTS, "" + suite.runCount() ); | |||
| rootElement.setAttribute( ATTR_FAILURES, "" + suite.failureCount() ); | |||
| rootElement.setAttribute( ATTR_ERRORS, "" + suite.errorCount() ); | |||
| rootElement.setAttribute( ATTR_TIME, "" + ( suite.getRunTime() / 1000.0 ) ); | |||
| if( out != null ) | |||
| { | |||
| Writer wri = null; | |||
| try | |||
| { | |||
| wri = new OutputStreamWriter( out, "UTF8" ); | |||
| wri.write( "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" ); | |||
| ( new DOMElementWriter() ).write( rootElement, wri, 0, " " ); | |||
| wri.flush(); | |||
| } | |||
| catch( IOException exc ) | |||
| { | |||
| throw new TaskException( "Unable to write log file", exc ); | |||
| } | |||
| finally | |||
| { | |||
| if( out != System.out && out != System.err ) | |||
| { | |||
| if( wri != null ) | |||
| { | |||
| try | |||
| { | |||
| wri.close(); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Interface TestListener. <p> | |||
| * | |||
| * A new Test is started. | |||
| * | |||
| * @param t Description of Parameter | |||
| */ | |||
| public void startTest( Test t ) | |||
| { | |||
| testStarts.put( t, new Long( System.currentTimeMillis() ) ); | |||
| Element currentTest = doc.createElement( TESTCASE ); | |||
| currentTest.setAttribute( ATTR_NAME, | |||
| JUnitVersionHelper.getTestCaseName( t ) ); | |||
| rootElement.appendChild( currentTest ); | |||
| testElements.put( t, currentTest ); | |||
| } | |||
| /** | |||
| * The whole testsuite started. | |||
| * | |||
| * @param suite Description of Parameter | |||
| */ | |||
| public void startTestSuite( JUnitTest suite ) | |||
| { | |||
| doc = getDocumentBuilder().newDocument(); | |||
| rootElement = doc.createElement( TESTSUITE ); | |||
| rootElement.setAttribute( ATTR_NAME, suite.getName() ); | |||
| // Output properties | |||
| Element propsElement = doc.createElement( PROPERTIES ); | |||
| rootElement.appendChild( propsElement ); | |||
| Properties props = suite.getProperties(); | |||
| if( props != null ) | |||
| { | |||
| final Iterator e = props.keySet().iterator(); | |||
| while( e.hasNext() ) | |||
| { | |||
| final String name = (String)e.next(); | |||
| final String value = props.getProperty( name ); | |||
| final Element propElement = doc.createElement( PROPERTY ); | |||
| propElement.setAttribute( ATTR_NAME, name ); | |||
| propElement.setAttribute( ATTR_VALUE, value ); | |||
| propsElement.appendChild( propElement ); | |||
| } | |||
| } | |||
| } | |||
| private void formatError( String type, Test test, Throwable t ) | |||
| { | |||
| if( test != null ) | |||
| { | |||
| endTest( test ); | |||
| } | |||
| Element nested = doc.createElement( type ); | |||
| Element currentTest = null; | |||
| if( test != null ) | |||
| { | |||
| currentTest = (Element)testElements.get( test ); | |||
| } | |||
| else | |||
| { | |||
| currentTest = rootElement; | |||
| } | |||
| currentTest.appendChild( nested ); | |||
| String message = t.getMessage(); | |||
| if( message != null && message.length() > 0 ) | |||
| { | |||
| nested.setAttribute( ATTR_MESSAGE, t.getMessage() ); | |||
| } | |||
| nested.setAttribute( ATTR_TYPE, t.getClass().getName() ); | |||
| String strace = JUnitTestRunner.getFilteredTrace( t ); | |||
| Text trace = doc.createTextNode( strace ); | |||
| nested.appendChild( trace ); | |||
| } | |||
| private void formatOutput( String type, String output ) | |||
| { | |||
| Element nested = doc.createElement( type ); | |||
| rootElement.appendChild( nested ); | |||
| Text content = doc.createTextNode( output ); | |||
| nested.appendChild( content ); | |||
| } | |||
| }// XMLJUnitResultFormatter | |||
| @@ -1,336 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.junit; | |||
| import java.io.File; | |||
| import java.io.FileOutputStream; | |||
| import java.io.IOException; | |||
| import java.io.OutputStream; | |||
| import java.io.OutputStreamWriter; | |||
| import java.io.PrintWriter; | |||
| import java.util.ArrayList; | |||
| import java.util.Iterator; | |||
| import javax.xml.parsers.DocumentBuilder; | |||
| import javax.xml.parsers.DocumentBuilderFactory; | |||
| import org.apache.avalon.framework.ExceptionUtil; | |||
| import org.apache.myrmidon.api.AbstractTask; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.api.TaskContext; | |||
| import org.apache.myrmidon.framework.FileSet; | |||
| import org.apache.tools.todo.types.DirectoryScanner; | |||
| import org.apache.tools.todo.types.ScannerUtil; | |||
| import org.w3c.dom.Document; | |||
| import org.w3c.dom.Element; | |||
| import org.xml.sax.SAXException; | |||
| /** | |||
| * <p> | |||
| * | |||
| * This is an helper class that will aggregate all testsuites under a specific | |||
| * directory and create a new single document. It is not particulary clean but | |||
| * should be helpful while I am thinking about another technique. <p> | |||
| * | |||
| * The main problem is due to the fact that a JVM can be forked for a testcase | |||
| * thus making it impossible to aggregate all testcases since the listener is | |||
| * (obviously) in the forked JVM. A solution could be to write a TestListener | |||
| * that will receive events from the TestRunner via sockets. This is IMHO the | |||
| * simplest way to do it to avoid this file hacking thing. | |||
| * | |||
| * @author <a href="mailto:sbailliez@imediation.com">Stephane Bailliez</a> | |||
| */ | |||
| public class XMLResultAggregator | |||
| extends AbstractTask | |||
| implements XMLConstants | |||
| { | |||
| /** | |||
| * the default directory: <tt>.</tt> . It is resolved from the project | |||
| * directory | |||
| */ | |||
| public final static String DEFAULT_DIR = "."; | |||
| /** | |||
| * the default file name: <tt>TESTS-TestSuites.xml</tt> | |||
| */ | |||
| public final static String DEFAULT_FILENAME = "TESTS-TestSuites.xml"; | |||
| /** | |||
| * the list of all filesets, that should contains the xml to aggregate | |||
| */ | |||
| protected ArrayList filesets = new ArrayList(); | |||
| protected ArrayList transformers = new ArrayList(); | |||
| /** | |||
| * the directory to write the file to | |||
| */ | |||
| protected File toDir; | |||
| /** | |||
| * the name of the result file | |||
| */ | |||
| protected String toFile; | |||
| /** | |||
| * Create a new document builder. Will issue an <tt> | |||
| * ExceptionInitializerError</tt> if something is going wrong. It is fatal | |||
| * anyway. | |||
| * | |||
| * @return a new document builder to create a DOM | |||
| * @todo factorize this somewhere else. It is duplicated code. | |||
| */ | |||
| private static DocumentBuilder getDocumentBuilder() | |||
| { | |||
| try | |||
| { | |||
| return DocumentBuilderFactory.newInstance().newDocumentBuilder(); | |||
| } | |||
| catch( Exception exc ) | |||
| { | |||
| throw new ExceptionInInitializerError( exc ); | |||
| } | |||
| } | |||
| /** | |||
| * Set the destination directory where the results should be written. If not | |||
| * set if will use {@link #DEFAULT_DIR}. When given a relative directory it | |||
| * will resolve it from the project directory. | |||
| * | |||
| * @param value the directory where to write the results, absolute or | |||
| * relative. | |||
| */ | |||
| public void setTodir( File value ) | |||
| { | |||
| toDir = value; | |||
| } | |||
| /** | |||
| * Set the name of the file aggregating the results. It must be relative | |||
| * from the <tt>todir</tt> attribute. If not set it will use {@link | |||
| * #DEFAULT_FILENAME} | |||
| * | |||
| * @param value the name of the file. | |||
| * @see #setTodir(File) | |||
| */ | |||
| public void setTofile( String value ) | |||
| { | |||
| toFile = value; | |||
| } | |||
| /** | |||
| * Add a new fileset containing the xml results to aggregate | |||
| * | |||
| * @param fs the new fileset of xml results. | |||
| */ | |||
| public void addFileSet( FileSet fs ) | |||
| { | |||
| filesets.add( fs ); | |||
| } | |||
| public AggregateTransformer createReport() | |||
| { | |||
| AggregateTransformer transformer = new AggregateTransformer( getContext() ); | |||
| transformers.add( transformer ); | |||
| return transformer; | |||
| } | |||
| /** | |||
| * Aggregate all testsuites into a single document and write it to the | |||
| * specified directory and file. | |||
| * | |||
| * @throws TaskException thrown if there is a serious error while writing | |||
| * the document. | |||
| */ | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| final Element rootElement = createDocument(); | |||
| File destFile = getDestinationFile(); | |||
| // write the document | |||
| try | |||
| { | |||
| writeDOMTree( rootElement.getOwnerDocument(), destFile ); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| throw new TaskException( "Unable to write test aggregate to '" + destFile + "'", e ); | |||
| } | |||
| // apply transformation | |||
| Iterator enum = transformers.iterator(); | |||
| while( enum.hasNext() ) | |||
| { | |||
| AggregateTransformer transformer = | |||
| (AggregateTransformer)enum.next(); | |||
| transformer.setXmlDocument( rootElement.getOwnerDocument() ); | |||
| transformer.transform(); | |||
| } | |||
| } | |||
| /** | |||
| * Get the full destination file where to write the result. It is made of | |||
| * the <tt>todir</tt> and <tt>tofile</tt> attributes. | |||
| * | |||
| * @return the destination file where should be written the result file. | |||
| */ | |||
| protected File getDestinationFile() | |||
| throws TaskException | |||
| { | |||
| if( toFile == null ) | |||
| { | |||
| toFile = DEFAULT_FILENAME; | |||
| } | |||
| if( toDir == null ) | |||
| { | |||
| toDir = getContext().resolveFile( DEFAULT_DIR ); | |||
| } | |||
| return new File( toDir, toFile ); | |||
| } | |||
| /** | |||
| * Get all <code>.xml</code> files in the fileset. | |||
| * | |||
| * @return all files in the fileset that end with a '.xml'. | |||
| */ | |||
| protected File[] getFiles() | |||
| throws TaskException | |||
| { | |||
| final ArrayList v = new ArrayList(); | |||
| final int size = filesets.size(); | |||
| for( int i = 0; i < size; i++ ) | |||
| { | |||
| final FileSet fileSet = (FileSet)filesets.get( i ); | |||
| final DirectoryScanner scanner = ScannerUtil.getDirectoryScanner( fileSet ); | |||
| scanner.scan(); | |||
| final String[] includes = scanner.getIncludedFiles(); | |||
| for( int j = 0; j < includes.length; j++ ) | |||
| { | |||
| final String pathname = includes[ j ]; | |||
| if( pathname.endsWith( ".xml" ) ) | |||
| { | |||
| File file = new File( scanner.getBasedir(), pathname ); | |||
| file = getContext().resolveFile( file.getPath() ); | |||
| v.add( file ); | |||
| } | |||
| } | |||
| } | |||
| return (File[])v.toArray( new File[ v.size() ] ); | |||
| } | |||
| /** | |||
| * <p> | |||
| * | |||
| * Add a new testsuite node to the document. The main difference is that it | |||
| * split the previous fully qualified name into a package and a name. <p> | |||
| * | |||
| * For example: <tt>org.apache.Whatever</tt> will be split into <tt> | |||
| * org.apache</tt> and <tt>Whatever</tt> . | |||
| * | |||
| * @param root the root element to which the <tt>testsuite</tt> node should | |||
| * be appended. | |||
| * @param testsuite the element to append to the given root. It will | |||
| * slightly modify the original node to change the name attribute and | |||
| * add a package one. | |||
| */ | |||
| protected void addTestSuite( Element root, Element testsuite ) | |||
| { | |||
| String fullclassname = testsuite.getAttribute( ATTR_NAME ); | |||
| int pos = fullclassname.lastIndexOf( '.' ); | |||
| // a missing . might imply no package at all. Don't get fooled. | |||
| String pkgName = ( pos == -1 ) ? "" : fullclassname.substring( 0, pos ); | |||
| String classname = ( pos == -1 ) ? fullclassname : fullclassname.substring( pos + 1 ); | |||
| Element copy = (Element)DOMUtil.importNode( root, testsuite ); | |||
| // modify the name attribute and set the package | |||
| copy.setAttribute( ATTR_NAME, classname ); | |||
| copy.setAttribute( ATTR_PACKAGE, pkgName ); | |||
| } | |||
| /** | |||
| * <p> | |||
| * | |||
| * Create a DOM tree. Has 'testsuites' as firstchild and aggregates all | |||
| * testsuite results that exists in the base directory. | |||
| * | |||
| * @return the root element of DOM tree that aggregates all testsuites. | |||
| */ | |||
| protected Element createDocument() | |||
| throws TaskException | |||
| { | |||
| // create the dom tree | |||
| DocumentBuilder builder = getDocumentBuilder(); | |||
| Document doc = builder.newDocument(); | |||
| Element rootElement = doc.createElement( TESTSUITES ); | |||
| doc.appendChild( rootElement ); | |||
| // get all files and add them to the document | |||
| final File[] files = getFiles(); | |||
| for( int i = 0; i < files.length; i++ ) | |||
| { | |||
| try | |||
| { | |||
| getContext().debug( "Parsing file: '" + files[ i ] + "'" ); | |||
| //XXX there seems to be a bug in xerces 1.3.0 that doesn't like file object | |||
| // will investigate later. It does not use the given directory but | |||
| // the vm dir instead ? Works fine with crimson. | |||
| Document testsuiteDoc = builder.parse( "file:///" + files[ i ].getAbsolutePath() ); | |||
| Element elem = testsuiteDoc.getDocumentElement(); | |||
| // make sure that this is REALLY a testsuite. | |||
| if( TESTSUITE.equals( elem.getNodeName() ) ) | |||
| { | |||
| addTestSuite( rootElement, elem ); | |||
| } | |||
| else | |||
| { | |||
| // issue a warning. | |||
| getContext().warn( "the file " + files[ i ] + " is not a valid testsuite XML document" ); | |||
| } | |||
| } | |||
| catch( SAXException e ) | |||
| { | |||
| // a testcase might have failed and write a zero-length document, | |||
| // It has already failed, but hey.... mm. just put a warning | |||
| getContext().warn( "The file " + files[ i ] + " is not a valid XML document. It is possibly corrupted." ); | |||
| getContext().debug( ExceptionUtil.printStackTrace( e ) ); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| getContext().error( "Error while accessing file " + files[ i ] + ": " + e.getMessage() ); | |||
| } | |||
| } | |||
| return rootElement; | |||
| } | |||
| //----- from now, the methods are all related to DOM tree manipulation | |||
| /** | |||
| * Write the DOM tree to a file. | |||
| * | |||
| * @param doc the XML document to dump to disk. | |||
| * @param file the filename to write the document to. Should obviouslly be a | |||
| * .xml file. | |||
| * @throws IOException thrown if there is an error while writing the | |||
| * content. | |||
| */ | |||
| protected void writeDOMTree( Document doc, File file ) | |||
| throws IOException | |||
| { | |||
| OutputStream out = new FileOutputStream( file ); | |||
| PrintWriter wri = new PrintWriter( new OutputStreamWriter( out, "UTF8" ) ); | |||
| wri.write( "<?xml version=\"1.0\"?>\n" ); | |||
| ( new DOMElementWriter() ).write( doc.getDocumentElement(), wri, 0, " " ); | |||
| wri.flush(); | |||
| wri.close(); | |||
| // writers do not throw exceptions, so check for them. | |||
| if( wri.checkError() ) | |||
| { | |||
| throw new IOException( "Error while writing DOM content" ); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,38 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.junit; | |||
| import java.io.OutputStream; | |||
| import org.apache.xalan.xslt.XSLTInputSource; | |||
| import org.apache.xalan.xslt.XSLTProcessor; | |||
| import org.apache.xalan.xslt.XSLTProcessorFactory; | |||
| import org.apache.xalan.xslt.XSLTResultTarget; | |||
| /** | |||
| * Xalan 1 executor. It will need a lot of things in the classpath: xerces for | |||
| * the serialization, xalan and bsf for the extension. | |||
| * | |||
| * @author RT | |||
| * @todo do everything via reflection to avoid compile problems ? | |||
| */ | |||
| public class Xalan1Executor extends XalanExecutor | |||
| { | |||
| void execute() | |||
| throws Exception | |||
| { | |||
| XSLTProcessor processor = XSLTProcessorFactory.getProcessor(); | |||
| // need to quote otherwise it breaks because of "extra illegal tokens" | |||
| processor.setStylesheetParam( "output.dir", "'" + caller.getToDir().getAbsolutePath() + "'" ); | |||
| XSLTInputSource xml_src = new XSLTInputSource( caller.getDocument() ); | |||
| String system_id = caller.getStylesheetSystemId(); | |||
| XSLTInputSource xsl_src = new XSLTInputSource( system_id ); | |||
| OutputStream os = getOutputStream(); | |||
| XSLTResultTarget target = new XSLTResultTarget( os ); | |||
| processor.process( xml_src, xsl_src, target ); | |||
| } | |||
| } | |||
| @@ -1,40 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.junit; | |||
| import java.io.OutputStream; | |||
| import javax.xml.transform.Result; | |||
| import javax.xml.transform.Source; | |||
| import javax.xml.transform.Transformer; | |||
| import javax.xml.transform.TransformerFactory; | |||
| import javax.xml.transform.dom.DOMSource; | |||
| import javax.xml.transform.stream.StreamResult; | |||
| import javax.xml.transform.stream.StreamSource; | |||
| /** | |||
| * Xalan executor via JAXP. Nothing special must exists in the classpath besides | |||
| * of course, a parser, jaxp and xalan. | |||
| * | |||
| * @author RT | |||
| */ | |||
| public class Xalan2Executor extends XalanExecutor | |||
| { | |||
| void execute() | |||
| throws Exception | |||
| { | |||
| TransformerFactory tfactory = TransformerFactory.newInstance(); | |||
| String system_id = caller.getStylesheetSystemId(); | |||
| Source xsl_src = new StreamSource( system_id ); | |||
| Transformer tformer = tfactory.newTransformer( xsl_src ); | |||
| Source xml_src = new DOMSource( caller.getDocument() ); | |||
| OutputStream os = getOutputStream(); | |||
| tformer.setParameter( "output.dir", caller.getToDir().getAbsolutePath() ); | |||
| Result result = new StreamResult( os ); | |||
| tformer.transform( xml_src, result ); | |||
| } | |||
| } | |||
| @@ -1,127 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.junit; | |||
| import java.io.ByteArrayOutputStream; | |||
| import java.io.File; | |||
| import java.io.FileOutputStream; | |||
| import java.io.IOException; | |||
| import java.io.OutputStream; | |||
| import java.lang.reflect.Field; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| /** | |||
| * Command class that encapsulate specific behavior for each Xalan version. The | |||
| * right executor will be instantiated at runtime via class lookup. For | |||
| * instance, it will check first for Xalan2, then for Xalan1. | |||
| * | |||
| * @author RT | |||
| */ | |||
| abstract class XalanExecutor | |||
| { | |||
| /** | |||
| * the transformer caller | |||
| */ | |||
| protected AggregateTransformer caller; | |||
| /** | |||
| * Create a valid Xalan executor. It checks first if Xalan2 is present, if | |||
| * not it checks for xalan1. If none is available, it fails. | |||
| * | |||
| * @param caller object containing the transformation information. | |||
| * @return Description of the Returned Value | |||
| * @throws TaskException thrown if it could not find a valid xalan | |||
| * executor. | |||
| */ | |||
| static XalanExecutor newInstance( AggregateTransformer caller ) | |||
| throws TaskException | |||
| { | |||
| Class procVersion = null; | |||
| XalanExecutor executor = null; | |||
| try | |||
| { | |||
| procVersion = Class.forName( "org.apache.xalan.processor.XSLProcessorVersion" ); | |||
| executor = new Xalan2Executor(); | |||
| } | |||
| catch( Exception xalan2missing ) | |||
| { | |||
| try | |||
| { | |||
| procVersion = Class.forName( "org.apache.xalan.xslt.XSLProcessorVersion" ); | |||
| executor = (XalanExecutor)Class.forName( | |||
| "org.apache.tools.ant.taskdefs.optional.junit.Xalan1Executor" ).newInstance(); | |||
| } | |||
| catch( Exception xalan1missing ) | |||
| { | |||
| throw new TaskException( "Could not find xalan2 nor xalan1 in the classpath. Check http://xml.apache.org/xalan-j" ); | |||
| } | |||
| } | |||
| String version = getXalanVersion( procVersion ); | |||
| //caller.task.getLogger().info( "Using Xalan version: " + version ); | |||
| executor.setCaller( caller ); | |||
| return executor; | |||
| } | |||
| /** | |||
| * pretty useful data (Xalan version information) to display. | |||
| * | |||
| * @param procVersion Description of Parameter | |||
| * @return The XalanVersion value | |||
| */ | |||
| private static String getXalanVersion( Class procVersion ) | |||
| { | |||
| try | |||
| { | |||
| Field f = procVersion.getField( "S_VERSION" ); | |||
| return f.get( null ).toString(); | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| return "?"; | |||
| } | |||
| } | |||
| /** | |||
| * get the appropriate stream based on the format (frames/noframes) | |||
| * | |||
| * @return The OutputStream value | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| protected OutputStream getOutputStream() | |||
| throws IOException | |||
| { | |||
| if( caller.FRAMES.equals( caller.getFormat() ) ) | |||
| { | |||
| // dummy output for the framed report | |||
| // it's all done by extension... | |||
| return new ByteArrayOutputStream(); | |||
| } | |||
| else | |||
| { | |||
| return new FileOutputStream( new File( caller.getToDir(), "junit-noframes.html" ) ); | |||
| } | |||
| } | |||
| /** | |||
| * override to perform transformation | |||
| * | |||
| * @exception Exception Description of Exception | |||
| */ | |||
| abstract void execute() | |||
| throws Exception; | |||
| /** | |||
| * set the caller for this object. | |||
| * | |||
| * @param caller The new Caller value | |||
| */ | |||
| private final void setCaller( AggregateTransformer caller ) | |||
| { | |||
| this.caller = caller; | |||
| } | |||
| } | |||
| @@ -1,117 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.manifest; | |||
| /** | |||
| * Class to hold manifest attributes | |||
| * | |||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
| * @author Conor MacNeill | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @version $Revision$ $Date$ | |||
| */ | |||
| public class Attribute | |||
| { | |||
| /** | |||
| * The attribute's name | |||
| */ | |||
| private String m_name; | |||
| /** | |||
| * The attribute's value | |||
| */ | |||
| private String m_value; | |||
| /** | |||
| * Construct an empty attribute | |||
| */ | |||
| public Attribute() | |||
| { | |||
| } | |||
| /** | |||
| * Construct a manifest by specifying its name and value | |||
| * | |||
| * @param name the attribute's name | |||
| * @param value the Attribute's value | |||
| */ | |||
| public Attribute( final String name, final String value ) | |||
| { | |||
| m_name = name; | |||
| m_value = value; | |||
| } | |||
| /** | |||
| * Set the Attribute's name | |||
| * | |||
| * @param name the attribute's name | |||
| */ | |||
| public void setName( final String name ) | |||
| { | |||
| m_name = name; | |||
| } | |||
| /** | |||
| * Set the Attribute's value | |||
| * | |||
| * @param value the attribute's value | |||
| */ | |||
| public void setValue( final String value ) | |||
| { | |||
| m_value = value; | |||
| } | |||
| /** | |||
| * Get the Attribute's name | |||
| * | |||
| * @return the attribute's name. | |||
| */ | |||
| public String getName() | |||
| { | |||
| return m_name; | |||
| } | |||
| /** | |||
| * Get the Attribute's value | |||
| * | |||
| * @return the attribute's value. | |||
| */ | |||
| public String getValue() | |||
| { | |||
| return m_value; | |||
| } | |||
| /** | |||
| * Add a continuation line from the Manifest file When lines are too | |||
| * long in a manifest, they are continued on the next line by starting | |||
| * with a space. This method adds the continuation data to the attribute | |||
| * value by skipping the first character. | |||
| * | |||
| * @param line The feature to be added to the Continuation attribute | |||
| */ | |||
| public void addContinuation( final String line ) | |||
| { | |||
| m_value += line.substring( 1 ); | |||
| } | |||
| public boolean equals( Object object ) | |||
| { | |||
| if( !( object instanceof Attribute ) ) | |||
| { | |||
| return false; | |||
| } | |||
| final Attribute other = (Attribute)object; | |||
| final String name = other.m_name; | |||
| return | |||
| ( null != m_name && null != name && | |||
| m_name.toLowerCase().equals( name.toLowerCase() ) && | |||
| null != m_value && m_value.equals( other.m_value ) ); | |||
| } | |||
| } | |||
| @@ -1,175 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.manifest; | |||
| import java.util.Collection; | |||
| import java.util.Enumeration; | |||
| import java.util.Hashtable; | |||
| import java.util.Iterator; | |||
| import java.util.Set; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| /** | |||
| * Class to manage Manifest information | |||
| * | |||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
| * @author Conor MacNeill | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @version $Revision$ $Date$ | |||
| */ | |||
| public class Manifest | |||
| { | |||
| /** | |||
| * The version of this manifest | |||
| */ | |||
| private String m_manifestVersion = ManifestUtil.DEFAULT_MANIFEST_VERSION; | |||
| /** | |||
| * The main section of this manifest | |||
| */ | |||
| private Section m_mainSection = new Section(); | |||
| /** | |||
| * The named sections of this manifest | |||
| */ | |||
| private Hashtable m_sections = new Hashtable(); | |||
| public void setManifestVersion( final String manifestVersion ) | |||
| { | |||
| m_manifestVersion = manifestVersion; | |||
| } | |||
| public void setMainSection( final Section mainSection ) | |||
| { | |||
| m_mainSection = mainSection; | |||
| } | |||
| public void addAttribute( final Attribute attribute ) | |||
| throws ManifestException | |||
| { | |||
| m_mainSection.addAttribute( attribute ); | |||
| } | |||
| public void addSection( final Section section ) | |||
| throws ManifestException | |||
| { | |||
| if( section.getName() == null ) | |||
| { | |||
| final String message = "Sections must have a name"; | |||
| throw new ManifestException( message ); | |||
| } | |||
| m_sections.put( section.getName().toLowerCase(), section ); | |||
| } | |||
| public String[] getSectionNames( final Manifest other ) | |||
| { | |||
| final Set keys = other.m_sections.keySet(); | |||
| return (String[])keys.toArray( new String[ keys.size() ] ); | |||
| } | |||
| public String getManifestVersion() | |||
| { | |||
| return m_manifestVersion; | |||
| } | |||
| public Section getMainSection() | |||
| { | |||
| return m_mainSection; | |||
| } | |||
| public Section getSection( final String name ) | |||
| { | |||
| return (Section)m_sections.get( name ); | |||
| } | |||
| public Section[] getSections() | |||
| { | |||
| final Collection sections = m_sections.values(); | |||
| return (Section[])sections.toArray( new Section[ sections.size() ] ); | |||
| } | |||
| /** | |||
| * Merge the contents of the given manifest into this manifest | |||
| * | |||
| * @param other the Manifest to be merged with this one. | |||
| * @throws org.apache.tools.todo.taskdefs.manifest.ManifestException if there is a problem merging the manfest | |||
| * according to the Manifest spec. | |||
| */ | |||
| public void merge( final Manifest other ) | |||
| throws ManifestException | |||
| { | |||
| if( other.m_manifestVersion != null ) | |||
| { | |||
| m_manifestVersion = other.m_manifestVersion; | |||
| } | |||
| m_mainSection.merge( other.m_mainSection ); | |||
| mergeSections( other ); | |||
| } | |||
| public boolean equals( final Object object ) | |||
| { | |||
| if( !( object instanceof Manifest ) ) | |||
| { | |||
| return false; | |||
| } | |||
| final Manifest other = (Manifest)object; | |||
| if( m_manifestVersion == null && other.m_manifestVersion != null ) | |||
| { | |||
| return false; | |||
| } | |||
| else if( !m_manifestVersion.equals( other.m_manifestVersion ) ) | |||
| { | |||
| return false; | |||
| } | |||
| if( m_sections.size() != other.m_sections.size() ) | |||
| { | |||
| return false; | |||
| } | |||
| if( !m_mainSection.equals( other.m_mainSection ) ) | |||
| { | |||
| return false; | |||
| } | |||
| final Iterator e = m_sections.values().iterator(); | |||
| while( e.hasNext() ) | |||
| { | |||
| final Section section = (Section)e.next(); | |||
| final String key = section.getName().toLowerCase(); | |||
| final Section otherSection = (Section)other.m_sections.get( key ); | |||
| if( !section.equals( otherSection ) ) | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| private void mergeSections( final Manifest other ) | |||
| throws ManifestException | |||
| { | |||
| final String[] sections = getSectionNames( other ); | |||
| for( int i = 0; i < sections.length; i++ ) | |||
| { | |||
| final String sectionName = sections[ i ]; | |||
| final Section section = getSection( sectionName ); | |||
| final Section otherSection = other.getSection( sectionName ); | |||
| if( section == null ) | |||
| { | |||
| m_sections.put( sectionName.toLowerCase(), otherSection ); | |||
| } | |||
| else | |||
| { | |||
| section.merge( otherSection ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -1,64 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.manifest; | |||
| /** | |||
| * ManifestException is thrown when there is a problem parsing, generating or | |||
| * handling a Manifest. | |||
| * | |||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
| * @version $Revision$ $Date$ | |||
| */ | |||
| public class ManifestException | |||
| extends Exception | |||
| { | |||
| /** | |||
| * The Throwable that caused this exception to be thrown. | |||
| */ | |||
| private final Throwable m_throwable; | |||
| /** | |||
| * Basic constructor for exception that does not specify a message | |||
| */ | |||
| public ManifestException() | |||
| { | |||
| this( "", null ); | |||
| } | |||
| /** | |||
| * Basic constructor with a message | |||
| * | |||
| * @param message the message | |||
| */ | |||
| public ManifestException( final String message ) | |||
| { | |||
| this( message, null ); | |||
| } | |||
| /** | |||
| * Constructor that builds cascade so that other exception information can be retained. | |||
| * | |||
| * @param message the message | |||
| * @param throwable the throwable | |||
| */ | |||
| public ManifestException( final String message, final Throwable throwable ) | |||
| { | |||
| super( message ); | |||
| m_throwable = throwable; | |||
| } | |||
| /** | |||
| * Retrieve root cause of the exception. | |||
| * | |||
| * @return the root cause | |||
| */ | |||
| public final Throwable getCause() | |||
| { | |||
| return m_throwable; | |||
| } | |||
| } | |||
| @@ -1,27 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.manifest; | |||
| import org.apache.tools.todo.types.EnumeratedAttribute; | |||
| /** | |||
| * Helper class for Manifest's mode attribute. | |||
| * | |||
| * @author Conor MacNeill | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
| * @version $Revision$ $Date$ | |||
| */ | |||
| public class ManifestMode | |||
| extends EnumeratedAttribute | |||
| { | |||
| public String[] getValues() | |||
| { | |||
| return new String[]{"update", "replace"}; | |||
| } | |||
| } | |||
| @@ -1,198 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.manifest; | |||
| import java.io.File; | |||
| import java.io.FileReader; | |||
| import java.io.FileWriter; | |||
| import java.io.IOException; | |||
| import java.io.PrintWriter; | |||
| import java.util.ArrayList; | |||
| import java.util.Iterator; | |||
| import org.apache.avalon.excalibur.io.IOUtil; | |||
| import org.apache.myrmidon.api.AbstractTask; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.tools.todo.taskdefs.manifest.Manifest; | |||
| import org.apache.tools.todo.taskdefs.manifest.Section; | |||
| /** | |||
| * Class to manage Manifest information | |||
| * | |||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
| * @author Conor MacNeill | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @version $Revision$ $Date$ | |||
| */ | |||
| public class ManifestTask | |||
| extends AbstractTask | |||
| { | |||
| private File m_destFile; | |||
| private ManifestMode m_mode; | |||
| private Manifest m_manifest = new Manifest(); | |||
| /** | |||
| * Construct an empty manifest | |||
| */ | |||
| public ManifestTask() | |||
| throws TaskException | |||
| { | |||
| m_mode = new ManifestMode(); | |||
| m_mode.setValue( "replace" ); | |||
| } | |||
| /** | |||
| * The name of the manifest file to write. | |||
| */ | |||
| public void setDestFile( final File destFile ) | |||
| { | |||
| m_destFile = destFile; | |||
| } | |||
| /** | |||
| * Shall we update or replace an existing manifest? | |||
| */ | |||
| public void setMode( final ManifestMode mode ) | |||
| { | |||
| m_mode = mode; | |||
| } | |||
| public void setManifestVersion( String manifestVersion ) | |||
| { | |||
| m_manifest.setManifestVersion( manifestVersion ); | |||
| } | |||
| public void addMainSection( Section mainSection ) | |||
| throws Exception | |||
| { | |||
| m_manifest.setMainSection( mainSection ); | |||
| } | |||
| /** | |||
| * Get the warnings for this manifest. | |||
| * | |||
| * @return an enumeration of warning strings | |||
| */ | |||
| public Iterator getWarnings() | |||
| { | |||
| ArrayList warnings = new ArrayList(); | |||
| for( Iterator e2 = m_manifest.getMainSection().getWarnings(); e2.hasNext(); ) | |||
| { | |||
| warnings.add( e2.next() ); | |||
| } | |||
| final Section[] sections = m_manifest.getSections(); | |||
| for( int i = 0; i < sections.length; i++ ) | |||
| { | |||
| final Section section = sections[ i ]; | |||
| for( Iterator e2 = section.getWarnings(); e2.hasNext(); ) | |||
| { | |||
| warnings.add( e2.next() ); | |||
| } | |||
| } | |||
| return warnings.iterator(); | |||
| } | |||
| public void addAttribute( final Attribute attribute ) | |||
| throws ManifestException, TaskException | |||
| { | |||
| m_manifest.addAttribute( attribute ); | |||
| } | |||
| public void addSection( final Section section ) | |||
| throws TaskException | |||
| { | |||
| try | |||
| { | |||
| m_manifest.addSection( section ); | |||
| } | |||
| catch( final ManifestException me ) | |||
| { | |||
| throw new TaskException( me.getMessage(), me ); | |||
| } | |||
| } | |||
| /** | |||
| * Create or update the Manifest when used as a task. | |||
| * | |||
| * @exception org.apache.myrmidon.api.TaskException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| if( null == m_destFile ) | |||
| { | |||
| throw new TaskException( "the file attribute is required" ); | |||
| } | |||
| Manifest toWrite = getDefaultManifest(); | |||
| if( m_mode.getValue().equals( "update" ) && m_destFile.exists() ) | |||
| { | |||
| FileReader f = null; | |||
| try | |||
| { | |||
| f = new FileReader( m_destFile ); | |||
| final Manifest other = ManifestUtil.buildManifest( f ); | |||
| toWrite.merge( other ); | |||
| } | |||
| catch( ManifestException m ) | |||
| { | |||
| throw new TaskException( "Existing manifest " + m_destFile | |||
| + " is invalid", m ); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| throw new | |||
| TaskException( "Failed to read " + m_destFile, e ); | |||
| } | |||
| finally | |||
| { | |||
| IOUtil.shutdownReader( f ); | |||
| } | |||
| } | |||
| try | |||
| { | |||
| toWrite.merge( m_manifest ); | |||
| } | |||
| catch( ManifestException m ) | |||
| { | |||
| throw new TaskException( "Manifest is invalid", m ); | |||
| } | |||
| PrintWriter w = null; | |||
| try | |||
| { | |||
| w = new PrintWriter( new FileWriter( m_destFile ) ); | |||
| ManifestUtil.write( toWrite, w ); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| throw new TaskException( "Failed to write " + m_destFile, e ); | |||
| } | |||
| finally | |||
| { | |||
| IOUtil.shutdownWriter( w ); | |||
| } | |||
| } | |||
| private Manifest getDefaultManifest() | |||
| throws TaskException | |||
| { | |||
| try | |||
| { | |||
| return ManifestUtil.getDefaultManifest(); | |||
| } | |||
| catch( final ManifestException me ) | |||
| { | |||
| throw new TaskException( me.getMessage(), me ); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,242 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.manifest; | |||
| import java.io.BufferedReader; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.io.InputStreamReader; | |||
| import java.io.PrintWriter; | |||
| import java.io.Reader; | |||
| import java.io.UnsupportedEncodingException; | |||
| import java.util.jar.Attributes; | |||
| import org.apache.tools.todo.taskdefs.manifest.Manifest; | |||
| import org.apache.tools.todo.taskdefs.manifest.Section; | |||
| import org.apache.tools.todo.taskdefs.manifest.Attribute; | |||
| /** | |||
| * Utility methods for manifest stuff. | |||
| * | |||
| * @author Conor MacNeill | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
| * @version $Revision$ $Date$ | |||
| */ | |||
| public final class ManifestUtil | |||
| { | |||
| /** | |||
| * The Name Attribute is the first in a named section | |||
| */ | |||
| public final static String ATTRIBUTE_NAME = "Name"; | |||
| /** | |||
| * The From Header is disallowed in a Manifest | |||
| */ | |||
| public final static String ATTRIBUTE_FROM = "From"; | |||
| /** | |||
| * The Class-Path Header is special - it can be duplicated | |||
| */ | |||
| public final static String ATTRIBUTE_CLASSPATH = Attributes.Name.CLASS_PATH.toString(); | |||
| /** | |||
| * Default Manifest version if one is not specified | |||
| */ | |||
| public final static String DEFAULT_MANIFEST_VERSION = "1.0"; | |||
| /** | |||
| * The max length of a line in a Manifest | |||
| */ | |||
| public final static int MAX_LINE_LENGTH = 70; | |||
| public static Attribute buildAttribute( final String line ) | |||
| throws ManifestException | |||
| { | |||
| final Attribute attribute = new Attribute(); | |||
| parse( attribute, line ); | |||
| return attribute; | |||
| } | |||
| public static Manifest buildManifest( final Reader reader ) | |||
| throws ManifestException, IOException | |||
| { | |||
| final Manifest manifest = new Manifest(); | |||
| BufferedReader bufferedReader = new BufferedReader( reader ); | |||
| // This should be the manifest version | |||
| final Section mainSection = manifest.getMainSection(); | |||
| String nextSectionName = mainSection.read( bufferedReader ); | |||
| final String readManifestVersion = | |||
| mainSection.getAttributeValue( Attributes.Name.MANIFEST_VERSION.toString() ); | |||
| if( readManifestVersion != null ) | |||
| { | |||
| manifest.setManifestVersion( readManifestVersion ); | |||
| mainSection.removeAttribute( Attributes.Name.MANIFEST_VERSION.toString() ); | |||
| } | |||
| String line = null; | |||
| while( ( line = bufferedReader.readLine() ) != null ) | |||
| { | |||
| if( line.length() == 0 ) | |||
| { | |||
| continue; | |||
| } | |||
| Section section = new Section(); | |||
| if( nextSectionName == null ) | |||
| { | |||
| Attribute sectionName = ManifestUtil.buildAttribute( line ); | |||
| if( !sectionName.getName().equalsIgnoreCase( ManifestUtil.ATTRIBUTE_NAME ) ) | |||
| { | |||
| throw new ManifestException( "Manifest sections should start with a \"" + ManifestUtil.ATTRIBUTE_NAME + | |||
| "\" attribute and not \"" + sectionName.getName() + "\"" ); | |||
| } | |||
| nextSectionName = sectionName.getValue(); | |||
| } | |||
| else | |||
| { | |||
| // we have already started reading this section | |||
| // this line is the first attribute. set it and then let the normal | |||
| // read handle the rest | |||
| Attribute firstAttribute = ManifestUtil.buildAttribute( line ); | |||
| section.addAttributeAndCheck( firstAttribute ); | |||
| } | |||
| section.setName( nextSectionName ); | |||
| nextSectionName = section.read( bufferedReader ); | |||
| manifest.addSection( section ); | |||
| } | |||
| return manifest; | |||
| } | |||
| /** | |||
| * Construct a manifest from Ant's default manifest file. | |||
| */ | |||
| public static Manifest getDefaultManifest() | |||
| throws ManifestException | |||
| { | |||
| try | |||
| { | |||
| final InputStream input = getInputStream(); | |||
| final InputStreamReader reader = getReader( input ); | |||
| return buildManifest( reader ); | |||
| } | |||
| catch( final IOException ioe ) | |||
| { | |||
| throw new ManifestException( "Unable to read default manifest", ioe ); | |||
| } | |||
| } | |||
| private static InputStream getInputStream() | |||
| throws ManifestException | |||
| { | |||
| final String location = "default.mf"; | |||
| final InputStream input = ManifestUtil.class.getResourceAsStream( location ); | |||
| if( null == input ) | |||
| { | |||
| throw new ManifestException( "Could not find default manifest: " + location ); | |||
| } | |||
| return input; | |||
| } | |||
| private static InputStreamReader getReader( final InputStream input ) | |||
| { | |||
| try | |||
| { | |||
| return new InputStreamReader( input, "ASCII" ); | |||
| } | |||
| catch( final UnsupportedEncodingException uee ) | |||
| { | |||
| return new InputStreamReader( input ); | |||
| } | |||
| } | |||
| /** | |||
| * Parse a line into name and value pairs | |||
| * | |||
| * @param line the line to be parsed | |||
| * @throws org.apache.tools.todo.taskdefs.manifest.ManifestException if the line does not contain a colon | |||
| * separating the name and value | |||
| */ | |||
| public static void parse( final Attribute attribute, final String line ) | |||
| throws ManifestException | |||
| { | |||
| final int index = line.indexOf( ": " ); | |||
| if( index == -1 ) | |||
| { | |||
| throw new ManifestException( "Manifest line \"" + line + "\" is not valid as it does not " + | |||
| "contain a name and a value separated by ': ' " ); | |||
| } | |||
| final String name = line.substring( 0, index ); | |||
| final String value = line.substring( index + 2 ); | |||
| attribute.setName( name ); | |||
| attribute.setValue( value ); | |||
| } | |||
| public static void write( final Attribute attribute, final PrintWriter writer ) | |||
| throws IOException | |||
| { | |||
| final String name = attribute.getName(); | |||
| final String value = attribute.getValue(); | |||
| String line = name + ": " + value; | |||
| while( line.getBytes().length > MAX_LINE_LENGTH ) | |||
| { | |||
| // try to find a MAX_LINE_LENGTH byte section | |||
| int breakIndex = MAX_LINE_LENGTH; | |||
| String section = line.substring( 0, breakIndex ); | |||
| while( section.getBytes().length > MAX_LINE_LENGTH && breakIndex > 0 ) | |||
| { | |||
| breakIndex--; | |||
| section = line.substring( 0, breakIndex ); | |||
| } | |||
| if( breakIndex == 0 ) | |||
| { | |||
| throw new IOException( "Unable to write manifest line " + name + ": " + value ); | |||
| } | |||
| writer.println( section ); | |||
| line = " " + line.substring( breakIndex ); | |||
| } | |||
| writer.println( line ); | |||
| } | |||
| /** | |||
| * Write the manifest out to a print writer. | |||
| * | |||
| * @param writer the Writer to which the manifest is written | |||
| * @throws java.io.IOException if the manifest cannot be written | |||
| */ | |||
| public static void write( Manifest manifest, PrintWriter writer ) | |||
| throws IOException | |||
| { | |||
| final String sigVersionKey = Attributes.Name.SIGNATURE_VERSION.toString(); | |||
| writer.println( Attributes.Name.MANIFEST_VERSION + ": " + manifest.getManifestVersion() ); | |||
| final String signatureVersion = | |||
| manifest.getMainSection().getAttributeValue( sigVersionKey ); | |||
| if( signatureVersion != null ) | |||
| { | |||
| writer.println( Attributes.Name.SIGNATURE_VERSION + ": " + signatureVersion ); | |||
| manifest.getMainSection().removeAttribute( sigVersionKey ); | |||
| } | |||
| manifest.getMainSection().write( writer ); | |||
| if( signatureVersion != null ) | |||
| { | |||
| try | |||
| { | |||
| manifest.getMainSection().addAttribute( new Attribute( sigVersionKey, signatureVersion ) ); | |||
| } | |||
| catch( ManifestException e ) | |||
| { | |||
| // shouldn't happen - ignore | |||
| } | |||
| } | |||
| final Section[] sections = manifest.getSections(); | |||
| for( int i = 0; i < sections.length; i++ ) | |||
| { | |||
| sections[ i ].write( writer ); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,334 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.manifest; | |||
| import java.io.BufferedReader; | |||
| import java.io.IOException; | |||
| import java.io.PrintWriter; | |||
| import java.util.ArrayList; | |||
| import java.util.Enumeration; | |||
| import java.util.Hashtable; | |||
| import java.util.Iterator; | |||
| /** | |||
| * Class to represent an individual section in the Manifest. A section | |||
| * consists of a set of attribute values, separated from other sections by a | |||
| * blank line. | |||
| * | |||
| * @author Conor MacNeill | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
| * @version $Revision$ $Date$ | |||
| */ | |||
| public class Section | |||
| { | |||
| private final ArrayList m_warnings = new ArrayList(); | |||
| /** | |||
| * The section's name if any. The main section in a manifest is unnamed. | |||
| */ | |||
| private String m_name; | |||
| /** | |||
| * The section's attributes. | |||
| */ | |||
| private final Hashtable m_attributes = new Hashtable(); | |||
| /** | |||
| * Set the Section's name | |||
| * | |||
| * @param name the section's name | |||
| */ | |||
| public void setName( final String name ) | |||
| { | |||
| m_name = name; | |||
| } | |||
| /** | |||
| * Get the value of the attribute with the name given. | |||
| * | |||
| * @param attributeName the name of the attribute to be returned. | |||
| * @return the attribute's value or null if the attribute does not exist | |||
| * in the section | |||
| */ | |||
| public String getAttributeValue( final String attributeName ) | |||
| { | |||
| final Object attributeObject = m_attributes.get( attributeName.toLowerCase() ); | |||
| if( null == attributeObject ) | |||
| { | |||
| return null; | |||
| } | |||
| else if( attributeObject instanceof Attribute ) | |||
| { | |||
| final Attribute attribute = (Attribute)attributeObject; | |||
| return attribute.getValue(); | |||
| } | |||
| else | |||
| { | |||
| String value = ""; | |||
| final ArrayList attributes = (ArrayList)attributeObject; | |||
| Iterator e = attributes.iterator(); | |||
| while( e.hasNext() ) | |||
| { | |||
| final Attribute classpathAttribute = (Attribute)e.next(); | |||
| value += classpathAttribute.getValue() + " "; | |||
| } | |||
| return value.trim(); | |||
| } | |||
| } | |||
| /** | |||
| * Get the Section's name | |||
| * | |||
| * @return the section's name. | |||
| */ | |||
| public String getName() | |||
| { | |||
| return m_name; | |||
| } | |||
| public Iterator getWarnings() | |||
| { | |||
| return m_warnings.iterator(); | |||
| } | |||
| /** | |||
| * Add an attribute to the section | |||
| * | |||
| * @param attribute the attribute to be added. | |||
| * @return the value of the attribute if it is a name attribute - null | |||
| * other wise | |||
| * @throws org.apache.tools.todo.taskdefs.manifest.ManifestException if the attribute already exists in this | |||
| * section. | |||
| */ | |||
| public String addAttributeAndCheck( Attribute attribute ) | |||
| throws ManifestException | |||
| { | |||
| if( attribute.getName() == null || attribute.getValue() == null ) | |||
| { | |||
| throw new ManifestException( "Attributes must have name and value" ); | |||
| } | |||
| if( attribute.getName().equalsIgnoreCase( ManifestUtil.ATTRIBUTE_NAME ) ) | |||
| { | |||
| m_warnings.add( "\"" + ManifestUtil.ATTRIBUTE_NAME + "\" attributes should not occur in the " + | |||
| "main section and must be the first element in all " + | |||
| "other sections: \"" + attribute.getName() + ": " + attribute.getValue() + "\"" ); | |||
| return attribute.getValue(); | |||
| } | |||
| if( attribute.getName().toLowerCase().startsWith( ManifestUtil.ATTRIBUTE_FROM.toLowerCase() ) ) | |||
| { | |||
| m_warnings.add( "Manifest attributes should not start with \"" + | |||
| ManifestUtil.ATTRIBUTE_FROM + "\" in \"" + attribute.getName() + ": " + attribute.getValue() + "\"" ); | |||
| } | |||
| else | |||
| { | |||
| // classpath attributes go into a vector | |||
| String attributeName = attribute.getName().toLowerCase(); | |||
| if( attributeName.equals( ManifestUtil.ATTRIBUTE_CLASSPATH ) ) | |||
| { | |||
| ArrayList classpathAttrs = (ArrayList)m_attributes.get( attributeName ); | |||
| if( classpathAttrs == null ) | |||
| { | |||
| classpathAttrs = new ArrayList(); | |||
| m_attributes.put( attributeName, classpathAttrs ); | |||
| } | |||
| classpathAttrs.add( attribute ); | |||
| } | |||
| else if( m_attributes.containsKey( attributeName ) ) | |||
| { | |||
| throw new ManifestException( "The attribute \"" + attribute.getName() + "\" may not " + | |||
| "occur more than once in the same section" ); | |||
| } | |||
| else | |||
| { | |||
| m_attributes.put( attributeName, attribute ); | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| public void addAttribute( final Attribute attribute ) | |||
| throws ManifestException | |||
| { | |||
| String check = addAttributeAndCheck( attribute ); | |||
| if( check != null ) | |||
| { | |||
| throw new ManifestException( "Specify the section name using the \"name\" attribute of the <section> element rather " + | |||
| "than using a \"Name\" manifest attribute" ); | |||
| } | |||
| } | |||
| public boolean equals( Object rhs ) | |||
| { | |||
| if( !( rhs instanceof Section ) ) | |||
| { | |||
| return false; | |||
| } | |||
| Section rhsSection = (Section)rhs; | |||
| if( m_attributes.size() != rhsSection.m_attributes.size() ) | |||
| { | |||
| return false; | |||
| } | |||
| for( Enumeration e = m_attributes.elements(); e.hasMoreElements(); ) | |||
| { | |||
| Attribute attribute = (Attribute)e.nextElement(); | |||
| Attribute rshAttribute = (Attribute)rhsSection.m_attributes.get( attribute.getName().toLowerCase() ); | |||
| if( !attribute.equals( rshAttribute ) ) | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| /** | |||
| * Merge in another section | |||
| * | |||
| * @param section the section to be merged with this one. | |||
| * @throws org.apache.tools.todo.taskdefs.manifest.ManifestException if the sections cannot be merged. | |||
| */ | |||
| public void merge( Section section ) | |||
| throws ManifestException | |||
| { | |||
| if( m_name == null && section.getName() != null || | |||
| m_name != null && !( m_name.equalsIgnoreCase( section.getName() ) ) ) | |||
| { | |||
| throw new ManifestException( "Unable to merge sections with different names" ); | |||
| } | |||
| for( Enumeration e = section.m_attributes.keys(); e.hasMoreElements(); ) | |||
| { | |||
| String attributeName = (String)e.nextElement(); | |||
| if( attributeName.equals( ManifestUtil.ATTRIBUTE_CLASSPATH ) && | |||
| m_attributes.containsKey( attributeName ) ) | |||
| { | |||
| // classpath entries are vetors which are merged | |||
| ArrayList classpathAttrs = (ArrayList)section.m_attributes.get( attributeName ); | |||
| ArrayList ourClasspathAttrs = (ArrayList)m_attributes.get( attributeName ); | |||
| for( Iterator e2 = classpathAttrs.iterator(); e2.hasNext(); ) | |||
| { | |||
| ourClasspathAttrs.add( e2.next() ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| // the merge file always wins | |||
| m_attributes.put( attributeName, section.m_attributes.get( attributeName ) ); | |||
| } | |||
| } | |||
| // add in the warnings | |||
| for( Iterator e = section.m_warnings.iterator(); e.hasNext(); ) | |||
| { | |||
| m_warnings.add( e.next() ); | |||
| } | |||
| } | |||
| /** | |||
| * Read a section through a reader | |||
| * | |||
| * @param reader the reader from which the section is read | |||
| * @return the name of the next section if it has been read as part of | |||
| * this section - This only happens if the Manifest is malformed. | |||
| * @throws org.apache.tools.todo.taskdefs.manifest.ManifestException if the section is not valid according to | |||
| * the JAR spec | |||
| * @throws java.io.IOException if the section cannot be read from the reader. | |||
| */ | |||
| public String read( BufferedReader reader ) | |||
| throws ManifestException, IOException | |||
| { | |||
| Attribute attribute = null; | |||
| while( true ) | |||
| { | |||
| String line = reader.readLine(); | |||
| if( line == null || line.length() == 0 ) | |||
| { | |||
| return null; | |||
| } | |||
| if( line.charAt( 0 ) == ' ' ) | |||
| { | |||
| // continuation line | |||
| if( attribute == null ) | |||
| { | |||
| if( m_name != null ) | |||
| { | |||
| // a continuation on the first line is a continuation of the name - concatenate | |||
| // this line and the name | |||
| m_name += line.substring( 1 ); | |||
| } | |||
| else | |||
| { | |||
| throw new ManifestException( "Can't start an attribute with a continuation line " + line ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| attribute.addContinuation( line ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| attribute = ManifestUtil.buildAttribute( line ); | |||
| String nameReadAhead = addAttributeAndCheck( attribute ); | |||
| if( nameReadAhead != null ) | |||
| { | |||
| return nameReadAhead; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Remove tge given attribute from the section | |||
| * | |||
| * @param attributeName the name of the attribute to be removed. | |||
| */ | |||
| public void removeAttribute( String attributeName ) | |||
| { | |||
| m_attributes.remove( attributeName.toLowerCase() ); | |||
| } | |||
| /** | |||
| * Write the section out to a print writer. | |||
| * | |||
| * @param writer the Writer to which the section is written | |||
| * @throws java.io.IOException if the section cannot be written | |||
| */ | |||
| public void write( PrintWriter writer ) | |||
| throws IOException | |||
| { | |||
| if( m_name != null ) | |||
| { | |||
| Attribute nameAttr = new Attribute( ManifestUtil.ATTRIBUTE_NAME, m_name ); | |||
| ManifestUtil.write( nameAttr, writer ); | |||
| } | |||
| for( Enumeration e = m_attributes.elements(); e.hasMoreElements(); ) | |||
| { | |||
| Object object = e.nextElement(); | |||
| if( object instanceof Attribute ) | |||
| { | |||
| Attribute attribute = (Attribute)object; | |||
| ManifestUtil.write( attribute, writer ); | |||
| } | |||
| else | |||
| { | |||
| ArrayList attrList = (ArrayList)object; | |||
| for( Iterator e2 = attrList.iterator(); e2.hasNext(); ) | |||
| { | |||
| Attribute attribute = (Attribute)e2.next(); | |||
| ManifestUtil.write( attribute, writer ); | |||
| } | |||
| } | |||
| } | |||
| writer.println(); | |||
| } | |||
| } | |||
| @@ -1,3 +0,0 @@ | |||
| Manifest-Version: 1.0 | |||
| Created-By: Apache Ant @VERSION@ | |||
| @@ -1,54 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.net; | |||
| import java.util.Locale; | |||
| import org.apache.tools.todo.types.EnumeratedAttribute; | |||
| public class Action | |||
| extends EnumeratedAttribute | |||
| { | |||
| private final static String[] validActions = new String[] | |||
| { | |||
| "send", "put", "recv", "get", "del", "delete", "list", "mkdir" | |||
| }; | |||
| public int getAction() | |||
| { | |||
| String actionL = getValue().toLowerCase( Locale.US ); | |||
| if( actionL.equals( "send" ) || | |||
| actionL.equals( "put" ) ) | |||
| { | |||
| return FTP.SEND_FILES; | |||
| } | |||
| else if( actionL.equals( "recv" ) || | |||
| actionL.equals( "get" ) ) | |||
| { | |||
| return FTP.GET_FILES; | |||
| } | |||
| else if( actionL.equals( "del" ) || | |||
| actionL.equals( "delete" ) ) | |||
| { | |||
| return FTP.DEL_FILES; | |||
| } | |||
| else if( actionL.equals( "list" ) ) | |||
| { | |||
| return FTP.LIST_FILES; | |||
| } | |||
| else if( actionL.equals( "mkdir" ) ) | |||
| { | |||
| return FTP.MK_DIR; | |||
| } | |||
| return FTP.SEND_FILES; | |||
| } | |||
| public String[] getValues() | |||
| { | |||
| return validActions; | |||
| } | |||
| } | |||
| @@ -1,63 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.todo.taskdefs.net; | |||
| import com.oroinc.net.telnet.TelnetClient; | |||
| import java.io.InputStream; | |||
| import java.io.OutputStream; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| /** | |||
| * This class handles the abstraction of the telnet protocol. Currently it | |||
| * is a wrapper around <a href="www.oroinc.com">ORO</a> 's NetComponents | |||
| */ | |||
| public class AntTelnetClient | |||
| extends TelnetClient | |||
| { | |||
| private TelnetTask m_task; | |||
| public AntTelnetClient( final TelnetTask task ) | |||
| { | |||
| m_task = task; | |||
| } | |||
| /** | |||
| * Write this string to the telnet session. | |||
| */ | |||
| public void sendString( final String string, final boolean echoString ) | |||
| throws TaskException | |||
| { | |||
| final OutputStream output = this.getOutputStream(); | |||
| m_task.doSendString( output, string, echoString ); | |||
| } | |||
| /** | |||
| * Read from the telnet session until the string we are waiting for is | |||
| * found | |||
| */ | |||
| public void waitForString( final String string ) | |||
| throws TaskException | |||
| { | |||
| waitForString( string, null ); | |||
| } | |||
| /** | |||
| * Read from the telnet session until the string we are waiting for is | |||
| * found or the timeout has been reached | |||
| * | |||
| * @parm s The string to wait on | |||
| * @parm timeout The maximum number of seconds to wait | |||
| */ | |||
| public void waitForString( final String string, | |||
| final Integer timeout ) | |||
| throws TaskException | |||
| { | |||
| final InputStream input = this.getInputStream(); | |||
| m_task.doWaitForString( input, string, timeout ); | |||
| } | |||
| } | |||