diff --git a/.gitignore b/.gitignore index 761f7ded..28a027e1 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,6 @@ bin *.ipr *.iws *.idea +release.properties +.java-version + diff --git a/pom.xml b/pom.xml index c46b3a17..e214eff9 100644 --- a/pom.xml +++ b/pom.xml @@ -22,11 +22,11 @@ limitations under the License. org.codehaus.plexus plexus - 3.2 + 3.3.1 plexus-utils - 3.0.8 + 3.0.16 Plexus Common Utilities A collection of various utility classes to ease working with strings, files, command lines, XML and @@ -38,7 +38,7 @@ limitations under the License. scm:git:git@github.com:sonatype/plexus-utils.git scm:git:git@github.com:sonatype/plexus-utils.git http://github.com/sonatype/plexus-utils - plexus-utils-3.0.8 + plexus-utils-3.0.16 JIRA @@ -89,6 +89,14 @@ limitations under the License. + + org.apache.maven.plugins + maven-compiler-plugin + + 1.6 + 1.6 + + diff --git a/src/main/java/org/codehaus/plexus/util/AbstractScanner.java b/src/main/java/org/codehaus/plexus/util/AbstractScanner.java index 1a1858dc..4477063f 100644 --- a/src/main/java/org/codehaus/plexus/util/AbstractScanner.java +++ b/src/main/java/org/codehaus/plexus/util/AbstractScanner.java @@ -345,6 +345,11 @@ protected boolean isIncluded( String name ) 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. @@ -371,6 +376,11 @@ protected boolean isExcluded( String name ) 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. */ diff --git a/src/main/java/org/codehaus/plexus/util/DirectoryScanner.java b/src/main/java/org/codehaus/plexus/util/DirectoryScanner.java index 11fb8324..7a1511f4 100644 --- a/src/main/java/org/codehaus/plexus/util/DirectoryScanner.java +++ b/src/main/java/org/codehaus/plexus/util/DirectoryScanner.java @@ -56,6 +56,7 @@ import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.Vector; /** @@ -218,6 +219,8 @@ public class DirectoryScanner */ protected boolean everythingIncluded = true; + private final String[] tokenizedEmpty = MatchPattern.tokenizePathToString( "", File.separator ); + /** * Sole constructor. */ @@ -321,9 +324,10 @@ public void scan() dirsExcluded = new Vector(); dirsDeselected = new Vector(); - if ( isIncluded( "" ) ) + if ( isIncluded( "", tokenizedEmpty ) ) { - if ( !isExcluded( "" ) ) + + if ( !isExcluded( "", tokenizedEmpty ) ) { if ( isSelected( "", basedir ) ) { @@ -438,7 +442,7 @@ protected void scandir( File dir, String vpath, boolean fast ) if ( !followSymlinks ) { - Vector noLinks = new Vector(); + ArrayList noLinks = new ArrayList(); for ( String newfile : newfiles ) { try @@ -458,7 +462,7 @@ protected void scandir( File dir, String vpath, boolean fast ) } else { - noLinks.addElement( newfile ); + noLinks.add( newfile ); } } catch ( IOException ioe ) @@ -466,22 +470,23 @@ protected void scandir( File dir, String vpath, boolean fast ) 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( newfile ); + noLinks.add( newfile ); } } - newfiles = new String[noLinks.size()]; - noLinks.copyInto( newfiles ); + newfiles = noLinks.toArray(new String[noLinks.size()]); } for ( String newfile : newfiles ) { 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 ) ) { @@ -528,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 ) ) { 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 f0e040bb..e1100162 100644 --- a/src/main/java/org/codehaus/plexus/util/FileUtils.java +++ b/src/main/java/org/codehaus/plexus/util/FileUtils.java @@ -145,7 +145,7 @@ public class FileUtils private static final long FILE_COPY_BUFFER_SIZE = ONE_MB * 30; /** - * The vm line separator + * The vm file separator */ public static String FS = System.getProperty( "file.separator" ); @@ -373,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; @@ -1183,9 +1183,10 @@ private static void checkCanWrite( File destination ) private static void mkdirsFor( File destination ) { //does destination directory exist ? - if ( destination.getParentFile() != null && !destination.getParentFile().exists() ) + File parentFile = destination.getParentFile(); + if ( parentFile != null && !parentFile.exists() ) { - destination.getParentFile().mkdirs(); + parentFile.mkdirs(); } } @@ -1336,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 @@ -1491,9 +1492,9 @@ private static void deleteDirectoryOnExit( final File directory ) { return; } + directory.deleteOnExit(); // The hook reverses the list cleanDirectoryOnExit( directory ); - directory.deleteOnExit(); } /** @@ -2372,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 633c1b2e..4045a7f4 100644 --- a/src/main/java/org/codehaus/plexus/util/IOUtil.java +++ b/src/main/java/org/codehaus/plexus/util/IOUtil.java @@ -153,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. diff --git a/src/main/java/org/codehaus/plexus/util/LineOrientedInterpolatingReader.java b/src/main/java/org/codehaus/plexus/util/LineOrientedInterpolatingReader.java index 7a2a6212..29b81acc 100644 --- a/src/main/java/org/codehaus/plexus/util/LineOrientedInterpolatingReader.java +++ b/src/main/java/org/codehaus/plexus/util/LineOrientedInterpolatingReader.java @@ -442,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) @@ -466,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 index 930bda38..00f4d959 100644 --- a/src/main/java/org/codehaus/plexus/util/MatchPattern.java +++ b/src/main/java/org/codehaus/plexus/util/MatchPattern.java @@ -36,6 +36,7 @@ public class MatchPattern private final String separator; private final String[] tokenized; + private final char[][] tokenizedChar; private MatchPattern( String source, String separator ) { @@ -49,6 +50,11 @@ private MatchPattern( String source, String separator ) : 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(); + } + } @@ -65,7 +71,7 @@ public boolean matchPath( String str, boolean isCaseSensitive ) } } - boolean matchPath( String str, String[] strDirs, boolean isCaseSensitive ) + boolean matchPath( String str, char[][] strDirs, boolean isCaseSensitive ) { if ( regexPattern != null ) { @@ -73,7 +79,7 @@ boolean matchPath( String str, String[] strDirs, boolean isCaseSensitive ) } else { - return SelectorUtils.matchAntPathPattern( getTokenizedPathString(), strDirs, isCaseSensitive ); + return SelectorUtils.matchAntPathPattern( getTokenizedPathChars(), strDirs, isCaseSensitive ); } } @@ -99,6 +105,10 @@ public String[] getTokenizedPathString() return tokenized; } + public char[][] getTokenizedPathChars() + { + return tokenizedChar; + } public boolean startsWith( String string ) { diff --git a/src/main/java/org/codehaus/plexus/util/MatchPatterns.java b/src/main/java/org/codehaus/plexus/util/MatchPatterns.java index e72505cf..bffb3ad7 100644 --- a/src/main/java/org/codehaus/plexus/util/MatchPatterns.java +++ b/src/main/java/org/codehaus/plexus/util/MatchPatterns.java @@ -30,9 +30,18 @@ private MatchPatterns( MatchPattern[] patterns ) 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, tokenized, isCaseSensitive ) ) + if ( pattern.matchPath( name, tokenizedNameChar, isCaseSensitive ) ) { return true; } diff --git a/src/main/java/org/codehaus/plexus/util/PathTool.java b/src/main/java/org/codehaus/plexus/util/PathTool.java index 78677a20..76301862 100644 --- a/src/main/java/org/codehaus/plexus/util/PathTool.java +++ b/src/main/java/org/codehaus/plexus/util/PathTool.java @@ -396,7 +396,7 @@ private static final String determineRelativePath( String filename, String separ * 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( "../" ); 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/SelectorUtils.java b/src/main/java/org/codehaus/plexus/util/SelectorUtils.java index 6309c570..4d1ebab1 100644 --- a/src/main/java/org/codehaus/plexus/util/SelectorUtils.java +++ b/src/main/java/org/codehaus/plexus/util/SelectorUtils.java @@ -58,7 +58,6 @@ 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 @@ -452,6 +451,141 @@ static boolean matchAntPathPattern( String[] patDirs, String[] strDirs, boolean 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 ) ) + { + return false; + } + patIdxEnd--; + strIdxEnd--; + } + if ( strIdxStart > strIdxEnd ) + { + // String is exhausted + for ( int i = patIdxStart; i <= patIdxEnd; i++ ) + { + if ( !isDoubleStar( patDirs[i] ) ) + { + return false; + } + } + return true; + } + + while ( patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd ) + { + int patIdxTmp = -1; + for ( int i = patIdxStart + 1; i <= patIdxEnd; i++ ) + { + if ( isDoubleStar( patDirs[i] ) ) + { + 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++ ) + { + 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 ) + { + return false; + } + + patIdxStart = patIdxTmp; + strIdxStart = foundIdx + patLength; + } + + for ( int i = patIdxStart; i <= patIdxEnd; i++ ) + { + if ( !isDoubleStar( patDirs[i] ) ) + { + return false; + } + } + + 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:
@@ -489,6 +623,11 @@ 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; @@ -711,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 873cad09..846f491f 100644 --- a/src/main/java/org/codehaus/plexus/util/StringUtils.java +++ b/src/main/java/org/codehaus/plexus/util/StringUtils.java @@ -137,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++ ) { @@ -292,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; @@ -326,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; @@ -574,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 @@ -594,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() ) { @@ -654,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++ ) { @@ -684,7 +683,7 @@ public static String join( Iterator iterator, String separator ) { 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() ); @@ -801,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 ) @@ -813,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(); } @@ -830,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(); } @@ -1107,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 ); @@ -1201,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 ); @@ -1478,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(); } } @@ -1504,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(); } } @@ -1529,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++ ) { @@ -1586,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++ ) { @@ -1627,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++ ) { @@ -2161,7 +2160,7 @@ public static String removeAndHump( String data, String replaceThis ) { String temp; - StringBuffer out = new StringBuffer(); + StringBuilder out = new StringBuilder(); temp = data; @@ -2197,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++ ) { @@ -2331,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; @@ -2379,7 +2378,7 @@ public static String escape( String source, final char[] escapedChars, String es System.arraycopy( escapedChars, 0, eqc, 0, escapedChars.length ); Arrays.sort( eqc ); - StringBuffer buffer = new StringBuffer( source.length() ); + StringBuilder buffer = new StringBuilder( source.length() ); for ( int i = 0; i < source.length(); i++ ) { @@ -2409,7 +2408,7 @@ public static String escape( String source, final char[] escapedChars, String es */ public static String removeDuplicateWhitespace( String s ) { - StringBuffer result = new StringBuffer( ); + StringBuilder result = new StringBuilder( ); int length = s.length(); boolean isPreviousWhiteSpace = false; for (int i = 0; i < length; i++){ @@ -2466,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/cli/CommandLineUtils.java b/src/main/java/org/codehaus/plexus/util/cli/CommandLineUtils.java index 283785eb..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,12 +16,8 @@ * 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.Locale; import java.util.Map; @@ -29,11 +25,8 @@ 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; -import org.codehaus.plexus.util.IOUtil; - /** * @author Trygve Laugstøl * @version $Id$ @@ -274,107 +267,18 @@ public static Properties getSystemEnvVars() 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) { - IOUtil.close( p.getOutputStream() ); - IOUtil.close( p.getErrorStream() ); - IOUtil.close( p.getInputStream() ); - - p.destroy(); + key = key.toUpperCase( Locale.ENGLISH ); } + envVars.put( key, value ); } + return envVars; } public static boolean isAlive( Process p ) @@ -598,36 +502,4 @@ public static String toString( String[] line ) return result.toString(); } - private static Method getEnvMethod() - { - try - { - return System.class.getMethod( "getenv"); - } - 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(); - @SuppressWarnings( { "unchecked" } ) Map envs = (Map) method.invoke( null ); - for ( String key : envs.keySet() ) - { - String value = 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/shell/BourneShell.java b/src/main/java/org/codehaus/plexus/util/cli/shell/BourneShell.java index e4b4cde4..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,34 +28,18 @@ 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 ); @@ -76,7 +59,7 @@ public String getExecutable() return super.getExecutable(); } - return unifyQuotes( super.getExecutable()); + return quoteOneItem( super.getOriginalExecutable(), true ); } public List getShellArgsList() @@ -123,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; - } - /** *

Unify quotes in a path for the Bourne Shell.

* *
-     * BourneShell.unifyQuotes(null)                       = null
-     * BourneShell.unifyQuotes("")                         = (empty)
-     * BourneShell.unifyQuotes("/test/quotedpath'abc")     = /test/quotedpath\'abc
-     * BourneShell.unifyQuotes("/test/quoted path'abc")    = "/test/quoted path'abc"
-     * BourneShell.unifyQuotes("/test/quotedpath\"abc")    = "/test/quotedpath\"abc"
-     * BourneShell.unifyQuotes("/test/quoted path\"abc")   = "/test/quoted path\"abc"
-     * BourneShell.unifyQuotes("/test/quotedpath\"'abc")   = "/test/quotedpath\"'abc"
-     * BourneShell.unifyQuotes("/test/quoted path\"'abc")  = "/test/quoted path\"'abc"
+     * BourneShell.quoteOneItem(null)                       = null
+     * BourneShell.quoteOneItem("")                         = ''
+     * BourneShell.quoteOneItem("/test/quotedpath'abc")     = '/test/quotedpath'"'"'abc'
+     * BourneShell.quoteOneItem("/test/quoted path'abc")    = '/test/quoted pat'"'"'habc'
+     * BourneShell.quoteOneItem("/test/quotedpath\"abc")    = '/test/quotedpath"abc'
+     * BourneShell.quoteOneItem("/test/quoted path\"abc")   = '/test/quoted path"abc'
+     * BourneShell.quoteOneItem("/test/quotedpath\"'abc")   = '/test/quotedpath"'"'"'abc'
+     * BourneShell.quoteOneItem("/test/quoted path\"'abc")  = '/test/quoted path"'"'"'abc'
      * 
* * @param path not null path. * @return the path unified correctly for the Bourne shell. */ - protected static String unifyQuotes( String path ) + protected String quoteOneItem( String path, boolean isExecutable ) { if ( path == null ) { return null; } - if ( path.indexOf( " " ) == -1 && path.indexOf( "'" ) != -1 && path.indexOf( "\"" ) == -1 ) - { - return StringUtils.escape( path ); - } + StringBuilder sb = new StringBuilder(); + sb.append( "'" ); + sb.append( path.replace( "'", "'\"'\"'" ) ); + sb.append( "'" ); - return StringUtils.quoteAndEscape( path, '\"', BASH_QUOTING_TRIGGER_CHARS ); + return sb.toString(); } } diff --git a/src/main/java/org/codehaus/plexus/util/cli/shell/CmdShell.java b/src/main/java/org/codehaus/plexus/util/cli/shell/CmdShell.java index bbe44728..a96bb68a 100644 --- a/src/main/java/org/codehaus/plexus/util/cli/shell/CmdShell.java +++ b/src/main/java/org/codehaus/plexus/util/cli/shell/CmdShell.java @@ -79,7 +79,7 @@ public CmdShell() */ 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 571b249d..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 @@ -48,6 +48,8 @@ public class Shell private boolean quotedArgumentsEnabled = true; + private boolean unconditionallyQuote = false; + private String executable; private String workingDir; @@ -68,6 +70,16 @@ public class Shell 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,...) * @@ -129,10 +141,23 @@ public List getCommandLine( String executable, String[] arguments ) return getRawCommandLine( executable, arguments ); } + protected String quoteOneItem(String inputString, boolean isExecutable) + { + 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(); - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); if ( executable != null ) { @@ -144,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 { @@ -162,9 +185,7 @@ protected List getRawCommandLine( String executable, String[] arguments if ( isQuotedArgumentsEnabled() ) { - char[] escapeChars = getEscapeChars( isSingleQuotedArgumentEscaped(), isDoubleQuotedArgumentEscaped() ); - - sb.append( StringUtils.quoteAndEscape( arguments[i], getArgumentQuoteDelimiter(), escapeChars, getQuotingTriggerChars(), getArgumentEscapePattern(), false ) ); + sb.append( quoteOneItem( arguments[i], false ) ); } else { @@ -189,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( '\'' ); @@ -278,7 +299,7 @@ public List getShellCommandLine( String[] arguments ) commandLine.addAll( getShellArgsList() ); } - commandLine.addAll( getCommandLine( getExecutable(), arguments ) ); + commandLine.addAll( getCommandLine( getOriginalExecutable(), arguments ) ); return commandLine; 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 06ff14d8..1fb667c1 100644 --- a/src/main/java/org/codehaus/plexus/util/introspection/ClassMap.java +++ b/src/main/java/org/codehaus/plexus/util/introspection/ClassMap.java @@ -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; 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/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 + "