Darcs: **/_darcs, **/_darcs/**, **/.darcsrepo, **/.darcsrepo/****/-darcs-backup*, **/.darcs-temp-mail
*
@@ -46,85 +50,73 @@ public abstract class AbstractScanner
*/
public static final String[] DEFAULTEXCLUDES = {
// Miscellaneous typical temporary files
- "**/*~",
- "**/#*#",
- "**/.#*",
- "**/%*%",
- "**/._*",
-
+ "**/*~", "**/#*#", "**/.#*", "**/%*%", "**/._*",
+
// CVS
- "**/CVS",
- "**/CVS/**",
- "**/.cvsignore",
-
+ "**/CVS", "**/CVS/**", "**/.cvsignore",
+
// RCS
- "**/RCS",
- "**/RCS/**",
-
+ "**/RCS", "**/RCS/**",
+
// SCCS
- "**/SCCS",
- "**/SCCS/**",
-
+ "**/SCCS", "**/SCCS/**",
+
// Visual SourceSafe
"**/vssver.scc",
-
+
+ // MKS
+ "**/project.pj",
+
// Subversion
- "**/.svn",
- "**/.svn/**",
-
+ "**/.svn", "**/.svn/**",
+
// Arch
- "**/.arch-ids",
- "**/.arch-ids/**",
-
+ "**/.arch-ids", "**/.arch-ids/**",
+
//Bazaar
- "**/.bzr",
- "**/.bzr/**",
-
+ "**/.bzr", "**/.bzr/**",
+
//SurroundSCM
"**/.MySCMServerInfo",
-
+
// Mac
"**/.DS_Store",
-
+
// Serena Dimensions Version 10
- "**/.metadata",
- "**/.metadata/**",
-
+ "**/.metadata", "**/.metadata/**",
+
// Mercurial
- "**/.hg",
- "**/.hg/**",
-
+ "**/.hg", "**/.hg/**",
+
// git
- "**/.git",
- "**/.git/**",
-
+ "**/.git", "**/.gitignore", "**/.gitattributes", "**/.git/**",
+
// BitKeeper
- "**/BitKeeper",
- "**/BitKeeper/**",
- "**/ChangeSet",
- "**/ChangeSet/**",
-
+ "**/BitKeeper", "**/BitKeeper/**", "**/ChangeSet", "**/ChangeSet/**",
+
// darcs
- "**/_darcs",
- "**/_darcs/**",
- "**/.darcsrepo",
- "**/.darcsrepo/**",
- "**/-darcs-backup*",
- "**/.darcs-temp-mail"
- };
-
- /** The patterns for the files to be included. */
+ "**/_darcs", "**/_darcs/**", "**/.darcsrepo", "**/.darcsrepo/**", "**/-darcs-backup*", "**/.darcs-temp-mail" };
+
+ /**
+ * The patterns for the files to be included.
+ */
protected String[] includes;
-
- /** The patterns for the files to be excluded. */
+
+ private MatchPatterns includesPatterns;
+
+ /**
+ * The patterns for the files to be excluded.
+ */
protected String[] excludes;
-
+
+ private MatchPatterns excludesPatterns;
+
/**
* Whether or not the file system should be treated as a case sensitive
* one.
*/
protected boolean isCaseSensitive = true;
-
+
/**
* Sets whether or not the file system should be regarded as case sensitive.
*
@@ -135,11 +127,11 @@ public void setCaseSensitive( boolean isCaseSensitive )
{
this.isCaseSensitive = isCaseSensitive;
}
-
+
/**
* Tests whether or not a given path matches the start of a given
* pattern up to the first "**".
- *
+ *
* This is not a general purpose test and should only be used if you
* can live with false positives. For example, pattern=**\a
* and str=b will yield true.
@@ -148,39 +140,36 @@ public void setCaseSensitive( boolean isCaseSensitive )
* null.
* @param str The path to match, as a String. Must not be
* null.
- *
* @return whether or not a given path matches the start of a given
- * pattern up to the first "**".
+ * pattern up to the first "**".
*/
protected static boolean matchPatternStart( String pattern, String str )
{
return SelectorUtils.matchPatternStart( pattern, str );
}
-
+
/**
* Tests whether or not a given path matches the start of a given
* pattern up to the first "**".
- *
+ *
* This is not a general purpose test and should only be used if you
* can live with false positives. For example, pattern=**\a
* and str=b will yield true.
*
- * @param pattern The pattern to match against. Must not be
- * null.
- * @param str The path to match, as a String. Must not be
- * null.
+ * @param pattern The pattern to match against. Must not be
+ * null.
+ * @param str The path to match, as a String. Must not be
+ * null.
* @param isCaseSensitive Whether or not matching should be performed
* case sensitively.
- *
* @return whether or not a given path matches the start of a given
- * pattern up to the first "**".
+ * pattern up to the first "**".
*/
- protected static boolean matchPatternStart( String pattern, String str,
- boolean isCaseSensitive )
+ protected static boolean matchPatternStart( String pattern, String str, boolean isCaseSensitive )
{
return SelectorUtils.matchPatternStart( pattern, str, isCaseSensitive );
}
-
+
/**
* Tests whether or not a given path matches a given pattern.
*
@@ -188,7 +177,6 @@ protected static boolean matchPatternStart( String pattern, String str,
* null.
* @param str The path to match, as a String. Must not be
* null.
- *
* @return true if the pattern matches against the string,
* or false otherwise.
*/
@@ -196,26 +184,24 @@ protected static boolean matchPath( String pattern, String str )
{
return SelectorUtils.matchPath( pattern, str );
}
-
+
/**
* Tests whether or not a given path matches a given pattern.
*
- * @param pattern The pattern to match against. Must not be
- * null.
- * @param str The path to match, as a String. Must not be
- * null.
+ * @param pattern The pattern to match against. Must not be
+ * null.
+ * @param str The path to match, as a String. Must not be
+ * null.
* @param isCaseSensitive Whether or not matching should be performed
* case sensitively.
- *
* @return true if the pattern matches against the string,
* or false otherwise.
*/
- protected static boolean matchPath( String pattern, String str,
- boolean isCaseSensitive )
+ protected static boolean matchPath( String pattern, String str, boolean isCaseSensitive )
{
return SelectorUtils.matchPath( pattern, str, isCaseSensitive );
}
-
+
/**
* Tests whether or not a string matches against a pattern.
* The pattern may contain two special characters:
@@ -226,7 +212,6 @@ protected static boolean matchPath( String pattern, String str,
* Must not be null.
* @param str The string which must be matched against the pattern.
* Must not be null.
- *
* @return true if the string matches against the pattern,
* or false otherwise.
*/
@@ -234,43 +219,40 @@ public static boolean match( String pattern, String str )
{
return SelectorUtils.match( pattern, str );
}
-
+
/**
* Tests whether or not a string matches against a pattern.
* The pattern may contain two special characters:
* '*' means zero or more characters
* '?' means one and only one character
*
- * @param pattern The pattern to match against.
- * Must not be null.
- * @param str The string which must be matched against the pattern.
- * Must not be null.
+ * @param pattern The pattern to match against.
+ * Must not be null.
+ * @param str The string which must be matched against the pattern.
+ * Must not be null.
* @param isCaseSensitive Whether or not matching should be performed
* case sensitively.
- *
- *
* @return true if the string matches against the pattern,
* or false otherwise.
*/
- protected static boolean match( String pattern, String str,
- boolean isCaseSensitive )
+ protected static boolean match( String pattern, String str, boolean isCaseSensitive )
{
return SelectorUtils.match( pattern, str, isCaseSensitive );
}
-
-
+
+
/**
* Sets the list of include patterns to use. All '/' and '\' characters
* are replaced by File.separatorChar, so the separator used
* need not match File.separatorChar.
- *
+ *
* When a pattern ends with a '/' or '\', "**" is appended.
*
* @param includes A list of include patterns.
* May be null, indicating that all files
* should be included. If a non-null
* list is given, all elements must be
- * non-null.
+ * non-null.
*/
public void setIncludes( String[] includes )
{
@@ -287,12 +269,12 @@ public void setIncludes( String[] includes )
}
}
}
-
+
/**
* Sets the list of exclude patterns to use. All '/' and '\' characters
* are replaced by File.separatorChar, so the separator used
* need not match File.separatorChar.
- *
+ *
* When a pattern ends with a '/' or '\', "**" is appended.
*
* @param excludes A list of exclude patterns.
@@ -318,7 +300,7 @@ public void setExcludes( String[] excludes )
/**
* Normalizes the pattern, e.g. converts forward and backward slashes to the platform-specific file separator.
- *
+ *
* @param pattern The pattern to normalize, must not be null.
* @return The normalized pattern, never null.
*/
@@ -360,16 +342,14 @@ private String normalizePattern( String pattern )
*/
protected boolean isIncluded( String name )
{
- for ( int i = 0; i < includes.length; i++ )
- {
- if ( matchPath( includes[i], name, isCaseSensitive ) )
- {
- return true;
- }
- }
- return false;
+ return includesPatterns.matches( name, isCaseSensitive );
}
-
+
+ protected boolean isIncluded( String name, String[] tokenizedName )
+ {
+ return includesPatterns.matches( name, tokenizedName, isCaseSensitive );
+ }
+
/**
* Tests whether or not a name matches the start of at least one include
* pattern.
@@ -380,16 +360,9 @@ protected boolean isIncluded( String name )
*/
protected boolean couldHoldIncluded( String name )
{
- for ( int i = 0; i < includes.length; i++ )
- {
- if ( matchPatternStart( includes[i], name, isCaseSensitive ) )
- {
- return true;
- }
- }
- return false;
+ return includesPatterns.matchesPatternStart(name, isCaseSensitive);
}
-
+
/**
* Tests whether or not a name matches against at least one exclude
* pattern.
@@ -400,16 +373,14 @@ protected boolean couldHoldIncluded( String name )
*/
protected boolean isExcluded( String name )
{
- for ( int i = 0; i < excludes.length; i++ )
- {
- if ( matchPath( excludes[i], name, isCaseSensitive ) )
- {
- return true;
- }
- }
- return false;
+ return excludesPatterns.matches( name, isCaseSensitive );
+ }
+
+ protected boolean isExcluded( String name, String[] tokenizedName )
+ {
+ return excludesPatterns.matches( name, tokenizedName, isCaseSensitive );
}
-
+
/**
* Adds default exclusions to the current exclusions set.
*/
@@ -428,8 +399,8 @@ public void addDefaultExcludes()
}
excludes = newExcludes;
}
-
- protected void setupDefaultFilters()
+
+ protected void setupDefaultFilters()
{
if ( includes == null )
{
@@ -442,4 +413,10 @@ protected void setupDefaultFilters()
excludes = new String[0];
}
}
+
+ protected void setupMatchPatterns()
+ {
+ includesPatterns = MatchPatterns.from( includes );
+ excludesPatterns = MatchPatterns.from( excludes );
+ }
}
diff --git a/src/main/java/org/codehaus/plexus/util/CollectionUtils.java b/src/main/java/org/codehaus/plexus/util/CollectionUtils.java
index 4192b79f..1762b9ab 100644
--- a/src/main/java/org/codehaus/plexus/util/CollectionUtils.java
+++ b/src/main/java/org/codehaus/plexus/util/CollectionUtils.java
@@ -55,7 +55,7 @@ public class CollectionUtils
* @param recessiveMap Recessive Map.
* @return The result map with combined dominant and recessive values.
*/
- public static Map mergeMaps( Map dominantMap, Map recessiveMap )
+ public static Map mergeMaps( Map dominantMap, Map recessiveMap )
{
if ( dominantMap == null && recessiveMap == null )
@@ -68,21 +68,21 @@ public static Map mergeMaps( Map dominantMap, Map recessiveMap )
return dominantMap;
}
- if ( dominantMap == null && recessiveMap != null )
+ if ( dominantMap == null)
{
return recessiveMap;
}
- Map result = new HashMap();
+ Map result = new HashMap();
// Grab the keys from the dominant and recessive maps.
- Set dominantMapKeys = dominantMap.keySet();
- Set recessiveMapKeys = recessiveMap.keySet();
+ Set dominantMapKeys = dominantMap.keySet();
+ Set recessiveMapKeys = recessiveMap.keySet();
// Create the set of keys that will be contributed by the
// recessive Map by subtracting the intersection of keys
// from the recessive Map's keys.
- Collection contributingRecessiveKeys =
+ Collection contributingRecessiveKeys =
CollectionUtils.subtract( recessiveMapKeys,
CollectionUtils.intersection( dominantMapKeys, recessiveMapKeys ) );
@@ -90,9 +90,8 @@ public static Map mergeMaps( Map dominantMap, Map recessiveMap )
// Now take the keys we just found and extract the values from
// the recessiveMap and put the key:value pairs into the dominantMap.
- for ( Iterator i = contributingRecessiveKeys.iterator(); i.hasNext(); )
+ for ( K key : contributingRecessiveKeys )
{
- Object key = i.next();
result.put( key, recessiveMap.get( key ) );
}
@@ -107,9 +106,9 @@ public static Map mergeMaps( Map dominantMap, Map recessiveMap )
* @param maps An array of Maps to merge.
* @return Map The result Map produced after the merging process.
*/
- public static Map mergeMaps( Map[] maps )
+ public static Map mergeMaps( Map[] maps )
{
- Map result = null;
+ Map result;
if ( maps.length == 0 )
{
@@ -140,20 +139,21 @@ else if ( maps.length == 1 )
* will be equal to the minimum of the cardinality of that element
* in the two given {@link Collection}s.
*
+ * @param a The first collection
+ * @param b The second collection
* @see Collection#retainAll
+ * @return The intersection of a and b, never null
*/
- public static Collection intersection( final Collection a, final Collection b )
+ public static Collection intersection( final Collection a, final Collection b )
{
- ArrayList list = new ArrayList();
- Map mapa = getCardinalityMap( a );
- Map mapb = getCardinalityMap( b );
- Set elts = new HashSet( a );
+ ArrayList list = new ArrayList();
+ Map mapa = getCardinalityMap( a );
+ Map mapb = getCardinalityMap( b );
+ Set elts = new HashSet( a );
elts.addAll( b );
- Iterator it = elts.iterator();
- while ( it.hasNext() )
+ for ( E obj : elts )
{
- Object obj = it.next();
- for ( int i = 0,m = Math.min( getFreq( obj, mapa ), getFreq( obj, mapb ) ); i < m; i++ )
+ for ( int i = 0, m = Math.min( getFreq( obj, mapa ), getFreq( obj, mapb ) ); i < m; i++ )
{
list.add( obj );
}
@@ -167,15 +167,17 @@ public static Collection intersection( final Collection a, final Collection b )
* will be the cardinality of e in a minus the cardinality
* of e in b, or zero, whichever is greater.
*
+ * @param a The start collection
+ * @param b The collection that will be subtracted
* @see Collection#removeAll
+ * @return The result of the subtraction
*/
- public static Collection subtract( final Collection a, final Collection b )
+ public static Collection subtract( final Collection a, final Collection b )
{
- ArrayList list = new ArrayList( a );
- Iterator it = b.iterator();
- while ( it.hasNext() )
+ ArrayList list = new ArrayList( a );
+ for ( T aB : b )
{
- list.remove( it.next() );
+ list.remove( aB );
}
return list;
}
@@ -187,35 +189,35 @@ public static Collection subtract( final Collection a, final Collection b )
* in the {@link Collection}.
* An entry that maps to null indicates that the
* element does not appear in the given {@link Collection}.
+ * @param col The collection to count cardinalities for
+ * @return A map of counts, indexed on each element in the collection
*/
- public static Map getCardinalityMap( final Collection col )
+ public static Map getCardinalityMap( final Collection col )
{
- HashMap count = new HashMap();
- Iterator it = col.iterator();
- while ( it.hasNext() )
+ HashMap count = new HashMap();
+ for ( E obj : col )
{
- Object obj = it.next();
- Integer c = (Integer) ( count.get( obj ) );
+ Integer c = count.get( obj );
if ( null == c )
{
- count.put( obj, new Integer( 1 ) );
+ count.put( obj, 1 );
}
else
{
- count.put( obj, new Integer( c.intValue() + 1 ) );
+ count.put( obj, c + 1 );
}
}
return count;
}
- public static List iteratorToList( Iterator it )
+ public static List iteratorToList( Iterator it )
{
if ( it == null )
{
throw new NullPointerException( "it cannot be null." );
}
- List list = new ArrayList();
+ List list = new ArrayList();
while ( it.hasNext() )
{
@@ -229,23 +231,21 @@ public static List iteratorToList( Iterator it )
//
// ----------------------------------------------------------------------
- private static final int getFreq( final Object obj, final Map freqMap )
+ private static int getFreq( final E obj, final Map freqMap )
{
try
{
- Object o = freqMap.get( obj );
+ Integer o = freqMap.get( obj );
if ( o != null ) // minimize NullPointerExceptions
{
- return ( (Integer) o ).intValue();
+ return o;
}
}
- catch ( NullPointerException e )
+ catch ( NullPointerException ignore )
{
- // ignored
}
- catch ( NoSuchElementException e )
+ catch ( NoSuchElementException ignore )
{
- // ignored
}
return 0;
}
diff --git a/src/main/java/org/codehaus/plexus/util/DirectoryScanner.java b/src/main/java/org/codehaus/plexus/util/DirectoryScanner.java
index b7155406..7a1511f4 100644
--- a/src/main/java/org/codehaus/plexus/util/DirectoryScanner.java
+++ b/src/main/java/org/codehaus/plexus/util/DirectoryScanner.java
@@ -56,17 +56,18 @@
import java.io.File;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Vector;
/**
* Class for scanning a directory for files/directories which match certain
* criteria.
- *
+ *
* These criteria consist of selectors and patterns which have been specified.
* With the selectors you can select which files you want to have included.
* Files which are not selected are excluded. With patterns you can include
* or exclude files based on their filename.
- *
+ *
* The idea is simple. A given directory is recursively scanned for all files
* and directories. Each file/directory is matched against a set of selectors,
* including special support for matching against filenames with include and
@@ -74,12 +75,12 @@
* pattern of the include pattern list or other file selector, and don't match
* any pattern of the exclude pattern list or fail to match against a required
* selector will be placed in the list of files/directories found.
- *
+ *
* When no list of include patterns is supplied, "**" will be used, which
* means that everything will be matched. When no list of exclude patterns is
* supplied, an empty list is used, such that nothing will be excluded. When
* no selectors are supplied, none are applied.
- *
+ *
* The filename pattern matching is done as follows:
* The name to be matched is split up in path segments. A path segment is the
* name of a directory or file, which is bounded by
@@ -87,11 +88,11 @@
* For example, "abc/def/ghi/xyz.java" is split up in the segments "abc",
* "def","ghi" and "xyz.java".
* The same is done for the pattern against which should be matched.
- *
+ *
* The segments of the name and the pattern are then matched against each
* other. When '**' is used for a path segment in the pattern, it matches
* zero or more path segments of the name.
- *
+ *
* There is a special case regarding the use of File.separators
* at the beginning of the pattern and the string to match:
* When a pattern starts with a File.separator, the string
@@ -100,27 +101,27 @@
* string to match may not start with a File.separator.
* When one of these rules is not obeyed, the string will not
* match.
- *
+ *
* When a name path segment is matched against a pattern path segment, the
* following special characters can be used:
* '*' matches zero or more characters
* '?' matches one character.
- *
+ *
* Examples:
- *
+ *
* "**\*.class" matches all .class files/dirs in a directory tree.
- *
+ *
* "test\a??.java" matches all files/dirs which start with an 'a', then two
* more characters and then ".java", in a directory called test.
- *
+ *
* "**" matches everything in a directory tree.
- *
+ *
* "**\test\**\XYZ*" matches all files/dirs which start with "XYZ" and where
* there is a parent directory called test (e.g. "abc\test\def\ghi\XYZ123").
- *
+ *
* Case sensitivity may be turned off if necessary. By default, it is
* turned on.
- *
+ *
* Example of usage:
*
* String[] includes = {"**\\*.class"};
@@ -141,56 +142,69 @@
* files in all proper subdirectories of a directory called "modules"
*
* @author Arnout J. Kuiper
- * ajkuiper@wxs.nl
+ * ajkuiper@wxs.nl
* @author Magesh Umasankar
* @author Bruce Atherton
* @author Antoine Levy-Lambert
*/
-public class DirectoryScanner extends AbstractScanner
+public class DirectoryScanner
+ extends AbstractScanner
{
- /** The base directory to be scanned. */
+ /**
+ * The base directory to be scanned.
+ */
protected File basedir;
- /** The files which matched at least one include and no excludes
- * and were selected.
+ /**
+ * The files which matched at least one include and no excludes
+ * and were selected.
*/
- protected Vector filesIncluded;
+ protected Vector filesIncluded;
- /** The files which did not match any includes or selectors. */
- protected Vector filesNotIncluded;
+ /**
+ * The files which did not match any includes or selectors.
+ */
+ protected Vector filesNotIncluded;
/**
* The files which matched at least one include and at least
* one exclude.
*/
- protected Vector filesExcluded;
+ protected Vector filesExcluded;
- /** The directories which matched at least one include and no excludes
- * and were selected.
+ /**
+ * The directories which matched at least one include and no excludes
+ * and were selected.
*/
- protected Vector dirsIncluded;
+ protected Vector dirsIncluded;
- /** The directories which were found and did not match any includes. */
- protected Vector dirsNotIncluded;
+ /**
+ * The directories which were found and did not match any includes.
+ */
+ protected Vector dirsNotIncluded;
/**
* The directories which matched at least one include and at least one
* exclude.
*/
- protected Vector dirsExcluded;
+ protected Vector dirsExcluded;
- /** The files which matched at least one include and no excludes and
- * which a selector discarded.
+ /**
+ * The files which matched at least one include and no excludes and
+ * which a selector discarded.
*/
- protected Vector filesDeselected;
+ protected Vector filesDeselected;
- /** The directories which matched at least one include and no excludes
- * but which a selector discarded.
+ /**
+ * The directories which matched at least one include and no excludes
+ * but which a selector discarded.
*/
- protected Vector dirsDeselected;
+ protected Vector dirsDeselected;
- /** Whether or not our results were built by a slow scan. */
+ /**
+ * Whether or not our results were built by a slow scan.
+ */
protected boolean haveSlowResults = false;
/**
@@ -200,9 +214,13 @@ public class DirectoryScanner extends AbstractScanner
*/
private boolean followSymlinks = true;
- /** Whether or not everything tested so far has been included. */
+ /**
+ * Whether or not everything tested so far has been included.
+ */
protected boolean everythingIncluded = true;
+ private final String[] tokenizedEmpty = MatchPattern.tokenizePathToString( "", File.separator );
+
/**
* Sole constructor.
*/
@@ -221,8 +239,7 @@ public DirectoryScanner()
*/
public void setBasedir( String basedir )
{
- setBasedir( new File( basedir.replace( '/', File.separatorChar ).replace(
- '\\', File.separatorChar ) ) );
+ setBasedir( new File( basedir.replace( '/', File.separatorChar ).replace( '\\', File.separatorChar ) ) );
}
/**
@@ -275,11 +292,12 @@ public boolean isEverythingIncluded()
* pattern and don't match any exclude patterns. If there are selectors
* then the files must pass muster there, as well.
*
- * @exception IllegalStateException if the base directory was set
- * incorrectly (i.e. if it is null, doesn't exist,
- * or isn't a directory).
+ * @throws IllegalStateException if the base directory was set
+ * incorrectly (i.e. if it is null, doesn't exist,
+ * or isn't a directory).
*/
- public void scan() throws IllegalStateException
+ public void scan()
+ throws IllegalStateException
{
if ( basedir == null )
{
@@ -287,29 +305,29 @@ public void scan() throws IllegalStateException
}
if ( !basedir.exists() )
{
- throw new IllegalStateException( "basedir " + basedir
- + " does not exist" );
+ throw new IllegalStateException( "basedir " + basedir + " does not exist" );
}
if ( !basedir.isDirectory() )
{
- throw new IllegalStateException( "basedir " + basedir
- + " is not a directory" );
+ throw new IllegalStateException( "basedir " + basedir + " is not a directory" );
}
setupDefaultFilters();
-
- filesIncluded = new Vector();
- filesNotIncluded = new Vector();
- filesExcluded = new Vector();
- filesDeselected = new Vector();
- dirsIncluded = new Vector();
- dirsNotIncluded = new Vector();
- dirsExcluded = new Vector();
- dirsDeselected = new Vector();
-
- if ( isIncluded( "" ) )
+ setupMatchPatterns();
+
+ filesIncluded = new Vector();
+ filesNotIncluded = new Vector();
+ filesExcluded = new Vector();
+ filesDeselected = new Vector();
+ dirsIncluded = new Vector();
+ dirsNotIncluded = new Vector();
+ dirsExcluded = new Vector();
+ dirsDeselected = new Vector();
+
+ if ( isIncluded( "", tokenizedEmpty ) )
{
- if ( !isExcluded( "" ) )
+
+ if ( !isExcluded( "", tokenizedEmpty ) )
{
if ( isSelected( "", basedir ) )
{
@@ -337,7 +355,7 @@ public void scan() throws IllegalStateException
* list of excluded/included files/directories, whereas a fast scan
* will only have full results for included files, as it ignores
* directories which can't possibly hold any included files/directories.
- *
+ *
* Returns immediately if a slow scan has already been completed.
*/
protected void slowScan()
@@ -353,21 +371,19 @@ protected void slowScan()
String[] notIncl = new String[dirsNotIncluded.size()];
dirsNotIncluded.copyInto( notIncl );
- for ( int i = 0; i < excl.length; i++ )
+ for ( String anExcl : excl )
{
- if ( !couldHoldIncluded( excl[i] ) )
+ if ( !couldHoldIncluded( anExcl ) )
{
- scandir( new File( basedir, excl[i] ),
- excl[i] + File.separator, false );
+ scandir( new File( basedir, anExcl ), anExcl + File.separator, false );
}
}
- for ( int i = 0; i < notIncl.length; i++ )
+ for ( String aNotIncl : notIncl )
{
- if ( !couldHoldIncluded( notIncl[i] ) )
+ if ( !couldHoldIncluded( aNotIncl ) )
{
- scandir( new File( basedir, notIncl[i] ),
- notIncl[i] + File.separator, false );
+ scandir( new File( basedir, aNotIncl ), aNotIncl + File.separator, false );
}
}
@@ -385,8 +401,6 @@ protected void slowScan()
* prevent problems with an absolute path when using
* dir). Must not be null.
* @param fast Whether or not this call is part of a fast scan.
- * @throws IOException
- *
* @see #filesIncluded
* @see #filesNotIncluded
* @see #filesExcluded
@@ -409,15 +423,14 @@ protected void scandir( File dir, String vpath, boolean fast )
* then???)
*/
-
/*
- * [jdcasey] (2) is apparently happening to me, as this is killing one of my tests...
- * this is affecting the assembly plugin, fwiw. I will initialize the newfiles array as
- * zero-length for now.
- *
- * NOTE: I can't find the problematic code, as it appears to come from a native method
- * in UnixFileSystem...
- */
+ * [jdcasey] (2) is apparently happening to me, as this is killing one of my tests...
+ * this is affecting the assembly plugin, fwiw. I will initialize the newfiles array as
+ * zero-length for now.
+ *
+ * NOTE: I can't find the problematic code, as it appears to come from a native method
+ * in UnixFileSystem...
+ */
/*
* [bentmann] A null array will also be returned from list() on NTFS when dir refers to a soft link or
* junction point whose target is not existent.
@@ -429,15 +442,15 @@ protected void scandir( File dir, String vpath, boolean fast )
if ( !followSymlinks )
{
- Vector noLinks = new Vector();
- for ( int i = 0; i < newfiles.length; i++ )
+ ArrayList noLinks = new ArrayList();
+ for ( String newfile : newfiles )
{
try
{
- if ( isSymbolicLink( dir, newfiles[i] ) )
+ if ( isSymbolicLink( dir, newfile ) )
{
- String name = vpath + newfiles[i];
- File file = new File( dir, newfiles[i] );
+ String name = vpath + newfile;
+ File file = new File( dir, newfile );
if ( file.isDirectory() )
{
dirsExcluded.addElement( name );
@@ -449,31 +462,31 @@ protected void scandir( File dir, String vpath, boolean fast )
}
else
{
- noLinks.addElement( newfiles[i] );
+ noLinks.add( newfile );
}
}
catch ( IOException ioe )
{
- String msg = "IOException caught while checking "
- + "for links, couldn't get cannonical path!";
+ String msg = "IOException caught while checking " + "for links, couldn't get cannonical path!";
// will be caught and redirected to Ant's logging system
System.err.println( msg );
- noLinks.addElement( newfiles[i] );
+ noLinks.add( newfile );
}
}
- newfiles = new String[noLinks.size()];
- noLinks.copyInto( newfiles );
+ newfiles = noLinks.toArray(new String[noLinks.size()]);
}
- for ( int i = 0; i < newfiles.length; i++ )
+ for ( String newfile : newfiles )
{
- String name = vpath + newfiles[i];
- File file = new File( dir, newfiles[i] );
+ String name = vpath + newfile;
+ String[] tokenizedName = MatchPattern.tokenizePathToString( name, File.separator );
+ File file = new File( dir, newfile );
if ( file.isDirectory() )
{
- if ( isIncluded( name ) )
+
+ if ( isIncluded( name, tokenizedName ) )
{
- if ( !isExcluded( name ) )
+ if ( !isExcluded( name, tokenizedName ) )
{
if ( isSelected( name, file ) )
{
@@ -520,9 +533,9 @@ protected void scandir( File dir, String vpath, boolean fast )
}
else if ( file.isFile() )
{
- if ( isIncluded( name ) )
+ if ( isIncluded( name, tokenizedName ) )
{
- if ( !isExcluded( name ) )
+ if ( !isExcluded( name, tokenizedName ) )
{
if ( isSelected( name, file ) )
{
@@ -584,7 +597,6 @@ public String[] getIncludedFiles()
*
* @return the names of the files which matched none of the include
* patterns.
- *
* @see #slowScan
*/
public String[] getNotIncludedFiles()
@@ -603,7 +615,6 @@ public String[] getNotIncludedFiles()
*
* @return the names of the files which matched at least one of the
* include patterns and at at least one of the exclude patterns.
- *
* @see #slowScan
*/
public String[] getExcludedFiles()
@@ -617,12 +628,11 @@ public String[] getExcludedFiles()
/**
*
Returns the names of the files which were selected out and
* therefore not ultimately included.
- *
+ *
*
The names are relative to the base directory. This involves
* performing a slow scan if one has not already been completed.
*
* @return the names of the files which were deselected.
- *
* @see #slowScan
*/
public String[] getDeselectedFiles()
@@ -639,7 +649,7 @@ public String[] getDeselectedFiles()
* The names are relative to the base directory.
*
* @return the names of the directories which matched at least one of the
- * include patterns and none of the exclude patterns.
+ * include patterns and none of the exclude patterns.
*/
public String[] getIncludedDirectories()
{
@@ -654,8 +664,7 @@ public String[] getIncludedDirectories()
* performing a slow scan if one has not already been completed.
*
* @return the names of the directories which matched none of the include
- * patterns.
- *
+ * patterns.
* @see #slowScan
*/
public String[] getNotIncludedDirectories()
@@ -673,8 +682,7 @@ public String[] getNotIncludedDirectories()
* performing a slow scan if one has not already been completed.
*
* @return the names of the directories which matched at least one of the
- * include patterns and at least one of the exclude patterns.
- *
+ * include patterns and at least one of the exclude patterns.
* @see #slowScan
*/
public String[] getExcludedDirectories()
@@ -688,12 +696,11 @@ public String[] getExcludedDirectories()
/**
*
Returns the names of the directories which were selected out and
* therefore not ultimately included.
- *
+ *
*
The names are relative to the base directory. This involves
* performing a slow scan if one has not already been completed.
*
* @return the names of the directories which were deselected.
- *
* @see #slowScan
*/
public String[] getDeselectedDirectories()
@@ -706,19 +713,24 @@ public String[] getDeselectedDirectories()
/**
* Checks whether a given file is a symbolic link.
- *
+ *
*
It doesn't really test for symbolic links but whether the
* canonical and absolute paths of the file are identical - this
* may lead to false positives on some platforms.
*
* @param parent the parent directory of the file to test
- * @param name the name of the file to test.
- *
+ * @param name the name of the file to test.
+ * @return true if it's a symbolic link
+ * @throws java.io.IOException .
* @since Ant 1.5
*/
public boolean isSymbolicLink( File parent, String name )
throws IOException
{
+ if ( Java7Detector.isJava7() )
+ {
+ return Java7FileUtil.isSymLink( new File( parent, name ) );
+ }
File resolvedParent = new File( parent.getCanonicalPath() );
File toTest = new File( resolvedParent, name );
return !toTest.getAbsolutePath().equals( toTest.getCanonicalPath() );
diff --git a/src/main/java/org/codehaus/plexus/util/DirectoryWalkListener.java b/src/main/java/org/codehaus/plexus/util/DirectoryWalkListener.java
index a3bb5e2c..a4af2527 100644
--- a/src/main/java/org/codehaus/plexus/util/DirectoryWalkListener.java
+++ b/src/main/java/org/codehaus/plexus/util/DirectoryWalkListener.java
@@ -19,8 +19,9 @@
import java.io.File;
/**
- * DirectoryWalkListener
+ * Observes the actions of a {@link DirectoryWalker}.
* @version $Id$
+ * @see DirectoryWalker
*/
public interface DirectoryWalkListener
{
diff --git a/src/main/java/org/codehaus/plexus/util/DirectoryWalker.java b/src/main/java/org/codehaus/plexus/util/DirectoryWalker.java
index 6f621b09..0d7c76cb 100644
--- a/src/main/java/org/codehaus/plexus/util/DirectoryWalker.java
+++ b/src/main/java/org/codehaus/plexus/util/DirectoryWalker.java
@@ -320,7 +320,7 @@ public void scan()
if ( debugEnabled )
{
Iterator it;
- StringBuffer dbg = new StringBuffer();
+ StringBuilder dbg = new StringBuilder();
dbg.append( "DirectoryWalker Scan" );
dbg.append( "\n Base Dir: " ).append( this.baseDir.getAbsolutePath() );
dbg.append( "\n Includes: " );
diff --git a/src/main/java/org/codehaus/plexus/util/FileUtils.java b/src/main/java/org/codehaus/plexus/util/FileUtils.java
index 28743811..e1100162 100644
--- a/src/main/java/org/codehaus/plexus/util/FileUtils.java
+++ b/src/main/java/org/codehaus/plexus/util/FileUtils.java
@@ -55,6 +55,9 @@
*
*/
+import org.codehaus.plexus.util.io.InputStreamFacade;
+import org.codehaus.plexus.util.io.URLInputStreamFacade;
+
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
@@ -64,22 +67,18 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.net.URL;
+import java.nio.channels.FileChannel;
import java.security.SecureRandom;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Iterator;
import java.util.List;
import java.util.Random;
-import java.util.Vector;
-
-import org.codehaus.plexus.util.io.FileInputStreamFacade;
-import org.codehaus.plexus.util.io.InputStreamFacade;
-import org.codehaus.plexus.util.io.URLInputStreamFacade;
/**
* This class provides basic facilities for manipulating files and file paths.
@@ -140,14 +139,21 @@ public class FileUtils
*/
public static final int ONE_GB = ONE_KB * ONE_MB;
- /** The vm line separator */
+ /**
+ * The file copy buffer size (30 MB)
+ */
+ private static final long FILE_COPY_BUFFER_SIZE = ONE_MB * 30;
+
+ /**
+ * The vm file separator
+ */
public static String FS = System.getProperty( "file.separator" );
/**
* Non-valid Characters for naming files, folders under Windows: ":", "*", "?", "\"", "<", ">", "|"
*
* @see
- * http://support.microsoft.com/?scid=kb%3Ben-us%3B177506&x=12&y=13
+ * http://support.microsoft.com/?scid=kb%3Ben-us%3B177506&x=12&y=13
*/
private static final String[] INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME = { ":", "*", "?", "\"", "<", ">", "|" };
@@ -164,7 +170,7 @@ public static String[] getDefaultExcludes()
* @return the default excludes pattern as list.
* @see #getDefaultExcludes()
*/
- public static List getDefaultExcludesAsList()
+ public static List getDefaultExcludesAsList()
{
return Arrays.asList( getDefaultExcludes() );
}
@@ -252,7 +258,7 @@ public static String basename( String filename )
* Matches the equally named unix command.
*
* @param filename the file path
- * @param suffix the file suffix
+ * @param suffix the file suffix
* @return the basename of the file
*/
public static String basename( String filename, String suffix )
@@ -300,7 +306,7 @@ public static String extension( String filename )
}
}
- if ( lastDot >= 0 && lastDot > lastSep)
+ if ( lastDot >= 0 && lastDot > lastSep )
{
return filename.substring( lastDot + 1 );
}
@@ -334,7 +340,7 @@ public static String fileRead( String file )
}
/**
- * @param file the file path
+ * @param file the file path
* @param encoding the wanted encoding
* @return the file content using the specified encoding.
* @throws IOException if any
@@ -355,11 +361,11 @@ public static String fileRead( String file, String encoding )
public static String fileRead( File file )
throws IOException
{
- return fileRead( file, null);
+ return fileRead( file, null );
}
/**
- * @param file the file path
+ * @param file the file path
* @param encoding the wanted encoding
* @return the file content using the specified encoding.
* @throws IOException if any
@@ -367,7 +373,7 @@ public static String fileRead( File file )
public static String fileRead( File file, String encoding )
throws IOException
{
- StringBuffer buf = new StringBuffer();
+ StringBuilder buf = new StringBuilder();
Reader reader = null;
@@ -401,13 +407,13 @@ public static String fileRead( File file, String encoding )
* Note: the data is written with platform encoding
*
* @param fileName The path of the file to write.
- * @param data The content to write to the file.
+ * @param data The content to write to the file.
* @throws IOException if any
*/
public static void fileAppend( String fileName, String data )
throws IOException
{
- fileAppend( fileName, null, data);
+ fileAppend( fileName, null, data );
}
/**
@@ -415,7 +421,7 @@ public static void fileAppend( String fileName, String data )
*
* @param fileName The path of the file to write.
* @param encoding The encoding of the file.
- * @param data The content to write to the file.
+ * @param data The content to write to the file.
* @throws IOException if any
*/
public static void fileAppend( String fileName, String encoding, String data )
@@ -425,7 +431,8 @@ public static void fileAppend( String fileName, String encoding, String data )
try
{
out = new FileOutputStream( fileName, true );
- if ( encoding != null ) {
+ if ( encoding != null )
+ {
out.write( data.getBytes( encoding ) );
}
else
@@ -444,7 +451,7 @@ public static void fileAppend( String fileName, String encoding, String data )
* Note: the data is written with platform encoding
*
* @param fileName The path of the file to write.
- * @param data The content to write to the file.
+ * @param data The content to write to the file.
* @throws IOException if any
*/
public static void fileWrite( String fileName, String data )
@@ -458,28 +465,60 @@ public static void fileWrite( String fileName, String data )
*
* @param fileName The path of the file to write.
* @param encoding The encoding of the file.
- * @param data The content to write to the file.
+ * @param data The content to write to the file.
* @throws IOException if any
*/
public static void fileWrite( String fileName, String encoding, String data )
throws IOException
{
- FileOutputStream out = null;
+ File file = ( fileName == null ) ? null : new File( fileName );
+ fileWrite( file, encoding, data );
+ }
+
+ /**
+ * Writes data to a file. The file will be created if it does not exist.
+ * Note: the data is written with platform encoding
+ *
+ * @param file The file to write.
+ * @param data The content to write to the file.
+ * @throws IOException if any
+ * @since 2.0.6
+ */
+ public static void fileWrite( File file, String data )
+ throws IOException
+ {
+ fileWrite( file, null, data );
+ }
+
+ /**
+ * Writes data to a file. The file will be created if it does not exist.
+ *
+ * @param file The file to write.
+ * @param encoding The encoding of the file.
+ * @param data The content to write to the file.
+ * @throws IOException if any
+ * @since 2.0.6
+ */
+ public static void fileWrite( File file, String encoding, String data )
+ throws IOException
+ {
+ Writer writer = null;
try
{
- out = new FileOutputStream( fileName );
+ OutputStream out = new FileOutputStream( file );
if ( encoding != null )
{
- out.write( data.getBytes( encoding ) );
+ writer = new OutputStreamWriter( out, encoding );
}
else
{
- out.write( data.getBytes() );
+ writer = new OutputStreamWriter( out );
}
+ writer.write( data );
}
finally
{
- IOUtil.close( out );
+ IOUtil.close( writer );
}
}
@@ -509,8 +548,8 @@ public static boolean waitFor( String fileName, int seconds )
/**
* Waits for NFS to propagate a file creation, imposing a timeout.
*
- * @param file The file.
- * @param seconds The maximum time in seconds to wait.
+ * @param file The file.
+ * @param seconds The maximum time in seconds to wait.
* @return True if file exists.
*/
public static boolean waitFor( File file, int seconds )
@@ -558,13 +597,13 @@ public static File getFile( String fileName )
*
* The given extensions should be like "java" and not like ".java"
*
- * @param directory The path of the directory.
+ * @param directory The path of the directory.
* @param extensions an array of expected extensions.
* @return An array of files for the wanted extensions.
*/
public static String[] getFilesFromExtension( String directory, String[] extensions )
{
- Vector files = new Vector();
+ List files = new ArrayList();
File currentDir = new File( directory );
@@ -601,14 +640,14 @@ public static String[] getFilesFromExtension( String directory, String[] extensi
String add = currentFile.getAbsolutePath();
if ( isValidFile( add, extensions ) )
{
- files.addElement( add );
+ files.add( add );
}
}
}
//ok... move the Vector into the files list...
String[] foundFiles = new String[files.size()];
- files.copyInto( foundFiles );
+ files.toArray( foundFiles );
return foundFiles;
}
@@ -616,11 +655,11 @@ public static String[] getFilesFromExtension( String directory, String[] extensi
/**
* Private helper method for getFilesFromExtension()
*/
- private static Vector blendFilesToVector( Vector v, String[] files )
+ private static List blendFilesToVector( List v, String[] files )
{
for ( int i = 0; i < files.length; ++i )
{
- v.addElement( files[i] );
+ v.add( files[i] );
}
return v;
@@ -665,14 +704,11 @@ public static void mkdir( String dir )
{
File file = new File( dir );
- if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
+ if ( Os.isFamily( Os.FAMILY_WINDOWS ) && !isValidWindowsFileName( file ) )
{
- if ( !isValidWindowsFileName( file ) )
- {
- throw new IllegalArgumentException( "The file (" + dir
- + ") cannot contain any of the following characters: \n"
- + StringUtils.join( INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME, " " ) );
- }
+ throw new IllegalArgumentException(
+ "The file (" + dir + ") cannot contain any of the following characters: \n" + StringUtils.join(
+ INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME, " " ) );
}
if ( !file.exists() )
@@ -788,9 +824,9 @@ public static URL[] toURLs( final File[] files )
*/
public static String removeExtension( final String filename )
{
- String ext = extension(filename);
+ String ext = extension( filename );
- if ( "".equals(ext) )
+ if ( "".equals( ext ) )
{
return filename;
}
@@ -813,7 +849,7 @@ public static String removeExtension( final String filename )
*/
public static String getExtension( final String filename )
{
- return extension(filename);
+ return extension( filename );
}
/**
@@ -840,7 +876,7 @@ public static String removePath( final String filepath )
* a.txt --> a.txt
*
*
- * @param filepath the path of the file
+ * @param filepath the path of the file
* @param fileSeparatorChar the file separator character like / on Unix plateforms.
* @return the filename minus path
*/
@@ -880,7 +916,7 @@ public static String getPath( final String filepath )
* a.txt --> ""
*
*
- * @param filepath the filepath
+ * @param filepath the filepath
* @param fileSeparatorChar the file separator character like / on Unix plateforms.
* @return the filename minus path
*/
@@ -1009,8 +1045,8 @@ public static void copyFile( final File source, final File destination )
//if they are equal, we can exit the method without doing any work
return;
}
-
- copyStreamToFile( new FileInputStreamFacade( source ), destination);
+ mkdirsFor( destination );
+ doCopyFile( source, destination );
if ( source.length() != destination.length() )
{
@@ -1019,19 +1055,48 @@ public static void copyFile( final File source, final File destination )
}
}
+ private static void doCopyFile( File source, File destination )
+ throws IOException
+ {
+ FileInputStream fis = null;
+ FileOutputStream fos = null;
+ FileChannel input = null;
+ FileChannel output = null;
+ try
+ {
+ fis = new FileInputStream( source );
+ fos = new FileOutputStream( destination );
+ input = fis.getChannel();
+ output = fos.getChannel();
+ long size = input.size();
+ long pos = 0;
+ long count = 0;
+ while ( pos < size )
+ {
+ count = size - pos > FILE_COPY_BUFFER_SIZE ? FILE_COPY_BUFFER_SIZE : size - pos;
+ pos += output.transferFrom( input, pos, count );
+ }
+ }
+ finally
+ {
+ IOUtil.close( output );
+ IOUtil.close( fos );
+ IOUtil.close( input );
+ IOUtil.close( fis );
+ }
+ }
+
/**
* Copy file from source to destination only if source timestamp is later than the destination timestamp.
* The directories up to destination will be created if they don't already exist.
* destination will be overwritten if it already exists.
*
- * @param source An existing non-directory File to copy bytes from.
+ * @param source An existing non-directory File to copy bytes from.
* @param destination A non-directory File to write bytes to (possibly
- * overwriting).
+ * overwriting).
* @return true if no problem occured
* @throws IOException if source does not exist, destination cannot be
- * written to, or an IO error occurs during copying.
- * @throws FileNotFoundException if destination is a directory
- * (use {@link #copyFileToDirectory}).
+ * written to, or an IO error occurs during copying.
*/
public static boolean copyFileIfModified( final File source, final File destination )
throws IOException
@@ -1051,20 +1116,20 @@ public static boolean copyFileIfModified( final File source, final File destinat
* The directories up to destination will be created if they don't already exist.
* destination will be overwritten if it already exists.
*
- * @param source A URL to copy bytes from.
+ * @param source A URL to copy bytes from.
* @param destination A non-directory File to write bytes to (possibly
- * overwriting).
+ * overwriting).
* @throws IOException if
- *
- *
source URL cannot be opened
- *
destination cannot be written to
- *
an IO error occurs during copying
- *
+ *
+ *
source URL cannot be opened
+ *
destination cannot be written to
+ *
an IO error occurs during copying
+ *
*/
public static void copyURLToFile( final URL source, final File destination )
throws IOException
{
- copyStreamToFile( new URLInputStreamFacade( source ) , destination);
+ copyStreamToFile( new URLInputStreamFacade( source ), destination );
}
/**
@@ -1072,32 +1137,22 @@ public static void copyURLToFile( final URL source, final File destination )
* The directories up to destination will be created if they don't already exist.
* destination will be overwritten if it already exists.
*
- * @param source An {@link InputStream} to copy bytes from. This stream is
- * guaranteed to be closed.
+ * @param source An {@link InputStream} to copy bytes from. This stream is
+ * guaranteed to be closed.
* @param destination A non-directory File to write bytes to (possibly
- * overwriting).
+ * overwriting).
* @throws IOException if
- *
- *
source URL cannot be opened
- *
destination cannot be written to
- *
an IO error occurs during copying
- *
+ *
+ *
source URL cannot be opened
+ *
destination cannot be written to
+ *
an IO error occurs during copying
+ *
*/
public static void copyStreamToFile( final InputStreamFacade source, final File destination )
throws IOException
{
- //does destination directory exist ?
- if ( destination.getParentFile() != null && !destination.getParentFile().exists() )
- {
- destination.getParentFile().mkdirs();
- }
-
- //make sure we can write to destination
- if ( destination.exists() && !destination.canWrite() )
- {
- final String message = "Unable to open file " + destination + " for writing.";
- throw new IOException( message );
- }
+ mkdirsFor( destination );
+ checkCanWrite( destination );
InputStream input = null;
FileOutputStream output = null;
@@ -1114,6 +1169,27 @@ public static void copyStreamToFile( final InputStreamFacade source, final File
}
}
+ private static void checkCanWrite( File destination )
+ throws IOException
+ {
+ //make sure we can write to destination
+ if ( destination.exists() && !destination.canWrite() )
+ {
+ final String message = "Unable to open file " + destination + " for writing.";
+ throw new IOException( message );
+ }
+ }
+
+ private static void mkdirsFor( File destination )
+ {
+ //does destination directory exist ?
+ File parentFile = destination.getParentFile();
+ if ( parentFile != null && !parentFile.exists() )
+ {
+ parentFile.mkdirs();
+ }
+ }
+
/**
* Normalize a path.
* Eliminates "/../" and "/./" in a string. Returns null if the ..'s went past the
@@ -1188,7 +1264,7 @@ public static String normalize( final String path )
* Thieved from Tomcat sources...
*
* @param lookupPath a path
- * @param path the path to concatenate
+ * @param path the path to concatenate
* @return The concatenated paths, or null if error occurs
*/
public static String catPath( final String lookupPath, final String path )
@@ -1225,7 +1301,7 @@ public static String catPath( final String lookupPath, final String path )
* baseFile, otherwise it is treated as a normal root-relative path.
*
* @param baseFile Where to resolve filename from, if filename is
- * relative.
+ * relative.
* @param filename Absolute or relative file path to resolve.
* @return The canonical File of filename.
*/
@@ -1261,7 +1337,7 @@ public static File resolveFile( final File baseFile, String filename )
// FIXME: I'm almost certain this // removal is unnecessary, as getAbsoluteFile() strips
// them. However, I'm not sure about this UNC stuff. (JT)
final char[] chars = filename.toCharArray();
- final StringBuffer sb = new StringBuffer();
+ final StringBuilder sb = new StringBuilder();
//remove duplicate file separators in succession - except
//on win32 at start of filename as UNC filenames can
@@ -1406,7 +1482,7 @@ public static void forceDeleteOnExit( final File file )
/**
* Recursively schedule directory for deletion on JVM exit.
*
- * @param file a directory
+ * @param directory a directory
* @throws IOException if any
*/
private static void deleteDirectoryOnExit( final File directory )
@@ -1416,15 +1492,15 @@ private static void deleteDirectoryOnExit( final File directory )
{
return;
}
+ directory.deleteOnExit(); // The hook reverses the list
cleanDirectoryOnExit( directory );
- directory.deleteOnExit();
}
/**
* Clean a directory without deleting it.
*
- * @param file a directory
+ * @param directory a directory
* @throws IOException if any
*/
private static void cleanDirectoryOnExit( final File directory )
@@ -1469,8 +1545,8 @@ private static void cleanDirectoryOnExit( final File directory )
* Make a directory.
*
* @param file not null
- * @throws IOException If there already exists a file with specified name or
- * the directory is unable to be created
+ * @throws IOException If there already exists a file with specified name or
+ * the directory is unable to be created
* @throws IllegalArgumentException if the file contains illegal Windows characters under Windows OS.
* @see #INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME
*/
@@ -1481,9 +1557,9 @@ public static void forceMkdir( final File file )
{
if ( !isValidWindowsFileName( file ) )
{
- throw new IllegalArgumentException( "The file (" + file.getAbsolutePath()
- + ") cannot contain any of the following characters: \n"
- + StringUtils.join( INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME, " " ) );
+ throw new IllegalArgumentException(
+ "The file (" + file.getAbsolutePath() + ") cannot contain any of the following characters: \n"
+ + StringUtils.join( INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME, " " ) );
}
}
@@ -1532,6 +1608,14 @@ public static void deleteDirectory( final File directory )
return;
}
+ /* try delete the directory before its contents, which will take
+ * care of any directories that are really symbolic links.
+ */
+ if ( directory.delete() )
+ {
+ return;
+ }
+
cleanDirectory( directory );
if ( !directory.delete() )
{
@@ -1657,13 +1741,13 @@ public static long sizeOfDirectory( final File directory )
* including the directory name in each of the files
*
* @param directory the directory to scan
- * @param includes the includes pattern, comma separated
- * @param excludes the excludes pattern, comma separated
+ * @param includes the includes pattern, comma separated
+ * @param excludes the excludes pattern, comma separated
* @return a list of File objects
* @throws IOException
- * @see #getFileNames( File, String, String, boolean )
+ * @see #getFileNames(File, String, String, boolean)
*/
- public static List getFiles( File directory, String includes, String excludes )
+ public static List getFiles( File directory, String includes, String excludes )
throws IOException
{
return getFiles( directory, includes, excludes, true );
@@ -1672,24 +1756,24 @@ public static List getFiles( File directory, String includes, String excludes )
/**
* Return the files contained in the directory, using inclusion and exclusion Ant patterns
*
- * @param directory the directory to scan
- * @param includes the includes pattern, comma separated
- * @param excludes the excludes pattern, comma separated
+ * @param directory the directory to scan
+ * @param includes the includes pattern, comma separated
+ * @param excludes the excludes pattern, comma separated
* @param includeBasedir true to include the base dir in each file
* @return a list of File objects
* @throws IOException
- * @see #getFileNames( File, String, String, boolean )
+ * @see #getFileNames(File, String, String, boolean)
*/
- public static List getFiles( File directory, String includes, String excludes, boolean includeBasedir )
+ public static List getFiles( File directory, String includes, String excludes, boolean includeBasedir )
throws IOException
{
- List fileNames = getFileNames( directory, includes, excludes, includeBasedir );
+ List fileNames = getFileNames( directory, includes, excludes, includeBasedir );
- List files = new ArrayList();
+ List files = new ArrayList();
- for ( Iterator i = fileNames.iterator(); i.hasNext(); )
+ for ( String filename : fileNames )
{
- files.add( new File( (String) i.next() ) );
+ files.add( new File( filename ) );
}
return files;
@@ -1699,14 +1783,14 @@ public static List getFiles( File directory, String includes, String excludes, b
* Return a list of files as String depending options.
* This method use case sensitive file name.
*
- * @param directory the directory to scan
- * @param includes the includes pattern, comma separated
- * @param excludes the excludes pattern, comma separated
+ * @param directory the directory to scan
+ * @param includes the includes pattern, comma separated
+ * @param excludes the excludes pattern, comma separated
* @param includeBasedir true to include the base dir in each String of file
* @return a list of files as String
* @throws IOException
*/
- public static List getFileNames( File directory, String includes, String excludes, boolean includeBasedir )
+ public static List getFileNames( File directory, String includes, String excludes, boolean includeBasedir )
throws IOException
{
return getFileNames( directory, includes, excludes, includeBasedir, true );
@@ -1715,16 +1799,16 @@ public static List getFileNames( File directory, String includes, String exclude
/**
* Return a list of files as String depending options.
*
- * @param directory the directory to scan
- * @param includes the includes pattern, comma separated
- * @param excludes the excludes pattern, comma separated
+ * @param directory the directory to scan
+ * @param includes the includes pattern, comma separated
+ * @param excludes the excludes pattern, comma separated
* @param includeBasedir true to include the base dir in each String of file
* @param isCaseSensitive true if case sensitive
* @return a list of files as String
* @throws IOException
*/
- public static List getFileNames( File directory, String includes, String excludes, boolean includeBasedir,
- boolean isCaseSensitive )
+ public static List getFileNames( File directory, String includes, String excludes, boolean includeBasedir,
+ boolean isCaseSensitive )
throws IOException
{
return getFileAndDirectoryNames( directory, includes, excludes, includeBasedir, isCaseSensitive, true, false );
@@ -1734,14 +1818,15 @@ public static List getFileNames( File directory, String includes, String exclude
* Return a list of directories as String depending options.
* This method use case sensitive file name.
*
- * @param directory the directory to scan
- * @param includes the includes pattern, comma separated
- * @param excludes the excludes pattern, comma separated
+ * @param directory the directory to scan
+ * @param includes the includes pattern, comma separated
+ * @param excludes the excludes pattern, comma separated
* @param includeBasedir true to include the base dir in each String of file
* @return a list of directories as String
* @throws IOException
*/
- public static List getDirectoryNames( File directory, String includes, String excludes, boolean includeBasedir )
+ public static List getDirectoryNames( File directory, String includes, String excludes,
+ boolean includeBasedir )
throws IOException
{
return getDirectoryNames( directory, includes, excludes, includeBasedir, true );
@@ -1750,16 +1835,16 @@ public static List getDirectoryNames( File directory, String includes, String ex
/**
* Return a list of directories as String depending options.
*
- * @param directory the directory to scan
- * @param includes the includes pattern, comma separated
- * @param excludes the excludes pattern, comma separated
+ * @param directory the directory to scan
+ * @param includes the includes pattern, comma separated
+ * @param excludes the excludes pattern, comma separated
* @param includeBasedir true to include the base dir in each String of file
* @param isCaseSensitive true if case sensitive
* @return a list of directories as String
* @throws IOException
*/
- public static List getDirectoryNames( File directory, String includes, String excludes, boolean includeBasedir,
- boolean isCaseSensitive )
+ public static List getDirectoryNames( File directory, String includes, String excludes,
+ boolean includeBasedir, boolean isCaseSensitive )
throws IOException
{
return getFileAndDirectoryNames( directory, includes, excludes, includeBasedir, isCaseSensitive, false, true );
@@ -1768,19 +1853,19 @@ public static List getDirectoryNames( File directory, String includes, String ex
/**
* Return a list of files as String depending options.
*
- * @param directory the directory to scan
- * @param includes the includes pattern, comma separated
- * @param excludes the excludes pattern, comma separated
+ * @param directory the directory to scan
+ * @param includes the includes pattern, comma separated
+ * @param excludes the excludes pattern, comma separated
* @param includeBasedir true to include the base dir in each String of file
* @param isCaseSensitive true if case sensitive
- * @param getFiles true if get files
+ * @param getFiles true if get files
* @param getDirectories true if get directories
* @return a list of files as String
* @throws IOException
*/
- public static List getFileAndDirectoryNames( File directory, String includes, String excludes,
- boolean includeBasedir, boolean isCaseSensitive, boolean getFiles,
- boolean getDirectories )
+ public static List getFileAndDirectoryNames( File directory, String includes, String excludes,
+ boolean includeBasedir, boolean isCaseSensitive,
+ boolean getFiles, boolean getDirectories )
throws IOException
{
DirectoryScanner scanner = new DirectoryScanner();
@@ -1801,7 +1886,7 @@ public static List getFileAndDirectoryNames( File directory, String includes, St
scanner.scan();
- List list = new ArrayList();
+ List list = new ArrayList();
if ( getFiles )
{
@@ -1843,7 +1928,7 @@ public static List getFileAndDirectoryNames( File directory, String includes, St
/**
* Copy a directory to an other one.
*
- * @param sourceDirectory the source dir
+ * @param sourceDirectory the source dir
* @param destinationDirectory the target dir
* @throws IOException if any
*/
@@ -1856,10 +1941,10 @@ public static void copyDirectory( File sourceDirectory, File destinationDirector
/**
* Copy a directory to an other one.
*
- * @param sourceDirectory the source dir
+ * @param sourceDirectory the source dir
* @param destinationDirectory the target dir
- * @param includes include pattern
- * @param excludes exlucde pattern
+ * @param includes include pattern
+ * @param excludes exlucde pattern
* @throws IOException if any
* @see #getFiles(File, String, String)
*/
@@ -1872,12 +1957,10 @@ public static void copyDirectory( File sourceDirectory, File destinationDirector
return;
}
- List files = getFiles( sourceDirectory, includes, excludes );
+ List files = getFiles( sourceDirectory, includes, excludes );
- for ( Iterator i = files.iterator(); i.hasNext(); )
+ for ( File file : files )
{
- File file = (File) i.next();
-
copyFileToDirectory( file, destinationDirectory );
}
}
@@ -1891,15 +1974,15 @@ public static void copyDirectory( File sourceDirectory, File destinationDirector
*
The sourceDirectory must exists.
*
*
- * @param sourceDirectory the source dir
+ * @param sourceDirectory the source dir
* @param destinationDirectory the target dir
- * @param includes include pattern
- * @param excludes exlucde pattern
- * @since 1.5.7
+ * @param includes include pattern
+ * @param excludes exlucde pattern
* @throws IOException if any
+ * @since 1.5.7
*/
public static void copyDirectoryLayout( File sourceDirectory, File destinationDirectory, String[] includes,
- String[] excludes )
+ String[] excludes )
throws IOException
{
if ( sourceDirectory == null )
@@ -1932,7 +2015,7 @@ public static void copyDirectoryLayout( File sourceDirectory, File destinationDi
}
else
{
- scanner.setIncludes( new String[] { "**" } );
+ scanner.setIncludes( new String[]{ "**" } );
}
if ( excludes != null && excludes.length >= 1 )
@@ -1942,20 +2025,18 @@ public static void copyDirectoryLayout( File sourceDirectory, File destinationDi
scanner.addDefaultExcludes();
scanner.scan();
- List includedDirectories = Arrays.asList( scanner.getIncludedDirectories() );
+ List includedDirectories = Arrays.asList( scanner.getIncludedDirectories() );
- for (Iterator i = includedDirectories.iterator();i.hasNext();)
+ for ( String name : includedDirectories )
{
- String name = (String)i.next();
-
- File source = new File(sourceDirectory, name);
+ File source = new File( sourceDirectory, name );
if ( source.equals( sourceDirectory ) )
{
continue;
}
- File destination = new File(destinationDirectory, name);
+ File destination = new File( destinationDirectory, name );
destination.mkdirs();
}
}
@@ -1969,7 +2050,7 @@ public static void copyDirectoryLayout( File sourceDirectory, File destinationDi
*
The sourceDirectory must exists.
*
*
- * @param sourceDirectory the source dir
+ * @param sourceDirectory the source dir
* @param destinationDirectory the target dir
* @throws IOException if any
*/
@@ -1988,7 +2069,7 @@ public static void copyDirectoryStructure( File sourceDirectory, File destinatio
*
The sourceDirectory must exists.
*
*
- * @param sourceDirectory the source dir
+ * @param sourceDirectory the source dir
* @param destinationDirectory the target dir
* @throws IOException if any
*/
@@ -2083,7 +2164,7 @@ else if ( file.isDirectory() )
* @param from the file to move
* @param to the new file name
* @throws IOException if anything bad happens during this process.
- * Note that to may have been deleted already when this happens.
+ * Note that to may have been deleted already when this happens.
*/
public static void rename( File from, File to )
throws IOException
@@ -2126,10 +2207,10 @@ public static void rename( File from, File to )
*
To delete automatically the file created by this method, use the
* {@link File#deleteOnExit()} method.
*
- * @param prefix prefix before the random number
- * @param suffix file extension; include the '.'
+ * @param prefix prefix before the random number
+ * @param suffix file extension; include the '.'
* @param parentDir Directory to create the temporary file in -java.io.tmpdir
- * used if not specificed
+ * used if not specificed
* @return a File reference to the new temporary file.
*/
public static File createTempFile( String prefix, String suffix, File parentDir )
@@ -2158,8 +2239,9 @@ public static File createTempFile( String prefix, String suffix, File parentDir
/**
* If wrappers is null or empty, the file will be copy only if to.lastModified() < from.lastModified()
- * @param from the file to copy
- * @param to the destination file
+ *
+ * @param from the file to copy
+ * @param to the destination file
* @param encoding the file output encoding (only if wrappers is not empty)
* @param wrappers array of {@link FilterWrapper}
* @throws IOException if an IO error occurs during copying or filtering
@@ -2177,12 +2259,13 @@ public static abstract class FilterWrapper
/**
* If wrappers is null or empty, the file will be copy only if to.lastModified() < from.lastModified() or if overwrite is true
- * @param from the file to copy
- * @param to the destination file
- * @param encoding the file output encoding (only if wrappers is not empty)
- * @param wrappers array of {@link FilterWrapper}
+ *
+ * @param from the file to copy
+ * @param to the destination file
+ * @param encoding the file output encoding (only if wrappers is not empty)
+ * @param wrappers array of {@link FilterWrapper}
* @param overwrite if true and f wrappers is null or empty, the file will be copy
- * enven if to.lastModified() < from.lastModified()
+ * enven if to.lastModified() < from.lastModified()
* @throws IOException if an IO error occurs during copying or filtering
* @since 1.5.2
*/
@@ -2243,10 +2326,10 @@ public static void copyFile( File from, File to, String encoding, FilterWrapper[
* @return a List containing every every line not starting with # and not empty
* @throws IOException if any
*/
- public static List loadFile( File file )
+ public static List loadFile( File file )
throws IOException
{
- List lines = new ArrayList();
+ List lines = new ArrayList();
if ( file.exists() )
{
@@ -2277,7 +2360,7 @@ public static List loadFile( File file )
*
* @param f not null file
* @return false if the file path contains any of forbidden Windows characters,
- * true if the Os is not Windows or if the file path respect the Windows constraints.
+ * true if the Os is not Windows or if the file path respect the Windows constraints.
* @see #INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME
* @since 1.5.2
*/
@@ -2290,9 +2373,10 @@ public static boolean isValidWindowsFileName( File f )
return false;
}
- if ( f.getParentFile()!= null)
+ File parentFile = f.getParentFile();
+ if ( parentFile != null )
{
- return isValidWindowsFileName( f.getParentFile() );
+ return isValidWindowsFileName( parentFile );
}
}
diff --git a/src/main/java/org/codehaus/plexus/util/IOUtil.java b/src/main/java/org/codehaus/plexus/util/IOUtil.java
index 20cab90d..4045a7f4 100644
--- a/src/main/java/org/codehaus/plexus/util/IOUtil.java
+++ b/src/main/java/org/codehaus/plexus/util/IOUtil.java
@@ -67,6 +67,7 @@
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
+import java.nio.channels.Channel;
/**
* General IO Stream manipulation.
@@ -152,7 +153,7 @@
public final class IOUtil
{
- private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
+ private static final int DEFAULT_BUFFER_SIZE = 1024 * 16;
/**
* Private constructor to prevent instantiation.
@@ -745,6 +746,28 @@ public static void close( InputStream inputStream )
}
}
+ /**
+ * Closes a channel. Channel can be null and any IOException's will be swallowed.
+ *
+ * @param channel The stream to close.
+ */
+ public static void close( Channel channel )
+ {
+ if ( channel == null )
+ {
+ return;
+ }
+
+ try
+ {
+ channel.close();
+ }
+ catch( IOException ex )
+ {
+ // ignore
+ }
+ }
+
/**
* Closes the output stream. The output stream can be null and any IOException's will be swallowed.
*
diff --git a/src/main/java/org/codehaus/plexus/util/InterpolationFilterReader.java b/src/main/java/org/codehaus/plexus/util/InterpolationFilterReader.java
index 8eec7e44..d765c0d5 100644
--- a/src/main/java/org/codehaus/plexus/util/InterpolationFilterReader.java
+++ b/src/main/java/org/codehaus/plexus/util/InterpolationFilterReader.java
@@ -61,6 +61,25 @@
import java.util.Map;
/**
+ * A FilterReader which interpolates keyword values into a character stream.
+ * Keywords are recognized when enclosed between starting and ending delimiter
+ * strings. The keywords themselves, and their values, are fetched from a Map
+ * supplied to the constructor.
+ *
+ * When a possible keyword token is recognized (by detecting the starting and
+ * ending token delimiters):
+ *
+ *
+ *
if the enclosed string is found in the keyword Map, the delimiters and
+ * the keyword are effectively replaced by the keyword's value;
+ *
if the enclosed string is found in the keyword Map, but its value has
+ * zero length, then the token (delimiters and keyword) is effectively removed
+ * from the character stream;
+ *
if the enclosed string is not found in the keyword Map, then
+ * no substitution is made; the token text is passed through unaltered.
+ *
+ * @see LineOrientedInterpolatingReader
+ * @see org.codehaus.plexus.interpolation
*/
public class InterpolationFilterReader
extends FilterReader
@@ -90,11 +109,20 @@ public class InterpolationFilterReader
private int endTokenLength;
/** Default begin token. */
- private static String DEFAULT_BEGIN_TOKEN = "${";
+ private static final String DEFAULT_BEGIN_TOKEN = "${";
/** Default end token. */
- private static String DEFAULT_END_TOKEN = "}";
+ private static final String DEFAULT_END_TOKEN = "}";
+ /**
+ * Construct a Reader to interpolate values enclosed between the given
+ * delimiter tokens.
+ *
+ * @param in a Reader to be wrapped for interpolation.
+ * @param variables name/value pairs to be interpolated into the character stream.
+ * @param beginToken an interpolation target begins with this.
+ * @param endToken an interpolation target ends with this.
+ */
public InterpolationFilterReader( Reader in, Map variables, String beginToken, String endToken )
{
super( in );
@@ -107,6 +135,13 @@ public InterpolationFilterReader( Reader in, Map variables, String beginToken, S
endTokenLength = endToken.length();
}
+ /**
+ * Construct a Reader using the default interpolation delimiter tokens
+ * "${" and "}".
+ *
+ * @param in a Reader to be wrapped for interpolation.
+ * @param variables name/value pairs to be interpolated into the character stream.
+ */
public InterpolationFilterReader( Reader in, Map variables )
{
this( in, variables, DEFAULT_BEGIN_TOKEN, DEFAULT_END_TOKEN );
@@ -201,7 +236,7 @@ public int read() throws IOException
return ch;
}
- int ch = -1;
+ int ch;
if ( previousIndex != -1 && previousIndex < endTokenLength )
{
ch = endToken.charAt( previousIndex++ );
@@ -213,7 +248,7 @@ public int read() throws IOException
if ( ch == beginToken.charAt( 0 ) )
{
- StringBuffer key = new StringBuffer();
+ StringBuilder key = new StringBuilder();
int beginTokenMatchPos = 1;
diff --git a/src/main/java/org/codehaus/plexus/util/Java7Detector.java b/src/main/java/org/codehaus/plexus/util/Java7Detector.java
new file mode 100644
index 00000000..64f71e4a
--- /dev/null
+++ b/src/main/java/org/codehaus/plexus/util/Java7Detector.java
@@ -0,0 +1,48 @@
+package org.codehaus.plexus.util;
+
+/*
+ * Copyright 2011 The Codehaus Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Java7 feature detection
+ *
+ * @author Kristian Rosenvold
+ */
+class Java7Detector
+{
+
+ private static final boolean isJava7;
+
+ static
+ {
+ boolean isJava7x = true;
+ try
+ {
+ Class.forName( "java.nio.file.Files" );
+ }
+ catch ( Exception e )
+ {
+ isJava7x = false;
+ }
+ isJava7 = isJava7x;
+ }
+
+
+ public static boolean isJava7()
+ {
+ return isJava7;
+ }
+}
diff --git a/src/main/java/org/codehaus/plexus/util/Java7FileUtil.java b/src/main/java/org/codehaus/plexus/util/Java7FileUtil.java
new file mode 100644
index 00000000..df4d9ec3
--- /dev/null
+++ b/src/main/java/org/codehaus/plexus/util/Java7FileUtil.java
@@ -0,0 +1,32 @@
+package org.codehaus.plexus.util;
+
+/*
+ * Copyright 2007 The Codehaus Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+
+/**
+ * Encapsulates use of java7 features
+ */
+public class Java7FileUtil
+{
+ public static boolean isSymLink( File file )
+ {
+ return Files.isSymbolicLink( file.toPath() );
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/codehaus/plexus/util/LineOrientedInterpolatingReader.java b/src/main/java/org/codehaus/plexus/util/LineOrientedInterpolatingReader.java
index 47a5ba2f..29b81acc 100644
--- a/src/main/java/org/codehaus/plexus/util/LineOrientedInterpolatingReader.java
+++ b/src/main/java/org/codehaus/plexus/util/LineOrientedInterpolatingReader.java
@@ -25,13 +25,40 @@
import java.io.Reader;
import java.util.Collections;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/**
+ * A FilterReader which interpolates keyword values into a character stream.
+ * Keywords are recognized when enclosed between starting and ending delimiter
+ * strings. The keywords themselves, and their values, are fetched from a Map
+ * supplied to the constructor.
+ *
+ * When a possible keyword token is recognized (by detecting the starting and
+ * ending token delimiters):
+ *
+ *
+ *
if the enclosed string is found in the keyword Map, the delimiters and
+ * the keyword are effectively replaced by the keyword's value;
+ *
if the enclosed string is found in the keyword Map, but its value has
+ * zero length, then the token (delimiters and keyword) is effectively removed
+ * from the character stream;
+ *
if the enclosed string is not found in the keyword Map, then
+ * no substitution is made; the token text is passed through unaltered.
+ *
+ *
+ * A token in the incoming character stream may be escaped by
+ * prepending an "escape sequence" which is specified to the constructor. An
+ * escaped token is passed through as written, with the escape sequence removed.
+ * This allows things which would look like tokens to be read literally rather
+ * than interpolated.
+ *
+ *
* @author jdcasey Created on Feb 3, 2005
+ *
+ * @see InterpolationFilterReader
+ * @see org.codehaus.plexus.interpolation
*/
public class LineOrientedInterpolatingReader
extends FilterReader
@@ -48,7 +75,7 @@ public class LineOrientedInterpolatingReader
private final PushbackReader pushbackReader;
- private final Map context;
+ private final Map context;
private final String startDelim;
@@ -64,7 +91,17 @@ public class LineOrientedInterpolatingReader
private String line;
- public LineOrientedInterpolatingReader( Reader reader, Map context, String startDelim, String endDelim,
+ /**
+ * Construct an interpolating Reader, specifying token delimiters and the
+ * escape sequence.
+ *
+ * @param reader the Reader to be filtered.
+ * @param context keyword/value pairs for interpolation.
+ * @param startDelim character sequence which (possibly) begins a token.
+ * @param endDelim character sequence which ends a token.
+ * @param escapeSeq
+ */
+ public LineOrientedInterpolatingReader( Reader reader, Map context, String startDelim, String endDelim,
String escapeSeq )
{
super( reader );
@@ -92,12 +129,27 @@ public LineOrientedInterpolatingReader( Reader reader, Map context, String start
}
}
- public LineOrientedInterpolatingReader( Reader reader, Map context, String startDelim, String endDelim )
+ /**
+ * Filters a Reader using the default escape sequence "\".
+ *
+ * @param reader the Reader to be filtered.
+ * @param context keyword/value pairs for interpolation.
+ * @param startDelim the character sequence which (possibly) begins a token.
+ * @param endDelim the character sequence which ends a token.
+ */
+ public LineOrientedInterpolatingReader( Reader reader, Map context, String startDelim, String endDelim )
{
this( reader, context, startDelim, endDelim, DEFAULT_ESCAPE_SEQ );
}
- public LineOrientedInterpolatingReader( Reader reader, Map context )
+ /**
+ * Filters a Reader using the default escape sequence "\" and token
+ * delimiters "${", "}".
+ *
+ * @param reader the Reader to be filtered.
+ * @param context keyword/value pairs for interpolation.
+ */
+ public LineOrientedInterpolatingReader( Reader reader, Map context )
{
this( reader, context, DEFAULT_START_DELIM, DEFAULT_END_DELIM, DEFAULT_ESCAPE_SEQ );
}
@@ -190,10 +242,15 @@ private void readAndInterpolateLine() throws IOException
}
}
+ /*
+ * Read one line from the wrapped Reader. A line is a sequence of characters
+ * ending in CRLF, CR, or LF. The terminating character(s) will be included
+ * in the returned line.
+ */
private String readLine() throws IOException
{
- StringBuffer lineBuffer = new StringBuffer( 40 ); // half of the "normal" line maxsize
- int next = -1;
+ StringBuilder lineBuffer = new StringBuilder( 40 ); // half of the "normal" line maxsize
+ int next;
boolean lastWasCR = false;
while ( ( next = pushbackReader.read() ) > -1 )
@@ -235,9 +292,9 @@ private String replaceWithInterpolatedValues( String rawLine, Map evaluatedExpre
{
String result = rawLine;
- for ( Iterator it = evaluatedExpressions.entrySet().iterator(); it.hasNext(); )
+ for ( Object o : evaluatedExpressions.entrySet() )
{
- Map.Entry entry = (Map.Entry) it.next();
+ Map.Entry entry = (Map.Entry) o;
String expression = (String) entry.getKey();
@@ -251,14 +308,14 @@ private String replaceWithInterpolatedValues( String rawLine, Map evaluatedExpre
private Map evaluateExpressions( Set expressions )
{
- Map evaluated = new TreeMap();
+ Map evaluated = new TreeMap();
- for ( Iterator it = expressions.iterator(); it.hasNext(); )
+ for ( Object expression : expressions )
{
- String rawExpression = (String) it.next();
+ String rawExpression = (String) expression;
- String realExpression = rawExpression.substring( startDelim.length(), rawExpression.length()
- - endDelim.length() );
+ String realExpression =
+ rawExpression.substring( startDelim.length(), rawExpression.length() - endDelim.length() );
String[] parts = realExpression.split( "\\." );
if ( parts.length > 0 )
@@ -297,7 +354,7 @@ private Map evaluateExpressions( Set expressions )
private Set parseForExpressions( String rawLine )
{
- Set expressions = new HashSet();
+ Set expressions = new HashSet();
if ( rawLine != null )
{
@@ -342,7 +399,7 @@ private int findDelimiter( String rawLine, String delimiter, int lastPos )
{
int placeholder = lastPos;
- int position = -1;
+ int position;
do
{
position = rawLine.indexOf( delimiter, placeholder );
@@ -371,7 +428,7 @@ private int findDelimiter( String rawLine, String delimiter, int lastPos )
private String findAndReplaceUnlessEscaped(String rawLine, String search, String replace)
{
- StringBuffer lineBuffer = new StringBuffer( (int)(rawLine.length() * 1.5) );
+ StringBuilder lineBuffer = new StringBuilder( (int) ( rawLine.length() * 1.5 ) );
int lastReplacement = -1;
@@ -385,7 +442,7 @@ private String findAndReplaceUnlessEscaped(String rawLine, String search, String
lastReplacement = 0;
}
- lineBuffer.append( rawLine.substring( lastReplacement, nextReplacement ) );
+ lineBuffer.append( rawLine, lastReplacement, nextReplacement );
int escIdx = rawLine.indexOf( escapeSeq, lastReplacement + 1 );
if(escIdx > -1 && escIdx + escapeSeq.length() == nextReplacement)
@@ -409,7 +466,7 @@ private String findAndReplaceUnlessEscaped(String rawLine, String search, String
if( lastReplacement < rawLine.length() )
{
- lineBuffer.append( rawLine.substring( lastReplacement ) );
+ lineBuffer.append( rawLine, lastReplacement, rawLine.length() );
}
return lineBuffer.toString();
diff --git a/src/main/java/org/codehaus/plexus/util/MatchPattern.java b/src/main/java/org/codehaus/plexus/util/MatchPattern.java
new file mode 100644
index 00000000..00f4d959
--- /dev/null
+++ b/src/main/java/org/codehaus/plexus/util/MatchPattern.java
@@ -0,0 +1,135 @@
+package org.codehaus.plexus.util;
+/*
+ * Copyright The Codehaus Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+/**
+ * Describes a match target for SelectorUtils.
+ *
+ * Significantly more efficient than using strings, since re-evaluation and re-tokenizing is avoided.
+ *
+ * @author Kristian Rosenvold
+ */
+public class MatchPattern
+{
+ private final String source;
+
+ private final String regexPattern;
+
+ private final String separator;
+
+ private final String[] tokenized;
+ private final char[][] tokenizedChar;
+
+ private MatchPattern( String source, String separator )
+ {
+ regexPattern = SelectorUtils.isRegexPrefixedPattern( source ) ? source.substring(
+ SelectorUtils.REGEX_HANDLER_PREFIX.length(),
+ source.length() - SelectorUtils.PATTERN_HANDLER_SUFFIX.length() ) : null;
+ this.source =
+ SelectorUtils.isAntPrefixedPattern( source )
+ ? source.substring( SelectorUtils.ANT_HANDLER_PREFIX.length(), source.length()
+ - SelectorUtils.PATTERN_HANDLER_SUFFIX.length() )
+ : source;
+ this.separator = separator;
+ tokenized = tokenizePathToString( this.source, separator );
+ tokenizedChar = new char[tokenized.length][];
+ for (int i = 0; i < tokenized.length; i++){
+ tokenizedChar[i] = tokenized[i].toCharArray();
+ }
+
+ }
+
+
+
+ public boolean matchPath( String str, boolean isCaseSensitive )
+ {
+ if ( regexPattern != null )
+ {
+ return str.matches( regexPattern );
+ }
+ else
+ {
+ return SelectorUtils.matchAntPathPattern( this, str, separator, isCaseSensitive );
+ }
+ }
+
+ boolean matchPath( String str, char[][] strDirs, boolean isCaseSensitive )
+ {
+ if ( regexPattern != null )
+ {
+ return str.matches( regexPattern );
+ }
+ else
+ {
+ return SelectorUtils.matchAntPathPattern( getTokenizedPathChars(), strDirs, isCaseSensitive );
+ }
+ }
+
+ public boolean matchPatternStart( String str, boolean isCaseSensitive )
+ {
+ if ( regexPattern != null )
+ {
+ // FIXME: ICK! But we can't do partial matches for regex, so we have to reserve judgement until we have
+ // a file to deal with, or we can definitely say this is an exclusion...
+ return true;
+ }
+ else
+ {
+ String altStr = source.replace( '\\', '/' );
+
+ return SelectorUtils.matchAntPathPatternStart( this, str, File.separator, isCaseSensitive )
+ || SelectorUtils.matchAntPathPatternStart( this, altStr, "/", isCaseSensitive );
+ }
+ }
+
+ public String[] getTokenizedPathString()
+ {
+ return tokenized;
+ }
+
+ public char[][] getTokenizedPathChars()
+ {
+ return tokenizedChar;
+ }
+
+ public boolean startsWith( String string )
+ {
+ return source.startsWith( string );
+ }
+
+
+ static String[] tokenizePathToString( String path, String separator )
+ {
+ List ret = new ArrayList();
+ StringTokenizer st = new StringTokenizer( path, separator );
+ while ( st.hasMoreTokens() )
+ {
+ ret.add( st.nextToken() );
+ }
+ return ret.toArray( new String[ret.size()] );
+ }
+
+ public static MatchPattern fromString( String source )
+ {
+ return new MatchPattern( source, File.separator );
+ }
+
+}
diff --git a/src/main/java/org/codehaus/plexus/util/MatchPatterns.java b/src/main/java/org/codehaus/plexus/util/MatchPatterns.java
new file mode 100644
index 00000000..bffb3ad7
--- /dev/null
+++ b/src/main/java/org/codehaus/plexus/util/MatchPatterns.java
@@ -0,0 +1,90 @@
+package org.codehaus.plexus.util;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A list of patterns to be matched
+ *
+ * @author Kristian Rosenvold
+ */
+public class MatchPatterns
+{
+ private final MatchPattern[] patterns;
+
+ private MatchPatterns( MatchPattern[] patterns )
+ {
+ this.patterns = patterns;
+ }
+
+ /**
+ * Checks these MatchPatterns against a specified string.
+ *
+ * Uses far less string tokenization than any of the alternatives.
+ *
+ * @param name The name to look for
+ * @param isCaseSensitive If the comparison is case sensitive
+ * @return true if any of the supplied patterns match
+ */
+ public boolean matches( String name, boolean isCaseSensitive )
+ {
+ String[] tokenized = MatchPattern.tokenizePathToString( name, File.separator );
+ return matches( name, tokenized, isCaseSensitive );
+ }
+
+ public boolean matches( String name, String[] tokenizedName, boolean isCaseSensitive )
+ {
+ char[][] tokenizedNameChar = new char[tokenizedName.length][];
+ for(int i = 0; i < tokenizedName.length; i++){
+ tokenizedNameChar[i] = tokenizedName[i].toCharArray();
+ }
+ for ( MatchPattern pattern : patterns )
+ {
+ if ( pattern.matchPath( name, tokenizedNameChar, isCaseSensitive ) )
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean matchesPatternStart( String name, boolean isCaseSensitive )
+ {
+ for ( MatchPattern includesPattern : patterns )
+ {
+ if ( includesPattern.matchPatternStart( name, isCaseSensitive ) )
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static MatchPatterns from( String... sources )
+ {
+ final int length = sources.length;
+ MatchPattern[] result = new MatchPattern[length];
+ for ( int i = 0; i < length; i++ )
+ {
+ result[i] = MatchPattern.fromString( sources[i] );
+ }
+ return new MatchPatterns( result );
+ }
+
+ public static MatchPatterns from( Iterable strings )
+ {
+ return new MatchPatterns( getMatchPatterns( strings ) );
+ }
+
+ private static MatchPattern[] getMatchPatterns( Iterable items )
+ {
+ List result = new ArrayList();
+ for ( String string : items )
+ {
+ result.add( MatchPattern.fromString( string ) );
+ }
+ return result.toArray( new MatchPattern[result.size()] );
+ }
+
+}
diff --git a/src/main/java/org/codehaus/plexus/util/Os.java b/src/main/java/org/codehaus/plexus/util/Os.java
index c8fc6b42..2f3af267 100644
--- a/src/main/java/org/codehaus/plexus/util/Os.java
+++ b/src/main/java/org/codehaus/plexus/util/Os.java
@@ -55,7 +55,6 @@
package org.codehaus.plexus.util;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.Locale;
import java.util.Set;
@@ -94,7 +93,7 @@ public class Os
public static final String FAMILY_OPENVMS = "openvms";
// store the valid families
- private static final Set validFamilies = setValidFamilies();
+ private static final Set validFamilies = setValidFamilies();
// get the current info
private static final String PATH_SEP = System.getProperty( "path.separator" );
@@ -136,9 +135,9 @@ public Os( String family )
/**
* Initializes the set of valid families.
*/
- private static Set setValidFamilies()
+ private static Set setValidFamilies()
{
- Set valid = new HashSet();
+ Set valid = new HashSet();
valid.add( FAMILY_DOS );
valid.add( FAMILY_MAC );
valid.add( FAMILY_NETWARE );
@@ -381,7 +380,7 @@ private static String getOsFamily()
// in case the order of static initialization is
// wrong, get the list
// safely.
- Set families = null;
+ Set families = null;
if ( !validFamilies.isEmpty() )
{
families = validFamilies;
@@ -390,10 +389,8 @@ private static String getOsFamily()
{
families = setValidFamilies();
}
- Iterator iter = families.iterator();
- while ( iter.hasNext() )
+ for ( String fam : families )
{
- String fam = (String) iter.next();
if ( Os.isFamily( fam ) )
{
return fam;
@@ -432,8 +429,8 @@ public static boolean isValidFamily( String theFamily )
* @return a copy of the valid families
* @since 1.4.2
*/
- public static Set getValidFamilies()
+ public static Set getValidFamilies()
{
- return new HashSet( validFamilies );
+ return new HashSet( validFamilies );
}
}
diff --git a/src/main/java/org/codehaus/plexus/util/PathTool.java b/src/main/java/org/codehaus/plexus/util/PathTool.java
index de52db8d..76301862 100644
--- a/src/main/java/org/codehaus/plexus/util/PathTool.java
+++ b/src/main/java/org/codehaus/plexus/util/PathTool.java
@@ -51,26 +51,26 @@ public class PathTool
* PathTool.getRelativePath( "/usr/local/java/bin/java.sh", "/usr/local/" ) = ""
*
*
- * @param basedir The base directory.
+ * @param basedir The base directory.
* @param filename The filename that is relative to the base
- * directory.
+ * directory.
* @return The relative path of the filename from the base
- * directory. This value is not terminated with a forward slash.
- * A zero-length string is returned if: the filename is not relative to
- * the base directory, basedir is null or zero-length,
- * or filename is null or zero-length.
+ * directory. This value is not terminated with a forward slash.
+ * A zero-length string is returned if: the filename is not relative to
+ * the base directory, basedir is null or zero-length,
+ * or filename is null or zero-length.
*/
public static final String getRelativePath( String basedir, String filename )
{
- basedir = uppercaseDrive(basedir);
- filename = uppercaseDrive(filename);
+ basedir = uppercaseDrive( basedir );
+ filename = uppercaseDrive( filename );
/*
* Verify the arguments and make sure the filename is relative
* to the base directory.
*/
- if ( basedir == null || basedir.length() == 0 || filename == null
- || filename.length() == 0 || !filename.startsWith( basedir ) )
+ if ( basedir == null || basedir.length() == 0 || filename == null || filename.length() == 0
+ || !filename.startsWith( basedir ) )
{
return "";
}
@@ -108,13 +108,13 @@ public static final String getRelativePath( String basedir, String filename )
*
* @param filename The filename to be parsed.
* @return The relative path of the filename. This value is not
- * terminated with a forward slash. A zero-length string is
- * returned if: filename is null or zero-length.
+ * terminated with a forward slash. A zero-length string is
+ * returned if: filename is null or zero-length.
* @see #getRelativeFilePath(String, String)
*/
public static final String getRelativePath( String filename )
{
- filename = uppercaseDrive(filename);
+ filename = uppercaseDrive( filename );
if ( filename == null || filename.length() == 0 )
{
@@ -155,8 +155,8 @@ public static final String getRelativePath( String filename )
*
* @param filename The filename to be parsed.
* @return The directory portion of the filename. If
- * the filename does not contain a directory component, "." is
- * returned.
+ * the filename does not contain a directory component, "." is
+ * returned.
*/
public static final String getDirectoryComponent( String filename )
{
@@ -191,44 +191,52 @@ public static final String getDirectoryComponent( String filename )
* @param relativePath
* @return String
*/
- public static final String calculateLink(String link, String relativePath)
+ public static final String calculateLink( String link, String relativePath )
{
+ if ( link == null )
+ {
+ link = "";
+ }
+ if ( relativePath == null )
+ {
+ relativePath = "";
+ }
//This must be some historical feature
- if (link.startsWith("/site/"))
+ if ( link.startsWith( "/site/" ) )
{
- return link.substring(5);
+ return link.substring( 5 );
}
//Allows absolute links in nav-bars etc
- if (link.startsWith("/absolute/"))
+ if ( link.startsWith( "/absolute/" ) )
{
- return link.substring(10);
+ return link.substring( 10 );
}
// This traps urls like http://
- if (link.indexOf(":") >= 0)
+ if ( link.indexOf( ":" ) >= 0 )
{
return link;
}
//If relativepath is current directory, just pass the link through
- if (relativePath.equals("."))
+ if ( StringUtils.equals( relativePath, "." ) )
{
- if (link.startsWith("/"))
+ if ( link.startsWith( "/" ) )
{
- return link.substring(1);
+ return link.substring( 1 );
}
return link;
}
//If we don't do this, you can end up with ..//bob.html rather than ../bob.html
- if (relativePath.endsWith("/") && link.startsWith("/"))
+ if ( relativePath.endsWith( "/" ) && link.startsWith( "/" ) )
{
- return relativePath + "." + link.substring(1);
+ return relativePath + "." + link.substring( 1 );
}
- if (relativePath.endsWith("/") || link.startsWith("/"))
+ if ( relativePath.endsWith( "/" ) || link.startsWith( "/" ) )
{
return relativePath + link;
}
@@ -324,16 +332,16 @@ public static final String getRelativeFilePath( final String oldPath, final Stri
// check for the presence of windows drives. No relative way of
// traversing from one to the other.
- if ( ( toPath.startsWith( ":", 1 ) && fromPath.startsWith( ":", 1 ) )
- && ( !toPath.substring( 0, 1 ).equals( fromPath.substring( 0, 1 ) ) ) )
+ if ( ( toPath.startsWith( ":", 1 ) && fromPath.startsWith( ":", 1 ) ) && ( !toPath.substring( 0, 1 ).equals(
+ fromPath.substring( 0, 1 ) ) ) )
{
// they both have drive path element but they dont match, no
// relative path
return null;
}
- if ( ( toPath.startsWith( ":", 1 ) && !fromPath.startsWith( ":", 1 ) )
- || ( !toPath.startsWith( ":", 1 ) && fromPath.startsWith( ":", 1 ) ) )
+ if ( ( toPath.startsWith( ":", 1 ) && !fromPath.startsWith( ":", 1 ) ) || ( !toPath.startsWith( ":", 1 )
+ && fromPath.startsWith( ":", 1 ) ) )
{
// one has a drive path element and the other doesnt, no relative
// path.
@@ -359,26 +367,24 @@ public static final String getRelativeFilePath( final String oldPath, final Stri
* within the filename (except the leading if present), append the
* "../" string to the return value.
*
- * @param filename The filename to parse.
+ * @param filename The filename to parse.
* @param separator The separator used within the filename.
* @return The relative path of the filename. This value is not
- * terminated with a forward slash. A zero-length string is
- * returned if: the filename is zero-length.
+ * terminated with a forward slash. A zero-length string is
+ * returned if: the filename is zero-length.
*/
- private static final String determineRelativePath( String filename,
- String separator )
+ private static final String determineRelativePath( String filename, String separator )
{
if ( filename.length() == 0 )
{
return "";
}
-
/*
- * Count the slashes in the relative filename, but exclude the
- * leading slash. If the path has no slashes, then the filename
- * is relative to the current directory.
- */
+ * Count the slashes in the relative filename, but exclude the
+ * leading slash. If the path has no slashes, then the filename
+ * is relative to the current directory.
+ */
int slashCount = StringUtils.countMatches( filename, separator ) - 1;
if ( slashCount <= 0 )
{
@@ -390,7 +396,7 @@ private static final String determineRelativePath( String filename,
* that the file is within one or more directories. Thus, each
* slash represents a "../" in the relative path.
*/
- StringBuffer sb = new StringBuffer();
+ StringBuilder sb = new StringBuilder();
for ( int i = 0; i < slashCount; i++ )
{
sb.append( "../" );
@@ -409,9 +415,9 @@ private static final String determineRelativePath( String filename,
* often is returned as the separator.
*
* @param filename The filename parsed to determine the file
- * separator.
+ * separator.
* @return The file separator used within filename.
- * This value is either a forward or backward slash.
+ * This value is either a forward or backward slash.
*/
private static final String determineSeparator( String filename )
{
@@ -423,23 +429,24 @@ private static final String determineSeparator( String filename )
/**
* Cygwin prefers lowercase drive letters, but other parts of maven use uppercase
+ *
* @param path
* @return String
*/
- static final String uppercaseDrive(String path)
+ static final String uppercaseDrive( String path )
{
- if (path == null)
+ if ( path == null )
{
return null;
}
- if (path.length() >= 2 && path.charAt(1) == ':')
+ if ( path.length() >= 2 && path.charAt( 1 ) == ':' )
{
path = Character.toUpperCase( path.charAt( 0 ) ) + path.substring( 1 );
}
return path;
}
- private static final String buildRelativePath( String toPath, String fromPath, final char separatorChar )
+ private static final String buildRelativePath( String toPath, String fromPath, final char separatorChar )
{
// use tokeniser to traverse paths and for lazy checking
StringTokenizer toTokeniser = new StringTokenizer( toPath, String.valueOf( separatorChar ) );
diff --git a/src/main/java/org/codehaus/plexus/util/PropertyUtils.java b/src/main/java/org/codehaus/plexus/util/PropertyUtils.java
index f327fd8a..0ed1aa48 100644
--- a/src/main/java/org/codehaus/plexus/util/PropertyUtils.java
+++ b/src/main/java/org/codehaus/plexus/util/PropertyUtils.java
@@ -24,7 +24,7 @@
import java.net.URL;
/**
- *
+ * Static methods to create Properties loaded from various sources.
*
* @author Jason van Zyl
* @author Michal Maczka
diff --git a/src/main/java/org/codehaus/plexus/util/ReaderFactory.java b/src/main/java/org/codehaus/plexus/util/ReaderFactory.java
index c9fe9927..8eddfdf9 100644
--- a/src/main/java/org/codehaus/plexus/util/ReaderFactory.java
+++ b/src/main/java/org/codehaus/plexus/util/ReaderFactory.java
@@ -190,6 +190,8 @@ public static Reader newReader( InputStream in, String encoding )
/**
* Create a new Reader with specified encoding.
*
+ * Note that there is no buffering on this reader, which favours clients that read into large buffers (8K+).
+ *
* @param file not null file.
* @param encoding not null supported encoding.
* @return a reader instance for the input file using the given encoding.
diff --git a/src/main/java/org/codehaus/plexus/util/ReflectionUtils.java b/src/main/java/org/codehaus/plexus/util/ReflectionUtils.java
index f19d4e19..53b2a24f 100644
--- a/src/main/java/org/codehaus/plexus/util/ReflectionUtils.java
+++ b/src/main/java/org/codehaus/plexus/util/ReflectionUtils.java
@@ -27,6 +27,8 @@
import java.util.Arrays;
/**
+ * Operations on a class' fields and their setters.
+ *
* @author Michal Maczka
* @author Jesse McConnell
* @author Trygve Laugstøl
@@ -38,7 +40,7 @@ public final class ReflectionUtils
// Field utils
// ----------------------------------------------------------------------
- public static Field getFieldByNameIncludingSuperclasses( String fieldName, Class clazz )
+ public static Field getFieldByNameIncludingSuperclasses( String fieldName, Class> clazz )
{
Field retValue = null;
@@ -48,7 +50,7 @@ public static Field getFieldByNameIncludingSuperclasses( String fieldName, Class
}
catch ( NoSuchFieldException e )
{
- Class superclass = clazz.getSuperclass();
+ Class> superclass = clazz.getSuperclass();
if ( superclass != null )
{
@@ -59,11 +61,11 @@ public static Field getFieldByNameIncludingSuperclasses( String fieldName, Class
return retValue;
}
- public static List getFieldsIncludingSuperclasses( Class clazz )
+ public static List getFieldsIncludingSuperclasses( Class> clazz )
{
- List fields = new ArrayList( Arrays.asList( clazz.getDeclaredFields() ) );
+ List fields = new ArrayList( Arrays.asList( clazz.getDeclaredFields() ) );
- Class superclass = clazz.getSuperclass();
+ Class> superclass = clazz.getSuperclass();
if ( superclass != null )
{
@@ -85,16 +87,14 @@ public static List getFieldsIncludingSuperclasses( Class clazz )
* @param clazz The class to find the method in.
* @return null or the method found.
*/
- public static Method getSetter( String fieldName, Class clazz )
+ public static Method getSetter( String fieldName, Class> clazz )
{
- Method [] methods = clazz.getMethods();
+ Method[] methods = clazz.getMethods();
fieldName = "set" + StringUtils.capitalizeFirstLetter( fieldName );
- for ( int i = 0; i < methods.length; i++ )
+ for ( Method method : methods )
{
- Method method = methods[i];
-
if ( method.getName().equals( fieldName ) && isSetter( method ) )
{
return method;
@@ -107,16 +107,14 @@ public static Method getSetter( String fieldName, Class clazz )
/**
* Finds all setters in the given class and super classes.
*/
- public static List getSetters( Class clazz )
+ public static List getSetters( Class> clazz )
{
Method[] methods = clazz.getMethods();
- List list = new ArrayList();
+ List list = new ArrayList();
- for ( int i = 0; i < methods.length; i++ )
+ for ( Method method : methods )
{
- Method method = methods[i];
-
if ( isSetter( method ) )
{
list.add( method );
@@ -131,7 +129,7 @@ public static List getSetters( Class clazz )
*
* Will throw an RuntimeException if the method isn't a setter.
*/
- public static Class getSetterType( Method method )
+ public static Class> getSetterType( Method method )
{
if ( !isSetter( method ) )
{
@@ -191,9 +189,9 @@ public static Object getValueIncludingSuperclasses( String variable, Object obje
public static Map getVariablesAndValuesIncludingSuperclasses( Object object )
throws IllegalAccessException
{
- HashMap map = new HashMap ();
+ HashMap map = new HashMap();
- gatherVariablesAndValuesIncludingSuperclasses(object, map);
+ gatherVariablesAndValuesIncludingSuperclasses( object, map );
return map;
}
@@ -220,7 +218,7 @@ private static void gatherVariablesAndValuesIncludingSuperclasses( Object object
throws IllegalAccessException
{
- Class clazz = object.getClass();
+ Class> clazz = object.getClass();
Field[] fields = clazz.getDeclaredFields();
@@ -234,7 +232,7 @@ private static void gatherVariablesAndValuesIncludingSuperclasses( Object object
}
- Class superclass = clazz.getSuperclass();
+ Class> superclass = clazz.getSuperclass();
if ( !Object.class.equals( superclass ) )
{
diff --git a/src/main/java/org/codehaus/plexus/util/Scanner.java b/src/main/java/org/codehaus/plexus/util/Scanner.java
index efd96e11..d2af7b4d 100644
--- a/src/main/java/org/codehaus/plexus/util/Scanner.java
+++ b/src/main/java/org/codehaus/plexus/util/Scanner.java
@@ -18,6 +18,9 @@
import java.io.File;
+/**
+ * Scan a directory tree for files, with specified inclusions and exclusions.
+ */
public interface Scanner
{
diff --git a/src/main/java/org/codehaus/plexus/util/SelectorUtils.java b/src/main/java/org/codehaus/plexus/util/SelectorUtils.java
index ecdd40ce..4d1ebab1 100644
--- a/src/main/java/org/codehaus/plexus/util/SelectorUtils.java
+++ b/src/main/java/org/codehaus/plexus/util/SelectorUtils.java
@@ -55,8 +55,9 @@
package org.codehaus.plexus.util;
import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
import java.util.StringTokenizer;
-import java.util.Vector;
/**
*
This is a utility class used by selectors and DirectoryScanner. The
@@ -67,23 +68,23 @@
*
This is a Singleton.
*
* @author Arnout J. Kuiper
- * ajkuiper@wxs.nl
+ * ajkuiper@wxs.nl
* @author Magesh Umasankar
* @author Bruce Atherton
- * @since 1.5
* @version $Id$
+ * @since 1.5
*/
public final class SelectorUtils
{
public static final String PATTERN_HANDLER_PREFIX = "[";
-
+
public static final String PATTERN_HANDLER_SUFFIX = "]";
-
+
public static final String REGEX_HANDLER_PREFIX = "%regex" + PATTERN_HANDLER_PREFIX;
-
+
public static final String ANT_HANDLER_PREFIX = "%ant" + PATTERN_HANDLER_PREFIX;
-
+
private static SelectorUtils instance = new SelectorUtils();
/**
@@ -104,7 +105,7 @@ public static SelectorUtils getInstance()
/**
* Tests whether or not a given path matches the start of a given
* pattern up to the first "**".
- *
+ *
* This is not a general purpose test and should only be used if you
* can live with false positives. For example, pattern=**\a
* and str=b will yield true.
@@ -113,9 +114,8 @@ public static SelectorUtils getInstance()
* null.
* @param str The path to match, as a String. Must not be
* null.
- *
* @return whether or not a given path matches the start of a given
- * pattern up to the first "**".
+ * pattern up to the first "**".
*/
public static boolean matchPatternStart( String pattern, String str )
{
@@ -125,26 +125,23 @@ public static boolean matchPatternStart( String pattern, String str )
/**
* Tests whether or not a given path matches the start of a given
* pattern up to the first "**".
- *
+ *
* This is not a general purpose test and should only be used if you
* can live with false positives. For example, pattern=**\a
* and str=b will yield true.
*
- * @param pattern The pattern to match against. Must not be
- * null.
- * @param str The path to match, as a String. Must not be
- * null.
+ * @param pattern The pattern to match against. Must not be
+ * null.
+ * @param str The path to match, as a String. Must not be
+ * null.
* @param isCaseSensitive Whether or not matching should be performed
* case sensitively.
- *
* @return whether or not a given path matches the start of a given
- * pattern up to the first "**".
+ * pattern up to the first "**".
*/
- public static boolean matchPatternStart( String pattern, String str,
- boolean isCaseSensitive )
+ public static boolean matchPatternStart( String pattern, String str, boolean isCaseSensitive )
{
- if ( pattern.length() > ( REGEX_HANDLER_PREFIX.length() + PATTERN_HANDLER_SUFFIX.length() + 1 )
- && pattern.startsWith( REGEX_HANDLER_PREFIX ) && pattern.endsWith( PATTERN_HANDLER_SUFFIX ) )
+ if ( isRegexPrefixedPattern( pattern ) )
{
// FIXME: ICK! But we can't do partial matches for regex, so we have to reserve judgement until we have
// a file to deal with, or we can definitely say this is an exclusion...
@@ -152,50 +149,85 @@ public static boolean matchPatternStart( String pattern, String str,
}
else
{
- if ( pattern.length() > ( ANT_HANDLER_PREFIX.length() + PATTERN_HANDLER_SUFFIX.length() + 1 )
- && pattern.startsWith( ANT_HANDLER_PREFIX ) && pattern.endsWith( PATTERN_HANDLER_SUFFIX ) )
+ if ( isAntPrefixedPattern( pattern ) )
{
- pattern =
- pattern.substring( ANT_HANDLER_PREFIX.length(), pattern.length() - PATTERN_HANDLER_SUFFIX.length() );
+ pattern = pattern.substring( ANT_HANDLER_PREFIX.length(),
+ pattern.length() - PATTERN_HANDLER_SUFFIX.length() );
}
String altStr = str.replace( '\\', '/' );
-
+
return matchAntPathPatternStart( pattern, str, File.separator, isCaseSensitive )
|| matchAntPathPatternStart( pattern, altStr, "/", isCaseSensitive );
}
}
-
- private static boolean matchAntPathPatternStart( String pattern, String str, String separator, boolean isCaseSensitive )
+
+ static boolean isAntPrefixedPattern( String pattern )
+ {
+ return pattern.length() > ( ANT_HANDLER_PREFIX.length() + PATTERN_HANDLER_SUFFIX.length() + 1 )
+ && pattern.startsWith( ANT_HANDLER_PREFIX ) && pattern.endsWith( PATTERN_HANDLER_SUFFIX );
+ }
+
+ @SuppressWarnings( "SimplifiableIfStatement" )
+ static boolean matchAntPathPatternStart( MatchPattern pattern, String str, String separator,
+ boolean isCaseSensitive )
+ {
+ if ( separatorPatternStartSlashMismatch( pattern, str, separator ) )
+ {
+ return false;
+ }
+
+ return matchAntPathPatternStart( pattern.getTokenizedPathString(), str, separator, isCaseSensitive );
+ }
+
+ static boolean matchAntPathPatternStart( String pattern, String str, String separator, boolean isCaseSensitive )
{
// When str starts with a File.separator, pattern has to start with a
// File.separator.
// When pattern starts with a File.separator, str has to start with a
// File.separator.
- if ( str.startsWith( separator ) !=
- pattern.startsWith( separator ) )
+ if ( separatorPatternStartSlashMismatch( pattern, str, separator ) )
{
return false;
}
- Vector patDirs = tokenizePath( pattern, separator );
- Vector strDirs = tokenizePath( str, separator );
+ String[] patDirs = tokenizePathToString( pattern, separator );
+ return matchAntPathPatternStart( patDirs, str, separator, isCaseSensitive );
+ }
+
+ // When str starts with a File.separator, pattern has to start with a
+ // File.separator.
+ // When pattern starts with a File.separator, str has to start with a
+ // File.separator.
+ private static boolean separatorPatternStartSlashMismatch( String pattern, String str, String separator )
+ {
+ return str.startsWith( separator ) != pattern.startsWith( separator );
+ }
+
+ private static boolean separatorPatternStartSlashMismatch( MatchPattern matchPattern, String str, String separator )
+ {
+ return str.startsWith( separator ) != matchPattern.startsWith( separator );
+ }
+
+
+ static boolean matchAntPathPatternStart( String[] patDirs, String str, String separator, boolean isCaseSensitive )
+ {
+ String[] strDirs = tokenizePathToString( str, separator );
int patIdxStart = 0;
- int patIdxEnd = patDirs.size() - 1;
+ int patIdxEnd = patDirs.length - 1;
int strIdxStart = 0;
- int strIdxEnd = strDirs.size() - 1;
+ int strIdxEnd = strDirs.length - 1;
// up to first '**'
while ( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd )
{
- String patDir = (String) patDirs.elementAt( patIdxStart );
+ String patDir = patDirs[patIdxStart];
if ( patDir.equals( "**" ) )
{
break;
}
- if ( !match( patDir, (String) strDirs.elementAt( strIdxStart ),
- isCaseSensitive ) )
+ if ( !match( patDir, strDirs[strIdxStart], isCaseSensitive ) )
{
return false;
}
@@ -203,22 +235,7 @@ private static boolean matchAntPathPatternStart( String pattern, String str, Str
strIdxStart++;
}
- if ( strIdxStart > strIdxEnd )
- {
- // String is exhausted
- return true;
- }
- else if ( patIdxStart > patIdxEnd )
- {
- // String not exhausted, but pattern is. Failure.
- return false;
- }
- else
- {
- // pattern now holds ** while string is not exhausted
- // this will generate false positives but we can live with that.
- return true;
- }
+ return strIdxStart > strIdxEnd || patIdxStart <= patIdxEnd;
}
/**
@@ -228,7 +245,6 @@ else if ( patIdxStart > patIdxEnd )
* null.
* @param str The path to match, as a String. Must not be
* null.
- *
* @return true if the pattern matches against the string,
* or false otherwise.
*/
@@ -240,73 +256,88 @@ public static boolean matchPath( String pattern, String str )
/**
* Tests whether or not a given path matches a given pattern.
*
- * @param pattern The pattern to match against. Must not be
- * null.
- * @param str The path to match, as a String. Must not be
- * null.
+ * @param pattern The pattern to match against. Must not be
+ * null.
+ * @param str The path to match, as a String. Must not be
+ * null.
* @param isCaseSensitive Whether or not matching should be performed
* case sensitively.
- *
* @return true if the pattern matches against the string,
* or false otherwise.
*/
- public static boolean matchPath( String pattern, String str,
- boolean isCaseSensitive )
+ public static boolean matchPath( String pattern, String str, boolean isCaseSensitive )
+ {
+ return matchPath( pattern, str, File.separator, isCaseSensitive );
+ }
+
+ public static boolean matchPath( String pattern, String str, String separator, boolean isCaseSensitive )
{
- if ( pattern.length() > ( REGEX_HANDLER_PREFIX.length() + PATTERN_HANDLER_SUFFIX.length() + 1 )
- && pattern.startsWith( REGEX_HANDLER_PREFIX ) && pattern.endsWith( PATTERN_HANDLER_SUFFIX ) )
+ if ( isRegexPrefixedPattern( pattern ) )
{
- pattern = pattern.substring( REGEX_HANDLER_PREFIX.length(), pattern.length()
- - PATTERN_HANDLER_SUFFIX.length() );
+ pattern =
+ pattern.substring( REGEX_HANDLER_PREFIX.length(), pattern.length() - PATTERN_HANDLER_SUFFIX.length() );
return str.matches( pattern );
}
else
{
- if ( pattern.length() > ( ANT_HANDLER_PREFIX.length() + PATTERN_HANDLER_SUFFIX.length() + 1 )
- && pattern.startsWith( ANT_HANDLER_PREFIX ) && pattern.endsWith( PATTERN_HANDLER_SUFFIX ) )
+ if ( isAntPrefixedPattern( pattern ) )
{
- pattern =
- pattern.substring( ANT_HANDLER_PREFIX.length(), pattern.length() - PATTERN_HANDLER_SUFFIX.length() );
+ pattern = pattern.substring( ANT_HANDLER_PREFIX.length(),
+ pattern.length() - PATTERN_HANDLER_SUFFIX.length() );
}
-
- return matchAntPathPattern( pattern, str, isCaseSensitive );
+
+ return matchAntPathPattern( pattern, str, separator, isCaseSensitive );
}
}
- private static boolean matchAntPathPattern( String pattern, String str, boolean isCaseSensitive )
+ static boolean isRegexPrefixedPattern( String pattern )
{
- // When str starts with a File.separator, pattern has to start with a
- // File.separator.
- // When pattern starts with a File.separator, str has to start with a
- // File.separator.
- if ( str.startsWith( File.separator ) !=
- pattern.startsWith( File.separator ) )
+ return pattern.length() > ( REGEX_HANDLER_PREFIX.length() + PATTERN_HANDLER_SUFFIX.length() + 1 )
+ && pattern.startsWith( REGEX_HANDLER_PREFIX ) && pattern.endsWith( PATTERN_HANDLER_SUFFIX );
+ }
+
+ static boolean matchAntPathPattern( MatchPattern matchPattern, String str, String separator,
+ boolean isCaseSensitive )
+ {
+ if ( separatorPatternStartSlashMismatch( matchPattern, str, separator ) )
+ {
+ return false;
+ }
+ String[] patDirs = matchPattern.getTokenizedPathString();
+ String[] strDirs = tokenizePathToString( str, separator );
+ return matchAntPathPattern( patDirs, strDirs, isCaseSensitive );
+ }
+
+ static boolean matchAntPathPattern( String pattern, String str, String separator, boolean isCaseSensitive )
+ {
+ if ( separatorPatternStartSlashMismatch( pattern, str, separator ) )
{
return false;
}
+ String[] patDirs = tokenizePathToString( pattern, separator );
+ String[] strDirs = tokenizePathToString( str, separator );
+ return matchAntPathPattern( patDirs, strDirs, isCaseSensitive );
- Vector patDirs = tokenizePath( pattern, File.separator );
- Vector strDirs = tokenizePath( str, File.separator );
+ }
+ static boolean matchAntPathPattern( String[] patDirs, String[] strDirs, boolean isCaseSensitive )
+ {
int patIdxStart = 0;
- int patIdxEnd = patDirs.size() - 1;
+ int patIdxEnd = patDirs.length - 1;
int strIdxStart = 0;
- int strIdxEnd = strDirs.size() - 1;
+ int strIdxEnd = strDirs.length - 1;
// up to first '**'
while ( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd )
{
- String patDir = (String) patDirs.elementAt( patIdxStart );
+ String patDir = patDirs[patIdxStart];
if ( patDir.equals( "**" ) )
{
break;
}
- if ( !match( patDir, (String) strDirs.elementAt( strIdxStart ),
- isCaseSensitive ) )
+ if ( !match( patDir, strDirs[strIdxStart], isCaseSensitive ) )
{
- patDirs = null;
- strDirs = null;
return false;
}
patIdxStart++;
@@ -317,10 +348,8 @@ private static boolean matchAntPathPattern( String pattern, String str, boolean
// String is exhausted
for ( int i = patIdxStart; i <= patIdxEnd; i++ )
{
- if ( !patDirs.elementAt( i ).equals( "**" ) )
+ if ( !patDirs[i].equals( "**" ) )
{
- patDirs = null;
- strDirs = null;
return false;
}
}
@@ -331,8 +360,6 @@ private static boolean matchAntPathPattern( String pattern, String str, boolean
if ( patIdxStart > patIdxEnd )
{
// String not exhausted, but pattern is. Failure.
- patDirs = null;
- strDirs = null;
return false;
}
}
@@ -340,16 +367,143 @@ private static boolean matchAntPathPattern( String pattern, String str, boolean
// up to last '**'
while ( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd )
{
- String patDir = (String) patDirs.elementAt( patIdxEnd );
+ String patDir = patDirs[patIdxEnd];
if ( patDir.equals( "**" ) )
{
break;
}
- if ( !match( patDir, (String) strDirs.elementAt( strIdxEnd ),
- isCaseSensitive ) )
+ if ( !match( patDir, strDirs[strIdxEnd], isCaseSensitive ) )
+ {
+ return false;
+ }
+ patIdxEnd--;
+ strIdxEnd--;
+ }
+ if ( strIdxStart > strIdxEnd )
+ {
+ // String is exhausted
+ for ( int i = patIdxStart; i <= patIdxEnd; i++ )
+ {
+ if ( !patDirs[i].equals( "**" ) )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ while ( patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd )
+ {
+ int patIdxTmp = -1;
+ for ( int i = patIdxStart + 1; i <= patIdxEnd; i++ )
+ {
+ if ( patDirs[i].equals( "**" ) )
+ {
+ patIdxTmp = i;
+ break;
+ }
+ }
+ if ( patIdxTmp == patIdxStart + 1 )
+ {
+ // '**/**' situation, so skip one
+ patIdxStart++;
+ continue;
+ }
+ // Find the pattern between padIdxStart & padIdxTmp in str between
+ // strIdxStart & strIdxEnd
+ int patLength = ( patIdxTmp - patIdxStart - 1 );
+ int strLength = ( strIdxEnd - strIdxStart + 1 );
+ int foundIdx = -1;
+ strLoop:
+ for ( int i = 0; i <= strLength - patLength; i++ )
+ {
+ for ( int j = 0; j < patLength; j++ )
+ {
+ String subPat = patDirs[patIdxStart + j + 1];
+ String subStr = strDirs[strIdxStart + i + j];
+ if ( !match( subPat, subStr, isCaseSensitive ) )
+ {
+ continue strLoop;
+ }
+ }
+
+ foundIdx = strIdxStart + i;
+ break;
+ }
+
+ if ( foundIdx == -1 )
+ {
+ return false;
+ }
+
+ patIdxStart = patIdxTmp;
+ strIdxStart = foundIdx + patLength;
+ }
+
+ for ( int i = patIdxStart; i <= patIdxEnd; i++ )
+ {
+ if ( !patDirs[i].equals( "**" ) )
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ static boolean matchAntPathPattern( char[][] patDirs, char[][] strDirs, boolean isCaseSensitive )
+ {
+ int patIdxStart = 0;
+ int patIdxEnd = patDirs.length - 1;
+ int strIdxStart = 0;
+ int strIdxEnd = strDirs.length - 1;
+
+ // up to first '**'
+ while ( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd )
+ {
+ char[] patDir = patDirs[patIdxStart];
+ if ( isDoubleStar( patDir ) )
+ {
+ break;
+ }
+ if ( !match( patDir, strDirs[strIdxStart], isCaseSensitive ) )
+ {
+ return false;
+ }
+ patIdxStart++;
+ strIdxStart++;
+ }
+ if ( strIdxStart > strIdxEnd )
+ {
+ // String is exhausted
+ for ( int i = patIdxStart; i <= patIdxEnd; i++ )
+ {
+ if ( !isDoubleStar( patDirs[i] ) )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ else
+ {
+ if ( patIdxStart > patIdxEnd )
+ {
+ // String not exhausted, but pattern is. Failure.
+ return false;
+ }
+ }
+
+ // up to last '**'
+ while ( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd )
+ {
+ char[] patDir = patDirs[patIdxEnd];
+ if ( isDoubleStar( patDir ) )
+ {
+ break;
+ }
+ if ( !match( patDir, strDirs[strIdxEnd], isCaseSensitive ) )
{
- patDirs = null;
- strDirs = null;
return false;
}
patIdxEnd--;
@@ -360,10 +514,8 @@ private static boolean matchAntPathPattern( String pattern, String str, boolean
// String is exhausted
for ( int i = patIdxStart; i <= patIdxEnd; i++ )
{
- if ( !patDirs.elementAt( i ).equals( "**" ) )
+ if ( !isDoubleStar( patDirs[i] ) )
{
- patDirs = null;
- strDirs = null;
return false;
}
}
@@ -375,7 +527,7 @@ private static boolean matchAntPathPattern( String pattern, String str, boolean
int patIdxTmp = -1;
for ( int i = patIdxStart + 1; i <= patIdxEnd; i++ )
{
- if ( patDirs.elementAt( i ).equals( "**" ) )
+ if ( isDoubleStar( patDirs[i] ) )
{
patIdxTmp = i;
break;
@@ -393,26 +545,24 @@ private static boolean matchAntPathPattern( String pattern, String str, boolean
int strLength = ( strIdxEnd - strIdxStart + 1 );
int foundIdx = -1;
strLoop:
- for ( int i = 0; i <= strLength - patLength; i++ )
- {
- for ( int j = 0; j < patLength; j++ )
- {
- String subPat = (String) patDirs.elementAt( patIdxStart + j + 1 );
- String subStr = (String) strDirs.elementAt( strIdxStart + i + j );
- if ( !match( subPat, subStr, isCaseSensitive ) )
- {
- continue strLoop;
- }
- }
-
- foundIdx = strIdxStart + i;
- break;
- }
+ for ( int i = 0; i <= strLength - patLength; i++ )
+ {
+ for ( int j = 0; j < patLength; j++ )
+ {
+ char[] subPat = patDirs[patIdxStart + j + 1];
+ char[] subStr = strDirs[strIdxStart + i + j];
+ if ( !match( subPat, subStr, isCaseSensitive ) )
+ {
+ continue strLoop;
+ }
+ }
+
+ foundIdx = strIdxStart + i;
+ break;
+ }
if ( foundIdx == -1 )
{
- patDirs = null;
- strDirs = null;
return false;
}
@@ -422,10 +572,8 @@ private static boolean matchAntPathPattern( String pattern, String str, boolean
for ( int i = patIdxStart; i <= patIdxEnd; i++ )
{
- if ( !patDirs.elementAt( i ).equals( "**" ) )
+ if ( !isDoubleStar( patDirs[i] ) )
{
- patDirs = null;
- strDirs = null;
return false;
}
}
@@ -433,6 +581,11 @@ private static boolean matchAntPathPattern( String pattern, String str, boolean
return true;
}
+ private static boolean isDoubleStar( char[] patDir )
+ {
+ return patDir != null && patDir.length == 2 && patDir[0] == '*' && patDir[1] == '*';
+ }
+
/**
* Tests whether or not a string matches against a pattern.
* The pattern may contain two special characters:
@@ -443,7 +596,6 @@ private static boolean matchAntPathPattern( String pattern, String str, boolean
* Must not be null.
* @param str The string which must be matched against the pattern.
* Must not be null.
- *
* @return true if the string matches against the pattern,
* or false otherwise.
*/
@@ -458,22 +610,24 @@ public static boolean match( String pattern, String str )
* '*' means zero or more characters
* '?' means one and only one character
*
- * @param pattern The pattern to match against.
- * Must not be null.
- * @param str The string which must be matched against the pattern.
- * Must not be null.
+ * @param pattern The pattern to match against.
+ * Must not be null.
+ * @param str The string which must be matched against the pattern.
+ * Must not be null.
* @param isCaseSensitive Whether or not matching should be performed
* case sensitively.
- *
- *
* @return true if the string matches against the pattern,
* or false otherwise.
*/
- public static boolean match( String pattern, String str,
- boolean isCaseSensitive )
+ public static boolean match( String pattern, String str, boolean isCaseSensitive )
{
char[] patArr = pattern.toCharArray();
char[] strArr = str.toCharArray();
+ return match( patArr, strArr, isCaseSensitive);
+ }
+
+ public static boolean match( char[] patArr, char[] strArr, boolean isCaseSensitive )
+ {
int patIdxStart = 0;
int patIdxEnd = patArr.length - 1;
int strIdxStart = 0;
@@ -481,9 +635,9 @@ public static boolean match( String pattern, String str,
char ch;
boolean containsStar = false;
- for ( int i = 0; i < patArr.length; i++ )
+ for ( char aPatArr : patArr )
{
- if ( patArr[i] == '*' )
+ if ( aPatArr == '*' )
{
containsStar = true;
break;
@@ -634,8 +788,8 @@ private static boolean equals( char c1, char c2, boolean isCaseSensitive )
if ( !isCaseSensitive )
{
// NOTE: Try both upper case and lower case as done by String.equalsIgnoreCase()
- if ( Character.toUpperCase( c1 ) == Character.toUpperCase( c2 ) ||
- Character.toLowerCase( c1 ) == Character.toLowerCase( c2 ) )
+ if ( Character.toUpperCase( c1 ) == Character.toUpperCase( c2 )
+ || Character.toLowerCase( c1 ) == Character.toLowerCase( c2 ) )
{
return true;
}
@@ -643,28 +797,15 @@ private static boolean equals( char c1, char c2, boolean isCaseSensitive )
return false;
}
- /**
- * Breaks a path up into a Vector of path elements, tokenizing on
- * File.separator.
- *
- * @param path Path to tokenize. Must not be null.
- *
- * @return a Vector of path elements from the tokenized path
- */
- public static Vector tokenizePath( String path )
- {
- return tokenizePath( path, File.separator );
- }
-
- public static Vector tokenizePath( String path, String separator )
+ private static String[] tokenizePathToString( String path, String separator )
{
- Vector ret = new Vector();
+ List ret = new ArrayList();
StringTokenizer st = new StringTokenizer( path, separator );
while ( st.hasMoreTokens() )
{
- ret.addElement( st.nextToken() );
+ ret.add( st.nextToken() );
}
- return ret;
+ return ret.toArray( new String[ret.size()] );
}
@@ -676,10 +817,10 @@ public static Vector tokenizePath( String path, String separator )
* false if the src file doesn't even exist, since how could the
* target then be out of date.
*
- * @param src the original file
- * @param target the file being compared against
+ * @param src the original file
+ * @param target the file being compared against
* @param granularity the amount in seconds of slack we will give in
- * determining out of dateness
+ * determining out of dateness
* @return whether the target is out of date
*/
public static boolean isOutOfDate( File src, File target, int granularity )
@@ -709,7 +850,7 @@ public static boolean isOutOfDate( File src, File target, int granularity )
*/
public static String removeWhitespace( String input )
{
- StringBuffer result = new StringBuffer();
+ StringBuilder result = new StringBuilder();
if ( input != null )
{
StringTokenizer st = new StringTokenizer( input );
diff --git a/src/main/java/org/codehaus/plexus/util/StringUtils.java b/src/main/java/org/codehaus/plexus/util/StringUtils.java
index 7e485e46..846f491f 100644
--- a/src/main/java/org/codehaus/plexus/util/StringUtils.java
+++ b/src/main/java/org/codehaus/plexus/util/StringUtils.java
@@ -58,8 +58,6 @@
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
/**
*
Common String manipulation routines.
@@ -139,7 +137,7 @@ public static String trim( String str )
*/
public static String deleteWhitespace( String str )
{
- StringBuffer buffer = new StringBuffer();
+ StringBuilder buffer = new StringBuilder();
int sz = str.length();
for ( int i = 0; i < sz; i++ )
{
@@ -294,10 +292,10 @@ public static int indexOfAny( String str, String[] searchStrs )
// String's can't have a MAX_VALUEth index.
int ret = Integer.MAX_VALUE;
- int tmp = 0;
- for ( int i = 0; i < sz; i++ )
+ int tmp;
+ for ( String searchStr : searchStrs )
{
- tmp = str.indexOf( searchStrs[i] );
+ tmp = str.indexOf( searchStr );
if ( tmp == -1 )
{
continue;
@@ -328,12 +326,11 @@ public static int lastIndexOfAny( String str, String[] searchStrs )
{
return -1;
}
- int sz = searchStrs.length;
int ret = -1;
- int tmp = 0;
- for ( int i = 0; i < sz; i++ )
+ int tmp;
+ for ( String searchStr : searchStrs )
{
- tmp = str.lastIndexOf( searchStrs[i] );
+ tmp = str.lastIndexOf( searchStr );
if ( tmp > ret )
{
ret = tmp;
@@ -576,7 +573,7 @@ public static String[] split( String text, String separator )
*/
public static String[] split( String str, String separator, int max )
{
- StringTokenizer tok = null;
+ StringTokenizer tok;
if ( separator == null )
{
// Null separator means we're using StringTokenizer's default
@@ -596,7 +593,7 @@ public static String[] split( String str, String separator, int max )
String[] list = new String[listSize];
int i = 0;
- int lastTokenBegin = 0;
+ int lastTokenBegin;
int lastTokenEnd = 0;
while ( tok.hasMoreTokens() )
{
@@ -656,7 +653,7 @@ public static String join( Object[] array, String separator )
int arraySize = array.length;
int bufSize = ( arraySize == 0 ? 0 : ( array[0].toString().length() +
separator.length() ) * arraySize );
- StringBuffer buf = new StringBuffer( bufSize );
+ StringBuilder buf = new StringBuilder( bufSize );
for ( int i = 0; i < arraySize; i++ )
{
@@ -680,13 +677,13 @@ public static String join( Object[] array, String separator )
* @param separator the separator character to use
* @return the joined String
*/
- public static String join( Iterator iterator, String separator )
+ public static String join( Iterator> iterator, String separator )
{
if ( separator == null )
{
separator = "";
}
- StringBuffer buf = new StringBuffer( 256 ); // Java default is 16, probably too small
+ StringBuilder buf = new StringBuilder( 256 ); // Java default is 16, probably too small
while ( iterator.hasNext() )
{
buf.append( iterator.next() );
@@ -803,11 +800,11 @@ public static String replace( String text, String repl, String with, int max )
return text;
}
- StringBuffer buf = new StringBuffer( text.length() );
- int start = 0, end = 0;
+ StringBuilder buf = new StringBuilder( text.length() );
+ int start = 0, end;
while ( ( end = text.indexOf( repl, start ) ) != -1 )
{
- buf.append( text.substring( start, end ) ).append( with );
+ buf.append( text, start, end ).append( with );
start = end + repl.length();
if ( --max == 0 )
@@ -815,7 +812,7 @@ public static String replace( String text, String repl, String with, int max )
break;
}
}
- buf.append( text.substring( start ) );
+ buf.append( text, start, text.length());
return buf.toString();
}
@@ -832,9 +829,9 @@ public static String replace( String text, String repl, String with, int max )
public static String overlayString( String text, String overlay, int start, int end )
{
return new StringBuffer( start + overlay.length() + text.length() - end + 1 )
- .append( text.substring( 0, start ) )
+ .append( text, 0, start )
.append( overlay )
- .append( text.substring( end ) )
+ .append( text, end, text.length() )
.toString();
}
@@ -1109,7 +1106,7 @@ public static String escape( String str )
// improved with code from cybertiger@cyberiantiger.org
// unicode from him, and defaul for < 32's.
int sz = str.length();
- StringBuffer buffer = new StringBuffer( 2 * sz );
+ StringBuilder buffer = new StringBuilder( 2 * sz );
for ( int i = 0; i < sz; i++ )
{
char ch = str.charAt( i );
@@ -1203,7 +1200,7 @@ else if ( ch < 32 )
*/
public static String repeat( String str, int repeat )
{
- StringBuffer buffer = new StringBuffer( repeat * str.length() );
+ StringBuilder buffer = new StringBuilder( repeat * str.length() );
for ( int i = 0; i < repeat; i++ )
{
buffer.append( str );
@@ -1480,7 +1477,7 @@ else if ( str.length() == 0 )
{
return new StringBuffer( str.length() )
.append( Character.toLowerCase( str.charAt( 0 ) ) )
- .append( str.substring( 1 ) )
+ .append( str, 1, str.length() )
.toString();
}
}
@@ -1506,9 +1503,9 @@ else if ( str.length() == 0 )
}
else
{
- return new StringBuffer( str.length() )
+ return new StringBuilder( str.length() )
.append( Character.toTitleCase( str.charAt( 0 ) ) )
- .append( str.substring( 1 ) )
+ .append( str, 1, str.length() )
.toString();
}
}
@@ -1531,11 +1528,11 @@ public static String swapCase( String str )
return null;
}
int sz = str.length();
- StringBuffer buffer = new StringBuffer( sz );
+ StringBuilder buffer = new StringBuilder( sz );
boolean whitespace = false;
- char ch = 0;
- char tmp = 0;
+ char ch;
+ char tmp;
for ( int i = 0; i < sz; i++ )
{
@@ -1588,7 +1585,7 @@ public static String capitaliseAllWords( String str )
return null;
}
int sz = str.length();
- StringBuffer buffer = new StringBuffer( sz );
+ StringBuilder buffer = new StringBuilder( sz );
boolean space = true;
for ( int i = 0; i < sz; i++ )
{
@@ -1629,7 +1626,7 @@ public static String uncapitaliseAllWords( String str )
return null;
}
int sz = str.length();
- StringBuffer buffer = new StringBuffer( sz );
+ StringBuilder buffer = new StringBuilder( sz );
boolean space = true;
for ( int i = 0; i < sz; i++ )
{
@@ -2132,9 +2129,9 @@ public static int differenceAt( String s1, String s2 )
return -1;
}
- public static String interpolate( String text, Map namespace )
+ public static String interpolate( String text, Map, ?> namespace )
{
- Iterator keys = namespace.keySet().iterator();
+ Iterator> keys = namespace.keySet().iterator();
while ( keys.hasNext() )
{
@@ -2163,7 +2160,7 @@ public static String removeAndHump( String data, String replaceThis )
{
String temp;
- StringBuffer out = new StringBuffer();
+ StringBuilder out = new StringBuilder();
temp = data;
@@ -2199,7 +2196,7 @@ public static String lowercaseFirstLetter( String data )
public static String addAndDeHump( String view )
{
- StringBuffer sb = new StringBuffer();
+ StringBuilder sb = new StringBuilder();
for ( int i = 0; i < view.length(); i++ )
{
@@ -2290,18 +2287,37 @@ public static String quoteAndEscape( String source,
char escapeChar,
boolean force )
{
+ return quoteAndEscape(source, quoteChar, escapedChars, quotingTriggers, escapeChar + "%s", force);
+ }
+
+ /**
+ * @param source
+ * @param quoteChar
+ * @param escapedChars
+ * @param quotingTriggers
+ * @param escapePattern
+ * @param force
+ * @return the String quoted and escaped
+ * @since 3.0.4
+ */
+ public static String quoteAndEscape(String source,
+ char quoteChar,
+ final char[] escapedChars,
+ final char[] quotingTriggers,
+ String escapePattern,
+ boolean force) {
if ( source == null )
{
return null;
}
if ( !force && source.startsWith( Character.toString( quoteChar ) )
- && source.endsWith( Character.toString( quoteChar ) ) )
+ && source.endsWith( Character.toString( quoteChar ) ) )
{
return source;
}
- String escaped = escape( source, escapedChars, escapeChar );
+ String escaped = escape( source, escapedChars, escapePattern );
boolean quote = false;
if ( force )
@@ -2314,9 +2330,9 @@ else if ( !escaped.equals( source ) )
}
else
{
- for ( int i = 0; i < quotingTriggers.length; i++ )
+ for ( char quotingTrigger : quotingTriggers )
{
- if ( escaped.indexOf( quotingTriggers[i] ) > -1 )
+ if ( escaped.indexOf( quotingTrigger ) > -1 )
{
quote = true;
break;
@@ -2340,6 +2356,18 @@ else if ( !escaped.equals( source ) )
* @since 1.5.1
*/
public static String escape( String source, final char[] escapedChars, char escapeChar )
+ {
+ return escape(source, escapedChars, escapeChar + "%s");
+ }
+
+ /**
+ * @param source
+ * @param escapedChars
+ * @param escapePattern
+ * @return the String escaped
+ * @since 3.0.4
+ */
+ public static String escape( String source, final char[] escapedChars, String escapePattern )
{
if ( source == null )
{
@@ -2350,9 +2378,8 @@ public static String escape( String source, final char[] escapedChars, char esca
System.arraycopy( escapedChars, 0, eqc, 0, escapedChars.length );
Arrays.sort( eqc );
- StringBuffer buffer = new StringBuffer( source.length() );
+ StringBuilder buffer = new StringBuilder( source.length() );
- int escapeCount = 0;
for ( int i = 0; i < source.length(); i++ )
{
final char c = source.charAt( i );
@@ -2360,11 +2387,12 @@ public static String escape( String source, final char[] escapedChars, char esca
if ( result > -1 )
{
- buffer.append( escapeChar );
- escapeCount++;
+ buffer.append( String.format(escapePattern, c) );
+ }
+ else
+ {
+ buffer.append( c );
}
-
- buffer.append( c );
}
return buffer.toString();
@@ -2380,11 +2408,18 @@ public static String escape( String source, final char[] escapedChars, char esca
*/
public static String removeDuplicateWhitespace( String s )
{
- String patternStr = "\\s+";
- String replaceStr = " ";
- Pattern pattern = Pattern.compile( patternStr );
- Matcher matcher = pattern.matcher( s );
- return matcher.replaceAll( replaceStr );
+ StringBuilder result = new StringBuilder( );
+ int length = s.length();
+ boolean isPreviousWhiteSpace = false;
+ for (int i = 0; i < length; i++){
+ char c = s.charAt( i );
+ boolean thisCharWhiteSpace = Character.isWhitespace( c );
+ if (!(isPreviousWhiteSpace && thisCharWhiteSpace)){
+ result.append( c );
+ }
+ isPreviousWhiteSpace = thisCharWhiteSpace;
+ }
+ return result.toString();
}
/**
@@ -2430,7 +2465,7 @@ public static String unifyLineSeparators( String s, String ls )
int length = s.length();
- StringBuffer buffer = new StringBuffer( length );
+ StringBuilder buffer = new StringBuilder( length );
for ( int i = 0; i < length; i++ )
{
if ( s.charAt( i ) == '\r' )
diff --git a/src/main/java/org/codehaus/plexus/util/WriterFactory.java b/src/main/java/org/codehaus/plexus/util/WriterFactory.java
index 58095195..b730bc0e 100644
--- a/src/main/java/org/codehaus/plexus/util/WriterFactory.java
+++ b/src/main/java/org/codehaus/plexus/util/WriterFactory.java
@@ -118,7 +118,7 @@ public static XmlStreamWriter newXmlWriter( File file )
}
/**
- * Create a new Writer with default plaform encoding.
+ * Create a new Writer with default platform encoding.
*
* @param out not null output stream.
* @return a writer instance for the output stream using the default platform charset.
@@ -131,7 +131,7 @@ public static Writer newPlatformWriter( OutputStream out )
}
/**
- * Create a new Writer with default plaform encoding.
+ * Create a new Writer with default platform encoding.
*
* @param file not null file.
* @return a writer instance for the output file using the default platform charset.
diff --git a/src/main/java/org/codehaus/plexus/util/cli/AbstractStreamHandler.java b/src/main/java/org/codehaus/plexus/util/cli/AbstractStreamHandler.java
new file mode 100644
index 00000000..2c7e8967
--- /dev/null
+++ b/src/main/java/org/codehaus/plexus/util/cli/AbstractStreamHandler.java
@@ -0,0 +1,59 @@
+package org.codehaus.plexus.util.cli;
+
+/*
+ * Copyright The Codehaus Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @author Kristian Rosenvold
+ */
+public class AbstractStreamHandler
+ extends Thread
+{
+ private boolean done;
+
+ private volatile boolean disabled;
+
+ public boolean isDone()
+ {
+ return done;
+ }
+
+ public synchronized void waitUntilDone()
+ throws InterruptedException
+ {
+ while ( !isDone() )
+ {
+ wait();
+ }
+ }
+
+
+ protected boolean isDisabled()
+ {
+ return disabled;
+ }
+
+ public void disable()
+ {
+ disabled = true;
+ }
+
+ public void setDone()
+ {
+ done = true;
+ }
+
+}
diff --git a/src/main/java/org/codehaus/plexus/util/cli/CommandLineCallable.java b/src/main/java/org/codehaus/plexus/util/cli/CommandLineCallable.java
new file mode 100644
index 00000000..8a451607
--- /dev/null
+++ b/src/main/java/org/codehaus/plexus/util/cli/CommandLineCallable.java
@@ -0,0 +1,28 @@
+package org.codehaus.plexus.util.cli;
+
+/*
+ * Copyright The Codehaus Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.concurrent.Callable;
+
+/**
+ * Callable wrapper that exposes the proper exeception type to the client.
+ * @author Kristian Rosenvold
+ */
+public interface CommandLineCallable extends Callable
+{
+ public Integer call() throws CommandLineException;
+}
diff --git a/src/main/java/org/codehaus/plexus/util/cli/CommandLineUtils.java b/src/main/java/org/codehaus/plexus/util/cli/CommandLineUtils.java
index 255a061d..fc73e515 100644
--- a/src/main/java/org/codehaus/plexus/util/cli/CommandLineUtils.java
+++ b/src/main/java/org/codehaus/plexus/util/cli/CommandLineUtils.java
@@ -16,24 +16,15 @@
* limitations under the License.
*/
-import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Vector;
-
import org.codehaus.plexus.util.Os;
-import org.codehaus.plexus.util.ReaderFactory;
import org.codehaus.plexus.util.StringUtils;
/**
@@ -42,47 +33,6 @@
*/
public abstract class CommandLineUtils
{
- private static Map processes = Collections.synchronizedMap( new HashMap() );
-
- private static Thread shutdownHook = new Thread( "CommandlineUtil shutdown" )
- {
- public void run()
- {
- if ( ( processes != null ) && ( processes.size() > 0 ) )
- {
- System.err.println( "Destroying " + processes.size() + " processes" );
- for ( Iterator it = processes.values().iterator(); it.hasNext(); )
- {
- System.err.println( "Destroying process.." );
- ( (Process) it.next() ).destroy();
-
- }
- System.err.println( "Destroyed " + processes.size() + " processes" );
- }
- }
- };
-
- static
- {
- shutdownHook.setContextClassLoader( null );
- addShutdownHook();
- }
-
- public static void addShutdownHook()
- {
- Runtime.getRuntime().addShutdownHook( shutdownHook );
- }
-
- public static void removeShutdownHook( boolean execute )
- {
- Runtime.getRuntime().removeShutdownHook( shutdownHook );
-
- if ( execute )
- {
- shutdownHook.run();
- }
- }
-
public static class StringStreamConsumer
implements StreamConsumer
{
@@ -101,6 +51,23 @@ public String getOutput()
}
}
+ private static class ProcessHook extends Thread {
+ private final Process process;
+
+ private ProcessHook( Process process )
+ {
+ super("CommandlineUtils process shutdown hook");
+ this.process = process;
+ this.setContextClassLoader( null );
+ }
+
+ public void run()
+ {
+ process.destroy();
+ }
+ }
+
+
public static int executeCommandLine( Commandline cl, StreamConsumer systemOut, StreamConsumer systemErr )
throws CommandLineException
{
@@ -122,39 +89,56 @@ public static int executeCommandLine( Commandline cl, InputStream systemIn, Stre
}
/**
- * @param cl The command line to execute
- * @param systemIn The input to read from, must be thread safe
- * @param systemOut A consumer that receives output, must be thread safe
- * @param systemErr A consumer that receives system error stream output, must be thread safe
+ * @param cl The command line to execute
+ * @param systemIn The input to read from, must be thread safe
+ * @param systemOut A consumer that receives output, must be thread safe
+ * @param systemErr A consumer that receives system error stream output, must be thread safe
* @param timeoutInSeconds Positive integer to specify timeout, zero and negative integers for no timeout.
* @return A return value, see {@link Process#exitValue()}
* @throws CommandLineException or CommandLineTimeOutException if time out occurs
+ * @noinspection ThrowableResultOfMethodCallIgnored
*/
public static int executeCommandLine( Commandline cl, InputStream systemIn, StreamConsumer systemOut,
StreamConsumer systemErr, int timeoutInSeconds )
throws CommandLineException
+ {
+ final CommandLineCallable future =
+ executeCommandLineAsCallable( cl, systemIn, systemOut, systemErr, timeoutInSeconds );
+ return future.call();
+ }
+
+ /**
+ * Immediately forks a process, returns a callable that will block until process is complete.
+ * @param cl The command line to execute
+ * @param systemIn The input to read from, must be thread safe
+ * @param systemOut A consumer that receives output, must be thread safe
+ * @param systemErr A consumer that receives system error stream output, must be thread safe
+ * @param timeoutInSeconds Positive integer to specify timeout, zero and negative integers for no timeout.
+ * @return A CommandLineCallable that provides the process return value, see {@link Process#exitValue()}. "call" must be called on
+ * this to be sure the forked process has terminated, no guarantees is made about
+ * any internal state before after the completion of the call statements
+ * @throws CommandLineException or CommandLineTimeOutException if time out occurs
+ * @noinspection ThrowableResultOfMethodCallIgnored
+ */
+ public static CommandLineCallable executeCommandLineAsCallable( final Commandline cl, final InputStream systemIn,
+ final StreamConsumer systemOut,
+ final StreamConsumer systemErr,
+ final int timeoutInSeconds )
+ throws CommandLineException
{
if ( cl == null )
{
throw new IllegalArgumentException( "cl cannot be null." );
}
- Process p;
+ final Process p = cl.execute();
- p = cl.execute();
-
- processes.put( new Long( cl.getPid() ), p );
-
- StreamFeeder inputFeeder = null;
-
- if ( systemIn != null )
- {
- inputFeeder = new StreamFeeder( systemIn, p.getOutputStream() );
- }
+ final StreamFeeder inputFeeder = systemIn != null ?
+ new StreamFeeder( systemIn, p.getOutputStream() ) : null;
- StreamPumper outputPumper = new StreamPumper( p.getInputStream(), systemOut );
+ final StreamPumper outputPumper = new StreamPumper( p.getInputStream(), systemOut );
- StreamPumper errorPumper = new StreamPumper( p.getErrorStream(), systemErr );
+ final StreamPumper errorPumper = new StreamPumper( p.getErrorStream(), systemErr );
if ( inputFeeder != null )
{
@@ -165,93 +149,92 @@ public static int executeCommandLine( Commandline cl, InputStream systemIn, Stre
errorPumper.start();
- try
+ final ProcessHook processHook = new ProcessHook( p );
+
+ ShutdownHookUtils.addShutDownHook( processHook );
+
+ return new CommandLineCallable()
{
- int returnValue;
- if ( timeoutInSeconds <= 0 )
- {
- returnValue = p.waitFor();
- }
- else
+ public Integer call()
+ throws CommandLineException
{
- long now = System.currentTimeMillis();
- long timeoutInMillis = 1000L * timeoutInSeconds;
- long finish = now + timeoutInMillis;
- while ( isAlive( p ) && ( System.currentTimeMillis() < finish ) )
+ try
{
- Thread.sleep( 10 );
- }
- if ( isAlive( p ) )
- {
- throw new InterruptedException( "Process timeout out after " + timeoutInSeconds + " seconds" );
- }
- returnValue = p.exitValue();
- }
+ int returnValue;
+ if ( timeoutInSeconds <= 0 )
+ {
+ returnValue = p.waitFor();
+ }
+ else
+ {
+ long now = System.currentTimeMillis();
+ long timeoutInMillis = 1000L * timeoutInSeconds;
+ long finish = now + timeoutInMillis;
+ while ( isAlive( p ) && ( System.currentTimeMillis() < finish ) )
+ {
+ Thread.sleep( 10 );
+ }
+ if ( isAlive( p ) )
+ {
+ throw new InterruptedException( "Process timeout out after " + timeoutInSeconds + " seconds" );
+ }
+ returnValue = p.exitValue();
+ }
- if ( inputFeeder != null )
- {
- synchronized ( inputFeeder )
- {
- while ( !inputFeeder.isDone() )
+ waitForAllPumpers( inputFeeder, outputPumper, errorPumper );
+
+ if ( outputPumper.getException() != null )
{
- inputFeeder.wait();
+ throw new CommandLineException( "Error inside systemOut parser", outputPumper.getException() );
}
- }
- }
- synchronized ( outputPumper )
- {
- while ( !outputPumper.isDone() )
- {
- outputPumper.wait();
- }
- }
+ if ( errorPumper.getException() != null )
+ {
+ throw new CommandLineException( "Error inside systemErr parser", errorPumper.getException() );
+ }
- synchronized ( errorPumper )
- {
- while ( !errorPumper.isDone() )
+ return returnValue;
+ }
+ catch ( InterruptedException ex )
{
- errorPumper.wait();
+ if ( inputFeeder != null )
+ {
+ inputFeeder.disable();
+ }
+ outputPumper.disable();
+ errorPumper.disable();
+ throw new CommandLineTimeOutException( "Error while executing external command, process killed.", ex );
}
- }
+ finally
+ {
+ ShutdownHookUtils.removeShutdownHook( processHook );
- processes.remove( new Long( cl.getPid() ) );
+ processHook.run();
- if ( outputPumper.getException() != null )
- {
- throw new CommandLineException( "Error inside systemOut parser", outputPumper.getException() );
- }
+ if ( inputFeeder != null )
+ {
+ inputFeeder.close();
+ }
- if ( errorPumper.getException() != null )
- {
- throw new CommandLineException( "Error inside systemErr parser", errorPumper.getException() );
+ outputPumper.close();
+
+ errorPumper.close();
+ }
}
+ };
+ }
- return returnValue;
- }
- catch ( InterruptedException ex )
+ private static void waitForAllPumpers( StreamFeeder inputFeeder, StreamPumper outputPumper,
+ StreamPumper errorPumper )
+ throws InterruptedException
+ {
+ if ( inputFeeder != null )
{
- killProcess( cl.getPid() );
- throw new CommandLineTimeOutException( "Error while executing external command, process killed.", ex );
+ inputFeeder.waitUntilDone();
}
- finally
- {
- if ( inputFeeder != null )
- {
- inputFeeder.close();
- }
-
- outputPumper.close();
-
- errorPumper.close();
- p.destroy();
-
- if ( processes.get( new Long( cl.getPid() ) ) != null )
- {
- processes.remove( new Long( cl.getPid() ) );
- }
- }
+ outputPumper.waitUntilDone();
+ errorPumper.waitUntilDone();
}
/**
@@ -263,7 +246,7 @@ public static int executeCommandLine( Commandline cl, InputStream systemIn, Stre
* @return The shell environment variables, can be empty but never null.
* @throws IOException If the environment variables could not be queried from the shell.
* @see System#getenv() System.getenv() API, new in JDK 5.0, to get the same result
- * since 2.0.2 System#getenv() will be used if available in the current running jvm.
+ * since 2.0.2 System#getenv() will be used if available in the current running jvm.
*/
public static Properties getSystemEnvVars()
throws IOException
@@ -277,137 +260,25 @@ public static Properties getSystemEnvVars()
*
* @param caseSensitive Whether environment variable keys should be treated case-sensitively.
* @return Properties object of (possibly modified) envar keys mapped to their values.
- * @throws IOException
+ * @throws IOException .
* @see System#getenv() System.getenv() API, new in JDK 5.0, to get the same result
- * since 2.0.2 System#getenv() will be used if available in the current running jvm.
+ * since 2.0.2 System#getenv() will be used if available in the current running jvm.
*/
public static Properties getSystemEnvVars( boolean caseSensitive )
throws IOException
{
-
- // check if it's 1.5+ run
-
- Method getenvMethod = getEnvMethod();
- if ( getenvMethod != null )
- {
- try
- {
- return getEnvFromSystem( getenvMethod, caseSensitive );
- }
- catch ( IllegalAccessException e )
- {
- throw new IOException( e.getMessage() );
- }
- catch ( IllegalArgumentException e )
- {
- throw new IOException( e.getMessage() );
- }
- catch ( InvocationTargetException e )
- {
- throw new IOException( e.getMessage() );
- }
- }
-
- Process p = null;
-
- try
- {
- Properties envVars = new Properties();
-
- Runtime r = Runtime.getRuntime();
-
- //If this is windows set the shell to command.com or cmd.exe with correct arguments.
- boolean overriddenEncoding = false;
- if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
- {
- if ( Os.isFamily( Os.FAMILY_WIN9X ) )
- {
- p = r.exec( "command.com /c set" );
- }
- else
- {
- overriddenEncoding = true;
- // /U = change stdout encoding to UTF-16LE to avoid encoding inconsistency
- // between command-line/DOS and GUI/Windows, see PLXUTILS-124
- p = r.exec( "cmd.exe /U /c set" );
- }
- }
- else
- {
- p = r.exec( "env" );
- }
-
- Reader reader = overriddenEncoding
- ? new InputStreamReader( p.getInputStream(), ReaderFactory.UTF_16LE )
- : new InputStreamReader( p.getInputStream() );
- BufferedReader br = new BufferedReader( reader );
-
- String line;
-
- String lastKey = null;
- String lastVal = null;
-
- while ( ( line = br.readLine() ) != null )
- {
- int idx = line.indexOf( '=' );
-
- if ( idx > 0 )
- {
- lastKey = line.substring( 0, idx );
-
- if ( !caseSensitive )
- {
- lastKey = lastKey.toUpperCase( Locale.ENGLISH );
- }
-
- lastVal = line.substring( idx + 1 );
-
- envVars.setProperty( lastKey, lastVal );
- }
- else if ( lastKey != null )
- {
- lastVal += "\n" + line;
-
- envVars.setProperty( lastKey, lastVal );
- }
- }
-
- return envVars;
- }
- finally
+ Properties envVars = new Properties();
+ Map envs = System.getenv();
+ for ( String key : envs.keySet() )
{
- if ( p != null )
+ String value = envs.get( key );
+ if ( !caseSensitive)
{
- p.destroy();
+ key = key.toUpperCase( Locale.ENGLISH );
}
+ envVars.put( key, value );
}
- }
-
- /**
- * Kill a process launched by executeCommandLine methods.
- * Doesn't work correctly on windows, only the cmd process will be destroy but not the sub process (Bug ID 4770092)
- *
- * @param pid The pid of command return by Commandline.getPid()
- */
- public static void killProcess( long pid )
- {
- Process p = (Process) processes.get( new Long( pid ) );
-
- if ( p != null )
- {
- p.destroy();
- System.out.println( "Process " + pid + " is killed." );
- processes.remove( new Long( pid ) );
- }
- else
- {
- System.out.println( "don't exist." );
- }
- }
-
- public static boolean isAlive( long pid )
- {
- return ( processes.get( new Long( pid ) ) != null );
+ return envVars;
}
public static boolean isAlive( Process p )
@@ -443,8 +314,8 @@ public static String[] translateCommandline( String toProcess )
final int inDoubleQuote = 2;
int state = normal;
StringTokenizer tok = new StringTokenizer( toProcess, "\"\' ", true );
- Vector v = new Vector();
- StringBuffer current = new StringBuffer();
+ Vector v = new Vector();
+ StringBuilder current = new StringBuilder();
while ( tok.hasMoreTokens() )
{
@@ -523,6 +394,7 @@ else if ( " ".equals( nextTok ) )
* {@link StringUtils#quoteAndEscape(String, char, char[], char, boolean)}, or
* {@link StringUtils#quoteAndEscape(String, char)} instead.
*/
+ @SuppressWarnings( { "JavaDoc", "deprecation" } )
public static String quote( String argument )
throws CommandLineException
{
@@ -541,6 +413,7 @@ public static String quote( String argument )
* {@link StringUtils#quoteAndEscape(String, char, char[], char, boolean)}, or
* {@link StringUtils#quoteAndEscape(String, char)} instead.
*/
+ @SuppressWarnings( { "JavaDoc", "UnusedDeclaration", "deprecation" } )
public static String quote( String argument, boolean wrapExistingQuotes )
throws CommandLineException
{
@@ -552,13 +425,14 @@ public static String quote( String argument, boolean wrapExistingQuotes )
* {@link StringUtils#quoteAndEscape(String, char, char[], char, boolean)}, or
* {@link StringUtils#quoteAndEscape(String, char)} instead.
*/
+ @SuppressWarnings( { "JavaDoc" } )
public static String quote( String argument, boolean escapeSingleQuotes, boolean escapeDoubleQuotes,
boolean wrapExistingQuotes )
throws CommandLineException
{
- if ( argument.indexOf( "\"" ) > -1 )
+ if ( argument.contains( "\"" ) )
{
- if ( argument.indexOf( "\'" ) > -1 )
+ if ( argument.contains( "\'" ) )
{
throw new CommandLineException( "Can't handle single and double quotes in same argument" );
}
@@ -574,7 +448,7 @@ else if ( wrapExistingQuotes )
}
}
}
- else if ( argument.indexOf( "\'" ) > -1 )
+ else if ( argument.contains( "\'" ) )
{
if ( escapeDoubleQuotes )
{
@@ -585,7 +459,7 @@ else if ( wrapExistingQuotes )
return '\"' + argument + '\"';
}
}
- else if ( argument.indexOf( " " ) > -1 )
+ else if ( argument.contains( " " ) )
{
if ( escapeDoubleQuotes )
{
@@ -609,7 +483,7 @@ public static String toString( String[] line )
}
// path containing one or more elements
- final StringBuffer result = new StringBuffer();
+ final StringBuilder result = new StringBuilder();
for ( int i = 0; i < line.length; i++ )
{
if ( i > 0 )
@@ -627,39 +501,5 @@ public static String toString( String[] line )
}
return result.toString();
}
-
- private static Method getEnvMethod()
- {
- try
- {
- return System.class.getMethod( "getenv", null );
- }
- catch ( NoSuchMethodException e )
- {
- return null;
- }
- catch ( SecurityException e )
- {
- return null;
- }
- }
-
- private static Properties getEnvFromSystem( Method method, boolean caseSensitive )
- throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
- {
- Properties envVars = new Properties();
- Map envs = (Map) method.invoke( null, null );
- Iterator iterator = envs.keySet().iterator();
- while ( iterator.hasNext() )
- {
- String key = (String) iterator.next();
- String value = (String) envs.get( key );
- if ( !caseSensitive )
- {
- key = key.toUpperCase( Locale.ENGLISH );
- }
- envVars.put( key, value );
- }
- return envVars;
- }
+
}
diff --git a/src/main/java/org/codehaus/plexus/util/cli/Commandline.java b/src/main/java/org/codehaus/plexus/util/cli/Commandline.java
index 5e0d5af4..7346c7ef 100644
--- a/src/main/java/org/codehaus/plexus/util/cli/Commandline.java
+++ b/src/main/java/org/codehaus/plexus/util/cli/Commandline.java
@@ -139,6 +139,8 @@ public class Commandline
* Create a new command line object.
* Shell is autodetected from operating system
*
+ * Shell usage is only desirable when generating code for remote execution.
+ *
* @param toProcess
*/
public Commandline( String toProcess, Shell shell )
@@ -167,6 +169,8 @@ public Commandline( String toProcess, Shell shell )
/**
* Create a new command line object.
* Shell is autodetected from operating system
+ *
+ * Shell usage is only desirable when generating code for remote execution.
*/
public Commandline( Shell shell )
{
@@ -174,8 +178,7 @@ public Commandline( Shell shell )
}
/**
- * Create a new command line object.
- * Shell is autodetected from operating system
+ * Create a new command line object, given a command following POSIX sh quoting rules
*
* @param toProcess
*/
@@ -203,7 +206,6 @@ public Commandline( String toProcess )
/**
* Create a new command line object.
- * Shell is autodetected from operating system
*/
public Commandline()
{
@@ -253,7 +255,7 @@ public int getPosition()
{
if ( realPos == -1 )
{
- realPos = ( getExecutable() == null ? 0 : 1 );
+ realPos = ( getLiteralExecutable() == null ? 0 : 1 );
for ( int i = 0; i < position; i++ )
{
Arg arg = (Arg) arguments.elementAt( i );
@@ -404,6 +406,21 @@ public void setExecutable( String executable )
this.executable = executable;
}
+ /**
+ * @return Executable to be run, as a literal string (no shell quoting/munging)
+ */
+ public String getLiteralExecutable()
+ {
+ return executable;
+ }
+
+ /**
+ * Return an executable name, quoted for shell use.
+ *
+ * Shell usage is only desirable when generating code for remote execution.
+ *
+ * @return Executable to be run, quoted for shell interpretation
+ */
public String getExecutable()
{
String exec = shell.getExecutable();
@@ -483,7 +500,7 @@ public String[] getEnvironmentVariables()
public String[] getCommandline()
{
final String[] args = getArguments();
- String executable = getExecutable();
+ String executable = getLiteralExecutable();
if ( executable == null )
{
@@ -497,6 +514,8 @@ public String[] getCommandline()
/**
* Returns the shell, executable and all defined arguments.
+ *
+ * Shell usage is only desirable when generating code for remote execution.
*/
public String[] getShellCommandline()
{
@@ -633,7 +652,7 @@ public Process execute()
{
if ( workingDir == null )
{
- process = Runtime.getRuntime().exec( getShellCommandline(), environment );
+ process = Runtime.getRuntime().exec( getCommandline(), environment, workingDir );
}
else
{
@@ -648,7 +667,7 @@ else if ( !workingDir.isDirectory() )
+ "\" does not specify a directory." );
}
- process = Runtime.getRuntime().exec( getShellCommandline(), environment, workingDir );
+ process = Runtime.getRuntime().exec( getCommandline(), environment, workingDir );
}
}
catch ( IOException ex )
@@ -669,7 +688,7 @@ private void verifyShellState()
shell.setWorkingDirectory( workingDir );
}
- if ( shell.getExecutable() == null )
+ if ( shell.getOriginalExecutable() == null )
{
shell.setExecutable( executable );
}
@@ -684,6 +703,8 @@ public Properties getSystemEnvVars()
/**
* Allows to set the shell to be used in this command line.
*
+ * Shell usage is only desirable when generating code for remote execution.
+ *
* @param shell
* @since 1.2
*/
@@ -695,6 +716,7 @@ public void setShell( Shell shell )
/**
* Get the shell to be used in this command line.
*
+ * Shell usage is only desirable when generating code for remote execution.
* @since 1.2
*/
public Shell getShell()
diff --git a/src/main/java/org/codehaus/plexus/util/cli/ShutdownHookUtils.java b/src/main/java/org/codehaus/plexus/util/cli/ShutdownHookUtils.java
new file mode 100644
index 00000000..20873b07
--- /dev/null
+++ b/src/main/java/org/codehaus/plexus/util/cli/ShutdownHookUtils.java
@@ -0,0 +1,62 @@
+package org.codehaus.plexus.util.cli;
+
+/*
+ * Copyright The Codehaus Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.security.AccessControlException;
+
+/**
+ * A shutdown hook that does not throw any exceptions upon container startup/shutdown or security manager
+ * restrictions.
+ *
+ * Incorrect usage of the hook itself may still throw an exception.
+ *
+ * @author Kristian Rosenvold
+ */
+class ShutdownHookUtils
+{
+
+ public static void addShutDownHook( Thread hook )
+ {
+ try
+ {
+ Runtime.getRuntime().addShutdownHook( hook );
+ }
+ catch ( IllegalStateException ignore )
+ {
+ }
+ catch ( AccessControlException ignore )
+ {
+ }
+
+
+ }
+
+ public static void removeShutdownHook( Thread hook )
+ {
+ try
+ {
+ Runtime.getRuntime().removeShutdownHook( hook );
+ }
+ catch ( IllegalStateException ignore )
+ {
+ }
+ catch ( AccessControlException ignore )
+ {
+ }
+ }
+
+}
diff --git a/src/main/java/org/codehaus/plexus/util/cli/StreamFeeder.java b/src/main/java/org/codehaus/plexus/util/cli/StreamFeeder.java
index 4b6ab4cb..4259b656 100644
--- a/src/main/java/org/codehaus/plexus/util/cli/StreamFeeder.java
+++ b/src/main/java/org/codehaus/plexus/util/cli/StreamFeeder.java
@@ -26,14 +26,11 @@
* @author Trygve Laugstøl
* @version $Id$
*/
-public class StreamFeeder
- extends Thread
-{
+public class StreamFeeder extends AbstractStreamHandler {
private InputStream input;
private OutputStream output;
- private boolean done;
/**
* Create a new StreamFeeder
@@ -66,10 +63,9 @@ public void run()
{
close();
-
synchronized ( this )
{
- done = true;
+ setDone();
this.notifyAll();
}
@@ -117,11 +113,6 @@ public void close()
}
}
- public boolean isDone()
- {
- return done;
- }
-
// ----------------------------------------------------------------------
//
// ----------------------------------------------------------------------
@@ -131,14 +122,18 @@ private void feed()
{
int data = input.read();
- while ( !done && data != -1 )
+ while ( !isDone() && data != -1 )
{
synchronized ( output )
{
- output.write( data );
+ if ( !isDisabled())
+ {
+ output.write( data );
+ }
data = input.read();
}
}
}
+
}
diff --git a/src/main/java/org/codehaus/plexus/util/cli/StreamPumper.java b/src/main/java/org/codehaus/plexus/util/cli/StreamPumper.java
index 67d54da6..e9d93f31 100644
--- a/src/main/java/org/codehaus/plexus/util/cli/StreamPumper.java
+++ b/src/main/java/org/codehaus/plexus/util/cli/StreamPumper.java
@@ -84,11 +84,11 @@
*
* @author Florin Vancea
* @author Paul Julius
- * @since June 11, 2001
* @version $Id$
+ * @since June 11, 2001
*/
public class StreamPumper
- extends Thread
+ extends AbstractStreamHandler
{
private final BufferedReader in;
@@ -100,8 +100,6 @@ public class StreamPumper
private static final int SIZE = 1024;
- boolean done;
-
public StreamPumper( InputStream in )
{
this( in, (StreamConsumer) null );
@@ -160,7 +158,7 @@ public void run()
synchronized ( this )
{
- done = true;
+ setDone();
this.notifyAll();
}
@@ -180,11 +178,6 @@ public void close()
IOUtil.close( out );
}
- public boolean isDone()
- {
- return done;
- }
-
public Exception getException()
{
return exception;
@@ -192,7 +185,7 @@ public Exception getException()
private void consumeLine( String line )
{
- if ( consumer != null )
+ if ( consumer != null && !isDisabled() )
{
consumer.consumeLine( line );
}
diff --git a/src/main/java/org/codehaus/plexus/util/cli/shell/BourneShell.java b/src/main/java/org/codehaus/plexus/util/cli/shell/BourneShell.java
index 18e52838..9bf3a09f 100644
--- a/src/main/java/org/codehaus/plexus/util/cli/shell/BourneShell.java
+++ b/src/main/java/org/codehaus/plexus/util/cli/shell/BourneShell.java
@@ -17,7 +17,6 @@
*/
import org.codehaus.plexus.util.Os;
-import org.codehaus.plexus.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
@@ -29,37 +28,22 @@
public class BourneShell
extends Shell
{
- private static final char[] BASH_QUOTING_TRIGGER_CHARS = {
- ' ',
- '$',
- ';',
- '&',
- '|',
- '<',
- '>',
- '*',
- '?',
- '(',
- ')',
- '[',
- ']',
- '{',
- '}',
- '`' };
public BourneShell()
{
- this( false );
+ this(false);
}
public BourneShell( boolean isLoginShell )
{
+ setUnconditionalQuoting( true );
setShellCommand( "/bin/sh" );
setArgumentQuoteDelimiter( '\'' );
- setExecutableQuoteDelimiter( '\"' );
+ setExecutableQuoteDelimiter( '\'' );
setSingleQuotedArgumentEscaped( true );
setSingleQuotedExecutableEscaped( false );
setQuotedExecutableEnabled( true );
+ setArgumentEscapePattern("'\\%s'");
if ( isLoginShell )
{
@@ -75,13 +59,13 @@ public String getExecutable()
return super.getExecutable();
}
- return unifyQuotes( super.getExecutable());
+ return quoteOneItem( super.getOriginalExecutable(), true );
}
- public List getShellArgsList()
+ public List getShellArgsList()
{
- List shellArgs = new ArrayList();
- List existingShellArgs = super.getShellArgsList();
+ List shellArgs = new ArrayList();
+ List existingShellArgs = super.getShellArgsList();
if ( ( existingShellArgs != null ) && !existingShellArgs.isEmpty() )
{
@@ -122,49 +106,44 @@ protected String getExecutionPreamble()
}
String dir = getWorkingDirectoryAsString();
- StringBuffer sb = new StringBuffer();
+ StringBuilder sb = new StringBuilder();
sb.append( "cd " );
- sb.append( unifyQuotes( dir ) );
+ sb.append( quoteOneItem( dir, false ) );
sb.append( " && " );
return sb.toString();
}
- protected char[] getQuotingTriggerChars()
- {
- return BASH_QUOTING_TRIGGER_CHARS;
- }
-
/**
*
*/
- public List getCommandLine( String executable, String[] arguments )
+ public List getCommandLine( String executable, String[] arguments )
{
- StringBuffer sb = new StringBuffer();
+ StringBuilder sb = new StringBuilder();
sb.append( "\"" );
sb.append( super.getCommandLine( executable, arguments ).get( 0 ) );
sb.append( "\"" );
diff --git a/src/main/java/org/codehaus/plexus/util/cli/shell/Shell.java b/src/main/java/org/codehaus/plexus/util/cli/shell/Shell.java
index 6e264cef..14fd62d6 100644
--- a/src/main/java/org/codehaus/plexus/util/cli/shell/Shell.java
+++ b/src/main/java/org/codehaus/plexus/util/cli/shell/Shell.java
@@ -44,10 +44,12 @@ public class Shell
private String shellCommand;
- private List shellArgs = new ArrayList();
+ private List shellArgs = new ArrayList();
private boolean quotedArgumentsEnabled = true;
+ private boolean unconditionallyQuote = false;
+
private String executable;
private String workingDir;
@@ -66,6 +68,18 @@ public class Shell
private char exeQuoteDelimiter = '\"';
+ private String argumentEscapePattern = "\\%s";
+
+ /**
+ * Toggle unconditional quoting
+ *
+ * @param unconditionallyQuote
+ */
+ public void setUnconditionalQuoting(boolean unconditionallyQuote)
+ {
+ this.unconditionallyQuote = unconditionallyQuote;
+ }
+
/**
* Set the command to execute the shell (eg. COMMAND.COM, /bin/bash,...)
*
@@ -122,15 +136,28 @@ public String[] getShellArgs()
* @param arguments arguments for the executable, not the shell
* @return List with one String object with executable and arguments quoted as needed
*/
- public List getCommandLine( String executable, String[] arguments )
+ public List getCommandLine( String executable, String[] arguments )
{
return getRawCommandLine( executable, arguments );
}
- protected List getRawCommandLine( String executable, String[] arguments )
+ protected String quoteOneItem(String inputString, boolean isExecutable)
{
- List commandLine = new ArrayList();
- StringBuffer sb = new StringBuffer();
+ char[] escapeChars = getEscapeChars( isSingleQuotedExecutableEscaped(), isDoubleQuotedExecutableEscaped() );
+ return StringUtils.quoteAndEscape(
+ inputString,
+ isExecutable ? getExecutableQuoteDelimiter() : getArgumentQuoteDelimiter(),
+ escapeChars,
+ getQuotingTriggerChars(),
+ '\\',
+ unconditionallyQuote
+ );
+ }
+
+ protected List getRawCommandLine( String executable, String[] arguments )
+ {
+ List commandLine = new ArrayList();
+ StringBuilder sb = new StringBuilder();
if ( executable != null )
{
@@ -142,9 +169,7 @@ protected List getRawCommandLine( String executable, String[] arguments )
if ( isQuotedExecutableEnabled() )
{
- char[] escapeChars = getEscapeChars( isSingleQuotedExecutableEscaped(), isDoubleQuotedExecutableEscaped() );
-
- sb.append( StringUtils.quoteAndEscape( getExecutable(), getExecutableQuoteDelimiter(), escapeChars, getQuotingTriggerChars(), '\\', false ) );
+ sb.append( quoteOneItem( getOriginalExecutable(), true ) );
}
else
{
@@ -160,9 +185,7 @@ protected List getRawCommandLine( String executable, String[] arguments )
if ( isQuotedArgumentsEnabled() )
{
- char[] escapeChars = getEscapeChars( isSingleQuotedExecutableEscaped(), isDoubleQuotedExecutableEscaped() );
-
- sb.append( StringUtils.quoteAndEscape( arguments[i], getArgumentQuoteDelimiter(), escapeChars, getQuotingTriggerChars(), '\\', false ) );
+ sb.append( quoteOneItem( arguments[i], false ) );
}
else
{
@@ -187,7 +210,7 @@ protected String getExecutionPreamble()
protected char[] getEscapeChars( boolean includeSingleQuote, boolean includeDoubleQuote )
{
- StringBuffer buf = new StringBuffer( 2 );
+ StringBuilder buf = new StringBuilder( 2 );
if ( includeSingleQuote )
{
buf.append( '\'' );
@@ -244,6 +267,15 @@ protected char getExecutableQuoteDelimiter()
return exeQuoteDelimiter;
}
+ protected void setArgumentEscapePattern(String argumentEscapePattern)
+ {
+ this.argumentEscapePattern = argumentEscapePattern;
+ }
+
+ protected String getArgumentEscapePattern() {
+ return argumentEscapePattern;
+ }
+
/**
* Get the full command line to execute, including shell command, shell arguments,
* executable and executable arguments
@@ -252,10 +284,10 @@ protected char getExecutableQuoteDelimiter()
* @return List of String objects, whose array version is suitable to be used as argument
* of Runtime.getRuntime().exec()
*/
- public List getShellCommandLine( String[] arguments )
+ public List getShellCommandLine( String[] arguments )
{
- List commandLine = new ArrayList();
+ List commandLine = new ArrayList();
if ( getShellCommand() != null )
{
@@ -267,13 +299,13 @@ public List getShellCommandLine( String[] arguments )
commandLine.addAll( getShellArgsList() );
}
- commandLine.addAll( getCommandLine( getExecutable(), arguments ) );
+ commandLine.addAll( getCommandLine( getOriginalExecutable(), arguments ) );
return commandLine;
}
- public List getShellArgsList()
+ public List getShellArgsList()
{
return shellArgs;
}
@@ -371,7 +403,7 @@ public String getOriginalExecutable()
return executable;
}
- public List getOriginalCommandLine( String executable, String[] arguments )
+ public List getOriginalCommandLine( String executable, String[] arguments )
{
return getRawCommandLine( executable, arguments );
}
@@ -395,5 +427,4 @@ protected void setSingleQuotedExecutableEscaped( boolean singleQuotedExecutableE
{
this.singleQuotedExecutableEscaped = singleQuotedExecutableEscaped;
}
-
}
diff --git a/src/main/java/org/codehaus/plexus/util/dag/CycleDetectedException.java b/src/main/java/org/codehaus/plexus/util/dag/CycleDetectedException.java
index 55287d0d..76dd1883 100644
--- a/src/main/java/org/codehaus/plexus/util/dag/CycleDetectedException.java
+++ b/src/main/java/org/codehaus/plexus/util/dag/CycleDetectedException.java
@@ -22,9 +22,9 @@
public class CycleDetectedException
extends Exception
{
- private List cycle;
+ private List cycle;
- public CycleDetectedException( final String message, final List cycle )
+ public CycleDetectedException( final String message, final List cycle )
{
super( message );
@@ -32,8 +32,7 @@ public CycleDetectedException( final String message, final List cycle )
}
-
- public List getCycle()
+ public List getCycle()
{
return cycle;
}
@@ -43,9 +42,9 @@ public List getCycle()
*/
public String cycleToString()
{
- final StringBuffer buffer = new StringBuffer();
+ final StringBuilder buffer = new StringBuilder();
- for ( Iterator iterator = cycle.iterator(); iterator.hasNext(); )
+ for ( Iterator iterator = cycle.iterator(); iterator.hasNext(); )
{
buffer.append( iterator.next() );
diff --git a/src/main/java/org/codehaus/plexus/util/dag/CycleDetector.java b/src/main/java/org/codehaus/plexus/util/dag/CycleDetector.java
index 4f26c61b..ea285883 100644
--- a/src/main/java/org/codehaus/plexus/util/dag/CycleDetector.java
+++ b/src/main/java/org/codehaus/plexus/util/dag/CycleDetector.java
@@ -18,7 +18,6 @@
import java.util.Collections;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -37,18 +36,16 @@ public class CycleDetector
private final static Integer VISITED = new Integer( 2 );
- public static List hasCycle( final DAG graph )
+ public static List hasCycle( final DAG graph )
{
- final List verticies = graph.getVerticies();
+ final List verticies = graph.getVerticies();
- final Map vertexStateMap = new HashMap();
+ final Map vertexStateMap = new HashMap();
- List retValue = null;
+ List retValue = null;
- for ( final Iterator iter = verticies.iterator(); iter.hasNext(); )
+ for ( Vertex vertex : verticies )
{
- final Vertex vertex = ( Vertex ) iter.next();
-
if ( isNotVisited( vertex, vertexStateMap ) )
{
retValue = introducesCycle( vertex, vertexStateMap );
@@ -61,12 +58,10 @@ public static List hasCycle( final DAG graph )
}
return retValue;
-
}
-
/**
- * This method will be called when an egde leading to given vertex was added
+ * This method will be called when an edge leading to given vertex was added
* and we want to check if introduction of this edge has not resulted
* in apparition of cycle in the graph
*
@@ -74,9 +69,9 @@ public static List hasCycle( final DAG graph )
* @param vertexStateMap
* @return
*/
- public static List introducesCycle( final Vertex vertex, final Map vertexStateMap )
+ public static List introducesCycle( final Vertex vertex, final Map vertexStateMap )
{
- final LinkedList cycleStack = new LinkedList();
+ final LinkedList cycleStack = new LinkedList();
final boolean hasCycle = dfsVisit( vertex, cycleStack, vertexStateMap );
@@ -84,15 +79,15 @@ public static List introducesCycle( final Vertex vertex, final Map vertexStateMa
{
// we have a situation like: [b, a, c, d, b, f, g, h].
// Label of Vertex which introduced the cycle is at the first position in the list
- // We have to find second occurence of this label and use its position in the list
- // for getting the sublist of vertex labels of cycle paricipants
+ // We have to find second occurrence of this label and use its position in the list
+ // for getting the sublist of vertex labels of cycle participants
//
- // So in our case we are seraching for [b, a, c, d, b]
- final String label = ( String ) cycleStack.getFirst();
+ // So in our case we are searching for [b, a, c, d, b]
+ final String label = cycleStack.getFirst();
final int pos = cycleStack.lastIndexOf( label );
- final List cycle = cycleStack.subList( 0, pos + 1 );
+ final List cycle = cycleStack.subList( 0, pos + 1 );
Collections.reverse( cycle );
@@ -103,13 +98,11 @@ public static List introducesCycle( final Vertex vertex, final Map vertexStateMa
}
- public static List introducesCycle( final Vertex vertex )
+ public static List introducesCycle( final Vertex vertex )
{
-
- final Map vertexStateMap = new HashMap();
+ final Map vertexStateMap = new HashMap();
return introducesCycle( vertex, vertexStateMap );
-
}
/**
@@ -117,16 +110,11 @@ public static List introducesCycle( final Vertex vertex )
* @param vertexStateMap
* @return
*/
- private static boolean isNotVisited( final Vertex vertex, final Map vertexStateMap )
+ private static boolean isNotVisited( final Vertex vertex, final Map vertexStateMap )
{
- if ( !vertexStateMap.containsKey( vertex ) )
- {
- return true;
- }
+ final Integer state = vertexStateMap.get( vertex );
- final Integer state = ( Integer ) vertexStateMap.get( vertex );
-
- return NOT_VISTITED.equals( state );
+ return ( state == null ) || NOT_VISTITED.equals( state );
}
/**
@@ -134,25 +122,22 @@ private static boolean isNotVisited( final Vertex vertex, final Map vertexStateM
* @param vertexStateMap
* @return
*/
- private static boolean isVisiting( final Vertex vertex, final Map vertexStateMap )
+ private static boolean isVisiting( final Vertex vertex, final Map vertexStateMap )
{
- final Integer state = ( Integer ) vertexStateMap.get( vertex );
+ final Integer state = vertexStateMap.get( vertex );
return VISITING.equals( state );
}
- private static boolean dfsVisit( final Vertex vertex, final LinkedList cycle, final Map vertexStateMap )
+ private static boolean dfsVisit( final Vertex vertex, final LinkedList cycle,
+ final Map vertexStateMap )
{
cycle.addFirst( vertex.getLabel() );
vertexStateMap.put( vertex, VISITING );
- final List verticies = vertex.getChildren();
-
- for ( final Iterator iter = verticies.iterator(); iter.hasNext(); )
+ for ( Vertex v : vertex.getChildren() )
{
- final Vertex v = ( Vertex ) iter.next();
-
if ( isNotVisited( v, vertexStateMap ) )
{
final boolean hasCycle = dfsVisit( v, cycle, vertexStateMap );
@@ -174,9 +159,6 @@ else if ( isVisiting( v, vertexStateMap ) )
cycle.removeFirst();
return false;
-
}
-
-
}
\ No newline at end of file
diff --git a/src/main/java/org/codehaus/plexus/util/dag/DAG.java b/src/main/java/org/codehaus/plexus/util/dag/DAG.java
index 89c23b68..715f7624 100644
--- a/src/main/java/org/codehaus/plexus/util/dag/DAG.java
+++ b/src/main/java/org/codehaus/plexus/util/dag/DAG.java
@@ -28,7 +28,7 @@
*
* @author Michal Maczka
* @version $Id$
- * @todo this class should be reanmed from DAG to Dag
+ * @todo this class should be renamed from DAG to Dag
*/
public class DAG implements Cloneable, Serializable
{
@@ -36,18 +36,18 @@ public class DAG implements Cloneable, Serializable
//Fields
//------------------------------------------------------------
/**
- * Nodes will be kept in two data strucures at the same time
+ * Nodes will be kept in two data structures at the same time
* for faster processing
*/
/**
* Maps vertex's label to vertex
*/
- private Map vertexMap = new HashMap();
+ private Map vertexMap = new HashMap();
/**
* Conatin list of all verticies
*/
- private List vertexList = new ArrayList();
+ private List vertexList = new ArrayList();
// ------------------------------------------------------------
// Constructors
@@ -68,17 +68,15 @@ public DAG()
/**
* @return
*/
- public List getVerticies()
+ public List getVerticies()
{
return vertexList;
}
- public Set getLabels()
+ public Set getLabels()
{
- final Set retValue = vertexMap.keySet();
-
- return retValue;
+ return vertexMap.keySet();
}
// ------------------------------------------------------------
@@ -100,7 +98,7 @@ public Vertex addVertex( final String label )
// check if vertex is alredy in DAG
if ( vertexMap.containsKey( label ) )
{
- retValue = ( Vertex ) vertexMap.get( label );
+ retValue = vertexMap.get( label );
}
else
{
@@ -130,7 +128,7 @@ public void addEdge( final Vertex from, final Vertex to ) throws CycleDetectedEx
to.addEdgeFrom( from );
- final List cycle = CycleDetector.introducesCycle( to );
+ final List cycle = CycleDetector.introducesCycle( to );
if ( cycle != null )
{
@@ -185,7 +183,7 @@ public boolean hasEdge( final String label1, final String label2 )
* @param label
* @return
*/
- public List getChildLabels( final String label )
+ public List getChildLabels( final String label )
{
final Vertex vertex = getVertex( label );
@@ -196,7 +194,7 @@ public List getChildLabels( final String label )
* @param label
* @return
*/
- public List getParentLabels( final String label )
+ public List getParentLabels( final String label )
{
final Vertex vertex = getVertex( label );
@@ -241,16 +239,16 @@ public boolean isConnected( final String label )
* the label passed as parameter to this method. This label should
* always be the last item in the list.
*/
- public List getSuccessorLabels( final String label )
+ public List getSuccessorLabels( final String label )
{
final Vertex vertex = getVertex( label );
- final List retValue;
+ final List retValue;
//optimization.
if ( vertex.isLeaf() )
{
- retValue = new ArrayList( 1 );
+ retValue = new ArrayList( 1 );
retValue.add( label );
}
diff --git a/src/main/java/org/codehaus/plexus/util/dag/TopologicalSorter.java b/src/main/java/org/codehaus/plexus/util/dag/TopologicalSorter.java
index 4a5f30d1..6c570a50 100644
--- a/src/main/java/org/codehaus/plexus/util/dag/TopologicalSorter.java
+++ b/src/main/java/org/codehaus/plexus/util/dag/TopologicalSorter.java
@@ -17,7 +17,6 @@
*/
import java.util.HashMap;
-import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -40,37 +39,30 @@ public class TopologicalSorter
* @return List of String (vertex labels)
*/
- public static List sort( final DAG graph )
+ public static List sort( final DAG graph )
{
return dfs( graph );
}
- public static List sort( final Vertex vertex )
+ public static List sort( final Vertex vertex )
{
// we need to use addFirst method so we will use LinkedList explicitly
- final LinkedList retValue = new LinkedList();
+ final List retValue = new LinkedList();
- final Map vertexStateMap = new HashMap();
-
- dfsVisit( vertex, vertexStateMap, retValue );
+ dfsVisit( vertex, new HashMap(), retValue );
return retValue;
}
- private static List dfs( final DAG graph )
+ private static List dfs( final DAG graph )
{
- final List verticies = graph.getVerticies();
-
// we need to use addFirst method so we will use LinkedList explicitly
- final LinkedList retValue = new LinkedList();
+ final List retValue = new LinkedList();
+ final Map vertexStateMap = new HashMap();
- final Map vertexStateMap = new HashMap();
-
- for ( final Iterator iter = verticies.iterator(); iter.hasNext(); )
+ for ( Vertex vertex : graph.getVerticies() )
{
- final Vertex vertex = ( Vertex ) iter.next();
-
if ( isNotVisited( vertex, vertexStateMap ) )
{
dfsVisit( vertex, vertexStateMap, retValue );
@@ -85,28 +77,21 @@ private static List dfs( final DAG graph )
* @param vertexStateMap
* @return
*/
- private static boolean isNotVisited( final Vertex vertex, final Map vertexStateMap )
+ private static boolean isNotVisited( final Vertex vertex, final Map vertexStateMap )
{
- if ( !vertexStateMap.containsKey( vertex ) )
- {
- return true;
- }
- final Integer state = ( Integer ) vertexStateMap.get( vertex );
+ final Integer state = vertexStateMap.get( vertex );
- return NOT_VISTITED.equals( state );
+ return ( state == null ) || NOT_VISTITED.equals( state );
}
- private static void dfsVisit( final Vertex vertex, final Map vertexStateMap, final LinkedList list )
+ private static void dfsVisit( final Vertex vertex, final Map vertexStateMap,
+ final List list )
{
vertexStateMap.put( vertex, VISITING );
- final List verticies = vertex.getChildren();
-
- for ( final Iterator iter = verticies.iterator(); iter.hasNext(); )
+ for ( Vertex v : vertex.getChildren() )
{
- final Vertex v = ( Vertex ) iter.next();
-
if ( isNotVisited( v, vertexStateMap ) )
{
dfsVisit( v, vertexStateMap, list );
diff --git a/src/main/java/org/codehaus/plexus/util/dag/Vertex.java b/src/main/java/org/codehaus/plexus/util/dag/Vertex.java
index 873c430c..a9f1324b 100644
--- a/src/main/java/org/codehaus/plexus/util/dag/Vertex.java
+++ b/src/main/java/org/codehaus/plexus/util/dag/Vertex.java
@@ -18,7 +18,6 @@
import java.io.Serializable;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
/**
@@ -32,9 +31,9 @@ public class Vertex implements Cloneable, Serializable
//------------------------------------------------------------
private String label = null;
- List children = new ArrayList();
+ List children = new ArrayList();
- List parents = new ArrayList();
+ List parents = new ArrayList();
// ------------------------------------------------------------
@@ -90,13 +89,11 @@ public void addEdgeFrom( final Vertex vertex )
public void removeEdgeFrom( final Vertex vertex )
{
-
parents.remove( vertex );
-
}
- public List getChildren()
+ public List getChildren()
{
return children;
}
@@ -107,14 +104,12 @@ public List getChildren()
*
* @return the labels used by the most direct children.
*/
- public List getChildLabels()
+ public List getChildLabels()
{
- final List retValue = new ArrayList( children.size() );
+ final List retValue = new ArrayList( children.size() );
- for ( final Iterator iter = children.iterator(); iter.hasNext(); )
+ for ( Vertex vertex : children )
{
- final Vertex vertex = ( Vertex ) iter.next();
-
retValue.add( vertex.getLabel() );
}
return retValue;
@@ -126,7 +121,7 @@ public List getChildLabels()
*
* @return list of parents
*/
- public List getParents()
+ public List getParents()
{
return parents;
}
@@ -137,14 +132,12 @@ public List getParents()
*
* @return the labels used parents
*/
- public List getParentLabels()
+ public List getParentLabels()
{
- final List retValue = new ArrayList( parents.size() );
+ final List retValue = new ArrayList( parents.size() );
- for ( final Iterator iter = parents.iterator(); iter.hasNext(); )
+ for ( Vertex vertex : parents )
{
- final Vertex vertex = ( Vertex ) iter.next();
-
retValue.add( vertex.getLabel() );
}
return retValue;
diff --git a/src/main/java/org/codehaus/plexus/util/introspection/ClassMap.java b/src/main/java/org/codehaus/plexus/util/introspection/ClassMap.java
index a8b06765..1fb667c1 100644
--- a/src/main/java/org/codehaus/plexus/util/introspection/ClassMap.java
+++ b/src/main/java/org/codehaus/plexus/util/introspection/ClassMap.java
@@ -23,7 +23,7 @@
/**
* A cache of introspection information for a specific class instance.
- * Keys {@link java.lang.Method} objects by a concatenation of the
+ * Keys {@link java.lang.reflect.Method} objects by a concatenation of the
* method name and the names of classes that make up the parameters.
*
* @author Jason van Zyl
@@ -46,7 +46,7 @@ private static final class CacheMiss
* the basis for the Method map.
*/
- private Class clazz;
+ private final Class clazz;
/**
* Cache of Methods, or CACHE_MISS, keyed by method
@@ -187,9 +187,9 @@ private String makeMethodKey( Method method )
{
Class[] parameterTypes = method.getParameterTypes();
- StringBuffer methodKey = new StringBuffer( method.getName() );
+ StringBuilder methodKey = new StringBuilder( method.getName() );
- for ( int j = 0; j < parameterTypes.length; j++ )
+ for ( Class parameterType : parameterTypes )
{
/*
* If the argument type is primitive then we want
@@ -197,28 +197,44 @@ private String makeMethodKey( Method method )
* corresponding Object type so introspection for
* methods with primitive types will work correctly.
*/
- if ( parameterTypes[j].isPrimitive() )
+ if ( parameterType.isPrimitive() )
{
- if ( parameterTypes[j].equals( Boolean.TYPE ) )
+ if ( parameterType.equals( Boolean.TYPE ) )
+ {
methodKey.append( "java.lang.Boolean" );
- else if ( parameterTypes[j].equals( Byte.TYPE ) )
+ }
+ else if ( parameterType.equals( Byte.TYPE ) )
+ {
methodKey.append( "java.lang.Byte" );
- else if ( parameterTypes[j].equals( Character.TYPE ) )
+ }
+ else if ( parameterType.equals( Character.TYPE ) )
+ {
methodKey.append( "java.lang.Character" );
- else if ( parameterTypes[j].equals( Double.TYPE ) )
+ }
+ else if ( parameterType.equals( Double.TYPE ) )
+ {
methodKey.append( "java.lang.Double" );
- else if ( parameterTypes[j].equals( Float.TYPE ) )
+ }
+ else if ( parameterType.equals( Float.TYPE ) )
+ {
methodKey.append( "java.lang.Float" );
- else if ( parameterTypes[j].equals( Integer.TYPE ) )
+ }
+ else if ( parameterType.equals( Integer.TYPE ) )
+ {
methodKey.append( "java.lang.Integer" );
- else if ( parameterTypes[j].equals( Long.TYPE ) )
+ }
+ else if ( parameterType.equals( Long.TYPE ) )
+ {
methodKey.append( "java.lang.Long" );
- else if ( parameterTypes[j].equals( Short.TYPE ) )
+ }
+ else if ( parameterType.equals( Short.TYPE ) )
+ {
methodKey.append( "java.lang.Short" );
+ }
}
else
{
- methodKey.append( parameterTypes[j].getName() );
+ methodKey.append( parameterType.getName() );
}
}
@@ -227,11 +243,11 @@ else if ( parameterTypes[j].equals( Short.TYPE ) )
private static String makeMethodKey( String method, Object[] params )
{
- StringBuffer methodKey = new StringBuffer().append( method );
+ StringBuilder methodKey = new StringBuilder().append( method );
- for ( int j = 0; j < params.length; j++ )
+ for ( Object param : params )
{
- Object arg = params[j];
+ Object arg = param;
if ( arg == null )
{
@@ -287,9 +303,8 @@ private static Method[] getAccessibleMethods( Class clazz )
}
int j = 0;
- for ( int i = 0; i < methodInfos.length; ++i )
+ for ( MethodInfo methodInfo : methodInfos )
{
- MethodInfo methodInfo = methodInfos[i];
if ( methodInfo.upcast )
{
methods[j++] = methodInfo.method;
@@ -426,7 +441,7 @@ public static Method getPublicMethod( Method method )
* Looks up the method with specified name and signature in the first public
* superclass or implemented interface of the class.
*
- * @param class the class whose method is sought
+ * @param clazz the class whose method is sought
* @param name the name of the method
* @param paramTypes the classes of method parameters
*/
diff --git a/src/main/java/org/codehaus/plexus/util/introspection/MethodMap.java b/src/main/java/org/codehaus/plexus/util/introspection/MethodMap.java
index bf733097..1b6a27e5 100644
--- a/src/main/java/org/codehaus/plexus/util/introspection/MethodMap.java
+++ b/src/main/java/org/codehaus/plexus/util/introspection/MethodMap.java
@@ -42,28 +42,27 @@ public class MethodMap
/**
* Keep track of all methods with the same name.
*/
- Map methodByNameMap = new Hashtable();
+ Map> methodByNameMap = new Hashtable>();
/**
* Add a method to a list of methods by name.
* For a particular class we are keeping track
* of all the methods with the same name.
+ * @param method The method
*/
public void add(Method method)
{
String methodName = method.getName();
- List l = get( methodName );
+ List l = get( methodName );
if ( l == null)
{
- l = new ArrayList();
+ l = new ArrayList();
methodByNameMap.put(methodName, l);
}
l.add(method);
-
- return;
}
/**
@@ -72,9 +71,9 @@ public void add(Method method)
* @param key The name of the method.
* @return List list of methods
*/
- public List get(String key)
+ public List get(String key)
{
- return (List) methodByNameMap.get(key);
+ return methodByNameMap.get(key);
}
/**
@@ -145,7 +144,7 @@ public static class AmbiguousException extends Exception
private static Method getMostSpecific(List methods, Class[] classes)
throws AmbiguousException
{
- LinkedList applicables = getApplicables(methods, classes);
+ LinkedList applicables = getApplicables(methods, classes);
if(applicables.isEmpty())
{
@@ -154,7 +153,7 @@ private static Method getMostSpecific(List methods, Class[] classes)
if(applicables.size() == 1)
{
- return (Method)applicables.getFirst();
+ return applicables.getFirst();
}
/*
@@ -163,21 +162,18 @@ private static Method getMostSpecific(List methods, Class[] classes)
* (the most specific method) otherwise we have ambiguity.
*/
- LinkedList maximals = new LinkedList();
+ LinkedList maximals = new LinkedList();
- for (Iterator applicable = applicables.iterator();
- applicable.hasNext();)
+ for ( Method app : applicables )
{
- Method app = (Method) applicable.next();
Class[] appArgs = app.getParameterTypes();
boolean lessSpecific = false;
- for (Iterator maximal = maximals.iterator();
- !lessSpecific && maximal.hasNext();)
+ for ( Iterator maximal = maximals.iterator(); !lessSpecific && maximal.hasNext(); )
{
Method max = (Method) maximal.next();
- switch(moreSpecific(appArgs, max.getParameterTypes()))
+ switch ( moreSpecific( appArgs, max.getParameterTypes() ) )
{
case MORE_SPECIFIC:
{
@@ -205,9 +201,9 @@ private static Method getMostSpecific(List methods, Class[] classes)
}
}
- if(!lessSpecific)
+ if ( !lessSpecific )
{
- maximals.addLast(app);
+ maximals.addLast( app );
}
}
@@ -217,7 +213,7 @@ private static Method getMostSpecific(List methods, Class[] classes)
throw new AmbiguousException();
}
- return (Method)maximals.getFirst();
+ return maximals.getFirst();
}
/**
@@ -282,17 +278,17 @@ private static int moreSpecific(Class[] c1, Class[] c2)
* formal and actual arguments matches, and argument types are assignable
* to formal types through a method invocation conversion).
*/
- private static LinkedList getApplicables(List methods, Class[] classes)
+ private static LinkedList getApplicables(List methods, Class[] classes)
{
- LinkedList list = new LinkedList();
+ LinkedList list = new LinkedList();
- for (Iterator imethod = methods.iterator(); imethod.hasNext();)
+ for ( Object method1 : methods )
{
- Method method = (Method) imethod.next();
+ Method method = (Method) method1;
- if(isApplicable(method, classes))
+ if ( isApplicable( method, classes ) )
{
- list.add(method);
+ list.add( method );
}
}
@@ -302,6 +298,9 @@ private static LinkedList getApplicables(List methods, Class[] classes)
/**
* Returns true if the supplied method is applicable to actual
* argument types.
+ * @param method The method to check for applicability
+ * @param classes The arguments
+ * @return true if the method applies to the parameter types
*/
private static boolean isApplicable(Method method, Class[] classes)
{
diff --git a/src/main/java/org/codehaus/plexus/util/introspection/ReflectionValueExtractor.java b/src/main/java/org/codehaus/plexus/util/introspection/ReflectionValueExtractor.java
index 2be103b5..53a124f2 100644
--- a/src/main/java/org/codehaus/plexus/util/introspection/ReflectionValueExtractor.java
+++ b/src/main/java/org/codehaus/plexus/util/introspection/ReflectionValueExtractor.java
@@ -16,66 +16,142 @@
* limitations under the License.
*/
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.util.Arrays;
import java.util.List;
-import java.util.WeakHashMap;
import java.util.Map;
-import java.util.StringTokenizer;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import java.util.WeakHashMap;
import org.codehaus.plexus.util.StringUtils;
/**
- *
Using simple dotted expressions to extract the values from an Object instance,
- * For example we might want to extract a value like: project.build.sourceDirectory
- *
- *
The implementation supports indexed, nested and mapped properties similar to the JSP way.
- *
+ *
+ * Using simple dotted expressions to extract the values from an Object instance, For example we might want to extract a
+ * value like: project.build.sourceDirectory
+ *
+ *
+ * The implementation supports indexed, nested and mapped properties similar to the JSP way.
+ *
+ *
* @author Jason van Zyl
* @author Vincent Siveton
* @version $Id$
- * @see http://struts.apache.org/1.x/struts-taglib/indexedprops.html
+ * @see http://struts.apache.org/1.x/struts-taglib/indexedprops.html
*/
public class ReflectionValueExtractor
{
- private static final Class[] CLASS_ARGS = new Class[0];
+ private static final Class>[] CLASS_ARGS = new Class[0];
private static final Object[] OBJECT_ARGS = new Object[0];
/**
- * Use a WeakHashMap here, so the keys (Class objects) can be garbage collected.
- * This approach prevents permgen space overflows due to retention of discarded
- * classloaders.
+ * Use a WeakHashMap here, so the keys (Class objects) can be garbage collected. This approach prevents permgen
+ * space overflows due to retention of discarded classloaders.
*/
- private static final Map classMaps = new WeakHashMap();
+ private static final Map, WeakReference> classMaps =
+ new WeakHashMap, WeakReference>();
- /**
- * Indexed properties pattern, ie (\\w+)\\[(\\d+)\\]
- */
- private static final Pattern INDEXED_PROPS = Pattern.compile( "(\\w+)\\[(\\d+)\\]" );
+ static final int EOF = -1;
- /**
- * Indexed properties pattern, ie (\\w+)\\((.+)\\)
- */
- private static final Pattern MAPPED_PROPS = Pattern.compile( "(\\w+)\\((.+)\\)" );
+ static final char PROPERTY_START = '.';
+
+ static final char INDEXED_START = '[';
+
+ static final char INDEXED_END = ']';
+
+ static final char MAPPED_START = '(';
+
+ static final char MAPPED_END = ')';
+
+ static class Tokenizer
+ {
+ final String expression;
+
+ int idx;
+
+ public Tokenizer( String expression )
+ {
+ this.expression = expression;
+ }
+
+ public int peekChar()
+ {
+ return idx < expression.length() ? expression.charAt( idx ) : EOF;
+ }
+
+ public int skipChar()
+ {
+ return idx < expression.length() ? expression.charAt( idx++ ) : EOF;
+ }
+
+ public String nextToken( char delimiter )
+ {
+ int start = idx;
+
+ while ( idx < expression.length() && delimiter != expression.charAt( idx ) )
+ {
+ idx++;
+ }
+
+ // delimiter MUST be present
+ if ( idx <= start || idx >= expression.length() )
+ {
+ return null;
+ }
+
+ return expression.substring( start, idx++ );
+ }
+
+ public String nextPropertyName()
+ {
+ final int start = idx;
+
+ while ( idx < expression.length() && Character.isJavaIdentifierPart( expression.charAt( idx ) ) )
+ {
+ idx++;
+ }
+
+ // property name does not require delimiter
+ if ( idx <= start || idx > expression.length() )
+ {
+ return null;
+ }
+
+ return expression.substring( start, idx );
+ }
+
+ public int getPosition()
+ {
+ return idx < expression.length() ? idx : EOF;
+ }
+
+ // to make tokenizer look pretty in debugger
+ @Override
+ public String toString()
+ {
+ return idx < expression.length() ? expression.substring( idx ) : "";
+ }
+ }
private ReflectionValueExtractor()
{
}
/**
- *
The implementation supports indexed, nested and mapped properties.
- *
+ *
+ * The implementation supports indexed, nested and mapped properties.
+ *
*
*
nested properties should be defined by a dot, i.e. "user.address.street"
*
indexed properties (java.util.List or array instance) should be contains (\\w+)\\[(\\d+)\\]
* pattern, i.e. "user.addresses[1].street"
- *
mapped properties should be contains (\\w+)\\((.+)\\) pattern, i.e. "user.addresses(myAddress).street"
+ *
mapped properties should be contains (\\w+)\\((.+)\\) pattern, i.e.
+ * "user.addresses(myAddress).street"
*
- *
+ *
* @param expression not null expression
* @param root not null object
* @return the object defined by the expression
@@ -88,30 +164,26 @@ public static Object evaluate( String expression, Object root )
}
/**
- *
The implementation supports indexed, nested and mapped properties.
- *
+ *
+ * The implementation supports indexed, nested and mapped properties.
+ *
*
*
nested properties should be defined by a dot, i.e. "user.address.street"
*
indexed properties (java.util.List or array instance) should be contains (\\w+)\\[(\\d+)\\]
* pattern, i.e. "user.addresses[1].street"
- *
mapped properties should be contains (\\w+)\\((.+)\\) pattern, i.e. "user.addresses(myAddress).street"
+ *
mapped properties should be contains (\\w+)\\((.+)\\) pattern, i.e.
+ * "user.addresses(myAddress).street"
*
- *
+ *
* @param expression not null expression
* @param root not null object
* @return the object defined by the expression
* @throws Exception if any
*/
// TODO: don't throw Exception
- public static Object evaluate( String expression, Object root, boolean trimRootToken )
+ public static Object evaluate( final String expression, final Object root, final boolean trimRootToken )
throws Exception
{
- // if the root token refers to the supplied root object parameter, remove it.
- if ( trimRootToken )
- {
- expression = expression.substring( expression.indexOf( '.' ) + 1 );
- }
-
Object value = root;
// ----------------------------------------------------------------------
@@ -119,128 +191,166 @@ public static Object evaluate( String expression, Object root, boolean trimRootT
// MavenProject instance.
// ----------------------------------------------------------------------
- StringTokenizer parser = new StringTokenizer( expression, "." );
+ if ( StringUtils.isEmpty( expression ) || !Character.isJavaIdentifierStart( expression.charAt( 0 ) ) )
+ {
+ return null;
+ }
+
+ final Tokenizer tokenizer;
+ if ( trimRootToken )
+ {
+ tokenizer = new Tokenizer( expression );
+ tokenizer.nextPropertyName();
+ }
+ else
+ {
+ tokenizer = new Tokenizer( "." + expression );
+ }
- while ( parser.hasMoreTokens() )
+ int propertyPosition = tokenizer.getPosition();
+ while ( value != null && tokenizer.peekChar() != EOF )
{
- // if we have nothing, stop now
- if ( value == null )
+ switch ( tokenizer.skipChar() )
{
- return null;
+ case INDEXED_START:
+ value =
+ getIndexedValue( expression, propertyPosition, tokenizer.getPosition(), value,
+ tokenizer.nextToken( INDEXED_END ) );
+ break;
+ case MAPPED_START:
+ value =
+ getMappedValue( expression, propertyPosition, tokenizer.getPosition(), value,
+ tokenizer.nextToken( MAPPED_END ) );
+ break;
+ case PROPERTY_START:
+ propertyPosition = tokenizer.getPosition();
+ value = getPropertyValue( value, tokenizer.nextPropertyName() );
+ break;
+ default:
+ // could not parse expression
+ return null;
}
+ }
- String token = parser.nextToken();
+ return value;
+ }
+ private static Object getMappedValue( final String expression, final int from, final int to, final Object value,
+ final String key )
+ throws Exception
+ {
+ if ( value == null || key == null )
+ {
+ return null;
+ }
+
+ if ( value instanceof Map )
+ {
+ Object[] localParams = new Object[] { key };
ClassMap classMap = getClassMap( value.getClass() );
+ Method method = classMap.findMethod( "get", localParams );
+ return method.invoke( value, localParams );
+ }
+
+ final String message =
+ String.format( "The token '%s' at position '%d' refers to a java.util.Map, but the value seems is an instance of '%s'",
+ expression.subSequence( from, to ), from, value.getClass() );
+
+ throw new Exception( message );
+ }
- Method method;
- Object[] localParams = OBJECT_ARGS;
+ private static Object getIndexedValue( final String expression, final int from, final int to, final Object value,
+ final String indexStr )
+ throws Exception
+ {
+ try
+ {
+ int index = Integer.parseInt( indexStr );
- // do we have an indexed property?
- Matcher matcher = INDEXED_PROPS.matcher( token );
- if ( matcher.find() )
+ if ( value.getClass().isArray() )
{
- String methodBase = StringUtils.capitalizeFirstLetter( matcher.group( 1 ) );
- String methodName = "get" + methodBase;
- method = classMap.findMethod( methodName, CLASS_ARGS );
- value = method.invoke( value, OBJECT_ARGS );
- classMap = getClassMap( value.getClass() );
-
- if ( classMap.getCachedClass().isArray() )
- {
- value = Arrays.asList( (Object[]) value );
- classMap = getClassMap( value.getClass() );
- }
-
- if ( value instanceof List )
- {
- // use get method on List interface
- localParams = new Object[1];
- localParams[0] = Integer.valueOf( matcher.group( 2 ) );
- method = classMap.findMethod( "get", localParams );
- }
- else
- {
- throw new Exception( "The token '" + token
- + "' refers to a java.util.List or an array, but the value seems is an instance of '"
- + value.getClass() + "'." );
- }
+ return Array.get( value, index );
}
- else
+
+ if ( value instanceof List )
{
- // do we have a mapped property?
- matcher = MAPPED_PROPS.matcher( token );
- if ( matcher.find() )
- {
- String methodBase = StringUtils.capitalizeFirstLetter( matcher.group( 1 ) );
- String methodName = "get" + methodBase;
- method = classMap.findMethod( methodName, CLASS_ARGS );
- value = method.invoke( value, OBJECT_ARGS );
- classMap = getClassMap( value.getClass() );
-
- if ( value instanceof Map )
- {
- // use get method on List interface
- localParams = new Object[1];
- localParams[0] = matcher.group( 2 );
- method = classMap.findMethod( "get", localParams );
- }
- else
- {
- throw new Exception( "The token '" + token
- + "' refers to a java.util.Map, but the value seems is an instance of '"
- + value.getClass() + "'." );
- }
- }
- else
- {
- String methodBase = StringUtils.capitalizeFirstLetter( token );
- String methodName = "get" + methodBase;
- method = classMap.findMethod( methodName, CLASS_ARGS );
-
- if ( method == null )
- {
- // perhaps this is a boolean property??
- methodName = "is" + methodBase;
-
- method = classMap.findMethod( methodName, CLASS_ARGS );
- }
- }
+ ClassMap classMap = getClassMap( value.getClass() );
+ // use get method on List interface
+ Object[] localParams = new Object[] { index };
+ Method method = classMap.findMethod( "get", localParams );
+ return method.invoke( value, localParams );
}
-
- if ( method == null )
+ }
+ catch ( NumberFormatException e )
+ {
+ return null;
+ }
+ catch ( InvocationTargetException e )
+ {
+ // catch array index issues gracefully, otherwise release
+ if ( e.getCause() instanceof IndexOutOfBoundsException )
{
return null;
}
- try
- {
- value = method.invoke( value, localParams );
- }
- catch ( InvocationTargetException e )
- {
- // catch array index issues gracefully, otherwise release
- if ( e.getCause() instanceof IndexOutOfBoundsException )
- {
- return null;
- }
+ throw e;
+ }
- throw e;
- }
+ final String message =
+ String.format( "The token '%s' at position '%d' refers to a java.util.List or an array, but the value seems is an instance of '%s'",
+ expression.subSequence( from, to ), from, value.getClass() );
+
+ throw new Exception( message );
+ }
+
+ private static Object getPropertyValue( Object value, String property )
+ throws Exception
+ {
+ if ( value == null || property == null )
+ {
+ return null;
}
- return value;
+ ClassMap classMap = getClassMap( value.getClass() );
+ String methodBase = StringUtils.capitalizeFirstLetter( property );
+ String methodName = "get" + methodBase;
+ Method method = classMap.findMethod( methodName, CLASS_ARGS );
+
+ if ( method == null )
+ {
+ // perhaps this is a boolean property??
+ methodName = "is" + methodBase;
+
+ method = classMap.findMethod( methodName, CLASS_ARGS );
+ }
+
+ if ( method == null )
+ {
+ return null;
+ }
+
+ try
+ {
+ return method.invoke( value, OBJECT_ARGS );
+ }
+ catch ( InvocationTargetException e )
+ {
+ throw e;
+ }
}
- private static ClassMap getClassMap( Class clazz )
+ private static ClassMap getClassMap( Class> clazz )
{
- ClassMap classMap = (ClassMap) classMaps.get( clazz );
- if ( classMap == null )
+ WeakReference softRef = classMaps.get( clazz );
+
+ ClassMap classMap;
+
+ if ( softRef == null || ( classMap = softRef.get() ) == null )
{
classMap = new ClassMap( clazz );
- classMaps.put( clazz, classMap );
+ classMaps.put( clazz, new WeakReference( classMap ) );
}
return classMap;
diff --git a/src/main/java/org/codehaus/plexus/util/io/RawInputStreamFacade.java b/src/main/java/org/codehaus/plexus/util/io/RawInputStreamFacade.java
index 008ce6ac..c982b8fb 100644
--- a/src/main/java/org/codehaus/plexus/util/io/RawInputStreamFacade.java
+++ b/src/main/java/org/codehaus/plexus/util/io/RawInputStreamFacade.java
@@ -22,12 +22,10 @@
/**
* Implementation of {@link InputStreamFacade} for raw input streams.
*/
+@SuppressWarnings( { "UnusedDeclaration" } )
public class RawInputStreamFacade implements InputStreamFacade {
final InputStream stream;
- /**
- * Creates a new instance.
- */
public RawInputStreamFacade( InputStream stream )
{
this.stream = stream;
diff --git a/src/main/java/org/codehaus/plexus/util/io/URLInputStreamFacade.java b/src/main/java/org/codehaus/plexus/util/io/URLInputStreamFacade.java
index bd09669b..9bd53d9f 100644
--- a/src/main/java/org/codehaus/plexus/util/io/URLInputStreamFacade.java
+++ b/src/main/java/org/codehaus/plexus/util/io/URLInputStreamFacade.java
@@ -26,9 +26,6 @@
public class URLInputStreamFacade implements InputStreamFacade {
private final URL url;
- /**
- * Creates a new instance.
- */
public URLInputStreamFacade( URL url )
{
this.url = url;
diff --git a/src/main/java/org/codehaus/plexus/util/reflection/Reflector.java b/src/main/java/org/codehaus/plexus/util/reflection/Reflector.java
index 1655803b..199c876a 100644
--- a/src/main/java/org/codehaus/plexus/util/reflection/Reflector.java
+++ b/src/main/java/org/codehaus/plexus/util/reflection/Reflector.java
@@ -56,7 +56,8 @@ public Reflector()
* @throws ReflectorException
* In case anything goes wrong here...
*/
- public Object newInstance( Class theClass, Object[] params )
+ @SuppressWarnings( { "UnusedDeclaration" } )
+ public T newInstance( Class theClass, Object[] params )
throws ReflectorException
{
if ( params == null )
@@ -73,19 +74,19 @@ public Object newInstance( Class theClass, Object[] params )
try
{
- Constructor con = getConstructor( theClass, paramTypes );
+ Constructor con = getConstructor( theClass, paramTypes );
if ( con == null )
{
- StringBuffer buffer = new StringBuffer();
+ StringBuilder buffer = new StringBuilder();
buffer.append( "Constructor not found for class: " );
buffer.append( theClass.getName() );
buffer.append( " with specified or ancestor parameter classes: " );
- for ( int i = 0; i < paramTypes.length; i++ )
+ for ( Class paramType : paramTypes )
{
- buffer.append( paramTypes[i].getName() );
+ buffer.append( paramType.getName() );
buffer.append( ',' );
}
@@ -123,7 +124,8 @@ public Object newInstance( Class theClass, Object[] params )
* @throws ReflectorException
* In case anything goes wrong here...
*/
- public Object getSingleton( Class theClass, Object[] initParams )
+ @SuppressWarnings( { "UnusedDeclaration" } )
+ public T getSingleton( Class theClass, Object[] initParams )
throws ReflectorException
{
Class[] paramTypes = new Class[initParams.length];
@@ -137,7 +139,8 @@ public Object getSingleton( Class theClass, Object[] initParams )
{
Method method = getMethod( theClass, GET_INSTANCE_METHOD_NAME, paramTypes );
- return method.invoke( null, initParams );
+ //noinspection unchecked
+ return (T) method.invoke( null, initParams );
}
catch ( InvocationTargetException ex )
{
@@ -163,6 +166,7 @@ public Object getSingleton( Class theClass, Object[] initParams )
* @throws ReflectorException
* In case of an error looking up or invoking the method.
*/
+ @SuppressWarnings( { "UnusedDeclaration" } )
public Object invoke( Object target, String methodName, Object[] params )
throws ReflectorException
{
@@ -184,14 +188,14 @@ public Object invoke( Object target, String methodName, Object[] params )
if ( method == null )
{
- StringBuffer buffer = new StringBuffer();
+ StringBuilder buffer = new StringBuilder();
buffer.append( "Singleton-producing method named '" ).append( methodName )
.append( "' not found with specified parameter classes: " );
- for ( int i = 0; i < paramTypes.length; i++ )
+ for ( Class paramType : paramTypes )
{
- buffer.append( paramTypes[i].getName() );
+ buffer.append( paramType.getName() );
buffer.append( ',' );
}
@@ -212,6 +216,7 @@ public Object invoke( Object target, String methodName, Object[] params )
}
}
+ @SuppressWarnings( { "UnusedDeclaration" } )
public Object getStaticField( Class targetClass, String fieldName )
throws ReflectorException
{
@@ -239,6 +244,7 @@ public Object getStaticField( Class targetClass, String fieldName )
}
}
+ @SuppressWarnings( { "UnusedDeclaration" } )
public Object getField( Object target, String fieldName )
throws ReflectorException
{
@@ -303,6 +309,7 @@ public Object getField( Object target, String fieldName, boolean breakAccessibil
* @throws ReflectorException
* In case of an error looking up or invoking the method.
*/
+ @SuppressWarnings( { "UnusedDeclaration" } )
public Object invokeStatic( Class targetClass, String methodName, Object[] params )
throws ReflectorException
{
@@ -324,14 +331,15 @@ public Object invokeStatic( Class targetClass, String methodName, Object[] param
if ( method == null )
{
- StringBuffer buffer = new StringBuffer();
+ StringBuilder buffer = new StringBuilder();
- buffer.append( "Singleton-producing method named \'" + methodName
- + "\' not found with specified parameter classes: " );
+ buffer.append( "Singleton-producing method named \'" )
+ .append( methodName )
+ .append( "\' not found with specified parameter classes: " );
- for ( int i = 0; i < paramTypes.length; i++ )
+ for ( Class paramType : paramTypes )
{
- buffer.append( paramTypes[i].getName() );
+ buffer.append( paramType.getName() );
buffer.append( ',' );
}
@@ -365,12 +373,12 @@ public Object invokeStatic( Class targetClass, String methodName, Object[] param
* @throws ReflectorException
* In case we can't retrieve the proper constructor.
*/
- public Constructor getConstructor( Class targetClass, Class[] params )
+ public Constructor getConstructor( Class targetClass, Class[] params )
throws ReflectorException
{
- Map constructorMap = getConstructorMap( targetClass );
+ Map> constructorMap = getConstructorMap( targetClass );
- StringBuffer key = new StringBuffer( 200 );
+ StringBuilder key = new StringBuilder( 200 );
key.append( "(" );
@@ -387,17 +395,18 @@ public Constructor getConstructor( Class targetClass, Class[] params )
key.append( ")" );
- Constructor constructor = null;
+ Constructor constructor;
String paramKey = key.toString();
synchronized ( paramKey.intern() )
{
- constructor = (Constructor) constructorMap.get( paramKey );
+ constructor = constructorMap.get( paramKey );
if ( constructor == null )
{
- Constructor[] cands = targetClass.getConstructors();
+ @SuppressWarnings( { "unchecked" } )
+ Constructor[] cands = (Constructor[]) targetClass.getConstructors();
for ( int i = 0, len = cands.length; i < len; i++ )
{
@@ -435,7 +444,7 @@ public Constructor getConstructor( Class targetClass, Class[] params )
public Object getObjectProperty( Object target, String propertyName )
throws ReflectorException
{
- Object returnValue = null;
+ Object returnValue;
if ( propertyName == null || propertyName.trim().length() < 1 )
{
@@ -494,7 +503,7 @@ public Object getObjectProperty( Object target, String propertyName )
else
{
returnValue = getField( target, propertyName, true );
- if ( method == null && returnValue == null )
+ if ( returnValue == null )
{
// TODO: Check if exception is the right action! Field exists, but contains null
throw new ReflectorException( "Neither method: \'" + propertyName + "\' nor bean accessor: \'"
@@ -535,9 +544,9 @@ public Method getMethod( Class targetClass, String methodName, Class[] params )
private Method _getMethod( Class targetClass, String methodName, Class[] params )
throws ReflectorException
{
- Map methodMap = getMethodMap( targetClass, methodName );
+ Map methodMap = (Map) getMethodMap( targetClass, methodName );
- StringBuffer key = new StringBuffer( 200 );
+ StringBuilder key = new StringBuilder( 200 );
key.append( "(" );
@@ -549,7 +558,7 @@ private Method _getMethod( Class targetClass, String methodName, Class[] params
key.append( ")" );
- Method method = null;
+ Method method;
String paramKey = key.toString();
@@ -604,10 +613,10 @@ private Method _getMethod( Class targetClass, String methodName, Class[] params
* @throws ReflectorException
* in case of a lookup error.
*/
- private Map getConstructorMap( Class theClass )
+ private Map> getConstructorMap( Class theClass )
throws ReflectorException
{
- return getMethodMap( theClass, CONSTRUCTOR_METHOD_NAME );
+ return (Map>) getMethodMap( theClass, CONSTRUCTOR_METHOD_NAME );
}
/**
@@ -621,10 +630,10 @@ private Map getConstructorMap( Class theClass )
* @throws ReflectorException
* in case of a lookup error.
*/
- private Map getMethodMap( Class theClass, String methodName )
+ private Map getMethodMap( Class theClass, String methodName )
throws ReflectorException
{
- Map methodMap = null;
+ Map methodMap;
if ( theClass == null )
{
@@ -635,14 +644,13 @@ private Map getMethodMap( Class theClass, String methodName )
synchronized ( className.intern() )
{
- Map classMethods = (Map) classMaps.get( className );
+ Map> classMethods = (Map>) classMaps.get( className );
if ( classMethods == null )
{
classMethods = new HashMap();
- methodMap = new HashMap();
+ methodMap = new HashMap();
classMethods.put( methodName, methodMap );
-
classMaps.put( className, classMethods );
}
else
@@ -651,11 +659,11 @@ private Map getMethodMap( Class theClass, String methodName )
synchronized ( key.intern() )
{
- methodMap = (Map) classMethods.get( methodName );
+ methodMap = classMethods.get( methodName );
if ( methodMap == null )
{
- methodMap = new HashMap();
+ methodMap = new HashMap();
classMethods.put( methodName, methodMap );
}
}
diff --git a/src/main/java/org/codehaus/plexus/util/reflection/ReflectorException.java b/src/main/java/org/codehaus/plexus/util/reflection/ReflectorException.java
index de564e2f..567b060c 100644
--- a/src/main/java/org/codehaus/plexus/util/reflection/ReflectorException.java
+++ b/src/main/java/org/codehaus/plexus/util/reflection/ReflectorException.java
@@ -26,9 +26,7 @@
public class ReflectorException
extends Exception
{
- /**
- * Create a new ReflectorException.
- */
+ @SuppressWarnings( { "UnusedDeclaration" } )
public ReflectorException()
{
}
diff --git a/src/main/java/org/codehaus/plexus/util/xml/PrettyPrintXMLWriter.java b/src/main/java/org/codehaus/plexus/util/xml/PrettyPrintXMLWriter.java
index ce8b3526..fae43373 100644
--- a/src/main/java/org/codehaus/plexus/util/xml/PrettyPrintXMLWriter.java
+++ b/src/main/java/org/codehaus/plexus/util/xml/PrettyPrintXMLWriter.java
@@ -206,30 +206,51 @@ private void writeText( String text, boolean escapeXml )
write( StringUtils.unifyLineSeparators( text, lineSeparator ) );
}
+ private static final Pattern amp = Pattern.compile( "&" );
+ private static final Pattern lt = Pattern.compile( "<" );
+ private static final Pattern gt = Pattern.compile( ">" );
+ private static final Pattern dqoute = Pattern.compile( "\"" );
+ private static final Pattern sqoute = Pattern.compile( "\'" );
+
private static String escapeXml( String text )
{
- text = text.replaceAll( "&", "&" );
-
- text = text.replaceAll( "<", "<" );
+ if (text.indexOf('&') >= 0){
+ text = amp.matcher( text ).replaceAll( "&" );
+ }
+ if (text.indexOf('<') >= 0){
+ text = lt.matcher( text ).replaceAll( "<" );
+ }
+ if (text.indexOf('>') >= 0){
+ text = gt.matcher( text ).replaceAll( ">" );
+ }
+ if (text.indexOf('"') >= 0){
+ text = dqoute.matcher( text ).replaceAll( """ );
+ }
+ if (text.indexOf('\'') >= 0){
+ text = sqoute.matcher( text ).replaceAll( "'" );
+ }
- text = text.replaceAll( ">", ">" );
+ return text;
+ }
- text = text.replaceAll( "\"", """ );
+ private static final String crlf_str = "\r\n";
- text = text.replaceAll( "\'", "'" );
+ private static final Pattern crlf = Pattern.compile( crlf_str );
+ private static final Pattern lowers = Pattern.compile( "([\000-\037])" );
- return text;
- }
private static String escapeXmlAttribute( String text )
{
text = escapeXml( text );
// Windows
- text = text.replaceAll( "\r\n", "
" );
+ Matcher crlfmatcher = crlf.matcher( text );
+ if (text.contains( crlf_str ))
+ {
+ text = crlfmatcher.replaceAll( "
" );
+ }
- Pattern pattern = Pattern.compile( "([\000-\037])" );
- Matcher m = pattern.matcher( text );
+ Matcher m = lowers.matcher( text );
StringBuffer b = new StringBuffer();
while ( m.find() )
{
diff --git a/src/main/java/org/codehaus/plexus/util/xml/XmlReader.java b/src/main/java/org/codehaus/plexus/util/xml/XmlReader.java
index 7f15c96e..b489e219 100644
--- a/src/main/java/org/codehaus/plexus/util/xml/XmlReader.java
+++ b/src/main/java/org/codehaus/plexus/util/xml/XmlReader.java
@@ -732,7 +732,7 @@ private static String getXmlProlog( BufferedInputStream is, String guessedEnc )
{
is.reset();
BufferedReader bReader = new BufferedReader( new StringReader( xmlProlog.substring( 0, firstGT + 1 ) ) );
- StringBuffer prolog = new StringBuffer();
+ StringBuilder prolog = new StringBuilder();
String line = bReader.readLine();
while ( line != null )
{
diff --git a/src/main/java/org/codehaus/plexus/util/xml/XmlWriterUtil.java b/src/main/java/org/codehaus/plexus/util/xml/XmlWriterUtil.java
index c1a90c7a..913b5f27 100644
--- a/src/main/java/org/codehaus/plexus/util/xml/XmlWriterUtil.java
+++ b/src/main/java/org/codehaus/plexus/util/xml/XmlWriterUtil.java
@@ -206,17 +206,16 @@ public static void writeComment( XMLWriter writer, String comment, int indent, i
String[] sentences = StringUtils.split( comment, LS );
StringBuffer line = new StringBuffer( indentation + "
+
+
+
+
+
+
+
+ Facades to create {@code InputStream}s representing various kinds of
+ data sources, identically.
+
+
diff --git a/src/main/javadoc/org/codehaus/plexus/util/package.html b/src/main/javadoc/org/codehaus/plexus/util/package.html
index 79bf2c28..e4ff4b2c 100644
--- a/src/main/javadoc/org/codehaus/plexus/util/package.html
+++ b/src/main/javadoc/org/codehaus/plexus/util/package.html
@@ -1,3 +1,3 @@
-Misc. utilities.
-
\ No newline at end of file
+Miscellaneous utilities, mainly dealing with I/O, strings, and filesystems.
+