plexus-utils-plexus-utils-3.0.22/000077500000000000000000000000001251077732300167375ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/.gitattributes000066400000000000000000000002441251077732300216320ustar00rootroot00000000000000# Auto detect text files and perform LF normalization * text=auto *.java text diff=java *.html text diff=html *.css text *.js text *.sql text plexus-utils-plexus-utils-3.0.22/.gitignore000066400000000000000000000001621251077732300207260ustar00rootroot00000000000000target/ .project .classpath .settings/ bin *.iml *.ipr *.iws *.idea release.properties .java-version plexus-utils-plexus-utils-3.0.22/NOTICE.txt000066400000000000000000000001451251077732300204610ustar00rootroot00000000000000This product includes software developed by The Apache Software Foundation (http://www.apache.org/). plexus-utils-plexus-utils-3.0.22/README.md000066400000000000000000000001561251077732300202200ustar00rootroot00000000000000Plexus-archiver =============== The current master is now at https://github.com/codehaus-plexus/plexus-utils plexus-utils-plexus-utils-3.0.22/pom.xml000066400000000000000000000073671251077732300202710ustar00rootroot00000000000000 4.0.0 org.codehaus.plexus plexus 3.3.1 plexus-utils 3.0.22 Plexus Common Utilities A collection of various utility classes to ease working with strings, files, command lines, XML and more. http://plexus.codehaus.org/plexus-utils scm:git:git@github.com:codehaus-plexus/plexus-utils.git scm:git:git@github.com:codehaus-plexus/plexus-utils.git http://github.com/codehaus-plexus/plexus-utils plexus-utils-3.0.22 JIRA http://jira.codehaus.org/browse/PLXUTILS org.apache.maven.shared maven-plugin-testing-harness 1.1 test org.apache.maven.plugins maven-surefire-plugin true org/codehaus/plexus/util/FileBasedTestCase.java **/Test*.java JAVA_HOME ${JAVA_HOME} M2_HOME ${M2_HOME} org.apache.maven.plugins maven-enforcer-plugin 1.1.1 enforce-java enforce 1.7.0 org.apache.maven.plugins maven-compiler-plugin 1.5 1.5 org.apache.maven.plugins maven-release-plugin 2.5.1 plexus-utils-plexus-utils-3.0.22/src/000077500000000000000000000000001251077732300175265ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/000077500000000000000000000000001251077732300204525ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/java/000077500000000000000000000000001251077732300213735ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/java/org/000077500000000000000000000000001251077732300221625ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/000077500000000000000000000000001251077732300237555ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/000077500000000000000000000000001251077732300252755ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/000077500000000000000000000000001251077732300262525ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/AbstractScanner.java000066400000000000000000000350571251077732300322040ustar00rootroot00000000000000package 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; /** * Scan a directory tree for files, with specified inclusions and exclusions. */ public abstract class AbstractScanner implements Scanner { /** * Patterns which should be excluded by default, like SCM files * * * @see #addDefaultExcludes() */ public static final String[] DEFAULTEXCLUDES = { // Miscellaneous typical temporary files "**/*~", "**/#*#", "**/.#*", "**/%*%", "**/._*", // CVS "**/CVS", "**/CVS/**", "**/.cvsignore", // RCS "**/RCS", "**/RCS/**", // SCCS "**/SCCS", "**/SCCS/**", // Visual SourceSafe "**/vssver.scc", // MKS "**/project.pj", // Subversion "**/.svn", "**/.svn/**", // Arch "**/.arch-ids", "**/.arch-ids/**", //Bazaar "**/.bzr", "**/.bzr/**", //SurroundSCM "**/.MySCMServerInfo", // Mac "**/.DS_Store", // Serena Dimensions Version 10 "**/.metadata", "**/.metadata/**", // Mercurial "**/.hg", "**/.hg/**", // git "**/.git", "**/.gitignore", "**/.gitattributes", "**/.git/**", // BitKeeper "**/BitKeeper", "**/BitKeeper/**", "**/ChangeSet", "**/ChangeSet/**", // darcs "**/_darcs", "**/_darcs/**", "**/.darcsrepo", "**/.darcsrepo/**", "**/-darcs-backup*", "**/.darcs-temp-mail" }; /** * The patterns for the files to be included. */ protected String[] includes; 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. * * @param isCaseSensitive whether or not the file system should be * regarded as a case sensitive one */ 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. * * @param pattern The pattern to match against. Must not be * 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 "**". */ 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 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 "**". */ 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. * * @param pattern The pattern to match against. Must not be * 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. */ 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 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 ) { return SelectorUtils.matchPath( pattern, str, isCaseSensitive ); } /** * 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. * @return true if the string matches against the pattern, * or false otherwise. */ 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 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 ) { 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. */ public void setIncludes( String[] includes ) { if ( includes == null ) { this.includes = null; } else { this.includes = new String[includes.length]; for ( int i = 0; i < includes.length; i++ ) { this.includes[i] = normalizePattern( includes[i] ); } } } /** * 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. * May be null, indicating that no files * should be excluded. If a non-null list is * given, all elements must be non-null. */ public void setExcludes( String[] excludes ) { if ( excludes == null ) { this.excludes = null; } else { this.excludes = new String[excludes.length]; for ( int i = 0; i < excludes.length; i++ ) { this.excludes[i] = normalizePattern( excludes[i] ); } } } /** * 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. */ private String normalizePattern( String pattern ) { pattern = pattern.trim(); if ( pattern.startsWith( SelectorUtils.REGEX_HANDLER_PREFIX ) ) { if ( File.separatorChar == '\\' ) { pattern = StringUtils.replace( pattern, "/", "\\\\" ); } else { pattern = StringUtils.replace( pattern, "\\\\", "/" ); } } else { pattern = pattern.replace( File.separatorChar == '/' ? '\\' : '/', File.separatorChar ); if ( pattern.endsWith( File.separator ) ) { pattern += "**"; } } return pattern; } /** * Tests whether or not a name matches against at least one include * pattern. * * @param name The name to match. Must not be null. * @return true when the name matches against at least one * include pattern, or false otherwise. */ 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. * * @param name The name to match. Must not be null. * @return true when the name matches against the start of at * least one include pattern, or false otherwise. */ protected boolean couldHoldIncluded( String name ) { return includesPatterns.matchesPatternStart(name, isCaseSensitive); } /** * Tests whether or not a name matches against at least one exclude * pattern. * * @param name The name to match. Must not be null. * @return true when the name matches against at least one * exclude pattern, or false otherwise. */ 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. */ public void addDefaultExcludes() { int excludesLength = excludes == null ? 0 : excludes.length; String[] newExcludes; newExcludes = new String[excludesLength + DEFAULTEXCLUDES.length]; if ( excludesLength > 0 ) { System.arraycopy( excludes, 0, newExcludes, 0, excludesLength ); } for ( int i = 0; i < DEFAULTEXCLUDES.length; i++ ) { newExcludes[i + excludesLength] = DEFAULTEXCLUDES[i].replace( '/', File.separatorChar ); } excludes = newExcludes; } protected void setupDefaultFilters() { if ( includes == null ) { // No includes supplied, so set it to 'matches all' includes = new String[1]; includes[0] = "**"; } if ( excludes == null ) { excludes = new String[0]; } } protected void setupMatchPatterns() { includesPatterns = MatchPatterns.from( includes ); excludesPatterns = MatchPatterns.from( excludes ); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/Base64.java000066400000000000000000000407151251077732300301500ustar00rootroot00000000000000package 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. */ /** * Provides Base64 encoding and decoding as defined by RFC 2045. * *

This class implements section 6.8. Base64 Content-Transfer-Encoding * from RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: * Format of Internet Message Bodies by Freed and Borenstein.

* * @see RFC 2045 * @author Apache Software Foundation * @since 1.0-dev * @version $Id$ */ public class Base64 { // // Source Id: Base64.java 161350 2005-04-14 20:39:46Z ggregory // /** * Chunk size per RFC 2045 section 6.8. * *

The {@value} character limit does not count the trailing CRLF, but counts * all other characters, including any equal signs.

* * @see RFC 2045 section 6.8 */ static final int CHUNK_SIZE = 76; /** * Chunk separator per RFC 2045 section 2.1. * * @see RFC 2045 section 2.1 */ static final byte[] CHUNK_SEPARATOR = "\r\n".getBytes(); /** * The base length. */ static final int BASELENGTH = 255; /** * Lookup length. */ static final int LOOKUPLENGTH = 64; /** * Used to calculate the number of bits in a byte. */ static final int EIGHTBIT = 8; /** * Used when encoding something which has fewer than 24 bits. */ static final int SIXTEENBIT = 16; /** * Used to determine how many bits data contains. */ static final int TWENTYFOURBITGROUP = 24; /** * Used to get the number of Quadruples. */ static final int FOURBYTE = 4; /** * Used to test the sign of a byte. */ static final int SIGN = -128; /** * Byte used to pad output. */ static final byte PAD = (byte) '='; /** * Contains the Base64 values 0 through 63 accessed by using character encodings as * indices. *

* For example, base64Alphabet['+'] returns 62. *

*

* The value of undefined encodings is -1. *

*/ private static byte[] base64Alphabet = new byte[BASELENGTH]; /** *

* Contains the Base64 encodings A through Z, followed by a through * z, followed by 0 through 9, followed by +, and * /. *

*

* This array is accessed by using character values as indices. *

*

* For example, lookUpBase64Alphabet[62] returns '+'. *

*/ private static byte[] lookUpBase64Alphabet = new byte[LOOKUPLENGTH]; // Populating the lookup and character arrays static { for (int i = 0; i < BASELENGTH; i++) { base64Alphabet[i] = (byte) -1; } for (int i = 'Z'; i >= 'A'; i--) { base64Alphabet[i] = (byte) (i - 'A'); } for (int i = 'z'; i >= 'a'; i--) { base64Alphabet[i] = (byte) (i - 'a' + 26); } for (int i = '9'; i >= '0'; i--) { base64Alphabet[i] = (byte) (i - '0' + 52); } base64Alphabet['+'] = 62; base64Alphabet['/'] = 63; for (int i = 0; i <= 25; i++) { lookUpBase64Alphabet[i] = (byte) ('A' + i); } for (int i = 26, j = 0; i <= 51; i++, j++) { lookUpBase64Alphabet[i] = (byte) ('a' + j); } for (int i = 52, j = 0; i <= 61; i++, j++) { lookUpBase64Alphabet[i] = (byte) ('0' + j); } lookUpBase64Alphabet[62] = (byte) '+'; lookUpBase64Alphabet[63] = (byte) '/'; } /** * Returns whether or not the octect is in the base 64 alphabet. * * @param octect The value to test * @return true if the value is defined in the the base 64 alphabet, false otherwise. */ private static boolean isBase64(byte octect) { if (octect == PAD) { return true; } else if (octect < 0 || base64Alphabet[octect] == -1) { return false; } else { return true; } } /** * Tests a given byte array to see if it contains * only valid characters within the Base64 alphabet. * * @param arrayOctect byte array to test * @return true if all bytes are valid characters in the Base64 * alphabet or if the byte array is empty; false, otherwise */ public static boolean isArrayByteBase64(byte[] arrayOctect) { arrayOctect = discardWhitespace(arrayOctect); int length = arrayOctect.length; if (length == 0) { // shouldn't a 0 length array be valid base64 data? // return false; return true; } for ( byte anArrayOctect : arrayOctect ) { if ( !isBase64( anArrayOctect ) ) { return false; } } return true; } /** * Encodes binary data using the base64 algorithm but * does not chunk the output. * * @param binaryData binary data to encode * @return Base64 characters */ public static byte[] encodeBase64(byte[] binaryData) { return encodeBase64(binaryData, false); } /** * Encodes binary data using the base64 algorithm and chunks * the encoded output into 76 character blocks * * @param binaryData binary data to encode * @return Base64 characters chunked in 76 character blocks */ public static byte[] encodeBase64Chunked(byte[] binaryData) { return encodeBase64(binaryData, true); } /** * Decodes a byte[] containing containing * characters in the Base64 alphabet. * * @param pArray A byte array containing Base64 character data * @return a byte array containing binary data */ public byte[] decode(byte[] pArray) { return decodeBase64(pArray); } /** * Encodes binary data using the base64 algorithm, optionally * chunking the output into 76 character blocks. * * @param binaryData Array containing binary data to encode. * @param isChunked if true this encoder will chunk * the base64 output into 76 character blocks * @return Base64-encoded data. */ public static byte[] encodeBase64(byte[] binaryData, boolean isChunked) { int lengthDataBits = binaryData.length * EIGHTBIT; int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP; int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP; byte encodedData[] = null; int encodedDataLength = 0; int nbrChunks = 0; if (fewerThan24bits != 0) { //data not divisible by 24 bit encodedDataLength = (numberTriplets + 1) * 4; } else { // 16 or 8 bit encodedDataLength = numberTriplets * 4; } // If the output is to be "chunked" into 76 character sections, // for compliance with RFC 2045 MIME, then it is important to // allow for extra length to account for the separator(s) if (isChunked) { nbrChunks = (CHUNK_SEPARATOR.length == 0 ? 0 : (int) Math.ceil((float) encodedDataLength / CHUNK_SIZE)); encodedDataLength += nbrChunks * CHUNK_SEPARATOR.length; } encodedData = new byte[encodedDataLength]; byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0; int encodedIndex = 0; int dataIndex = 0; int i = 0; int nextSeparatorIndex = CHUNK_SIZE; int chunksSoFar = 0; //log.debug("number of triplets = " + numberTriplets); for (i = 0; i < numberTriplets; i++) { dataIndex = i * 3; b1 = binaryData[dataIndex]; b2 = binaryData[dataIndex + 1]; b3 = binaryData[dataIndex + 2]; //log.debug("b1= " + b1 +", b2= " + b2 + ", b3= " + b3); l = (byte) (b2 & 0x0f); k = (byte) (b1 & 0x03); byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc); encodedData[encodedIndex] = lookUpBase64Alphabet[val1]; //log.debug( "val2 = " + val2 ); //log.debug( "k4 = " + (k<<4) ); //log.debug( "vak = " + (val2 | (k<<4)) ); encodedData[encodedIndex + 1] = lookUpBase64Alphabet[val2 | (k << 4)]; encodedData[encodedIndex + 2] = lookUpBase64Alphabet[(l << 2) | val3]; encodedData[encodedIndex + 3] = lookUpBase64Alphabet[b3 & 0x3f]; encodedIndex += 4; // If we are chunking, let's put a chunk separator down. if (isChunked) { // this assumes that CHUNK_SIZE % 4 == 0 if (encodedIndex == nextSeparatorIndex) { System.arraycopy( CHUNK_SEPARATOR, 0, encodedData, encodedIndex, CHUNK_SEPARATOR.length); chunksSoFar++; nextSeparatorIndex = (CHUNK_SIZE * (chunksSoFar + 1)) + (chunksSoFar * CHUNK_SEPARATOR.length); encodedIndex += CHUNK_SEPARATOR.length; } } } // form integral number of 6-bit groups dataIndex = i * 3; if (fewerThan24bits == EIGHTBIT) { b1 = binaryData[dataIndex]; k = (byte) (b1 & 0x03); //log.debug("b1=" + b1); //log.debug("b1<<2 = " + (b1>>2) ); byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); encodedData[encodedIndex] = lookUpBase64Alphabet[val1]; encodedData[encodedIndex + 1] = lookUpBase64Alphabet[k << 4]; encodedData[encodedIndex + 2] = PAD; encodedData[encodedIndex + 3] = PAD; } else if (fewerThan24bits == SIXTEENBIT) { b1 = binaryData[dataIndex]; b2 = binaryData[dataIndex + 1]; l = (byte) (b2 & 0x0f); k = (byte) (b1 & 0x03); byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); encodedData[encodedIndex] = lookUpBase64Alphabet[val1]; encodedData[encodedIndex + 1] = lookUpBase64Alphabet[val2 | (k << 4)]; encodedData[encodedIndex + 2] = lookUpBase64Alphabet[l << 2]; encodedData[encodedIndex + 3] = PAD; } if (isChunked) { // we also add a separator to the end of the final chunk. if (chunksSoFar < nbrChunks) { System.arraycopy( CHUNK_SEPARATOR, 0, encodedData, encodedDataLength - CHUNK_SEPARATOR.length, CHUNK_SEPARATOR.length); } } return encodedData; } /** * Decodes Base64 data into octects * * @param base64Data Byte array containing Base64 data * @return Array containing decoded data. */ public static byte[] decodeBase64(byte[] base64Data) { // RFC 2045 requires that we discard ALL non-Base64 characters base64Data = discardNonBase64(base64Data); // handle the edge case, so we don't have to worry about it later if (base64Data.length == 0) { return new byte[0]; } int numberQuadruple = base64Data.length / FOURBYTE; byte decodedData[] = null; byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0; // Throw away anything not in base64Data int encodedIndex = 0; int dataIndex = 0; { // this sizes the output array properly - rlw int lastData = base64Data.length; // ignore the '=' padding while (base64Data[lastData - 1] == PAD) { if (--lastData == 0) { return new byte[0]; } } decodedData = new byte[lastData - numberQuadruple]; } for (int i = 0; i < numberQuadruple; i++) { dataIndex = i * 4; marker0 = base64Data[dataIndex + 2]; marker1 = base64Data[dataIndex + 3]; b1 = base64Alphabet[base64Data[dataIndex]]; b2 = base64Alphabet[base64Data[dataIndex + 1]]; if (marker0 != PAD && marker1 != PAD) { //No PAD e.g 3cQl b3 = base64Alphabet[marker0]; b4 = base64Alphabet[marker1]; decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); decodedData[encodedIndex + 1] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4); } else if (marker0 == PAD) { //Two PAD e.g. 3c[Pad][Pad] decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); } else if (marker1 == PAD) { //One PAD e.g. 3cQ[Pad] b3 = base64Alphabet[marker0]; decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); decodedData[encodedIndex + 1] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); } encodedIndex += 3; } return decodedData; } /** * Discards any whitespace from a base-64 encoded block. * * @param data The base-64 encoded data to discard the whitespace * from. * @return The data, less whitespace (see RFC 2045). */ static byte[] discardWhitespace(byte[] data) { byte groomedData[] = new byte[data.length]; int bytesCopied = 0; for ( byte aData : data ) { switch ( aData ) { case (byte) ' ': case (byte) '\n': case (byte) '\r': case (byte) '\t': break; default: groomedData[bytesCopied++] = aData; } } byte packedData[] = new byte[bytesCopied]; System.arraycopy(groomedData, 0, packedData, 0, bytesCopied); return packedData; } /** * Discards any characters outside of the base64 alphabet, per * the requirements on page 25 of RFC 2045 - "Any characters * outside of the base64 alphabet are to be ignored in base64 * encoded data." * * @param data The base-64 encoded data to groom * @return The data, less non-base64 characters (see RFC 2045). */ static byte[] discardNonBase64(byte[] data) { byte groomedData[] = new byte[data.length]; int bytesCopied = 0; for ( byte aData : data ) { if ( isBase64( aData ) ) { groomedData[bytesCopied++] = aData; } } byte packedData[] = new byte[bytesCopied]; System.arraycopy(groomedData, 0, packedData, 0, bytesCopied); return packedData; } /** * Encodes a byte[] containing binary data, into a byte[] containing * characters in the Base64 alphabet. * * @param pArray a byte array containing binary data * @return A byte array containing only Base64 character data */ public byte[] encode(byte[] pArray) { return encodeBase64(pArray, false); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/CachedMap.java000066400000000000000000000337111251077732300307270ustar00rootroot00000000000000/* * J.A.D.E. Java(TM) Addition to Default Environment. * Latest release available at http://jade.dautelle.com/ * This class is public domain (not copyrighted). */ package org.codehaus.plexus.util; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.Map; import java.util.Set; /** *

This class provides cache access to Map collections.

* *

Instance of this class can be used as "proxy" for any collection * implementing the java.util.Map interface.

* *

Typically, {@link CachedMap} are used to accelerate access to * large collections when the access to the collection is not evenly * distributed (associative cache). The performance gain is about * 50% for the fastest hash map collections (e.g. {@link FastMap}). * For slower collections such as java.util.TreeMap, * non-resizable {@link FastMap} (real-time) or database access, * performance can be of several orders of magnitude.

* *

Note: The keys used to access elements of a {@link CachedMap} do * not need to be immutable as they are not stored in the cache * (only keys specified by the {@link #put} method are). * In other words, access can be performed using mutable keys as long * as these keys can be compared for equality with the real map's keys * (e.g. same hashCode values).

* *

This implementation is not synchronized. Multiple threads accessing * or modifying the collection must be synchronized externally.

* *

This class is public domain (not copyrighted).

* * @author Jean-Marie Dautelle * @version 5.3, October 30, 2003 */ public final class CachedMap implements Map { /** * Holds the FastMap backing this collection * (null if generic backing map). */ private final FastMap _backingFastMap; /** * Holds the generic map backing this collection. */ private final Map _backingMap; /** * Holds the keys of the backing map (key-to-key mapping). * (null if FastMap backing map). */ private final FastMap _keysMap; /** * Holds the cache's mask (capacity - 1). */ private final int _mask; /** * Holds the keys being cached. */ private final Object[] _keys; /** * Holds the values being cached. */ private final Object[] _values; /** * Creates a cached map backed by a {@link FastMap}. * The default cache size and map capacity is set to 256 * entries. */ public CachedMap() { this(256, new FastMap()); } /** * Creates a cached map backed by a {@link FastMap} and having the * specified cache size. * * @param cacheSize the cache size, the actual cache size is the * first power of 2 greater or equal to cacheSize. * This is also the initial capacity of the backing map. */ public CachedMap(int cacheSize) { this(cacheSize, new FastMap(cacheSize)); } /** * Creates a cached map backed by the specified map and having the specified * cache size. In order to maitain cache veracity, it is critical * that all update to the backing map is accomplished through the * {@link CachedMap} instance; otherwise {@link #flush} has to be called. * * @param cacheSize the cache size, the actual cache size is the * first power of 2 greater or equal to cacheSize. * @param backingMap the backing map to be "wrapped" in a cached map. */ public CachedMap(int cacheSize, Map backingMap) { // Find a power of 2 >= minimalCache int actualCacheSize = 1; while (actualCacheSize < cacheSize) { actualCacheSize <<= 1; } // Sets up cache. _keys = new Object[actualCacheSize]; _values = new Object[actualCacheSize]; _mask = actualCacheSize - 1; // Sets backing map references. if (backingMap instanceof FastMap) { _backingFastMap = (FastMap)backingMap; _backingMap = _backingFastMap; _keysMap = null; } else { _backingFastMap = null; _backingMap = backingMap; _keysMap = new FastMap(backingMap.size()); for ( Object key : backingMap.keySet() ) { _keysMap.put( key, key ); } } } /** * Returns the actual cache size. * * @return the cache size (power of 2). */ public int getCacheSize() { return _keys.length; } /** * Returns the backing map. If the backing map is modified directly, * this {@link CachedMap} has to be flushed. * * @return the backing map. * @see #flush */ public Map getBackingMap() { return (_backingFastMap != null) ? _backingFastMap : _backingMap; } /** * Flushes the key/value pairs being cached. This method should be called * if the backing map is externally modified. */ public void flush() { for (int i=0; i < _keys.length; i++) { _keys[i] = null; _values[i] = null; } if (_keysMap != null) { // Re-populates keys from backing map. for ( Object key : _backingMap.keySet() ) { _keysMap.put( key, key ); } } } /** * Returns the value to which this map maps the specified key. * First, the cache is being checked, then if the cache does not contains * the specified key, the backing map is accessed and the key/value * pair is stored in the cache. * * @param key the key whose associated value is to be returned. * @return the value to which this map maps the specified key, or * null if the map contains no mapping for this key. * @throws ClassCastException if the key is of an inappropriate type for * the backing map (optional). * @throws NullPointerException if the key is null. */ public Object get(Object key) { int index = key.hashCode() & _mask; return key.equals(_keys[index]) ? _values[index] : getCacheMissed(key, index); } private Object getCacheMissed(Object key, int index) { if (_backingFastMap != null) { Map.Entry entry = _backingFastMap.getEntry(key); if (entry != null) { _keys[index] = entry.getKey(); Object value = entry.getValue(); _values[index] = value; return value; } else { return null; } } else { // Generic backing map. Object mapKey = _keysMap.get(key); if (mapKey != null) { _keys[index] = mapKey; Object value = _backingMap.get(key); _values[index] = value; return value; } else { return null; } } } /** * Associates the specified value with the specified key in this map. * * @param key the key with which the specified value is to be associated. * @param value the value to be associated with the specified key. * @return the previous value associated with specified key, or * null if there was no mapping for the key. * @throws UnsupportedOperationException if the put operation * is not supported by the backing map. * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map. * @throws IllegalArgumentException if some aspect of this key or value * prevents it from being stored in this map. * @throws NullPointerException if the key is null. */ public Object put(Object key, Object value) { // Updates the cache. int index = key.hashCode() & _mask; if (key.equals(_keys[index]) ) { _values[index] = value; } else if (_keysMap != null) { // Possibly a new key. _keysMap.put(key, key); } // Updates the backing map. return _backingMap.put(key, value); } /** * Removes the mapping for this key from this map if it is present. * * @param key key whose mapping is to be removed from the map. * @return previous value associated with specified key, * or null if there was no mapping for key. * @throws ClassCastException if the key is of an inappropriate type for * the backing map (optional). * @throws NullPointerException if the key is null. * @throws UnsupportedOperationException if the remove method * is not supported by the backing map. */ public Object remove(Object key) { // Removes from cache. int index = key.hashCode() & _mask; if (key.equals(_keys[index]) ) { _keys[index] = null; } // Removes from key map. if (_keysMap != null) { _keysMap.remove(key); } // Removes from backing map. return _backingMap.remove(key); } /** * Indicates if this map contains a mapping for the specified key. * * @param key the key whose presence in this map is to be tested. * @return true if this map contains a mapping for the * specified key; false otherwise. */ public boolean containsKey(Object key) { // Checks the cache. int index = key.hashCode() & _mask; if (key.equals(_keys[index]) ) { return true; } else { // Checks the backing map. return _backingMap.containsKey(key); } } /** * Returns the number of key-value mappings in this map. If the * map contains more than Integer.MAX_VALUE elements, * returns Integer.MAX_VALUE. * * @return the number of key-value mappings in this map. */ public int size() { return _backingMap.size(); } /** * Returns true if this map contains no key-value mappings. * * @return true if this map contains no key-value mappings. */ public boolean isEmpty() { return _backingMap.isEmpty(); } /** * Returns true if this map maps one or more keys to the * specified value. * * @param value value whose presence in this map is to be tested. * @return true if this map maps one or more keys to the * specified value. * @throws ClassCastException if the value is of an inappropriate type for * the backing map (optional). * @throws NullPointerException if the value is null and the * backing map does not not permit null values. */ public boolean containsValue(Object value) { return _backingMap.containsValue(value); } /** * Copies all of the mappings from the specified map to this map * (optional operation). This method automatically flushes the cache. * * @param map the mappings to be stored in this map. * @throws UnsupportedOperationException if the putAll method * is not supported by the backing map. * @throws ClassCastException if the class of a key or value in the * specified map prevents it from being stored in this map. * @throws IllegalArgumentException some aspect of a key or value in the * specified map prevents it from being stored in this map. * @throws NullPointerException the specified map is null, or * if the backing map does not permit null keys or * values, and the specified map contains null keys or * values. */ public void putAll(Map map) { _backingMap.putAll(map); flush(); } /** * Removes all mappings from this map (optional operation). This method * automatically flushes the cache. * * @throws UnsupportedOperationException if clear is not supported by the * backing map. */ public void clear() { _backingMap.clear(); flush(); } /** * Returns an unmodifiable view of the keys contained in this * map. * * @return an unmodifiable view of the keys contained in this map. */ public Set keySet() { return Collections.unmodifiableSet(_backingMap.keySet()); } /** * Returns an unmodifiable view of the values contained in this map. * * @return an unmodifiable view of the values contained in this map. */ public Collection values() { return Collections.unmodifiableCollection(_backingMap.values()); } /** * Returns an unmodifiable view of the mappings contained in this * map. Each element in the returned set is a Map.Entry. * * @return an unmodifiable view of the mappings contained in this map. */ public Set entrySet() { return Collections.unmodifiableSet(_backingMap.entrySet()); } /** * Compares the specified object with this map for equality. Returns * true if the given object is also a map and the two Maps * represent the same mappings. * * @param o object to be compared for equality with this map. * @return true if the specified object is equal to this map. */ public boolean equals(Object o) { return _backingMap.equals(o); } /** * Returns the hash code value for this map. * * @return the hash code value for this map. */ public int hashCode() { return _backingMap.hashCode(); } }plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/CollectionUtils.java000066400000000000000000000171411251077732300322350ustar00rootroot00000000000000package 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.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; /** * @author olamy * @version $Id$ */ public class CollectionUtils { // ---------------------------------------------------------------------- // Static methods that can probably be moved to a real util class. // ---------------------------------------------------------------------- /** * Take a dominant and recessive Map and merge the key:value * pairs where the recessive Map may add key:value pairs to the dominant * Map but may not override any existing key:value pairs. * * If we have two Maps, a dominant and recessive, and * their respective keys are as follows: * * dominantMapKeys = { a, b, c, d, e, f } * recessiveMapKeys = { a, b, c, x, y, z } * * Then the result should be the following: * * resultantKeys = { a, b, c, d, e, f, x, y, z } * * @param dominantMap Dominant Map. * @param recessiveMap Recessive Map. * @return The result map with combined dominant and recessive values. */ public static Map mergeMaps( Map dominantMap, Map recessiveMap ) { if ( dominantMap == null && recessiveMap == null ) { return null; } if ( dominantMap != null && recessiveMap == null ) { return dominantMap; } if ( dominantMap == null) { return recessiveMap; } Map result = new HashMap(); // Grab the keys from the dominant and recessive maps. 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 = CollectionUtils.subtract( recessiveMapKeys, CollectionUtils.intersection( dominantMapKeys, recessiveMapKeys ) ); result.putAll( dominantMap ); // Now take the keys we just found and extract the values from // the recessiveMap and put the key:value pairs into the dominantMap. for ( K key : contributingRecessiveKeys ) { result.put( key, recessiveMap.get( key ) ); } return result; } /** * Take a series of Maps and merge * them where the ordering of the array from 0..n * is the dominant order. * * @param maps An array of Maps to merge. * @return Map The result Map produced after the merging process. */ public static Map mergeMaps( Map[] maps ) { Map result; if ( maps.length == 0 ) { result = null; } else if ( maps.length == 1 ) { result = maps[0]; } else { result = mergeMaps( maps[0], maps[1] ); for ( int i = 2; i < maps.length; i++ ) { result = mergeMaps( result, maps[i] ); } } return result; } /** * Returns a {@link Collection} containing the intersection * of the given {@link Collection}s. *

* The cardinality of each element in the returned {@link Collection} * 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 ) { ArrayList list = new ArrayList(); Map mapa = getCardinalityMap( a ); Map mapb = getCardinalityMap( b ); Set elts = new HashSet( a ); elts.addAll( b ); for ( E obj : elts ) { for ( int i = 0, m = Math.min( getFreq( obj, mapa ), getFreq( obj, mapb ) ); i < m; i++ ) { list.add( obj ); } } return list; } /** * Returns a {@link Collection} containing a - b. * The cardinality of each element e in the returned {@link Collection} * 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 ) { ArrayList list = new ArrayList( a ); for ( T aB : b ) { list.remove( aB ); } return list; } /** * Returns a {@link Map} mapping each unique element in * the given {@link Collection} to an {@link Integer} * representing the number of occurances of that element * 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 ) { HashMap count = new HashMap(); for ( E obj : col ) { Integer c = count.get( obj ); if ( null == c ) { count.put( obj, 1 ); } else { count.put( obj, c + 1 ); } } return count; } public static List iteratorToList( Iterator it ) { if ( it == null ) { throw new NullPointerException( "it cannot be null." ); } List list = new ArrayList(); while ( it.hasNext() ) { list.add( it.next() ); } return list; } // ---------------------------------------------------------------------- // // ---------------------------------------------------------------------- private static int getFreq( final E obj, final Map freqMap ) { try { Integer o = freqMap.get( obj ); if ( o != null ) // minimize NullPointerExceptions { return o; } } catch ( NullPointerException ignore ) { } catch ( NoSuchElementException ignore ) { } return 0; } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/DirectoryScanner.java000066400000000000000000000650131251077732300324000ustar00rootroot00000000000000/* * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.codehaus.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "Ant" and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact codehaus@codehaus.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . */ package org.codehaus.plexus.util; 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 * and exclude patterns. Only files/directories which match at least one * 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 * File.separator ('/' under UNIX, '\' under Windows). * 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 * to match must also start with a File.separator. * When a pattern does not start with a File.separator, the * 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"};
 *   String[] excludes = {"modules\\*\\**"};
 *   ds.setIncludes(includes);
 *   ds.setExcludes(excludes);
 *   ds.setBasedir(new File("test"));
 *   ds.setCaseSensitive(true);
 *   ds.scan();
 *
 *   System.out.println("FILES:");
 *   String[] files = ds.getIncludedFiles();
 *   for (int i = 0; i < files.length; i++) {
 *     System.out.println(files[i]);
 *   }
 * 
* This will scan a directory called test for .class files, but excludes all * files in all proper subdirectories of a directory called "modules" * * @author Arnout J. Kuiper * ajkuiper@wxs.nl * @author Magesh Umasankar * @author Bruce Atherton * @author Antoine Levy-Lambert */ public class DirectoryScanner extends AbstractScanner { /** * The base directory to be scanned. */ protected File basedir; /** * The files which matched at least one include and no excludes * and were selected. */ protected Vector filesIncluded; /** * 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; /** * The directories which matched at least one include and no excludes * and were selected. */ protected Vector dirsIncluded; /** * 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; /** * The files which matched at least one include and no excludes and * which a selector discarded. */ protected Vector filesDeselected; /** * The directories which matched at least one include and no excludes * but which a selector discarded. */ protected Vector dirsDeselected; /** * Whether or not our results were built by a slow scan. */ protected boolean haveSlowResults = false; /** * Whether or not symbolic links should be followed. * * @since Ant 1.5 */ private boolean followSymlinks = true; /** * Whether or not everything tested so far has been included. */ protected boolean everythingIncluded = true; private final String[] tokenizedEmpty = MatchPattern.tokenizePathToString( "", File.separator ); /** * Sole constructor. */ public DirectoryScanner() { } /** * Sets the base directory to be scanned. This is the directory which is * scanned recursively. All '/' and '\' characters are replaced by * File.separatorChar, so the separator used need not match * File.separatorChar. * * @param basedir The base directory to scan. * Must not be null. */ public void setBasedir( String basedir ) { setBasedir( new File( basedir.replace( '/', File.separatorChar ).replace( '\\', File.separatorChar ) ) ); } /** * Sets the base directory to be scanned. This is the directory which is * scanned recursively. * * @param basedir The base directory for scanning. * Should not be null. */ public void setBasedir( File basedir ) { this.basedir = basedir; } /** * Returns the base directory to be scanned. * This is the directory which is scanned recursively. * * @return the base directory to be scanned */ public File getBasedir() { return basedir; } /** * Sets whether or not symbolic links should be followed. * * @param followSymlinks whether or not symbolic links should be followed */ public void setFollowSymlinks( boolean followSymlinks ) { this.followSymlinks = followSymlinks; } /** * Returns whether or not the scanner has included all the files or * directories it has come across so far. * * @return true if all files and directories which have * been found so far have been included. */ public boolean isEverythingIncluded() { return everythingIncluded; } /** * Scans the base directory for files which match at least one include * pattern and don't match any exclude patterns. If there are selectors * then the files must pass muster there, as well. * * @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 { if ( basedir == null ) { throw new IllegalStateException( "No basedir set" ); } if ( !basedir.exists() ) { throw new IllegalStateException( "basedir " + basedir + " does not exist" ); } if ( !basedir.isDirectory() ) { throw new IllegalStateException( "basedir " + basedir + " is not a directory" ); } setupDefaultFilters(); 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( "", tokenizedEmpty ) ) { if ( isSelected( "", basedir ) ) { dirsIncluded.addElement( "" ); } else { dirsDeselected.addElement( "" ); } } else { dirsExcluded.addElement( "" ); } } else { dirsNotIncluded.addElement( "" ); } scandir( basedir, "", true ); } /** * Top level invocation for a slow scan. A slow scan builds up a full * 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() { if ( haveSlowResults ) { return; } String[] excl = new String[dirsExcluded.size()]; dirsExcluded.copyInto( excl ); String[] notIncl = new String[dirsNotIncluded.size()]; dirsNotIncluded.copyInto( notIncl ); for ( String anExcl : excl ) { if ( !couldHoldIncluded( anExcl ) ) { scandir( new File( basedir, anExcl ), anExcl + File.separator, false ); } } for ( String aNotIncl : notIncl ) { if ( !couldHoldIncluded( aNotIncl ) ) { scandir( new File( basedir, aNotIncl ), aNotIncl + File.separator, false ); } } haveSlowResults = true; } /** * Scans the given directory for files and directories. Found files and * directories are placed in their respective collections, based on the * matching of includes, excludes, and the selectors. When a directory * is found, it is scanned recursively. * * @param dir The directory to scan. Must not be null. * @param vpath The path relative to the base directory (needed to * 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. * @see #filesIncluded * @see #filesNotIncluded * @see #filesExcluded * @see #dirsIncluded * @see #dirsNotIncluded * @see #dirsExcluded * @see #slowScan */ protected void scandir( File dir, String vpath, boolean fast ) { String[] newfiles = dir.list(); if ( newfiles == null ) { /* * two reasons are mentioned in the API docs for File.list * (1) dir is not a directory. This is impossible as * we wouldn't get here in this case. * (2) an IO error occurred (why doesn't it throw an exception * 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... */ /* * [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. */ newfiles = new String[0]; // throw new IOException( "IO error scanning directory " + dir.getAbsolutePath() ); } if ( !followSymlinks ) { ArrayList noLinks = new ArrayList(); for ( String newfile : newfiles ) { try { if ( isParentSymbolicLink( dir, newfile ) ) { String name = vpath + newfile; File file = new File( dir, newfile ); if ( file.isDirectory() ) { dirsExcluded.addElement( name ); } else { filesExcluded.addElement( name ); } } else { noLinks.add( newfile ); } } catch ( IOException ioe ) { 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.add( newfile ); } } 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, tokenizedName ) ) { if ( !isExcluded( name, tokenizedName ) ) { if ( isSelected( name, file ) ) { dirsIncluded.addElement( name ); if ( fast ) { scandir( file, name + File.separator, fast ); } } else { everythingIncluded = false; dirsDeselected.addElement( name ); if ( fast && couldHoldIncluded( name ) ) { scandir( file, name + File.separator, fast ); } } } else { everythingIncluded = false; dirsExcluded.addElement( name ); if ( fast && couldHoldIncluded( name ) ) { scandir( file, name + File.separator, fast ); } } } else { everythingIncluded = false; dirsNotIncluded.addElement( name ); if ( fast && couldHoldIncluded( name ) ) { scandir( file, name + File.separator, fast ); } } if ( !fast ) { scandir( file, name + File.separator, fast ); } } else if ( file.isFile() ) { if ( isIncluded( name, tokenizedName ) ) { if ( !isExcluded( name, tokenizedName ) ) { if ( isSelected( name, file ) ) { filesIncluded.addElement( name ); } else { everythingIncluded = false; filesDeselected.addElement( name ); } } else { everythingIncluded = false; filesExcluded.addElement( name ); } } else { everythingIncluded = false; filesNotIncluded.addElement( name ); } } } } /** * Tests whether a name should be selected. * * @param name the filename to check for selecting * @param file the java.io.File object for this filename * @return false when the selectors says that the file * should not be selected, true otherwise. */ protected boolean isSelected( String name, File file ) { return true; } /** * Returns the names of the files which matched at least one of the * include patterns and none of the exclude patterns. * The names are relative to the base directory. * * @return the names of the files which matched at least one of the * include patterns and none of the exclude patterns. */ public String[] getIncludedFiles() { String[] files = new String[filesIncluded.size()]; filesIncluded.copyInto( files ); return files; } /** * Returns the names of the files which matched none of the include * patterns. 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 matched none of the include * patterns. * @see #slowScan */ public String[] getNotIncludedFiles() { slowScan(); String[] files = new String[filesNotIncluded.size()]; filesNotIncluded.copyInto( files ); return files; } /** * Returns the names of the files which matched at least one of the * include patterns and at least one of the exclude patterns. * 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 matched at least one of the * include patterns and at at least one of the exclude patterns. * @see #slowScan */ public String[] getExcludedFiles() { slowScan(); String[] files = new String[filesExcluded.size()]; filesExcluded.copyInto( files ); return files; } /** *

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() { slowScan(); String[] files = new String[filesDeselected.size()]; filesDeselected.copyInto( files ); return files; } /** * Returns the names of the directories which matched at least one of the * include patterns and none of the exclude patterns. * 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. */ public String[] getIncludedDirectories() { String[] directories = new String[dirsIncluded.size()]; dirsIncluded.copyInto( directories ); return directories; } /** * Returns the names of the directories which matched none of the include * patterns. 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 matched none of the include * patterns. * @see #slowScan */ public String[] getNotIncludedDirectories() { slowScan(); String[] directories = new String[dirsNotIncluded.size()]; dirsNotIncluded.copyInto( directories ); return directories; } /** * Returns the names of the directories which matched at least one of the * include patterns and at least one of the exclude patterns. * 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 matched at least one of the * include patterns and at least one of the exclude patterns. * @see #slowScan */ public String[] getExcludedDirectories() { slowScan(); String[] directories = new String[dirsExcluded.size()]; dirsExcluded.copyInto( directories ); return directories; } /** *

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() { slowScan(); String[] directories = new String[dirsDeselected.size()]; dirsDeselected.copyInto( directories ); return directories; } /** * 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. * @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 NioFiles.isSymbolicLink( parent ); } File resolvedParent = new File( parent.getCanonicalPath() ); File toTest = new File( resolvedParent, name ); return !toTest.getAbsolutePath().equals( toTest.getCanonicalPath() ); } /** * Checks whether the parent of this file is a symbolic link. *

* *

For java versions prior to 7 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. * @return true if it's a symbolic link * @throws java.io.IOException . * @since Ant 1.5 */ public boolean isParentSymbolicLink( File parent, String name ) throws IOException { if ( Java7Detector.isJava7() ) { return NioFiles.isSymbolicLink( parent ); } File resolvedParent = new File( parent.getCanonicalPath() ); File toTest = new File( resolvedParent, name ); return !toTest.getAbsolutePath().equals( toTest.getCanonicalPath() ); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/DirectoryWalkListener.java000066400000000000000000000025151251077732300334110ustar00rootroot00000000000000package 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; /** * Observes the actions of a {@link DirectoryWalker}. * @version $Id$ * @see DirectoryWalker */ public interface DirectoryWalkListener { /** * The directory walking has begun. * * @param basedir the basedir that walk started in. */ void directoryWalkStarting( File basedir ); /** * The included entry that was encountered. * * @param percentage rough percentage of the walk completed. (inaccurate) * @param file the file that was included. */ void directoryWalkStep( int percentage, File file ); /** * The directory walking has finished. */ void directoryWalkFinished(); void debug( String message ); } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/DirectoryWalker.java000066400000000000000000000254701251077732300322370ustar00rootroot00000000000000package 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.Iterator; import java.util.List; import java.util.Stack; /** * DirectoryWalker * @version $Id$ */ public class DirectoryWalker { /** * DirStackEntry is an Item on the {@link DirectoryWalker#dirStack} */ class DirStackEntry { /** * Count of files in the directory. */ public int count; /** * Current Directory. */ public File dir; /** * Index (or offset) within the directory count. */ public int index; /** * Offset for percentage calculations. Based on parent DirStackEntry. */ public double percentageOffset; /** * Size of percentage space to work with. */ public double percentageSize; /** * Create a DirStackEntry. * * @param d the directory to track * @param length the length of entries in the directory. */ public DirStackEntry( File d, int length ) { dir = d; count = length; } /** * Calculate the next percentage offset. * Used by the next DirStackEntry. * * @return the value for the next percentage offset. */ public double getNextPercentageOffset() { return percentageOffset + ( index * ( percentageSize / count ) ); } /** * Calculate the next percentage size. * Used by the next DirStackEntry. * * @return the value for the next percentage size. */ public double getNextPercentageSize() { return ( percentageSize / count ); } /** * The percentage of the DirStackEntry right now. * Based on count, index, percentageOffset, and percentageSize. * * @return the percentage right now. */ public int getPercentage() { double percentageWithinDir = (double) index / (double) count; return (int) Math.floor( percentageOffset + ( percentageWithinDir * percentageSize ) ); } public String toString() { return "DirStackEntry[" + "dir=" + dir.getAbsolutePath() + ",count=" + count + ",index=" + index + ",percentageOffset=" + percentageOffset + ",percentageSize=" + percentageSize + ",percentage()=" + getPercentage() + ",getNextPercentageOffset()=" + getNextPercentageOffset() + ",getNextPercentageSize()=" + getNextPercentageSize() + "]"; } } private File baseDir; private int baseDirOffset; private Stack dirStack; private List excludes; private List includes; private boolean isCaseSensitive = true; private List listeners; private boolean debugEnabled = false; public DirectoryWalker() { includes = new ArrayList(); excludes = new ArrayList(); listeners = new ArrayList(); } public void addDirectoryWalkListener( DirectoryWalkListener listener ) { listeners.add( listener ); } public void addExclude( String exclude ) { excludes.add( fixPattern( exclude ) ); } public void addInclude( String include ) { includes.add( fixPattern( include ) ); } /** * Add's to the Exclude List the default list of SCM excludes. */ public void addSCMExcludes() { String scmexcludes[] = DirectoryScanner.DEFAULTEXCLUDES; for ( String scmexclude : scmexcludes ) { addExclude( scmexclude ); } } private void fireStep( File file ) { DirStackEntry dsEntry = dirStack.peek(); int percentage = dsEntry.getPercentage(); for ( Object listener1 : listeners ) { DirectoryWalkListener listener = (DirectoryWalkListener) listener1; listener.directoryWalkStep( percentage, file ); } } private void fireWalkFinished() { for ( DirectoryWalkListener listener1 : listeners ) { listener1.directoryWalkFinished(); } } private void fireWalkStarting() { for ( DirectoryWalkListener listener1 : listeners ) { listener1.directoryWalkStarting( baseDir ); } } private void fireDebugMessage( String message ) { for ( DirectoryWalkListener listener1 : listeners ) { listener1.debug( message ); } } private String fixPattern( String pattern ) { String cleanPattern = pattern; if ( File.separatorChar != '/' ) { cleanPattern = cleanPattern.replace( '/', File.separatorChar ); } if ( File.separatorChar != '\\' ) { cleanPattern = cleanPattern.replace( '\\', File.separatorChar ); } return cleanPattern; } public void setDebugMode( boolean debugEnabled ) { this.debugEnabled = debugEnabled; } /** * @return Returns the baseDir. */ public File getBaseDir() { return baseDir; } /** * @return Returns the excludes. */ public List getExcludes() { return excludes; } /** * @return Returns the includes. */ public List getIncludes() { return includes; } private boolean isExcluded( String name ) { return isMatch( excludes, name ); } private boolean isIncluded( String name ) { return isMatch( includes, name ); } private boolean isMatch( List patterns, String name ) { for ( String pattern1 : patterns ) { if ( SelectorUtils.matchPath( pattern1, name, isCaseSensitive ) ) { return true; } } return false; } private String relativeToBaseDir( File file ) { return file.getAbsolutePath().substring( baseDirOffset + 1 ); } /** * Removes a DirectoryWalkListener. * * @param listener the listener to remove. */ public void removeDirectoryWalkListener( DirectoryWalkListener listener ) { listeners.remove( listener ); } /** * Performs a Scan against the provided {@link #setBaseDir(File)} */ public void scan() { if ( baseDir == null ) { throw new IllegalStateException( "Scan Failure. BaseDir not specified." ); } if ( !baseDir.exists() ) { throw new IllegalStateException( "Scan Failure. BaseDir does not exist." ); } if ( !baseDir.isDirectory() ) { throw new IllegalStateException( "Scan Failure. BaseDir is not a directory." ); } if ( includes.isEmpty() ) { // default to include all. addInclude( "**" ); } if ( debugEnabled ) { Iterator it; StringBuilder dbg = new StringBuilder(); dbg.append( "DirectoryWalker Scan" ); dbg.append( "\n Base Dir: " ).append( baseDir.getAbsolutePath() ); dbg.append( "\n Includes: " ); it = includes.iterator(); while ( it.hasNext() ) { String include = it.next(); dbg.append( "\n - \"" ).append( include ).append( "\"" ); } dbg.append( "\n Excludes: " ); it = excludes.iterator(); while ( it.hasNext() ) { String exclude = it.next(); dbg.append( "\n - \"" ).append( exclude ).append( "\"" ); } fireDebugMessage( dbg.toString() ); } fireWalkStarting(); dirStack = new Stack(); scanDir( baseDir ); fireWalkFinished(); } private void scanDir( File dir ) { File[] files = dir.listFiles(); if ( files == null ) { return; } DirectoryWalker.DirStackEntry curStackEntry = new DirectoryWalker.DirStackEntry( dir, files.length ); if ( dirStack.isEmpty() ) { curStackEntry.percentageOffset = 0; curStackEntry.percentageSize = 100; } else { DirectoryWalker.DirStackEntry previousStackEntry = (DirectoryWalker.DirStackEntry) dirStack.peek(); curStackEntry.percentageOffset = previousStackEntry.getNextPercentageOffset(); curStackEntry.percentageSize = previousStackEntry.getNextPercentageSize(); } dirStack.push( curStackEntry ); for ( int idx = 0; idx < files.length; idx++ ) { curStackEntry.index = idx; String name = relativeToBaseDir( files[idx] ); if ( isExcluded( name ) ) { fireDebugMessage( name + " is excluded." ); continue; } if ( files[idx].isDirectory() ) { scanDir( files[idx] ); } else { if ( isIncluded( name ) ) { fireStep( files[idx] ); } } } dirStack.pop(); } /** * @param baseDir The baseDir to set. */ public void setBaseDir( File baseDir ) { this.baseDir = baseDir; baseDirOffset = baseDir.getAbsolutePath().length(); } /** * @param entries The excludes to set. */ public void setExcludes( List entries ) { excludes.clear(); if ( entries != null ) { for ( String entry : entries ) { excludes.add( fixPattern( entry ) ); } } } /** * @param entries The includes to set. */ public void setIncludes( List entries ) { includes.clear(); if ( entries != null ) { for ( String entry : entries ) { includes.add( fixPattern( entry ) ); } } } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/ExceptionUtils.java000066400000000000000000000525431251077732300321050ustar00rootroot00000000000000/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2002-2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.codehaus.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Commons", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact codehaus@codehaus.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . */ package org.codehaus.plexus.util; import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.StringTokenizer; /** *

ExceptionUtils provides utilities for manipulating * Throwable objects.

* * @author Daniel Rall * @author Dmitri Plotnikov * @author Stephen Colebourne * @since 1.0 * @version $Id$ */ public class ExceptionUtils { /** * Used when printing stack frames to denote the start of a * wrapped exception. Package private for accessibility by test * suite. */ static final String WRAPPED_MARKER = " [wrapped] "; /** * The names of methods commonly used to access a wrapped * exception. */ protected static String[] CAUSE_METHOD_NAMES = { "getCause", "getNextException", "getTargetException", "getException", "getSourceException", "getRootCause", "getCausedByException", "getNested" }; /** * Constructs a new ExceptionUtils. Protected to * discourage instantiation. */ protected ExceptionUtils() { } /** *

Adds to the list of method names used in the search for Throwable * objects.

* * @param methodName the methodName to add to the list, null and empty strings are ignored */ public static void addCauseMethodName( String methodName ) { if ( methodName != null && methodName.length() > 0 ) { List list = new ArrayList( Arrays.asList( CAUSE_METHOD_NAMES ) ); list.add( methodName ); CAUSE_METHOD_NAMES = list.toArray( new String[list.size()] ); } } /** *

Introspects the specified Throwable to obtain the cause.

* *

The method searches for methods with specific names that return a * Throwable object. This will pick up most wrapping exceptions, * including those from JDK 1.4, and * The method names can be added to using {@link #addCauseMethodName(String)}. * The default list searched for are:

*
    *
  • getCause() *
  • getNextException() *
  • getTargetException() *
  • getException() *
  • getSourceException() *
  • getRootCause() *
  • getCausedByException() *
  • getNested() *
* *

In the absence of any such method, the object is inspected for a * detail field assignable to a Throwable.

* *

If none of the above is found, returns null.

* * @param throwable The exception to introspect for a cause. * @return The cause of the Throwable. * @throws NullPointerException if the throwable is null */ public static Throwable getCause( Throwable throwable ) { return getCause( throwable, CAUSE_METHOD_NAMES ); } /** *

Introspects the specified Throwable to obtain the cause * using a supplied array of method names.

* * @param throwable The exception to introspect for a cause. * @return The cause of the Throwable. * @throws NullPointerException if the method names array is null or contains null * @throws NullPointerException if the throwable is null */ public static Throwable getCause( Throwable throwable, String[] methodNames ) { Throwable cause = getCauseUsingWellKnownTypes( throwable ); if ( cause == null ) { for ( String methodName : methodNames ) { cause = getCauseUsingMethodName( throwable, methodName ); if ( cause != null ) { break; } } if ( cause == null ) { cause = getCauseUsingFieldName( throwable, "detail" ); } } return cause; } /** *

Walks through the exception chain to the last element -- the * "root" of the tree -- using {@link #getCause(Throwable)}, and * returns that exception.

* * @param throwable the throwable to get the root cause for * @return The root cause of the Throwable. */ public static Throwable getRootCause( Throwable throwable ) { Throwable cause = getCause( throwable ); if ( cause != null ) { throwable = cause; while ( ( throwable = getCause( throwable ) ) != null ) { cause = throwable; } } return cause; } /** *

Uses instanceof checks to examine the exception, * looking for well known types which could contain chained or * wrapped exceptions.

* * @param throwable the exception to examine * @return The wrapped exception, or null if not * found. */ private static Throwable getCauseUsingWellKnownTypes( Throwable throwable ) { if ( throwable instanceof SQLException ) { return ( (SQLException) throwable ).getNextException(); } else if ( throwable instanceof InvocationTargetException ) { return ( (InvocationTargetException) throwable ).getTargetException(); } else { return null; } } /** *

Find a throwable by method name.

* * @param throwable the exception to examine * @param methodName the name of the method to find and invoke * @return The wrapped exception, or null if not * found. */ private static Throwable getCauseUsingMethodName( Throwable throwable, String methodName ) { Method method = null; try { method = throwable.getClass().getMethod( methodName, null ); } catch ( NoSuchMethodException ignored ) { } catch ( SecurityException ignored ) { } if ( method != null && Throwable.class.isAssignableFrom( method.getReturnType() ) ) { try { return (Throwable) method.invoke( throwable, new Object[0] ); } catch ( IllegalAccessException ignored ) { } catch ( IllegalArgumentException ignored ) { } catch ( InvocationTargetException ignored ) { } } return null; } /** *

Find a throwable by field name.

* * @param throwable the exception to examine * @param fieldName the name of the attribute to examine * @return The wrapped exception, or null if not * found. */ private static Throwable getCauseUsingFieldName( Throwable throwable, String fieldName ) { Field field = null; try { field = throwable.getClass().getField( fieldName ); } catch ( NoSuchFieldException ignored ) { } catch ( SecurityException ignored ) { } if ( field != null && Throwable.class.isAssignableFrom( field.getType() ) ) { try { return (Throwable) field.get( throwable ); } catch ( IllegalAccessException ignored ) { } catch ( IllegalArgumentException ignored ) { } } return null; } /** *

Returns the number of Throwable objects in the * exception chain.

* * @param throwable the exception to inspect * @return The throwable count. */ public static int getThrowableCount( Throwable throwable ) { // Count the number of throwables int count = 0; while ( throwable != null ) { count++; throwable = ExceptionUtils.getCause( throwable ); } return count; } /** *

Returns the list of Throwable objects in the * exception chain.

* * @param throwable the exception to inspect * @return The list of Throwable objects. */ public static Throwable[] getThrowables( Throwable throwable ) { List list = new ArrayList(); while ( throwable != null ) { list.add( throwable ); throwable = getCause( throwable ); } return list.toArray( new Throwable[list.size()] ); } /** *

Delegates to {@link #indexOfThrowable(Throwable, Class, int)}, * starting the search at the beginning of the exception chain.

* * @see #indexOfThrowable(Throwable, Class, int) */ public static int indexOfThrowable( Throwable throwable, Class type ) { return indexOfThrowable( throwable, type, 0 ); } /** *

Returns the (zero based) index, of the first * Throwable that matches the specified type in the * exception chain of Throwable objects with an index * greater than or equal to the specified index, or * -1 if the type is not found.

* * @param throwable the exception to inspect * @param type Class to look for * @param fromIndex the (zero based) index of the starting * position in the chain to be searched * @return the first occurrence of the type in the chain, or * -1 if the type is not found * @throws IndexOutOfBoundsException If the fromIndex * argument is negative or not less than the count of * Throwables in the chain. */ public static int indexOfThrowable( Throwable throwable, Class type, int fromIndex ) { if ( fromIndex < 0 ) { throw new IndexOutOfBoundsException( "Throwable index out of range: " + fromIndex ); } Throwable[] throwables = ExceptionUtils.getThrowables( throwable ); if ( fromIndex >= throwables.length ) { throw new IndexOutOfBoundsException( "Throwable index out of range: " + fromIndex ); } for ( int i = fromIndex; i < throwables.length; i++ ) { if ( throwables[i].getClass().equals( type ) ) { return i; } } return -1; } /** * Prints a compact stack trace for the root cause of a throwable. * The compact stack trace starts with the root cause and prints * stack frames up to the place where it was caught and wrapped. * Then it prints the wrapped exception and continues with stack frames * until the wrapper exception is caught and wrapped again, etc. *

* The method is equivalent to t.printStackTrace() for throwables * that don't have nested causes. */ public static void printRootCauseStackTrace( Throwable t, PrintStream stream ) { String trace[] = getRootCauseStackTrace( t ); for ( String aTrace : trace ) { stream.println( aTrace ); } stream.flush(); } /** * Equivalent to printRootCauseStackTrace(t, System.err) */ public static void printRootCauseStackTrace( Throwable t ) { printRootCauseStackTrace( t, System.err ); } /** * Same as printRootCauseStackTrace(t, stream), except it takes * a PrintWriter as an argument. */ public static void printRootCauseStackTrace( Throwable t, PrintWriter writer ) { String trace[] = getRootCauseStackTrace( t ); for ( String aTrace : trace ) { writer.println( aTrace ); } writer.flush(); } /** * Creates a compact stack trace for the root cause of the supplied * throwable. * * See printRootCauseStackTrace(Throwable t, PrintStream s) */ public static String[] getRootCauseStackTrace( Throwable t ) { Throwable[] throwables = getThrowables( t ); int count = throwables.length; ArrayList frames = new ArrayList(); List nextTrace = getStackFrameList( throwables[count - 1] ); for ( int i = count; --i >= 0; ) { List trace = nextTrace; if ( i != 0 ) { nextTrace = getStackFrameList( throwables[i - 1] ); removeCommonFrames( trace, nextTrace ); } if ( i == ( count - 1 ) ) { frames.add( throwables[i].toString() ); } else { frames.add( WRAPPED_MARKER + throwables[i].toString() ); } for ( String aTrace : trace ) { frames.add( aTrace ); } } return frames.toArray( new String[frames.size()] ); } /** * Given two stack traces, removes common frames from the cause trace. * * @param causeFrames stack trace of a cause throwable * @param wrapperFrames stack trace of a wrapper throwable */ private static void removeCommonFrames( List causeFrames, List wrapperFrames ) { int causeFrameIndex = causeFrames.size() - 1; int wrapperFrameIndex = wrapperFrames.size() - 1; while ( causeFrameIndex >= 0 && wrapperFrameIndex >= 0 ) { // Remove the frame from the cause trace if it is the same // as in the wrapper trace String causeFrame = causeFrames.get( causeFrameIndex ); String wrapperFrame = wrapperFrames.get( wrapperFrameIndex ); if ( causeFrame.equals( wrapperFrame ) ) { causeFrames.remove( causeFrameIndex ); } causeFrameIndex--; wrapperFrameIndex--; } } /** * A convenient way of extracting the stack trace from an * exception. * * @param t The Throwable. * @return The stack trace as generated by the exception's * printStackTrace(PrintWriter) method. */ public static String getStackTrace( Throwable t ) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter( sw, true ); t.printStackTrace( pw ); return sw.getBuffer().toString(); } /** * A way to get the entire nested stack-trace of an throwable. * * @param t The Throwable. * @return The nested stack trace, with the root cause first. */ public static String getFullStackTrace( Throwable t ) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter( sw, true ); Throwable[] ts = getThrowables( t ); for ( Throwable t1 : ts ) { t1.printStackTrace( pw ); if ( isNestedThrowable( t1 ) ) { break; } } return sw.getBuffer().toString(); } /** * Whether an Throwable is considered nested or not. * * @param throwable The Throwable. * @return boolean true/false */ public static boolean isNestedThrowable( Throwable throwable ) { if ( throwable == null ) { return false; } if ( throwable instanceof SQLException ) { return true; } else if ( throwable instanceof InvocationTargetException ) { return true; } for ( String CAUSE_METHOD_NAME : CAUSE_METHOD_NAMES ) { try { Method method = throwable.getClass().getMethod( CAUSE_METHOD_NAME, null ); if ( method != null ) { return true; } } catch ( NoSuchMethodException ignored ) { } catch ( SecurityException ignored ) { } } try { Field field = throwable.getClass().getField( "detail" ); if ( field != null ) { return true; } } catch ( NoSuchFieldException ignored ) { } catch ( SecurityException ignored ) { } return false; } /** * Captures the stack trace associated with the specified * Throwable object, decomposing it into a list of * stack frames. * * @param t The Throwable. * @return An array of strings describing each stack frame. */ public static String[] getStackFrames( Throwable t ) { return getStackFrames( getStackTrace( t ) ); } /** * Functionality shared between the * getStackFrames(Throwable) methods of this and the * classes. */ static String[] getStackFrames( String stackTrace ) { String linebreak = System.getProperty( "line.separator" ); StringTokenizer frames = new StringTokenizer( stackTrace, linebreak ); List list = new LinkedList(); while ( frames.hasMoreTokens() ) { list.add( frames.nextToken() ); } return list.toArray( new String[list.size()]); } /** * Produces a List of stack frames - the message is not included. * This works in most cases - it will only fail if the exception message * contains a line that starts with: " at". * * @param t is any throwable * @return List of stack frames */ static List getStackFrameList( Throwable t ) { String stackTrace = getStackTrace( t ); String linebreak = System.getProperty( "line.separator" ); StringTokenizer frames = new StringTokenizer( stackTrace, linebreak ); List list = new LinkedList(); boolean traceStarted = false; while ( frames.hasMoreTokens() ) { String token = frames.nextToken(); // Determine if the line starts with at int at = token.indexOf( "at" ); if ( at != -1 && token.substring( 0, at ).trim().length() == 0 ) { traceStarted = true; list.add( token ); } else if ( traceStarted ) { break; } } return list; } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/Expand.java000066400000000000000000000162351251077732300303430ustar00rootroot00000000000000package org.codehaus.plexus.util; /* * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.codehaus.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Ant", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact codehaus@codehaus.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . */ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Date; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; /** * Unzip a file. * * @author costin@dnt.ro * @author Stefan Bodewig * @author Magesh Umasankar * @since Ant 1.1 @ant.task category="packaging" name="unzip" name="unjar" * name="unwar" * @version $Id$ */ public class Expand { private File dest;//req private File source;// req private boolean overwrite = true; /** * Do the work. * * @exception Exception Thrown in unrecoverable error. */ public void execute() throws Exception { expandFile( source, dest ); } /* * This method is to be overridden by extending unarchival tasks. */ /** * Description of the Method */ protected void expandFile( File srcF, File dir ) throws Exception { ZipInputStream zis = null; try { // code from WarExpand zis = new ZipInputStream( new FileInputStream( srcF ) ); ZipEntry ze = null; while ( ( ze = zis.getNextEntry() ) != null ) { extractFile( srcF, dir, zis, ze.getName(), new Date( ze.getTime() ), ze.isDirectory() ); } //log("expand complete", Project.MSG_VERBOSE); } catch ( IOException ioe ) { throw new Exception("Error while expanding " + srcF.getPath(), ioe); } finally { if ( zis != null ) { try { zis.close(); } catch ( IOException e ) { } } } } /** * Description of the Method */ protected void extractFile( File srcF, File dir, InputStream compressedInputStream, String entryName, Date entryDate, boolean isDirectory ) throws Exception { File f = FileUtils.resolveFile( dir, entryName ); try { if ( !overwrite && f.exists() && f.lastModified() >= entryDate.getTime() ) { return; } // create intermediary directories - sometimes zip don't add them File dirF = f.getParentFile(); dirF.mkdirs(); if ( isDirectory ) { f.mkdirs(); } else { byte[] buffer = new byte[1024]; int length = 0; FileOutputStream fos = null; try { fos = new FileOutputStream( f ); while ( ( length = compressedInputStream.read( buffer ) ) >= 0 ) { fos.write( buffer, 0, length ); } fos.close(); fos = null; } finally { if ( fos != null ) { try { fos.close(); } catch ( IOException e ) { } } } } f.setLastModified( entryDate.getTime() ); } catch ( FileNotFoundException ex ) { throw new Exception( "Can't extract file " + srcF.getPath(), ex ); } } /** * Set the destination directory. File will be unzipped into the destination * directory. * * @param d Path to the directory. */ public void setDest( File d ) { this.dest = d; } /** * Set the path to zip-file. * * @param s Path to zip-file. */ public void setSrc( File s ) { this.source = s; } /** * Should we overwrite files in dest, even if they are newer than the * corresponding entries in the archive? */ public void setOverwrite( boolean b ) { overwrite = b; } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/FastMap.java000066400000000000000000000735721251077732300304660ustar00rootroot00000000000000/* * J.A.D.E. Java(TM) Addition to Default Environment. * Latest release available at http://jade.dautelle.com/ * This class is public domain (not copyrighted). */ package org.codehaus.plexus.util; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.AbstractCollection; import java.util.AbstractSet; import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.Set; /** *

This class represents a Map collection with real-time * behavior. Unless the map's size exceeds its current capacity, * no dynamic memory allocation is ever performed and response time is * extremely fast and consistent.

* *

Our benchmark * indicates that {@link FastMap#put FastMap.put(key, value)} is up to * 5x faster than java.util.HashMap.put(key, value). * This difference is mostly due to the cost of the Map.Entry * allocations that {@link FastMap} avoids by recycling its entries * (see note below).

* *

{@link FastMap} has a predictable iteration order, which is the order * in which keys were inserted into the map (similar to * java.util.LinkedHashMap collection class).

* *

Applications may change the resizing policy of {@link FastMap} * by overriding the {@link #sizeChanged} method. For example, to improve * predictability, automatic resizing can be disabled.

* *

This implementation is not synchronized. Multiple threads accessing * or modifying the collection must be synchronized externally.

* *

Note: To avoid dynamic memory allocations, {@link FastMap} * maintains an internal pool of Map.Entry objects. The size * of the pool is determined by the map's capacity. When an entry is * removed from the map, it is automatically restored to the pool.

* *

This class is public domain (not copyrighted).

* * @author Jean-Marie Dautelle * @version 5.3, October 31 2003 */ public class FastMap implements Map, Cloneable, Serializable { /** * Holds the map's hash table. */ private transient EntryImpl[] _entries; /** * Holds the map's current capacity. */ private transient int _capacity; /** * Holds the hash code mask. */ private transient int _mask; /** * Holds the first pool entry (linked list). */ private transient EntryImpl _poolFirst; /** * Holds the first map entry (linked list). */ private transient EntryImpl _mapFirst; /** * Holds the last map entry (linked list). */ private transient EntryImpl _mapLast; /** * Holds the current size. */ private transient int _size; /** * Creates a {@link FastMap} with a capacity of 256 entries. */ public FastMap() { initialize(256); } /** * Creates a {@link FastMap}, copy of the specified Map. * If the specified map is not an instance of {@link FastMap}, the * newly created map has a capacity set to the specified map's size. * The copy has the same order as the original, regardless of the original * map's implementation:
     *     TreeMap dictionary = ...;
     *     FastMap dictionaryLookup = new FastMap(dictionary);
     * 
* * @param map the map whose mappings are to be placed in this map. */ public FastMap(Map map) { int capacity = (map instanceof FastMap) ? ((FastMap)map).capacity() : map.size(); initialize(capacity); putAll(map); } /** * Creates a {@link FastMap} with the specified capacity. Unless the * capacity is exceeded, operations on this map do not allocate entries. * For optimum performance, the capacity should be of the same order * of magnitude or larger than the expected map's size. * * @param capacity the number of buckets in the hash table; it also * defines the number of pre-allocated entries. */ public FastMap(int capacity) { initialize(capacity); } /** * Returns the number of key-value mappings in this {@link FastMap}. * * @return this map's size. */ public int size() { return _size; } /** * Returns the capacity of this {@link FastMap}. The capacity defines * the number of buckets in the hash table, as well as the maximum number * of entries the map may contain without allocating memory. * * @return this map's capacity. */ public int capacity() { return _capacity; } /** * Indicates if this {@link FastMap} contains no key-value mappings. * * @return true if this map contains no key-value mappings; * false otherwise. */ public boolean isEmpty() { return _size == 0; } /** * Indicates if this {@link FastMap} contains a mapping for the specified * key. * * @param key the key whose presence in this map is to be tested. * @return true if this map contains a mapping for the * specified key; false otherwise. * @throws NullPointerException if the key is null. */ public boolean containsKey(Object key) { EntryImpl entry = _entries[keyHash(key) & _mask]; while (entry != null) { if (key.equals(entry._key) ) { return true; } entry = entry._next; } return false; } /** * Indicates if this {@link FastMap} maps one or more keys to the * specified value. * * @param value the value whose presence in this map is to be tested. * @return true if this map maps one or more keys to the * specified value. * @throws NullPointerException if the key is null. */ public boolean containsValue(Object value) { EntryImpl entry = _mapFirst; while (entry != null) { if (value.equals(entry._value) ) { return true; } entry = entry._after; } return false; } /** * Returns the value to which this {@link FastMap} maps the specified key. * * @param key the key whose associated value is to be returned. * @return the value to which this map maps the specified key, * or null if there is no mapping for the key. * @throws NullPointerException if key is null. */ public V get(Object key) { EntryImpl entry = _entries[keyHash(key) & _mask]; while (entry != null) { if (key.equals(entry._key) ) { return entry._value; } entry = entry._next; } return null; } /** * Returns the entry with the specified key. * * @param key the key whose associated entry is to be returned. * @return the entry for the specified key or null if none. */ public Map.Entry getEntry(Object key) { EntryImpl entry = _entries[keyHash(key) & _mask]; while (entry != null) { if (key.equals(entry._key)) { return entry; } entry = entry._next; } return null; } /** * Associates the specified value with the specified key in this * {@link FastMap}. If the {@link FastMap} previously contained a mapping * for this key, the old value is replaced. * * @param key the key with which the specified value is to be associated. * @param value the value to be associated with the specified key. * @return the previous value associated with specified key, * or null if there was no mapping for key. * A null return can also indicate that the map * previously associated null with the specified key. * @throws NullPointerException if the key is null. */ public Object put(Object key, Object value) { EntryImpl entry = _entries[keyHash(key) & _mask]; while (entry != null) { if (key.equals(entry._key) ) { Object prevValue = entry._value; entry._value = value; return prevValue; } entry = entry._next; } // No previous mapping. addEntry(key, value); return null; } /** * Copies all of the mappings from the specified map to this * {@link FastMap}. * * @param map the mappings to be stored in this map. * @throws NullPointerException the specified map is null, or * the specified map contains null keys. */ public void putAll(Map map) { for ( Entry entry : map.entrySet() ) { addEntry( entry.getKey(), entry.getValue() ); } } /** * Removes the mapping for this key from this {@link FastMap} if present. * * @param key the key whose mapping is to be removed from the map. * @return previous value associated with specified key, * or null if there was no mapping for key. * A null return can also indicate that the map * previously associated null with the specified key. * @throws NullPointerException if the key is null. */ public V remove(Object key) { EntryImpl entry = _entries[keyHash(key) & _mask]; while (entry != null) { if (key.equals(entry._key) ) { V prevValue = entry._value; removeEntry(entry); return prevValue; } entry = entry._next; } return null; } /** * Removes all mappings from this {@link FastMap}. */ public void clear() { // Clears all keys, values and buckets linked lists. for (EntryImpl entry = _mapFirst; entry != null; entry = entry._after) { entry._key = null; entry._value = null; entry._before = null; entry._next = null; if (entry._previous == null) { // First in bucket. _entries[entry._index] = null; } else { entry._previous = null; } } // Recycles all entries. if (_mapLast != null) { _mapLast._after = _poolFirst; // Connects to pool. _poolFirst = _mapFirst; _mapFirst = null; _mapLast = null; _size = 0; sizeChanged(); } } /** * Changes the current capacity of this {@link FastMap}. If the capacity * is increased, new entries are allocated and added to the pool. * If the capacity is decreased, entries from the pool are deallocated * (and are eventually garbage collected). The capacity also determined * the number of buckets for the hash table. * * @param newCapacity the new capacity of this map. */ public void setCapacity(int newCapacity) { if (newCapacity > _capacity) { // Capacity increases. for (int i = _capacity; i < newCapacity; i++) { EntryImpl entry = new EntryImpl(); entry._after = _poolFirst; _poolFirst = entry; } } else if (newCapacity < _capacity) { // Capacity decreases. for ( int i = newCapacity; (i < _capacity) && (_poolFirst != null); i++) { // Disconnects the entry for gc to do its work. EntryImpl entry = _poolFirst; _poolFirst = entry._after; entry._after = null; // All pointers are now null! } } // Find a power of 2 >= capacity int tableLength = 16; while (tableLength < newCapacity) { tableLength <<= 1; } // Checks if the hash table has to be re-sized. if (_entries.length != tableLength) { _entries = new EntryImpl[tableLength]; _mask = tableLength - 1; // Repopulates the hash table. EntryImpl entry = _mapFirst; while (entry != null) { int index = keyHash(entry._key) & _mask; entry._index = index; // Connects to bucket. entry._previous = null; // Resets previous. EntryImpl next = _entries[index]; entry._next = next; if (next != null) { next._previous = entry; } _entries[index] = entry; entry = entry._after; } } _capacity = newCapacity; } /** * Returns a shallow copy of this {@link FastMap}. The keys and * the values themselves are not cloned. * * @return a shallow copy of this map. */ public Object clone() { try { FastMap clone = (FastMap) super.clone(); clone.initialize(_capacity); clone.putAll(this); return clone; } catch (CloneNotSupportedException e) { // Should not happen, since we are Cloneable. throw new InternalError(); } } /** * Compares the specified object with this {@link FastMap} for equality. * Returns true if the given object is also a map and the two * maps represent the same mappings (regardless of collection iteration * order). * * @param obj the object to be compared for equality with this map. * @return true if the specified object is equal to this map; * false otherwise. */ public boolean equals(Object obj) { if (obj == this) { return true; } else if (obj instanceof Map) { Map that = (Map) obj; if (this.size() == that.size()) { EntryImpl entry = _mapFirst; while (entry != null) { if (!that.entrySet().contains(entry)) { return false; } entry = entry._after; } return true; } else { return false; } } else { return false; } } /** * Returns the hash code value for this {@link FastMap}. * * @return the hash code value for this map. */ public int hashCode() { int code = 0; EntryImpl entry = _mapFirst; while (entry != null) { code += entry.hashCode(); entry = entry._after; } return code; } /** * Returns a String representation of this {@link FastMap}. * * @return this.entrySet().toString(); */ public String toString() { return entrySet().toString(); } /** * Returns a collection view of the values contained in this * {@link FastMap}. The collection is backed by the map, so changes to * the map are reflected in the collection, and vice-versa. * The collection supports element removal, which removes the corresponding * mapping from this map, via the * Iterator.remove, Collection.remove, * removeAll, retainAll, * and clear operations. It does not support the * add or addAll operations. * * @return a collection view of the values contained in this map. */ public Collection values() { return _values; } private transient Values _values; private class Values extends AbstractCollection { public Iterator iterator() { return new Iterator() { EntryImpl after = _mapFirst; EntryImpl before; public void remove() { removeEntry(before); } public boolean hasNext() { return after != null; } public Object next() { before = after; after = after._after; return before._value; } }; } public int size() { return _size; } public boolean contains(Object o) { return containsValue(o); } public void clear() { FastMap.this.clear(); } } /** * Returns a collection view of the mappings contained in this * {@link FastMap}. Each element in the returned collection is a * Map.Entry. The collection is backed by the map, * so changes to the map are reflected in the collection, and vice-versa. * The collection supports element removal, which removes the corresponding * mapping from this map, via the * Iterator.remove, Collection.remove, * removeAll, retainAll, * and clear operations. It does not support the * add or addAll operations. * * @return a collection view of the mappings contained in this map. */ public Set entrySet() { return _entrySet; } private transient EntrySet _entrySet; private class EntrySet extends AbstractSet { public Iterator iterator() { return new Iterator() { EntryImpl after = _mapFirst; EntryImpl before; public void remove() { removeEntry(before); } public boolean hasNext() { return after != null; } public Object next() { before = after; after = after._after; return before; } }; } public int size() { return _size; } public boolean contains(Object obj) { // Optimization. if (obj instanceof Map.Entry) { Map.Entry entry = (Map.Entry) obj; Map.Entry mapEntry = getEntry(entry.getKey()); return entry.equals(mapEntry); } else { return false; } } public boolean remove(Object obj) { // Optimization. if (obj instanceof Map.Entry) { Map.Entry entry = (Map.Entry)obj; EntryImpl mapEntry = (EntryImpl) getEntry(entry.getKey()); if ((mapEntry != null) && (entry.getValue()).equals(mapEntry._value)) { removeEntry(mapEntry); return true; } } return false; } } /** * Returns a set view of the keys contained in this {@link FastMap}. * The set is backed by the map, so changes to the map are reflected * in the set, and vice-versa. The set supports element removal, * which removes the corresponding mapping from this map, via the * Iterator.remove, Collection.remove, * removeAll, retainAll, * and clear operations. It does not support the * add or addAll operations. * * @return a set view of the keys contained in this map. */ public Set keySet() { return _keySet; } private transient KeySet _keySet; private class KeySet extends AbstractSet { public Iterator iterator() { return new Iterator() { EntryImpl after = _mapFirst; EntryImpl before; public void remove() { removeEntry(before); } public boolean hasNext() { return after != null; } public Object next() { before = after; after = after._after; return before._key; } }; } public int size() { return _size; } public boolean contains(Object obj) { // Optimization. return FastMap.this.containsKey(obj); } public boolean remove(Object obj) { // Optimization. return FastMap.this.remove(obj) != null; } public void clear() { // Optimization. FastMap.this.clear(); } } /** * This methods is being called when the size of this {@link FastMap} * has changed. The default behavior is to double the map's capacity * when the map's size reaches the current map's capacity. * Sub-class may override this method to implement custom resizing * policies or to disable automatic resizing. For example:
     *     Map fixedCapacityMap = new FastMap(256) { 
     *           protected sizeChanged() {
     *               // Do nothing, automatic resizing disabled.
     *           }
     *     };
* @see #setCapacity */ protected void sizeChanged() { if (size() > capacity()) { setCapacity(capacity() * 2); } } /** * Returns the hash code for the specified key. The formula being used * is identical to the formula used by java.util.HashMap * (ensures similar behavior for ill-conditioned hashcode keys). * * @param key the key to calculate the hashcode for. * @return the hash code for the specified key. */ private static int keyHash(Object key) { // From HashMap.hash(Object) function. int hashCode = key.hashCode(); hashCode += ~(hashCode << 9); hashCode ^= (hashCode >>> 14); hashCode += (hashCode << 4); hashCode ^= (hashCode >>> 10); return hashCode; } /** * Adds a new entry for the specified key and value. * @param key the entry's key. * @param value the entry's value. */ private void addEntry(Object key, Object value) { EntryImpl entry = _poolFirst; if (entry != null) { _poolFirst = entry._after; entry._after = null; } else { // Pool empty. entry = new EntryImpl(); } // Setup entry paramters. entry._key = key; entry._value = value; int index = keyHash(key) & _mask; entry._index = index; // Connects to bucket. EntryImpl next = _entries[index]; entry._next = next; if (next != null) { next._previous = entry; } _entries[index] = entry; // Connects to collection. if (_mapLast != null) { entry._before = _mapLast; _mapLast._after = entry; } else { _mapFirst = entry; } _mapLast = entry; // Updates size. _size++; sizeChanged(); } /** * Removes the specified entry from the map. * * @param entry the entry to be removed. */ private void removeEntry(EntryImpl entry) { // Removes from bucket. EntryImpl previous = entry._previous; EntryImpl next = entry._next; if (previous != null) { previous._next = next; entry._previous = null; } else { // First in bucket. _entries[entry._index] = next; } if (next != null) { next._previous = previous; entry._next = null; } // Else do nothing, no last pointer. // Removes from collection. EntryImpl before = entry._before; EntryImpl after = entry._after; if (before != null) { before._after = after; entry._before = null; } else { // First in collection. _mapFirst = after; } if (after != null) { after._before = before; } else { // Last in collection. _mapLast = before; } // Clears value and key. entry._key = null; entry._value = null; // Recycles. entry._after = _poolFirst; _poolFirst = entry; // Updates size. _size--; sizeChanged(); } /** * Initializes this instance for the specified capacity. * Once initialized, operations on this map should not create new objects * (unless the map's size exceeds the specified capacity). * * @param capacity the initial capacity. */ private void initialize(int capacity) { // Find a power of 2 >= capacity int tableLength = 16; while (tableLength < capacity) { tableLength <<= 1; } // Allocates hash table. _entries = new EntryImpl[tableLength]; _mask = tableLength - 1; _capacity = capacity; _size = 0; // Allocates views. _values = new Values(); _entrySet = new EntrySet(); _keySet = new KeySet(); // Resets pointers. _poolFirst = null; _mapFirst = null; _mapLast = null; // Allocates entries. for (int i=0; i < capacity; i++) { EntryImpl entry = new EntryImpl(); entry._after = _poolFirst; _poolFirst = entry; } } /** * Requires special handling during de-serialization process. * * @param stream the object input stream. * @throws IOException if an I/O error occurs. * @throws ClassNotFoundException if the class for the object de-serialized * is not found. */ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { int capacity = stream.readInt(); initialize(capacity); int size = stream.readInt(); for (int i=0; i < size; i++) { Object key = stream.readObject(); Object value = stream.readObject(); addEntry(key, value); } } /** * Requires special handling during serialization process. * * @param stream the object output stream. * @throws IOException if an I/O error occurs. */ private void writeObject(ObjectOutputStream stream) throws IOException { stream.writeInt(_capacity); stream.writeInt(_size); int count = 0; EntryImpl entry = _mapFirst; while (entry != null) { stream.writeObject(entry._key); stream.writeObject(entry._value); count++; entry = entry._after; } if (count != _size) { throw new IOException("FastMap Corrupted"); } } /** * This class represents a {@link FastMap} entry. */ private static final class EntryImpl implements Map.Entry { /** * Holds the entry key (null when in pool). */ private K _key; /** * Holds the entry value (null when in pool). */ private V _value; /** * Holds the bucket index (undefined when in pool). */ private int _index; /** * Holds the previous entry in the same bucket (null when in pool). */ private EntryImpl _previous; /** * Holds the next entry in the same bucket (null when in pool). */ private EntryImpl _next; /** * Holds the entry added before this entry (null when in pool). */ private EntryImpl _before; /** * Holds the entry added after this entry * or the next available entry when in pool. */ private EntryImpl _after; /** * Returns the key for this entry. * * @return the entry's key. */ public K getKey() { return _key; } /** * Returns the value for this entry. * * @return the entry's value. */ public V getValue() { return _value; } /** * Sets the value for this entry. * * @param value the new value. * @return the previous value. */ public V setValue(V value) { V old = _value; _value = value; return old; } /** * Indicates if this entry is considered equals to the specified * entry. * * @param that the object to test for equality. * @return true if both entry are considered equal; * false otherwise. */ public boolean equals(Object that) { if (that instanceof Map.Entry) { Map.Entry entry = (Map.Entry) that; return (_key.equals(entry.getKey())) && ((_value != null) ? _value.equals(entry.getValue()) : (entry.getValue() == null)); } else { return false; } } /** * Returns the hash code for this entry. * * @return this entry's hash code. */ public int hashCode() { return _key.hashCode() ^ ((_value != null) ? _value.hashCode() : 0); } /** * Returns the text representation of this entry. * * @return this entry's textual representation. */ public String toString() { return _key + "=" + _value; } } }plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/FileUtils.java000066400000000000000000002303731251077732300310250ustar00rootroot00000000000000package org.codehaus.plexus.util; /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.codehaus.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" and * "Apache Turbine" must not be used to endorse or promote products * derived from this software without prior written permission. For * written permission, please contact codehaus@codehaus.org. * * 5. Products derived from this software may not be called "Apache", * "Apache Turbine", nor may "Apache" appear in their name, without * prior written permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * */ 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; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; 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.List; import java.util.Random; /** * This class provides basic facilities for manipulating files and file paths. *

*

Path-related methods

*

*

Methods exist to retrieve the components of a typical file path. For example * /www/hosted/mysite/index.html, can be broken into: *

    *
  • /www/hosted/mysite/ -- retrievable through {@link #getPath}
  • *
  • index.html -- retrievable through {@link #removePath}
  • *
  • /www/hosted/mysite/index -- retrievable through {@link #removeExtension}
  • *
  • html -- retrievable through {@link #getExtension}
  • *
* There are also methods to {@link #catPath concatenate two paths}, {@link #resolveFile resolve a * path relative to a File} and {@link #normalize} a path. *

*

*

File-related methods

*

* There are methods to create a {@link #toFile File from a URL}, copy a * {@link #copyFileToDirectory File to a directory}, * copy a {@link #copyFile File to another File}, * copy a {@link #copyURLToFile URL's contents to a File}, * as well as methods to {@link #deleteDirectory(File) delete} and {@link #cleanDirectory(File) * clean} a directory. *

*

* Common {@link java.io.File} manipulation routines. *

* Taken from the commons-utils repo. * Also code from Alexandria's FileUtils. * And from Avalon Excalibur's IO. * And from Ant. * * @author Kevin A. Burton * @author Scott Sanders * @author Daniel Rall * @author Christoph.Reck * @author Peter Donald * @author Jeff Turner * @version $Id$ */ public class FileUtils { /** * The number of bytes in a kilobyte. */ public static final int ONE_KB = 1024; /** * The number of bytes in a megabyte. */ public static final int ONE_MB = ONE_KB * ONE_KB; /** * The number of bytes in a gigabyte. */ public static final int ONE_GB = ONE_KB * ONE_MB; /** * 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 */ private static final String[] INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME = { ":", "*", "?", "\"", "<", ">", "|" }; /** * @return the default excludes pattern * @see DirectoryScanner#DEFAULTEXCLUDES */ public static String[] getDefaultExcludes() { return DirectoryScanner.DEFAULTEXCLUDES; } /** * @return the default excludes pattern as list. * @see #getDefaultExcludes() */ public static List getDefaultExcludesAsList() { return Arrays.asList( getDefaultExcludes() ); } /** * @return the default excludes pattern as comma separated string. * @see DirectoryScanner#DEFAULTEXCLUDES * @see StringUtils#join(Object[], String) */ public static String getDefaultExcludesAsString() { return StringUtils.join( DirectoryScanner.DEFAULTEXCLUDES, "," ); } /** * Returns a human-readable version of the file size (original is in * bytes). * * @param size The number of bytes. * @return A human-readable display value (includes units). */ public static String byteCountToDisplaySize( int size ) { String displaySize; if ( size / ONE_GB > 0 ) { displaySize = String.valueOf( size / ONE_GB ) + " GB"; } else if ( size / ONE_MB > 0 ) { displaySize = String.valueOf( size / ONE_MB ) + " MB"; } else if ( size / ONE_KB > 0 ) { displaySize = String.valueOf( size / ONE_KB ) + " KB"; } else { displaySize = String.valueOf( size ) + " bytes"; } return displaySize; } /** * Returns the directory path portion of a file specification string. * Matches the equally named unix command. * * @param filename the file path * @return The directory portion excluding the ending file separator. */ public static String dirname( String filename ) { int i = filename.lastIndexOf( File.separator ); return ( i >= 0 ? filename.substring( 0, i ) : "" ); } /** * Returns the filename portion of a file specification string. * * @param filename the file path * @return The filename string with extension. */ public static String filename( String filename ) { int i = filename.lastIndexOf( File.separator ); return ( i >= 0 ? filename.substring( i + 1 ) : filename ); } /** * Returns the filename portion of a file specification string. * Matches the equally named unix command. * * @param filename the file path * @return The filename string without extension. */ public static String basename( String filename ) { return basename( filename, extension( filename ) ); } /** * Returns the filename portion of a file specification string. * Matches the equally named unix command. * * @param filename the file path * @param suffix the file suffix * @return the basename of the file */ public static String basename( String filename, String suffix ) { int i = filename.lastIndexOf( File.separator ) + 1; int lastDot = ( ( suffix != null ) && ( suffix.length() > 0 ) ) ? filename.lastIndexOf( suffix ) : -1; if ( lastDot >= 0 ) { return filename.substring( i, lastDot ); } else if ( i > 0 ) { return filename.substring( i ); } else { return filename; // else returns all (no path and no extension) } } /** * Returns the extension portion of a file specification string. * This everything after the last dot '.' in the filename (NOT including * the dot). * * @param filename the file path * @return the extension of the file */ public static String extension( String filename ) { // Ensure the last dot is after the last file separator int lastSep = filename.lastIndexOf( File.separatorChar ); int lastDot; if ( lastSep < 0 ) { lastDot = filename.lastIndexOf( '.' ); } else { lastDot = filename.substring( lastSep + 1 ).lastIndexOf( '.' ); if ( lastDot >= 0 ) { lastDot += lastSep + 1; } } if ( lastDot >= 0 && lastDot > lastSep ) { return filename.substring( lastDot + 1 ); } return ""; } /** * Check if a file exits. * * @param fileName the file path. * @return true if file exists. */ public static boolean fileExists( String fileName ) { File file = new File( fileName ); return file.exists(); } /** * Note: the file content is read with platform encoding. * * @param file the file path * @return the file content using the platform encoding. * @throws IOException if any */ public static String fileRead( String file ) throws IOException { return fileRead( file, null ); } /** * @param file the file path * @param encoding the wanted encoding * @return the file content using the specified encoding. * @throws IOException if any */ public static String fileRead( String file, String encoding ) throws IOException { return fileRead( new File( file ), encoding ); } /** * Note: the file content is read with platform encoding * * @param file the file path * @return the file content using the platform encoding. * @throws IOException if any */ public static String fileRead( File file ) throws IOException { return fileRead( file, null ); } /** * @param file the file path * @param encoding the wanted encoding * @return the file content using the specified encoding. * @throws IOException if any */ public static String fileRead( File file, String encoding ) throws IOException { StringBuilder buf = new StringBuilder(); Reader reader = null; try { if ( encoding != null ) { reader = new InputStreamReader( new FileInputStream( file ), encoding ); } else { reader = new InputStreamReader( new FileInputStream( file ) ); } int count; char[] b = new char[512]; while ( ( count = reader.read( b ) ) > 0 ) // blocking read { buf.append( b, 0, count ); } } finally { IOUtil.close( reader ); } return buf.toString(); } /** * Appends data to a file. The file will be created if it does not exist. * 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. * @throws IOException if any */ public static void fileAppend( String fileName, String data ) throws IOException { fileAppend( fileName, null, data ); } /** * Appends data to a file. The file will be created if it does not exist. * * @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. * @throws IOException if any */ public static void fileAppend( String fileName, String encoding, String data ) throws IOException { FileOutputStream out = null; try { out = new FileOutputStream( fileName, true ); if ( encoding != null ) { out.write( data.getBytes( encoding ) ); } else { out.write( data.getBytes() ); } } finally { IOUtil.close( out ); } } /** * Writes data to a file. The file will be created if it does not exist. * 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. * @throws IOException if any */ public static void fileWrite( String fileName, String data ) throws IOException { fileWrite( fileName, null, data ); } /** * Writes data to a file. The file will be created if it does not exist. * * @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. * @throws IOException if any */ public static void fileWrite( String fileName, String encoding, String data ) throws IOException { 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 { OutputStream out = new FileOutputStream( file ); if ( encoding != null ) { writer = new OutputStreamWriter( out, encoding ); } else { writer = new OutputStreamWriter( out ); } writer.write( data ); } finally { IOUtil.close( writer ); } } /** * Deletes a file. * * @param fileName The path of the file to delete. */ public static void fileDelete( String fileName ) { File file = new File( fileName ); if (Java7Detector.isJava7()) { try { NioFiles.deleteIfExists(file); } catch ( IOException e ) { throw new RuntimeException( e ); } } else { file.delete(); } } /** * Waits for NFS to propagate a file creation, imposing a timeout. * * @param fileName The path of the file. * @param seconds The maximum time in seconds to wait. * @return True if file exists. */ public static boolean waitFor( String fileName, int seconds ) { return waitFor( new File( fileName ), 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. * @return True if file exists. */ public static boolean waitFor( File file, int seconds ) { int timeout = 0; int tick = 0; while ( !file.exists() ) { if ( tick++ >= 10 ) { tick = 0; if ( timeout++ > seconds ) { return false; } } try { Thread.sleep( 100 ); } catch ( InterruptedException ignore ) { // nop } } return true; } /** * Creates a file handle. * * @param fileName The path of the file. * @return A File manager. */ public static File getFile( String fileName ) { return new File( fileName ); } /** * Given a directory and an array of extensions return an array of compliant files. *

* TODO Should an ignore list be passed in? * TODO Should a recurse flag be passed in? *

* The given extensions should be like "java" and not like ".java" * * @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 ) { List files = new ArrayList(); File currentDir = new File( directory ); String[] unknownFiles = currentDir.list(); if ( unknownFiles == null ) { return new String[0]; } for ( String unknownFile : unknownFiles ) { String currentFileName = directory + System.getProperty( "file.separator" ) + unknownFile; File currentFile = new File( currentFileName ); if ( currentFile.isDirectory() ) { //ignore all CVS directories... if ( currentFile.getName().equals( "CVS" ) ) { continue; } //ok... transverse into this directory and get all the files... then combine //them with the current list. String[] fetchFiles = getFilesFromExtension( currentFileName, extensions ); files = blendFilesToVector( files, fetchFiles ); } else { //ok... add the file String add = currentFile.getAbsolutePath(); if ( isValidFile( add, extensions ) ) { files.add( add ); } } } //ok... move the Vector into the files list... String[] foundFiles = new String[files.size()]; files.toArray( foundFiles ); return foundFiles; } /** * Private helper method for getFilesFromExtension() */ private static List blendFilesToVector( List v, String[] files ) { for ( String file : files ) { v.add( file ); } return v; } /** * Checks to see if a file is of a particular type(s). * Note that if the file does not have an extension, an empty string * ("") is matched for. */ private static boolean isValidFile( String file, String[] extensions ) { String extension = extension( file ); if ( extension == null ) { extension = ""; } //ok.. now that we have the "extension" go through the current know //excepted extensions and determine if this one is OK. for ( String extension1 : extensions ) { if ( extension1.equals( extension ) ) { return true; } } return false; } /** * Simple way to make a directory * * @param dir the directory to create * @throws IllegalArgumentException if the dir contains illegal Windows characters under Windows OS. * @see #INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME */ public static void mkdir( String dir ) { File file = new File( dir ); if ( Os.isFamily( Os.FAMILY_WINDOWS ) && !isValidWindowsFileName( file ) ) { 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() ) { file.mkdirs(); } } /** * Compare the contents of two files to determine if they are equal or not. * * @param file1 the first file * @param file2 the second file * @return true if the content of the files are equal or they both don't exist, false otherwise * @throws IOException if any */ public static boolean contentEquals( final File file1, final File file2 ) throws IOException { final boolean file1Exists = file1.exists(); if ( file1Exists != file2.exists() ) { return false; } if ( !file1Exists ) { // two not existing files are equal return true; } if ( file1.isDirectory() || file2.isDirectory() ) { // don't want to compare directory contents return false; } InputStream input1 = null; InputStream input2 = null; try { input1 = new FileInputStream( file1 ); input2 = new FileInputStream( file2 ); return IOUtil.contentEquals( input1, input2 ); } finally { IOUtil.close( input1 ); IOUtil.close( input2 ); } } /** * Convert from a URL to a File. * * @param url File URL. * @return The equivalent File object, or null if the URL's protocol * is not file */ public static File toFile( final URL url ) { if ( url == null || !url.getProtocol().equalsIgnoreCase( "file" ) ) { return null; } String filename = url.getFile().replace( '/', File.separatorChar ); int pos = -1; while ( ( pos = filename.indexOf( '%', pos + 1 ) ) >= 0 ) { if ( pos + 2 < filename.length() ) { String hexStr = filename.substring( pos + 1, pos + 3 ); char ch = (char) Integer.parseInt( hexStr, 16 ); filename = filename.substring( 0, pos ) + ch + filename.substring( pos + 3 ); } } return new File( filename ); } /** * Convert the array of Files into a list of URLs. * * @param files the array of files * @return the array of URLs * @throws IOException if an error occurs */ public static URL[] toURLs( final File[] files ) throws IOException { final URL[] urls = new URL[files.length]; for ( int i = 0; i < urls.length; i++ ) { urls[i] = files[i].toURL(); } return urls; } /** * Remove extension from filename. * ie *

     * foo.txt    --> foo
     * a\b\c.jpg --> a\b\c
     * a\b\c     --> a\b\c
     * 
* * @param filename the path of the file * @return the filename minus extension */ public static String removeExtension( final String filename ) { String ext = extension( filename ); if ( "".equals( ext ) ) { return filename; } final int index = filename.lastIndexOf( ext ) - 1; return filename.substring( 0, index ); } /** * Get extension from filename. * ie *
     * foo.txt    --> "txt"
     * a\b\c.jpg --> "jpg"
     * a\b\c     --> ""
     * 
* * @param filename the path of the file * @return the extension of filename or "" if none */ public static String getExtension( final String filename ) { return extension( filename ); } /** * Remove path from filename. Equivalent to the unix command basename * ie. *
     * a/b/c.txt --> c.txt
     * a.txt     --> a.txt
     * 
* * @param filepath the path of the file * @return the filename minus path */ public static String removePath( final String filepath ) { return removePath( filepath, File.separatorChar ); } /** * Remove path from filename. * ie. *
     * a/b/c.txt --> c.txt
     * a.txt     --> a.txt
     * 
* * @param filepath the path of the file * @param fileSeparatorChar the file separator character like / on Unix plateforms. * @return the filename minus path */ public static String removePath( final String filepath, final char fileSeparatorChar ) { final int index = filepath.lastIndexOf( fileSeparatorChar ); if ( -1 == index ) { return filepath; } return filepath.substring( index + 1 ); } /** * Get path from filename. Roughly equivalent to the unix command dirname. * ie. *
     * a/b/c.txt --> a/b
     * a.txt     --> ""
     * 
* * @param filepath the filepath * @return the filename minus path */ public static String getPath( final String filepath ) { return getPath( filepath, File.separatorChar ); } /** * Get path from filename. * ie. *
     * a/b/c.txt --> a/b
     * a.txt     --> ""
     * 
* * @param filepath the filepath * @param fileSeparatorChar the file separator character like / on Unix plateforms. * @return the filename minus path */ public static String getPath( final String filepath, final char fileSeparatorChar ) { final int index = filepath.lastIndexOf( fileSeparatorChar ); if ( -1 == index ) { return ""; } return filepath.substring( 0, index ); } /** * Copy file from source to destination. If destinationDirectory does not exist, it * (and any parent directories) will be created. If a file source in * destinationDirectory exists, it will be overwritten. * * @param source An existing File to copy. * @param destinationDirectory A directory to copy source into. * @throws java.io.FileNotFoundException if source isn't a normal file. * @throws IllegalArgumentException if destinationDirectory isn't a directory. * @throws IOException if source does not exist, the file in * destinationDirectory cannot be written to, or an IO error occurs during copying. */ public static void copyFileToDirectory( final String source, final String destinationDirectory ) throws IOException { copyFileToDirectory( new File( source ), new File( destinationDirectory ) ); } /** * Copy file from source to destination only if source is newer than the target file. * If destinationDirectory does not exist, it * (and any parent directories) will be created. If a file source in * destinationDirectory exists, it will be overwritten. * * @param source An existing File to copy. * @param destinationDirectory A directory to copy source into. * @throws java.io.FileNotFoundException if source isn't a normal file. * @throws IllegalArgumentException if destinationDirectory isn't a directory. * @throws IOException if source does not exist, the file in * destinationDirectory cannot be written to, or an IO error occurs during copying. */ public static void copyFileToDirectoryIfModified( final String source, final String destinationDirectory ) throws IOException { copyFileToDirectoryIfModified( new File( source ), new File( destinationDirectory ) ); } /** * Copy file from source to destination. If destinationDirectory does not exist, it * (and any parent directories) will be created. If a file source in * destinationDirectory exists, it will be overwritten. * * @param source An existing File to copy. * @param destinationDirectory A directory to copy source into. * @throws java.io.FileNotFoundException if source isn't a normal file. * @throws IllegalArgumentException if destinationDirectory isn't a directory. * @throws IOException if source does not exist, the file in * destinationDirectory cannot be written to, or an IO error occurs during copying. */ public static void copyFileToDirectory( final File source, final File destinationDirectory ) throws IOException { if ( destinationDirectory.exists() && !destinationDirectory.isDirectory() ) { throw new IllegalArgumentException( "Destination is not a directory" ); } copyFile( source, new File( destinationDirectory, source.getName() ) ); } /** * Copy file from source to destination only if source is newer than the target file. * If destinationDirectory does not exist, it * (and any parent directories) will be created. If a file source in * destinationDirectory exists, it will be overwritten. * * @param source An existing File to copy. * @param destinationDirectory A directory to copy source into. * @throws java.io.FileNotFoundException if source isn't a normal file. * @throws IllegalArgumentException if destinationDirectory isn't a directory. * @throws IOException if source does not exist, the file in * destinationDirectory cannot be written to, or an IO error occurs during copying. */ public static void copyFileToDirectoryIfModified( final File source, final File destinationDirectory ) throws IOException { if ( destinationDirectory.exists() && !destinationDirectory.isDirectory() ) { throw new IllegalArgumentException( "Destination is not a directory" ); } copyFileIfModified( source, new File( destinationDirectory, source.getName() ) ); } /** * Creates a number of directories, as delivered from DirectoryScanner * @param sourceBase The basedir used for the directory scan * @param dirs The getIncludedDirs from the dirscanner * @param destination The base dir of the output structure */ public static void mkDirs( final File sourceBase, String[] dirs, final File destination ) throws IOException { for ( String dir : dirs ) { File src = new File( sourceBase, dir); File dst = new File( destination, dir); if (Java7Detector.isJava7() && NioFiles.isSymbolicLink( src )){ File target = NioFiles.readSymbolicLink( src ); NioFiles.createSymbolicLink( dst, target ); } else { dst.mkdirs(); } } } /** * Copy file from source to 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 existing non-directory File to copy bytes from. * @param destination A non-directory File to write bytes to (possibly * overwriting). * @throws IOException if source does not exist, destination cannot be * written to, or an IO error occurs during copying. * @throws java.io.FileNotFoundException if destination is a directory * (use {@link #copyFileToDirectory}). */ public static void copyFile( final File source, final File destination ) throws IOException { //check source exists if ( !source.exists() ) { final String message = "File " + source + " does not exist"; throw new IOException( message ); } //check source != destination, see PLXUTILS-10 if ( source.getCanonicalPath().equals( destination.getCanonicalPath() ) ) { //if they are equal, we can exit the method without doing any work return; } mkdirsFor( destination ); doCopyFile( source, destination ); if ( source.length() != destination.length() ) { String message = "Failed to copy full contents from " + source + " to " + destination; throw new IOException( message ); } } 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 destination A non-directory File to write bytes to (possibly * 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. */ public static boolean copyFileIfModified( final File source, final File destination ) throws IOException { if ( destination.lastModified() < source.lastModified() ) { copyFile( source, destination ); return true; } return false; } /** * Copies bytes from the URL source to a 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 A URL to copy bytes from. * @param destination A non-directory File to write bytes to (possibly * overwriting). * @throws IOException if *
    *
  • 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 ); } /** * Copies bytes from the {@link InputStream} source to a 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 destination A non-directory File to write bytes to (possibly * overwriting). * @throws IOException if *
    *
  • 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 { mkdirsFor( destination ); checkCanWrite( destination ); InputStream input = null; FileOutputStream output = null; try { input = source.getInputStream(); output = new FileOutputStream( destination ); IOUtil.copy( input, output ); } finally { IOUtil.close( input ); IOUtil.close( output ); } } 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 * root. * Eg: *
     * /foo//               -->     /foo/
     * /foo/./              -->     /foo/
     * /foo/../bar          -->     /bar
     * /foo/../bar/         -->     /bar/
     * /foo/../bar/../baz   -->     /baz
     * //foo//./bar         -->     /foo/bar
     * /../                 -->     null
     * 
* * @param path the path to normalize * @return the normalized String, or null if too many ..'s. */ public static String normalize( final String path ) { String normalized = path; // Resolve occurrences of "//" in the normalized path while ( true ) { int index = normalized.indexOf( "//" ); if ( index < 0 ) { break; } normalized = normalized.substring( 0, index ) + normalized.substring( index + 1 ); } // Resolve occurrences of "/./" in the normalized path while ( true ) { int index = normalized.indexOf( "/./" ); if ( index < 0 ) { break; } normalized = normalized.substring( 0, index ) + normalized.substring( index + 2 ); } // Resolve occurrences of "/../" in the normalized path while ( true ) { int index = normalized.indexOf( "/../" ); if ( index < 0 ) { break; } if ( index == 0 ) { return null; // Trying to go outside our context } int index2 = normalized.lastIndexOf( '/', index - 1 ); normalized = normalized.substring( 0, index2 ) + normalized.substring( index + 3 ); } // Return the normalized path that we have completed return normalized; } /** * Will concatenate 2 paths. Paths with .. will be * properly handled. *

Eg.,
* /a/b/c + d = /a/b/d
* /a/b/c + ../d = /a/d
*

*

* Thieved from Tomcat sources... * * @param lookupPath a path * @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 ) { // Cut off the last slash and everything beyond int index = lookupPath.lastIndexOf( "/" ); String lookup = lookupPath.substring( 0, index ); String pth = path; // Deal with .. by chopping dirs off the lookup path while ( pth.startsWith( "../" ) ) { if ( lookup.length() > 0 ) { index = lookup.lastIndexOf( "/" ); lookup = lookup.substring( 0, index ); } else { // More ..'s than dirs, return null return null; } index = pth.indexOf( "../" ) + 3; pth = pth.substring( index ); } return new StringBuffer( lookup ).append( "/" ).append( pth ).toString(); } /** * Resolve a file filename to it's canonical form. If filename is * relative (doesn't start with /), it will be resolved relative to * baseFile, otherwise it is treated as a normal root-relative path. * * @param baseFile Where to resolve filename from, if filename is * relative. * @param filename Absolute or relative file path to resolve. * @return The canonical File of filename. */ public static File resolveFile( final File baseFile, String filename ) { String filenm = filename; if ( '/' != File.separatorChar ) { filenm = filename.replace( '/', File.separatorChar ); } if ( '\\' != File.separatorChar ) { filenm = filename.replace( '\\', File.separatorChar ); } // deal with absolute files if ( filenm.startsWith( File.separator ) || ( Os.isFamily( Os.FAMILY_WINDOWS ) && filenm.indexOf( ":" ) > 0 ) ) { File file = new File( filenm ); try { file = file.getCanonicalFile(); } catch ( final IOException ioe ) { // nop } return file; } // 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 StringBuilder sb = new StringBuilder(); //remove duplicate file separators in succession - except //on win32 at start of filename as UNC filenames can //be \\AComputer\AShare\myfile.txt int start = 0; if ( '\\' == File.separatorChar ) { sb.append( filenm.charAt( 0 ) ); start++; } for ( int i = start; i < chars.length; i++ ) { final boolean doubleSeparator = File.separatorChar == chars[i] && File.separatorChar == chars[i - 1]; if ( !doubleSeparator ) { sb.append( chars[i] ); } } filenm = sb.toString(); //must be relative File file = ( new File( baseFile, filenm ) ).getAbsoluteFile(); try { file = file.getCanonicalFile(); } catch ( final IOException ioe ) { // nop } return file; } /** * Delete a file. If file is directory delete it and all sub-directories. * * @param file the file path * @throws IOException if any */ public static void forceDelete( final String file ) throws IOException { forceDelete( new File( file ) ); } /** * Delete a file. If file is directory delete it and all sub-directories. * * @param file a file * @throws IOException if any */ public static void forceDelete( final File file ) throws IOException { if ( file.isDirectory() ) { deleteDirectory( file ); } else { /* * NOTE: Always try to delete the file even if it appears to be non-existent. This will ensure that a * symlink whose target does not exist is deleted, too. */ boolean filePresent = file.getCanonicalFile().exists(); if ( !deleteFile( file ) && filePresent ) { final String message = "File " + file + " unable to be deleted."; throw new IOException( message ); } } } /** * Accommodate Windows bug encountered in both Sun and IBM JDKs. * Others possible. If the delete does not work, call System.gc(), * wait a little and try again. * * @param file a file * @throws IOException if any */ private static boolean deleteFile( File file ) throws IOException { if ( file.isDirectory() ) { throw new IOException( "File " + file + " isn't a file." ); } if ( !file.delete() ) { if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) { file = file.getCanonicalFile(); System.gc(); } try { Thread.sleep( 10 ); return file.delete(); } catch ( InterruptedException ignore ) { return file.delete(); } } return true; } /** * Schedule a file to be deleted when JVM exits. * If file is directory delete it and all sub-directories. * * @param file a file * @throws IOException if any */ public static void forceDeleteOnExit( final File file ) throws IOException { if ( !file.exists() ) { return; } if ( file.isDirectory() ) { deleteDirectoryOnExit( file ); } else { file.deleteOnExit(); } } /** * Recursively schedule directory for deletion on JVM exit. * * @param directory a directory * @throws IOException if any */ private static void deleteDirectoryOnExit( final File directory ) throws IOException { if ( !directory.exists() ) { return; } directory.deleteOnExit(); // The hook reverses the list cleanDirectoryOnExit( directory ); } /** * Clean a directory without deleting it. * * @param directory a directory * @throws IOException if any */ private static void cleanDirectoryOnExit( final File directory ) throws IOException { if ( !directory.exists() ) { final String message = directory + " does not exist"; throw new IllegalArgumentException( message ); } if ( !directory.isDirectory() ) { final String message = directory + " is not a directory"; throw new IllegalArgumentException( message ); } IOException exception = null; final File[] files = directory.listFiles(); for ( final File file : files ) { try { forceDeleteOnExit( file ); } catch ( final IOException ioe ) { exception = ioe; } } if ( null != exception ) { throw exception; } } /** * 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 IllegalArgumentException if the file contains illegal Windows characters under Windows OS. * @see #INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME */ public static void forceMkdir( final File file ) throws IOException { if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) { 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, " " ) ); } } if ( file.exists() ) { if ( file.isFile() ) { final String message = "File " + file + " exists and is " + "not a directory. Unable to create directory."; throw new IOException( message ); } } else { if ( false == file.mkdirs() ) { final String message = "Unable to create directory " + file; throw new IOException( message ); } } } /** * Recursively delete a directory. * * @param directory a directory * @throws IOException if any */ public static void deleteDirectory( final String directory ) throws IOException { deleteDirectory( new File( directory ) ); } /** * Recursively delete a directory. * * @param directory a directory * @throws IOException if any */ public static void deleteDirectory( final File directory ) throws IOException { if ( !directory.exists() ) { 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() ) { final String message = "Directory " + directory + " unable to be deleted."; throw new IOException( message ); } } /** * Clean a directory without deleting it. * * @param directory a directory * @throws IOException if any */ public static void cleanDirectory( final String directory ) throws IOException { cleanDirectory( new File( directory ) ); } /** * Clean a directory without deleting it. * * @param directory a directory * @throws IOException if any */ public static void cleanDirectory( final File directory ) throws IOException { if ( !directory.exists() ) { final String message = directory + " does not exist"; throw new IllegalArgumentException( message ); } if ( !directory.isDirectory() ) { final String message = directory + " is not a directory"; throw new IllegalArgumentException( message ); } IOException exception = null; final File[] files = directory.listFiles(); if ( files == null ) { return; } for ( final File file : files ) { try { forceDelete( file ); } catch ( final IOException ioe ) { exception = ioe; } } if ( null != exception ) { throw exception; } } /** * Recursively count size of a directory. * * @param directory a directory * @return size of directory in bytes. */ public static long sizeOfDirectory( final String directory ) { return sizeOfDirectory( new File( directory ) ); } /** * Recursively count size of a directory. * * @param directory a directory * @return size of directory in bytes. */ public static long sizeOfDirectory( final File directory ) { if ( !directory.exists() ) { final String message = directory + " does not exist"; throw new IllegalArgumentException( message ); } if ( !directory.isDirectory() ) { final String message = directory + " is not a directory"; throw new IllegalArgumentException( message ); } long size = 0; final File[] files = directory.listFiles(); for ( final File file : files ) { if ( file.isDirectory() ) { size += sizeOfDirectory( file ); } else { size += file.length(); } } return size; } /** * Return the files contained in the directory, using inclusion and exclusion Ant patterns, * 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 * @return a list of File objects * @throws IOException * @see #getFileNames(File, String, String, boolean) */ public static List getFiles( File directory, String includes, String excludes ) throws IOException { return getFiles( directory, includes, excludes, true ); } /** * 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 includeBasedir true to include the base dir in each file * @return a list of File objects * @throws IOException * @see #getFileNames(File, String, String, boolean) */ public static List getFiles( File directory, String includes, String excludes, boolean includeBasedir ) throws IOException { List fileNames = getFileNames( directory, includes, excludes, includeBasedir ); List files = new ArrayList(); for ( String filename : fileNames ) { files.add( new File( filename ) ); } return files; } /** * 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 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 ) throws IOException { return getFileNames( directory, includes, excludes, includeBasedir, true ); } /** * 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 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 ) throws IOException { return getFileAndDirectoryNames( directory, includes, excludes, includeBasedir, isCaseSensitive, true, false ); } /** * 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 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 ) throws IOException { return getDirectoryNames( directory, includes, excludes, includeBasedir, true ); } /** * 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 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 ) throws IOException { return getFileAndDirectoryNames( directory, includes, excludes, includeBasedir, isCaseSensitive, false, true ); } /** * 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 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 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 ) throws IOException { DirectoryScanner scanner = new DirectoryScanner(); scanner.setBasedir( directory ); if ( includes != null ) { scanner.setIncludes( StringUtils.split( includes, "," ) ); } if ( excludes != null ) { scanner.setExcludes( StringUtils.split( excludes, "," ) ); } scanner.setCaseSensitive( isCaseSensitive ); scanner.scan(); List list = new ArrayList(); if ( getFiles ) { String[] files = scanner.getIncludedFiles(); for ( String file : files ) { if ( includeBasedir ) { list.add( directory + FileUtils.FS + file ); } else { list.add( file ); } } } if ( getDirectories ) { String[] directories = scanner.getIncludedDirectories(); for ( String directory1 : directories ) { if ( includeBasedir ) { list.add( directory + FileUtils.FS + directory1 ); } else { list.add( directory1 ); } } } return list; } /** * Copy a directory to an other one. * * @param sourceDirectory the source dir * @param destinationDirectory the target dir * @throws IOException if any */ public static void copyDirectory( File sourceDirectory, File destinationDirectory ) throws IOException { copyDirectory( sourceDirectory, destinationDirectory, "**", null ); } /** * Copy a directory to an other one. * * @param sourceDirectory the source dir * @param destinationDirectory the target dir * @param includes include pattern * @param excludes exlucde pattern * @throws IOException if any * @see #getFiles(File, String, String) */ public static void copyDirectory( File sourceDirectory, File destinationDirectory, String includes, String excludes ) throws IOException { if ( !sourceDirectory.exists() ) { return; } List files = getFiles( sourceDirectory, includes, excludes ); for ( File file : files ) { copyFileToDirectory( file, destinationDirectory ); } } /** * Copies a entire directory layout : no files will be copied only directories *

* Note: *

    *
  • It will include empty directories. *
  • The sourceDirectory must exists. *
* * @param sourceDirectory the source dir * @param destinationDirectory the target dir * @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 ) throws IOException { if ( sourceDirectory == null ) { throw new IOException( "source directory can't be null." ); } if ( destinationDirectory == null ) { throw new IOException( "destination directory can't be null." ); } if ( sourceDirectory.equals( destinationDirectory ) ) { throw new IOException( "source and destination are the same directory." ); } if ( !sourceDirectory.exists() ) { throw new IOException( "Source directory doesn't exists (" + sourceDirectory.getAbsolutePath() + ")." ); } DirectoryScanner scanner = new DirectoryScanner(); scanner.setBasedir( sourceDirectory ); if ( includes != null && includes.length >= 1 ) { scanner.setIncludes( includes ); } else { scanner.setIncludes( new String[]{ "**" } ); } if ( excludes != null && excludes.length >= 1 ) { scanner.setExcludes( excludes ); } scanner.addDefaultExcludes(); scanner.scan(); List includedDirectories = Arrays.asList( scanner.getIncludedDirectories() ); for ( String name : includedDirectories ) { File source = new File( sourceDirectory, name ); if ( source.equals( sourceDirectory ) ) { continue; } File destination = new File( destinationDirectory, name ); destination.mkdirs(); } } /** * Copies a entire directory structure. *

* Note: *

    *
  • It will include empty directories. *
  • The sourceDirectory must exists. *
* * @param sourceDirectory the source dir * @param destinationDirectory the target dir * @throws IOException if any */ public static void copyDirectoryStructure( File sourceDirectory, File destinationDirectory ) throws IOException { copyDirectoryStructure( sourceDirectory, destinationDirectory, destinationDirectory, false ); } /** * Copies an entire directory structure but only source files with timestamp later than the destinations'. *

* Note: *

    *
  • It will include empty directories. *
  • The sourceDirectory must exists. *
* * @param sourceDirectory the source dir * @param destinationDirectory the target dir * @throws IOException if any */ public static void copyDirectoryStructureIfModified( File sourceDirectory, File destinationDirectory ) throws IOException { copyDirectoryStructure( sourceDirectory, destinationDirectory, destinationDirectory, true ); } private static void copyDirectoryStructure( File sourceDirectory, File destinationDirectory, File rootDestinationDirectory, boolean onlyModifiedFiles ) throws IOException { if ( sourceDirectory == null ) { throw new IOException( "source directory can't be null." ); } if ( destinationDirectory == null ) { throw new IOException( "destination directory can't be null." ); } if ( sourceDirectory.equals( destinationDirectory ) ) { throw new IOException( "source and destination are the same directory." ); } if ( !sourceDirectory.exists() ) { throw new IOException( "Source directory doesn't exists (" + sourceDirectory.getAbsolutePath() + ")." ); } File[] files = sourceDirectory.listFiles(); String sourcePath = sourceDirectory.getAbsolutePath(); for ( File file : files ) { if ( file.equals( rootDestinationDirectory ) ) { // We don't copy the destination directory in itself continue; } String dest = file.getAbsolutePath(); dest = dest.substring( sourcePath.length() + 1 ); File destination = new File( destinationDirectory, dest ); if ( file.isFile() ) { destination = destination.getParentFile(); if ( onlyModifiedFiles ) { copyFileToDirectoryIfModified( file, destination ); } else { copyFileToDirectory( file, destination ); } } else if ( file.isDirectory() ) { if ( !destination.exists() && !destination.mkdirs() ) { throw new IOException( "Could not create destination directory '" + destination.getAbsolutePath() + "'." ); } copyDirectoryStructure( file, destination, rootDestinationDirectory, onlyModifiedFiles ); } else { throw new IOException( "Unknown file type: " + file.getAbsolutePath() ); } } } /** * Renames a file, even if that involves crossing file system boundaries. *

*

This will remove to (if it exists), ensure that * to's parent directory exists and move * from, which involves deleting from as * well.

* * @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. */ public static void rename( File from, File to ) throws IOException { if ( to.exists() && !to.delete() ) { throw new IOException( "Failed to delete " + to + " while trying to rename " + from ); } File parent = to.getParentFile(); if ( parent != null && !parent.exists() && !parent.mkdirs() ) { throw new IOException( "Failed to create directory " + parent + " while trying to rename " + from ); } if ( !from.renameTo( to ) ) { copyFile( from, to ); if ( !from.delete() ) { throw new IOException( "Failed to delete " + from + " while trying to rename it." ); } } } /** * Create a temporary file in a given directory. *

*

The file denoted by the returned abstract pathname did not * exist before this method was invoked, any subsequent invocation * of this method will yield a different file name.

*

* The filename is prefixNNNNNsuffix where NNNN is a random number *

*

This method is different to {@link File#createTempFile(String, String, File)} of JDK 1.2 * as it doesn't create the file itself. * It uses the location pointed to by java.io.tmpdir * when the parentDir attribute is * null.

*

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 parentDir Directory to create the temporary file in -java.io.tmpdir * used if not specificed * @return a File reference to the new temporary file. */ public static File createTempFile( String prefix, String suffix, File parentDir ) { File result = null; String parent = System.getProperty( "java.io.tmpdir" ); if ( parentDir != null ) { parent = parentDir.getPath(); } DecimalFormat fmt = new DecimalFormat( "#####" ); SecureRandom secureRandom = new SecureRandom(); long secureInitializer = secureRandom.nextLong(); Random rand = new Random( secureInitializer + Runtime.getRuntime().freeMemory() ); synchronized ( rand ) { do { result = new File( parent, prefix + fmt.format( Math.abs( rand.nextInt() ) ) + suffix ); } while ( result.exists() ); } return result; } /** * 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 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 */ public static void copyFile( File from, File to, String encoding, FilterWrapper[] wrappers ) throws IOException { copyFile( from, to, encoding, wrappers, false ); } public static abstract class FilterWrapper { public abstract Reader getReader( Reader fileReader ); } /** * 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 overwrite if true and f wrappers is null or empty, the file will be copy * enven if to.lastModified() < from.lastModified() * @throws IOException if an IO error occurs during copying or filtering * @since 1.5.2 */ public static void copyFile( File from, File to, String encoding, FilterWrapper[] wrappers, boolean overwrite ) throws IOException { if ( wrappers != null && wrappers.length > 0 ) { // buffer so it isn't reading a byte at a time! Reader fileReader = null; Writer fileWriter = null; try { if ( encoding == null || encoding.length() < 1 ) { fileReader = new BufferedReader( new FileReader( from ) ); fileWriter = new FileWriter( to ); } else { FileInputStream instream = new FileInputStream( from ); FileOutputStream outstream = new FileOutputStream( to ); fileReader = new BufferedReader( new InputStreamReader( instream, encoding ) ); fileWriter = new OutputStreamWriter( outstream, encoding ); } Reader reader = fileReader; for ( FilterWrapper wrapper : wrappers ) { reader = wrapper.getReader( reader ); } IOUtil.copy( reader, fileWriter ); } finally { IOUtil.close( fileReader ); IOUtil.close( fileWriter ); } } else { if ( to.lastModified() < from.lastModified() || overwrite ) { copyFile( from, to ); } } } /** * Note: the file content is read with platform encoding * * @param file the file * @return a List containing every every line not starting with # and not empty * @throws IOException if any */ public static List loadFile( File file ) throws IOException { List lines = new ArrayList(); if ( file.exists() ) { BufferedReader reader = new BufferedReader( new FileReader( file ) ); String line = reader.readLine(); while ( line != null ) { line = line.trim(); if ( !line.startsWith( "#" ) && line.length() != 0 ) { lines.add( line ); } line = reader.readLine(); } reader.close(); } return lines; } /** * For Windows OS, check if the file name contains any of the following characters: * ":", "*", "?", "\"", "<", ">", "|" * * @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. * @see #INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME * @since 1.5.2 */ public static boolean isValidWindowsFileName( File f ) { if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) { if ( StringUtils.indexOfAny( f.getName(), INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME ) != -1 ) { return false; } File parentFile = f.getParentFile(); if ( parentFile != null ) { return isValidWindowsFileName( parentFile ); } } return true; } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/IOUtil.java000066400000000000000000000713061251077732300302710ustar00rootroot00000000000000package org.codehaus.plexus.util; /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.codehaus.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" and * "Apache Turbine" must not be used to endorse or promote products * derived from this software without prior written permission. For * written permission, please contact codehaus@codehaus.org. * * 5. Products derived from this software may not be called "Apache", * "Apache Turbine", nor may "Apache" appear in their name, without * prior written permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . */ import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; 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.StringReader; import java.io.StringWriter; import java.io.Writer; import java.nio.channels.Channel; /** * General IO Stream manipulation. *

* This class provides static utility methods for input/output operations, particularly buffered * copying between sources (InputStream, Reader, String and * byte[]) and destinations (OutputStream, Writer, * String and byte[]). *

* *

Unless otherwise noted, these copy methods do not flush or close the * streams. Often, doing so would require making non-portable assumptions about the streams' origin * and further use. This means that both streams' close() methods must be called after * copying. if one omits this step, then the stream resources (sockets, file descriptors) are * released when the associated Stream is garbage-collected. It is not a good idea to rely on this * mechanism. For a good overview of the distinction between "memory management" and "resource * management", see this * UnixReview article

* *

For each copy method, a variant is provided that allows the caller to specify the * buffer size (the default is 4k). As the buffer size can have a fairly large impact on speed, this * may be worth tweaking. Often "large buffer -> faster" does not hold, even for large data * transfers.

* *

For byte-to-char methods, a copy variant allows the encoding to be selected * (otherwise the platform default is used).

* *

The copy methods use an internal buffer when copying. It is therefore advisable * not to deliberately wrap the stream arguments to the copy methods in * Buffered* streams. For example, don't do the * following:

* * copy( new BufferedInputStream( in ), new BufferedOutputStream( out ) ); * *

The rationale is as follows:

* *

Imagine that an InputStream's read() is a very expensive operation, which would usually suggest * wrapping in a BufferedInputStream. The BufferedInputStream works by issuing infrequent * {@link java.io.InputStream#read(byte[] b, int off, int len)} requests on the underlying InputStream, to * fill an internal buffer, from which further read requests can inexpensively get * their data (until the buffer runs out).

*

However, the copy methods do the same thing, keeping an internal buffer, * populated by {@link InputStream#read(byte[] b, int off, int len)} requests. Having two buffers * (or three if the destination stream is also buffered) is pointless, and the unnecessary buffer * management hurts performance slightly (about 3%, according to some simple experiments).

* * @author Peter Donald * @author Jeff Turner * @version $Id$ * @since 4.0 */ /* * Behold, intrepid explorers; a map of this class: * * Method Input Output Dependency * ------ ----- ------ ------- * 1 copy InputStream OutputStream (primitive) * 2 copy Reader Writer (primitive) * * 3 copy InputStream Writer 2 * 4 toString InputStream String 3 * 5 toByteArray InputStream byte[] 1 * * 6 copy Reader OutputStream 2 * 7 toString Reader String 2 * 8 toByteArray Reader byte[] 6 * * 9 copy String OutputStream 2 * 10 copy String Writer (trivial) * 11 toByteArray String byte[] 9 * * 12 copy byte[] Writer 3 * 13 toString byte[] String 12 * 14 copy byte[] OutputStream (trivial) * * * Note that only the first two methods shuffle bytes; the rest use these two, or (if possible) copy * using native Java copy methods. As there are method variants to specify buffer size and encoding, * each row may correspond to up to 4 methods. * */ public final class IOUtil { private static final int DEFAULT_BUFFER_SIZE = 1024 * 16; /** * Private constructor to prevent instantiation. */ private IOUtil() { } /////////////////////////////////////////////////////////////// // Core copy methods /////////////////////////////////////////////////////////////// /** * Copy bytes from an InputStream to an OutputStream. */ public static void copy( final InputStream input, final OutputStream output ) throws IOException { copy( input, output, DEFAULT_BUFFER_SIZE ); } /** * Copy bytes from an InputStream to an OutputStream. * @param bufferSize Size of internal buffer to use. */ public static void copy( final InputStream input, final OutputStream output, final int bufferSize ) throws IOException { final byte[] buffer = new byte[bufferSize]; int n = 0; while ( -1 != ( n = input.read( buffer ) ) ) { output.write( buffer, 0, n ); } } /** * Copy chars from a Reader to a Writer. */ public static void copy( final Reader input, final Writer output ) throws IOException { copy( input, output, DEFAULT_BUFFER_SIZE ); } /** * Copy chars from a Reader to a Writer. * @param bufferSize Size of internal buffer to use. */ public static void copy( final Reader input, final Writer output, final int bufferSize ) throws IOException { final char[] buffer = new char[bufferSize]; int n = 0; while ( -1 != ( n = input.read( buffer ) ) ) { output.write( buffer, 0, n ); } output.flush(); } /////////////////////////////////////////////////////////////// // Derived copy methods // InputStream -> * /////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////// // InputStream -> Writer /** * Copy and convert bytes from an InputStream to chars on a * Writer. * The platform's default encoding is used for the byte-to-char conversion. */ public static void copy( final InputStream input, final Writer output ) throws IOException { copy( input, output, DEFAULT_BUFFER_SIZE ); } /** * Copy and convert bytes from an InputStream to chars on a * Writer. * The platform's default encoding is used for the byte-to-char conversion. * @param bufferSize Size of internal buffer to use. */ public static void copy( final InputStream input, final Writer output, final int bufferSize ) throws IOException { final InputStreamReader in = new InputStreamReader( input ); copy( in, output, bufferSize ); } /** * Copy and convert bytes from an InputStream to chars on a * Writer, using the specified encoding. * @param encoding The name of a supported character encoding. See the * IANA * Charset Registry for a list of valid encoding types. */ public static void copy( final InputStream input, final Writer output, final String encoding ) throws IOException { final InputStreamReader in = new InputStreamReader( input, encoding ); copy( in, output ); } /** * Copy and convert bytes from an InputStream to chars on a * Writer, using the specified encoding. * @param encoding The name of a supported character encoding. See the * IANA * Charset Registry for a list of valid encoding types. * @param bufferSize Size of internal buffer to use. */ public static void copy( final InputStream input, final Writer output, final String encoding, final int bufferSize ) throws IOException { final InputStreamReader in = new InputStreamReader( input, encoding ); copy( in, output, bufferSize ); } /////////////////////////////////////////////////////////////// // InputStream -> String /** * Get the contents of an InputStream as a String. * The platform's default encoding is used for the byte-to-char conversion. */ public static String toString( final InputStream input ) throws IOException { return toString( input, DEFAULT_BUFFER_SIZE ); } /** * Get the contents of an InputStream as a String. * The platform's default encoding is used for the byte-to-char conversion. * @param bufferSize Size of internal buffer to use. */ public static String toString( final InputStream input, final int bufferSize ) throws IOException { final StringWriter sw = new StringWriter(); copy( input, sw, bufferSize ); return sw.toString(); } /** * Get the contents of an InputStream as a String. * @param encoding The name of a supported character encoding. See the * IANA * Charset Registry for a list of valid encoding types. */ public static String toString( final InputStream input, final String encoding ) throws IOException { return toString( input, encoding, DEFAULT_BUFFER_SIZE ); } /** * Get the contents of an InputStream as a String. * @param encoding The name of a supported character encoding. See the * IANA * Charset Registry for a list of valid encoding types. * @param bufferSize Size of internal buffer to use. */ public static String toString( final InputStream input, final String encoding, final int bufferSize ) throws IOException { final StringWriter sw = new StringWriter(); copy( input, sw, encoding, bufferSize ); return sw.toString(); } /////////////////////////////////////////////////////////////// // InputStream -> byte[] /** * Get the contents of an InputStream as a byte[]. */ public static byte[] toByteArray( final InputStream input ) throws IOException { return toByteArray( input, DEFAULT_BUFFER_SIZE ); } /** * Get the contents of an InputStream as a byte[]. * @param bufferSize Size of internal buffer to use. */ public static byte[] toByteArray( final InputStream input, final int bufferSize ) throws IOException { final ByteArrayOutputStream output = new ByteArrayOutputStream(); copy( input, output, bufferSize ); return output.toByteArray(); } /////////////////////////////////////////////////////////////// // Derived copy methods // Reader -> * /////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////// // Reader -> OutputStream /** * Serialize chars from a Reader to bytes on an OutputStream, and * flush the OutputStream. */ public static void copy( final Reader input, final OutputStream output ) throws IOException { copy( input, output, DEFAULT_BUFFER_SIZE ); } /** * Serialize chars from a Reader to bytes on an OutputStream, and * flush the OutputStream. * @param bufferSize Size of internal buffer to use. */ public static void copy( final Reader input, final OutputStream output, final int bufferSize ) throws IOException { final OutputStreamWriter out = new OutputStreamWriter( output ); copy( input, out, bufferSize ); // NOTE: Unless anyone is planning on rewriting OutputStreamWriter, we have to flush // here. out.flush(); } /////////////////////////////////////////////////////////////// // Reader -> String /** * Get the contents of a Reader as a String. */ public static String toString( final Reader input ) throws IOException { return toString( input, DEFAULT_BUFFER_SIZE ); } /** * Get the contents of a Reader as a String. * @param bufferSize Size of internal buffer to use. */ public static String toString( final Reader input, final int bufferSize ) throws IOException { final StringWriter sw = new StringWriter(); copy( input, sw, bufferSize ); return sw.toString(); } /////////////////////////////////////////////////////////////// // Reader -> byte[] /** * Get the contents of a Reader as a byte[]. */ public static byte[] toByteArray( final Reader input ) throws IOException { return toByteArray( input, DEFAULT_BUFFER_SIZE ); } /** * Get the contents of a Reader as a byte[]. * @param bufferSize Size of internal buffer to use. */ public static byte[] toByteArray( final Reader input, final int bufferSize ) throws IOException { ByteArrayOutputStream output = new ByteArrayOutputStream(); copy( input, output, bufferSize ); return output.toByteArray(); } /////////////////////////////////////////////////////////////// // Derived copy methods // String -> * /////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////// // String -> OutputStream /** * Serialize chars from a String to bytes on an OutputStream, and * flush the OutputStream. */ public static void copy( final String input, final OutputStream output ) throws IOException { copy( input, output, DEFAULT_BUFFER_SIZE ); } /** * Serialize chars from a String to bytes on an OutputStream, and * flush the OutputStream. * @param bufferSize Size of internal buffer to use. */ public static void copy( final String input, final OutputStream output, final int bufferSize ) throws IOException { final StringReader in = new StringReader( input ); final OutputStreamWriter out = new OutputStreamWriter( output ); copy( in, out, bufferSize ); // NOTE: Unless anyone is planning on rewriting OutputStreamWriter, we have to flush // here. out.flush(); } /////////////////////////////////////////////////////////////// // String -> Writer /** * Copy chars from a String to a Writer. */ public static void copy( final String input, final Writer output ) throws IOException { output.write( input ); } /** * Copy bytes from an InputStream to an * OutputStream, with buffering. * This is equivalent to passing a * {@link java.io.BufferedInputStream} and * {@link java.io.BufferedOutputStream} to {@link #copy(InputStream, OutputStream)}, * and flushing the output stream afterwards. The streams are not closed * after the copy. * @deprecated Buffering streams is actively harmful! See the class description as to why. Use * {@link #copy(InputStream, OutputStream)} instead. */ public static void bufferedCopy( final InputStream input, final OutputStream output ) throws IOException { final BufferedInputStream in = new BufferedInputStream( input ); final BufferedOutputStream out = new BufferedOutputStream( output ); copy( in, out ); out.flush(); } /////////////////////////////////////////////////////////////// // String -> byte[] /** * Get the contents of a String as a byte[]. */ public static byte[] toByteArray( final String input ) throws IOException { return toByteArray( input, DEFAULT_BUFFER_SIZE ); } /** * Get the contents of a String as a byte[]. * @param bufferSize Size of internal buffer to use. */ public static byte[] toByteArray( final String input, final int bufferSize ) throws IOException { ByteArrayOutputStream output = new ByteArrayOutputStream(); copy( input, output, bufferSize ); return output.toByteArray(); } /////////////////////////////////////////////////////////////// // Derived copy methods // byte[] -> * /////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////// // byte[] -> Writer /** * Copy and convert bytes from a byte[] to chars on a * Writer. * The platform's default encoding is used for the byte-to-char conversion. */ public static void copy( final byte[] input, final Writer output ) throws IOException { copy( input, output, DEFAULT_BUFFER_SIZE ); } /** * Copy and convert bytes from a byte[] to chars on a * Writer. * The platform's default encoding is used for the byte-to-char conversion. * @param bufferSize Size of internal buffer to use. */ public static void copy( final byte[] input, final Writer output, final int bufferSize ) throws IOException { final ByteArrayInputStream in = new ByteArrayInputStream( input ); copy( in, output, bufferSize ); } /** * Copy and convert bytes from a byte[] to chars on a * Writer, using the specified encoding. * @param encoding The name of a supported character encoding. See the * IANA * Charset Registry for a list of valid encoding types. */ public static void copy( final byte[] input, final Writer output, final String encoding ) throws IOException { final ByteArrayInputStream in = new ByteArrayInputStream( input ); copy( in, output, encoding ); } /** * Copy and convert bytes from a byte[] to chars on a * Writer, using the specified encoding. * @param encoding The name of a supported character encoding. See the * IANA * Charset Registry for a list of valid encoding types. * @param bufferSize Size of internal buffer to use. */ public static void copy( final byte[] input, final Writer output, final String encoding, final int bufferSize ) throws IOException { final ByteArrayInputStream in = new ByteArrayInputStream( input ); copy( in, output, encoding, bufferSize ); } /////////////////////////////////////////////////////////////// // byte[] -> String /** * Get the contents of a byte[] as a String. * The platform's default encoding is used for the byte-to-char conversion. */ public static String toString( final byte[] input ) throws IOException { return toString( input, DEFAULT_BUFFER_SIZE ); } /** * Get the contents of a byte[] as a String. * The platform's default encoding is used for the byte-to-char conversion. * @param bufferSize Size of internal buffer to use. */ public static String toString( final byte[] input, final int bufferSize ) throws IOException { final StringWriter sw = new StringWriter(); copy( input, sw, bufferSize ); return sw.toString(); } /** * Get the contents of a byte[] as a String. * @param encoding The name of a supported character encoding. See the * IANA * Charset Registry for a list of valid encoding types. */ public static String toString( final byte[] input, final String encoding ) throws IOException { return toString( input, encoding, DEFAULT_BUFFER_SIZE ); } /** * Get the contents of a byte[] as a String. * @param encoding The name of a supported character encoding. See the * IANA * Charset Registry for a list of valid encoding types. * @param bufferSize Size of internal buffer to use. */ public static String toString( final byte[] input, final String encoding, final int bufferSize ) throws IOException { final StringWriter sw = new StringWriter(); copy( input, sw, encoding, bufferSize ); return sw.toString(); } /////////////////////////////////////////////////////////////// // byte[] -> OutputStream /** * Copy bytes from a byte[] to an OutputStream. */ public static void copy( final byte[] input, final OutputStream output ) throws IOException { copy( input, output, DEFAULT_BUFFER_SIZE ); } /** * Copy bytes from a byte[] to an OutputStream. * @param bufferSize Size of internal buffer to use. */ public static void copy( final byte[] input, final OutputStream output, final int bufferSize ) throws IOException { output.write( input ); } /** * Compare the contents of two Streams to determine if they are equal or not. * * @param input1 the first stream * @param input2 the second stream * @return true if the content of the streams are equal or they both don't exist, false otherwise */ public static boolean contentEquals( final InputStream input1, final InputStream input2 ) throws IOException { final InputStream bufferedInput1 = new BufferedInputStream( input1 ); final InputStream bufferedInput2 = new BufferedInputStream( input2 ); int ch = bufferedInput1.read(); while ( -1 != ch ) { final int ch2 = bufferedInput2.read(); if ( ch != ch2 ) { return false; } ch = bufferedInput1.read(); } final int ch2 = bufferedInput2.read(); if ( -1 != ch2 ) { return false; } else { return true; } } // ---------------------------------------------------------------------- // closeXXX() // ---------------------------------------------------------------------- /** * Closes the input stream. The input stream can be null and any IOException's will be swallowed. * * @param inputStream The stream to close. */ public static void close( InputStream inputStream ) { if ( inputStream == null ) { return; } try { inputStream.close(); } catch( IOException ex ) { // ignore } } /** * 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. * * @param outputStream The stream to close. */ public static void close( OutputStream outputStream ) { if ( outputStream == null ) { return; } try { outputStream.close(); } catch( IOException ex ) { // ignore } } /** * Closes the reader. The reader can be null and any IOException's will be swallowed. * * @param reader The reader to close. */ public static void close( Reader reader ) { if ( reader == null ) { return; } try { reader.close(); } catch( IOException ex ) { // ignore } } /** * Closes the writer. The writer can be null and any IOException's will be swallowed. * * @param writer The writer to close. */ public static void close( Writer writer ) { if ( writer == null ) { return; } try { writer.close(); } catch( IOException ex ) { // ignore } } } InterpolationFilterReader.java000066400000000000000000000271211251077732300341610ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/* * The Apache Software License, Version 1.1 * * Copyright (c) 2002-2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.codehaus.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "Ant" and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact codehaus@codehaus.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . */ package org.codehaus.plexus.util; import java.io.FilterReader; import java.io.IOException; import java.io.Reader; import java.util.HashMap; 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 s */ public class InterpolationFilterReader extends FilterReader { /** replacement text from a token */ private String replaceData = null; /** Index into replacement data */ private int replaceIndex = -1; /** Index into previous data */ private int previousIndex = -1; /** Hashtable to hold the replacee-replacer pairs (String to String). */ private Map variables = new HashMap(); /** Character marking the beginning of a token. */ private String beginToken; /** Character marking the end of a token. */ private String endToken; /** Length of begin token. */ private int beginTokenLength; /** Length of end token. */ private int endTokenLength; /** Default begin token. */ private static final String DEFAULT_BEGIN_TOKEN = "${"; /** 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 ); this.variables = variables; this.beginToken = beginToken; this.endToken = endToken; beginTokenLength = beginToken.length(); 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 ); } /** * Skips characters. This method will block until some characters are * available, an I/O error occurs, or the end of the stream is reached. * * @param n The number of characters to skip * * @return the number of characters actually skipped * * @exception IllegalArgumentException If n is negative. * @exception IOException If an I/O error occurs */ public long skip( long n ) throws IOException { if ( n < 0L ) { throw new IllegalArgumentException( "skip value is negative" ); } for ( long i = 0; i < n; i++ ) { if ( read() == -1 ) { return i; } } return n; } /** * Reads characters into a portion of an array. This method will block * until some input is available, an I/O error occurs, or the end of the * stream is reached. * * @param cbuf Destination buffer to write characters to. * Must not be null. * @param off Offset at which to start storing characters. * @param len Maximum number of characters to read. * * @return the number of characters read, or -1 if the end of the * stream has been reached * * @exception IOException If an I/O error occurs */ public int read( char cbuf[], int off, int len ) throws IOException { for ( int i = 0; i < len; i++ ) { int ch = read(); if ( ch == -1 ) { if ( i == 0 ) { return -1; } else { return i; } } cbuf[off + i] = (char) ch; } return len; } /** * Returns the next character in the filtered stream, replacing tokens * from the original stream. * * @return the next character in the resulting stream, or -1 * if the end of the resulting stream has been reached * * @exception IOException if the underlying stream throws an IOException * during reading */ public int read() throws IOException { if ( replaceIndex != -1 && replaceIndex < replaceData.length() ) { int ch = replaceData.charAt( replaceIndex++ ); if ( replaceIndex >= replaceData.length() ) { replaceIndex = -1; } return ch; } int ch; if ( previousIndex != -1 && previousIndex < endTokenLength ) { ch = endToken.charAt( previousIndex++ ); } else { ch = in.read(); } if ( ch == beginToken.charAt( 0 ) ) { StringBuilder key = new StringBuilder(); int beginTokenMatchPos = 1; do { if ( previousIndex != -1 && previousIndex < endTokenLength ) { ch = endToken.charAt( previousIndex++ ); } else { ch = in.read(); } if ( ch != -1 ) { key.append( (char) ch ); if ( ( beginTokenMatchPos < beginTokenLength ) && ( ch != beginToken.charAt( beginTokenMatchPos++ ) ) ) { ch = -1; // not really EOF but to trigger code below break; } } else { break; } } while ( ch != endToken.charAt( 0 ) ); // now test endToken if ( ch != -1 && endTokenLength > 1 ) { int endTokenMatchPos = 1; do { if ( previousIndex != -1 && previousIndex < endTokenLength ) { ch = endToken.charAt( previousIndex++ ); } else { ch = in.read(); } if ( ch != -1 ) { key.append( (char) ch ); if ( ch != endToken.charAt( endTokenMatchPos++ ) ) { ch = -1; // not really EOF but to trigger code below break; } } else { break; } } while ( endTokenMatchPos < endTokenLength ); } // There is nothing left to read so we have the situation where the begin/end token // are in fact the same and as there is nothing left to read we have got ourselves // end of a token boundary so let it pass through. if ( ch == -1 ) { replaceData = key.toString(); replaceIndex = 0; return beginToken.charAt( 0 ); } String variableKey = key.substring( beginTokenLength - 1, key.length() - endTokenLength ); Object o = variables.get(variableKey); if ( o != null ) { String value = o.toString(); if ( value.length() != 0 ) { replaceData = value; replaceIndex = 0; } return read(); } else { previousIndex = 0; replaceData = key.substring(0, key.length() - endTokenLength ); replaceIndex = 0; return beginToken.charAt(0); } } return ch; } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/Java7Detector.java000066400000000000000000000021171251077732300315600ustar00rootroot00000000000000package 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; } } LineOrientedInterpolatingReader.java000066400000000000000000000335341251077732300353120ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/utilpackage 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 org.codehaus.plexus.util.reflection.Reflector; import org.codehaus.plexus.util.reflection.ReflectorException; import java.io.FilterReader; import java.io.IOException; import java.io.PushbackReader; import java.io.Reader; import java.util.Collections; import java.util.HashSet; 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 { public static final String DEFAULT_START_DELIM = "${"; public static final String DEFAULT_END_DELIM = "}"; public static final String DEFAULT_ESCAPE_SEQ = "\\"; private static final char CARRIAGE_RETURN_CHAR = '\r'; private static final char NEWLINE_CHAR = '\n'; private final PushbackReader pushbackReader; private final Map context; private final String startDelim; private final String endDelim; private final String escapeSeq; private final int minExpressionSize; private final Reflector reflector; private int lineIdx = -1; private String line; /** * 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 ); this.startDelim = startDelim; this.endDelim = endDelim; this.escapeSeq = escapeSeq; // Expressions have to be at least this size... this.minExpressionSize = startDelim.length() + endDelim.length() + 1; this.context = Collections.unmodifiableMap( context ); this.reflector = new Reflector(); if ( reader instanceof PushbackReader ) { this.pushbackReader = (PushbackReader) reader; } else { this.pushbackReader = new PushbackReader( reader, 1 ); } } /** * 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 ); } /** * 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 ); } public int read() throws IOException { if ( line == null || lineIdx >= line.length() ) { readAndInterpolateLine(); } int next = -1; if ( line != null && lineIdx < line.length() ) { next = line.charAt( lineIdx++ ); } return next; } public int read( char[] cbuf, int off, int len ) throws IOException { int fillCount = 0; for ( int i = off; i < off + len; i++ ) { int next = read(); if ( next > -1 ) { cbuf[i] = (char) next; } else { break; } fillCount++; } if ( fillCount == 0 ) { fillCount = -1; } return fillCount; } public long skip( long n ) throws IOException { long skipCount = 0; for ( long i = 0; i < n; i++ ) { int next = read(); if ( next < 0 ) { break; } skipCount++; } return skipCount; } private void readAndInterpolateLine() throws IOException { String rawLine = readLine(); if(rawLine != null) { Set expressions = parseForExpressions( rawLine ); Map evaluatedExpressions = evaluateExpressions( expressions ); String interpolated = replaceWithInterpolatedValues( rawLine, evaluatedExpressions ); if ( interpolated != null && interpolated.length() > 0 ) { line = interpolated; lineIdx = 0; } } else { line = null; lineIdx = -1; } } /* * 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 { StringBuilder lineBuffer = new StringBuilder( 40 ); // half of the "normal" line maxsize int next; boolean lastWasCR = false; while ( ( next = pushbackReader.read() ) > -1 ) { char c = (char) next; if ( c == CARRIAGE_RETURN_CHAR ) { lastWasCR = true; lineBuffer.append( c ); } else if ( c == NEWLINE_CHAR ) { lineBuffer.append( c ); break; // end of line. } else if ( lastWasCR ) { pushbackReader.unread( c ); break; } else { lineBuffer.append( c ); } } if ( lineBuffer.length() < 1 ) { return null; } else { return lineBuffer.toString(); } } private String replaceWithInterpolatedValues( String rawLine, Map evaluatedExpressions ) { String result = rawLine; for ( Object o : evaluatedExpressions.entrySet() ) { Map.Entry entry = (Map.Entry) o; String expression = (String) entry.getKey(); String value = String.valueOf( entry.getValue() ); result = findAndReplaceUnlessEscaped( result, expression, value ); } return result; } private Map evaluateExpressions( Set expressions ) { Map evaluated = new TreeMap(); for ( Object expression : expressions ) { String rawExpression = (String) expression; String realExpression = rawExpression.substring( startDelim.length(), rawExpression.length() - endDelim.length() ); String[] parts = realExpression.split( "\\." ); if ( parts.length > 0 ) { Object value = context.get( parts[0] ); if ( value != null ) { for ( int i = 1; i < parts.length; i++ ) { try { value = reflector.getObjectProperty( value, parts[i] ); if ( value == null ) { break; } } catch ( ReflectorException e ) { // TODO: Fix this! It should report, but not interrupt. e.printStackTrace(); break; } } evaluated.put( rawExpression, value ); } } } return evaluated; } private Set parseForExpressions( String rawLine ) { Set expressions = new HashSet(); if ( rawLine != null ) { int placeholder = -1; do { // find the beginning of the next expression. int start = findDelimiter( rawLine, startDelim, placeholder ); // if we can't find a start-delimiter, then there is no valid expression. Ignore everything else. if ( start < 0 ) { // no expression found. break; } // find the end of the next expression. int end = findDelimiter( rawLine, endDelim, start + 1 ); // if we can't find an end-delimiter, then this is not a valid expression. Ignore it. if ( end < 0 ) { // no VALID expression found. break; } // if we reach this point, we have a valid start and end position, which // means we have a valid expression. So, we add it to the set of // expressions in need of evaluation. expressions.add( rawLine.substring( start, end + endDelim.length() ) ); // increment the placeholder so we can look beyond this expression. placeholder = end + 1; } while ( placeholder < rawLine.length() - minExpressionSize ); } return expressions; } private int findDelimiter( String rawLine, String delimiter, int lastPos ) { int placeholder = lastPos; int position; do { position = rawLine.indexOf( delimiter, placeholder ); if ( position < 0 ) { break; } else { int escEndIdx = rawLine.indexOf( escapeSeq, placeholder ) + escapeSeq.length(); if ( escEndIdx > escapeSeq.length() - 1 && escEndIdx == position ) { placeholder = position + 1; position = -1; } } } while ( position < 0 && placeholder < rawLine.length() - endDelim.length() ); // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // use length() - endDelim.length() b/c otherwise there is nothing left to search. return position; } private String findAndReplaceUnlessEscaped(String rawLine, String search, String replace) { StringBuilder lineBuffer = new StringBuilder( (int) ( rawLine.length() * 1.5 ) ); int lastReplacement = -1; do { int nextReplacement = rawLine.indexOf( search, lastReplacement + 1 ); if(nextReplacement > -1) { if(lastReplacement < 0) { lastReplacement = 0; } lineBuffer.append( rawLine, lastReplacement, nextReplacement ); int escIdx = rawLine.indexOf( escapeSeq, lastReplacement + 1 ); if(escIdx > -1 && escIdx + escapeSeq.length() == nextReplacement) { lineBuffer.setLength( lineBuffer.length() - escapeSeq.length() ); lineBuffer.append( search ); } else { lineBuffer.append( replace ); } lastReplacement = nextReplacement + search.length(); } else { break; } } while(lastReplacement > -1); if( lastReplacement < rawLine.length() ) { lineBuffer.append( rawLine, lastReplacement, rawLine.length() ); } return lineBuffer.toString(); } }plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/MatchPattern.java000066400000000000000000000100001251077732300314760ustar00rootroot00000000000000package 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 ); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/MatchPatterns.java000066400000000000000000000050701251077732300316740ustar00rootroot00000000000000package 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()] ); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/NioFiles.java000066400000000000000000000104761251077732300306350ustar00rootroot00000000000000package 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.io.IOException; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.PosixFilePermission; import java.util.HashSet; import java.util.Set; /** * Encapsulates use of java7 features, exposing mostly backward compatible types */ @SuppressWarnings( "Since15" ) public class NioFiles { public static boolean isSymbolicLink( File file ) { return Files.isSymbolicLink( file.toPath() ); } public static void chmod( File file, int mode ) throws IOException { Path path = file.toPath(); if ( !Files.isSymbolicLink( path ) ) { Files.setPosixFilePermissions( path, getPermissions( mode ) ); } } @SuppressWarnings( { "OctalInteger", "MagicNumber" } ) private static Set getPermissions( int mode ) { Set perms = new HashSet(); //add owners permission if ( ( mode & 0400 ) > 0 ) { perms.add( PosixFilePermission.OWNER_READ ); } if ( ( mode & 0200 ) > 0 ) { perms.add( PosixFilePermission.OWNER_WRITE ); } if ( ( mode & 0100 ) > 0 ) { perms.add( PosixFilePermission.OWNER_EXECUTE ); } //add group permissions if ( ( mode & 0040 ) > 0 ) { perms.add( PosixFilePermission.GROUP_READ ); } if ( ( mode & 0020 ) > 0 ) { perms.add( PosixFilePermission.GROUP_WRITE ); } if ( ( mode & 0010 ) > 0 ) { perms.add( PosixFilePermission.GROUP_EXECUTE ); } //add others permissions if ( ( mode & 0004 ) > 0 ) { perms.add( PosixFilePermission.OTHERS_READ ); } if ( ( mode & 0002 ) > 0 ) { perms.add( PosixFilePermission.OTHERS_WRITE ); } if ( ( mode & 0001 ) > 0 ) { perms.add( PosixFilePermission.OTHERS_EXECUTE ); } return perms; } public static long getLastModified( File file ) throws IOException { BasicFileAttributes basicFileAttributes = Files.readAttributes( file.toPath(), BasicFileAttributes.class ); return basicFileAttributes.lastModifiedTime().toMillis(); } /** * Reads the target of the symbolic link * * @param symlink A file that is a symlink * @return A file that is the target of the symlink * @throws java.io.IOException */ public static File readSymbolicLink( File symlink ) throws IOException { Path path = Files.readSymbolicLink( symlink.toPath() ); return path.toFile(); } public static File createSymbolicLink( File symlink, File target ) throws IOException { Path link = symlink.toPath(); if ( !Files.exists( link, LinkOption.NOFOLLOW_LINKS ) ) { link = Files.createSymbolicLink( link, target.toPath() ); } return link.toFile(); } public static boolean deleteIfExists( File file ) throws IOException { return Files.deleteIfExists( file.toPath() ); } public static File copy( File source, File target ) throws IOException { Path copy = Files.copy( source.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES, LinkOption.NOFOLLOW_LINKS ); return copy.toFile(); } }plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/Os.java000066400000000000000000000315421251077732300275030ustar00rootroot00000000000000/* * The Apache Software License, Version 1.1 * * Copyright (c) 2001-2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "Ant" and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . */ package org.codehaus.plexus.util; import java.util.HashSet; import java.util.Locale; import java.util.Set; /** * Condition that tests the OS type. * * @author Stefan Bodewig * @author Magesh Umasankar * @author Brian Fox * @since 1.0 * @version $Revision$ */ public class Os { // define the families for easier reference public static final String FAMILY_DOS = "dos"; public static final String FAMILY_MAC = "mac"; public static final String FAMILY_NETWARE = "netware"; public static final String FAMILY_OS2 = "os/2"; public static final String FAMILY_TANDEM = "tandem"; public static final String FAMILY_UNIX = "unix"; public static final String FAMILY_WINDOWS = "windows"; public static final String FAMILY_WIN9X = "win9x"; public static final String FAMILY_ZOS = "z/os"; public static final String FAMILY_OS400 = "os/400"; public static final String FAMILY_OPENVMS = "openvms"; // store the valid families private static final Set validFamilies = setValidFamilies(); // get the current info private static final String PATH_SEP = System.getProperty( "path.separator" ); public static final String OS_NAME = System.getProperty( "os.name" ).toLowerCase( Locale.US ); public static final String OS_ARCH = System.getProperty( "os.arch" ).toLowerCase( Locale.US ); public static final String OS_VERSION = System.getProperty( "os.version" ).toLowerCase( Locale.US ); // Make sure this method is called after static fields it depends on have been set! public static final String OS_FAMILY = getOsFamily(); private String family; private String name; private String version; private String arch; /** * Default constructor */ public Os() { } /** * Constructor that sets the family attribute * * @param family a String value */ public Os( String family ) { setFamily( family ); } /** * Initializes the set of valid families. */ private static Set setValidFamilies() { Set valid = new HashSet(); valid.add( FAMILY_DOS ); valid.add( FAMILY_MAC ); valid.add( FAMILY_NETWARE ); valid.add( FAMILY_OS2 ); valid.add( FAMILY_TANDEM ); valid.add( FAMILY_UNIX ); valid.add( FAMILY_WINDOWS ); valid.add( FAMILY_WIN9X ); valid.add( FAMILY_ZOS ); valid.add( FAMILY_OS400 ); valid.add( FAMILY_OPENVMS ); return valid; } /** * Sets the desired OS family type * * @param f The OS family type desired
* Possible values:
*

    *
  • dos
  • *
  • mac
  • *
  • netware
  • *
  • os/2
  • *
  • tandem
  • *
  • unix
  • *
  • windows
  • *
  • win9x
  • *
  • z/os
  • *
  • os/400
  • *
  • openvms
  • *
*/ public void setFamily( String f ) { family = f.toLowerCase( Locale.US ); } /** * Sets the desired OS name * * @param name The OS name */ public void setName( String name ) { this.name = name.toLowerCase( Locale.US ); } /** * Sets the desired OS architecture * * @param arch The OS architecture */ public void setArch( String arch ) { this.arch = arch.toLowerCase( Locale.US ); } /** * Sets the desired OS version * * @param version The OS version */ public void setVersion( String version ) { this.version = version.toLowerCase( Locale.US ); } /** * Determines if the current OS matches the type of that * set in setFamily. * * @see Os#setFamily(String) */ public boolean eval() throws Exception { return isOs( family, name, arch, version ); } /** * Determines if the current OS matches the given OS * family. * * @param family the family to check for * @return true if the OS matches * @since 1.0 */ public static boolean isFamily( String family ) { return isOs( family, null, null, null ); } /** * Determines if the current OS matches the given OS * name. * * @param name the OS name to check for * @return true if the OS matches * @since 1.0 */ public static boolean isName( String name ) { return isOs( null, name, null, null ); } /** * Determines if the current OS matches the given OS * architecture. * * @param arch the OS architecture to check for * @return true if the OS matches * @since 1.0 */ public static boolean isArch( String arch ) { return isOs( null, null, arch, null ); } /** * Determines if the current OS matches the given OS * version. * * @param version the OS version to check for * @return true if the OS matches * @since 1.0 */ public static boolean isVersion( String version ) { return isOs( null, null, null, version ); } /** * Determines if the current OS matches the given OS * family, name, architecture and version. * * The name, archictecture and version are compared to * the System properties os.name, os.version and os.arch * in a case-independent way. * * @param family The OS family * @param name The OS name * @param arch The OS architecture * @param version The OS version * @return true if the OS matches * @since 1.0 */ public static boolean isOs( String family, String name, String arch, String version ) { boolean retValue = false; if ( family != null || name != null || arch != null || version != null ) { boolean isFamily = true; boolean isName = true; boolean isArch = true; boolean isVersion = true; if ( family != null ) { if ( family.equalsIgnoreCase( FAMILY_WINDOWS ) ) { isFamily = OS_NAME.contains( FAMILY_WINDOWS ); } else if ( family.equalsIgnoreCase( FAMILY_OS2 ) ) { isFamily = OS_NAME.contains( FAMILY_OS2 ); } else if ( family.equalsIgnoreCase( FAMILY_NETWARE ) ) { isFamily = OS_NAME.contains( FAMILY_NETWARE ); } else if ( family.equalsIgnoreCase( FAMILY_DOS ) ) { isFamily = PATH_SEP.equals( ";" ) && !isFamily( FAMILY_NETWARE ); } else if ( family.equalsIgnoreCase( FAMILY_MAC ) ) { isFamily = OS_NAME.contains( FAMILY_MAC ); } else if ( family.equalsIgnoreCase( FAMILY_TANDEM ) ) { isFamily = OS_NAME.contains( "nonstop_kernel" ); } else if ( family.equalsIgnoreCase( FAMILY_UNIX ) ) { isFamily = PATH_SEP.equals( ":" ) && !isFamily( FAMILY_OPENVMS ) && ( !isFamily( FAMILY_MAC ) || OS_NAME.endsWith( "x" ) ); } else if ( family.equalsIgnoreCase( FAMILY_WIN9X ) ) { isFamily = isFamily( FAMILY_WINDOWS ) && ( OS_NAME.contains( "95" ) || OS_NAME.contains( "98" ) || OS_NAME.contains( "me" ) || OS_NAME.contains( "ce" ) ); } else if ( family.equalsIgnoreCase( FAMILY_ZOS ) ) { isFamily = OS_NAME.contains( FAMILY_ZOS ) || OS_NAME.contains( "os/390" ); } else if ( family.equalsIgnoreCase( FAMILY_OS400 ) ) { isFamily = OS_NAME.contains( FAMILY_OS400 ); } else if ( family.equalsIgnoreCase( FAMILY_OPENVMS ) ) { isFamily = OS_NAME.contains( FAMILY_OPENVMS ); } else { isFamily = OS_NAME.contains( family.toLowerCase( Locale.US ) ); } } if ( name != null ) { isName = name.toLowerCase( Locale.US ).equals( OS_NAME ); } if ( arch != null ) { isArch = arch.toLowerCase( Locale.US ).equals( OS_ARCH ); } if ( version != null ) { isVersion = version.toLowerCase( Locale.US ).equals( OS_VERSION ); } retValue = isFamily && isName && isArch && isVersion; } return retValue; } /** * Helper method to determine the current OS family. * * @return name of current OS family. * @since 1.4.2 */ private static String getOsFamily() { // in case the order of static initialization is // wrong, get the list // safely. Set families = null; if ( !validFamilies.isEmpty() ) { families = validFamilies; } else { families = setValidFamilies(); } for ( String fam : families ) { if ( Os.isFamily( fam ) ) { return fam; } } return null; } /** * Helper method to check if the given family is in the * following list: *
    *
  • dos
  • *
  • mac
  • *
  • netware
  • *
  • os/2
  • *
  • tandem
  • *
  • unix
  • *
  • windows
  • *
  • win9x
  • *
  • z/os
  • *
  • os/400
  • *
  • openvms
  • *
* * @param theFamily the family to check. * @return true if one of the valid families. * @since 1.4.2 */ public static boolean isValidFamily( String theFamily ) { return ( validFamilies.contains( theFamily ) ); } /** * @return a copy of the valid families * @since 1.4.2 */ public static Set getValidFamilies() { return new HashSet( validFamilies ); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/PathTool.java000066400000000000000000000460401251077732300306530ustar00rootroot00000000000000package 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.StringTokenizer; /** * Path tool contains static methods to assist in determining path-related * information such as relative paths. * * @author Pete Kazmier * @author Vincent Massol * @author Vincent Siveton * @version $Id$ */ public class PathTool { /** * Determines the relative path of a filename from a base directory. * This method is useful in building relative links within pages of * a web site. It provides similar functionality to Anakia's * $relativePath context variable. The arguments to * this method may contain either forward or backward slashes as * file separators. The relative path returned is formed using * forward slashes as it is expected this path is to be used as a * link in a web page (again mimicking Anakia's behavior). *

* This method is thread-safe. *
*

     * PathTool.getRelativePath( null, null )                                   = ""
     * PathTool.getRelativePath( null, "/usr/local/java/bin" )                  = ""
     * PathTool.getRelativePath( "/usr/local/", null )                          = ""
     * PathTool.getRelativePath( "/usr/local/", "/usr/local/java/bin" )         = ".."
     * PathTool.getRelativePath( "/usr/local/", "/usr/local/java/bin/java.sh" ) = "../.."
     * PathTool.getRelativePath( "/usr/local/java/bin/java.sh", "/usr/local/" ) = ""
     * 
* * @param basedir The base directory. * @param filename The filename that is relative to the base * 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. */ public static final String getRelativePath( String basedir, String 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 ) ) { return ""; } /* * Normalize the arguments. First, determine the file separator * that is being used, then strip that off the end of both the * base directory and filename. */ String separator = determineSeparator( filename ); basedir = StringUtils.chompLast( basedir, separator ); filename = StringUtils.chompLast( filename, separator ); /* * Remove the base directory from the filename to end up with a * relative filename (relative to the base directory). This * filename is then used to determine the relative path. */ String relativeFilename = filename.substring( basedir.length() ); return determineRelativePath( relativeFilename, separator ); } /** * Determines the relative path of a filename. This method is * useful in building relative links within pages of a web site. It * provides similar functionality to Anakia's * $relativePath context variable. The argument to * this method may contain either forward or backward slashes as * file separators. The relative path returned is formed using * forward slashes as it is expected this path is to be used as a * link in a web page (again mimicking Anakia's behavior). *

* This method is thread-safe. * * @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. * @see #getRelativeFilePath(String, String) */ public static final String getRelativePath( String filename ) { filename = uppercaseDrive( filename ); if ( filename == null || filename.length() == 0 ) { return ""; } /* * Normalize the argument. First, determine the file separator * that is being used, then strip that off the end of the * filename. Then, if the filename doesn't begin with a * separator, add one. */ String separator = determineSeparator( filename ); filename = StringUtils.chompLast( filename, separator ); if ( !filename.startsWith( separator ) ) { filename = separator + filename; } return determineRelativePath( filename, separator ); } /** * Determines the directory component of a filename. This is useful * within DVSL templates when used in conjunction with the DVSL's * $context.getAppValue("infilename") to get the * current directory that is currently being processed. *

* This method is thread-safe. *
*

     * PathTool.getDirectoryComponent( null )                                   = ""
     * PathTool.getDirectoryComponent( "/usr/local/java/bin" )                  = "/usr/local/java"
     * PathTool.getDirectoryComponent( "/usr/local/java/bin/" )                 = "/usr/local/java/bin"
     * PathTool.getDirectoryComponent( "/usr/local/java/bin/java.sh" )          = "/usr/local/java/bin"
     * 
* * @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. */ public static final String getDirectoryComponent( String filename ) { if ( filename == null || filename.length() == 0 ) { return ""; } String separator = determineSeparator( filename ); String directory = StringUtils.chomp( filename, separator ); if ( filename.equals( directory ) ) { return "."; } return directory; } /** * Calculates the appropriate link given the preferred link and the relativePath of the document. *
*
     * PathTool.calculateLink( "/index.html", "../.." )                                        = "../../index.html"
     * PathTool.calculateLink( "http://plexus.codehaus.org/plexus-utils/index.html", "../.." ) = "http://plexus.codehaus.org/plexus-utils/index.html"
     * PathTool.calculateLink( "/usr/local/java/bin/java.sh", "../.." )                        = "../../usr/local/java/bin/java.sh"
     * PathTool.calculateLink( "../index.html", "/usr/local/java/bin" )                        = "/usr/local/java/bin/../index.html"
     * PathTool.calculateLink( "../index.html", "http://plexus.codehaus.org/plexus-utils" )    = "http://plexus.codehaus.org/plexus-utils/../index.html"
     * 
* * @param link * @param relativePath * @return String */ 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/" ) ) { return link.substring( 5 ); } //Allows absolute links in nav-bars etc if ( link.startsWith( "/absolute/" ) ) { return link.substring( 10 ); } // This traps urls like http:// if ( link.contains( ":" ) ) { return link; } //If relativepath is current directory, just pass the link through if ( StringUtils.equals( relativePath, "." ) ) { if ( link.startsWith( "/" ) ) { 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( "/" ) ) { return relativePath + "." + link.substring( 1 ); } if ( relativePath.endsWith( "/" ) || link.startsWith( "/" ) ) { return relativePath + link; } return relativePath + "/" + link; } /** * This method can calculate the relative path between two pathes on a web site. *
*
     * PathTool.getRelativeWebPath( null, null )                                          = ""
     * PathTool.getRelativeWebPath( null, "http://plexus.codehaus.org/" )                 = ""
     * PathTool.getRelativeWebPath( "http://plexus.codehaus.org/", null )                 = ""
     * PathTool.getRelativeWebPath( "http://plexus.codehaus.org/",
     *                      "http://plexus.codehaus.org/plexus-utils/index.html" )        = "plexus-utils/index.html"
     * PathTool.getRelativeWebPath( "http://plexus.codehaus.org/plexus-utils/index.html",
     *                      "http://plexus.codehaus.org/"                                 = "../../"
     * 
* * @param oldPath * @param newPath * @return a relative web path from oldPath. */ public static final String getRelativeWebPath( final String oldPath, final String newPath ) { if ( StringUtils.isEmpty( oldPath ) || StringUtils.isEmpty( newPath ) ) { return ""; } String resultPath = buildRelativePath( newPath, oldPath, '/' ); if ( newPath.endsWith( "/" ) && !resultPath.endsWith( "/" ) ) { return resultPath + "/"; } return resultPath; } /** * This method can calculate the relative path between two pathes on a file system. *
*
     * PathTool.getRelativeFilePath( null, null )                                   = ""
     * PathTool.getRelativeFilePath( null, "/usr/local/java/bin" )                  = ""
     * PathTool.getRelativeFilePath( "/usr/local", null )                           = ""
     * PathTool.getRelativeFilePath( "/usr/local", "/usr/local/java/bin" )          = "java/bin"
     * PathTool.getRelativeFilePath( "/usr/local", "/usr/local/java/bin/" )         = "java/bin"
     * PathTool.getRelativeFilePath( "/usr/local/java/bin", "/usr/local/" )         = "../.."
     * PathTool.getRelativeFilePath( "/usr/local/", "/usr/local/java/bin/java.sh" ) = "java/bin/java.sh"
     * PathTool.getRelativeFilePath( "/usr/local/java/bin/java.sh", "/usr/local/" ) = "../../.."
     * PathTool.getRelativeFilePath( "/usr/local/", "/bin" )                        = "../../bin"
     * PathTool.getRelativeFilePath( "/bin", "/usr/local/" )                        = "../usr/local"
     * 
* Note: On Windows based system, the / character should be replaced by \ character. * * @param oldPath * @param newPath * @return a relative file path from oldPath. */ public static final String getRelativeFilePath( final String oldPath, final String newPath ) { if ( StringUtils.isEmpty( oldPath ) || StringUtils.isEmpty( newPath ) ) { return ""; } // normalise the path delimiters String fromPath = new File( oldPath ).getPath(); String toPath = new File( newPath ).getPath(); // strip any leading slashes if its a windows path if ( toPath.matches( "^\\[a-zA-Z]:" ) ) { toPath = toPath.substring( 1 ); } if ( fromPath.matches( "^\\[a-zA-Z]:" ) ) { fromPath = fromPath.substring( 1 ); } // lowercase windows drive letters. if ( fromPath.startsWith( ":", 1 ) ) { fromPath = Character.toLowerCase( fromPath.charAt( 0 ) ) + fromPath.substring( 1 ); } if ( toPath.startsWith( ":", 1 ) ) { toPath = Character.toLowerCase( toPath.charAt( 0 ) ) + toPath.substring( 1 ); } // 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 ) ) ) ) { // 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 ) ) ) { // one has a drive path element and the other doesnt, no relative // path. return null; } String resultPath = buildRelativePath( toPath, fromPath, File.separatorChar ); if ( newPath.endsWith( File.separator ) && !resultPath.endsWith( File.separator ) ) { return resultPath + File.separator; } return resultPath; } // ---------------------------------------------------------------------- // Private methods // ---------------------------------------------------------------------- /** * Determines the relative path of a filename. For each separator * within the filename (except the leading if present), append the * "../" string to the return value. * * @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. */ 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. */ int slashCount = StringUtils.countMatches( filename, separator ) - 1; if ( slashCount <= 0 ) { return "."; } /* * The relative filename contains one or more slashes indicating * that the file is within one or more directories. Thus, each * slash represents a "../" in the relative path. */ StringBuilder sb = new StringBuilder(); for ( int i = 0; i < slashCount; i++ ) { sb.append( "../" ); } /* * Finally, return the relative path but strip the trailing * slash to mimic Anakia's behavior. */ return StringUtils.chop( sb.toString() ); } /** * Helper method to determine the file separator (forward or * backward slash) used in a filename. The slash that occurs more * often is returned as the separator. * * @param filename The filename parsed to determine the file * separator. * @return The file separator used within filename. * This value is either a forward or backward slash. */ private static final String determineSeparator( String filename ) { int forwardCount = StringUtils.countMatches( filename, "/" ); int backwardCount = StringUtils.countMatches( filename, "\\" ); return forwardCount >= backwardCount ? "/" : "\\"; } /** * Cygwin prefers lowercase drive letters, but other parts of maven use uppercase * * @param path * @return String */ static final String uppercaseDrive( String path ) { if ( path == null ) { return null; } 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 ) { // use tokeniser to traverse paths and for lazy checking StringTokenizer toTokeniser = new StringTokenizer( toPath, String.valueOf( separatorChar ) ); StringTokenizer fromTokeniser = new StringTokenizer( fromPath, String.valueOf( separatorChar ) ); int count = 0; // walk along the to path looking for divergence from the from path while ( toTokeniser.hasMoreTokens() && fromTokeniser.hasMoreTokens() ) { if ( separatorChar == '\\' ) { if ( !fromTokeniser.nextToken().equalsIgnoreCase( toTokeniser.nextToken() ) ) { break; } } else { if ( !fromTokeniser.nextToken().equals( toTokeniser.nextToken() ) ) { break; } } count++; } // reinitialise the tokenisers to count positions to retrieve the // gobbled token toTokeniser = new StringTokenizer( toPath, String.valueOf( separatorChar ) ); fromTokeniser = new StringTokenizer( fromPath, String.valueOf( separatorChar ) ); while ( count-- > 0 ) { fromTokeniser.nextToken(); toTokeniser.nextToken(); } String relativePath = ""; // add back refs for the rest of from location. while ( fromTokeniser.hasMoreTokens() ) { fromTokeniser.nextToken(); relativePath += ".."; if ( fromTokeniser.hasMoreTokens() ) { relativePath += separatorChar; } } if ( relativePath.length() != 0 && toTokeniser.hasMoreTokens() ) { relativePath += separatorChar; } // add fwd fills for whatevers left of newPath. while ( toTokeniser.hasMoreTokens() ) { relativePath += toTokeniser.nextToken(); if ( toTokeniser.hasMoreTokens() ) { relativePath += separatorChar; } } return relativePath; } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/PropertyUtils.java000066400000000000000000000043521251077732300317660ustar00rootroot00000000000000package 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.util.Properties; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.IOException; import java.net.URL; /** * Static methods to create Properties loaded from various sources. * * @author Jason van Zyl * @author Michal Maczka * * @version $Id$ */ public class PropertyUtils { public static Properties loadProperties( URL url ) { try { return loadProperties( url.openStream() ); } catch ( Exception e ) { // ignore } return null; } public static Properties loadProperties( File file ) { try { return loadProperties( new FileInputStream( file ) ); } catch ( Exception e ) { // ignore } return null; } public static Properties loadProperties( InputStream is ) { try { Properties properties = new Properties(); // Make sure the properties stream is valid if ( is != null ) { properties.load( is ); } return properties; } catch ( IOException e ) { // ignore } finally { try { if ( is != null ) { is.close(); } } catch ( IOException e ) { // ignore } } return null; } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/ReaderFactory.java000066400000000000000000000165241251077732300316570ustar00rootroot00000000000000package 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.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.UnsupportedEncodingException; import java.net.URL; import java.nio.charset.Charset; import org.codehaus.plexus.util.xml.XmlStreamReader; /** * Utility to create Readers from streams, with explicit encoding choice: platform default, * XML, or specified. * * @author Herve Boutemy * @see Charset * @see Supported encodings * @version $Id$ * @since 1.4.3 */ public class ReaderFactory { /** * ISO Latin Alphabet #1, also known as ISO-LATIN-1. * Every implementation of the Java platform is required to support this character encoding. * @see Charset */ public static final String ISO_8859_1 = "ISO-8859-1"; /** * Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block of the Unicode character set. * Every implementation of the Java platform is required to support this character encoding. * @see Charset */ public static final String US_ASCII = "US-ASCII"; /** * Sixteen-bit Unicode Transformation Format, byte order specified by a mandatory initial byte-order mark (either * order accepted on input, big-endian used on output). * Every implementation of the Java platform is required to support this character encoding. * @see Charset */ public static final String UTF_16 = "UTF-16"; /** * Sixteen-bit Unicode Transformation Format, big-endian byte order. * Every implementation of the Java platform is required to support this character encoding. * @see Charset */ public static final String UTF_16BE = "UTF-16BE"; /** * Sixteen-bit Unicode Transformation Format, little-endian byte order. * Every implementation of the Java platform is required to support this character encoding. * @see Charset */ public static final String UTF_16LE = "UTF-16LE"; /** * Eight-bit Unicode Transformation Format. * Every implementation of the Java platform is required to support this character encoding. * @see Charset */ public static final String UTF_8 = "UTF-8"; /** * The file.encoding System Property. */ public static final String FILE_ENCODING = System.getProperty( "file.encoding" ); /** * Create a new Reader with XML encoding detection rules. * * @param in not null input stream. * @return an XML reader instance for the input stream. * @throws IOException if any. * @see XmlStreamReader */ public static XmlStreamReader newXmlReader( InputStream in ) throws IOException { return new XmlStreamReader( in ); } /** * Create a new Reader with XML encoding detection rules. * * @param file not null file. * @return an XML reader instance for the input file. * @throws IOException if any. * @see XmlStreamReader */ public static XmlStreamReader newXmlReader( File file ) throws IOException { return new XmlStreamReader( file ); } /** * Create a new Reader with XML encoding detection rules. * * @param url not null url. * @return an XML reader instance for the input url. * @throws IOException if any. * @see XmlStreamReader */ public static XmlStreamReader newXmlReader( URL url ) throws IOException { return new XmlStreamReader( url ); } /** * Create a new Reader with default plaform encoding. * * @param in not null input stream. * @return a reader instance for the input stream using the default platform charset. * @see Charset#defaultCharset() */ public static Reader newPlatformReader( InputStream in ) { return new InputStreamReader( in ); } /** * Create a new Reader with default plaform encoding. * * @param file not null file. * @return a reader instance for the input file using the default platform charset. * @throws FileNotFoundException if any. * @see Charset#defaultCharset() */ public static Reader newPlatformReader( File file ) throws FileNotFoundException { return new FileReader( file ); } /** * Create a new Reader with default plaform encoding. * * @param url not null url. * @return a reader instance for the input url using the default platform charset. * @throws IOException if any. * @see Charset#defaultCharset() */ public static Reader newPlatformReader( URL url ) throws IOException { return new InputStreamReader( url.openStream() ); } /** * Create a new Reader with specified encoding. * * @param in not null input stream. * @param encoding not null supported encoding. * @return a reader instance for the input stream using the given encoding. * @throws UnsupportedEncodingException if any. * @see Supported encodings */ public static Reader newReader( InputStream in, String encoding ) throws UnsupportedEncodingException { return new InputStreamReader( in, 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. * @throws FileNotFoundException if any. * @throws UnsupportedEncodingException if any. * @see Supported encodings */ public static Reader newReader( File file, String encoding ) throws FileNotFoundException, UnsupportedEncodingException { return new InputStreamReader( new FileInputStream(file), encoding ); } /** * Create a new Reader with specified encoding. * * @param url not null url. * @param encoding not null supported encoding. * @return a reader instance for the input url using the given encoding. * @throws IOException if any. * @see Supported encodings */ public static Reader newReader( URL url, String encoding ) throws IOException { return new InputStreamReader( url.openStream(), encoding ); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/ReflectionUtils.java000066400000000000000000000161771251077732300322440ustar00rootroot00000000000000package 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.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.AccessibleObject; import java.util.Map; import java.util.HashMap; import java.util.List; import java.util.ArrayList; import java.util.Arrays; /** * Operations on a class' fields and their setters. * * @author Michal Maczka * @author Jesse McConnell * @author Trygve Laugstøl * @version $Id$ */ public final class ReflectionUtils { // ---------------------------------------------------------------------- // Field utils // ---------------------------------------------------------------------- public static Field getFieldByNameIncludingSuperclasses( String fieldName, Class clazz ) { Field retValue = null; try { retValue = clazz.getDeclaredField( fieldName ); } catch ( NoSuchFieldException e ) { Class superclass = clazz.getSuperclass(); if ( superclass != null ) { retValue = getFieldByNameIncludingSuperclasses( fieldName, superclass ); } } return retValue; } public static List getFieldsIncludingSuperclasses( Class clazz ) { List fields = new ArrayList( Arrays.asList( clazz.getDeclaredFields() ) ); Class superclass = clazz.getSuperclass(); if ( superclass != null ) { fields.addAll( getFieldsIncludingSuperclasses( superclass ) ); } return fields; } // ---------------------------------------------------------------------- // Setter utils // ---------------------------------------------------------------------- /** * Finds a setter in the given class for the given field. It searches * interfaces and superclasses too. * * @param fieldName the name of the field (i.e. 'fooBar'); it will search for a method named 'setFooBar'. * @param clazz The class to find the method in. * @return null or the method found. */ public static Method getSetter( String fieldName, Class clazz ) { Method[] methods = clazz.getMethods(); fieldName = "set" + StringUtils.capitalizeFirstLetter( fieldName ); for ( Method method : methods ) { if ( method.getName().equals( fieldName ) && isSetter( method ) ) { return method; } } return null; } /** * Finds all setters in the given class and super classes. */ public static List getSetters( Class clazz ) { Method[] methods = clazz.getMethods(); List list = new ArrayList(); for ( Method method : methods ) { if ( isSetter( method ) ) { list.add( method ); } } return list; } /** * Returns the class of the argument to the setter. * * Will throw an RuntimeException if the method isn't a setter. */ public static Class getSetterType( Method method ) { if ( !isSetter( method ) ) { throw new RuntimeException( "The method " + method.getDeclaringClass().getName() + "." + method.getName() + " is not a setter." ); } return method.getParameterTypes()[0]; } // ---------------------------------------------------------------------- // Value accesstors // ---------------------------------------------------------------------- /** * attempts to set the value to the variable in the object passed in * * @param object * @param variable * @param value * @throws IllegalAccessException */ public static void setVariableValueInObject( Object object, String variable, Object value ) throws IllegalAccessException { Field field = getFieldByNameIncludingSuperclasses( variable, object.getClass() ); field.setAccessible( true ); field.set(object, value ); } /** * Generates a map of the fields and values on a given object, * also pulls from superclasses * * @param object the object to generate the list of fields from * @return map containing the fields and their values */ public static Object getValueIncludingSuperclasses( String variable, Object object ) throws IllegalAccessException { Field field = getFieldByNameIncludingSuperclasses( variable, object.getClass() ); field.setAccessible( true ); return field.get( object ); } /** * Generates a map of the fields and values on a given object, * also pulls from superclasses * * @param object the object to generate the list of fields from * @return map containing the fields and their values */ public static Map getVariablesAndValuesIncludingSuperclasses( Object object ) throws IllegalAccessException { Map map = new HashMap(); gatherVariablesAndValuesIncludingSuperclasses( object, map ); return map; } // ---------------------------------------------------------------------- // Private // ---------------------------------------------------------------------- public static boolean isSetter( Method method ) { return method.getReturnType().equals( Void.TYPE ) && // FIXME: needed /required? !Modifier.isStatic( method.getModifiers() ) && method.getParameterTypes().length == 1; } /** * populates a map of the fields and values on a given object, * also pulls from superclasses * * @param object the object to generate the list of fields from * @param map to populate */ private static void gatherVariablesAndValuesIncludingSuperclasses( Object object, Map map ) throws IllegalAccessException { Class clazz = object.getClass(); Field[] fields = clazz.getDeclaredFields(); AccessibleObject.setAccessible( fields, true); for ( Field field : fields ) { map.put( field.getName(), field.get( object ) ); } Class superclass = clazz.getSuperclass(); if ( !Object.class.equals( superclass ) ) { gatherVariablesAndValuesIncludingSuperclasses( superclass, map ); } } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/Scanner.java000066400000000000000000000066221251077732300305140ustar00rootroot00000000000000package 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; /** * Scan a directory tree for files, with specified inclusions and exclusions. */ public interface Scanner { /** * 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. */ 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. * May be null, indicating that no files * should be excluded. If a non-null list is * given, all elements must be non-null. */ void setExcludes(String[] excludes); /** * Adds default exclusions to the current exclusions set. */ void addDefaultExcludes(); /** * Scans the base directory for files which match at least one include * pattern and don't match any exclude patterns. * * @exception IllegalStateException if the base directory was set * incorrectly (i.e. if it is null, doesn't exist, * or isn't a directory). */ void scan(); /** * Returns the names of the files which matched at least one of the * include patterns and none of the exclude patterns. * The names are relative to the base directory. * * @return the names of the files which matched at least one of the * include patterns and none of the exclude patterns. */ String[] getIncludedFiles(); /** * Returns the names of the directories which matched at least one of the * include patterns and none of the exclude patterns. * 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. */ String[] getIncludedDirectories(); /** * Returns the base directory to be scanned. * This is the directory which is scanned recursively. * * @return the base directory to be scanned */ File getBasedir(); } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/SelectorUtils.java000066400000000000000000000716571251077732300317360ustar00rootroot00000000000000/* * The Apache Software License, Version 1.1 * * Copyright (c) 2002-2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.codehaus.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "Ant" and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact codehaus@codehaus.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . */ package org.codehaus.plexus.util; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; /** *

This is a utility class used by selectors and DirectoryScanner. The * functionality more properly belongs just to selectors, but unfortunately * DirectoryScanner exposed these as protected methods. Thus we have to * support any subclasses of DirectoryScanner that may access these methods. *

*

This is a Singleton.

* * @author Arnout J. Kuiper * ajkuiper@wxs.nl * @author Magesh Umasankar * @author Bruce Atherton * @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(); /** * Private Constructor */ private SelectorUtils() { } /** * Retrieves the manager of the Singleton. */ public static SelectorUtils getInstance() { return instance; } /** * 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. * @return whether or not a given path matches the start of a given * pattern up to the first "**". */ public static boolean matchPatternStart( String pattern, String str ) { return matchPatternStart( pattern, str, true ); } /** * 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 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 "**". */ public static boolean matchPatternStart( String pattern, String str, boolean isCaseSensitive ) { 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... return true; } else { if ( isAntPrefixedPattern( pattern ) ) { 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 ); } } 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 ( separatorPatternStartSlashMismatch( pattern, str, separator ) ) { return false; } 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.length - 1; int strIdxStart = 0; int strIdxEnd = strDirs.length - 1; // up to first '**' while ( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd ) { String patDir = patDirs[patIdxStart]; if ( patDir.equals( "**" ) ) { break; } if ( !match( patDir, strDirs[strIdxStart], isCaseSensitive ) ) { return false; } patIdxStart++; strIdxStart++; } return strIdxStart > strIdxEnd || patIdxStart <= patIdxEnd; } /** * 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. * @return true if the pattern matches against the string, * or false otherwise. */ public static boolean matchPath( String pattern, String str ) { return matchPath( pattern, str, true ); } /** * 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 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 ) { return matchPath( pattern, str, File.separator, isCaseSensitive ); } public static boolean matchPath( String pattern, String str, String separator, boolean isCaseSensitive ) { if ( isRegexPrefixedPattern( pattern ) ) { pattern = pattern.substring( REGEX_HANDLER_PREFIX.length(), pattern.length() - PATTERN_HANDLER_SUFFIX.length() ); return str.matches( pattern ); } else { if ( isAntPrefixedPattern( pattern ) ) { pattern = pattern.substring( ANT_HANDLER_PREFIX.length(), pattern.length() - PATTERN_HANDLER_SUFFIX.length() ); } return matchAntPathPattern( pattern, str, separator, isCaseSensitive ); } } static boolean isRegexPrefixedPattern( String pattern ) { 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 ); } static boolean matchAntPathPattern( String[] patDirs, String[] 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 ) { String patDir = patDirs[patIdxStart]; if ( patDir.equals( "**" ) ) { 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 ( !patDirs[i].equals( "**" ) ) { 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 ) { String patDir = patDirs[patIdxEnd]; if ( patDir.equals( "**" ) ) { 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 ( !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 ) ) { 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:
* '*' 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. * @return true if the string matches against the pattern, * or false otherwise. */ public static boolean match( String pattern, String str ) { return match( pattern, str, true ); } /** * 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 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 ) { 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; int strIdxEnd = strArr.length - 1; char ch; boolean containsStar = false; for ( char aPatArr : patArr ) { if ( aPatArr == '*' ) { containsStar = true; break; } } if ( !containsStar ) { // No '*'s, so we make a shortcut if ( patIdxEnd != strIdxEnd ) { return false; // Pattern and string do not have the same size } for ( int i = 0; i <= patIdxEnd; i++ ) { ch = patArr[i]; if ( ch != '?' && !equals( ch, strArr[i], isCaseSensitive ) ) { return false; // Character mismatch } } return true; // String matches against pattern } if ( patIdxEnd == 0 ) { return true; // Pattern contains only '*', which matches anything } // Process characters before first star while ( ( ch = patArr[patIdxStart] ) != '*' && strIdxStart <= strIdxEnd ) { if ( ch != '?' && !equals( ch, strArr[strIdxStart], isCaseSensitive ) ) { return false; // Character mismatch } patIdxStart++; strIdxStart++; } if ( strIdxStart > strIdxEnd ) { // All characters in the string are used. Check if only '*'s are // left in the pattern. If so, we succeeded. Otherwise failure. for ( int i = patIdxStart; i <= patIdxEnd; i++ ) { if ( patArr[i] != '*' ) { return false; } } return true; } // Process characters after last star while ( ( ch = patArr[patIdxEnd] ) != '*' && strIdxStart <= strIdxEnd ) { if ( ch != '?' && !equals( ch, strArr[strIdxEnd], isCaseSensitive ) ) { return false; // Character mismatch } patIdxEnd--; strIdxEnd--; } if ( strIdxStart > strIdxEnd ) { // All characters in the string are used. Check if only '*'s are // left in the pattern. If so, we succeeded. Otherwise failure. for ( int i = patIdxStart; i <= patIdxEnd; i++ ) { if ( patArr[i] != '*' ) { return false; } } return true; } // process pattern between stars. padIdxStart and patIdxEnd point // always to a '*'. while ( patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd ) { int patIdxTmp = -1; for ( int i = patIdxStart + 1; i <= patIdxEnd; i++ ) { if ( patArr[i] == '*' ) { patIdxTmp = i; break; } } if ( patIdxTmp == patIdxStart + 1 ) { // Two stars next to each other, skip the first 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++ ) { ch = patArr[patIdxStart + j + 1]; if ( ch != '?' && !equals( ch, strArr[strIdxStart + i + j], isCaseSensitive ) ) { continue strLoop; } } foundIdx = strIdxStart + i; break; } if ( foundIdx == -1 ) { return false; } patIdxStart = patIdxTmp; strIdxStart = foundIdx + patLength; } // All characters in the string are used. Check if only '*'s are left // in the pattern. If so, we succeeded. Otherwise failure. for ( int i = patIdxStart; i <= patIdxEnd; i++ ) { if ( patArr[i] != '*' ) { return false; } } return true; } /** * Tests whether two characters are equal. */ private static boolean equals( char c1, char c2, boolean isCaseSensitive ) { if ( c1 == c2 ) { return true; } 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 ) ) { return true; } } return false; } private 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()] ); } /** * Returns dependency information on these two files. If src has been * modified later than target, it returns true. If target doesn't exist, * it likewise returns true. Otherwise, target is newer than src and * is not out of date, thus the method returns false. It also returns * 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 granularity the amount in seconds of slack we will give in * determining out of dateness * @return whether the target is out of date */ public static boolean isOutOfDate( File src, File target, int granularity ) { if ( !src.exists() ) { return false; } if ( !target.exists() ) { return true; } if ( ( src.lastModified() - granularity ) > target.lastModified() ) { return true; } return false; } /** * "Flattens" a string by removing all whitespace (space, tab, linefeed, * carriage return, and formfeed). This uses StringTokenizer and the * default set of tokens as documented in the single arguement constructor. * * @param input a String to remove all whitespace. * @return a String that has had all whitespace removed. */ public static String removeWhitespace( String input ) { StringBuilder result = new StringBuilder(); if ( input != null ) { StringTokenizer st = new StringTokenizer( input ); while ( st.hasMoreTokens() ) { result.append( st.nextToken() ); } } return result.toString(); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/StringInputStream.java000066400000000000000000000121661251077732300325650ustar00rootroot00000000000000package org.codehaus.plexus.util; /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.codehaus.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" and * "Apache MavenSession" must not be used to endorse or promote products * derived from this software without prior written permission. For * written permission, please contact codehaus@codehaus.org. * * 5. Products derived from this software may not be called "Apache", * "Apache MavenSession", nor may "Apache" appear in their name, without * prior written permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * * ==================================================================== */ import java.io.IOException; import java.io.InputStream; import java.io.StringReader; /** * Wraps a String as an InputStream. Note that data will be lost for * characters not in ISO Latin 1, as a simple char->byte mapping is assumed. * * @author Magesh Umasankar * @deprecated As of version 1.5.2 this class should no longer be used because it does not properly handle character * encoding. Instead, wrap the output from {@link String#getBytes(String)} into a * {@link java.io.ByteArrayInputStream}. */ public class StringInputStream extends InputStream { /** Source string, stored as a StringReader */ private StringReader in; /** * Composes a stream from a String * * @param source The string to read from. Must not be null. */ public StringInputStream( String source ) { in = new StringReader( source ); } /** * Reads from the Stringreader, returning the same value. Note that * data will be lost for characters not in ISO Latin 1. Clients * assuming a return value in the range -1 to 255 may even fail on * such input. * * @return the value of the next character in the StringReader * * @exception IOException if the original StringReader fails to be read */ public int read() throws IOException { return in.read(); } /** * Closes the Stringreader. * * @exception IOException if the original StringReader fails to be closed */ public void close() throws IOException { in.close(); } /** * Marks the read limit of the StringReader. * * @param limit the maximum limit of bytes that can be read before the * mark position becomes invalid */ public synchronized void mark( final int limit ) { try { in.mark( limit ); } catch ( IOException ioe ) { throw new RuntimeException( ioe.getMessage() ); } } /** * Resets the StringReader. * * @exception IOException if the StringReader fails to be reset */ public synchronized void reset() throws IOException { in.reset(); } /** * @see InputStream#markSupported */ public boolean markSupported() { return in.markSupported(); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/StringOutputStream.java000066400000000000000000000031461251077732300327640ustar00rootroot00000000000000package 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.IOException; import java.io.OutputStream; /** * Wraps a String as an OutputStream. * * @author Emmanuel Venisse * @version $Id$ * @deprecated As of version 1.5.2 this class should no longer be used because it does not properly handle character * encoding. Instead, use {@link java.io.ByteArrayOutputStream#toString(String)}. */ public class StringOutputStream extends OutputStream { private StringBuffer buf = new StringBuffer(); public void write( byte[] b ) throws IOException { buf.append( new String( b ) ); } public void write( byte[] b, int off, int len ) throws IOException { buf.append( new String( b, off, len ) ); } public void write( int b ) throws IOException { byte[] bytes = new byte[1]; bytes[0] = (byte)b; buf.append( new String( bytes ) ); } public String toString() { return buf.toString(); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/StringUtils.java000066400000000000000000002271461251077732300314200ustar00rootroot00000000000000/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.codehaus.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Commons", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact codehaus@codehaus.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . */ package org.codehaus.plexus.util; import java.util.Arrays; import java.util.Iterator; import java.util.Locale; import java.util.Map; import java.util.StringTokenizer; /** *

Common String manipulation routines.

* *

Originally from * Turbine and the * GenerationJavaCore library.

* * @author Jon S. Stevens * @author Daniel Rall * @author Greg Coladonato * @author Henri Yandell * @author Ed Korthof * @author Rand McNeely * @author Stephen Colebourne * @author Fredrik Westermarck * @author Holger Krauth * @author Alexander Day Chaffee * @author Vincent Siveton * @since 1.0 * @version $Id$ */ public class StringUtils { /** *

StringUtils instances should NOT be constructed in * standard programming. Instead, the class should be used as * StringUtils.trim(" foo ");.

* *

This constructor is public to permit tools that require a JavaBean * manager to operate.

*/ public StringUtils() { } // Empty //-------------------------------------------------------------------------- /** *

Removes control characters, including whitespace, from both * ends of this String, handling null by returning * an empty String.

* * @see java.lang.String#trim() * @param str the String to check * @return the trimmed text (never null) */ public static String clean( String str ) { return ( str == null ? "" : str.trim() ); } /** *

Removes control characters, including whitespace, from both * ends of this String, handling null by returning * null.

* * @see java.lang.String#trim() * @param str the String to check * @return the trimmed text (or null) */ public static String trim( String str ) { return ( str == null ? null : str.trim() ); } /** *

Deletes all whitespaces from a String.

* *

Whitespace is defined by * {@link Character#isWhitespace(char)}.

* * @param str String target to delete whitespace from * @return the String without whitespaces * @throws NullPointerException */ public static String deleteWhitespace( String str ) { StringBuilder buffer = new StringBuilder(); int sz = str.length(); for ( int i = 0; i < sz; i++ ) { if ( !Character.isWhitespace( str.charAt( i ) ) ) { buffer.append( str.charAt( i ) ); } } return buffer.toString(); } /** *

Checks if a String is non null and is * not empty (length > 0).

* * @param str the String to check * @return true if the String is non-null, and not length zero */ public static boolean isNotEmpty( String str ) { return ( ( str != null ) && ( str.length() > 0 ) ); } /** *

Checks if a (trimmed) String is null or empty.

* *

Note: In future releases, this method will no longer trim the input string such that it works * complementary to {@link #isNotEmpty(String)}. Code that wants to test for whitespace-only strings should be * migrated to use {@link #isBlank(String)} instead.

* * @param str the String to check * @return true if the String is null, or * length zero once trimmed */ public static boolean isEmpty( String str ) { return ( ( str == null ) || ( str.trim().length() == 0 ) ); } /** *

* Checks if a String is whitespace, empty ("") or null. *

* *
     * StringUtils.isBlank(null)      = true
     * StringUtils.isBlank("")        = true
     * StringUtils.isBlank(" ")       = true
     * StringUtils.isBlank("bob")     = false
     * StringUtils.isBlank("  bob  ") = false
     * 
* * @param str the String to check, may be null * @return true if the String is null, empty or whitespace * @since 1.5.2 */ public static boolean isBlank( String str ) { int strLen; if ( str == null || ( strLen = str.length() ) == 0 ) { return true; } for ( int i = 0; i < strLen; i++ ) { if ( !Character.isWhitespace( str.charAt( i ) ) ) { return false; } } return true; } /** *

* Checks if a String is not empty (""), not null and not whitespace only. *

* *
     * StringUtils.isNotBlank(null)      = false
     * StringUtils.isNotBlank("")        = false
     * StringUtils.isNotBlank(" ")       = false
     * StringUtils.isNotBlank("bob")     = true
     * StringUtils.isNotBlank("  bob  ") = true
     * 
* * @param str the String to check, may be null * @return true if the String is not empty and not null and not whitespace * @since 1.5.2 */ public static boolean isNotBlank( String str ) { return !StringUtils.isBlank( str ); } // Equals and IndexOf //-------------------------------------------------------------------------- /** *

Compares two Strings, returning true if they are equal.

* *

nulls are handled without exceptions. Two null * references are considered to be equal. The comparison is case sensitive.

* * @see java.lang.String#equals(Object) * @param str1 the first string * @param str2 the second string * @return true if the Strings are equal, case sensitive, or * both null */ public static boolean equals( String str1, String str2 ) { return ( str1 == null ? str2 == null : str1.equals( str2 ) ); } /** *

Compares two Strings, returning true if they are equal ignoring * the case.

* *

Nulls are handled without exceptions. Two null * references are considered equal. Comparison is case insensitive.

* * @see java.lang.String#equalsIgnoreCase(String) * @param str1 the first string * @param str2 the second string * @return true if the Strings are equal, case insensitive, or * both null */ public static boolean equalsIgnoreCase( String str1, String str2 ) { return ( str1 == null ? str2 == null : str1.equalsIgnoreCase( str2 ) ); } /** *

Find the first index of any of a set of potential substrings.

* *

null String will return -1.

* * @param str the String to check * @param searchStrs the Strings to search for * @return the first index of any of the searchStrs in str * @throws NullPointerException if any of searchStrs[i] is null */ public static int indexOfAny( String str, String[] searchStrs ) { if ( ( str == null ) || ( searchStrs == null ) ) { return -1; } int sz = searchStrs.length; // String's can't have a MAX_VALUEth index. int ret = Integer.MAX_VALUE; int tmp; for ( String searchStr : searchStrs ) { tmp = str.indexOf( searchStr ); if ( tmp == -1 ) { continue; } if ( tmp < ret ) { ret = tmp; } } return ( ret == Integer.MAX_VALUE ) ? -1 : ret; } /** *

Find the latest index of any of a set of potential substrings.

* *

null string will return -1.

* * @param str the String to check * @param searchStrs the Strings to search for * @return the last index of any of the Strings * @throws NullPointerException if any of searchStrs[i] is null */ public static int lastIndexOfAny( String str, String[] searchStrs ) { if ( ( str == null ) || ( searchStrs == null ) ) { return -1; } int ret = -1; int tmp; for ( String searchStr : searchStrs ) { tmp = str.lastIndexOf( searchStr ); if ( tmp > ret ) { ret = tmp; } } return ret; } // Substring //-------------------------------------------------------------------------- /** *

Gets a substring from the specified string avoiding exceptions.

* *

A negative start position can be used to start n * characters from the end of the String.

* * @param str the String to get the substring from * @param start the position to start from, negative means * count back from the end of the String by this many characters * @return substring from start position */ public static String substring( String str, int start ) { if ( str == null ) { return null; } // handle negatives, which means last n characters if ( start < 0 ) { start = str.length() + start; // remember start is negative } if ( start < 0 ) { start = 0; } if ( start > str.length() ) { return ""; } return str.substring( start ); } /** *

Gets a substring from the specified String avoiding exceptions.

* *

A negative start position can be used to start/end n * characters from the end of the String.

* * @param str the String to get the substring from * @param start the position to start from, negative means * count back from the end of the string by this many characters * @param end the position to end at (exclusive), negative means * count back from the end of the String by this many characters * @return substring from start position to end positon */ public static String substring( String str, int start, int end ) { if ( str == null ) { return null; } // handle negatives if ( end < 0 ) { end = str.length() + end; // remember end is negative } if ( start < 0 ) { start = str.length() + start; // remember start is negative } // check length next if ( end > str.length() ) { // check this works. end = str.length(); } // if start is greater than end, return "" if ( start > end ) { return ""; } if ( start < 0 ) { start = 0; } if ( end < 0 ) { end = 0; } return str.substring( start, end ); } /** *

Gets the leftmost n characters of a String.

* *

If n characters are not available, or the * String is null, the String will be returned without * an exception.

* * @param str the String to get the leftmost characters from * @param len the length of the required String * @return the leftmost characters * @throws IllegalArgumentException if len is less than zero */ public static String left( String str, int len ) { if ( len < 0 ) { throw new IllegalArgumentException( "Requested String length " + len + " is less than zero" ); } if ( ( str == null ) || ( str.length() <= len ) ) { return str; } else { return str.substring( 0, len ); } } /** *

Gets the rightmost n characters of a String.

* *

If n characters are not available, or the String * is null, the String will be returned without an * exception.

* * @param str the String to get the rightmost characters from * @param len the length of the required String * @return the leftmost characters * @throws IllegalArgumentException if len is less than zero */ public static String right( String str, int len ) { if ( len < 0 ) { throw new IllegalArgumentException( "Requested String length " + len + " is less than zero" ); } if ( ( str == null ) || ( str.length() <= len ) ) { return str; } else { return str.substring( str.length() - len ); } } /** *

Gets n characters from the middle of a String.

* *

If n characters are not available, the remainder * of the String will be returned without an exception. If the * String is null, null will be returned.

* * @param str the String to get the characters from * @param pos the position to start from * @param len the length of the required String * @return the leftmost characters * @throws IndexOutOfBoundsException if pos is out of bounds * @throws IllegalArgumentException if len is less than zero */ public static String mid( String str, int pos, int len ) { if ( ( pos < 0 ) || ( ( str != null ) && ( pos > str.length() ) ) ) { throw new StringIndexOutOfBoundsException( "String index " + pos + " is out of bounds" ); } if ( len < 0 ) { throw new IllegalArgumentException( "Requested String length " + len + " is less than zero" ); } if ( str == null ) { return null; } if ( str.length() <= ( pos + len ) ) { return str.substring( pos ); } else { return str.substring( pos, pos + len ); } } // Splitting //-------------------------------------------------------------------------- /** *

Splits the provided text into a array, using whitespace as the * separator.

* *

The separator is not included in the returned String array.

* * @param str the String to parse * @return an array of parsed Strings */ public static String[] split( String str ) { return split( str, null, -1 ); } /** * @see #split(String, String, int) */ public static String[] split( String text, String separator ) { return split( text, separator, -1 ); } /** *

Splits the provided text into a array, based on a given separator.

* *

The separator is not included in the returned String array. The * maximum number of splits to perfom can be controlled. A null * separator will cause parsing to be on whitespace.

* *

This is useful for quickly splitting a String directly into * an array of tokens, instead of an enumeration of tokens (as * StringTokenizer does).

* * @param str The string to parse. * @param separator Characters used as the delimiters. If * null, splits on whitespace. * @param max The maximum number of elements to include in the * array. A zero or negative value implies no limit. * @return an array of parsed Strings */ public static String[] split( String str, String separator, int max ) { StringTokenizer tok; if ( separator == null ) { // Null separator means we're using StringTokenizer's default // delimiter, which comprises all whitespace characters. tok = new StringTokenizer( str ); } else { tok = new StringTokenizer( str, separator ); } int listSize = tok.countTokens(); if ( ( max > 0 ) && ( listSize > max ) ) { listSize = max; } String[] list = new String[listSize]; int i = 0; int lastTokenBegin; int lastTokenEnd = 0; while ( tok.hasMoreTokens() ) { if ( ( max > 0 ) && ( i == listSize - 1 ) ) { // In the situation where we hit the max yet have // tokens left over in our input, the last list // element gets all remaining text. String endToken = tok.nextToken(); lastTokenBegin = str.indexOf( endToken, lastTokenEnd ); list[i] = str.substring( lastTokenBegin ); break; } else { list[i] = tok.nextToken(); lastTokenBegin = str.indexOf( list[i], lastTokenEnd ); lastTokenEnd = lastTokenBegin + list[i].length(); } i++; } return list; } // Joining //-------------------------------------------------------------------------- /** *

Concatenates elements of an array into a single String.

* *

The difference from join is that concatenate has no delimiter.

* * @param array the array of values to concatenate. * @return the concatenated string. */ public static String concatenate( Object[] array ) { return join( array, "" ); } /** *

Joins the elements of the provided array into a single String * containing the provided list of elements.

* *

No delimiter is added before or after the list. A * null separator is the same as a blank String.

* * @param array the array of values to join together * @param separator the separator character to use * @return the joined String */ public static String join( Object[] array, String separator ) { if ( separator == null ) { separator = ""; } int arraySize = array.length; int bufSize = ( arraySize == 0 ? 0 : ( array[0].toString().length() + separator.length() ) * arraySize ); StringBuilder buf = new StringBuilder( bufSize ); for ( int i = 0; i < arraySize; i++ ) { if ( i > 0 ) { buf.append( separator ); } buf.append( array[i] ); } return buf.toString(); } /** *

Joins the elements of the provided Iterator into * a single String containing the provided elements.

* *

No delimiter is added before or after the list. A * null separator is the same as a blank String.

* * @param iterator the Iterator of values to join together * @param separator the separator character to use * @return the joined String */ public static String join( Iterator iterator, String separator ) { if ( separator == null ) { separator = ""; } StringBuilder buf = new StringBuilder( 256 ); // Java default is 16, probably too small while ( iterator.hasNext() ) { buf.append( iterator.next() ); if ( iterator.hasNext() ) { buf.append( separator ); } } return buf.toString(); } // Replacing //-------------------------------------------------------------------------- /** *

Replace a char with another char inside a larger String, once.

* *

A null reference passed to this method is a no-op.

* * @see #replace(String text, char repl, char with, int max) * @param text text to search and replace in * @param repl char to search for * @param with char to replace with * @return the text with any replacements processed */ public static String replaceOnce( String text, char repl, char with ) { return replace( text, repl, with, 1 ); } /** *

Replace all occurances of a char within another char.

* *

A null reference passed to this method is a no-op.

* * @see #replace(String text, char repl, char with, int max) * @param text text to search and replace in * @param repl char to search for * @param with char to replace with * @return the text with any replacements processed */ public static String replace( String text, char repl, char with ) { return replace( text, repl, with, -1 ); } /** *

Replace a char with another char inside a larger String, * for the first max values of the search char.

* *

A null reference passed to this method is a no-op.

* * @param text text to search and replace in * @param repl char to search for * @param with char to replace with * @param max maximum number of values to replace, or -1 if no maximum * @return the text with any replacements processed */ public static String replace( String text, char repl, char with, int max ) { return replace( text, String.valueOf( repl ), String.valueOf( with ), max ); } /** *

Replace a String with another String inside a larger String, once.

* *

A null reference passed to this method is a no-op.

* * @see #replace(String text, String repl, String with, int max) * @param text text to search and replace in * @param repl String to search for * @param with String to replace with * @return the text with any replacements processed */ public static String replaceOnce( String text, String repl, String with ) { return replace( text, repl, with, 1 ); } /** *

Replace all occurances of a String within another String.

* *

A null reference passed to this method is a no-op.

* * @see #replace(String text, String repl, String with, int max) * @param text text to search and replace in * @param repl String to search for * @param with String to replace with * @return the text with any replacements processed */ public static String replace( String text, String repl, String with ) { return replace( text, repl, with, -1 ); } /** *

Replace a String with another String inside a larger String, * for the first max values of the search String.

* *

A null reference passed to this method is a no-op.

* * @param text text to search and replace in * @param repl String to search for * @param with String to replace with * @param max maximum number of values to replace, or -1 if no maximum * @return the text with any replacements processed */ public static String replace( String text, String repl, String with, int max ) { if ( ( text == null ) || ( repl == null ) || ( with == null ) || ( repl.length() == 0 ) ) { return text; } StringBuilder buf = new StringBuilder( text.length() ); int start = 0, end; while ( ( end = text.indexOf( repl, start ) ) != -1 ) { buf.append( text, start, end ).append( with ); start = end + repl.length(); if ( --max == 0 ) { break; } } buf.append( text, start, text.length()); return buf.toString(); } /** *

Overlay a part of a String with another String.

* * @param text String to do overlaying in * @param overlay String to overlay * @param start int to start overlaying at * @param end int to stop overlaying before * @return String with overlayed text * @throws NullPointerException if text or overlay is null */ public static String overlayString( String text, String overlay, int start, int end ) { return new StringBuffer( start + overlay.length() + text.length() - end + 1 ) .append( text, 0, start ) .append( overlay ) .append( text, end, text.length() ) .toString(); } // Centering //-------------------------------------------------------------------------- /** *

Center a String in a larger String of size n.

* *

Uses spaces as the value to buffer the String with. * Equivalent to center(str, size, " ").

* * @param str String to center * @param size int size of new String * @return String containing centered String * @throws NullPointerException if str is null */ public static String center( String str, int size ) { return center( str, size, " " ); } /** *

Center a String in a larger String of size n.

* *

Uses a supplied String as the value to buffer the String with.

* * @param str String to center * @param size int size of new String * @param delim String to buffer the new String with * @return String containing centered String * @throws NullPointerException if str or delim is null * @throws ArithmeticException if delim is the empty String */ public static String center( String str, int size, String delim ) { int sz = str.length(); int p = size - sz; if ( p < 1 ) { return str; } str = leftPad( str, sz + p / 2, delim ); str = rightPad( str, size, delim ); return str; } // Chomping //-------------------------------------------------------------------------- /** *

Remove the last newline, and everything after it from a String.

* * @param str String to chomp the newline from * @return String without chomped newline * @throws NullPointerException if str is null */ public static String chomp( String str ) { return chomp( str, "\n" ); } /** *

Remove the last value of a supplied String, and everything after * it from a String.

* * @param str String to chomp from * @param sep String to chomp * @return String without chomped ending * @throws NullPointerException if str or sep is null */ public static String chomp( String str, String sep ) { int idx = str.lastIndexOf( sep ); if ( idx != -1 ) { return str.substring( 0, idx ); } else { return str; } } /** *

Remove a newline if and only if it is at the end * of the supplied String.

* * @param str String to chomp from * @return String without chomped ending * @throws NullPointerException if str is null */ public static String chompLast( String str ) { return chompLast( str, "\n" ); } /** *

Remove a value if and only if the String ends with that value.

* * @param str String to chomp from * @param sep String to chomp * @return String without chomped ending * @throws NullPointerException if str or sep is null */ public static String chompLast( String str, String sep ) { if ( str.length() == 0 ) { return str; } String sub = str.substring( str.length() - sep.length() ); if ( sep.equals( sub ) ) { return str.substring( 0, str.length() - sep.length() ); } else { return str; } } /** *

Remove everything and return the last value of a supplied String, and * everything after it from a String.

* * @param str String to chomp from * @param sep String to chomp * @return String chomped * @throws NullPointerException if str or sep is null */ public static String getChomp( String str, String sep ) { int idx = str.lastIndexOf( sep ); if ( idx == str.length() - sep.length() ) { return sep; } else if ( idx != -1 ) { return str.substring( idx ); } else { return ""; } } /** *

Remove the first value of a supplied String, and everything before it * from a String.

* * @param str String to chomp from * @param sep String to chomp * @return String without chomped beginning * @throws NullPointerException if str or sep is null */ public static String prechomp( String str, String sep ) { int idx = str.indexOf( sep ); if ( idx != -1 ) { return str.substring( idx + sep.length() ); } else { return str; } } /** *

Remove and return everything before the first value of a * supplied String from another String.

* * @param str String to chomp from * @param sep String to chomp * @return String prechomped * @throws NullPointerException if str or sep is null */ public static String getPrechomp( String str, String sep ) { int idx = str.indexOf( sep ); if ( idx != -1 ) { return str.substring( 0, idx + sep.length() ); } else { return ""; } } // Chopping //-------------------------------------------------------------------------- /** *

Remove the last character from a String.

* *

If the String ends in \r\n, then remove both * of them.

* * @param str String to chop last character from * @return String without last character * @throws NullPointerException if str is null */ public static String chop( String str ) { if ( "".equals( str ) ) { return ""; } if ( str.length() == 1 ) { return ""; } int lastIdx = str.length() - 1; String ret = str.substring( 0, lastIdx ); char last = str.charAt( lastIdx ); if ( last == '\n' ) { if ( ret.charAt( lastIdx - 1 ) == '\r' ) { return ret.substring( 0, lastIdx - 1 ); } } return ret; } /** *

Remove \n from end of a String if it's there. * If a \r precedes it, then remove that too.

* * @param str String to chop a newline from * @return String without newline * @throws NullPointerException if str is null */ public static String chopNewline( String str ) { int lastIdx = str.length() - 1; char last = str.charAt( lastIdx ); if ( last == '\n' ) { if ( str.charAt( lastIdx - 1 ) == '\r' ) { lastIdx--; } } else { lastIdx++; } return str.substring( 0, lastIdx ); } // Conversion //-------------------------------------------------------------------------- // spec 3.10.6 /** *

Escapes any values it finds into their String form.

* *

So a tab becomes the characters '\\' and * 't'.

* * @param str String to escape values in * @return String with escaped values * @throws NullPointerException if str is null */ 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(); StringBuilder buffer = new StringBuilder( 2 * sz ); for ( int i = 0; i < sz; i++ ) { char ch = str.charAt( i ); // handle unicode if ( ch > 0xfff ) { buffer.append( "\\u" + Integer.toHexString( ch ) ); } else if ( ch > 0xff ) { buffer.append( "\\u0" + Integer.toHexString( ch ) ); } else if ( ch > 0x7f ) { buffer.append( "\\u00" + Integer.toHexString( ch ) ); } else if ( ch < 32 ) { switch ( ch ) { case '\b': buffer.append( '\\' ); buffer.append( 'b' ); break; case '\n': buffer.append( '\\' ); buffer.append( 'n' ); break; case '\t': buffer.append( '\\' ); buffer.append( 't' ); break; case '\f': buffer.append( '\\' ); buffer.append( 'f' ); break; case '\r': buffer.append( '\\' ); buffer.append( 'r' ); break; default : if ( ch > 0xf ) { buffer.append( "\\u00" + Integer.toHexString( ch ) ); } else { buffer.append( "\\u000" + Integer.toHexString( ch ) ); } break; } } else { switch ( ch ) { case '\'': buffer.append( '\\' ); buffer.append( '\'' ); break; case '"': buffer.append( '\\' ); buffer.append( '"' ); break; case '\\': buffer.append( '\\' ); buffer.append( '\\' ); break; default : buffer.append( ch ); break; } } } return buffer.toString(); } // Padding //-------------------------------------------------------------------------- /** *

Repeat a String n times to form a * new string.

* * @param str String to repeat * @param repeat number of times to repeat str * @return String with repeated String * @throws NegativeArraySizeException if repeat < 0 * @throws NullPointerException if str is null */ public static String repeat( String str, int repeat ) { StringBuilder buffer = new StringBuilder( repeat * str.length() ); for ( int i = 0; i < repeat; i++ ) { buffer.append( str ); } return buffer.toString(); } /** *

Right pad a String with spaces.

* *

The String is padded to the size of n.

* * @param str String to repeat * @param size number of times to repeat str * @return right padded String * @throws NullPointerException if str is null */ public static String rightPad( String str, int size ) { return rightPad( str, size, " " ); } /** *

Right pad a String with a specified string.

* *

The String is padded to the size of n.

* * @param str String to pad out * @param size size to pad to * @param delim String to pad with * @return right padded String * @throws NullPointerException if str or delim is null * @throws ArithmeticException if delim is the empty String */ public static String rightPad( String str, int size, String delim ) { size = ( size - str.length() ) / delim.length(); if ( size > 0 ) { str += repeat( delim, size ); } return str; } /** *

Left pad a String with spaces.

* *

The String is padded to the size of n.

* * @param str String to pad out * @param size size to pad to * @return left padded String * @throws NullPointerException if str or delim is null */ public static String leftPad( String str, int size ) { return leftPad( str, size, " " ); } /** * Left pad a String with a specified string. Pad to a size of n. * * @param str String to pad out * @param size size to pad to * @param delim String to pad with * @return left padded String * @throws NullPointerException if str or delim is null * @throws ArithmeticException if delim is the empty string */ public static String leftPad( String str, int size, String delim ) { size = ( size - str.length() ) / delim.length(); if ( size > 0 ) { str = repeat( delim, size ) + str; } return str; } // Stripping //-------------------------------------------------------------------------- /** *

Remove whitespace from the front and back of a String.

* * @param str the String to remove whitespace from * @return the stripped String */ public static String strip( String str ) { return strip( str, null ); } /** *

Remove a specified String from the front and back of a * String.

* *

If whitespace is wanted to be removed, used the * {@link #strip(java.lang.String)} method.

* * @param str the String to remove a string from * @param delim the String to remove at start and end * @return the stripped String */ public static String strip( String str, String delim ) { str = stripStart( str, delim ); return stripEnd( str, delim ); } /** *

Strip whitespace from the front and back of every String * in the array.

* * @param strs the Strings to remove whitespace from * @return the stripped Strings */ public static String[] stripAll( String[] strs ) { return stripAll( strs, null ); } /** *

Strip the specified delimiter from the front and back of * every String in the array.

* * @param strs the Strings to remove a String from * @param delimiter the String to remove at start and end * @return the stripped Strings */ public static String[] stripAll( String[] strs, String delimiter ) { if ( ( strs == null ) || ( strs.length == 0 ) ) { return strs; } int sz = strs.length; String[] newArr = new String[sz]; for ( int i = 0; i < sz; i++ ) { newArr[i] = strip( strs[i], delimiter ); } return newArr; } /** *

Strip any of a supplied String from the end of a String.

* *

If the strip String is null, whitespace is * stripped.

* * @param str the String to remove characters from * @param strip the String to remove * @return the stripped String */ public static String stripEnd( String str, String strip ) { if ( str == null ) { return null; } int end = str.length(); if ( strip == null ) { while ( ( end != 0 ) && Character.isWhitespace( str.charAt( end - 1 ) ) ) { end--; } } else { while ( ( end != 0 ) && ( strip.indexOf( str.charAt( end - 1 ) ) != -1 ) ) { end--; } } return str.substring( 0, end ); } /** *

Strip any of a supplied String from the start of a String.

* *

If the strip String is null, whitespace is * stripped.

* * @param str the String to remove characters from * @param strip the String to remove * @return the stripped String */ public static String stripStart( String str, String strip ) { if ( str == null ) { return null; } int start = 0; int sz = str.length(); if ( strip == null ) { while ( ( start != sz ) && Character.isWhitespace( str.charAt( start ) ) ) { start++; } } else { while ( ( start != sz ) && ( strip.indexOf( str.charAt( start ) ) != -1 ) ) { start++; } } return str.substring( start ); } // Case conversion //-------------------------------------------------------------------------- /** *

Convert a String to upper case, null String * returns null.

* * @param str the String to uppercase * @return the upper cased String */ public static String upperCase( String str ) { if ( str == null ) { return null; } return str.toUpperCase(); } /** *

Convert a String to lower case, null String * returns null.

* * @param str the string to lowercase * @return the lower cased String */ public static String lowerCase( String str ) { if ( str == null ) { return null; } return str.toLowerCase(); } /** *

Uncapitalise a String.

* *

That is, convert the first character into lower-case. * null is returned as null.

* * @param str the String to uncapitalise * @return uncapitalised String */ public static String uncapitalise( String str ) { if ( str == null ) { return null; } else if ( str.length() == 0 ) { return ""; } else { return new StringBuffer( str.length() ) .append( Character.toLowerCase( str.charAt( 0 ) ) ) .append( str, 1, str.length() ) .toString(); } } /** *

Capitalise a String.

* *

That is, convert the first character into title-case. * null is returned as null.

* * @param str the String to capitalise * @return capitalised String */ public static String capitalise( String str ) { if ( str == null ) { return null; } else if ( str.length() == 0 ) { return ""; } else { return new StringBuilder( str.length() ) .append( Character.toTitleCase( str.charAt( 0 ) ) ) .append( str, 1, str.length() ) .toString(); } } /** *

Swaps the case of String.

* *

Properly looks after making sure the start of words * are Titlecase and not Uppercase.

* *

null is returned as null.

* * @param str the String to swap the case of * @return the modified String */ public static String swapCase( String str ) { if ( str == null ) { return null; } int sz = str.length(); StringBuilder buffer = new StringBuilder( sz ); boolean whitespace = false; char ch; char tmp; for ( int i = 0; i < sz; i++ ) { ch = str.charAt( i ); if ( Character.isUpperCase( ch ) ) { tmp = Character.toLowerCase( ch ); } else if ( Character.isTitleCase( ch ) ) { tmp = Character.toLowerCase( ch ); } else if ( Character.isLowerCase( ch ) ) { if ( whitespace ) { tmp = Character.toTitleCase( ch ); } else { tmp = Character.toUpperCase( ch ); } } else { tmp = ch; } buffer.append( tmp ); whitespace = Character.isWhitespace( ch ); } return buffer.toString(); } /** *

Capitalise all the words in a String.

* *

Uses {@link Character#isWhitespace(char)} as a * separator between words.

* *

null will return null.

* * @param str the String to capitalise * @return capitalised String */ public static String capitaliseAllWords( String str ) { if ( str == null ) { return null; } int sz = str.length(); StringBuilder buffer = new StringBuilder( sz ); boolean space = true; for ( int i = 0; i < sz; i++ ) { char ch = str.charAt( i ); if ( Character.isWhitespace( ch ) ) { buffer.append( ch ); space = true; } else if ( space ) { buffer.append( Character.toTitleCase( ch ) ); space = false; } else { buffer.append( ch ); } } return buffer.toString(); } /** *

Uncapitalise all the words in a string.

* *

Uses {@link Character#isWhitespace(char)} as a * separator between words.

* *

null will return null.

* * @param str the string to uncapitalise * @return uncapitalised string */ public static String uncapitaliseAllWords( String str ) { if ( str == null ) { return null; } int sz = str.length(); StringBuilder buffer = new StringBuilder( sz ); boolean space = true; for ( int i = 0; i < sz; i++ ) { char ch = str.charAt( i ); if ( Character.isWhitespace( ch ) ) { buffer.append( ch ); space = true; } else if ( space ) { buffer.append( Character.toLowerCase( ch ) ); space = false; } else { buffer.append( ch ); } } return buffer.toString(); } // Nested extraction //-------------------------------------------------------------------------- /** *

Get the String that is nested in between two instances of the * same String.

* *

If str is null, will * return null.

* * @param str the String containing nested-string * @param tag the String before and after nested-string * @return the String that was nested, or null * @throws NullPointerException if tag is null */ public static String getNestedString( String str, String tag ) { return getNestedString( str, tag, tag ); } /** *

Get the String that is nested in between two Strings.

* * @param str the String containing nested-string * @param open the String before nested-string * @param close the String after nested-string * @return the String that was nested, or null * @throws NullPointerException if open or close is null */ public static String getNestedString( String str, String open, String close ) { if ( str == null ) { return null; } int start = str.indexOf( open ); if ( start != -1 ) { int end = str.indexOf( close, start + open.length() ); if ( end != -1 ) { return str.substring( start + open.length(), end ); } } return null; } /** *

How many times is the substring in the larger String.

* *

null returns 0.

* * @param str the String to check * @param sub the substring to count * @return the number of occurances, 0 if the String is null * @throws NullPointerException if sub is null */ public static int countMatches( String str, String sub ) { if ( sub.equals( "" ) ) { return 0; } if ( str == null ) { return 0; } int count = 0; int idx = 0; while ( ( idx = str.indexOf( sub, idx ) ) != -1 ) { count++; idx += sub.length(); } return count; } // Character Tests //-------------------------------------------------------------------------- /** *

Checks if the String contains only unicode letters.

* *

null will return false. * An empty String will return true.

* * @param str the String to check * @return true if only contains letters, and is non-null */ public static boolean isAlpha( String str ) { if ( str == null ) { return false; } int sz = str.length(); for ( int i = 0; i < sz; i++ ) { if ( Character.isLetter( str.charAt( i ) ) == false ) { return false; } } return true; } /** *

Checks if the String contains only whitespace.

* *

null will return false. An * empty String will return true.

* * @param str the String to check * @return true if only contains whitespace, and is non-null */ public static boolean isWhitespace( String str ) { if ( str == null ) { return false; } int sz = str.length(); for ( int i = 0; i < sz; i++ ) { if ( ( Character.isWhitespace( str.charAt( i ) ) == false ) ) { return false; } } return true; } /** *

Checks if the String contains only unicode letters and * space (' ').

* *

null will return false. An * empty String will return true.

* * @param str the String to check * @return true if only contains letters and space, * and is non-null */ public static boolean isAlphaSpace( String str ) { if ( str == null ) { return false; } int sz = str.length(); for ( int i = 0; i < sz; i++ ) { if ( ( Character.isLetter( str.charAt( i ) ) == false ) && ( str.charAt( i ) != ' ' ) ) { return false; } } return true; } /** *

Checks if the String contains only unicode letters or digits.

* *

null will return false. An empty * String will return true.

* * @param str the String to check * @return true if only contains letters or digits, * and is non-null */ public static boolean isAlphanumeric( String str ) { if ( str == null ) { return false; } int sz = str.length(); for ( int i = 0; i < sz; i++ ) { if ( Character.isLetterOrDigit( str.charAt( i ) ) == false ) { return false; } } return true; } /** *

Checks if the String contains only unicode letters, digits * or space (' ').

* *

null will return false. An empty * String will return true.

* * @param str the String to check * @return true if only contains letters, digits or space, * and is non-null */ public static boolean isAlphanumericSpace( String str ) { if ( str == null ) { return false; } int sz = str.length(); for ( int i = 0; i < sz; i++ ) { if ( ( Character.isLetterOrDigit( str.charAt( i ) ) == false ) && ( str.charAt( i ) != ' ' ) ) { return false; } } return true; } /** *

Checks if the String contains only unicode digits.

* *

null will return false. * An empty String will return true.

* * @param str the String to check * @return true if only contains digits, and is non-null */ public static boolean isNumeric( String str ) { if ( str == null ) { return false; } int sz = str.length(); for ( int i = 0; i < sz; i++ ) { if ( Character.isDigit( str.charAt( i ) ) == false ) { return false; } } return true; } /** *

Checks if the String contains only unicode digits or space * (' ').

* *

null will return false. An empty * String will return true.

* * @param str the String to check * @return true if only contains digits or space, * and is non-null */ public static boolean isNumericSpace( String str ) { if ( str == null ) { return false; } int sz = str.length(); for ( int i = 0; i < sz; i++ ) { if ( ( Character.isDigit( str.charAt( i ) ) == false ) && ( str.charAt( i ) != ' ' ) ) { return false; } } return true; } // Defaults //-------------------------------------------------------------------------- /** *

Returns either the passed in Object as a String, * or, if the Object is null, an empty * String.

* * @param obj the Object to check * @return the passed in Object's toString, or blank if it was * null */ public static String defaultString( Object obj ) { return defaultString( obj, "" ); } /** *

Returns either the passed in Object as a String, * or, if the Object is null, a passed * in default String.

* * @param obj the Object to check * @param defaultString the default String to return if str is * null * @return the passed in string, or the default if it was * null */ public static String defaultString( Object obj, String defaultString ) { return ( obj == null ) ? defaultString : obj.toString(); } // Reversing //-------------------------------------------------------------------------- /** *

Reverse a String.

* *

null String returns null.

* * @param str the String to reverse * @return the reversed String */ public static String reverse( String str ) { if ( str == null ) { return null; } return new StringBuffer( str ).reverse().toString(); } /** *

Reverses a String that is delimited by a specific character.

* *

The Strings between the delimiters are not reversed. * Thus java.lang.String becomes String.lang.java (if the delimiter * is '.').

* * @param str the String to reverse * @param delimiter the delimiter to use * @return the reversed String */ public static String reverseDelimitedString( String str, String delimiter ) { // could implement manually, but simple way is to reuse other, // probably slower, methods. String[] strs = split( str, delimiter ); reverseArray( strs ); return join( strs, delimiter ); } /** *

Reverses an array.

* *

TAKEN FROM CollectionsUtils.

* * @param array the array to reverse */ private static void reverseArray( Object[] array ) { int i = 0; int j = array.length - 1; Object tmp; while ( j > i ) { tmp = array[j]; array[j] = array[i]; array[i] = tmp; j--; i++; } } // Abbreviating //-------------------------------------------------------------------------- /** * Turn "Now is the time for all good men" into "Now is the time for..." *

* Specifically: *

* If str is less than max characters long, return it. * Else abbreviate it to (substring(str, 0, max-3) + "..."). * If maxWidth is less than 3, throw an IllegalArgumentException. * In no case will it return a string of length greater than maxWidth. * * @param maxWidth maximum length of result string **/ public static String abbreviate( String s, int maxWidth ) { return abbreviate( s, 0, maxWidth ); } /** * Turn "Now is the time for all good men" into "...is the time for..." *

* Works like abbreviate(String, int), but allows you to specify a "left edge" * offset. Note that this left edge is not necessarily going to be the leftmost * character in the result, or the first * character following the ellipses, but it will appear somewhere in the result. * In no case will it return a string of length greater than maxWidth. * * @param offset left edge of source string * @param maxWidth maximum length of result string **/ public static String abbreviate( String s, int offset, int maxWidth ) { if ( maxWidth < 4 ) { throw new IllegalArgumentException( "Minimum abbreviation width is 4" ); } if ( s.length() <= maxWidth ) { return s; } if ( offset > s.length() ) { offset = s.length(); } if ( ( s.length() - offset ) < ( maxWidth - 3 ) ) { offset = s.length() - ( maxWidth - 3 ); } if ( offset <= 4 ) { return s.substring( 0, maxWidth - 3 ) + "..."; } if ( maxWidth < 7 ) { throw new IllegalArgumentException( "Minimum abbreviation width with offset is 7" ); } if ( ( offset + ( maxWidth - 3 ) ) < s.length() ) { return "..." + abbreviate( s.substring( offset ), maxWidth - 3 ); } return "..." + s.substring( s.length() - ( maxWidth - 3 ) ); } // Difference //-------------------------------------------------------------------------- /** * Compare two strings, and return the portion where they differ. * (More precisely, return the remainder of the second string, * starting from where it's different from the first.) *

* E.g. strdiff("i am a machine", "i am a robot") -> "robot" * * @return the portion of s2 where it differs from s1; returns the empty string ("") if they are equal **/ public static String difference( String s1, String s2 ) { int at = differenceAt( s1, s2 ); if ( at == -1 ) { return ""; } return s2.substring( at ); } /** * Compare two strings, and return the index at which the strings begin to differ. *

* E.g. strdiff("i am a machine", "i am a robot") -> 7 *

* * @return the index where s2 and s1 begin to differ; -1 if they are equal **/ public static int differenceAt( String s1, String s2 ) { int i; for ( i = 0; ( i < s1.length() ) && ( i < s2.length() ); ++i ) { if ( s1.charAt( i ) != s2.charAt( i ) ) { break; } } if ( ( i < s2.length() ) || ( i < s1.length() ) ) { return i; } return -1; } public static String interpolate( String text, Map namespace ) { Iterator keys = namespace.keySet().iterator(); while ( keys.hasNext() ) { String key = keys.next().toString(); Object obj = namespace.get( key ); if ( obj == null ) { throw new NullPointerException( "The value of the key '" + key + "' is null." ); } String value = obj.toString(); text = replace( text, "${" + key + "}", value ); if ( !key.contains( " " ) ) { text = replace( text, "$" + key, value ); } } return text; } public static String removeAndHump( String data, String replaceThis ) { String temp; StringBuilder out = new StringBuilder(); temp = data; StringTokenizer st = new StringTokenizer( temp, replaceThis ); while ( st.hasMoreTokens() ) { String element = (String) st.nextElement(); out.append( capitalizeFirstLetter( element ) ); } return out.toString(); } public static String capitalizeFirstLetter( String data ) { char firstLetter = Character.toTitleCase( data.substring( 0, 1 ).charAt( 0 ) ); String restLetters = data.substring( 1 ); return firstLetter + restLetters; } public static String lowercaseFirstLetter( String data ) { char firstLetter = Character.toLowerCase( data.substring( 0, 1 ).charAt( 0 ) ); String restLetters = data.substring( 1 ); return firstLetter + restLetters; } public static String addAndDeHump( String view ) { StringBuilder sb = new StringBuilder(); for ( int i = 0; i < view.length(); i++ ) { if ( ( i != 0 ) && Character.isUpperCase( view.charAt( i ) ) ) { sb.append( '-' ); } sb.append( view.charAt( i ) ); } return sb.toString().trim().toLowerCase( Locale.ENGLISH ); } /** *

Quote and escape a String with the given character, handling null.

* *
     * StringUtils.quoteAndEscape(null, *)    = null
     * StringUtils.quoteAndEscape("", *)      = ""
     * StringUtils.quoteAndEscape("abc", '"') = abc
     * StringUtils.quoteAndEscape("a\"bc", '"') = "a\"bc"
     * StringUtils.quoteAndEscape("a\"bc", '\'') = 'a\"bc'
     * 
* * @param source * @param quoteChar * @return the String quoted and escaped * @since 1.5.1 * @see #quoteAndEscape(String, char, char[], char[], char, boolean) */ public static String quoteAndEscape( String source, char quoteChar ) { return quoteAndEscape( source, quoteChar, new char[]{ quoteChar }, new char[]{ ' ' }, '\\', false ); } /** *

Quote and escape a String with the given character, handling null.

* * @param source * @param quoteChar * @param quotingTriggers * @return the String quoted and escaped * @since 1.5.1 * @see #quoteAndEscape(String, char, char[], char[], char, boolean) */ public static String quoteAndEscape( String source, char quoteChar, char[] quotingTriggers ) { return quoteAndEscape( source, quoteChar, new char[]{ quoteChar }, quotingTriggers, '\\', false ); } /** * @param source * @param quoteChar * @param escapedChars * @param escapeChar * @param force * @return the String quoted and escaped * @since 1.5.1 * @see #quoteAndEscape(String, char, char[], char[], char, boolean) */ public static String quoteAndEscape( String source, char quoteChar, final char[] escapedChars, char escapeChar, boolean force ) { return quoteAndEscape( source, quoteChar, escapedChars, new char[]{ ' ' }, escapeChar, force ); } /** * @param source * @param quoteChar * @param escapedChars * @param quotingTriggers * @param escapeChar * @param force * @return the String quoted and escaped * @since 1.5.1 */ public static String quoteAndEscape( String source, char quoteChar, final char[] escapedChars, final char[] quotingTriggers, 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 ) ) ) { return source; } String escaped = escape( source, escapedChars, escapePattern ); boolean quote = false; if ( force ) { quote = true; } else if ( !escaped.equals( source ) ) { quote = true; } else { for ( char quotingTrigger : quotingTriggers ) { if ( escaped.indexOf( quotingTrigger ) > -1 ) { quote = true; break; } } } if ( quote ) { return quoteChar + escaped + quoteChar; } return escaped; } /** * @param source * @param escapedChars * @param escapeChar * @return the String escaped * @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 ) { return null; } char[] eqc = new char[ escapedChars.length ]; System.arraycopy( escapedChars, 0, eqc, 0, escapedChars.length ); Arrays.sort( eqc ); StringBuilder buffer = new StringBuilder( source.length() ); for ( int i = 0; i < source.length(); i++ ) { final char c = source.charAt( i ); int result = Arrays.binarySearch( eqc, c ); if ( result > -1 ) { buffer.append( String.format(escapePattern, c) ); } else { buffer.append( c ); } } return buffer.toString(); } /** * Remove all duplicate whitespace characters and line terminators are replaced with a single * space. * * @param s a not null String * @return a string with unique whitespace. * @since 1.5.7 */ public static String removeDuplicateWhitespace( String s ) { 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(); } /** * Parses the given String and replaces all occurrences of * '\n', '\r' and '\r\n' with the system line separator. * * @param s a not null String * @return a String that contains only System line separators. * @see #unifyLineSeparators(String, String) * @since 1.5.7 */ public static String unifyLineSeparators( String s ) { return unifyLineSeparators( s, System.getProperty( "line.separator" ) ); } /** * Parses the given String and replaces all occurrences of * '\n', '\r' and '\r\n' with the system line separator. * * @param s a not null String * @param ls the wanted line separator ("\n" on UNIX), if null using the System line separator. * @return a String that contains only System line separators. * @throws IllegalArgumentException if ls is not '\n', '\r' and '\r\n' characters. * @since 1.5.7 */ public static String unifyLineSeparators( String s, String ls ) { if ( s == null ) { return null; } if ( ls == null ) { ls = System.getProperty( "line.separator" ); } if ( !( ls.equals( "\n" ) || ls.equals( "\r" ) || ls.equals( "\r\n" ) ) ) { throw new IllegalArgumentException( "Requested line separator is invalid." ); } int length = s.length(); StringBuilder buffer = new StringBuilder( length ); for ( int i = 0; i < length; i++ ) { if ( s.charAt( i ) == '\r' ) { if ( ( i + 1 ) < length && s.charAt( i + 1 ) == '\n' ) { i++; } buffer.append( ls ); } else if ( s.charAt( i ) == '\n' ) { buffer.append( ls ); } else { buffer.append( s.charAt( i ) ); } } return buffer.toString(); } /** *

Checks if String contains a search character, handling null. * This method uses {@link String#indexOf(int)}.

* *

A null or empty ("") String will return false.

* *
     * StringUtils.contains(null, *)    = false
     * StringUtils.contains("", *)      = false
     * StringUtils.contains("abc", 'a') = true
     * StringUtils.contains("abc", 'z') = false
     * 
* * @param str the String to check, may be null * @param searchChar the character to find * @return true if the String contains the search character, * false if not or null string input * @since 1.5.7 */ public static boolean contains( String str, char searchChar ) { if ( isEmpty( str ) ) { return false; } return str.indexOf( searchChar ) >= 0; } /** *

Checks if String contains a search String, handling null. * This method uses {@link String#indexOf(int)}.

* *

A null String will return false.

* *
     * StringUtils.contains(null, *)     = false
     * StringUtils.contains(*, null)     = false
     * StringUtils.contains("", "")      = true
     * StringUtils.contains("abc", "")   = true
     * StringUtils.contains("abc", "a")  = true
     * StringUtils.contains("abc", "z")  = false
     * 
* * @param str the String to check, may be null * @param searchStr the String to find, may be null * @return true if the String contains the search String, * false if not or null string input * @since 1.5.7 */ public static boolean contains( String str, String searchStr ) { if ( str == null || searchStr == null ) { return false; } return str.contains( searchStr ); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/SweeperPool.java000066400000000000000000000224151251077732300313650ustar00rootroot00000000000000package 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.util.ArrayList; /** * Pools a bunch of objects . Runs a sweeper periodically to * keep it down to size. The objects in the pool first get disposed first. * * @author Bert van Brakel * @version $Id$ */ public class SweeperPool { /***/ private static final boolean DEBUG = false; /** Sweeps the pool periodically to trim it's size */ private transient Sweeper sweeper; /** Absolute maxiumuim size of the pool.*/ private transient int maxSize; /** The size the pool gets trimmed down to */ private transient int minSize; /** When the sweeper runs * and the pool is over this size, then the pool is trimmed */ private int triggerSize; /** Holds the pooled objects */ private ArrayList pooledObjects; /** Flag indicating this pool is shuting down */ private boolean shuttingDown = false; //private Vector used; /** * *

There are a number of settings to control how the pool operates. *

    *
  • minSize - this is the size the pool is trimmed to
  • *
  • triggerSize - this determines if the pool is trimmed when * the sweeper runs. If the pool size is greater or equal than this value then * the pool is trimmed to minSize. *
  • maxSize - if the pool has reached this size, any objects added * are immediatley disposed. If the pool is this size when the sweeper runs, then * the pool is also trimmed to minSize irrespective of the triggerSize. *
  • *
  • sweepInterval - how often the sweeper runs. Is actually the * time since the sweeper last finished a pass. 0 if the sweeper should not run. *
  • *
*

* *

Any value less than 0 is automatically converted to 0

*/ public SweeperPool( int maxSize, int minSize, int intialCapacity, int sweepInterval, int triggerSize ) { super(); this.maxSize = saneConvert( maxSize ); this.minSize = saneConvert( minSize ); this.triggerSize = saneConvert( triggerSize ); pooledObjects = new ArrayList( intialCapacity ); //only run a sweeper if sweep interval is positive if ( sweepInterval > 0 ) { sweeper = new Sweeper( this, sweepInterval ); sweeper.start(); } } private int saneConvert( int value ) { if ( value < 0 ) { return 0; } else { return value; } } /** * Return the pooled object */ public synchronized Object get() { if ( ( pooledObjects.size() == 0 ) || shuttingDown ) { return null; } else { Object obj = pooledObjects.remove( 0 ); objectRetrieved( obj ); //used.add(obj); return obj; } } /** * Add an object to the pool * * @param obj the object to pool. Can be null. * * @return true if the object was added to the pool, false if it was disposed or null * */ public synchronized boolean put( Object obj ) { objectAdded( obj ); if ( ( obj != null ) && ( pooledObjects.size() < maxSize ) && ( shuttingDown == false ) ) { pooledObjects.add( obj ); return true; } else if ( obj != null ) { //no longer need the object, so dispose it objectDisposed( obj ); } return false; } /** * Return the number of pooled objects. This is never * greater than t maximuim size of the pool * * @return the number of pooled objects */ public synchronized int getSize() { return pooledObjects.size(); } /** * Dispose of this pool. Stops the sweeper and disposes each object in the pool * */ public void dispose() { shuttingDown = true; if ( sweeper != null ) { sweeper.stop(); try { sweeper.join(); } catch ( InterruptedException e ) { System.err.println( "Unexpected execption occurred: " ); e.printStackTrace(); } } synchronized ( this ) { // use an array here as objects may still be being put back in the pool // and we don't want to throw a ConcurrentModificationException Object[] objects = pooledObjects.toArray(); for ( Object object : objects ) { objectDisposed( object ); } pooledObjects.clear(); } } /** * A pool has been disposed if has been shutdown and the sweeper has completed running. * * @return true if the pool has been disposed, false otherwise */ boolean isDisposed() { if ( !shuttingDown ) { return false; } // A null sweeper means one was never started. if ( sweeper == null ) { return true; } return sweeper.hasStopped(); } /** * Trim the pool down to min size * */ public synchronized void trim() { if ( ( ( triggerSize > 0 ) && ( pooledObjects.size() >= triggerSize ) ) || ( ( maxSize > 0 ) && ( pooledObjects.size() >= maxSize ) ) ) { while ( pooledObjects.size() > minSize ) { objectDisposed( pooledObjects.remove( 0 ) ); } } } /** * Override this to be notified of object disposal. Called * after the object has been removed. Occurs when the pool * is trimmed. * * @param obj */ public void objectDisposed( Object obj ) { } /** * Override this to be notified of object addition. * Called before object is to be added. * * @param obj */ public void objectAdded( Object obj ) { } /** * Override this to be notified of object retrieval. * Called after object removed from the pool, but * before returned to the client. * * @param obj */ public void objectRetrieved( Object obj ) { } /** * Periodically at sweepInterval goes through * and tests if the pool should be trimmed. * * @author bert * */ private static class Sweeper implements Runnable { private final transient SweeperPool pool; private transient boolean service = false; private final transient int sweepInterval; private transient Thread t = null; /** * */ public Sweeper( SweeperPool pool, int sweepInterval ) { super(); this.sweepInterval = sweepInterval; this.pool = pool; } /** * Run the seeper. * * @see java.lang.Runnable#run() */ public void run() { debug( "started" ); if ( sweepInterval > 0 ) { synchronized ( this ) { while ( service ) { try { //wait specified number of seconds //before running next sweep wait( sweepInterval * 1000 ); } catch ( InterruptedException e ) { } runSweep(); } } } debug( "stopped" ); } public void start() { if ( !service ) { service = true; t = new Thread( this ); t.setName( "Sweeper" ); t.start(); } } public synchronized void stop() { service = false; notifyAll(); } void join() throws InterruptedException { t.join(); } boolean hasStopped() { return !service && !t.isAlive(); } private final void debug( String msg ) { if ( DEBUG ) { System.err.println( this + ":" + msg ); } } private void runSweep() { debug( "runningSweep. time=" + System.currentTimeMillis() ); pool.trim(); } } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/TypeFormat.java000066400000000000000000001054111251077732300312110ustar00rootroot00000000000000/* * J.A.D.E. Java(TM) Addition to Default Environment. * Latest release available at http://jade.dautelle.com/ * This class is public domain (not copyrighted). */ package org.codehaus.plexus.util; /** *

This class provides utility methods to parse CharSequence * into primitive types and to format primitive types into * StringBuffer.

* *

Methods from this utility class do not create temporary objects * and are typically faster than standard library methods (e.g {@link * #parseDouble} is up to 15x faster than Double.parseDouble). *

* *

For class instances, formatting is typically performed using specialized * java.text.Format (Locale sensitive) * and/or using conventional methods (class sensitive). For example:

 *     public class Foo {
 *         public static Foo valueOf(CharSequence chars) {...} // Parses.
 *         public StringBuffer appendTo(StringBuffer sb) {...} // Formats.
 *         public String toString() {
 *             return appendTo(new StringBuffer()).toString();
 *         }
 *     }

* *

This class is public domain (not copyrighted).

* * @author Jean-Marie Dautelle * @version 4.6, June 22, 2003 */ public final class TypeFormat { /** * Holds the characters used to represent numbers. */ private final static char[] DIGITS = { '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' , 'h' , 'i' , 'j' , 'k' , 'l' , 'm' , 'n' , 'o' , 'p' , 'q' , 'r' , 's' , 't' , 'u' , 'v' , 'w' , 'x' , 'y' , 'z' }; /** * Default constructor (forbids derivation). */ private TypeFormat() {} /** * Searches for a particular sequence within a character sequence * (general purpose parsing function). * * @param pattern the character sequence to search for. * @param chars the character sequence being searched. * @param fromIndex the index in chars to start the search * from. * @return the index in the range * [fromIndex, chars.length()-pattern.length()] * or -1 if the character sequence is not found. */ public static int indexOf(CharSequence pattern, CharSequence chars, int fromIndex) { int patternLength = pattern.length(); fromIndex = Math.max(0, fromIndex); if (patternLength != 0) { // At least one character to search for. char firstChar = pattern.charAt(0); int last = chars.length() - patternLength; for (int i=fromIndex; i <= last; i++) { if (chars.charAt(i) == firstChar) { boolean match = true; for (int j=1; j < patternLength; j++) { if (chars.charAt(i+j) != pattern.charAt(j)) { match = false; break; } } if (match) { return i; } } } return -1; } else { return Math.min(0, fromIndex); } } /** * Parses the specified CharSequence as a boolean. * * @param chars the character sequence to parse. * @return the corresponding boolean. */ public static boolean parseBoolean(CharSequence chars) { return (chars.length() == 4) && (chars.charAt(0) == 't' || chars.charAt(0) == 'T') && (chars.charAt(1) == 'r' || chars.charAt(1) == 'R') && (chars.charAt(2) == 'u' || chars.charAt(2) == 'U') && (chars.charAt(3) == 'e' || chars.charAt(3) == 'E'); } /** * Parses the specified CharSequence as a signed decimal * short. * * @param chars the character sequence to parse. * @return parseShort(chars, 10) * @throws NumberFormatException if the specified character sequence * does not contain a parsable short. * @see #parseShort(CharSequence, int) */ public static short parseShort(CharSequence chars) { return parseShort(chars, 10); } /** * Parses the specified CharSequence as a signed * short in the specified radix. The characters in the string * must all be digits of the specified radix, except the first character * which may be a plus sign '+' or a minus sign * '-'. * * @param chars the character sequence to parse. * @param radix the radix to be used while parsing. * @return the corresponding short. * @throws NumberFormatException if the specified character sequence * does not contain a parsable short. */ public static short parseShort(CharSequence chars, int radix) { try { boolean isNegative = (chars.charAt(0) == '-') ? true : false; int result = 0; int limit = (isNegative) ? Short.MIN_VALUE : -Short.MAX_VALUE; int multmin = limit / radix; int length = chars.length(); int i = (isNegative || (chars.charAt(0) == '+')) ? 1 : 0; while (true) { int digit = Character.digit(chars.charAt(i), radix); int tmp = result * radix; if ((digit < 0) || (result < multmin) || (tmp < limit + digit)) { // Overflow. throw new NumberFormatException( "For input characters: \"" + chars.toString() + "\""); } // Accumulates negatively. result = tmp - digit; if (++i >= length) { break; } } return (short) (isNegative ? result : -result); } catch (IndexOutOfBoundsException e) { throw new NumberFormatException( "For input characters: \"" + chars.toString() + "\""); } } /** * Parses the specified CharSequence as a signed decimal * int. * * @param chars the character sequence to parse. * @return parseInt(chars, 10) * @throws NumberFormatException if the specified character sequence * does not contain a parsable int. * @see #parseInt(CharSequence, int) */ public static int parseInt(CharSequence chars) { return parseInt(chars, 10); } /** * Parses the specified CharSequence as a signed * int in the specified radix. The characters in the string * must all be digits of the specified radix, except the first character * which may be a plus sign '+' or a minus sign * '-'. * * @param chars the character sequence to parse. * @param radix the radix to be used while parsing. * @return the corresponding int. * @throws NumberFormatException if the specified character sequence * does not contain a parsable int. */ public static int parseInt(CharSequence chars, int radix) { try { boolean isNegative = (chars.charAt(0) == '-') ? true : false; int result = 0; int limit = (isNegative) ? Integer.MIN_VALUE : -Integer.MAX_VALUE; int multmin = limit / radix; int length = chars.length(); int i = (isNegative || (chars.charAt(0) == '+')) ? 1 : 0; while (true) { int digit = Character.digit(chars.charAt(i), radix); int tmp = result * radix; if ((digit < 0) || (result < multmin) || (tmp < limit + digit)) { // Overflow. throw new NumberFormatException( "For input characters: \"" + chars.toString() + "\""); } // Accumulates negatively to avoid surprises near MAX_VALUE result = tmp - digit; if (++i >= length) { break; } } return isNegative ? result : -result; } catch (IndexOutOfBoundsException e) { throw new NumberFormatException( "For input characters: \"" + chars.toString() + "\""); } } /** * Parses the specified CharSequence as a signed decimal * long. * * @param chars the character sequence to parse. * @return parseLong(chars, 10) * @throws NumberFormatException if the specified character sequence * does not contain a parsable long. * @see #parseLong(CharSequence, int) */ public static long parseLong(CharSequence chars) { return parseLong(chars, 10); } /** * Parses the specified CharSequence as a signed * long in the specified radix. The characters in the string * must all be digits of the specified radix, except the first character * which may be a plus sign '+' or a minus sign * '-'. * * @param chars the character sequence to parse. * @param radix the radix to be used while parsing. * @return the corresponding long. * @throws NumberFormatException if the specified character sequence * does not contain a parsable long. */ public static long parseLong(CharSequence chars, int radix) { try { boolean isNegative = (chars.charAt(0) == '-') ? true : false; long result = 0; long limit = (isNegative) ? Long.MIN_VALUE : -Long.MAX_VALUE; long multmin = limit / radix; int length = chars.length(); int i = (isNegative || (chars.charAt(0) == '+')) ? 1 : 0; while (true) { int digit = Character.digit(chars.charAt(i), radix); long tmp = result * radix; if ((digit < 0) || (result < multmin) || (tmp < limit + digit)) { // Overflow. throw new NumberFormatException( "For input characters: \"" + chars.toString() + "\""); } // Accumulates negatively to avoid surprises near MAX_VALUE result = tmp - digit; if (++i >= length) { break; } } return isNegative ? result : -result; } catch (IndexOutOfBoundsException e) { throw new NumberFormatException( "For input characters: \"" + chars.toString() + "\""); } } /** * Parses this CharSequence as a float. * * @param chars the character sequence to parse. * @return the float number represented by the specified character sequence. * @throws NumberFormatException if the character sequence does not contain * a parsable float. */ public static float parseFloat(CharSequence chars) { double d = parseDouble(chars); if ( (d >= Float.MIN_VALUE) && (d <= Float.MAX_VALUE)) { return (float) d; } else { throw new NumberFormatException( "Float overflow for input characters: \"" + chars.toString() + "\""); } } /** * Parses this CharSequence as a double. * * @param chars the character sequence to parse. * @return the double number represented by this character sequence. * @throws NumberFormatException if the character sequence does not contain * a parsable double. */ public static double parseDouble(CharSequence chars) throws NumberFormatException { try { int length = chars.length(); double result = 0.0; int exp = 0; boolean isNegative = (chars.charAt(0) == '-') ? true : false; int i = (isNegative || (chars.charAt(0) == '+')) ? 1 : 0; // Checks special cases NaN or Infinity. if ((chars.charAt(i) == 'N') || (chars.charAt(i) == 'I')) { if (chars.toString().equals("NaN")) { return Double.NaN; } else if (chars.subSequence(i, length).toString(). equals("Infinity")) { return isNegative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY; } } // Reads decimal number. boolean fraction = false; while (true) { char c = chars.charAt(i); if ( (c == '.') && (!fraction)) { fraction = true; } else if ((c == 'e') || (c == 'E')) { break; } else if ((c >= '0') && (c <= '9')) { result = result * 10 + (c - '0'); if (fraction) { exp--; } } else { throw new NumberFormatException( "For input characters: \"" + chars.toString() + "\""); } if (++i >= length) { break; } } result = isNegative ? - result : result; // Reads exponent (if any). if (i < length) { i++; boolean negE = (chars.charAt(i) == '-') ? true : false; i = (negE || (chars.charAt(i) == '+')) ? i+1 : i; int valE = 0; while (true) { char c = chars.charAt(i); if ((c >= '0') && (c <= '9')) { valE = valE * 10 + (c - '0'); if (valE > 10000000) { // Hard-limit to avoid overflow. valE = 10000000; } } else { throw new NumberFormatException( "For input characters: \"" + chars.toString() + "\""); } if (++i >= length) { break; } } exp += negE ? -valE : valE; } // Returns product decimal number with exponent. return multE(result, exp); } catch (IndexOutOfBoundsException e) { throw new NumberFormatException( "For input characters: \"" + chars.toString() + "\""); } } /** * Formats the specified boolean and appends the resulting * text to the StringBuffer argument. * * @param b a boolean. * @param sb the StrinBuffer to append. * @return the specified StringBuffer object. * @see #parseBoolean */ public static StringBuffer format(boolean b, StringBuffer sb) { return b ? sb.append("true") : sb.append("false"); } /** * Formats the specified short and appends the resulting * text (decimal representation) to the StringBuffer argument. * *

Note: This method is preferred to StringBuffer.append(short) * as it does not create temporary String * objects (several times faster for small numbers).

* * @param s the short number. * @param sb the StrinBuffer to append. * @return the specified StringBuffer object. * @see #parseShort */ public static StringBuffer format(short s, StringBuffer sb) { return format((int)s, sb); // Forwards to int formatting (fast). } /** * Formats the specified short in the specified radix and * appends the resulting text to the StringBuffer argument. * * @param s the short number. * @param radix the radix. * @param sb the StrinBuffer to append. * @return the specified StringBuffer object. * @see #parseShort(CharSequence, int) * throws IllegalArgumentException if radix is not in [2 .. 36] range. */ public static StringBuffer format(short s, int radix, StringBuffer sb) { return format((int)s, radix, sb); // Forwards to int formatting (fast). } /** * Formats the specified int and appends the resulting * text (decimal representation) to the StringBuffer argument. * *

Note: This method is preferred to StringBuffer.append(int) * as it does not create temporary String * objects (several times faster for small numbers).

* * @param i the int number. * @param sb the StrinBuffer to append. * @return the specified StringBuffer object. * @see #parseInt */ public static StringBuffer format(int i, StringBuffer sb) { if (i <= 0) { if (i == Integer.MIN_VALUE) { // Negation would overflow. return sb.append("-2147483648"); // 11 char max. } else if (i == 0) { return sb.append('0'); } i = -i; sb.append('-'); } int j = 1; for (; (j < 10) && (i >= INT_POW_10[j]); j++) {} // POW_10[j] > i >= POW_10[j-1] for (j--; j >= 0; j--) { int pow10 = INT_POW_10[j]; int digit = i / pow10; i -= digit * pow10; sb.append(DIGITS[digit]); } return sb; } private static final int[] INT_POW_10 = new int[10]; static { int pow = 1; for (int i=0; i < 10; i++) { INT_POW_10[i] = pow; pow *= 10; } } /** * Formats the specified int in the specified radix and appends * the resulting text to the StringBuffer argument. * * @param i the int number. * @param radix the radix. * @param sb the StrinBuffer to append. * @return the specified StringBuffer object. * @see #parseInt(CharSequence, int) * throws IllegalArgumentException if radix is not in [2 .. 36] range. */ public static StringBuffer format(int i, int radix, StringBuffer sb) { if (radix == 10) { return format(i, sb); // Faster version. } else if (radix < 2 || radix > 36) { throw new IllegalArgumentException("radix: " + radix); } if (i < 0) { sb.append('-'); } else { i = -i; } format2(i, radix, sb); return sb; } private static void format2(int i, int radix, StringBuffer sb) { if (i <= -radix) { format2(i / radix, radix, sb); sb.append(DIGITS[-(i % radix)]); } else { sb.append(DIGITS[-i]); } } /** * Formats the specified long and appends the resulting * text (decimal representation) to the StringBuffer argument. * *

Note: This method is preferred to StringBuffer.append(long) * as it does not create temporary String * objects (several times faster for small numbers).

* * @param l the long number. * @param sb the StrinBuffer to append. * @return the specified StringBuffer object. * @see #parseLong */ public static StringBuffer format(long l, StringBuffer sb) { if (l <= 0) { if (l == Long.MIN_VALUE) { // Negation would overflow. return sb.append("-9223372036854775808"); // 20 characters max. } else if (l == 0) { return sb.append('0'); } l = -l; sb.append('-'); } int j = 1; for (; (j < 19) && (l >= LONG_POW_10[j]); j++) {} // POW_10[j] > l >= POW_10[j-1] for (j--; j >= 0; j--) { long pow10 = LONG_POW_10[j]; int digit = (int) (l / pow10); l -= digit * pow10; sb.append(DIGITS[digit]); } return sb; } private static final long[] LONG_POW_10 = new long[19]; static { long pow = 1; for (int i=0; i < 19; i++) { LONG_POW_10[i] = pow; pow *= 10; } } /** * Formats the specified long in the specified radix and * appends the resulting text to the StringBuffer argument. * * @param l the long number. * @param radix the radix. * @param sb the StrinBuffer to append. * @return the specified StringBuffer object. * @see #parseLong(CharSequence, int) * throws IllegalArgumentException if radix is not in [2 .. 36] range. */ public static StringBuffer format(long l, int radix, StringBuffer sb) { if (radix == 10) { return format(l, sb); // Faster version. } else if (radix < 2 || radix > 36) { throw new IllegalArgumentException("radix: " + radix); } if (l < 0) { sb.append('-'); } else { l = -l; } format2(l, radix, sb); return sb; } private static void format2(long l, int radix, StringBuffer sb) { if (l <= -radix) { format2(l / radix, radix, sb); sb.append(DIGITS[(int)-(l % radix)]); } else { sb.append(DIGITS[(int)-l]); } } /** * Formats the specified float and appends the resulting * text to the StringBuffer argument. * * @param f the float number. * @param sb the StrinBuffer to append. * @return format(f, 0.0f, sb) * @see #format(float, float, StringBuffer) */ public static StringBuffer format(float f, StringBuffer sb) { return format(f, 0.0f, sb); } /** * Formats the specified float and appends the resulting text * to the StringBuffer argument; the number of significative * digits is deduced from the specifed precision. All digits at least as * significant as the specified precision are represented. For example: *
    *
  • format(5.6f, 0.01f, sb) appends "5.60"
  • *
  • format(5.6f, 0.1f, sb) appends "5.6"
  • *
  • format(5.6f, 1f, sb) appends "6"
  • *
* If the precision is 0.0f, the precision is assumed to be * the intrinsic float precision (64 bits IEEE 754 format); * no formatting is performed, all significant digits are displayed and * trailing zeros are removed. * * @param f the float number. * @param precision the maximum weight of the last digit represented. * @param sb the StrinBuffer to append. * @return the specified StringBuffer object. * @throws IllegalArgumentException if the specified precision is negative * or would result in too many digits (19+). */ public static StringBuffer format(float f, float precision, StringBuffer sb) { // Adjusts precision. boolean precisionOnLastDigit; if (precision > 0.0f) { precisionOnLastDigit = true; } else if (precision == 0.0f) { if (f != 0.0f) { precisionOnLastDigit = false; precision = Math.max(Math.abs(f * FLOAT_RELATIVE_ERROR), Float.MIN_VALUE); } else { return sb.append("0.0"); // Exact zero. } } else { throw new IllegalArgumentException( "precision: Negative values not allowed"); } return format(f, precision, precisionOnLastDigit, sb); } /** * Formats the specified double and appends the resulting * text to the StringBuffer argument. * *

Note : This method is preferred to StringBuffer.append(double) * or even String.valueOf(double) as it * does not create temporary String or * FloatingDecimal objects (several times faster, * e.g. 15x faster for Double.MAX_VALUE).

* * @param d the double number. * @param sb the StrinBuffer to append. * @return format(d, 0.0, sb) * @see #format(double, double, StringBuffer) */ public static StringBuffer format(double d, StringBuffer sb) { return format(d, 0.0, sb); } /** * Formats the specified double and appends the resulting text * to the StringBuffer argument; the number of significand * digits is specified as integer argument. * * @param d the double number. * @param digits the number of significand digits (excludes exponent). * @param sb the StrinBuffer to append. * @return the specified StringBuffer object. * @throws IllegalArgumentException if the number of digits is not in * range [1..19]. */ public static StringBuffer format(double d, int digits, StringBuffer sb) { if ((digits >= 1) && (digits <= 19)) { double precision = Math.abs(d / DOUBLE_POW_10[digits-1]); return format(d, precision, sb); } else { throw new java.lang.IllegalArgumentException( "digits: " + digits + " is not in range [1 .. 19]"); } } /** * Formats the specified double and appends the resulting text * to the StringBuffer argument; the number of significative * digits is deduced from the specifed precision. All digits at least as * significant as the specified precision are represented. For example: *
    *
  • format(5.6, 0.01, sb) appends "5.60"
  • *
  • format(5.6, 0.1, sb) appends "5.6"
  • *
  • format(5.6, 1, sb) appends "6"
  • *
* If the precision is 0.0, the precision is assumed to be * the intrinsic double precision (64 bits IEEE 754 format); * no formatting is performed, all significant digits are displayed and * trailing zeros are removed. * * @param d the double number. * @param precision the maximum weight of the last digit represented. * @param sb the StrinBuffer to append. * @return the specified StringBuffer object. * @throws IllegalArgumentException if the specified precision is negative * or would result in too many digits (19+). */ public static StringBuffer format(double d, double precision, StringBuffer sb) { // Adjusts precision. boolean precisionOnLastDigit = false; if (precision > 0.0) { precisionOnLastDigit = true; } else if (precision == 0.0) { if (d != 0.0) { precision = Math.max(Math.abs(d * DOUBLE_RELATIVE_ERROR), Double.MIN_VALUE); } else { return sb.append("0.0"); // Exact zero. } } else if (precision < 0.0) { // Not NaN throw new IllegalArgumentException( "precision: Negative values not allowed"); } return format(d, precision, precisionOnLastDigit, sb); } /** * Formats the specified double and appends the resulting text * to the StringBuffer argument; the number of significative * digits is deduced from the specifed precision. * * @param d the double number. * @param precision the maximum weight of the last digit represented. * @param precisionOnLastDigit indicates if the number of digits is * deduced from the specified precision. * @param sb the StrinBuffer to append. * @return the specified StringBuffer object. */ private static StringBuffer format(double d, double precision, boolean precisionOnLastDigit, StringBuffer sb) { // Special cases. if (Double.isNaN(d)) { return sb.append("NaN"); } else if (Double.isInfinite(d)) { return (d >= 0) ? sb.append("Infinity") : sb.append("-Infinity"); } if (d < 0) { d = -d; sb.append('-'); } // Formats decimal part. int rank = (int) Math.floor(Math.log(precision) / LOG_10); double digitValue = multE(d, -rank); if (digitValue >= Long.MAX_VALUE) { throw new IllegalArgumentException( "Specified precision would result in too many digits"); } int digitStart = sb.length(); format(Math.round(digitValue), sb); int digitLength = sb.length() - digitStart; int dotPos = digitLength + rank; boolean useScientificNotation = false; // Inserts dot ('.') if ((dotPos <= -LEADING_ZEROS.length) || (dotPos > digitLength)) { // Scientific notation has to be used ("x.xxxEyy"). sb.insert(digitStart + 1, '.'); useScientificNotation = true; } else if (dotPos > 0) { // Dot within the string ("xxxx.xxxxx"). sb.insert(digitStart + dotPos, '.'); } else { // Leading zeros ("0.xxxxx"). sb.insert(digitStart, LEADING_ZEROS[-dotPos]); } // Removes trailing zeros. if (!precisionOnLastDigit) { int newLength = sb.length(); do { newLength--; } while (sb.charAt(newLength) == '0'); sb.setLength(newLength+1); } // Avoids trailing '.' if (sb.charAt(sb.length()-1) == '.') { if (precisionOnLastDigit) { sb.setLength(sb.length()-1); // Prefers "xxx" to "xxx." } else { sb.append('0'); // Prefer "xxx.0" to "xxx." } } // Writes exponent. if (useScientificNotation) { sb.append('E'); format(dotPos - 1, sb); } return sb; } private static final double LOG_10 = Math.log(10); private static final float FLOAT_RELATIVE_ERROR = (float) Math.pow(2, -24); private static final double DOUBLE_RELATIVE_ERROR = Math.pow(2, -53); private static String[] LEADING_ZEROS = {"0.", "0.0", "0.00"}; /** * Returns the product of the specified value with 10 raised * at the specified power exponent. * * @param value the value. * @param E the exponent. * @return value * 10^E */ private static final double multE(double value, int E) { if (E >= 0) { if (E <= 308) { // Max: 1.7976931348623157E+308 return value * DOUBLE_POW_10[E]; } else { value *= 1E21; // Exact multiplicand. E = Math.min(308, E-21); return value * DOUBLE_POW_10[E]; } } else { if (E >= -308) { return value / DOUBLE_POW_10[-E]; } else { // Min: 4.9E-324 value /= 1E21; // Exact divisor. E = Math.max(-308, E+21); return value / DOUBLE_POW_10[-E]; } } } // Note: Approximation for exponents > 21. This may introduce round-off // errors (e.g. 1E23 represented as "9.999999999999999E22"). private static final double[] DOUBLE_POW_10 = new double[] { 1E000, 1E001, 1E002, 1E003, 1E004, 1E005, 1E006, 1E007, 1E008, 1E009, 1E010, 1E011, 1E012, 1E013, 1E014, 1E015, 1E016, 1E017, 1E018, 1E019, 1E020, 1E021, 1E022, 1E023, 1E024, 1E025, 1E026, 1E027, 1E028, 1E029, 1E030, 1E031, 1E032, 1E033, 1E034, 1E035, 1E036, 1E037, 1E038, 1E039, 1E040, 1E041, 1E042, 1E043, 1E044, 1E045, 1E046, 1E047, 1E048, 1E049, 1E050, 1E051, 1E052, 1E053, 1E054, 1E055, 1E056, 1E057, 1E058, 1E059, 1E060, 1E061, 1E062, 1E063, 1E064, 1E065, 1E066, 1E067, 1E068, 1E069, 1E070, 1E071, 1E072, 1E073, 1E074, 1E075, 1E076, 1E077, 1E078, 1E079, 1E080, 1E081, 1E082, 1E083, 1E084, 1E085, 1E086, 1E087, 1E088, 1E089, 1E090, 1E091, 1E092, 1E093, 1E094, 1E095, 1E096, 1E097, 1E098, 1E099, 1E100, 1E101, 1E102, 1E103, 1E104, 1E105, 1E106, 1E107, 1E108, 1E109, 1E110, 1E111, 1E112, 1E113, 1E114, 1E115, 1E116, 1E117, 1E118, 1E119, 1E120, 1E121, 1E122, 1E123, 1E124, 1E125, 1E126, 1E127, 1E128, 1E129, 1E130, 1E131, 1E132, 1E133, 1E134, 1E135, 1E136, 1E137, 1E138, 1E139, 1E140, 1E141, 1E142, 1E143, 1E144, 1E145, 1E146, 1E147, 1E148, 1E149, 1E150, 1E151, 1E152, 1E153, 1E154, 1E155, 1E156, 1E157, 1E158, 1E159, 1E160, 1E161, 1E162, 1E163, 1E164, 1E165, 1E166, 1E167, 1E168, 1E169, 1E170, 1E171, 1E172, 1E173, 1E174, 1E175, 1E176, 1E177, 1E178, 1E179, 1E180, 1E181, 1E182, 1E183, 1E184, 1E185, 1E186, 1E187, 1E188, 1E189, 1E190, 1E191, 1E192, 1E193, 1E194, 1E195, 1E196, 1E197, 1E198, 1E199, 1E200, 1E201, 1E202, 1E203, 1E204, 1E205, 1E206, 1E207, 1E208, 1E209, 1E210, 1E211, 1E212, 1E213, 1E214, 1E215, 1E216, 1E217, 1E218, 1E219, 1E220, 1E221, 1E222, 1E223, 1E224, 1E225, 1E226, 1E227, 1E228, 1E229, 1E230, 1E231, 1E232, 1E233, 1E234, 1E235, 1E236, 1E237, 1E238, 1E239, 1E240, 1E241, 1E242, 1E243, 1E244, 1E245, 1E246, 1E247, 1E248, 1E249, 1E250, 1E251, 1E252, 1E253, 1E254, 1E255, 1E256, 1E257, 1E258, 1E259, 1E260, 1E261, 1E262, 1E263, 1E264, 1E265, 1E266, 1E267, 1E268, 1E269, 1E270, 1E271, 1E272, 1E273, 1E274, 1E275, 1E276, 1E277, 1E278, 1E279, 1E280, 1E281, 1E282, 1E283, 1E284, 1E285, 1E286, 1E287, 1E288, 1E289, 1E290, 1E291, 1E292, 1E293, 1E294, 1E295, 1E296, 1E297, 1E298, 1E299, 1E300, 1E301, 1E302, 1E303, 1E304, 1E305, 1E306, 1E307, 1E308 }; }plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/WriterFactory.java000066400000000000000000000136351251077732300317310ustar00rootroot00000000000000package 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.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.nio.charset.Charset; import org.codehaus.plexus.util.xml.XmlStreamWriter; /** * Utility to create Writers, with explicit encoding choice: platform default, * XML, or specified. * * @author Herve Boutemy * @see Charset * @see Supported encodings * @version $Id$ * @since 1.4.4 */ public class WriterFactory { /** * ISO Latin Alphabet #1, also known as ISO-LATIN-1. * Every implementation of the Java platform is required to support this character encoding. * @see Charset */ public static final String ISO_8859_1 = "ISO-8859-1"; /** * Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block of the Unicode character set. * Every implementation of the Java platform is required to support this character encoding. * @see Charset */ public static final String US_ASCII = "US-ASCII"; /** * Sixteen-bit Unicode Transformation Format, byte order specified by a mandatory initial byte-order mark (either * order accepted on input, big-endian used on output). * Every implementation of the Java platform is required to support this character encoding. * @see Charset */ public static final String UTF_16 = "UTF-16"; /** * Sixteen-bit Unicode Transformation Format, big-endian byte order. * Every implementation of the Java platform is required to support this character encoding. * @see Charset */ public static final String UTF_16BE = "UTF-16BE"; /** * Sixteen-bit Unicode Transformation Format, little-endian byte order. * Every implementation of the Java platform is required to support this character encoding. * @see Charset */ public static final String UTF_16LE = "UTF-16LE"; /** * Eight-bit Unicode Transformation Format. * Every implementation of the Java platform is required to support this character encoding. * @see Charset */ public static final String UTF_8 = "UTF-8"; /** * The file.encoding System Property. */ public static final String FILE_ENCODING = System.getProperty( "file.encoding" ); /** * Create a new Writer with XML encoding detection rules. * * @param out not null output stream. * @return an XML writer instance for the output stream. * @throws IOException if any. * @see XmlStreamWriter */ public static XmlStreamWriter newXmlWriter( OutputStream out ) throws IOException { return new XmlStreamWriter( out ); } /** * Create a new Writer with XML encoding detection rules. * * @param file not null file. * @return an XML writer instance for the output file. * @throws IOException if any. * @see XmlStreamWriter */ public static XmlStreamWriter newXmlWriter( File file ) throws IOException { return new XmlStreamWriter( file ); } /** * 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. * @throws IOException if any. * @see Charset#defaultCharset() */ public static Writer newPlatformWriter( OutputStream out ) { return new OutputStreamWriter( out ); } /** * 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. * @throws IOException if any. * @see Charset#defaultCharset() */ public static Writer newPlatformWriter( File file ) throws IOException { return new FileWriter( file ); } /** * Create a new Writer with specified encoding. * * @param out not null output stream. * @param encoding not null supported encoding. * @return a writer instance for the output stream using the given encoding. * @throws UnsupportedEncodingException if any. * @see Supported encodings */ public static Writer newWriter( OutputStream out, String encoding ) throws UnsupportedEncodingException { return new OutputStreamWriter( out, encoding ); } /** * Create a new Writer with specified encoding. * * @param file not null file. * @param encoding not null supported encoding. * @return a writer instance for the output file using the given encoding. * @throws UnsupportedEncodingException if any. * @throws FileNotFoundException if any. * @see Supported encodings */ public static Writer newWriter( File file, String encoding ) throws UnsupportedEncodingException, FileNotFoundException { return newWriter( new FileOutputStream( file ), encoding ); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/cli/000077500000000000000000000000001251077732300270215ustar00rootroot00000000000000AbstractStreamHandler.java000066400000000000000000000023761251077732300340320ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/clipackage 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; } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/cli/Arg.java000066400000000000000000000014621251077732300304000ustar00rootroot00000000000000package 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.io.File; public interface Arg { void setValue( String value ); void setLine( String line ); void setFile( File value ); String[] getParts(); } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/cli/CommandLineCallable.java000066400000000000000000000016251251077732300334760ustar00rootroot00000000000000package 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; } CommandLineException.java000066400000000000000000000017511251077732300336560ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/clipackage 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 Trygve Laugstøl * @version $Id$ */ public class CommandLineException extends Exception { public CommandLineException( String message ) { super( message ); } public CommandLineException( String message, Throwable cause ) { super( message, cause ); } } CommandLineTimeOutException.java000066400000000000000000000024731251077732300351670ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/clipackage org.codehaus.plexus.util.cli; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 olamy * @since 1.5.9 * @version $Id$ */ public class CommandLineTimeOutException extends CommandLineException { /** * @param message */ public CommandLineTimeOutException( String message ) { super( message ); } /** * @param message * @param cause */ public CommandLineTimeOutException( String message, Throwable cause ) { super( message, cause ); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/cli/CommandLineUtils.java000066400000000000000000000434251251077732300331030ustar00rootroot00000000000000package 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.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; 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.StringUtils; /** * @author Trygve Laugstøl * @version $Id$ */ public abstract class CommandLineUtils { public static class StringStreamConsumer implements StreamConsumer { private StringBuffer string = new StringBuffer(); private String ls = System.getProperty( "line.separator" ); public void consumeLine( String line ) { string.append( line ).append( ls ); } public String getOutput() { return string.toString(); } } 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 { return executeCommandLine( cl, null, systemOut, systemErr, 0 ); } public static int executeCommandLine( Commandline cl, StreamConsumer systemOut, StreamConsumer systemErr, int timeoutInSeconds ) throws CommandLineException { return executeCommandLine( cl, null, systemOut, systemErr, timeoutInSeconds ); } public static int executeCommandLine( Commandline cl, InputStream systemIn, StreamConsumer systemOut, StreamConsumer systemErr ) throws CommandLineException { return executeCommandLine( cl, systemIn, systemOut, systemErr, 0 ); } /** * @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." ); } final Process p = cl.execute(); final StreamFeeder inputFeeder = systemIn != null ? new StreamFeeder( systemIn, p.getOutputStream() ) : null; final StreamPumper outputPumper = new StreamPumper( p.getInputStream(), systemOut ); final StreamPumper errorPumper = new StreamPumper( p.getErrorStream(), systemErr ); if ( inputFeeder != null ) { inputFeeder.start(); } outputPumper.start(); errorPumper.start(); final ProcessHook processHook = new ProcessHook( p ); ShutdownHookUtils.addShutDownHook( processHook ); return new CommandLineCallable() { public Integer call() throws CommandLineException { try { 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(); } waitForAllPumpers( inputFeeder, outputPumper, errorPumper ); if ( outputPumper.getException() != null ) { throw new CommandLineException( "Error inside systemOut parser", outputPumper.getException() ); } if ( errorPumper.getException() != null ) { throw new CommandLineException( "Error inside systemErr parser", errorPumper.getException() ); } return returnValue; } catch ( InterruptedException ex ) { if ( inputFeeder != null ) { inputFeeder.disable(); } outputPumper.disable(); errorPumper.disable(); throw new CommandLineTimeOutException( "Error while executing external command, process killed.", ex ); } finally { ShutdownHookUtils.removeShutdownHook( processHook ); processHook.run(); if ( inputFeeder != null ) { inputFeeder.close(); } outputPumper.close(); errorPumper.close(); } } }; } private static void waitForAllPumpers( StreamFeeder inputFeeder, StreamPumper outputPumper, StreamPumper errorPumper ) throws InterruptedException { if ( inputFeeder != null ) { inputFeeder.waitUntilDone(); } outputPumper.waitUntilDone(); errorPumper.waitUntilDone(); } /** * Gets the shell environment variables for this process. Note that the returned mapping from variable names to * values will always be case-sensitive regardless of the platform, i.e. getSystemEnvVars().get("path") * and getSystemEnvVars().get("PATH") will in general return different values. However, on platforms * with case-insensitive environment variables like Windows, all variable names will be normalized to upper case. * * @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. */ public static Properties getSystemEnvVars() throws IOException { return getSystemEnvVars( !Os.isFamily( Os.FAMILY_WINDOWS ) ); } /** * Return the shell environment variables. If caseSensitive == true, then envar * keys will all be upper-case. * * @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 . * @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. */ public static Properties getSystemEnvVars( boolean caseSensitive ) throws IOException { Properties envVars = new Properties(); Map envs = System.getenv(); for ( String key : envs.keySet() ) { String value = envs.get( key ); if ( !caseSensitive) { key = key.toUpperCase( Locale.ENGLISH ); } envVars.put( key, value ); } return envVars; } public static boolean isAlive( Process p ) { if ( p == null ) { return false; } try { p.exitValue(); return false; } catch ( IllegalThreadStateException e ) { return true; } } public static String[] translateCommandline( String toProcess ) throws Exception { if ( ( toProcess == null ) || ( toProcess.length() == 0 ) ) { return new String[0]; } // parse with a simple finite state machine final int normal = 0; final int inQuote = 1; final int inDoubleQuote = 2; int state = normal; StringTokenizer tok = new StringTokenizer( toProcess, "\"\' ", true ); Vector v = new Vector(); StringBuilder current = new StringBuilder(); while ( tok.hasMoreTokens() ) { String nextTok = tok.nextToken(); switch ( state ) { case inQuote: if ( "\'".equals( nextTok ) ) { state = normal; } else { current.append( nextTok ); } break; case inDoubleQuote: if ( "\"".equals( nextTok ) ) { state = normal; } else { current.append( nextTok ); } break; default: if ( "\'".equals( nextTok ) ) { state = inQuote; } else if ( "\"".equals( nextTok ) ) { state = inDoubleQuote; } else if ( " ".equals( nextTok ) ) { if ( current.length() != 0 ) { v.addElement( current.toString() ); current.setLength( 0 ); } } else { current.append( nextTok ); } break; } } if ( current.length() != 0 ) { v.addElement( current.toString() ); } if ( ( state == inQuote ) || ( state == inDoubleQuote ) ) { throw new CommandLineException( "unbalanced quotes in " + toProcess ); } String[] args = new String[v.size()]; v.copyInto( args ); return args; } /** *

Put quotes around the given String if necessary.

*

If the argument doesn't include spaces or quotes, return it * as is. If it contains double quotes, use single quotes - else * surround the argument by double quotes.

* * @throws CommandLineException if the argument contains both, single * and double quotes. * @deprecated Use {@link StringUtils#quoteAndEscape(String, char, char[], char[], char, boolean)}, * {@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 { return quote( argument, false, false, true ); } /** *

Put quotes around the given String if necessary.

*

If the argument doesn't include spaces or quotes, return it * as is. If it contains double quotes, use single quotes - else * surround the argument by double quotes.

* * @throws CommandLineException if the argument contains both, single * and double quotes. * @deprecated Use {@link StringUtils#quoteAndEscape(String, char, char[], char[], char, boolean)}, * {@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 { return quote( argument, false, false, wrapExistingQuotes ); } /** * @deprecated Use {@link StringUtils#quoteAndEscape(String, char, char[], char[], char, boolean)}, * {@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.contains( "\"" ) ) { if ( argument.contains( "\'" ) ) { throw new CommandLineException( "Can't handle single and double quotes in same argument" ); } else { if ( escapeSingleQuotes ) { return "\\\'" + argument + "\\\'"; } else if ( wrapExistingQuotes ) { return '\'' + argument + '\''; } } } else if ( argument.contains( "\'" ) ) { if ( escapeDoubleQuotes ) { return "\\\"" + argument + "\\\""; } else if ( wrapExistingQuotes ) { return '\"' + argument + '\"'; } } else if ( argument.contains( " " ) ) { if ( escapeDoubleQuotes ) { return "\\\"" + argument + "\\\""; } else { return '\"' + argument + '\"'; } } return argument; } public static String toString( String[] line ) { // empty path return empty string if ( ( line == null ) || ( line.length == 0 ) ) { return ""; } // path containing one or more elements final StringBuilder result = new StringBuilder(); for ( int i = 0; i < line.length; i++ ) { if ( i > 0 ) { result.append( ' ' ); } try { result.append( StringUtils.quoteAndEscape( line[i], '\"' ) ); } catch ( Exception e ) { System.err.println( "Error quoting argument: " + e.getMessage() ); } } return result.toString(); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/cli/Commandline.java000066400000000000000000000545441251077732300321260ustar00rootroot00000000000000package 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. */ /*************************************************************************************************** * CruiseControl, a Continuous Integration Toolkit Copyright (c) 2001-2003, ThoughtWorks, Inc. 651 W * Washington Ave. Suite 500 Chicago, IL 60661 USA All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted * provided that the following conditions are met: + Redistributions of source code must retain the * above copyright notice, this list of conditions and the following disclaimer. + Redistributions * in binary form must reproduce the above copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of ThoughtWorks, Inc., CruiseControl, nor the names of its contributors may be * used to endorse or promote products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **************************************************************************************************/ /* * ==================================================================== * Copyright 2003-2004 The Apache Software 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 org.codehaus.plexus.util.Os; import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.util.cli.shell.BourneShell; import org.codehaus.plexus.util.cli.shell.CmdShell; import org.codehaus.plexus.util.cli.shell.CommandShell; import org.codehaus.plexus.util.cli.shell.Shell; import java.io.File; import java.io.IOException; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Properties; import java.util.Vector; /** *

* Commandline objects help handling command lines specifying processes to * execute. *

*

* The class can be used to define a command line as nested elements or as a * helper to define a command line by an application. *

*

* * <someelement>
*   <acommandline executable="/executable/to/run">
*     <argument value="argument 1" />
*     <argument line="argument_1 argument_2 argument_3" />
*     <argument value="argument 4" />
*   </acommandline>
* </someelement>
*
*

*

* The element someelement must provide a method * createAcommandline which returns an instance of this class. *

* * @author thomas.haas@softwired-inc.com * @author Stefan Bodewig */ public class Commandline implements Cloneable { /** * @deprecated Use {@link org.codehaus.plexus.util.Os} class instead. */ protected static final String OS_NAME = "os.name"; /** * @deprecated Use {@link org.codehaus.plexus.util.Os} class instead. */ protected static final String WINDOWS = "Windows"; protected Vector arguments = new Vector(); //protected Vector envVars = new Vector(); // synchronized added to preserve synchronize of Vector class protected Map envVars = Collections.synchronizedMap( new LinkedHashMap() ); private long pid = -1; private Shell shell; /** * @deprecated Use {@link Commandline#setExecutable(String)} instead. */ protected String executable; /** * @deprecated Use {@link Commandline#setWorkingDirectory(File)} or * {@link Commandline#setWorkingDirectory(String)} instead. */ private File workingDir; /** * 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 ) { this.shell = shell; String[] tmp = new String[0]; try { tmp = CommandLineUtils.translateCommandline( toProcess ); } catch ( Exception e ) { System.err.println( "Error translating Commandline." ); } if ( ( tmp != null ) && ( tmp.length > 0 ) ) { setExecutable( tmp[0] ); for ( int i = 1; i < tmp.length; i++ ) { createArgument().setValue( tmp[i] ); } } } /** * 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 ) { this.shell = shell; } /** * Create a new command line object, given a command following POSIX sh quoting rules * * @param toProcess */ public Commandline( String toProcess ) { setDefaultShell(); String[] tmp = new String[0]; try { tmp = CommandLineUtils.translateCommandline( toProcess ); } catch ( Exception e ) { System.err.println( "Error translating Commandline." ); } if ( ( tmp != null ) && ( tmp.length > 0 ) ) { setExecutable( tmp[0] ); for ( int i = 1; i < tmp.length; i++ ) { createArgument().setValue( tmp[i] ); } } } /** * Create a new command line object. */ public Commandline() { setDefaultShell(); } public long getPid() { if ( pid == -1 ) { pid = Long.parseLong( String.valueOf( System.currentTimeMillis() ) ); } return pid; } public void setPid( long pid ) { this.pid = pid; } /** * Class to keep track of the position of an Argument. */ //

This class is there to support the srcfile and targetfile // elements of <execon> and <transform> - don't know // whether there might be additional use cases.

--SB public class Marker { private int position; private int realPos = -1; Marker( int position ) { this.position = position; } /** * Return the number of arguments that preceeded this marker. *

*

The name of the executable - if set - is counted as the * very first argument.

*/ public int getPosition() { if ( realPos == -1 ) { realPos = ( getLiteralExecutable() == null ? 0 : 1 ); for ( int i = 0; i < position; i++ ) { Arg arg = (Arg) arguments.elementAt( i ); realPos += arg.getParts().length; } } return realPos; } } /** *

Sets the shell or command-line interpretor for the detected operating system, * and the shell arguments.

*/ private void setDefaultShell() { //If this is windows set the shell to command.com or cmd.exe with correct arguments. if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) { if ( Os.isFamily( Os.FAMILY_WIN9X ) ) { setShell( new CommandShell() ); } else { setShell( new CmdShell() ); } } else { setShell( new BourneShell() ); } } /** * Creates an argument object. *

*

Each commandline object has at most one instance of the * argument class. This method calls * this.createArgument(false).

* * @return the argument object. * @see #createArgument(boolean) * @deprecated Use {@link Commandline#createArg()} instead */ public Argument createArgument() { return this.createArgument( false ); } /** * Creates an argument object and adds it to our list of args. *

*

Each commandline object has at most one instance of the * argument class.

* * @param insertAtStart if true, the argument is inserted at the * beginning of the list of args, otherwise it is appended. * @deprecated Use {@link Commandline#createArg(boolean)} instead */ public Argument createArgument( boolean insertAtStart ) { Argument argument = new Argument(); if ( insertAtStart ) { arguments.insertElementAt( argument, 0 ); } else { arguments.addElement( argument ); } return argument; } /** * Creates an argument object. *

*

Each commandline object has at most one instance of the * argument class. This method calls * this.createArgument(false).

* * @return the argument object. * @see #createArgument(boolean) */ public Arg createArg() { return this.createArg( false ); } /** * Creates an argument object and adds it to our list of args. *

*

Each commandline object has at most one instance of the * argument class.

* * @param insertAtStart if true, the argument is inserted at the * beginning of the list of args, otherwise it is appended. */ public Arg createArg( boolean insertAtStart ) { Arg argument = new Argument(); if ( insertAtStart ) { arguments.insertElementAt( argument, 0 ); } else { arguments.addElement( argument ); } return argument; } /** * Adds an argument object to our list of args. * * @return the argument object. * @see #addArg(Arg,boolean) */ public void addArg( Arg argument ) { this.addArg( argument, false ); } /** * Adds an argument object to our list of args. * * @param insertAtStart if true, the argument is inserted at the * beginning of the list of args, otherwise it is appended. */ public void addArg( Arg argument, boolean insertAtStart ) { if ( insertAtStart ) { arguments.insertElementAt( argument, 0 ); } else { arguments.addElement( argument ); } } /** * Sets the executable to run. */ public void setExecutable( String executable ) { shell.setExecutable( 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(); if ( exec == null ) { exec = executable; } return exec; } public void addArguments( String[] line ) { for ( String aLine : line ) { createArgument().setValue( aLine ); } } /** * Add an environment variable */ public void addEnvironment( String name, String value ) { //envVars.add( name + "=" + value ); envVars.put( name, value ); } /** * Add system environment variables */ public void addSystemEnvironment() throws Exception { Properties systemEnvVars = CommandLineUtils.getSystemEnvVars(); for ( Object o : systemEnvVars.keySet() ) { String key = (String) o; if ( !envVars.containsKey( key ) ) { addEnvironment( key, systemEnvVars.getProperty( key ) ); } } } /** * Return the list of environment variables */ public String[] getEnvironmentVariables() throws CommandLineException { try { addSystemEnvironment(); } catch ( Exception e ) { throw new CommandLineException( "Error setting up environmental variables", e ); } String[] environmentVars = new String[envVars.size()]; int i = 0; for ( Object o : envVars.keySet() ) { String name = (String) o; String value = (String) envVars.get( name ); environmentVars[i] = name + "=" + value; i++; } return environmentVars; } /** * Returns the executable and all defined arguments. */ public String[] getCommandline() { final String[] args = getArguments(); String executable = getLiteralExecutable(); if ( executable == null ) { return args; } final String[] result = new String[args.length + 1]; result[0] = executable; System.arraycopy( args, 0, result, 1, args.length ); return result; } /** * Returns the shell, executable and all defined arguments. * * Shell usage is only desirable when generating code for remote execution. */ public String[] getShellCommandline() { // TODO: Provided only for backward compat. with <= 1.4 verifyShellState(); return (String[]) getShell().getShellCommandLine( getArguments() ).toArray( new String[0] ); } /** * Returns all arguments defined by addLine, * addValue or the argument object. */ public String[] getArguments() { Vector result = new Vector( arguments.size() * 2 ); for ( int i = 0; i < arguments.size(); i++ ) { Arg arg = arguments.elementAt( i ); String[] s = arg.getParts(); if ( s != null ) { for ( String value : s ) { result.addElement( value ); } } } String[] res = new String[result.size()]; result.copyInto( res ); return res; } public String toString() { return StringUtils.join( getShellCommandline(), " " ); } public int size() { return getCommandline().length; } public Object clone() { Commandline c = new Commandline( (Shell) shell.clone() ); c.executable = executable; c.workingDir = workingDir; c.addArguments( getArguments() ); return c; } /** * Clear out the whole command line. */ public void clear() { executable = null; workingDir = null; shell.setExecutable( null ); shell.clearArguments(); arguments.removeAllElements(); } /** * Clear out the arguments but leave the executable in place for another operation. */ public void clearArgs() { arguments.removeAllElements(); } /** * Return a marker. *

*

This marker can be used to locate a position on the * commandline - to insert something for example - when all * parameters have been set.

*/ public Marker createMarker() { return new Marker( arguments.size() ); } /** * Sets execution directory. */ public void setWorkingDirectory( String path ) { shell.setWorkingDirectory( path ); workingDir = new File( path ); } /** * Sets execution directory. */ public void setWorkingDirectory( File workingDirectory ) { shell.setWorkingDirectory( workingDirectory ); workingDir = workingDirectory; } public File getWorkingDirectory() { File workDir = shell.getWorkingDirectory(); if ( workDir == null ) { workDir = workingDir; } return workDir; } /** * Executes the command. */ public Process execute() throws CommandLineException { // TODO: Provided only for backward compat. with <= 1.4 verifyShellState(); Process process; //addEnvironment( "MAVEN_TEST_ENVAR", "MAVEN_TEST_ENVAR_VALUE" ); String[] environment = getEnvironmentVariables(); File workingDir = shell.getWorkingDirectory(); try { if ( workingDir == null ) { process = Runtime.getRuntime().exec( getCommandline(), environment, workingDir ); } else { if ( !workingDir.exists() ) { throw new CommandLineException( "Working directory \"" + workingDir.getPath() + "\" does not exist!" ); } else if ( !workingDir.isDirectory() ) { throw new CommandLineException( "Path \"" + workingDir.getPath() + "\" does not specify a directory." ); } process = Runtime.getRuntime().exec( getCommandline(), environment, workingDir ); } } catch ( IOException ex ) { throw new CommandLineException( "Error while executing process.", ex ); } return process; } /** * @deprecated Remove once backward compat with plexus-utils <= 1.4 is no longer a consideration */ private void verifyShellState() { if ( shell.getWorkingDirectory() == null ) { shell.setWorkingDirectory( workingDir ); } if ( shell.getOriginalExecutable() == null ) { shell.setExecutable( executable ); } } public Properties getSystemEnvVars() throws Exception { return CommandLineUtils.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 */ public void setShell( Shell shell ) { this.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() { return shell; } /** * @deprecated Use {@link CommandLineUtils#translateCommandline(String)} instead. */ public static String[] translateCommandline( String toProcess ) throws Exception { return CommandLineUtils.translateCommandline( toProcess ); } /** * @deprecated Use {@link CommandLineUtils#quote(String)} instead. */ public static String quoteArgument( String argument ) throws CommandLineException { return CommandLineUtils.quote( argument ); } /** * @deprecated Use {@link CommandLineUtils#toString(String[])} instead. */ public static String toString( String[] line ) { return CommandLineUtils.toString( line ); } public static class Argument implements Arg { private String[] parts; /* (non-Javadoc) * @see org.codehaus.plexus.util.cli.Argumnt#setValue(java.lang.String) */ public void setValue( String value ) { if ( value != null ) { parts = new String[] { value }; } } /* (non-Javadoc) * @see org.codehaus.plexus.util.cli.Argumnt#setLine(java.lang.String) */ public void setLine( String line ) { if ( line == null ) { return; } try { parts = CommandLineUtils.translateCommandline( line ); } catch ( Exception e ) { System.err.println( "Error translating Commandline." ); } } /* (non-Javadoc) * @see org.codehaus.plexus.util.cli.Argumnt#setFile(java.io.File) */ public void setFile( File value ) { parts = new String[] { value.getAbsolutePath() }; } /* (non-Javadoc) * @see org.codehaus.plexus.util.cli.Argumnt#getParts() */ public String[] getParts() { return parts; } } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/cli/DefaultConsumer.java000066400000000000000000000015731251077732300327720ustar00rootroot00000000000000package 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 Emmanuel Venisse * @version $Id$ */ public class DefaultConsumer implements StreamConsumer { public void consumeLine( String line ) { System.out.println( line ); } } EnhancedStringTokenizer.java000066400000000000000000000062221251077732300343760ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/clipackage 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.StringTokenizer; /** * The java.util.StringTokenizer is horribly broken. * Given the string 1,,,3,,4 (, delim) * It will return 1,3,4 * Which is clearly wrong - 1,EMPTY,EMPTY,3,EMPTY,4 is what it should return * @version $Id$ */ public final class EnhancedStringTokenizer { private StringTokenizer cst = null; String cdelim; final boolean cdelimSingleChar; final char cdelimChar; boolean creturnDelims; String lastToken = null; boolean delimLast = true; public EnhancedStringTokenizer( String str ) { this( str, " \t\n\r\f", false ); } public EnhancedStringTokenizer( String str, String delim ) { this( str, delim, false ); } public EnhancedStringTokenizer( String str, String delim, boolean returnDelims ) { cst = new StringTokenizer( str, delim, true ); cdelim = delim; creturnDelims = returnDelims; cdelimSingleChar = ( delim.length() == 1 ); cdelimChar = delim.charAt( 0 ); } public boolean hasMoreTokens() { return cst.hasMoreTokens(); } private String internalNextToken() { if ( lastToken != null ) { String last = lastToken; lastToken = null; return last; } String token = cst.nextToken(); if ( isDelim( token ) ) { if ( delimLast ) { lastToken = token; return ""; } else { delimLast = true; return token; } } else { delimLast = false; return token; } } public String nextToken() { String token = internalNextToken(); if ( creturnDelims ) { return token; } if ( isDelim( token ) ) { return hasMoreTokens() ? internalNextToken() : ""; } else { return token; } } private boolean isDelim( String str ) { if ( str.length() == 1 ) { char ch = str.charAt( 0 ); if ( cdelimSingleChar ) { if ( cdelimChar == ch ) { return true; } } else { if ( cdelim.indexOf( ch ) >= 0 ) { return true; } } } return false; } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/cli/ShutdownHookUtils.java000066400000000000000000000030111251077732300333340ustar00rootroot00000000000000package 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 ) { } } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/cli/StreamConsumer.java000066400000000000000000000061041251077732300326340ustar00rootroot00000000000000package 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. */ /******************************************************************************** * CruiseControl, a Continuous Integration Toolkit * Copyright (c) 2003, ThoughtWorks, Inc. * 651 W Washington Ave. Suite 500 * Chicago, IL 60661 USA * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * + Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * + Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the * names of its contributors may be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ********************************************************************************/ /** * Works in concert with the StreamPumper class to * allow implementations to gain access to the lines being * "Pumped". * * Please note that implementations of this interface can be expected to be * called from arbitrary threads and must therefore be threadsafe. * * @author Florin Vancea * @author Paul Julius * @version $Id$ */ public interface StreamConsumer { /** * Called when the StreamPumper pumps a line from the Stream. */ public void consumeLine( String line ); } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/cli/StreamFeeder.java000066400000000000000000000063711251077732300322410ustar00rootroot00000000000000package 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.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * Read from an InputStream and write the output to an OutputStream. * * @author Trygve Laugstøl * @version $Id$ */ public class StreamFeeder extends AbstractStreamHandler { private InputStream input; private OutputStream output; /** * Create a new StreamFeeder * * @param input Stream to read from * @param output Stream to write to */ public StreamFeeder( InputStream input, OutputStream output ) { this.input = input; this.output = output; } // ---------------------------------------------------------------------- // Runnable implementation // ---------------------------------------------------------------------- public void run() { try { feed(); } catch ( Throwable ex ) { // Catched everything so the streams will be closed and flagged as done. } finally { close(); synchronized ( this ) { setDone(); this.notifyAll(); } } } // ---------------------------------------------------------------------- // // ---------------------------------------------------------------------- public void close() { if ( input != null ) { synchronized ( input ) { try { input.close(); } catch ( IOException ex ) { // ignore } input = null; } } if ( output != null ) { synchronized ( output ) { try { output.close(); } catch ( IOException ex ) { // ignore } output = null; } } } // ---------------------------------------------------------------------- // // ---------------------------------------------------------------------- private void feed() throws IOException { int data = input.read(); while ( !isDone() && data != -1 ) { synchronized ( output ) { if ( !isDisabled()) { output.write( data ); } data = input.read(); } } } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/cli/StreamPumper.java000066400000000000000000000134641251077732300323200ustar00rootroot00000000000000package 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. */ /******************************************************************************** * CruiseControl, a Continuous Integration Toolkit * Copyright (c) 2001-2003, ThoughtWorks, Inc. * 651 W Washington Ave. Suite 500 * Chicago, IL 60661 USA * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * + Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * + Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the * names of its contributors may be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ********************************************************************************/ /* ==================================================================== * Copyright 2003-2004 The Apache Software 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 org.codehaus.plexus.util.IOUtil; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; /** * Class to pump the error stream during Process's runtime. Copied from the Ant * built-in task. * * @author Florin Vancea * @author Paul Julius * @version $Id$ * @since June 11, 2001 */ public class StreamPumper extends AbstractStreamHandler { private final BufferedReader in; private final StreamConsumer consumer; private final PrintWriter out; private volatile Exception exception = null; private static final int SIZE = 1024; public StreamPumper( InputStream in ) { this( in, (StreamConsumer) null ); } public StreamPumper( InputStream in, StreamConsumer consumer ) { this( in, null, consumer ); } public StreamPumper( InputStream in, PrintWriter writer ) { this( in, writer, null ); } public StreamPumper( InputStream in, PrintWriter writer, StreamConsumer consumer ) { this.in = new BufferedReader( new InputStreamReader( in ), SIZE ); this.out = writer; this.consumer = consumer; } public void run() { try { for ( String line = in.readLine(); line != null; line = in.readLine() ) { try { if ( exception == null ) { consumeLine( line ); } } catch ( Exception t ) { exception = t; } if ( out != null ) { out.println( line ); out.flush(); } } } catch ( IOException e ) { exception = e; } finally { IOUtil.close( in ); synchronized ( this ) { setDone(); this.notifyAll(); } } } public void flush() { if ( out != null ) { out.flush(); } } public void close() { IOUtil.close( out ); } public Exception getException() { return exception; } private void consumeLine( String line ) { if ( consumer != null && !isDisabled() ) { consumer.consumeLine( line ); } } } WriterStreamConsumer.java000066400000000000000000000021221251077732300337460ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/clipackage 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.io.PrintWriter; import java.io.Writer; /** * @author Jason van Zyl * @version $Id$ */ public class WriterStreamConsumer implements StreamConsumer { private PrintWriter writer; public WriterStreamConsumer( Writer writer ) { this.writer = new PrintWriter( writer ); } public void consumeLine( String line ) { writer.println( line ); writer.flush(); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/cli/shell/000077500000000000000000000000001251077732300301305ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/cli/shell/BourneShell.java000066400000000000000000000101431251077732300332140ustar00rootroot00000000000000package org.codehaus.plexus.util.cli.shell; /* * 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 org.codehaus.plexus.util.Os; import java.util.ArrayList; import java.util.List; /** * @author Jason van Zyl * @version $Id$ */ public class BourneShell extends Shell { public BourneShell() { this(false); } public BourneShell( boolean isLoginShell ) { setUnconditionalQuoting( true ); setShellCommand( "/bin/sh" ); setArgumentQuoteDelimiter( '\'' ); setExecutableQuoteDelimiter( '\'' ); setSingleQuotedArgumentEscaped( true ); setSingleQuotedExecutableEscaped( false ); setQuotedExecutableEnabled( true ); setArgumentEscapePattern("'\\%s'"); if ( isLoginShell ) { addShellArg( "-l" ); } } /** {@inheritDoc} */ public String getExecutable() { if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) { return super.getExecutable(); } return quoteOneItem( super.getOriginalExecutable(), true ); } public List getShellArgsList() { List shellArgs = new ArrayList(); List existingShellArgs = super.getShellArgsList(); if ( ( existingShellArgs != null ) && !existingShellArgs.isEmpty() ) { shellArgs.addAll( existingShellArgs ); } shellArgs.add( "-c" ); return shellArgs; } public String[] getShellArgs() { String[] shellArgs = super.getShellArgs(); if ( shellArgs == null ) { shellArgs = new String[0]; } if ( ( shellArgs.length > 0 ) && !shellArgs[shellArgs.length - 1].equals( "-c" ) ) { String[] newArgs = new String[shellArgs.length + 1]; System.arraycopy( shellArgs, 0, newArgs, 0, shellArgs.length ); newArgs[shellArgs.length] = "-c"; shellArgs = newArgs; } return shellArgs; } protected String getExecutionPreamble() { if ( getWorkingDirectoryAsString() == null ) { return null; } String dir = getWorkingDirectoryAsString(); StringBuilder sb = new StringBuilder(); sb.append( "cd " ); sb.append( quoteOneItem( dir, false ) ); sb.append( " && " ); return sb.toString(); } /** *

Unify quotes in a path for the Bourne Shell.

* *
     * 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 String quoteOneItem( String path, boolean isExecutable ) { if ( path == null ) { return null; } StringBuilder sb = new StringBuilder(); sb.append( "'" ); sb.append( path.replace( "'", "'\"'\"'" ) ); sb.append( "'" ); return sb.toString(); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/cli/shell/CmdShell.java000066400000000000000000000056321251077732300324740ustar00rootroot00000000000000package org.codehaus.plexus.util.cli.shell; /* * 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.Arrays; import java.util.List; /** *

* Implementation to call the CMD Shell present on Windows NT, 2000 and XP *

* * @author Carlos Sanchez * @since 1.2 * @version $Id$ */ public class CmdShell extends Shell { public CmdShell() { setShellCommand( "cmd.exe" ); setQuotedExecutableEnabled( true ); setShellArgs( new String[]{"/X", "/C"} ); } /** *

* Specific implementation that quotes all the command line. *

*

* Workaround for http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6468220 *

*

* From cmd.exe /? output: *

* *
     *      If /C or /K is specified, then the remainder of the command line after
     *      the switch is processed as a command line, where the following logic is
     *      used to process quote (") characters:
     *
     *      1.  If all of the following conditions are met, then quote characters
     *      on the command line are preserved:
     *
     *      - no /S switch
     *      - exactly two quote characters
     *      - no special characters between the two quote characters,
     *      where special is one of: &<>()@ˆ|
     *      - there are one or more whitespace characters between the
     *      the two quote characters
     *      - the string between the two quote characters is the name
     *      of an executable file.
     *
     *      2.  Otherwise, old behavior is to see if the first character is
     *      a quote character and if so, strip the leading character and
     *      remove the last quote character on the command line, preserving
     *      any text after the last quote character.
     * 
* *

* Always quoting the entire command line, regardless of these conditions * appears to make Windows processes invoke successfully. *

*/ public List getCommandLine( String executable, String[] arguments ) { StringBuilder sb = new StringBuilder(); sb.append( "\"" ); sb.append( super.getCommandLine( executable, arguments ).get( 0 ) ); sb.append( "\"" ); return Arrays.asList( new String[] { sb.toString() } ); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/cli/shell/CommandShell.java000066400000000000000000000020011251077732300333320ustar00rootroot00000000000000package org.codehaus.plexus.util.cli.shell; /* * 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. */ /** *

* Implementation to call the Command.com Shell present on Windows 95, 98 and Me *

* * @author Carlos Sanchez * @since 1.2 * @version $Id$ */ public class CommandShell extends Shell { public CommandShell() { setShellCommand( "command.com" ); setShellArgs( new String[]{"/C"} ); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/cli/shell/Shell.java000066400000000000000000000252571251077732300320550ustar00rootroot00000000000000package org.codehaus.plexus.util.cli.shell; /* * 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 org.codehaus.plexus.util.StringUtils; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** *

* Class that abstracts the Shell functionality, * with subclases for shells that behave particularly, like *

    *
  • command.com
  • *
  • cmd.exe
  • *
*

* * @author Carlos Sanchez * @since 1.2 * @version $Id$ */ public class Shell implements Cloneable { private static final char[] DEFAULT_QUOTING_TRIGGER_CHARS = { ' ' }; private String shellCommand; private List shellArgs = new ArrayList(); private boolean quotedArgumentsEnabled = true; private boolean unconditionallyQuote = false; private String executable; private String workingDir; private boolean quotedExecutableEnabled = true; private boolean doubleQuotedArgumentEscaped = false; private boolean singleQuotedArgumentEscaped = false; private boolean doubleQuotedExecutableEscaped = false; private boolean singleQuotedExecutableEscaped = false; private char argQuoteDelimiter = '\"'; 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,...) * * @param shellCommand */ public void setShellCommand( String shellCommand ) { this.shellCommand = shellCommand; } /** * Get the command to execute the shell * * @return */ public String getShellCommand() { return shellCommand; } /** * Set the shell arguments when calling a command line (not the executable arguments) * (eg. /X /C for CMD.EXE) * * @param shellArgs */ public void setShellArgs( String[] shellArgs ) { this.shellArgs.clear(); this.shellArgs.addAll( Arrays.asList( shellArgs ) ); } /** * Get the shell arguments * * @return */ public String[] getShellArgs() { if ( ( shellArgs == null ) || shellArgs.isEmpty() ) { return null; } else { return (String[]) shellArgs.toArray( new String[shellArgs.size()] ); } } /** * Get the command line for the provided executable and arguments in this shell * * @param executable executable that the shell has to call * @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 ) { 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(); StringBuilder sb = new StringBuilder(); if ( executable != null ) { String preamble = getExecutionPreamble(); if ( preamble != null ) { sb.append( preamble ); } if ( isQuotedExecutableEnabled() ) { sb.append( quoteOneItem( getOriginalExecutable(), true ) ); } else { sb.append( getExecutable() ); } } for ( String argument : arguments ) { if ( sb.length() > 0 ) { sb.append( " " ); } if ( isQuotedArgumentsEnabled() ) { sb.append( quoteOneItem( argument, false ) ); } else { sb.append( argument ); } } commandLine.add( sb.toString() ); return commandLine; } protected char[] getQuotingTriggerChars() { return DEFAULT_QUOTING_TRIGGER_CHARS; } protected String getExecutionPreamble() { return null; } protected char[] getEscapeChars( boolean includeSingleQuote, boolean includeDoubleQuote ) { StringBuilder buf = new StringBuilder( 2 ); if ( includeSingleQuote ) { buf.append( '\'' ); } if ( includeDoubleQuote ) { buf.append( '\"' ); } char[] result = new char[buf.length()]; buf.getChars( 0, buf.length(), result, 0 ); return result; } protected boolean isDoubleQuotedArgumentEscaped() { return doubleQuotedArgumentEscaped; } protected boolean isSingleQuotedArgumentEscaped() { return singleQuotedArgumentEscaped; } protected boolean isDoubleQuotedExecutableEscaped() { return doubleQuotedExecutableEscaped; } protected boolean isSingleQuotedExecutableEscaped() { return singleQuotedExecutableEscaped; } protected void setArgumentQuoteDelimiter( char argQuoteDelimiter ) { this.argQuoteDelimiter = argQuoteDelimiter; } protected char getArgumentQuoteDelimiter() { return argQuoteDelimiter; } protected void setExecutableQuoteDelimiter( char exeQuoteDelimiter ) { this.exeQuoteDelimiter = exeQuoteDelimiter; } 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 * * @param arguments arguments for the executable, not the shell * @return List of String objects, whose array version is suitable to be used as argument * of Runtime.getRuntime().exec() */ public List getShellCommandLine( String[] arguments ) { List commandLine = new ArrayList(); if ( getShellCommand() != null ) { commandLine.add( getShellCommand() ); } if ( getShellArgs() != null ) { commandLine.addAll( getShellArgsList() ); } commandLine.addAll( getCommandLine( getOriginalExecutable(), arguments ) ); return commandLine; } public List getShellArgsList() { return shellArgs; } public void addShellArg( String arg ) { shellArgs.add( arg ); } public void setQuotedArgumentsEnabled( boolean quotedArgumentsEnabled ) { this.quotedArgumentsEnabled = quotedArgumentsEnabled; } public boolean isQuotedArgumentsEnabled() { return quotedArgumentsEnabled; } public void setQuotedExecutableEnabled( boolean quotedExecutableEnabled ) { this.quotedExecutableEnabled = quotedExecutableEnabled; } public boolean isQuotedExecutableEnabled() { return quotedExecutableEnabled; } /** * Sets the executable to run. */ public void setExecutable( String executable ) { if ( ( executable == null ) || ( executable.length() == 0 ) ) { return; } this.executable = executable.replace( '/', File.separatorChar ).replace( '\\', File.separatorChar ); } public String getExecutable() { return executable; } /** * Sets execution directory. */ public void setWorkingDirectory( String path ) { if ( path != null ) { workingDir = path; } } /** * Sets execution directory. */ public void setWorkingDirectory( File workingDir ) { if ( workingDir != null ) { this.workingDir = workingDir.getAbsolutePath(); } } public File getWorkingDirectory() { return workingDir == null ? null : new File( workingDir ); } public String getWorkingDirectoryAsString() { return workingDir; } public void clearArguments() { shellArgs.clear(); } public Object clone() { Shell shell = new Shell(); shell.setExecutable( getExecutable() ); shell.setWorkingDirectory( getWorkingDirectory() ); shell.setShellArgs( getShellArgs() ); return shell; } public String getOriginalExecutable() { return executable; } public List getOriginalCommandLine( String executable, String[] arguments ) { return getRawCommandLine( executable, arguments ); } protected void setDoubleQuotedArgumentEscaped( boolean doubleQuotedArgumentEscaped ) { this.doubleQuotedArgumentEscaped = doubleQuotedArgumentEscaped; } protected void setDoubleQuotedExecutableEscaped( boolean doubleQuotedExecutableEscaped ) { this.doubleQuotedExecutableEscaped = doubleQuotedExecutableEscaped; } protected void setSingleQuotedArgumentEscaped( boolean singleQuotedArgumentEscaped ) { this.singleQuotedArgumentEscaped = singleQuotedArgumentEscaped; } protected void setSingleQuotedExecutableEscaped( boolean singleQuotedExecutableEscaped ) { this.singleQuotedExecutableEscaped = singleQuotedExecutableEscaped; } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/dag/000077500000000000000000000000001251077732300270055ustar00rootroot00000000000000CycleDetectedException.java000066400000000000000000000030121251077732300341450ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/dagpackage org.codehaus.plexus.util.dag; /* * 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.Iterator; import java.util.List; public class CycleDetectedException extends Exception { private List cycle; public CycleDetectedException( final String message, final List cycle ) { super( message ); this.cycle = cycle; } public List getCycle() { return cycle; } /** * @return */ public String cycleToString() { final StringBuilder buffer = new StringBuilder(); for ( Iterator iterator = cycle.iterator(); iterator.hasNext(); ) { buffer.append( iterator.next() ); if ( iterator.hasNext() ) { buffer.append( " --> " ); } } return buffer.toString(); } public String getMessage() { return super.getMessage() + " " + cycleToString(); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/dag/CycleDetector.java000066400000000000000000000111211251077732300323750ustar00rootroot00000000000000package org.codehaus.plexus.util.dag; /* * 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.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; /** * @author Michal Maczka * @version $Id$ */ public class CycleDetector { private final static Integer NOT_VISTITED = 0; private final static Integer VISITING = 1; private final static Integer VISITED = 2; public static List hasCycle( final DAG graph ) { final List verticies = graph.getVerticies(); final Map vertexStateMap = new HashMap(); List retValue = null; for ( Vertex vertex : verticies ) { if ( isNotVisited( vertex, vertexStateMap ) ) { retValue = introducesCycle( vertex, vertexStateMap ); if ( retValue != null ) { break; } } } return retValue; } /** * 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 * * @param vertex * @param vertexStateMap * @return */ public static List introducesCycle( final Vertex vertex, final Map vertexStateMap ) { final LinkedList cycleStack = new LinkedList(); final boolean hasCycle = dfsVisit( vertex, cycleStack, vertexStateMap ); if ( hasCycle ) { // 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 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 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 ); Collections.reverse( cycle ); return cycle; } return null; } public static List introducesCycle( final Vertex vertex ) { final Map vertexStateMap = new HashMap(); return introducesCycle( vertex, vertexStateMap ); } /** * @param vertex * @param vertexStateMap * @return */ private static boolean isNotVisited( final Vertex vertex, final Map vertexStateMap ) { final Integer state = vertexStateMap.get( vertex ); return ( state == null ) || NOT_VISTITED.equals( state ); } /** * @param vertex * @param vertexStateMap * @return */ private static boolean isVisiting( final Vertex vertex, final Map vertexStateMap ) { final Integer state = vertexStateMap.get( vertex ); return VISITING.equals( state ); } private static boolean dfsVisit( final Vertex vertex, final LinkedList cycle, final Map vertexStateMap ) { cycle.addFirst( vertex.getLabel() ); vertexStateMap.put( vertex, VISITING ); for ( Vertex v : vertex.getChildren() ) { if ( isNotVisited( v, vertexStateMap ) ) { final boolean hasCycle = dfsVisit( v, cycle, vertexStateMap ); if ( hasCycle ) { return true; } } else if ( isVisiting( v, vertexStateMap ) ) { cycle.addFirst( v.getLabel() ); return true; } } vertexStateMap.put( vertex, VISITED ); cycle.removeFirst(); return false; } }plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/dag/DAG.java000066400000000000000000000145531251077732300302530ustar00rootroot00000000000000package org.codehaus.plexus.util.dag; /* * 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.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; /** * DAG = Directed Acyclic Graph * * @author Michal Maczka * @version $Id$ * @todo this class should be renamed from DAG to Dag */ public class DAG implements Cloneable, Serializable { //------------------------------------------------------------ //Fields //------------------------------------------------------------ /** * 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(); /** * Conatin list of all verticies */ private List vertexList = new ArrayList(); // ------------------------------------------------------------ // Constructors // ------------------------------------------------------------ /** * */ public DAG() { super(); } // ------------------------------------------------------------ // Accessors // ------------------------------------------------------------ /** * @return */ public List getVerticies() { return vertexList; } public Set getLabels() { return vertexMap.keySet(); } // ------------------------------------------------------------ // Implementation // ------------------------------------------------------------ /** * Adds vertex to DAG. If vertex of given label alredy exist in DAG * no vertex is added * * @param label The lable of the Vertex * @return New vertex if vertext of given label was not presenst in the DAG * or exising vertex if vertex of given labale was alredy added to DAG */ public Vertex addVertex( final String label ) { Vertex retValue = null; // check if vertex is alredy in DAG if ( vertexMap.containsKey( label ) ) { retValue = vertexMap.get( label ); } else { retValue = new Vertex( label ); vertexMap.put( label, retValue ); vertexList.add( retValue ); } return retValue; } public void addEdge( final String from, final String to ) throws CycleDetectedException { final Vertex v1 = addVertex( from ); final Vertex v2 = addVertex( to ); addEdge( v1, v2 ); } public void addEdge( final Vertex from, final Vertex to ) throws CycleDetectedException { from.addEdgeTo( to ); to.addEdgeFrom( from ); final List cycle = CycleDetector.introducesCycle( to ); if ( cycle != null ) { // remove edge which introduced cycle removeEdge( from, to ); final String msg = "Edge between '" + from + "' and '" + to + "' introduces to cycle in the graph"; throw new CycleDetectedException( msg, cycle ); } } public void removeEdge( final String from, final String to ) { final Vertex v1 = addVertex( from ); final Vertex v2 = addVertex( to ); removeEdge( v1, v2 ); } public void removeEdge( final Vertex from, final Vertex to ) { from.removeEdgeTo( to ); to.removeEdgeFrom( from ); } public Vertex getVertex( final String label ) { final Vertex retValue = ( Vertex ) vertexMap.get( label ); return retValue; } public boolean hasEdge( final String label1, final String label2 ) { final Vertex v1 = getVertex( label1 ); final Vertex v2 = getVertex( label2 ); final boolean retValue = v1.getChildren().contains( v2 ); return retValue; } /** * @param label * @return */ public List getChildLabels( final String label ) { final Vertex vertex = getVertex( label ); return vertex.getChildLabels(); } /** * @param label * @return */ public List getParentLabels( final String label ) { final Vertex vertex = getVertex( label ); return vertex.getParentLabels(); } /** * @see java.lang.Object#clone() */ public Object clone() throws CloneNotSupportedException { // this is what's failing.. final Object retValue = super.clone(); return retValue; } /** * Indicates if there is at least one edge leading to or from vertex of given label * * @return true if this vertex is connected with other vertex,false otherwise */ public boolean isConnected( final String label ) { final Vertex vertex = getVertex( label ); final boolean retValue = vertex.isConnected(); return retValue; } /** * Return the list of labels of successor in order decided by topological sort * * @param label The label of the vertex whose predessors are serched * * @return The list of labels. Returned list contains also * 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 ) { final Vertex vertex = getVertex( label ); final List retValue; //optimization. if ( vertex.isLeaf() ) { retValue = new ArrayList( 1 ); retValue.add( label ); } else { retValue = TopologicalSorter.sort( vertex ); } return retValue; } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/dag/TopologicalSorter.java000066400000000000000000000055151251077732300333310ustar00rootroot00000000000000package org.codehaus.plexus.util.dag; /* * 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.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; /** * @author Michal Maczka * @version $Id$ */ public class TopologicalSorter { private final static Integer NOT_VISTITED = 0; private final static Integer VISITING = 1; private final static Integer VISITED = 2; /** * @param graph * @return List of String (vertex labels) */ public static List sort( final DAG graph ) { return dfs( graph ); } public static List sort( final Vertex vertex ) { // we need to use addFirst method so we will use LinkedList explicitly final List retValue = new LinkedList(); dfsVisit( vertex, new HashMap(), retValue ); return retValue; } private static List dfs( final DAG graph ) { // we need to use addFirst method so we will use LinkedList explicitly final List retValue = new LinkedList(); final Map vertexStateMap = new HashMap(); for ( Vertex vertex : graph.getVerticies() ) { if ( isNotVisited( vertex, vertexStateMap ) ) { dfsVisit( vertex, vertexStateMap, retValue ); } } return retValue; } /** * @param vertex * @param vertexStateMap * @return */ private static boolean isNotVisited( final Vertex vertex, final Map vertexStateMap ) { final Integer state = vertexStateMap.get( vertex ); return ( state == null ) || NOT_VISTITED.equals( state ); } private static void dfsVisit( final Vertex vertex, final Map vertexStateMap, final List list ) { vertexStateMap.put( vertex, VISITING ); for ( Vertex v : vertex.getChildren() ) { if ( isNotVisited( v, vertexStateMap ) ) { dfsVisit( v, vertexStateMap, list ); } } vertexStateMap.put( vertex, VISITED ); list.add( vertex.getLabel() ); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/dag/Vertex.java000066400000000000000000000103551251077732300311310ustar00rootroot00000000000000package org.codehaus.plexus.util.dag; /* * 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.Serializable; import java.util.ArrayList; import java.util.List; /** * @author Michal Maczka * @version $Id$ */ public class Vertex implements Cloneable, Serializable { //------------------------------------------------------------ //Fields //------------------------------------------------------------ private String label = null; List children = new ArrayList(); List parents = new ArrayList(); // ------------------------------------------------------------ // Constructors // ------------------------------------------------------------ /** * */ public Vertex( final String label ) { this.label = label; } // ------------------------------------------------------------ // Accessors // ------------------------------------------------------------ /** * @return */ public String getLabel() { return label; } /** * @param vertex */ public void addEdgeTo( final Vertex vertex ) { children.add( vertex ); } /** * @param vertex */ public void removeEdgeTo( final Vertex vertex ) { children.remove( vertex ); } /** * @param vertex */ public void addEdgeFrom( final Vertex vertex ) { parents.add( vertex ); } public void removeEdgeFrom( final Vertex vertex ) { parents.remove( vertex ); } public List getChildren() { return children; } /** * Get the labels used by the most direct children. * * @return the labels used by the most direct children. */ public List getChildLabels() { final List retValue = new ArrayList( children.size() ); for ( Vertex vertex : children ) { retValue.add( vertex.getLabel() ); } return retValue; } /** * Get the list the most direct ancestors (parents). * * @return list of parents */ public List getParents() { return parents; } /** * Get the labels used by the most direct ancestors (parents). * * @return the labels used parents */ public List getParentLabels() { final List retValue = new ArrayList( parents.size() ); for ( Vertex vertex : parents ) { retValue.add( vertex.getLabel() ); } return retValue; } /** * Indicates if given vertex has no child * * @return true if this vertex has no child, false otherwise */ public boolean isLeaf() { return children.size() == 0; } /** * Indicates if given vertex has no parent * * @return true if this vertex has no parent, false otherwise */ public boolean isRoot() { return parents.size() == 0; } /** * Indicates if there is at least one edee leading to or from given vertex * * @return true if this vertex is connected with other vertex,false otherwise */ public boolean isConnected() { return isRoot() || isLeaf(); } public Object clone() throws CloneNotSupportedException { // this is what's failing.. final Object retValue = super.clone(); return retValue; } public String toString() { return "Vertex{" + "label='" + label + "'" + "}"; } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/introspection/000077500000000000000000000000001251077732300311525ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/introspection/ClassMap.java000066400000000000000000000360061251077732300335250ustar00rootroot00000000000000package org.codehaus.plexus.util.introspection; /* * 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.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Hashtable; import java.util.Map; /** * A cache of introspection information for a specific class instance. * 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 * @author Bob McWhirter * @author Attila Szegedi * @author Geir Magnusson Jr. * @version $Id$ */ public class ClassMap { private static final class CacheMiss { } private static final CacheMiss CACHE_MISS = new CacheMiss(); private static final Object OBJECT = new Object(); /** * Class passed into the constructor used to as * the basis for the Method map. */ private final Class clazz; /** * Cache of Methods, or CACHE_MISS, keyed by method * name and actual arguments used to find it. */ private Map methodCache = new Hashtable(); private final MethodMap methodMap = new MethodMap(); /** * Standard constructor */ public ClassMap( Class clazz ) { this.clazz = clazz; populateMethodCache(); } /** * @return the class object whose methods are cached by this map. */ Class getCachedClass() { return clazz; } /** * Find a Method using the methodKey * provided. *

* Look in the methodMap for an entry. If found, * it'll either be a CACHE_MISS, in which case we * simply give up, or it'll be a Method, in which * case, we return it. *

* If nothing is found, then we must actually go * and introspect the method from the MethodMap. */ public Method findMethod( String name, Object[] params ) throws MethodMap.AmbiguousException { String methodKey = makeMethodKey( name, params ); Object cacheEntry = methodCache.get( methodKey ); if ( cacheEntry == CACHE_MISS ) { return null; } if ( cacheEntry == null ) { try { cacheEntry = methodMap.find( name, params ); } catch ( MethodMap.AmbiguousException ae ) { /* * that's a miss :) */ methodCache.put( methodKey, CACHE_MISS ); throw ae; } if ( cacheEntry == null ) { methodCache.put( methodKey, CACHE_MISS ); } else { methodCache.put( methodKey, cacheEntry ); } } // Yes, this might just be null. return (Method) cacheEntry; } /** * Populate the Map of direct hits. These * are taken from all the public methods * that our class provides. */ private void populateMethodCache() { StringBuffer methodKey; /* * get all publicly accessible methods */ Method[] methods = getAccessibleMethods( clazz ); /* * map and cache them */ for ( Method method : methods ) { /* * now get the 'public method', the method declared by a * public interface or class. (because the actual implementing * class may be a facade... */ Method publicMethod = getPublicMethod( method ); /* * it is entirely possible that there is no public method for * the methods of this class (i.e. in the facade, a method * that isn't on any of the interfaces or superclass * in which case, ignore it. Otherwise, map and cache */ if ( publicMethod != null ) { methodMap.add( publicMethod ); methodCache.put( makeMethodKey( publicMethod ), publicMethod ); } } } /** * Make a methodKey for the given method using * the concatenation of the name and the * types of the method parameters. */ private String makeMethodKey( Method method ) { Class[] parameterTypes = method.getParameterTypes(); StringBuilder methodKey = new StringBuilder( method.getName() ); for ( Class parameterType : parameterTypes ) { /* * If the argument type is primitive then we want * to convert our primitive type signature to the * corresponding Object type so introspection for * methods with primitive types will work correctly. */ if ( parameterType.isPrimitive() ) { if ( parameterType.equals( Boolean.TYPE ) ) { methodKey.append( "java.lang.Boolean" ); } else if ( parameterType.equals( Byte.TYPE ) ) { methodKey.append( "java.lang.Byte" ); } else if ( parameterType.equals( Character.TYPE ) ) { methodKey.append( "java.lang.Character" ); } else if ( parameterType.equals( Double.TYPE ) ) { methodKey.append( "java.lang.Double" ); } else if ( parameterType.equals( Float.TYPE ) ) { methodKey.append( "java.lang.Float" ); } else if ( parameterType.equals( Integer.TYPE ) ) { methodKey.append( "java.lang.Integer" ); } else if ( parameterType.equals( Long.TYPE ) ) { methodKey.append( "java.lang.Long" ); } else if ( parameterType.equals( Short.TYPE ) ) { methodKey.append( "java.lang.Short" ); } } else { methodKey.append( parameterType.getName() ); } } return methodKey.toString(); } private static String makeMethodKey( String method, Object[] params ) { StringBuilder methodKey = new StringBuilder().append( method ); for ( Object param : params ) { Object arg = param; if ( arg == null ) { arg = OBJECT; } methodKey.append( arg.getClass().getName() ); } return methodKey.toString(); } /** * Retrieves public methods for a class. In case the class is not * public, retrieves methods with same signature as its public methods * from public superclasses and interfaces (if they exist). Basically * upcasts every method to the nearest acccessible method. */ private static Method[] getAccessibleMethods( Class clazz ) { Method[] methods = clazz.getMethods(); /* * Short circuit for the (hopefully) majority of cases where the * clazz is public */ if ( Modifier.isPublic( clazz.getModifiers() ) ) { return methods; } /* * No luck - the class is not public, so we're going the longer way. */ MethodInfo[] methodInfos = new MethodInfo[methods.length]; for ( int i = methods.length; i-- > 0; ) { methodInfos[i] = new MethodInfo( methods[i] ); } int upcastCount = getAccessibleMethods( clazz, methodInfos, 0 ); /* * Reallocate array in case some method had no accessible counterpart. */ if ( upcastCount < methods.length ) { methods = new Method[upcastCount]; } int j = 0; for ( MethodInfo methodInfo : methodInfos ) { if ( methodInfo.upcast ) { methods[j++] = methodInfo.method; } } return methods; } /** * Recursively finds a match for each method, starting with the class, and then * searching the superclass and interfaces. * * @param clazz Class to check * @param methodInfos array of methods we are searching to match * @param upcastCount current number of methods we have matched * @return count of matched methods */ private static int getAccessibleMethods( Class clazz, MethodInfo[] methodInfos, int upcastCount ) { int l = methodInfos.length; /* * if this class is public, then check each of the currently * 'non-upcasted' methods to see if we have a match */ if ( Modifier.isPublic( clazz.getModifiers() ) ) { for ( int i = 0; i < l && upcastCount < l; ++i ) { try { MethodInfo methodInfo = methodInfos[i]; if ( !methodInfo.upcast ) { methodInfo.tryUpcasting( clazz ); upcastCount++; } } catch ( NoSuchMethodException e ) { /* * Intentionally ignored - it means * it wasn't found in the current class */ } } /* * Short circuit if all methods were upcast */ if ( upcastCount == l ) { return upcastCount; } } /* * Examine superclass */ Class superclazz = clazz.getSuperclass(); if ( superclazz != null ) { upcastCount = getAccessibleMethods( superclazz, methodInfos, upcastCount ); /* * Short circuit if all methods were upcast */ if ( upcastCount == l ) { return upcastCount; } } /* * Examine interfaces. Note we do it even if superclazz == null. * This is redundant as currently java.lang.Object does not implement * any interfaces, however nothing guarantees it will not in future. */ Class[] interfaces = clazz.getInterfaces(); for ( int i = interfaces.length; i-- > 0; ) { upcastCount = getAccessibleMethods( interfaces[i], methodInfos, upcastCount ); /* * Short circuit if all methods were upcast */ if ( upcastCount == l ) { return upcastCount; } } return upcastCount; } /** * For a given method, retrieves its publicly accessible counterpart. * This method will look for a method with same name * and signature declared in a public superclass or implemented interface of this * method's declaring class. This counterpart method is publicly callable. * * @param method a method whose publicly callable counterpart is requested. * @return the publicly callable counterpart method. Note that if the parameter * method is itself declared by a public class, this method is an identity * function. */ public static Method getPublicMethod( Method method ) { Class clazz = method.getDeclaringClass(); /* * Short circuit for (hopefully the majority of) cases where the declaring * class is public. */ if ( ( clazz.getModifiers() & Modifier.PUBLIC ) != 0 ) { return method; } return getPublicMethod( clazz, method.getName(), method.getParameterTypes() ); } /** * Looks up the method with specified name and signature in the first public * superclass or implemented interface of the class. * * @param clazz the class whose method is sought * @param name the name of the method * @param paramTypes the classes of method parameters */ private static Method getPublicMethod( Class clazz, String name, Class[] paramTypes ) { /* * if this class is public, then try to get it */ if ( ( clazz.getModifiers() & Modifier.PUBLIC ) != 0 ) { try { return clazz.getMethod( name, paramTypes ); } catch ( NoSuchMethodException e ) { /* * If the class does not have the method, then neither its * superclass nor any of its interfaces has it so quickly return * null. */ return null; } } /* * try the superclass */ Class superclazz = clazz.getSuperclass(); if ( superclazz != null ) { Method superclazzMethod = getPublicMethod( superclazz, name, paramTypes ); if ( superclazzMethod != null ) { return superclazzMethod; } } /* * and interfaces */ Class[] interfaces = clazz.getInterfaces(); for ( Class anInterface : interfaces ) { Method interfaceMethod = getPublicMethod( anInterface, name, paramTypes ); if ( interfaceMethod != null ) { return interfaceMethod; } } return null; } /** * Used for the iterative discovery process for public methods. */ private static final class MethodInfo { Method method; String name; Class[] parameterTypes; boolean upcast; MethodInfo( Method method ) { this.method = null; name = method.getName(); parameterTypes = method.getParameterTypes(); upcast = false; } void tryUpcasting( Class clazz ) throws NoSuchMethodException { method = clazz.getMethod( name, parameterTypes ); name = null; parameterTypes = null; upcast = true; } } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/introspection/MethodMap.java000066400000000000000000000351201251077732300336740ustar00rootroot00000000000000package org.codehaus.plexus.util.introspection; /* * 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.lang.reflect.Method; import java.util.ArrayList; import java.util.Hashtable; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; /** * * @author Jason van Zyl * @author Bob McWhirter * @author Christoph Reck * @author Geir Magnusson Jr. * @author Attila Szegedi * @version $Id$ */ public class MethodMap { private static final int MORE_SPECIFIC = 0; private static final int LESS_SPECIFIC = 1; private static final int INCOMPARABLE = 2; /** * Keep track of all methods with the same name. */ 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 ); if ( l == null) { l = new ArrayList(); methodByNameMap.put(methodName, l); } l.add(method); } /** * Return a list of methods with the same name. * * @param key The name of the method. * @return List list of methods */ public List get(String key) { return methodByNameMap.get(key); } /** *

* Find a method. Attempts to find the * most specific applicable method using the * algorithm described in the JLS section * 15.12.2 (with the exception that it can't * distinguish a primitive type argument from * an object type argument, since in reflection * primitive type arguments are represented by * their object counterparts, so for an argument of * type (say) java.lang.Integer, it will not be able * to decide between a method that takes int and a * method that takes java.lang.Integer as a parameter. *

* *

* This turns out to be a relatively rare case * where this is needed - however, functionality * like this is needed. *

* * @param methodName name of method * @param args the actual arguments with which the method is called * @return the most specific applicable method, or null if no * method is applicable. * @throws AmbiguousException if there is more than one maximally * specific applicable method */ public Method find(String methodName, Object[] args) throws AmbiguousException { List methodList = get(methodName); if (methodList == null) { return null; } int l = args.length; Class[] classes = new Class[l]; for(int i = 0; i < l; ++i) { Object arg = args[i]; /* * if we are careful down below, a null argument goes in there * so we can know that the null was passed to the method */ classes[i] = arg == null ? null : arg.getClass(); } return getMostSpecific(methodList, classes); } /** * simple distinguishable exception, used when * we run across ambiguous overloading */ public static class AmbiguousException extends Exception { } private static Method getMostSpecific(List methods, Class[] classes) throws AmbiguousException { LinkedList applicables = getApplicables(methods, classes); if(applicables.isEmpty()) { return null; } if(applicables.size() == 1) { return applicables.getFirst(); } /* * This list will contain the maximally specific methods. Hopefully at * the end of the below loop, the list will contain exactly one method, * (the most specific method) otherwise we have ambiguity. */ LinkedList maximals = new LinkedList(); for ( Method app : applicables ) { Class[] appArgs = app.getParameterTypes(); boolean lessSpecific = false; for ( Iterator maximal = maximals.iterator(); !lessSpecific && maximal.hasNext(); ) { Method max = maximal.next(); switch ( moreSpecific( appArgs, max.getParameterTypes() ) ) { case MORE_SPECIFIC: { /* * This method is more specific than the previously * known maximally specific, so remove the old maximum. */ maximal.remove(); break; } case LESS_SPECIFIC: { /* * This method is less specific than some of the * currently known maximally specific methods, so we * won't add it into the set of maximally specific * methods */ lessSpecific = true; break; } } } if ( !lessSpecific ) { maximals.addLast( app ); } } if(maximals.size() > 1) { // We have more than one maximally specific method throw new AmbiguousException(); } return maximals.getFirst(); } /** * Determines which method signature (represented by a class array) is more * specific. This defines a partial ordering on the method signatures. * @param c1 first signature to compare * @param c2 second signature to compare * @return MORE_SPECIFIC if c1 is more specific than c2, LESS_SPECIFIC if * c1 is less specific than c2, INCOMPARABLE if they are incomparable. */ private static int moreSpecific(Class[] c1, Class[] c2) { boolean c1MoreSpecific = false; boolean c2MoreSpecific = false; for(int i = 0; i < c1.length; ++i) { if(c1[i] != c2[i]) { c1MoreSpecific = c1MoreSpecific || isStrictMethodInvocationConvertible(c2[i], c1[i]); c2MoreSpecific = c2MoreSpecific || isStrictMethodInvocationConvertible(c1[i], c2[i]); } } if(c1MoreSpecific) { if(c2MoreSpecific) { /* * Incomparable due to cross-assignable arguments (i.e. * foo(String, Object) vs. foo(Object, String)) */ return INCOMPARABLE; } return MORE_SPECIFIC; } if(c2MoreSpecific) { return LESS_SPECIFIC; } /* * Incomparable due to non-related arguments (i.e. * foo(Runnable) vs. foo(Serializable)) */ return INCOMPARABLE; } /** * Returns all methods that are applicable to actual argument types. * @param methods list of all candidate methods * @param classes the actual types of the arguments * @return a list that contains only applicable methods (number of * 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) { LinkedList list = new LinkedList(); for ( Object method1 : methods ) { Method method = (Method) method1; if ( isApplicable( method, classes ) ) { list.add( method ); } } return list; } /** * 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) { Class[] methodArgs = method.getParameterTypes(); if(methodArgs.length != classes.length) { return false; } for(int i = 0; i < classes.length; ++i) { if(!isMethodInvocationConvertible(methodArgs[i], classes[i])) { return false; } } return true; } /** * Determines whether a type represented by a class object is * convertible to another type represented by a class object using a * method invocation conversion, treating object types of primitive * types as if they were primitive types (that is, a Boolean actual * parameter type matches boolean primitive formal type). This behavior * is because this method is used to determine applicable methods for * an actual parameter list, and primitive types are represented by * their object duals in reflective method calls. * * @param formal the formal parameter type to which the actual * parameter type should be convertible * @param actual the actual parameter type. * @return true if either formal type is assignable from actual type, * or formal is a primitive type and actual is its corresponding object * type or an object type of a primitive type that can be converted to * the formal type. */ private static boolean isMethodInvocationConvertible(Class formal, Class actual) { /* * if it's a null, it means the arg was null */ if (actual == null && !formal.isPrimitive()) { return true; } /* * Check for identity or widening reference conversion */ if (actual != null && formal.isAssignableFrom(actual)) { return true; } /* * Check for boxing with widening primitive conversion. Note that * actual parameters are never primitives. */ if (formal.isPrimitive()) { if(formal == Boolean.TYPE && actual == Boolean.class) return true; if(formal == Character.TYPE && actual == Character.class) return true; if(formal == Byte.TYPE && actual == Byte.class) return true; if(formal == Short.TYPE && (actual == Short.class || actual == Byte.class)) return true; if(formal == Integer.TYPE && (actual == Integer.class || actual == Short.class || actual == Byte.class)) return true; if(formal == Long.TYPE && (actual == Long.class || actual == Integer.class || actual == Short.class || actual == Byte.class)) return true; if(formal == Float.TYPE && (actual == Float.class || actual == Long.class || actual == Integer.class || actual == Short.class || actual == Byte.class)) return true; if(formal == Double.TYPE && (actual == Double.class || actual == Float.class || actual == Long.class || actual == Integer.class || actual == Short.class || actual == Byte.class)) return true; } return false; } /** * Determines whether a type represented by a class object is * convertible to another type represented by a class object using a * method invocation conversion, without matching object and primitive * types. This method is used to determine the more specific type when * comparing signatures of methods. * * @param formal the formal parameter type to which the actual * parameter type should be convertible * @param actual the actual parameter type. * @return true if either formal type is assignable from actual type, * or formal and actual are both primitive types and actual can be * subject to widening conversion to formal. */ private static boolean isStrictMethodInvocationConvertible(Class formal, Class actual) { /* * we shouldn't get a null into, but if so */ if (actual == null && !formal.isPrimitive()) { return true; } /* * Check for identity or widening reference conversion */ if(formal.isAssignableFrom(actual)) { return true; } /* * Check for widening primitive conversion. */ if(formal.isPrimitive()) { if(formal == Short.TYPE && (actual == Byte.TYPE)) return true; if(formal == Integer.TYPE && (actual == Short.TYPE || actual == Byte.TYPE)) return true; if(formal == Long.TYPE && (actual == Integer.TYPE || actual == Short.TYPE || actual == Byte.TYPE)) return true; if(formal == Float.TYPE && (actual == Long.TYPE || actual == Integer.TYPE || actual == Short.TYPE || actual == Byte.TYPE)) return true; if(formal == Double.TYPE && (actual == Float.TYPE || actual == Long.TYPE || actual == Integer.TYPE || actual == Short.TYPE || actual == Byte.TYPE)) return true; } return false; } } ReflectionValueExtractor.java000066400000000000000000000265151251077732300367320ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/introspectionpackage org.codehaus.plexus.util.introspection; /* * 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.lang.ref.WeakReference; import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; import java.util.Map; 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. *

* * @author Jason van Zyl * @author Vincent Siveton * @version $Id$ * @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 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. */ private static final Map, WeakReference> classMaps = new WeakHashMap, WeakReference>(); static final int EOF = -1; 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. *

*
    *
  • 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"
  • *
      * * @param expression not null expression * @param root not null object * @return the object defined by the expression * @throws Exception if any */ public static Object evaluate( String expression, Object root ) throws Exception { return evaluate( expression, root, true ); } /** *

      * 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"
      • *
          * * @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, final Object root, final boolean trimRootToken ) throws Exception { Object value = root; // ---------------------------------------------------------------------- // Walk the dots and retrieve the ultimate value desired from the // MavenProject instance. // ---------------------------------------------------------------------- if ( StringUtils.isEmpty( expression ) || !Character.isJavaIdentifierStart( expression.charAt( 0 ) ) ) { return null; } boolean hasDots = expression.indexOf( PROPERTY_START ) >= 0; final Tokenizer tokenizer; if ( trimRootToken && hasDots ) { tokenizer = new Tokenizer( expression ); tokenizer.nextPropertyName(); if ( tokenizer.getPosition() == EOF ) { return null; } } else { tokenizer = new Tokenizer( "." + expression ); } int propertyPosition = tokenizer.getPosition(); while ( value != null && tokenizer.peekChar() != EOF ) { switch ( tokenizer.skipChar() ) { 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; } } 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 ); } 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 ); if ( value.getClass().isArray() ) { return Array.get( value, index ); } if ( value instanceof List ) { 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 ); } } catch ( NumberFormatException e ) { return null; } catch ( InvocationTargetException e ) { // catch array index issues gracefully, otherwise release if ( e.getCause() instanceof IndexOutOfBoundsException ) { return null; } 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; } 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 ) { WeakReference softRef = classMaps.get( clazz ); ClassMap classMap; if ( softRef == null || ( classMap = softRef.get() ) == null ) { classMap = new ClassMap( clazz ); classMaps.put( clazz, new WeakReference( classMap ) ); } return classMap; } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/io/000077500000000000000000000000001251077732300266615ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/io/InputStreamFacade.java000066400000000000000000000020751251077732300330670ustar00rootroot00000000000000package org.codehaus.plexus.util.io; /* * 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.IOException; import java.io.InputStream; /** * Interface of a wrapper for input streams. This facade is used * by methods, which are being implemented for files, URL's, or * input streams. */ public interface InputStreamFacade { /** * Retrieves the actual {@link InputStream}. The caller must assume, * that this method may be invoked only once. */ InputStream getInputStream() throws IOException; } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/io/RawInputStreamFacade.java000066400000000000000000000021231251077732300335330ustar00rootroot00000000000000package org.codehaus.plexus.util.io; /* * 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.IOException; import java.io.InputStream; /** * Implementation of {@link InputStreamFacade} for raw input streams. */ @SuppressWarnings( { "UnusedDeclaration" } ) public class RawInputStreamFacade implements InputStreamFacade { final InputStream stream; public RawInputStreamFacade( InputStream stream ) { this.stream = stream; } public InputStream getInputStream() throws IOException { return stream; } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/io/URLInputStreamFacade.java000066400000000000000000000020451251077732300334470ustar00rootroot00000000000000package org.codehaus.plexus.util.io; /* * 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.IOException; import java.io.InputStream; import java.net.URL; /** * Implementation of {@link InputStreamFacade} for URL's. */ public class URLInputStreamFacade implements InputStreamFacade { private final URL url; public URLInputStreamFacade( URL url ) { this.url = url; } public InputStream getInputStream() throws IOException { return url.openStream(); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/reflection/000077500000000000000000000000001251077732300304045ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/reflection/Reflector.java000066400000000000000000000507031251077732300332010ustar00rootroot00000000000000package org.codehaus.plexus.util.reflection; /* * 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.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; /** * Utility class used to instantiate an object using reflection. This utility * hides many of the gory details needed to do this. * * @author John Casey */ public final class Reflector { private static final String CONSTRUCTOR_METHOD_NAME = "$$CONSTRUCTOR$$"; private static final String GET_INSTANCE_METHOD_NAME = "getInstance"; private Map>> classMaps = new HashMap>>(); /** Ensure no instances of Reflector are created...this is a utility. */ public Reflector() { } /** * Create a new instance of a class, given the array of parameters... Uses * constructor caching to find a constructor that matches the parameter * types, either specifically (first choice) or abstractly... * * @param theClass * The class to instantiate * @param params * The parameters to pass to the constructor * @return The instantiated object * @throws ReflectorException * In case anything goes wrong here... */ @SuppressWarnings( { "UnusedDeclaration" } ) public T newInstance( Class theClass, Object[] params ) throws ReflectorException { if ( params == null ) { params = new Object[0]; } Class[] paramTypes = new Class[params.length]; for ( int i = 0, len = params.length; i < len; i++ ) { paramTypes[i] = params[i].getClass(); } try { Constructor con = getConstructor( theClass, paramTypes ); if ( con == null ) { StringBuilder buffer = new StringBuilder(); buffer.append( "Constructor not found for class: " ); buffer.append( theClass.getName() ); buffer.append( " with specified or ancestor parameter classes: " ); for ( Class paramType : paramTypes ) { buffer.append( paramType.getName() ); buffer.append( ',' ); } buffer.setLength( buffer.length() - 1 ); throw new ReflectorException( buffer.toString() ); } return con.newInstance( params ); } catch ( InstantiationException ex ) { throw new ReflectorException( ex ); } catch ( InvocationTargetException ex ) { throw new ReflectorException( ex ); } catch ( IllegalAccessException ex ) { throw new ReflectorException( ex ); } } /** * Retrieve the singleton instance of a class, given the array of * parameters... Uses constructor caching to find a constructor that matches * the parameter types, either specifically (first choice) or abstractly... * * @param theClass * The class to retrieve the singleton of * @param initParams * The parameters to pass to the constructor * @return The singleton object * @throws ReflectorException * In case anything goes wrong here... */ @SuppressWarnings( { "UnusedDeclaration" } ) public T getSingleton( Class theClass, Object[] initParams ) throws ReflectorException { Class[] paramTypes = new Class[initParams.length]; for ( int i = 0, len = initParams.length; i < len; i++ ) { paramTypes[i] = initParams[i].getClass(); } try { Method method = getMethod( theClass, GET_INSTANCE_METHOD_NAME, paramTypes ); //noinspection unchecked return (T) method.invoke( null, initParams ); } catch ( InvocationTargetException ex ) { throw new ReflectorException( ex ); } catch ( IllegalAccessException ex ) { throw new ReflectorException( ex ); } } /** * Invoke the specified method on the specified target with the specified * params... * * @param target * The target of the invocation * @param methodName * The method name to invoke * @param params * The parameters to pass to the method invocation * @return The result of the method call * @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 { if ( params == null ) { params = new Object[0]; } Class[] paramTypes = new Class[params.length]; for ( int i = 0, len = params.length; i < len; i++ ) { paramTypes[i] = params[i].getClass(); } try { Method method = getMethod( target.getClass(), methodName, paramTypes ); if ( method == null ) { StringBuilder buffer = new StringBuilder(); buffer.append( "Singleton-producing method named '" ).append( methodName ) .append( "' not found with specified parameter classes: " ); for ( Class paramType : paramTypes ) { buffer.append( paramType.getName() ); buffer.append( ',' ); } buffer.setLength( buffer.length() - 1 ); throw new ReflectorException( buffer.toString() ); } return method.invoke( target, params ); } catch ( InvocationTargetException ex ) { throw new ReflectorException( ex ); } catch ( IllegalAccessException ex ) { throw new ReflectorException( ex ); } } @SuppressWarnings( { "UnusedDeclaration" } ) public Object getStaticField( Class targetClass, String fieldName ) throws ReflectorException { try { Field field = targetClass.getField( fieldName ); return field.get( null ); } catch ( SecurityException e ) { throw new ReflectorException( e ); } catch ( NoSuchFieldException e ) { throw new ReflectorException( e ); } catch ( IllegalArgumentException e ) { throw new ReflectorException( e ); } catch ( IllegalAccessException e ) { throw new ReflectorException( e ); } } @SuppressWarnings( { "UnusedDeclaration" } ) public Object getField( Object target, String fieldName ) throws ReflectorException { return getField( target, fieldName, false ); } public Object getField( Object target, String fieldName, boolean breakAccessibility ) throws ReflectorException { Class targetClass = target.getClass(); while ( targetClass != null ) { try { Field field = targetClass.getDeclaredField( fieldName ); boolean accessibilityBroken = false; if ( !field.isAccessible() && breakAccessibility ) { field.setAccessible( true ); accessibilityBroken = true; } Object result = field.get( target ); if ( accessibilityBroken ) { field.setAccessible( false ); } return result; } catch ( SecurityException e ) { throw new ReflectorException( e ); } catch ( NoSuchFieldException e ) { if ( targetClass == Object.class ) throw new ReflectorException( e ); targetClass = targetClass.getSuperclass(); } catch ( IllegalAccessException e ) { throw new ReflectorException( e ); } } // Never reached, but needed to satisfy compiler return null; } /** * Invoke the specified static method with the specified params... * * @param targetClass * The target class of the invocation * @param methodName * The method name to invoke * @param params * The parameters to pass to the method invocation * @return The result of the method call * @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 { if ( params == null ) { params = new Object[0]; } Class[] paramTypes = new Class[params.length]; for ( int i = 0, len = params.length; i < len; i++ ) { paramTypes[i] = params[i].getClass(); } try { Method method = getMethod( targetClass, methodName, paramTypes ); if ( method == null ) { StringBuilder buffer = new StringBuilder(); buffer.append( "Singleton-producing method named \'" ) .append( methodName ) .append( "\' not found with specified parameter classes: " ); for ( Class paramType : paramTypes ) { buffer.append( paramType.getName() ); buffer.append( ',' ); } buffer.setLength( buffer.length() - 1 ); throw new ReflectorException( buffer.toString() ); } return method.invoke( null, params ); } catch ( InvocationTargetException ex ) { throw new ReflectorException( ex ); } catch ( IllegalAccessException ex ) { throw new ReflectorException( ex ); } } /** * Return the constructor, checking the cache first and storing in cache if * not already there.. * * @param targetClass * The class to get the constructor from * @param params * The classes of the parameters which the constructor should * match. * @return the Constructor object that matches. * @throws ReflectorException * In case we can't retrieve the proper constructor. */ public Constructor getConstructor( Class targetClass, Class[] params ) throws ReflectorException { Map> constructorMap = getConstructorMap( targetClass ); StringBuilder key = new StringBuilder( 200 ); key.append( "(" ); for ( Class param : params ) { key.append( param.getName() ); key.append( "," ); } if ( params.length > 0 ) { key.setLength( key.length() - 1 ); } key.append( ")" ); Constructor constructor; String paramKey = key.toString(); synchronized ( paramKey.intern() ) { constructor = constructorMap.get( paramKey ); if ( constructor == null ) { @SuppressWarnings( { "unchecked" } ) Constructor[] cands = (Constructor[]) targetClass.getConstructors(); for ( Constructor cand : cands ) { Class[] types = cand.getParameterTypes(); if ( params.length != types.length ) { continue; } for ( int j = 0, len2 = params.length; j < len2; j++ ) { if ( !types[j].isAssignableFrom( params[j] ) ) { continue; } } // we got it, so store it! constructor = cand; constructorMap.put( paramKey, constructor ); } } } if ( constructor == null ) { throw new ReflectorException( "Error retrieving constructor object for: " + targetClass.getName() + paramKey ); } return constructor; } public Object getObjectProperty( Object target, String propertyName ) throws ReflectorException { Object returnValue; if ( propertyName == null || propertyName.trim().length() < 1 ) { throw new ReflectorException( "Cannot retrieve value for empty property." ); } String beanAccessor = "get" + Character.toUpperCase( propertyName.charAt( 0 ) ); if ( propertyName.trim().length() > 1 ) { beanAccessor += propertyName.substring( 1 ).trim(); } Class targetClass = target.getClass(); Class[] emptyParams = {}; Method method = _getMethod( targetClass, beanAccessor, emptyParams ); if ( method == null ) { method = _getMethod( targetClass, propertyName, emptyParams ); } if ( method != null ) { try { returnValue = method.invoke( target, new Object[] {} ); } catch ( IllegalAccessException e ) { throw new ReflectorException( "Error retrieving property \'" + propertyName + "\' from \'" + targetClass + "\'", e ); } catch ( InvocationTargetException e ) { throw new ReflectorException( "Error retrieving property \'" + propertyName + "\' from \'" + targetClass + "\'", e ); } } if ( method != null ) { try { returnValue = method.invoke( target, new Object[] {} ); } catch ( IllegalAccessException e ) { throw new ReflectorException( "Error retrieving property \'" + propertyName + "\' from \'" + targetClass + "\'", e ); } catch ( InvocationTargetException e ) { throw new ReflectorException( "Error retrieving property \'" + propertyName + "\' from \'" + targetClass + "\'", e ); } } else { returnValue = getField( target, propertyName, true ); 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: \'" + beanAccessor + "\' can be found for class: \'" + targetClass + "\', and retrieval of field: \'" + propertyName + "\' returned null as value." ); } } return returnValue; } /** * Return the method, checking the cache first and storing in cache if not * already there.. * * @param targetClass * The class to get the method from * @param params * The classes of the parameters which the method should match. * @return the Method object that matches. * @throws ReflectorException * In case we can't retrieve the proper method. */ public Method getMethod( Class targetClass, String methodName, Class[] params ) throws ReflectorException { Method method = _getMethod( targetClass, methodName, params ); if ( method == null ) { throw new ReflectorException( "Method: \'" + methodName + "\' not found in class: \'" + targetClass + "\'" ); } return method; } private Method _getMethod( Class targetClass, String methodName, Class[] params ) throws ReflectorException { Map methodMap = (Map) getMethodMap( targetClass, methodName ); StringBuilder key = new StringBuilder( 200 ); key.append( "(" ); for ( Class param : params ) { key.append( param.getName() ); key.append( "," ); } key.append( ")" ); Method method; String paramKey = key.toString(); synchronized ( paramKey.intern() ) { method = (Method) methodMap.get( paramKey ); if ( method == null ) { Method[] cands = targetClass.getMethods(); for ( Method cand : cands ) { String name = cand.getName(); if ( !methodName.equals( name ) ) { continue; } Class[] types = cand.getParameterTypes(); if ( params.length != types.length ) { continue; } for ( int j = 0, len2 = params.length; j < len2; j++ ) { if ( !types[j].isAssignableFrom( params[j] ) ) { continue; } } // we got it, so store it! method = cand; methodMap.put( paramKey, method ); } } } return method; } /** * Retrieve the cache of constructors for the specified class. * * @param theClass * the class to lookup. * @return The cache of constructors. * @throws ReflectorException * in case of a lookup error. */ private Map> getConstructorMap( Class theClass ) throws ReflectorException { return (Map>) getMethodMap( theClass, CONSTRUCTOR_METHOD_NAME ); } /** * Retrieve the cache of methods for the specified class and method name. * * @param theClass * the class to lookup. * @param methodName * The name of the method to lookup. * @return The cache of constructors. * @throws ReflectorException * in case of a lookup error. */ private Map getMethodMap( Class theClass, String methodName ) throws ReflectorException { Map methodMap; if ( theClass == null ) { return null; } String className = theClass.getName(); synchronized ( className.intern() ) { Map> classMethods = classMaps.get( className ); if ( classMethods == null ) { classMethods = new HashMap>(); methodMap = new HashMap(); classMethods.put( methodName, methodMap ); classMaps.put( className, classMethods ); } else { String key = className + "::" + methodName; synchronized ( key.intern() ) { methodMap = classMethods.get( methodName ); if ( methodMap == null ) { methodMap = new HashMap(); classMethods.put( methodName, methodMap ); } } } } return methodMap; } }ReflectorException.java000066400000000000000000000034551251077732300350030ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/reflectionpackage org.codehaus.plexus.util.reflection; /* * 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. */ /** * Exception indicating that an error has occurred while instantiating a class * with the Reflector class. This exception is meant to put a more user-friendly * face on the myriad other exceptions throws during reflective object creation. * * @author John Casey */ public class ReflectorException extends Exception { @SuppressWarnings( { "UnusedDeclaration" } ) public ReflectorException() { } /** * Create a new ReflectorException with the specified message. * * @param msg * The message. */ public ReflectorException( String msg ) { super( msg ); } /** * Create a new ReflectorException with the specified root cause. * * @param root * The root cause. */ public ReflectorException( Throwable root ) { super( root ); } /** * Create a new ReflectorException with the specified message and root * cause. * * @param msg * The message. * @param root * The root cause. */ public ReflectorException( String msg, Throwable root ) { super( msg, root ); } }plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/xml/000077500000000000000000000000001251077732300270525ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/xml/CompactXMLWriter.java000066400000000000000000000020521251077732300330600ustar00rootroot00000000000000package org.codehaus.plexus.util.xml; /* * 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.PrintWriter; import java.io.Writer; /** * @version $Id$ */ public class CompactXMLWriter extends PrettyPrintXMLWriter { public CompactXMLWriter( PrintWriter writer ) { super( writer ); } public CompactXMLWriter( Writer writer ) { super( writer ); } protected void endOfLine() { // override parent: don't write anything at end of line } } PrettyPrintXMLWriter.java000066400000000000000000000266431251077732300337330ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/xmlpackage org.codehaus.plexus.util.xml; /* * 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.PrintWriter; import java.io.Writer; import java.util.LinkedList; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.codehaus.plexus.util.StringUtils; /** * Implementation of XMLWriter which emits nicely formatted documents. * * @version $Id$ */ public class PrettyPrintXMLWriter implements XMLWriter { /** Line separator ("\n" on UNIX) */ protected static final String LS = System.getProperty( "line.separator" ); private PrintWriter writer; private LinkedList elementStack = new LinkedList(); private boolean tagInProgress; private int depth; private String lineIndenter; private String lineSeparator; private String encoding; private String docType; private boolean readyForNewLine; private boolean tagIsEmpty; /** * @param writer not null * @param lineIndenter could be null, but the normal way is some spaces. */ public PrettyPrintXMLWriter( PrintWriter writer, String lineIndenter ) { this( writer, lineIndenter, null, null ); } /** * @param writer not null * @param lineIndenter could be null, but the normal way is some spaces. */ public PrettyPrintXMLWriter( Writer writer, String lineIndenter ) { this( new PrintWriter( writer ), lineIndenter ); } /** * @param writer not null */ public PrettyPrintXMLWriter( PrintWriter writer ) { this( writer, null, null ); } /** * @param writer not null */ public PrettyPrintXMLWriter( Writer writer ) { this( new PrintWriter( writer ) ); } /** * @param writer not null * @param lineIndenter could be null, but the normal way is some spaces. * @param encoding could be null or invalid. * @param doctype could be null. */ public PrettyPrintXMLWriter( PrintWriter writer, String lineIndenter, String encoding, String doctype ) { this( writer, lineIndenter, LS, encoding, doctype ); } /** * @param writer not null * @param lineIndenter could be null, but the normal way is some spaces. * @param encoding could be null or invalid. * @param doctype could be null. */ public PrettyPrintXMLWriter( Writer writer, String lineIndenter, String encoding, String doctype ) { this( new PrintWriter( writer ), lineIndenter, encoding, doctype ); } /** * @param writer not null * @param encoding could be null or invalid. * @param doctype could be null. */ public PrettyPrintXMLWriter( PrintWriter writer, String encoding, String doctype ) { this( writer, " ", encoding, doctype ); } /** * @param writer not null * @param encoding could be null or invalid. * @param doctype could be null. */ public PrettyPrintXMLWriter( Writer writer, String encoding, String doctype ) { this( new PrintWriter( writer ), encoding, doctype ); } /** * @param writer not null * @param lineIndenter could be null, but the normal way is some spaces. * @param lineSeparator could be null, but the normal way is valid line separator ("\n" on UNIX). * @param encoding could be null or invalid. * @param doctype could be null. */ public PrettyPrintXMLWriter( PrintWriter writer, String lineIndenter, String lineSeparator, String encoding, String doctype ) { setWriter( writer ); setLineIndenter( lineIndenter ); setLineSeparator( lineSeparator ); setEncoding( encoding ); setDocType( doctype ); if ( doctype != null || encoding != null ) { writeDocumentHeaders(); } } /** {@inheritDoc} */ public void startElement( String name ) { tagIsEmpty = false; finishTag(); write( "<" ); write( name ); elementStack.addLast( name ); tagInProgress = true; setDepth( getDepth() + 1 ); readyForNewLine = true; tagIsEmpty = true; } /** {@inheritDoc} */ public void writeText( String text ) { writeText( text, true ); } /** {@inheritDoc} */ public void writeMarkup( String text ) { writeText( text, false ); } private void writeText( String text, boolean escapeXml ) { readyForNewLine = false; tagIsEmpty = false; finishTag(); if ( escapeXml ) { text = escapeXml( text ); } 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 ) { 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( "'" ); } return text; } private static final String crlf_str = "\r\n"; private static final Pattern crlf = Pattern.compile( crlf_str ); private static final Pattern lowers = Pattern.compile( "([\000-\037])" ); private static String escapeXmlAttribute( String text ) { text = escapeXml( text ); // Windows Matcher crlfmatcher = crlf.matcher( text ); if (text.contains( crlf_str )) { text = crlfmatcher.replaceAll( " " ); } Matcher m = lowers.matcher( text ); StringBuffer b = new StringBuffer(); while ( m.find() ) { m = m.appendReplacement( b, "&#" + Integer.toString( m.group( 1 ).charAt( 0 ) ) + ";" ); } m.appendTail( b ); return b.toString(); } /** {@inheritDoc} */ public void addAttribute( String key, String value ) { write( " " ); write( key ); write( "=\"" ); write( escapeXmlAttribute( value ) ); write( "\"" ); } /** {@inheritDoc} */ public void endElement() { setDepth( getDepth() - 1 ); if ( tagIsEmpty ) { write( "/" ); readyForNewLine = false; finishTag(); elementStack.removeLast(); } else { finishTag(); write( "" ); } readyForNewLine = true; } /** * Write a string to the underlying writer * @param str */ private void write( String str ) { getWriter().write( str ); } private void finishTag() { if ( tagInProgress ) { write( ">" ); } tagInProgress = false; if ( readyForNewLine ) { endOfLine(); } readyForNewLine = false; tagIsEmpty = false; } /** * Get the string used as line indenter * * @return the line indenter */ protected String getLineIndenter() { return lineIndenter; } /** * Set the string used as line indenter * * @param lineIndenter new line indenter, could be null, but the normal way is some spaces. */ protected void setLineIndenter( String lineIndenter ) { this.lineIndenter = lineIndenter; } /** * Get the string used as line separator or LS if not set. * * @return the line separator * @see #LS */ protected String getLineSeparator() { return lineSeparator; } /** * Set the string used as line separator * * @param lineSeparator new line separator, could be null but the normal way is valid line separator * ("\n" on UNIX). */ protected void setLineSeparator( String lineSeparator ) { this.lineSeparator = lineSeparator; } /** * Write the end of line character (using specified line separator) * and start new line with indentation * * @see #getLineIndenter() * @see #getLineSeparator() */ protected void endOfLine() { write( getLineSeparator() ); for ( int i = 0; i < getDepth(); i++ ) { write( getLineIndenter() ); } } private void writeDocumentHeaders() { write( "" ); endOfLine(); if ( getDocType() != null ) { write( "" ); endOfLine(); } } /** * Set the underlying writer * * @param writer not null writer */ protected void setWriter( PrintWriter writer ) { if ( writer == null ) { throw new IllegalArgumentException( "writer could not be null"); } this.writer = writer; } /** * Get the underlying writer * * @return the underlying writer */ protected PrintWriter getWriter() { return writer; } /** * Set the depth in the xml indentation * * @param depth new depth */ protected void setDepth( int depth ) { this.depth = depth; } /** * Get the current depth in the xml indentation * * @return the current depth */ protected int getDepth() { return depth; } /** * Set the encoding in the xml * * @param encoding new encoding */ protected void setEncoding( String encoding ) { this.encoding = encoding; } /** * Get the current encoding in the xml * * @return the current encoding */ protected String getEncoding() { return encoding; } /** * Set the docType in the xml * * @param docType new docType */ protected void setDocType( String docType ) { this.docType = docType; } /** * Get the docType in the xml * * @return the current docType */ protected String getDocType() { return docType; } /** * @return the current elementStack; */ protected LinkedList getElementStack() { return elementStack; } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/xml/SerializerXMLWriter.java000066400000000000000000000056031251077732300336100ustar00rootroot00000000000000package org.codehaus.plexus.util.xml; /* * 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 org.codehaus.plexus.util.xml.pull.XmlSerializer; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Stack; /** * Write to an MXSerializer. * * @author Brett Porter * @version $Id$ */ public class SerializerXMLWriter implements XMLWriter { private final XmlSerializer serializer; private final String namespace; private final Stack elements = new Stack(); private List exceptions; public SerializerXMLWriter( String namespace, XmlSerializer serializer ) { this.serializer = serializer; this.namespace = namespace; } public void startElement( String name ) { try { serializer.startTag( namespace, name ); elements.push( name ); } catch ( IOException e ) { storeException( e ); } } public void addAttribute( String key, String value ) { try { serializer.attribute( namespace, key, value ); } catch ( IOException e ) { storeException( e ); } } public void writeText( String text ) { try { serializer.text( text ); } catch ( IOException e ) { storeException( e ); } } public void writeMarkup( String text ) { try { serializer.cdsect( text ); } catch ( IOException e ) { storeException( e ); } } public void endElement() { try { serializer.endTag( namespace, (String) elements.pop() ); } catch ( IOException e ) { storeException( e ); } } /** * @todo Maybe the interface should allow IOExceptions on each? */ private void storeException( IOException e ) { if ( exceptions == null ) { exceptions = new ArrayList(); } exceptions.add( e ); } public List getExceptions() { return exceptions == null ? Collections.emptyList() : exceptions; } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/xml/XMLWriter.java000066400000000000000000000015701251077732300315550ustar00rootroot00000000000000package org.codehaus.plexus.util.xml; /* * 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. */ /** * @version $Id$ */ public interface XMLWriter { void startElement( String name ); void addAttribute( String key, String value ); void writeText( String text ); void writeMarkup( String text ); void endElement(); } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/xml/XmlReader.java000066400000000000000000000706231251077732300316100ustar00rootroot00000000000000/* * Copyright 2004 Sun Microsystems, Inc. * * 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. * */ package org.codehaus.plexus.util.xml; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; import java.net.URL; import java.net.URLConnection; import java.net.HttpURLConnection; import java.util.Locale; import java.util.regex.Pattern; import java.util.regex.Matcher; import java.text.MessageFormat; /** * Character stream that handles (or at least attemtps to) all the necessary Voodo to figure out the charset encoding of * the XML document within the stream. *

          * IMPORTANT: This class is not related in any way to the org.xml.sax.XMLReader. This one IS a character stream. *

          * All this has to be done without consuming characters from the stream, if not the XML parser will not recognized the * document as a valid XML. This is not 100% true, but it's close enough (UTF-8 BOM is not handled by all parsers right * now, XmlReader handles it and things work in all parsers). *

          * The XmlReader class handles the charset encoding of XML documents in Files, raw streams and HTTP streams by offering * a wide set of constructors. *

          * By default the charset encoding detection is lenient, the constructor with the lenient flag can be used for an script * (following HTTP MIME and XML specifications). All this is nicely explained by Mark Pilgrim in his blog, Determining the character encoding of a feed. *

          * * @author Alejandro Abdelnur * @version revision 1.17 taken on 26/06/2007 from Rome (see https://rome.dev.java.net/source/browse/rome/src/java/com/sun/syndication/io/XmlReader.java) * @deprecated use XmlStreamReader * @since 1.4.3 */ public class XmlReader extends Reader { private static final int BUFFER_SIZE = 4096; private static final String UTF_8 = "UTF-8"; private static final String US_ASCII = "US-ASCII"; private static final String UTF_16BE = "UTF-16BE"; private static final String UTF_16LE = "UTF-16LE"; private static final String UTF_16 = "UTF-16"; private static final String EBCDIC = "CP1047"; private static String _staticDefaultEncoding = null; private Reader _reader; private String _encoding; private String _defaultEncoding; /** * Sets the default encoding to use if none is set in HTTP content-type, XML prolog and the rules based on * content-type are not adequate.

          If it is set to NULL the content-type based rules are used.

          By default * it is NULL.

          * * @param encoding * charset encoding to default to. */ public static void setDefaultEncoding( String encoding ) { _staticDefaultEncoding = encoding; } /** * Returns the default encoding to use if none is set in HTTP content-type, XML prolog and the rules based on * content-type are not adequate.

          If it is NULL the content-type based rules are used.

          * * @return the default encoding to use. */ public static String getDefaultEncoding() { return _staticDefaultEncoding; } /** * Creates a Reader for a File. *

          * It looks for the UTF-8 BOM first, if none sniffs the XML prolog charset, if this is also missing defaults to * UTF-8. *

          * It does a lenient charset encoding detection, check the constructor with the lenient parameter for details. *

          * * @param file * File to create a Reader from. * @throws IOException * thrown if there is a problem reading the file. * */ public XmlReader( File file ) throws IOException { this( new FileInputStream( file ) ); } /** * Creates a Reader for a raw InputStream. *

          * It follows the same logic used for files. *

          * It does a lenient charset encoding detection, check the constructor with the lenient parameter for details. *

          * * @param is * InputStream to create a Reader from. * @throws IOException * thrown if there is a problem reading the stream. * */ public XmlReader( InputStream is ) throws IOException { this( is, true ); } /** * Creates a Reader for a raw InputStream. *

          * It follows the same logic used for files. *

          * If lenient detection is indicated and the detection above fails as per specifications it then attempts the * following: *

          * If the content type was 'text/html' it replaces it with 'text/xml' and tries the detection again. *

          * Else if the XML prolog had a charset encoding that encoding is used. *

          * Else if the content type had a charset encoding that encoding is used. *

          * Else 'UTF-8' is used. *

          * If lenient detection is indicated an XmlStreamReaderException is never thrown. *

          * * @param is * InputStream to create a Reader from. * @param lenient * indicates if the charset encoding detection should be relaxed. * @throws IOException * thrown if there is a problem reading the stream. * @throws XmlStreamReaderException * thrown if the charset encoding could not be determined according to the specs. * */ public XmlReader( InputStream is, boolean lenient ) throws IOException, XmlStreamReaderException { _defaultEncoding = _staticDefaultEncoding; try { doRawStream( is, lenient ); } catch ( XmlStreamReaderException ex ) { if ( !lenient ) { throw ex; } else { doLenientDetection( null, ex ); } } } /** * Creates a Reader using the InputStream of a URL. *

          * If the URL is not of type HTTP and there is not 'content-type' header in the fetched data it uses the same logic * used for Files. *

          * If the URL is a HTTP Url or there is a 'content-type' header in the fetched data it uses the same logic used for * an InputStream with content-type. *

          * It does a lenient charset encoding detection, check the constructor with the lenient parameter for details. *

          * * @param url * URL to create a Reader from. * @throws IOException * thrown if there is a problem reading the stream of the URL. * */ public XmlReader( URL url ) throws IOException { this( url.openConnection() ); } /** * Creates a Reader using the InputStream of a URLConnection. *

          * If the URLConnection is not of type HttpURLConnection and there is not 'content-type' header in the fetched data * it uses the same logic used for files. *

          * If the URLConnection is a HTTP Url or there is a 'content-type' header in the fetched data it uses the same logic * used for an InputStream with content-type. *

          * It does a lenient charset encoding detection, check the constructor with the lenient parameter for details. *

          * * @param conn * URLConnection to create a Reader from. * @throws IOException * thrown if there is a problem reading the stream of the URLConnection. * */ public XmlReader( URLConnection conn ) throws IOException { _defaultEncoding = _staticDefaultEncoding; boolean lenient = true; if ( conn instanceof HttpURLConnection ) { try { doHttpStream( conn.getInputStream(), conn.getContentType(), lenient ); } catch ( XmlStreamReaderException ex ) { doLenientDetection( conn.getContentType(), ex ); } } else if ( conn.getContentType() != null ) { try { doHttpStream( conn.getInputStream(), conn.getContentType(), lenient ); } catch ( XmlStreamReaderException ex ) { doLenientDetection( conn.getContentType(), ex ); } } else { try { doRawStream( conn.getInputStream(), lenient ); } catch ( XmlStreamReaderException ex ) { doLenientDetection( null, ex ); } } } /** * Creates a Reader using an InputStream an the associated content-type header. *

          * First it checks if the stream has BOM. If there is not BOM checks the content-type encoding. If there is not * content-type encoding checks the XML prolog encoding. If there is not XML prolog encoding uses the default * encoding mandated by the content-type MIME type. *

          * It does a lenient charset encoding detection, check the constructor with the lenient parameter for details. *

          * * @param is * InputStream to create the reader from. * @param httpContentType * content-type header to use for the resolution of the charset encoding. * @throws IOException * thrown if there is a problem reading the file. * */ public XmlReader( InputStream is, String httpContentType ) throws IOException { this( is, httpContentType, true ); } /** * Creates a Reader using an InputStream an the associated content-type header. This constructor is lenient * regarding the encoding detection. *

          * First it checks if the stream has BOM. If there is not BOM checks the content-type encoding. If there is not * content-type encoding checks the XML prolog encoding. If there is not XML prolog encoding uses the default * encoding mandated by the content-type MIME type. *

          * If lenient detection is indicated and the detection above fails as per specifications it then attempts the * following: *

          * If the content type was 'text/html' it replaces it with 'text/xml' and tries the detection again. *

          * Else if the XML prolog had a charset encoding that encoding is used. *

          * Else if the content type had a charset encoding that encoding is used. *

          * Else 'UTF-8' is used. *

          * If lenient detection is indicated an XmlStreamReaderException is never thrown. *

          * * @param is * InputStream to create the reader from. * @param httpContentType * content-type header to use for the resolution of the charset encoding. * @param lenient * indicates if the charset encoding detection should be relaxed. * @throws IOException * thrown if there is a problem reading the file. * @throws XmlStreamReaderException * thrown if the charset encoding could not be determined according to the specs. * */ public XmlReader( InputStream is, String httpContentType, boolean lenient, String defaultEncoding ) throws IOException, XmlStreamReaderException { _defaultEncoding = ( defaultEncoding == null ) ? _staticDefaultEncoding : defaultEncoding; try { doHttpStream( is, httpContentType, lenient ); } catch ( XmlStreamReaderException ex ) { if ( !lenient ) { throw ex; } else { doLenientDetection( httpContentType, ex ); } } } /** * Creates a Reader using an InputStream an the associated content-type header. This constructor is lenient * regarding the encoding detection. *

          * First it checks if the stream has BOM. If there is not BOM checks the content-type encoding. If there is not * content-type encoding checks the XML prolog encoding. If there is not XML prolog encoding uses the default * encoding mandated by the content-type MIME type. *

          * If lenient detection is indicated and the detection above fails as per specifications it then attempts the * following: *

          * If the content type was 'text/html' it replaces it with 'text/xml' and tries the detection again. *

          * Else if the XML prolog had a charset encoding that encoding is used. *

          * Else if the content type had a charset encoding that encoding is used. *

          * Else 'UTF-8' is used. *

          * If lenient detection is indicated an XmlStreamReaderException is never thrown. *

          * * @param is * InputStream to create the reader from. * @param httpContentType * content-type header to use for the resolution of the charset encoding. * @param lenient * indicates if the charset encoding detection should be relaxed. * @throws IOException * thrown if there is a problem reading the file. * @throws XmlStreamReaderException * thrown if the charset encoding could not be determined according to the specs. * */ public XmlReader( InputStream is, String httpContentType, boolean lenient ) throws IOException, XmlStreamReaderException { this( is, httpContentType, lenient, null ); } private void doLenientDetection( String httpContentType, XmlStreamReaderException ex ) throws IOException { if ( httpContentType != null ) { if ( httpContentType.startsWith( "text/html" ) ) { httpContentType = httpContentType.substring( "text/html".length() ); httpContentType = "text/xml" + httpContentType; try { doHttpStream( ex.getInputStream(), httpContentType, true ); ex = null; } catch ( XmlStreamReaderException ex2 ) { ex = ex2; } } } if ( ex != null ) { String encoding = ex.getXmlEncoding(); if ( encoding == null ) { encoding = ex.getContentTypeEncoding(); } if ( encoding == null ) { encoding = ( _defaultEncoding == null ) ? UTF_8 : _defaultEncoding; } prepareReader( ex.getInputStream(), encoding ); } } /** * Returns the charset encoding of the XmlReader. *

          * * @return charset encoding. * */ public String getEncoding() { return _encoding; } public int read( char[] buf, int offset, int len ) throws IOException { return _reader.read( buf, offset, len ); } /** * Closes the XmlReader stream. *

          * * @throws IOException * thrown if there was a problem closing the stream. * */ public void close() throws IOException { _reader.close(); } private void doRawStream( InputStream is, boolean lenient ) throws IOException { BufferedInputStream pis = new BufferedInputStream( is, BUFFER_SIZE ); String bomEnc = getBOMEncoding( pis ); String xmlGuessEnc = getXMLGuessEncoding( pis ); String xmlEnc = getXmlProlog( pis, xmlGuessEnc ); String encoding = calculateRawEncoding( bomEnc, xmlGuessEnc, xmlEnc, pis ); prepareReader( pis, encoding ); } private void doHttpStream( InputStream is, String httpContentType, boolean lenient ) throws IOException { BufferedInputStream pis = new BufferedInputStream( is, BUFFER_SIZE ); String cTMime = getContentTypeMime( httpContentType ); String cTEnc = getContentTypeEncoding( httpContentType ); String bomEnc = getBOMEncoding( pis ); String xmlGuessEnc = getXMLGuessEncoding( pis ); String xmlEnc = getXmlProlog( pis, xmlGuessEnc ); String encoding = calculateHttpEncoding( cTMime, cTEnc, bomEnc, xmlGuessEnc, xmlEnc, pis, lenient ); prepareReader( pis, encoding ); } private void prepareReader( InputStream is, String encoding ) throws IOException { _reader = new InputStreamReader( is, encoding ); _encoding = encoding; } // InputStream is passed for XmlStreamReaderException creation only private String calculateRawEncoding( String bomEnc, String xmlGuessEnc, String xmlEnc, InputStream is ) throws IOException { String encoding; if ( bomEnc == null ) { if ( xmlGuessEnc == null || xmlEnc == null ) { encoding = ( _defaultEncoding == null ) ? UTF_8 : _defaultEncoding; } else if ( xmlEnc.equals( UTF_16 ) && ( xmlGuessEnc.equals( UTF_16BE ) || xmlGuessEnc.equals( UTF_16LE ) ) ) { encoding = xmlGuessEnc; } else { encoding = xmlEnc; } } else if ( bomEnc.equals( UTF_8 ) ) { if ( xmlGuessEnc != null && !xmlGuessEnc.equals( UTF_8 ) ) { throw new XmlStreamReaderException( RAW_EX_1.format( new Object[] { bomEnc, xmlGuessEnc, xmlEnc } ), bomEnc, xmlGuessEnc, xmlEnc, is ); } if ( xmlEnc != null && !xmlEnc.equals( UTF_8 ) ) { throw new XmlStreamReaderException( RAW_EX_1.format( new Object[] { bomEnc, xmlGuessEnc, xmlEnc } ), bomEnc, xmlGuessEnc, xmlEnc, is ); } encoding = UTF_8; } else if ( bomEnc.equals( UTF_16BE ) || bomEnc.equals( UTF_16LE ) ) { if ( xmlGuessEnc != null && !xmlGuessEnc.equals( bomEnc ) ) { throw new IOException( RAW_EX_1.format( new Object[] { bomEnc, xmlGuessEnc, xmlEnc } ) ); } if ( xmlEnc != null && !xmlEnc.equals( UTF_16 ) && !xmlEnc.equals( bomEnc ) ) { throw new XmlStreamReaderException( RAW_EX_1.format( new Object[] { bomEnc, xmlGuessEnc, xmlEnc } ), bomEnc, xmlGuessEnc, xmlEnc, is ); } encoding = bomEnc; } else { throw new XmlStreamReaderException( RAW_EX_2.format( new Object[] { bomEnc, xmlGuessEnc, xmlEnc } ), bomEnc, xmlGuessEnc, xmlEnc, is ); } return encoding; } // InputStream is passed for XmlStreamReaderException creation only private String calculateHttpEncoding( String cTMime, String cTEnc, String bomEnc, String xmlGuessEnc, String xmlEnc, InputStream is, boolean lenient ) throws IOException { String encoding; if ( lenient & xmlEnc != null ) { encoding = xmlEnc; } else { boolean appXml = isAppXml( cTMime ); boolean textXml = isTextXml( cTMime ); if ( appXml || textXml ) { if ( cTEnc == null ) { if ( appXml ) { encoding = calculateRawEncoding( bomEnc, xmlGuessEnc, xmlEnc, is ); } else { encoding = ( _defaultEncoding == null ) ? US_ASCII : _defaultEncoding; } } else if ( bomEnc != null && ( cTEnc.equals( UTF_16BE ) || cTEnc.equals( UTF_16LE ) ) ) { throw new XmlStreamReaderException( HTTP_EX_1.format( new Object[] { cTMime, cTEnc, bomEnc, xmlGuessEnc, xmlEnc } ), cTMime, cTEnc, bomEnc, xmlGuessEnc, xmlEnc, is ); } else if ( cTEnc.equals( UTF_16 ) ) { if ( bomEnc != null && bomEnc.startsWith( UTF_16 ) ) { encoding = bomEnc; } else { throw new XmlStreamReaderException( HTTP_EX_2.format( new Object[] { cTMime, cTEnc, bomEnc, xmlGuessEnc, xmlEnc } ), cTMime, cTEnc, bomEnc, xmlGuessEnc, xmlEnc, is ); } } else { encoding = cTEnc; } } else { throw new XmlStreamReaderException( HTTP_EX_3.format( new Object[] { cTMime, cTEnc, bomEnc, xmlGuessEnc, xmlEnc } ), cTMime, cTEnc, bomEnc, xmlGuessEnc, xmlEnc, is ); } } return encoding; } // returns MIME type or NULL if httpContentType is NULL private static String getContentTypeMime( String httpContentType ) { String mime = null; if ( httpContentType != null ) { int i = httpContentType.indexOf( ";" ); mime = ( ( i == -1 ) ? httpContentType : httpContentType.substring( 0, i ) ).trim(); } return mime; } private static final Pattern CHARSET_PATTERN = Pattern.compile( "charset=([.[^; ]]*)" ); // returns charset parameter value, NULL if not present, NULL if httpContentType is NULL private static String getContentTypeEncoding( String httpContentType ) { String encoding = null; if ( httpContentType != null ) { int i = httpContentType.indexOf( ";" ); if ( i > -1 ) { String postMime = httpContentType.substring( i + 1 ); Matcher m = CHARSET_PATTERN.matcher( postMime ); encoding = ( m.find() ) ? m.group( 1 ) : null; encoding = ( encoding != null ) ? encoding.toUpperCase( Locale.ENGLISH ) : null; } } return encoding; } // returns the BOM in the stream, NULL if not present, // if there was BOM the in the stream it is consumed private static String getBOMEncoding( BufferedInputStream is ) throws IOException { String encoding = null; int[] bytes = new int[3]; is.mark( 3 ); bytes[0] = is.read(); bytes[1] = is.read(); bytes[2] = is.read(); if ( bytes[0] == 0xFE && bytes[1] == 0xFF ) { encoding = UTF_16BE; is.reset(); is.read(); is.read(); } else if ( bytes[0] == 0xFF && bytes[1] == 0xFE ) { encoding = UTF_16LE; is.reset(); is.read(); is.read(); } else if ( bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF ) { encoding = UTF_8; } else { is.reset(); } return encoding; } // returns the best guess for the encoding by looking the first bytes of the stream, ', NULL if none private static String getXmlProlog( BufferedInputStream is, String guessedEnc ) throws IOException { String encoding = null; if ( guessedEnc != null ) { byte[] bytes = new byte[BUFFER_SIZE]; is.mark( BUFFER_SIZE ); int offset = 0; int max = BUFFER_SIZE; int c = is.read( bytes, offset, max ); int firstGT = -1; String xmlProlog = null; while ( c != -1 && firstGT == -1 && offset < BUFFER_SIZE ) { offset += c; max -= c; c = is.read( bytes, offset, max ); xmlProlog = new String( bytes, 0, offset, guessedEnc ); firstGT = xmlProlog.indexOf( '>' ); } if ( firstGT == -1 ) { if ( c == -1 ) { throw new IOException( "Unexpected end of XML stream" ); } else { throw new IOException( "XML prolog or ROOT element not found on first " + offset + " bytes" ); } } int bytesRead = offset; if ( bytesRead > 0 ) { is.reset(); BufferedReader bReader = new BufferedReader( new StringReader( xmlProlog.substring( 0, firstGT + 1 ) ) ); StringBuilder prolog = new StringBuilder(); String line = bReader.readLine(); while ( line != null ) { prolog.append( line ); line = bReader.readLine(); } Matcher m = ENCODING_PATTERN.matcher( prolog ); if ( m.find() ) { encoding = m.group( 1 ).toUpperCase( Locale.ENGLISH ); encoding = encoding.substring( 1, encoding.length() - 1 ); } } } return encoding; } // indicates if the MIME type belongs to the APPLICATION XML family private static boolean isAppXml( String mime ) { return mime != null && ( mime.equals( "application/xml" ) || mime.equals( "application/xml-dtd" ) || mime.equals( "application/xml-external-parsed-entity" ) || ( mime.startsWith( "application/" ) && mime.endsWith( "+xml" ) ) ); } // indicates if the MIME type belongs to the TEXT XML family private static boolean isTextXml( String mime ) { return mime != null && ( mime.equals( "text/xml" ) || mime.equals( "text/xml-external-parsed-entity" ) || ( mime.startsWith( "text/" ) && mime.endsWith( "+xml" ) ) ); } private static final MessageFormat RAW_EX_1 = new MessageFormat( "Invalid encoding, BOM [{0}] XML guess [{1}] XML prolog [{2}] encoding mismatch" ); private static final MessageFormat RAW_EX_2 = new MessageFormat( "Invalid encoding, BOM [{0}] XML guess [{1}] XML prolog [{2}] unknown BOM" ); private static final MessageFormat HTTP_EX_1 = new MessageFormat( "Invalid encoding, CT-MIME [{0}] CT-Enc [{1}] BOM [{2}] XML guess [{3}] XML prolog [{4}], BOM must be NULL" ); private static final MessageFormat HTTP_EX_2 = new MessageFormat( "Invalid encoding, CT-MIME [{0}] CT-Enc [{1}] BOM [{2}] XML guess [{3}] XML prolog [{4}], encoding mismatch" ); private static final MessageFormat HTTP_EX_3 = new MessageFormat( "Invalid encoding, CT-MIME [{0}] CT-Enc [{1}] BOM [{2}] XML guess [{3}] XML prolog [{4}], Invalid MIME" ); } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/xml/XmlReaderException.java000066400000000000000000000120611251077732300334570ustar00rootroot00000000000000/* * Copyright 2004 Sun Microsystems, Inc. * * 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. * */ package org.codehaus.plexus.util.xml; import java.io.InputStream; import java.io.IOException; /** * The XmlReaderException is thrown by the XmlReader constructors if the charset encoding can not be determined * according to the XML 1.0 specification and RFC 3023. *

          * The exception returns the unconsumed InputStream to allow the application to do an alternate processing with the * stream. Note that the original InputStream given to the XmlReader cannot be used as that one has been already read. *

          * * @author Alejandro Abdelnur * @version revision 1.1 taken on 26/06/2007 from Rome (see https://rome.dev.java.net/source/browse/rome/src/java/com/sun/syndication/io/XmlReaderException.java) */ public class XmlReaderException extends IOException { private String _bomEncoding; private String _xmlGuessEncoding; private String _xmlEncoding; private String _contentTypeMime; private String _contentTypeEncoding; private InputStream _is; /** * Creates an exception instance if the charset encoding could not be determined. *

          * Instances of this exception are thrown by the XmlReader. *

          * * @param msg * message describing the reason for the exception. * @param bomEnc * BOM encoding. * @param xmlGuessEnc * XML guess encoding. * @param xmlEnc * XML prolog encoding. * @param is * the unconsumed InputStream. * */ public XmlReaderException( String msg, String bomEnc, String xmlGuessEnc, String xmlEnc, InputStream is ) { this( msg, null, null, bomEnc, xmlGuessEnc, xmlEnc, is ); } /** * Creates an exception instance if the charset encoding could not be determined. *

          * Instances of this exception are thrown by the XmlReader. *

          * * @param msg * message describing the reason for the exception. * @param ctMime * MIME type in the content-type. * @param ctEnc * encoding in the content-type. * @param bomEnc * BOM encoding. * @param xmlGuessEnc * XML guess encoding. * @param xmlEnc * XML prolog encoding. * @param is * the unconsumed InputStream. * */ public XmlReaderException( String msg, String ctMime, String ctEnc, String bomEnc, String xmlGuessEnc, String xmlEnc, InputStream is ) { super( msg ); _contentTypeMime = ctMime; _contentTypeEncoding = ctEnc; _bomEncoding = bomEnc; _xmlGuessEncoding = xmlGuessEnc; _xmlEncoding = xmlEnc; _is = is; } /** * Returns the BOM encoding found in the InputStream. *

          * * @return the BOM encoding, null if none. * */ public String getBomEncoding() { return _bomEncoding; } /** * Returns the encoding guess based on the first bytes of the InputStream. *

          * * @return the encoding guess, null if it couldn't be guessed. * */ public String getXmlGuessEncoding() { return _xmlGuessEncoding; } /** * Returns the encoding found in the XML prolog of the InputStream. *

          * * @return the encoding of the XML prolog, null if none. * */ public String getXmlEncoding() { return _xmlEncoding; } /** * Returns the MIME type in the content-type used to attempt determining the encoding. *

          * * @return the MIME type in the content-type, null if there was not content-type or the encoding detection did not * involve HTTP. * */ public String getContentTypeMime() { return _contentTypeMime; } /** * Returns the encoding in the content-type used to attempt determining the encoding. *

          * * @return the encoding in the content-type, null if there was not content-type, no encoding in it or the encoding * detection did not involve HTTP. * */ public String getContentTypeEncoding() { return _contentTypeEncoding; } /** * Returns the unconsumed InputStream to allow the application to do an alternate encoding detection on the * InputStream. *

          * * @return the unconsumed InputStream. * */ public InputStream getInputStream() { return _is; } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/xml/XmlStreamReader.java000066400000000000000000000251641251077732300327640ustar00rootroot00000000000000/* * Copyright 2004 Sun Microsystems, Inc. * * 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. * */ package org.codehaus.plexus.util.xml; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; /** * Character stream that handles (or at least attemtps to) all the necessary Voodo to figure out the charset encoding of * the XML document within the stream. *

          * IMPORTANT: This class is not related in any way to the org.xml.sax.XMLReader. This one IS a character stream. *

          * All this has to be done without consuming characters from the stream, if not the XML parser will not recognized the * document as a valid XML. This is not 100% true, but it's close enough (UTF-8 BOM is not handled by all parsers right * now, XmlReader handles it and things work in all parsers). *

          * The XmlReader class handles the charset encoding of XML documents in Files, raw streams and HTTP streams by offering * a wide set of constructors. *

          * By default the charset encoding detection is lenient, the constructor with the lenient flag can be used for an script * (following HTTP MIME and XML specifications). All this is nicely explained by Mark Pilgrim in his blog, Determining the character encoding of a feed. *

          * * @author Alejandro Abdelnur * @version revision 1.17 taken on 26/06/2007 from Rome (see https://rome.dev.java.net/source/browse/rome/src/java/com/sun/syndication/io/XmlReader.java) * @since 1.4.4 */ public class XmlStreamReader extends XmlReader { /** * Creates a Reader for a File. *

          * It looks for the UTF-8 BOM first, if none sniffs the XML prolog charset, if this is also missing defaults to * UTF-8. *

          * It does a lenient charset encoding detection, check the constructor with the lenient parameter for details. *

          * * @param file * File to create a Reader from. * @throws IOException * thrown if there is a problem reading the file. * */ public XmlStreamReader( File file ) throws IOException { super( file ); } /** * Creates a Reader for a raw InputStream. *

          * It follows the same logic used for files. *

          * It does a lenient charset encoding detection, check the constructor with the lenient parameter for details. *

          * * @param is * InputStream to create a Reader from. * @throws IOException * thrown if there is a problem reading the stream. * */ public XmlStreamReader( InputStream is ) throws IOException { super( is ); } /** * Creates a Reader for a raw InputStream. *

          * It follows the same logic used for files. *

          * If lenient detection is indicated and the detection above fails as per specifications it then attempts the * following: *

          * If the content type was 'text/html' it replaces it with 'text/xml' and tries the detection again. *

          * Else if the XML prolog had a charset encoding that encoding is used. *

          * Else if the content type had a charset encoding that encoding is used. *

          * Else 'UTF-8' is used. *

          * If lenient detection is indicated an XmlStreamReaderException is never thrown. *

          * * @param is * InputStream to create a Reader from. * @param lenient * indicates if the charset encoding detection should be relaxed. * @throws IOException * thrown if there is a problem reading the stream. * @throws XmlStreamReaderException * thrown if the charset encoding could not be determined according to the specs. * */ public XmlStreamReader( InputStream is, boolean lenient ) throws IOException, XmlStreamReaderException { super( is, lenient ); } /** * Creates a Reader using the InputStream of a URL. *

          * If the URL is not of type HTTP and there is not 'content-type' header in the fetched data it uses the same logic * used for Files. *

          * If the URL is a HTTP Url or there is a 'content-type' header in the fetched data it uses the same logic used for * an InputStream with content-type. *

          * It does a lenient charset encoding detection, check the constructor with the lenient parameter for details. *

          * * @param url * URL to create a Reader from. * @throws IOException * thrown if there is a problem reading the stream of the URL. * */ public XmlStreamReader( URL url ) throws IOException { super( url ); } /** * Creates a Reader using the InputStream of a URLConnection. *

          * If the URLConnection is not of type HttpURLConnection and there is not 'content-type' header in the fetched data * it uses the same logic used for files. *

          * If the URLConnection is a HTTP Url or there is a 'content-type' header in the fetched data it uses the same logic * used for an InputStream with content-type. *

          * It does a lenient charset encoding detection, check the constructor with the lenient parameter for details. *

          * * @param conn * URLConnection to create a Reader from. * @throws IOException * thrown if there is a problem reading the stream of the URLConnection. * */ public XmlStreamReader( URLConnection conn ) throws IOException { super( conn ); } /** * Creates a Reader using an InputStream an the associated content-type header. *

          * First it checks if the stream has BOM. If there is not BOM checks the content-type encoding. If there is not * content-type encoding checks the XML prolog encoding. If there is not XML prolog encoding uses the default * encoding mandated by the content-type MIME type. *

          * It does a lenient charset encoding detection, check the constructor with the lenient parameter for details. *

          * * @param is * InputStream to create the reader from. * @param httpContentType * content-type header to use for the resolution of the charset encoding. * @throws IOException * thrown if there is a problem reading the file. * */ public XmlStreamReader( InputStream is, String httpContentType ) throws IOException { super( is, httpContentType ); } /** * Creates a Reader using an InputStream an the associated content-type header. This constructor is lenient * regarding the encoding detection. *

          * First it checks if the stream has BOM. If there is not BOM checks the content-type encoding. If there is not * content-type encoding checks the XML prolog encoding. If there is not XML prolog encoding uses the default * encoding mandated by the content-type MIME type. *

          * If lenient detection is indicated and the detection above fails as per specifications it then attempts the * following: *

          * If the content type was 'text/html' it replaces it with 'text/xml' and tries the detection again. *

          * Else if the XML prolog had a charset encoding that encoding is used. *

          * Else if the content type had a charset encoding that encoding is used. *

          * Else 'UTF-8' is used. *

          * If lenient detection is indicated an XmlStreamReaderException is never thrown. *

          * * @param is * InputStream to create the reader from. * @param httpContentType * content-type header to use for the resolution of the charset encoding. * @param lenient * indicates if the charset encoding detection should be relaxed. * @throws IOException * thrown if there is a problem reading the file. * @throws XmlStreamReaderException * thrown if the charset encoding could not be determined according to the specs. * */ public XmlStreamReader( InputStream is, String httpContentType, boolean lenient, String defaultEncoding ) throws IOException, XmlStreamReaderException { super( is, httpContentType, lenient, defaultEncoding ); } /** * Creates a Reader using an InputStream an the associated content-type header. This constructor is lenient * regarding the encoding detection. *

          * First it checks if the stream has BOM. If there is not BOM checks the content-type encoding. If there is not * content-type encoding checks the XML prolog encoding. If there is not XML prolog encoding uses the default * encoding mandated by the content-type MIME type. *

          * If lenient detection is indicated and the detection above fails as per specifications it then attempts the * following: *

          * If the content type was 'text/html' it replaces it with 'text/xml' and tries the detection again. *

          * Else if the XML prolog had a charset encoding that encoding is used. *

          * Else if the content type had a charset encoding that encoding is used. *

          * Else 'UTF-8' is used. *

          * If lenient detection is indicated an XmlStreamReaderException is never thrown. *

          * * @param is * InputStream to create the reader from. * @param httpContentType * content-type header to use for the resolution of the charset encoding. * @param lenient * indicates if the charset encoding detection should be relaxed. * @throws IOException * thrown if there is a problem reading the file. * @throws XmlStreamReaderException * thrown if the charset encoding could not be determined according to the specs. * */ public XmlStreamReader( InputStream is, String httpContentType, boolean lenient ) throws IOException, XmlStreamReaderException { super( is, httpContentType, lenient ); } } XmlStreamReaderException.java000066400000000000000000000057121251077732300345610ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/xml/* * Copyright 2004 Sun Microsystems, Inc. * * 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. * */ package org.codehaus.plexus.util.xml; import java.io.InputStream; /** * The XmlStreamReaderException is thrown by the XmlStreamReader constructors if the charset encoding can not be determined * according to the XML 1.0 specification and RFC 3023. *

          * The exception returns the unconsumed InputStream to allow the application to do an alternate processing with the * stream. Note that the original InputStream given to the XmlStreamReader cannot be used as that one has been already read. *

          * * @author Alejandro Abdelnur * @version revision 1.1 taken on 26/06/2007 from Rome (see https://rome.dev.java.net/source/browse/rome/src/java/com/sun/syndication/io/XmlReaderException.java) */ public class XmlStreamReaderException extends XmlReaderException { /** * Creates an exception instance if the charset encoding could not be determined. *

          * Instances of this exception are thrown by the XmlReader. *

          * * @param msg * message describing the reason for the exception. * @param bomEnc * BOM encoding. * @param xmlGuessEnc * XML guess encoding. * @param xmlEnc * XML prolog encoding. * @param is * the unconsumed InputStream. * */ public XmlStreamReaderException( String msg, String bomEnc, String xmlGuessEnc, String xmlEnc, InputStream is ) { super( msg, bomEnc, xmlGuessEnc, xmlEnc, is ); } /** * Creates an exception instance if the charset encoding could not be determined. *

          * Instances of this exception are thrown by the XmlReader. *

          * * @param msg * message describing the reason for the exception. * @param ctMime * MIME type in the content-type. * @param ctEnc * encoding in the content-type. * @param bomEnc * BOM encoding. * @param xmlGuessEnc * XML guess encoding. * @param xmlEnc * XML prolog encoding. * @param is * the unconsumed InputStream. * */ public XmlStreamReaderException( String msg, String ctMime, String ctEnc, String bomEnc, String xmlGuessEnc, String xmlEnc, InputStream is ) { super( msg, ctMime, ctEnc, bomEnc, xmlGuessEnc, xmlEnc, is ); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/xml/XmlStreamWriter.java000066400000000000000000000112451251077732300330310ustar00rootroot00000000000000package org.codehaus.plexus.util.xml; /* * 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.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.StringWriter; import java.io.Writer; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Character stream that handles (or at least attemtps to) all the necessary Voodo to figure out the charset encoding of * the XML document written to the stream. * @author Herve Boutemy * @version $Id$ * @since 1.4.4 */ public class XmlStreamWriter extends Writer { private static final int BUFFER_SIZE = 4096; private StringWriter xmlPrologWriter = new StringWriter( BUFFER_SIZE ); private OutputStream out; private Writer writer; private String encoding; public XmlStreamWriter( OutputStream out ) { this.out = out; } public XmlStreamWriter( File file ) throws FileNotFoundException { this( new FileOutputStream( file ) ); } public String getEncoding() { return encoding; } public void close() throws IOException { if ( writer == null ) { encoding = "UTF-8"; writer = new OutputStreamWriter( out, encoding ); writer.write( xmlPrologWriter.toString() ); } writer.close(); } public void flush() throws IOException { if ( writer != null ) { writer.flush(); } } private void detectEncoding( char[] cbuf, int off, int len ) throws IOException { int size = len; StringBuffer xmlProlog = xmlPrologWriter.getBuffer(); if ( xmlProlog.length() + len > BUFFER_SIZE ) { size = BUFFER_SIZE - xmlProlog.length(); } xmlPrologWriter.write( cbuf, off, size ); // try to determine encoding if ( xmlProlog.length() >= 5 ) { if ( xmlProlog.substring( 0, 5 ).equals( "" ); if ( xmlPrologEnd > 0 ) { // ok, full XML prolog written: let's extract encoding Matcher m = ENCODING_PATTERN.matcher( xmlProlog.substring( 0, xmlPrologEnd ) ); if ( m.find() ) { encoding = m.group( 1 ).toUpperCase( Locale.ENGLISH ); encoding = encoding.substring( 1, encoding.length() - 1 ); } else { // no encoding found in XML prolog: using default encoding encoding = "UTF-8"; } } else { if ( xmlProlog.length() >= BUFFER_SIZE ) { // no encoding found in first characters: using default encoding encoding = "UTF-8"; } } } else { // no XML prolog: using default encoding encoding = "UTF-8"; } if ( encoding != null ) { // encoding has been chosen: let's do it xmlPrologWriter = null; writer = new OutputStreamWriter( out, encoding ); writer.write( xmlProlog.toString() ); if ( len > size ) { writer.write( cbuf, off + size, len - size ); } } } } public void write( char[] cbuf, int off, int len ) throws IOException { if ( xmlPrologWriter != null ) { detectEncoding( cbuf, off, len ); } else { writer.write( cbuf, off, len ); } } static final Pattern ENCODING_PATTERN = XmlReader.ENCODING_PATTERN; } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/xml/XmlUtil.java000066400000000000000000000246071251077732300313240ustar00rootroot00000000000000package org.codehaus.plexus.util.xml; /* * 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.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; import org.codehaus.plexus.util.IOUtil; import org.codehaus.plexus.util.ReaderFactory; import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.util.WriterFactory; import org.codehaus.plexus.util.xml.pull.MXParser; import org.codehaus.plexus.util.xml.pull.XmlPullParser; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; /** * Common XML utilities methods. * * @author Vincent Siveton * @version $Id$ * @since 1.5.7 */ public class XmlUtil { /** The default line indenter size i.e. 2. */ public static final int DEFAULT_INDENTATION_SIZE = 2; /** The default line separator ("\n" on UNIX) */ public static final String DEFAULT_LINE_SEPARATOR = System.getProperty( "line.separator" ); /** * Determines if a given File shall be handled as XML. * * @param f not null file * @return true if the given file has XML content, false otherwise. */ public static boolean isXml( File f ) { if ( f == null ) { throw new IllegalArgumentException( "f could not be null." ); } if ( !f.isFile() ) { throw new IllegalArgumentException( "The file '" + f.getAbsolutePath() + "' is not a file." ); } Reader reader = null; try { reader = ReaderFactory.newXmlReader( f ); XmlPullParser parser = new MXParser(); parser.setInput( reader ); parser.nextToken(); return true; } catch ( Exception e ) { return false; } finally { IOUtil.close( reader ); } } /** * Pretty format the input reader. For instance, the following input: *

               * <div><b>content</b></div>
               * 
          * becomes *
               * <div>
               *   <b>content</b>
               * </div>
               * 
          * * @param reader not null * @param writer not null * @throws IOException if any or invalid xml content * @see #prettyFormat(Reader, Writer, int, String) * @see ReaderFactory to read an xml content * @see WriterFactory to write an xml content */ public static void prettyFormat( Reader reader, Writer writer ) throws IOException { prettyFormat( reader, writer, DEFAULT_INDENTATION_SIZE, DEFAULT_LINE_SEPARATOR ); } /** * Pretty format the input reader. For instance, the following input: *
               * <div><b>content</b></div>
               * 
          * becomes *
               * <div>
               *   <b>content</b>
               * </div>
               * 
          * * @param reader not null * @param writer not null * @param indentSize positive number for the indentation * @param lineSeparator the wanted line separator * @throws IOException if any or invalid xml content * @see ReaderFactory to read an xml content * @see WriterFactory to write an xml content */ public static void prettyFormat( Reader reader, Writer writer, int indentSize, String lineSeparator ) throws IOException { if ( reader == null ) { throw new IllegalArgumentException( "The reader is null" ); } if ( writer == null ) { throw new IllegalArgumentException( "The writer is null" ); } if ( indentSize < 0 ) { indentSize = 0; } PrettyPrintXMLWriter xmlWriter = new PrettyPrintXMLWriter( writer ); xmlWriter.setLineIndenter( StringUtils.repeat( " ", indentSize ) ); xmlWriter.setLineSeparator( lineSeparator ); XmlPullParser parser = new MXParser(); try { parser.setInput( reader ); prettyFormatInternal( parser, xmlWriter ); } catch ( XmlPullParserException e ) { throw new IOException( "Unable to parse the XML: " + e.getMessage() ); } } /** * Pretty format the input stream. For instance, the following input: *
               * <div><b>content</b></div>
               * 
          * becomes *
               * <div>
               *   <b>content</b>
               * </div>
               * 
          * * @param is not null * @param os not null * @throws IOException if any or invalid xml content * @see #prettyFormat(InputStream, OutputStream, int, String) */ public static void prettyFormat( InputStream is, OutputStream os ) throws IOException { prettyFormat( is, os, DEFAULT_INDENTATION_SIZE, DEFAULT_LINE_SEPARATOR ); } /** * Pretty format the input stream. For instance, the following input: *
               * <div><b>content</b></div>
               * 
          * becomes *
               * <div>
               *   <b>content</b>
               * </div>
               * 
          * * @param is not null * @param os not null * @param indentSize positive number for the indentation * @param lineSeparator the wanted line separator * @throws IOException if any or invalid xml content */ public static void prettyFormat( InputStream is, OutputStream os, int indentSize, String lineSeparator ) throws IOException { if ( is == null ) { throw new IllegalArgumentException( "The is is null" ); } if ( os == null ) { throw new IllegalArgumentException( "The os is null" ); } if ( indentSize < 0 ) { indentSize = 0; } Reader reader = null; Writer out = new OutputStreamWriter( os ); PrettyPrintXMLWriter xmlWriter = new PrettyPrintXMLWriter( out ); xmlWriter.setLineIndenter( StringUtils.repeat( " ", indentSize ) ); xmlWriter.setLineSeparator( lineSeparator ); XmlPullParser parser = new MXParser(); try { reader = ReaderFactory.newXmlReader( is ); parser.setInput( reader ); prettyFormatInternal( parser, xmlWriter ); } catch ( XmlPullParserException e ) { throw new IOException( "Unable to parse the XML: " + e.getMessage() ); } finally { IOUtil.close( reader ); IOUtil.close( out ); } } /** * @param parser not null * @param writer not null * @throws XmlPullParserException if any * @throws IOException if any */ private static void prettyFormatInternal( XmlPullParser parser, PrettyPrintXMLWriter writer ) throws XmlPullParserException, IOException { boolean hasTag = false; boolean hasComment = false; int eventType = parser.getEventType(); while ( eventType != XmlPullParser.END_DOCUMENT ) { if ( eventType == XmlPullParser.START_TAG ) { hasTag = true; if ( hasComment ) { writer.writeText( writer.getLineIndenter() ); hasComment = false; } writer.startElement( parser.getName() ); for ( int i = 0; i < parser.getAttributeCount(); i++ ) { String key = parser.getAttributeName( i ); String value = parser.getAttributeValue( i ); writer.addAttribute( key, value ); } } else if ( eventType == XmlPullParser.TEXT ) { String text = parser.getText(); if ( !text.trim().equals( "" ) ) { text = StringUtils.removeDuplicateWhitespace( text ); writer.writeText( text ); } } else if ( eventType == XmlPullParser.END_TAG ) { hasTag = false; writer.endElement(); } else if ( eventType == XmlPullParser.COMMENT ) { hasComment = true; if ( !hasTag ) { writer.writeMarkup( writer.getLineSeparator() ); for ( int i = 0; i < writer.getDepth(); i++ ) { writer.writeMarkup( writer.getLineIndenter() ); } } writer.writeMarkup( "" ); if ( !hasTag ) { writer.writeMarkup( writer.getLineSeparator() ); for ( int i = 0; i < writer.getDepth() - 1; i++ ) { writer.writeMarkup( writer.getLineIndenter() ); } } } else if ( eventType == XmlPullParser.DOCDECL ) { writer.writeMarkup( "" ); writer.endOfLine(); } else if ( eventType == XmlPullParser.PROCESSING_INSTRUCTION ) { writer.writeMarkup( "" ); writer.endOfLine(); } else if ( eventType == XmlPullParser.CDSECT ) { writer.writeMarkup( "" ); } else if ( eventType == XmlPullParser.ENTITY_REF ) { writer.writeMarkup( "&" + parser.getName() + ";" ); } eventType = parser.nextToken(); } } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/xml/XmlWriterUtil.java000066400000000000000000000254121251077732300325140ustar00rootroot00000000000000package org.codehaus.plexus.util.xml; /* * 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 org.codehaus.plexus.util.StringUtils; /** * Utility class for the XmlWriter class. * * @author Vincent Siveton * @version $Id$ */ public class XmlWriterUtil { /** The vm line separator */ public static final String LS = System.getProperty( "line.separator" ); /** The default line indenter size i.e. 2. */ public static final int DEFAULT_INDENTATION_SIZE = 2; /** The default column before line wrapping i.e. 80. */ public static final int DEFAULT_COLUMN_LINE = 80; /** * Convenience method to write one CRLF. * * @param writer not null writer */ public static void writeLineBreak( XMLWriter writer ) { writeLineBreak( writer, 1 ); } /** * Convenience method to repeat CRLF. * * @param writer not null * @param repeat positive number */ public static void writeLineBreak( XMLWriter writer, int repeat ) { for ( int i = 0; i < repeat; i++ ) { writer.writeMarkup( LS ); } } /** * Convenience method to repeat CRLF and to indent the writer by 2. * * @param writer not null * @param repeat * @param indent positive number * @see #DEFAULT_INDENTATION_SIZE * @see #writeLineBreak(XMLWriter, int, int, int) */ public static void writeLineBreak( XMLWriter writer, int repeat, int indent ) { writeLineBreak( writer, repeat, indent, DEFAULT_INDENTATION_SIZE ); } /** * Convenience method to repeat CRLF and to indent the writer by indentSize. * * @param writer not null * @param repeat * @param indent positive number * @param indentSize positive number */ public static void writeLineBreak( XMLWriter writer, int repeat, int indent, int indentSize ) { writeLineBreak( writer, repeat ); if ( indent < 0 ) { indent = 0; } if ( indentSize < 0 ) { indentSize = 0; } writer.writeText( StringUtils.repeat( " ", indent * indentSize ) ); } /** * Convenience method to write XML comment line break. Its size is 80. * * @param writer not null * @see #DEFAULT_COLUMN_LINE * @see #writeCommentLineBreak(XMLWriter, int) */ public static void writeCommentLineBreak( XMLWriter writer ) { writeCommentLineBreak( writer, DEFAULT_COLUMN_LINE ); } /** * Convenience method to write XML comment line break with columnSize as length. * * @param writer not null * @param columnSize positive number */ public static void writeCommentLineBreak( XMLWriter writer, int columnSize ) { if ( columnSize < 10 ) { columnSize = DEFAULT_COLUMN_LINE; } writer.writeMarkup( "" + LS ); } /** * Convenience method to write XML comment line. The comment is splitted to have a size of 80. * * @param writer not null * @param comment * @see #DEFAULT_INDENTATION_SIZE * @see #writeComment(XMLWriter, String, int, int) */ public static void writeComment( XMLWriter writer, String comment ) { writeComment( writer, comment, 0, DEFAULT_INDENTATION_SIZE ); } /** * Convenience method to write XML comment line. The comment is splitted to have a size of 80 * and is indented by indent using 2 as indentation size. * * @param writer not null * @param comment * @param indent positive number * @see #DEFAULT_INDENTATION_SIZE * @see #writeComment(XMLWriter, String, int, int) */ public static void writeComment( XMLWriter writer, String comment, int indent ) { writeComment( writer, comment, indent, DEFAULT_INDENTATION_SIZE ); } /** * Convenience method to write XML comment line. The comment is splitted to have a size of 80 * and is indented by indent using indentSize. * * @param writer not null * @param comment * @param indent positive number * @param indentSize positive number * @see #DEFAULT_COLUMN_LINE * @see #writeComment(XMLWriter, String, int, int, int) */ public static void writeComment( XMLWriter writer, String comment, int indent, int indentSize ) { writeComment( writer, comment, indent, indentSize, DEFAULT_COLUMN_LINE ); } /** * Convenience method to write XML comment line. The comment is splitted to have a size of columnSize * and is indented by indent using indentSize. * * @param writer not null * @param comment * @param indent positive number * @param indentSize positive number * @param columnSize positive number */ public static void writeComment( XMLWriter writer, String comment, int indent, int indentSize, int columnSize ) { if ( comment == null ) { comment = "null"; } if ( indent < 0 ) { indent = 0; } if ( indentSize < 0 ) { indentSize = 0; } if ( columnSize < 0 ) { columnSize = DEFAULT_COLUMN_LINE; } String indentation = StringUtils.repeat( " ", indent * indentSize ); int magicNumber = indentation.length() + columnSize - "-->".length() - 1; String[] sentences = StringUtils.split( comment, LS ); StringBuffer line = new StringBuffer( indentation + "" ).append( LS ); writer.writeMarkup( line.toString() ); } line = new StringBuffer( indentation + "" ).append( LS ); writer.writeMarkup( line.toString() ); } /** * Convenience method to write XML comments between two comments line break. * The XML comment block is not indented. * * @param writer not null * @param comment * @see #DEFAULT_INDENTATION_SIZE * @see #writeCommentText(XMLWriter, String, int, int) */ public static void writeCommentText( XMLWriter writer, String comment ) { writeCommentText( writer, comment, 0, DEFAULT_INDENTATION_SIZE ); } /** * Convenience method to write XML comments between two comments line break. * The XML comment block is also indented by indent using * 2 as indentation size. * * @param writer not null * @param comment * @param indent positive number * @see #DEFAULT_INDENTATION_SIZE * @see #writeCommentText(XMLWriter, String, int, int) */ public static void writeCommentText( XMLWriter writer, String comment, int indent ) { writeCommentText( writer, comment, indent, DEFAULT_INDENTATION_SIZE ); } /** * Convenience method to write XML comment between two comment line break. * The XML comment block is also indented by indent using indentSize. * * @param writer not null * @param comment * @param indent positive number * @param indentSize positive number * @see #DEFAULT_COLUMN_LINE * @see #writeCommentText(XMLWriter, String, int, int, int) */ public static void writeCommentText( XMLWriter writer, String comment, int indent, int indentSize ) { writeCommentText( writer, comment, indent, indentSize, DEFAULT_COLUMN_LINE ); } /** * Convenience method to write XML comments between two comments line break. * The XML comment block is also indented by indent using indentSize. * The column size could be also be specified. * * @param writer not null * @param comment * @param indent positive number * @param indentSize positive number * @param columnSize positive number */ public static void writeCommentText( XMLWriter writer, String comment, int indent, int indentSize, int columnSize ) { if ( indent < 0 ) { indent = 0; } if ( indentSize < 0 ) { indentSize = 0; } if ( columnSize < 0 ) { columnSize = DEFAULT_COLUMN_LINE; } writeLineBreak( writer, 1 ); writer.writeMarkup( StringUtils.repeat( " ", indent * indentSize ) ); writeCommentLineBreak( writer, columnSize ); writeComment( writer, comment, indent, indentSize, columnSize ); writer.writeMarkup( StringUtils.repeat( " ", indent * indentSize ) ); writeCommentLineBreak( writer, columnSize ); writeLineBreak( writer, 1, indent, indentSize ); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/xml/Xpp3Dom.java000066400000000000000000000446211251077732300312160ustar00rootroot00000000000000package org.codehaus.plexus.util.xml; /* * 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 org.codehaus.plexus.util.xml.pull.XmlSerializer; import java.io.IOException; import java.io.Serializable; import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; /** * @version $Id$ * NOTE: remove all the util code in here when separated, this class should be pure data. */ public class Xpp3Dom implements Serializable { private static final long serialVersionUID = 2567894443061173996L; protected String name; protected String value; protected Map attributes; protected final List childList; protected final Map childMap; protected Xpp3Dom parent; private static final String[] EMPTY_STRING_ARRAY = new String[0]; private static final Xpp3Dom[] EMPTY_DOM_ARRAY = new Xpp3Dom[0]; public static final String CHILDREN_COMBINATION_MODE_ATTRIBUTE = "combine.children"; public static final String CHILDREN_COMBINATION_MERGE = "merge"; public static final String CHILDREN_COMBINATION_APPEND = "append"; /** * This default mode for combining children DOMs during merge means that where element names * match, the process will try to merge the element data, rather than putting the dominant * and recessive elements (which share the same element name) as siblings in the resulting * DOM. */ public static final String DEFAULT_CHILDREN_COMBINATION_MODE = CHILDREN_COMBINATION_MERGE; public static final String SELF_COMBINATION_MODE_ATTRIBUTE = "combine.self"; public static final String SELF_COMBINATION_OVERRIDE = "override"; public static final String SELF_COMBINATION_MERGE = "merge"; /** * This default mode for combining a DOM node during merge means that where element names * match, the process will try to merge the element attributes and values, rather than * overriding the recessive element completely with the dominant one. This means that * wherever the dominant element doesn't provide the value or a particular attribute, that * value or attribute will be set from the recessive DOM node. */ public static final String DEFAULT_SELF_COMBINATION_MODE = SELF_COMBINATION_MERGE; public Xpp3Dom( String name ) { this.name = name; childList = new ArrayList(); childMap = new HashMap(); } /** * Copy constructor. */ public Xpp3Dom( Xpp3Dom src ) { this( src, src.getName() ); } /** * Copy constructor with alternative name. */ public Xpp3Dom( Xpp3Dom src, String name ) { this.name = name; int childCount = src.getChildCount(); childList = new ArrayList( childCount ); childMap = new HashMap( childCount << 1 ); setValue( src.getValue() ); String[] attributeNames = src.getAttributeNames(); for ( String attributeName : attributeNames ) { setAttribute( attributeName, src.getAttribute( attributeName ) ); } for ( int i = 0; i < childCount; i++ ) { addChild( new Xpp3Dom( src.getChild( i ) ) ); } } // ---------------------------------------------------------------------- // Name handling // ---------------------------------------------------------------------- public String getName() { return name; } // ---------------------------------------------------------------------- // Value handling // ---------------------------------------------------------------------- public String getValue() { return value; } public void setValue( String value ) { this.value = value; } // ---------------------------------------------------------------------- // Attribute handling // ---------------------------------------------------------------------- public String[] getAttributeNames() { if ( null == attributes || attributes.isEmpty() ) { return EMPTY_STRING_ARRAY; } else { return (String[]) attributes.keySet().toArray( new String[attributes.size()] ); } } public String getAttribute( String name ) { return ( null != attributes ) ? (String) attributes.get( name ) : null; } /** * Set the attribute value * @param name String not null * @param value String not null */ public void setAttribute( String name, String value ) { if ( null == value ) { throw new NullPointerException( "Attribute value can not be null" ); } if ( null == name ) { throw new NullPointerException( "Attribute name can not be null" ); } if ( null == attributes ) { attributes = new HashMap(); } attributes.put( name, value ); } // ---------------------------------------------------------------------- // Child handling // ---------------------------------------------------------------------- public Xpp3Dom getChild( int i ) { return (Xpp3Dom) childList.get( i ); } public Xpp3Dom getChild( String name ) { return (Xpp3Dom) childMap.get( name ); } public void addChild( Xpp3Dom xpp3Dom ) { xpp3Dom.setParent( this ); childList.add( xpp3Dom ); childMap.put( xpp3Dom.getName(), xpp3Dom ); } public Xpp3Dom[] getChildren() { if ( null == childList || childList.isEmpty() ) { return EMPTY_DOM_ARRAY; } else { return (Xpp3Dom[]) childList.toArray( new Xpp3Dom[childList.size()] ); } } public Xpp3Dom[] getChildren( String name ) { if ( null == childList ) { return EMPTY_DOM_ARRAY; } else { ArrayList children = new ArrayList(); int size = childList.size(); for ( Xpp3Dom aChildList : childList ) { Xpp3Dom configuration = (Xpp3Dom) aChildList; if ( name.equals( configuration.getName() ) ) { children.add( configuration ); } } return (Xpp3Dom[]) children.toArray( new Xpp3Dom[children.size()] ); } } public int getChildCount() { if ( null == childList ) { return 0; } return childList.size(); } public void removeChild( int i ) { Xpp3Dom child = getChild( i ); childMap.values().remove( child ); childList.remove( i ); // In case of any dangling references child.setParent( null ); } // ---------------------------------------------------------------------- // Parent handling // ---------------------------------------------------------------------- public Xpp3Dom getParent() { return parent; } public void setParent( Xpp3Dom parent ) { this.parent = parent; } // ---------------------------------------------------------------------- // Helpers // ---------------------------------------------------------------------- public void writeToSerializer( String namespace, XmlSerializer serializer ) throws IOException { // TODO: WARNING! Later versions of plexus-utils psit out an header due to thinking this is a new document - not the desired behaviour! SerializerXMLWriter xmlWriter = new SerializerXMLWriter( namespace, serializer ); Xpp3DomWriter.write( xmlWriter, this ); if ( xmlWriter.getExceptions().size() > 0 ) { throw (IOException) xmlWriter.getExceptions().get( 0 ); } } /** * Merges one DOM into another, given a specific algorithm and possible override points for that algorithm. * The algorithm is as follows: * * 1. if the recessive DOM is null, there is nothing to do...return. * * 2. Determine whether the dominant node will suppress the recessive one (flag=mergeSelf). * * A. retrieve the 'combine.self' attribute on the dominant node, and try to match against 'override'... * if it matches 'override', then set mergeSelf == false...the dominant node suppresses the recessive * one completely. * * B. otherwise, use the default value for mergeSelf, which is true...this is the same as specifying * 'combine.self' == 'merge' as an attribute of the dominant root node. * * 3. If mergeSelf == true * * A. if the dominant root node's value is empty, set it to the recessive root node's value * * B. For each attribute in the recessive root node which is not set in the dominant root node, set it. * * C. Determine whether children from the recessive DOM will be merged or appended to the dominant * DOM as siblings (flag=mergeChildren). * * i. if childMergeOverride is set (non-null), use that value (true/false) * * ii. retrieve the 'combine.children' attribute on the dominant node, and try to match against * 'append'...if it matches 'append', then set mergeChildren == false...the recessive children * will be appended as siblings of the dominant children. * * iii. otherwise, use the default value for mergeChildren, which is true...this is the same as * specifying 'combine.children' == 'merge' as an attribute on the dominant root node. * * D. Iterate through the recessive children, and: * * i. if mergeChildren == true and there is a corresponding dominant child (matched by element name), * merge the two. * * ii. otherwise, add the recessive child as a new child on the dominant root node. */ private static void mergeIntoXpp3Dom( Xpp3Dom dominant, Xpp3Dom recessive, Boolean childMergeOverride ) { // TODO: share this as some sort of assembler, implement a walk interface? if ( recessive == null ) { return; } boolean mergeSelf = true; String selfMergeMode = dominant.getAttribute( SELF_COMBINATION_MODE_ATTRIBUTE ); if ( SELF_COMBINATION_OVERRIDE.equals( selfMergeMode ) ) { mergeSelf = false; } if ( mergeSelf ) { if ( isEmpty( dominant.getValue() ) ) { dominant.setValue( recessive.getValue() ); } String[] recessiveAttrs = recessive.getAttributeNames(); for ( String attr : recessiveAttrs ) { if ( isEmpty( dominant.getAttribute( attr ) ) ) { dominant.setAttribute( attr, recessive.getAttribute( attr ) ); } } if ( recessive.getChildCount() > 0 ) { boolean mergeChildren = true; if ( childMergeOverride != null ) { mergeChildren = childMergeOverride; } else { String childMergeMode = dominant.getAttribute( CHILDREN_COMBINATION_MODE_ATTRIBUTE ); if ( CHILDREN_COMBINATION_APPEND.equals( childMergeMode ) ) { mergeChildren = false; } } if ( !mergeChildren ) { Xpp3Dom[] dominantChildren = dominant.getChildren(); // remove these now, so we can append them to the recessive list later. dominant.childList.clear(); for ( int i = 0, recessiveChildCount = recessive.getChildCount(); i < recessiveChildCount; i++ ) { Xpp3Dom recessiveChild = recessive.getChild( i ); dominant.addChild( new Xpp3Dom( recessiveChild ) ); } // now, re-add these children so they'll be appended to the recessive list. for ( Xpp3Dom aDominantChildren : dominantChildren ) { dominant.addChild( aDominantChildren ); } } else { Map> commonChildren = new HashMap>(); for ( String childName : recessive.childMap.keySet() ) { Xpp3Dom[] dominantChildren = dominant.getChildren( childName ); if ( dominantChildren.length > 0 ) { commonChildren.put( childName, Arrays.asList( dominantChildren ).iterator() ); } } for ( int i = 0, recessiveChildCount = recessive.getChildCount(); i < recessiveChildCount; i++ ) { Xpp3Dom recessiveChild = recessive.getChild( i ); Iterator it = commonChildren.get( recessiveChild.getName() ); if ( it == null ) { dominant.addChild( new Xpp3Dom( recessiveChild ) ); } else if ( it.hasNext() ) { Xpp3Dom dominantChild = it.next(); mergeIntoXpp3Dom( dominantChild, recessiveChild, childMergeOverride ); } } } } } } /** * Merge two DOMs, with one having dominance in the case of collision. * * @see #CHILDREN_COMBINATION_MODE_ATTRIBUTE * @see #SELF_COMBINATION_MODE_ATTRIBUTE * * @param dominant The dominant DOM into which the recessive value/attributes/children will be merged * @param recessive The recessive DOM, which will be merged into the dominant DOM * @param childMergeOverride Overrides attribute flags to force merging or appending of child elements * into the dominant DOM */ public static Xpp3Dom mergeXpp3Dom( Xpp3Dom dominant, Xpp3Dom recessive, Boolean childMergeOverride ) { if ( dominant != null ) { mergeIntoXpp3Dom( dominant, recessive, childMergeOverride ); return dominant; } return recessive; } /** * Merge two DOMs, with one having dominance in the case of collision. * Merge mechanisms (vs. override for nodes, or vs. append for children) is determined by * attributes of the dominant root node. * * @see #CHILDREN_COMBINATION_MODE_ATTRIBUTE * @see #SELF_COMBINATION_MODE_ATTRIBUTE * * @param dominant The dominant DOM into which the recessive value/attributes/children will be merged * @param recessive The recessive DOM, which will be merged into the dominant DOM */ public static Xpp3Dom mergeXpp3Dom( Xpp3Dom dominant, Xpp3Dom recessive ) { if ( dominant != null ) { mergeIntoXpp3Dom( dominant, recessive, null ); return dominant; } return recessive; } // ---------------------------------------------------------------------- // Standard object handling // ---------------------------------------------------------------------- public boolean equals( Object obj ) { if ( obj == this ) { return true; } if ( !( obj instanceof Xpp3Dom ) ) { return false; } Xpp3Dom dom = (Xpp3Dom) obj; if ( name == null ? dom.name != null : !name.equals( dom.name ) ) { return false; } else if ( value == null ? dom.value != null : !value.equals( dom.value ) ) { return false; } else if ( attributes == null ? dom.attributes != null : !attributes.equals( dom.attributes ) ) { return false; } else if ( childList == null ? dom.childList != null : !childList.equals( dom.childList ) ) { return false; } else { return true; } } public int hashCode() { int result = 17; result = 37 * result + ( name != null ? name.hashCode() : 0 ); result = 37 * result + ( value != null ? value.hashCode() : 0 ); result = 37 * result + ( attributes != null ? attributes.hashCode() : 0 ); result = 37 * result + ( childList != null ? childList.hashCode() : 0 ); return result; } public String toString() { // TODO: WARNING! Later versions of plexus-utils psit out an header due to thinking this is a new document - not the desired behaviour! StringWriter writer = new StringWriter(); XMLWriter xmlWriter = new PrettyPrintXMLWriter( writer, "UTF-8", null ); Xpp3DomWriter.write( xmlWriter, this ); return writer.toString(); } public String toUnescapedString() { // TODO: WARNING! Later versions of plexus-utils psit out an header due to thinking this is a new document - not the desired behaviour! StringWriter writer = new StringWriter(); XMLWriter xmlWriter = new PrettyPrintXMLWriter( writer, "UTF-8", null ); Xpp3DomWriter.write( xmlWriter, this, false ); return writer.toString(); } public static boolean isNotEmpty( String str ) { return ( ( str != null ) && ( str.length() > 0 ) ); } public static boolean isEmpty( String str ) { return ( ( str == null ) || ( str.trim().length() == 0 ) ); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/xml/Xpp3DomBuilder.java000066400000000000000000000126521251077732300325240ustar00rootroot00000000000000package org.codehaus.plexus.util.xml; /* * 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 org.codehaus.plexus.util.IOUtil; import org.codehaus.plexus.util.xml.pull.MXParser; import org.codehaus.plexus.util.xml.pull.XmlPullParser; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.util.ArrayList; import java.util.List; /** * @version $Id$ */ public class Xpp3DomBuilder { private static final boolean DEFAULT_TRIM = true; public static Xpp3Dom build( Reader reader ) throws XmlPullParserException, IOException { return build( reader, DEFAULT_TRIM ); } public static Xpp3Dom build( InputStream is, String encoding ) throws XmlPullParserException, IOException { return build( is, encoding, DEFAULT_TRIM ); } public static Xpp3Dom build( InputStream is, String encoding, boolean trim ) throws XmlPullParserException, IOException { XmlPullParser parser = new MXParser(); parser.setInput( is, encoding ); try { return build( parser, trim ); } finally { IOUtil.close( is ); } } public static Xpp3Dom build( Reader reader, boolean trim ) throws XmlPullParserException, IOException { XmlPullParser parser = new MXParser(); parser.setInput( reader ); try { return build( parser, trim ); } finally { IOUtil.close( reader ); } } public static Xpp3Dom build( XmlPullParser parser ) throws XmlPullParserException, IOException { return build( parser, DEFAULT_TRIM ); } public static Xpp3Dom build( XmlPullParser parser, boolean trim ) throws XmlPullParserException, IOException { List elements = new ArrayList(); List values = new ArrayList(); int eventType = parser.getEventType(); boolean spacePreserve = false; while ( eventType != XmlPullParser.END_DOCUMENT ) { if ( eventType == XmlPullParser.START_TAG ) { spacePreserve = false; String rawName = parser.getName(); Xpp3Dom childConfiguration = new Xpp3Dom( rawName ); int depth = elements.size(); if ( depth > 0 ) { Xpp3Dom parent = elements.get( depth - 1 ); parent.addChild( childConfiguration ); } elements.add( childConfiguration ); if ( parser.isEmptyElementTag() ) { values.add( null ); } else { values.add( new StringBuilder() ); } int attributesSize = parser.getAttributeCount(); for ( int i = 0; i < attributesSize; i++ ) { String name = parser.getAttributeName( i ); String value = parser.getAttributeValue( i ); childConfiguration.setAttribute( name, value ); spacePreserve = spacePreserve || ( "xml:space".equals( name ) && "preserve".equals( value ) ); } } else if ( eventType == XmlPullParser.TEXT ) { int depth = values.size() - 1; @SuppressWarnings( "MismatchedQueryAndUpdateOfStringBuilder" ) StringBuilder valueBuffer = values.get( depth ); String text = parser.getText(); if ( trim && !spacePreserve ) { text = text.trim(); } valueBuffer.append( text ); } else if ( eventType == XmlPullParser.END_TAG ) { int depth = elements.size() - 1; Xpp3Dom finishedConfiguration = elements.remove( depth ); /* this Object could be null if it is a singleton tag */ Object accumulatedValue = values.remove( depth ); if ( finishedConfiguration.getChildCount() == 0 ) { if ( accumulatedValue == null ) { finishedConfiguration.setValue( null ); } else { finishedConfiguration.setValue( accumulatedValue.toString() ); } } if ( depth == 0 ) { return finishedConfiguration; } } eventType = parser.next(); } throw new IllegalStateException( "End of document found before returning to 0 depth" ); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/xml/Xpp3DomUtils.java000066400000000000000000000234171251077732300322370ustar00rootroot00000000000000package org.codehaus.plexus.util.xml; /* * 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 org.codehaus.plexus.util.xml.pull.XmlSerializer; import java.io.IOException; /** @author Jason van Zyl */ public class Xpp3DomUtils { public static final String CHILDREN_COMBINATION_MODE_ATTRIBUTE = "combine.children"; public static final String CHILDREN_COMBINATION_MERGE = "merge"; public static final String CHILDREN_COMBINATION_APPEND = "append"; /** * This default mode for combining children DOMs during merge means that where element names * match, the process will try to merge the element data, rather than putting the dominant * and recessive elements (which share the same element name) as siblings in the resulting * DOM. */ public static final String DEFAULT_CHILDREN_COMBINATION_MODE = CHILDREN_COMBINATION_MERGE; public static final String SELF_COMBINATION_MODE_ATTRIBUTE = "combine.self"; public static final String SELF_COMBINATION_OVERRIDE = "override"; public static final String SELF_COMBINATION_MERGE = "merge"; /** * In case of complex XML structures, combining can be done based on id. * * @since 3.0.22 */ public static final String ID_COMBINATION_MODE_ATTRIBUTE = "combine.id"; /** * This default mode for combining a DOM node during merge means that where element names * match, the process will try to merge the element attributes and values, rather than * overriding the recessive element completely with the dominant one. This means that * wherever the dominant element doesn't provide the value or a particular attribute, that * value or attribute will be set from the recessive DOM node. */ public static final String DEFAULT_SELF_COMBINATION_MODE = SELF_COMBINATION_MERGE; public void writeToSerializer( String namespace, XmlSerializer serializer, Xpp3Dom dom ) throws IOException { // TODO: WARNING! Later versions of plexus-utils psit out an header due to thinking this is a new document - not the desired behaviour! SerializerXMLWriter xmlWriter = new SerializerXMLWriter( namespace, serializer ); Xpp3DomWriter.write( xmlWriter, dom ); if ( xmlWriter.getExceptions().size() > 0 ) { throw (IOException) xmlWriter.getExceptions().get( 0 ); } } /** * Merges one DOM into another, given a specific algorithm and possible override points for that algorithm. * The algorithm is as follows: * * 1. if the recessive DOM is null, there is nothing to do...return. * * 2. Determine whether the dominant node will suppress the recessive one (flag=mergeSelf). * * A. retrieve the 'combine.self' attribute on the dominant node, and try to match against 'override'... * if it matches 'override', then set mergeSelf == false...the dominant node suppresses the recessive * one completely. * * B. otherwise, use the default value for mergeSelf, which is true...this is the same as specifying * 'combine.self' == 'merge' as an attribute of the dominant root node. * * 3. If mergeSelf == true * * A. if the dominant root node's value is empty, set it to the recessive root node's value * * B. For each attribute in the recessive root node which is not set in the dominant root node, set it. * * C. Determine whether children from the recessive DOM will be merged or appended to the dominant * DOM as siblings (flag=mergeChildren). * * i. if childMergeOverride is set (non-null), use that value (true/false) * * ii. retrieve the 'combine.children' attribute on the dominant node, and try to match against * 'append'...if it matches 'append', then set mergeChildren == false...the recessive children * will be appended as siblings of the dominant children. * * iii. otherwise, use the default value for mergeChildren, which is true...this is the same as * specifying 'combine.children' == 'merge' as an attribute on the dominant root node. * * D. Iterate through the recessive children, and: * * i. if 'combine.id' is set and there is a corresponding dominant child (matched by value of 'combine.id'), * merge the two. * * ii. if mergeChildren == true and there is a corresponding dominant child (matched by element name), * merge the two. * * iii. otherwise, add the recessive child as a new child on the dominant root node. */ private static void mergeIntoXpp3Dom( Xpp3Dom dominant, Xpp3Dom recessive, Boolean childMergeOverride ) { // TODO: share this as some sort of assembler, implement a walk interface? if ( recessive == null ) { return; } boolean mergeSelf = true; String selfMergeMode = dominant.getAttribute( SELF_COMBINATION_MODE_ATTRIBUTE ); if ( isNotEmpty( selfMergeMode ) && SELF_COMBINATION_OVERRIDE.equals( selfMergeMode ) ) { mergeSelf = false; } if ( mergeSelf ) { if ( isEmpty( dominant.getValue() ) ) { dominant.setValue( recessive.getValue() ); } String[] recessiveAttrs = recessive.getAttributeNames(); for ( String attr : recessiveAttrs ) { if ( isEmpty( dominant.getAttribute( attr ) ) ) { dominant.setAttribute( attr, recessive.getAttribute( attr ) ); } } boolean mergeChildren = true; if ( childMergeOverride != null ) { mergeChildren = childMergeOverride; } else { String childMergeMode = dominant.getAttribute( CHILDREN_COMBINATION_MODE_ATTRIBUTE ); if ( isNotEmpty( childMergeMode ) && CHILDREN_COMBINATION_APPEND.equals( childMergeMode ) ) { mergeChildren = false; } } Xpp3Dom[] children = recessive.getChildren(); for ( Xpp3Dom recessiveChild : children ) { String idValue = recessiveChild.getAttribute( ID_COMBINATION_MODE_ATTRIBUTE ); Xpp3Dom childDom = null; if ( isNotEmpty( idValue ) ) { for ( Xpp3Dom dominantChild : dominant.getChildren() ) { if ( idValue.equals( dominantChild.getAttribute( ID_COMBINATION_MODE_ATTRIBUTE ) ) ) { childDom = dominantChild; // we have a match, so don't append but merge mergeChildren = true; } } } else { childDom = dominant.getChild( recessiveChild.getName() ); } if ( mergeChildren && childDom != null ) { mergeIntoXpp3Dom( childDom, recessiveChild, childMergeOverride ); } else { dominant.addChild( new Xpp3Dom( recessiveChild ) ); } } } } /** * Merge two DOMs, with one having dominance in the case of collision. * * @see #CHILDREN_COMBINATION_MODE_ATTRIBUTE * @see #SELF_COMBINATION_MODE_ATTRIBUTE * * @param dominant The dominant DOM into which the recessive value/attributes/children will be merged * @param recessive The recessive DOM, which will be merged into the dominant DOM * @param childMergeOverride Overrides attribute flags to force merging or appending of child elements * into the dominant DOM */ public static Xpp3Dom mergeXpp3Dom( Xpp3Dom dominant, Xpp3Dom recessive, Boolean childMergeOverride ) { if ( dominant != null ) { mergeIntoXpp3Dom( dominant, recessive, childMergeOverride ); return dominant; } return recessive; } /** * Merge two DOMs, with one having dominance in the case of collision. * Merge mechanisms (vs. override for nodes, or vs. append for children) is determined by * attributes of the dominant root node. * * @see #CHILDREN_COMBINATION_MODE_ATTRIBUTE * @see #SELF_COMBINATION_MODE_ATTRIBUTE * * @param dominant The dominant DOM into which the recessive value/attributes/children will be merged * @param recessive The recessive DOM, which will be merged into the dominant DOM */ public static Xpp3Dom mergeXpp3Dom( Xpp3Dom dominant, Xpp3Dom recessive ) { if ( dominant != null ) { mergeIntoXpp3Dom( dominant, recessive, null ); return dominant; } return recessive; } public static boolean isNotEmpty( String str ) { return ( str != null && str.length() > 0 ); } public static boolean isEmpty( String str ) { return ( str == null || str.trim().length() == 0 ); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/xml/Xpp3DomWriter.java000066400000000000000000000037351251077732300324140ustar00rootroot00000000000000package org.codehaus.plexus.util.xml; /* * 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.PrintWriter; import java.io.Writer; /** * @version $Id$ */ public class Xpp3DomWriter { public static void write( Writer writer, Xpp3Dom dom ) { write( new PrettyPrintXMLWriter( writer ), dom ); } public static void write( PrintWriter writer, Xpp3Dom dom ) { write( new PrettyPrintXMLWriter( writer ), dom ); } public static void write( XMLWriter xmlWriter, Xpp3Dom dom ) { write( xmlWriter, dom, true ); } public static void write( XMLWriter xmlWriter, Xpp3Dom dom, boolean escape ) { // TODO: move to XMLWriter? xmlWriter.startElement( dom.getName() ); String[] attributeNames = dom.getAttributeNames(); for ( String attributeName : attributeNames ) { xmlWriter.addAttribute( attributeName, dom.getAttribute( attributeName ) ); } Xpp3Dom[] children = dom.getChildren(); for ( Xpp3Dom aChildren : children ) { write( xmlWriter, aChildren, escape ); } String value = dom.getValue(); if ( value != null ) { if ( escape ) { xmlWriter.writeText( value ); } else { xmlWriter.writeMarkup( value ); } } xmlWriter.endElement(); } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/xml/pull/000077500000000000000000000000001251077732300300265ustar00rootroot00000000000000EntityReplacementMap.java000066400000000000000000000251431251077732300347110ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/xml/pullpackage org.codehaus.plexus.util.xml.pull; /* * 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. */ public class EntityReplacementMap { final String entityName[]; final char[] entityNameBuf[]; final String entityReplacement[]; final char[] entityReplacementBuf[]; int entityEnd; final int entityNameHash[]; public EntityReplacementMap( String[][] replacements ){ int length = replacements.length; entityName = new String[length]; entityNameBuf = new char[length][]; entityReplacement = new String[length]; entityReplacementBuf = new char[length][]; entityNameHash = new int[length]; for ( String[] replacement : replacements ) { defineEntityReplacementText( replacement[0],replacement[1] ); } } private void defineEntityReplacementText(String entityName, String replacementText) { if ( !replacementText.startsWith( "&#" ) && this.entityName != null && replacementText.length() > 1 ) { String tmp = replacementText.substring( 1, replacementText.length() - 1 ); for ( int i = 0; i < this.entityName.length; i++ ) { if ( this.entityName[i] != null && this.entityName[i].equals( tmp ) ) { replacementText = this.entityReplacement[i]; } } } // this is to make sure that if interning works we will take advantage of it ... char[] entityNameCharData = entityName.toCharArray(); //noinspection ConstantConditions this.entityName[entityEnd] = newString( entityNameCharData, 0, entityName.length()); entityNameBuf[entityEnd] = entityNameCharData; entityReplacement[entityEnd] = replacementText; entityReplacementBuf[entityEnd] = replacementText.toCharArray(); entityNameHash[ entityEnd ] = fastHash( entityNameBuf[entityEnd], 0, entityNameBuf[entityEnd].length); ++entityEnd; //TODO disallow < or & in entity replacement text (or ]]>???) //TODO keepEntityNormalizedForAttributeValue cached as well ... } private String newString(char[] cbuf, int off, int len) { return new String(cbuf, off, len); } /** * simplistic implementation of hash function that has constant * time to compute - so it also means diminishing hash quality for long strings * but for XML parsing it should be good enough ... */ private static int fastHash( char ch[], int off, int len ) { if(len == 0) return 0; //assert len >0 int hash = ch[off]; // hash at beginning //try { hash = (hash << 7) + ch[ off + len - 1 ]; // hash at the end //} catch(ArrayIndexOutOfBoundsException aie) { // aie.printStackTrace(); //should never happen ... // throw new RuntimeException("this is violation of pre-condition"); //} if(len > 16) hash = (hash << 7) + ch[ off + (len / 4)]; // 1/4 from beginning if(len > 8) hash = (hash << 7) + ch[ off + (len / 2)]; // 1/2 of string size ... // notice that hash is at most done 3 times <<7 so shifted by 21 bits 8 bit value // so max result == 29 bits so it is quite just below 31 bits for long (2^32) ... //assert hash >= 0; return hash; } public static final EntityReplacementMap defaultEntityReplacementMap = new EntityReplacementMap( new String[][]{ { "nbsp", "\u00a0" }, { "iexcl", "\u00a1" }, { "cent", "\u00a2" }, { "pound", "\u00a3" }, { "curren", "\u00a4" }, { "yen", "\u00a5" }, { "brvbar", "\u00a6" }, { "sect", "\u00a7" }, { "uml", "\u00a8" }, { "copy", "\u00a9" }, { "ordf", "\u00aa" }, { "laquo", "\u00ab" }, { "not", "\u00ac" }, { "shy", "\u00ad" }, { "reg", "\u00ae" }, { "macr", "\u00af" }, { "deg", "\u00b0" }, { "plusmn", "\u00b1" }, { "sup2", "\u00b2" }, { "sup3", "\u00b3" }, { "acute", "\u00b4" }, { "micro", "\u00b5" }, { "para", "\u00b6" }, { "middot", "\u00b7" }, { "cedil", "\u00b8" }, { "sup1", "\u00b9" }, { "ordm", "\u00ba" }, { "raquo", "\u00bb" }, { "frac14", "\u00bc" }, { "frac12", "\u00bd" }, { "frac34", "\u00be" }, { "iquest", "\u00bf" }, { "Agrave", "\u00c0" }, { "Aacute", "\u00c1" }, { "Acirc", "\u00c2" }, { "Atilde", "\u00c3" }, { "Auml", "\u00c4" }, { "Aring", "\u00c5" }, { "AElig", "\u00c6" }, { "Ccedil", "\u00c7" }, { "Egrave", "\u00c8" }, { "Eacute", "\u00c9" }, { "Ecirc", "\u00ca" }, { "Euml", "\u00cb" }, { "Igrave", "\u00cc" }, { "Iacute", "\u00cd" }, { "Icirc", "\u00ce" }, { "Iuml", "\u00cf" }, { "ETH", "\u00d0" }, { "Ntilde", "\u00d1" }, { "Ograve", "\u00d2" }, { "Oacute", "\u00d3" }, { "Ocirc", "\u00d4" }, { "Otilde", "\u00d5" }, { "Ouml", "\u00d6" }, { "times", "\u00d7" }, { "Oslash", "\u00d8" }, { "Ugrave", "\u00d9" }, { "Uacute", "\u00da" }, { "Ucirc", "\u00db" }, { "Uuml", "\u00dc" }, { "Yacute", "\u00dd" }, { "THORN", "\u00de" }, { "szlig", "\u00df" }, { "agrave", "\u00e0" }, { "aacute", "\u00e1" }, { "acirc", "\u00e2" }, { "atilde", "\u00e3" }, { "auml", "\u00e4" }, { "aring", "\u00e5" }, { "aelig", "\u00e6" }, { "ccedil", "\u00e7" }, { "egrave", "\u00e8" }, { "eacute", "\u00e9" }, { "ecirc", "\u00ea" }, { "euml", "\u00eb" }, { "igrave", "\u00ec" }, { "iacute", "\u00ed" }, { "icirc", "\u00ee" }, { "iuml", "\u00ef" }, { "eth", "\u00f0" }, { "ntilde", "\u00f1" }, { "ograve", "\u00f2" }, { "oacute", "\u00f3" }, { "ocirc", "\u00f4" }, { "otilde", "\u00f5" }, { "ouml", "\u00f6" }, { "divide", "\u00f7" }, { "oslash", "\u00f8" }, { "ugrave", "\u00f9" }, { "uacute", "\u00fa" }, { "ucirc", "\u00fb" }, { "uuml", "\u00fc" }, { "yacute", "\u00fd" }, { "thorn", "\u00fe" }, { "yuml", "\u00ff" }, // ---------------------------------------------------------------------- // Special entities // ---------------------------------------------------------------------- { "OElig", "\u0152" }, { "oelig", "\u0153" }, { "Scaron", "\u0160" }, { "scaron", "\u0161" }, { "Yuml", "\u0178" }, { "circ", "\u02c6" }, { "tilde", "\u02dc" }, { "ensp", "\u2002" }, { "emsp", "\u2003" }, { "thinsp", "\u2009" }, { "zwnj", "\u200c" }, { "zwj", "\u200d" }, { "lrm", "\u200e" }, { "rlm", "\u200f" }, { "ndash", "\u2013" }, { "mdash", "\u2014" }, { "lsquo", "\u2018" }, { "rsquo", "\u2019" }, { "sbquo", "\u201a" }, { "ldquo", "\u201c" }, { "rdquo", "\u201d" }, { "bdquo", "\u201e" }, { "dagger", "\u2020" }, { "Dagger", "\u2021" }, { "permil", "\u2030" }, { "lsaquo", "\u2039" }, { "rsaquo", "\u203a" }, { "euro", "\u20ac" }, // ---------------------------------------------------------------------- // Symbol entities // ---------------------------------------------------------------------- { "fnof", "\u0192" }, { "Alpha", "\u0391" }, { "Beta", "\u0392" }, { "Gamma", "\u0393" }, { "Delta", "\u0394" }, { "Epsilon", "\u0395" }, { "Zeta", "\u0396" }, { "Eta", "\u0397" }, { "Theta", "\u0398" }, { "Iota", "\u0399" }, { "Kappa", "\u039a" }, { "Lambda", "\u039b" }, { "Mu", "\u039c" }, { "Nu", "\u039d" }, { "Xi", "\u039e" }, { "Omicron", "\u039f" }, { "Pi", "\u03a0" }, { "Rho", "\u03a1" }, { "Sigma", "\u03a3" }, { "Tau", "\u03a4" }, { "Upsilon", "\u03a5" }, { "Phi", "\u03a6" }, { "Chi", "\u03a7" }, { "Psi", "\u03a8" }, { "Omega", "\u03a9" }, { "alpha", "\u03b1" }, { "beta", "\u03b2" }, { "gamma", "\u03b3" }, { "delta", "\u03b4" }, { "epsilon", "\u03b5" }, { "zeta", "\u03b6" }, { "eta", "\u03b7" }, { "theta", "\u03b8" }, { "iota", "\u03b9" }, { "kappa", "\u03ba" }, { "lambda", "\u03bb" }, { "mu", "\u03bc" }, { "nu", "\u03bd" }, { "xi", "\u03be" }, { "omicron", "\u03bf" }, { "pi", "\u03c0" }, { "rho", "\u03c1" }, { "sigmaf", "\u03c2" }, { "sigma", "\u03c3" }, { "tau", "\u03c4" }, { "upsilon", "\u03c5" }, { "phi", "\u03c6" }, { "chi", "\u03c7" }, { "psi", "\u03c8" }, { "omega", "\u03c9" }, { "thetasym", "\u03d1" }, { "upsih", "\u03d2" }, { "piv", "\u03d6" }, { "bull", "\u2022" }, { "hellip", "\u2026" }, { "prime", "\u2032" }, { "Prime", "\u2033" }, { "oline", "\u203e" }, { "frasl", "\u2044" }, { "weierp", "\u2118" }, { "image", "\u2111" }, { "real", "\u211c" }, { "trade", "\u2122" }, { "alefsym", "\u2135" }, { "larr", "\u2190" }, { "uarr", "\u2191" }, { "rarr", "\u2192" }, { "darr", "\u2193" }, { "harr", "\u2194" }, { "crarr", "\u21b5" }, { "lArr", "\u21d0" }, { "uArr", "\u21d1" }, { "rArr", "\u21d2" }, { "dArr", "\u21d3" }, { "hArr", "\u21d4" }, { "forall", "\u2200" }, { "part", "\u2202" }, { "exist", "\u2203" }, { "empty", "\u2205" }, { "nabla", "\u2207" }, { "isin", "\u2208" }, { "notin", "\u2209" }, { "ni", "\u220b" }, { "prod", "\u220f" }, { "sum", "\u2211" }, { "minus", "\u2212" }, { "lowast", "\u2217" }, { "radic", "\u221a" }, { "prop", "\u221d" }, { "infin", "\u221e" }, { "ang", "\u2220" }, { "and", "\u2227" }, { "or", "\u2228" }, { "cap", "\u2229" }, { "cup", "\u222a" }, { "int", "\u222b" }, { "there4", "\u2234" }, { "sim", "\u223c" }, { "cong", "\u2245" }, { "asymp", "\u2248" }, { "ne", "\u2260" }, { "equiv", "\u2261" }, { "le", "\u2264" }, { "ge", "\u2265" }, { "sub", "\u2282" }, { "sup", "\u2283" }, { "nsub", "\u2284" }, { "sube", "\u2286" }, { "supe", "\u2287" }, { "oplus", "\u2295" }, { "otimes", "\u2297" }, { "perp", "\u22a5" }, { "sdot", "\u22c5" }, { "lceil", "\u2308" }, { "rceil", "\u2309" }, { "lfloor", "\u230a" }, { "rfloor", "\u230b" }, { "lang", "\u2329" }, { "rang", "\u232a" }, { "loz", "\u25ca" }, { "spades", "\u2660" }, { "clubs", "\u2663" }, { "hearts", "\u2665" }, { "diams", "\u2666" } } ); } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/xml/pull/MXParser.java000066400000000000000000004131651251077732300324040ustar00rootroot00000000000000/* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- //------100-columns-wide------>|*/ /* * Copyright (c) 2003 Extreme! Lab, Indiana University. All rights reserved. * * This software is open source. See the bottom of this file for the licence. * * $Id$ */ package org.codehaus.plexus.util.xml.pull; import java.io.EOFException; import java.io.IOException; import java.io.Reader; import java.io.UnsupportedEncodingException; import org.codehaus.plexus.util.ReaderFactory; //import java.util.Hashtable; //TODO best handling of interning issues // have isAllNewStringInterned ??? //TODO handling surrogate pairs: http://www.unicode.org/unicode/faq/utf_bom.html#6 //TODO review code for use of bufAbsoluteStart when keeping pos between next()/fillBuf() /** * Absolutely minimal implementation of XMLPULL V1 API. Encoding handling done with XmlReader * * @see org.codehaus.plexus.util.xml.XmlReader * @author Aleksander Slominski */ public class MXParser implements XmlPullParser { //NOTE: no interning of those strings --> by Java leng spec they MUST be already interned protected final static String XML_URI = "http://www.w3.org/XML/1998/namespace"; protected final static String XMLNS_URI = "http://www.w3.org/2000/xmlns/"; protected final static String FEATURE_XML_ROUNDTRIP= //"http://xmlpull.org/v1/doc/features.html#xml-roundtrip"; "http://xmlpull.org/v1/doc/features.html#xml-roundtrip"; protected final static String FEATURE_NAMES_INTERNED = "http://xmlpull.org/v1/doc/features.html#names-interned"; protected final static String PROPERTY_XMLDECL_VERSION = "http://xmlpull.org/v1/doc/properties.html#xmldecl-version"; protected final static String PROPERTY_XMLDECL_STANDALONE = "http://xmlpull.org/v1/doc/properties.html#xmldecl-standalone"; protected final static String PROPERTY_XMLDECL_CONTENT = "http://xmlpull.org/v1/doc/properties.html#xmldecl-content"; protected final static String PROPERTY_LOCATION = "http://xmlpull.org/v1/doc/properties.html#location"; /** * Implementation notice: * the is instance variable that controls if newString() is interning. *

          NOTE: newStringIntern always returns interned strings * and newString MAY return interned String depending on this variable. *

          NOTE: by default in this minimal implementation it is false! */ protected boolean allStringsInterned; protected void resetStringCache() { //System.out.println("resetStringCache() minimum called"); } protected String newString(char[] cbuf, int off, int len) { return new String(cbuf, off, len); } protected String newStringIntern(char[] cbuf, int off, int len) { return (new String(cbuf, off, len)).intern(); } private static final boolean TRACE_SIZING = false; // NOTE: features are not resetable and typically defaults to false ... protected boolean processNamespaces; protected boolean roundtripSupported; // global parser state protected String location; protected int lineNumber; protected int columnNumber; protected boolean seenRoot; protected boolean reachedEnd; protected int eventType; protected boolean emptyElementTag; // element stack protected int depth; protected char[] elRawName[]; protected int elRawNameEnd[]; protected int elRawNameLine[]; protected String elName[]; protected String elPrefix[]; protected String elUri[]; //protected String elValue[]; protected int elNamespaceCount[]; /** * Make sure that we have enough space to keep element stack if passed size. * It will always create one additional slot then current depth */ protected void ensureElementsCapacity() { final int elStackSize = elName != null ? elName.length : 0; if( (depth + 1) >= elStackSize) { // we add at least one extra slot ... final int newSize = (depth >= 7 ? 2 * depth : 8) + 2; // = lucky 7 + 1 //25 if(TRACE_SIZING) { System.err.println("TRACE_SIZING elStackSize "+elStackSize+" ==> "+newSize); } final boolean needsCopying = elStackSize > 0; String[] arr = null; // resue arr local variable slot arr = new String[newSize]; if(needsCopying) System.arraycopy(elName, 0, arr, 0, elStackSize); elName = arr; arr = new String[newSize]; if(needsCopying) System.arraycopy(elPrefix, 0, arr, 0, elStackSize); elPrefix = arr; arr = new String[newSize]; if(needsCopying) System.arraycopy(elUri, 0, arr, 0, elStackSize); elUri = arr; int[] iarr = new int[newSize]; if(needsCopying) { System.arraycopy(elNamespaceCount, 0, iarr, 0, elStackSize); } else { // special initialization iarr[0] = 0; } elNamespaceCount = iarr; //TODO: avoid using element raw name ... iarr = new int[newSize]; if(needsCopying) { System.arraycopy(elRawNameEnd, 0, iarr, 0, elStackSize); } elRawNameEnd = iarr; iarr = new int[newSize]; if(needsCopying) { System.arraycopy(elRawNameLine, 0, iarr, 0, elStackSize); } elRawNameLine = iarr; final char[][] carr = new char[newSize][]; if(needsCopying) { System.arraycopy(elRawName, 0, carr, 0, elStackSize); } elRawName = carr; // arr = new String[newSize]; // if(needsCopying) System.arraycopy(elLocalName, 0, arr, 0, elStackSize); // elLocalName = arr; // arr = new String[newSize]; // if(needsCopying) System.arraycopy(elDefaultNs, 0, arr, 0, elStackSize); // elDefaultNs = arr; // int[] iarr = new int[newSize]; // if(needsCopying) System.arraycopy(elNsStackPos, 0, iarr, 0, elStackSize); // for (int i = elStackSize; i < iarr.length; i++) // { // iarr[i] = (i > 0) ? -1 : 0; // } // elNsStackPos = iarr; //assert depth < elName.length; } } // attribute stack protected int attributeCount; protected String attributeName[]; protected int attributeNameHash[]; //protected int attributeNameStart[]; //protected int attributeNameEnd[]; protected String attributePrefix[]; protected String attributeUri[]; protected String attributeValue[]; //protected int attributeValueStart[]; //protected int attributeValueEnd[]; /** * Make sure that in attributes temporary array is enough space. */ protected void ensureAttributesCapacity(int size) { final int attrPosSize = attributeName != null ? attributeName.length : 0; if(size >= attrPosSize) { final int newSize = size > 7 ? 2 * size : 8; // = lucky 7 + 1 //25 if(TRACE_SIZING) { System.err.println("TRACE_SIZING attrPosSize "+attrPosSize+" ==> "+newSize); } final boolean needsCopying = attrPosSize > 0; String[] arr = null; arr = new String[newSize]; if(needsCopying) System.arraycopy(attributeName, 0, arr, 0, attrPosSize); attributeName = arr; arr = new String[newSize]; if(needsCopying) System.arraycopy(attributePrefix, 0, arr, 0, attrPosSize); attributePrefix = arr; arr = new String[newSize]; if(needsCopying) System.arraycopy(attributeUri, 0, arr, 0, attrPosSize); attributeUri = arr; arr = new String[newSize]; if(needsCopying) System.arraycopy(attributeValue, 0, arr, 0, attrPosSize); attributeValue = arr; if( ! allStringsInterned ) { final int[] iarr = new int[newSize]; if(needsCopying) System.arraycopy(attributeNameHash, 0, iarr, 0, attrPosSize); attributeNameHash = iarr; } arr = null; // //assert attrUri.length > size } } // namespace stack protected int namespaceEnd; protected String namespacePrefix[]; protected int namespacePrefixHash[]; protected String namespaceUri[]; protected void ensureNamespacesCapacity(int size) { final int namespaceSize = namespacePrefix != null ? namespacePrefix.length : 0; if(size >= namespaceSize) { final int newSize = size > 7 ? 2 * size : 8; // = lucky 7 + 1 //25 if(TRACE_SIZING) { System.err.println("TRACE_SIZING namespaceSize "+namespaceSize+" ==> "+newSize); } final String[] newNamespacePrefix = new String[newSize]; final String[] newNamespaceUri = new String[newSize]; if(namespacePrefix != null) { System.arraycopy( namespacePrefix, 0, newNamespacePrefix, 0, namespaceEnd); System.arraycopy( namespaceUri, 0, newNamespaceUri, 0, namespaceEnd); } namespacePrefix = newNamespacePrefix; namespaceUri = newNamespaceUri; if( ! allStringsInterned ) { final int[] newNamespacePrefixHash = new int[newSize]; if(namespacePrefixHash != null) { System.arraycopy( namespacePrefixHash, 0, newNamespacePrefixHash, 0, namespaceEnd); } namespacePrefixHash = newNamespacePrefixHash; } //prefixesSize = newSize; // //assert nsPrefixes.length > size && nsPrefixes.length == newSize } } /** * simplistic implementation of hash function that has constant * time to compute - so it also means diminishing hash quality for long strings * but for XML parsing it should be good enough ... */ protected static final int fastHash( char ch[], int off, int len ) { if(len == 0) return 0; //assert len >0 int hash = ch[off]; // hash at beginning //try { hash = (hash << 7) + ch[ off + len - 1 ]; // hash at the end //} catch(ArrayIndexOutOfBoundsException aie) { // aie.printStackTrace(); //should never happen ... // throw new RuntimeException("this is violation of pre-condition"); //} if(len > 16) hash = (hash << 7) + ch[ off + (len / 4)]; // 1/4 from beginning if(len > 8) hash = (hash << 7) + ch[ off + (len / 2)]; // 1/2 of string size ... // notice that hash is at most done 3 times <<7 so shifted by 21 bits 8 bit value // so max result == 29 bits so it is quite just below 31 bits for long (2^32) ... //assert hash >= 0; return hash; } // entity replacement stack protected int entityEnd; protected String entityName[]; protected char[] entityNameBuf[]; protected String entityReplacement[]; protected char[] entityReplacementBuf[]; protected int entityNameHash[]; private final EntityReplacementMap replacementMapTemplate; protected void ensureEntityCapacity() { final int entitySize = entityReplacementBuf != null ? entityReplacementBuf.length : 0; if(entityEnd >= entitySize) { final int newSize = entityEnd > 7 ? 2 * entityEnd : 8; // = lucky 7 + 1 //25 if(TRACE_SIZING) { System.err.println("TRACE_SIZING entitySize "+entitySize+" ==> "+newSize); } final String[] newEntityName = new String[newSize]; final char[] newEntityNameBuf[] = new char[newSize][]; final String[] newEntityReplacement = new String[newSize]; final char[] newEntityReplacementBuf[] = new char[newSize][]; if(entityName != null) { System.arraycopy(entityName, 0, newEntityName, 0, entityEnd); System.arraycopy(entityNameBuf, 0, newEntityNameBuf, 0, entityEnd); System.arraycopy(entityReplacement, 0, newEntityReplacement, 0, entityEnd); System.arraycopy(entityReplacementBuf, 0, newEntityReplacementBuf, 0, entityEnd); } entityName = newEntityName; entityNameBuf = newEntityNameBuf; entityReplacement = newEntityReplacement; entityReplacementBuf = newEntityReplacementBuf; if( ! allStringsInterned ) { final int[] newEntityNameHash = new int[newSize]; if(entityNameHash != null) { System.arraycopy(entityNameHash, 0, newEntityNameHash, 0, entityEnd); } entityNameHash = newEntityNameHash; } } } // input buffer management protected static final int READ_CHUNK_SIZE = 8*1024; //max data chars in one read() call protected Reader reader; protected String inputEncoding; protected int bufLoadFactor = 95; // 99% //protected int bufHardLimit; // only matters when expanding protected char buf[] = new char[ Runtime.getRuntime().freeMemory() > 1000000L ? READ_CHUNK_SIZE : 256 ]; protected int bufSoftLimit = ( bufLoadFactor * buf.length ) /100; // desirable size of buffer protected boolean preventBufferCompaction; protected int bufAbsoluteStart; // this is buf protected int bufStart; protected int bufEnd; protected int pos; protected int posStart; protected int posEnd; protected char pc[] = new char[ Runtime.getRuntime().freeMemory() > 1000000L ? READ_CHUNK_SIZE : 64 ]; protected int pcStart; protected int pcEnd; // parsing state //protected boolean needsMore; //protected boolean seenMarkup; protected boolean usePC; protected boolean seenStartTag; protected boolean seenEndTag; protected boolean pastEndTag; protected boolean seenAmpersand; protected boolean seenMarkup; protected boolean seenDocdecl; // transient variable set during each call to next/Token() protected boolean tokenize; protected String text; protected String entityRefName; protected String xmlDeclVersion; protected Boolean xmlDeclStandalone; protected String xmlDeclContent; protected void reset() { //System.out.println("reset() called"); location = null; lineNumber = 1; columnNumber = 0; seenRoot = false; reachedEnd = false; eventType = START_DOCUMENT; emptyElementTag = false; depth = 0; attributeCount = 0; namespaceEnd = 0; entityEnd = 0; setupFromTemplate(); reader = null; inputEncoding = null; preventBufferCompaction = false; bufAbsoluteStart = 0; bufEnd = bufStart = 0; pos = posStart = posEnd = 0; pcEnd = pcStart = 0; usePC = false; seenStartTag = false; seenEndTag = false; pastEndTag = false; seenAmpersand = false; seenMarkup = false; seenDocdecl = false; xmlDeclVersion = null; xmlDeclStandalone = null; xmlDeclContent = null; resetStringCache(); } public MXParser() { replacementMapTemplate = null; } public MXParser(EntityReplacementMap entityReplacementMap){ this.replacementMapTemplate = entityReplacementMap; } public void setupFromTemplate() { if ( replacementMapTemplate != null){ int length = replacementMapTemplate.entityEnd; // This is a bit cheeky, since the EntityReplacementMap contains exact-sized arrays, // and elements are always added to the array, we can use the array from the template. // Kids; dont do this at home. entityName = replacementMapTemplate.entityName; entityNameBuf = replacementMapTemplate.entityNameBuf; entityReplacement = replacementMapTemplate.entityReplacement; entityReplacementBuf = replacementMapTemplate.entityReplacementBuf; entityNameHash = replacementMapTemplate.entityNameHash; entityEnd = length; } } /** * Method setFeature * * @param name a String * @param state a boolean * * @throws XmlPullParserException * */ public void setFeature(String name, boolean state) throws XmlPullParserException { if(name == null) throw new IllegalArgumentException("feature name should not be null"); if(FEATURE_PROCESS_NAMESPACES.equals(name)) { if(eventType != START_DOCUMENT) throw new XmlPullParserException( "namespace processing feature can only be changed before parsing", this, null); processNamespaces = state; // } else if(FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name)) { // if(type != START_DOCUMENT) throw new XmlPullParserException( // "namespace reporting feature can only be changed before parsing", this, null); // reportNsAttribs = state; } else if(FEATURE_NAMES_INTERNED.equals(name)) { if(state != false) { throw new XmlPullParserException( "interning names in this implementation is not supported"); } } else if(FEATURE_PROCESS_DOCDECL.equals(name)) { if(state != false) { throw new XmlPullParserException( "processing DOCDECL is not supported"); } //} else if(REPORT_DOCDECL.equals(name)) { // paramNotifyDoctype = state; } else if(FEATURE_XML_ROUNDTRIP.equals(name)) { //if(state == false) { // throw new XmlPullParserException( // "roundtrip feature can not be switched off"); //} roundtripSupported = state; } else { throw new XmlPullParserException("unsupporte feature "+name); } } /** Unknown properties are always returned as false */ public boolean getFeature(String name) { if(name == null) throw new IllegalArgumentException("feature name should not be nulll"); if(FEATURE_PROCESS_NAMESPACES.equals(name)) { return processNamespaces; // } else if(FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name)) { // return reportNsAttribs; } else if(FEATURE_NAMES_INTERNED.equals(name)) { return false; } else if(FEATURE_PROCESS_DOCDECL.equals(name)) { return false; //} else if(REPORT_DOCDECL.equals(name)) { // return paramNotifyDoctype; } else if(FEATURE_XML_ROUNDTRIP.equals(name)) { //return true; return roundtripSupported; } return false; } public void setProperty(String name, Object value) throws XmlPullParserException { if(PROPERTY_LOCATION.equals(name)) { location = (String) value; } else { throw new XmlPullParserException("unsupported property: '"+name+"'"); } } public Object getProperty(String name) { if(name == null) throw new IllegalArgumentException("property name should not be nulll"); if(PROPERTY_XMLDECL_VERSION.equals(name)) { return xmlDeclVersion; } else if(PROPERTY_XMLDECL_STANDALONE.equals(name)) { return xmlDeclStandalone; } else if(PROPERTY_XMLDECL_CONTENT.equals(name)) { return xmlDeclContent; } else if(PROPERTY_LOCATION.equals(name)) { return location; } return null; } public void setInput(Reader in) throws XmlPullParserException { reset(); reader = in; } public void setInput(java.io.InputStream inputStream, String inputEncoding) throws XmlPullParserException { if(inputStream == null) { throw new IllegalArgumentException("input stream can not be null"); } Reader reader; try { if(inputEncoding != null) { reader = ReaderFactory.newReader(inputStream, inputEncoding); } else { reader = ReaderFactory.newXmlReader(inputStream); } } catch (UnsupportedEncodingException une) { throw new XmlPullParserException( "could not create reader for encoding "+inputEncoding+" : "+une, this, une); } catch ( IOException e ) { throw new XmlPullParserException( "could not create reader : "+e, this, e); } setInput(reader); //must be here as reset() was called in setInput() and has set this.inputEncoding to null ... this.inputEncoding = inputEncoding; } public String getInputEncoding() { return inputEncoding; } public void defineEntityReplacementText(String entityName, String replacementText) throws XmlPullParserException { // throw new XmlPullParserException("not allowed"); if ( !replacementText.startsWith( "&#" ) && this.entityName != null && replacementText.length() > 1 ) { String tmp = replacementText.substring( 1, replacementText.length() - 1 ); for ( int i = 0; i < this.entityName.length; i++ ) { if ( this.entityName[i] != null && this.entityName[i].equals( tmp ) ) { replacementText = this.entityReplacement[i]; } } } //protected char[] entityReplacement[]; ensureEntityCapacity(); // this is to make sure that if interning works we will take advantage of it ... char[] entityNameCharData = entityName.toCharArray(); this.entityName[entityEnd] = newString( entityNameCharData, 0, entityName.length()); entityNameBuf[entityEnd] = entityNameCharData; entityReplacement[entityEnd] = replacementText; entityReplacementBuf[entityEnd] = replacementText.toCharArray(); if(!allStringsInterned) { entityNameHash[ entityEnd ] = fastHash(entityNameBuf[entityEnd], 0, entityNameBuf[entityEnd].length); } ++entityEnd; //TODO disallow < or & in entity replacement text (or ]]>???) // TOOD keepEntityNormalizedForAttributeValue cached as well ... } public int getNamespaceCount(int depth) throws XmlPullParserException { if(processNamespaces == false || depth == 0) { return 0; } //int maxDepth = eventType == END_TAG ? this.depth + 1 : this.depth; //if(depth < 0 || depth > maxDepth) throw new IllegalArgumentException( if(depth < 0 || depth > this.depth) throw new IllegalArgumentException( "napespace count mayt be for depth 0.."+this.depth+" not "+depth); return elNamespaceCount[ depth ]; } public String getNamespacePrefix(int pos) throws XmlPullParserException { //int end = eventType == END_TAG ? elNamespaceCount[ depth + 1 ] : namespaceEnd; //if(pos < end) { if(pos < namespaceEnd) { return namespacePrefix[ pos ]; } else { throw new XmlPullParserException( "position "+pos+" exceeded number of available namespaces "+namespaceEnd); } } public String getNamespaceUri(int pos) throws XmlPullParserException { //int end = eventType == END_TAG ? elNamespaceCount[ depth + 1 ] : namespaceEnd; //if(pos < end) { if(pos < namespaceEnd) { return namespaceUri[ pos ]; } else { throw new XmlPullParserException( "position "+pos+" exceedded number of available namespaces "+namespaceEnd); } } public String getNamespace( String prefix ) //throws XmlPullParserException { //int count = namespaceCount[ depth ]; if(prefix != null) { for( int i = namespaceEnd -1; i >= 0; i--) { if( prefix.equals( namespacePrefix[ i ] ) ) { return namespaceUri[ i ]; } } if("xml".equals( prefix )) { return XML_URI; } else if("xmlns".equals( prefix )) { return XMLNS_URI; } } else { for( int i = namespaceEnd -1; i >= 0; i--) { if( namespacePrefix[ i ] == null) { //"") { //null ) { //TODO check FIXME Alek return namespaceUri[ i ]; } } } return null; } public int getDepth() { return depth; } private static int findFragment(int bufMinPos, char[] b, int start, int end) { //System.err.println("bufStart="+bufStart+" b="+printable(new String(b, start, end - start))+" start="+start+" end="+end); if(start < bufMinPos) { start = bufMinPos; if(start > end) start = end; return start; } if(end - start > 65) { start = end - 10; // try to find good location } int i = start + 1; while(--i > bufMinPos) { if((end - i) > 65) break; final char c = b[i]; if(c == '<' && (start - i) > 10) break; } return i; } /** * Return string describing current position of parsers as * text 'STATE [seen %s...] @line:column'. */ public String getPositionDescription () { String fragment = null; if(posStart <= pos) { final int start = findFragment(0, buf, posStart, pos); //System.err.println("start="+start); if(start < pos) { fragment = new String(buf, start, pos - start); } if(bufAbsoluteStart > 0 || start > 0) fragment = "..." + fragment; } // return " at line "+tokenizerPosRow // +" and column "+(tokenizerPosCol-1) // +(fragment != null ? " seen "+printable(fragment)+"..." : ""); return " "+TYPES[ eventType ] + (fragment != null ? " seen "+printable(fragment)+"..." : "") +" "+(location != null ? location : "") +"@"+getLineNumber()+":"+getColumnNumber(); } public int getLineNumber() { return lineNumber; } public int getColumnNumber() { return columnNumber; } public boolean isWhitespace() throws XmlPullParserException { if(eventType == TEXT || eventType == CDSECT) { if(usePC) { for (int i = pcStart; i = 0; i--) { // if( prefix.equals( namespacePrefix[ i ] ) ) { // return namespaceUri[ i ]; // } // } // } else { // for( int i = namespaceEnd -1; i >= 0; i--) { // if( namespacePrefix[ i ] == null ) { // return namespaceUri[ i ]; // } // } // // } // return ""; } public String getName() { if(eventType == START_TAG) { //return elName[ depth - 1 ] ; return elName[ depth ] ; } else if(eventType == END_TAG) { return elName[ depth ] ; } else if(eventType == ENTITY_REF) { if(entityRefName == null) { entityRefName = newString(buf, posStart, posEnd - posStart); } return entityRefName; } else { return null; } } public String getPrefix() { if(eventType == START_TAG) { //return elPrefix[ depth - 1 ] ; return elPrefix[ depth ] ; } else if(eventType == END_TAG) { return elPrefix[ depth ] ; } return null; // if(eventType != START_TAG && eventType != END_TAG) return null; // int maxDepth = eventType == END_TAG ? depth : depth - 1; // return elPrefix[ maxDepth ]; } public boolean isEmptyElementTag() throws XmlPullParserException { if(eventType != START_TAG) throw new XmlPullParserException( "parser must be on START_TAG to check for empty element", this, null); return emptyElementTag; } public int getAttributeCount() { if(eventType != START_TAG) return -1; return attributeCount; } public String getAttributeNamespace(int index) { if(eventType != START_TAG) throw new IndexOutOfBoundsException( "only START_TAG can have attributes"); if(processNamespaces == false) return NO_NAMESPACE; if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException( "attribute position must be 0.."+(attributeCount-1)+" and not "+index); return attributeUri[ index ]; } public String getAttributeName(int index) { if(eventType != START_TAG) throw new IndexOutOfBoundsException( "only START_TAG can have attributes"); if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException( "attribute position must be 0.."+(attributeCount-1)+" and not "+index); return attributeName[ index ]; } public String getAttributePrefix(int index) { if(eventType != START_TAG) throw new IndexOutOfBoundsException( "only START_TAG can have attributes"); if(processNamespaces == false) return null; if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException( "attribute position must be 0.."+(attributeCount-1)+" and not "+index); return attributePrefix[ index ]; } public String getAttributeType(int index) { if(eventType != START_TAG) throw new IndexOutOfBoundsException( "only START_TAG can have attributes"); if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException( "attribute position must be 0.."+(attributeCount-1)+" and not "+index); return "CDATA"; } public boolean isAttributeDefault(int index) { if(eventType != START_TAG) throw new IndexOutOfBoundsException( "only START_TAG can have attributes"); if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException( "attribute position must be 0.."+(attributeCount-1)+" and not "+index); return false; } public String getAttributeValue(int index) { if(eventType != START_TAG) throw new IndexOutOfBoundsException( "only START_TAG can have attributes"); if(index < 0 || index >= attributeCount) throw new IndexOutOfBoundsException( "attribute position must be 0.."+(attributeCount-1)+" and not "+index); return attributeValue[ index ]; } public String getAttributeValue(String namespace, String name) { if(eventType != START_TAG) throw new IndexOutOfBoundsException( "only START_TAG can have attributes"+getPositionDescription()); if(name == null) { throw new IllegalArgumentException("attribute name can not be null"); } // TODO make check if namespace is interned!!! etc. for names!!! if(processNamespaces) { if(namespace == null) { namespace = ""; } for(int i = 0; i < attributeCount; ++i) { if((namespace == attributeUri[ i ] || namespace.equals(attributeUri[ i ]) ) //(namespace != null && namespace.equals(attributeUri[ i ])) // taking advantage of String.intern() && name.equals(attributeName[ i ]) ) { return attributeValue[i]; } } } else { if(namespace != null && namespace.length() == 0) { namespace = null; } if(namespace != null) throw new IllegalArgumentException( "when namespaces processing is disabled attribute namespace must be null"); for(int i = 0; i < attributeCount; ++i) { if(name.equals(attributeName[i])) { return attributeValue[i]; } } } return null; } public int getEventType() throws XmlPullParserException { return eventType; } public void require(int type, String namespace, String name) throws XmlPullParserException, IOException { if(processNamespaces == false && namespace != null) { throw new XmlPullParserException( "processing namespaces must be enabled on parser (or factory)"+ " to have possible namespaces delcared on elements" +(" (postion:"+ getPositionDescription())+")"); } if (type != getEventType() || (namespace != null && !namespace.equals (getNamespace())) || (name != null && !name.equals (getName ())) ) { throw new XmlPullParserException ( "expected event "+TYPES[ type ] +(name != null ? " with name '"+name+"'" : "") +(namespace != null && name != null ? " and" : "") +(namespace != null ? " with namespace '"+namespace+"'" : "") +" but got" +(type != getEventType() ? " "+TYPES[ getEventType() ] : "") +(name != null && getName() != null && !name.equals (getName ()) ? " name '"+getName()+"'" : "") +(namespace != null && name != null && getName() != null && !name.equals (getName ()) && getNamespace() != null && !namespace.equals (getNamespace()) ? " and" : "") +(namespace != null && getNamespace() != null && !namespace.equals (getNamespace()) ? " namespace '"+getNamespace()+"'" : "") +(" (postion:"+ getPositionDescription())+")"); } } /** * Skip sub tree that is currently porser positioned on. *
          NOTE: parser must be on START_TAG and when funtion returns * parser will be positioned on corresponding END_TAG */ public void skipSubTree() throws XmlPullParserException, IOException { require(START_TAG, null, null); int level = 1; while(level > 0) { int eventType = next(); if(eventType == END_TAG) { --level; } else if(eventType == START_TAG) { ++level; } } } // public String readText() throws XmlPullParserException, IOException // { // if (getEventType() != TEXT) return ""; // String result = getText(); // next(); // return result; // } public String nextText() throws XmlPullParserException, IOException { // String result = null; // boolean onStartTag = false; // if(eventType == START_TAG) { // onStartTag = true; // next(); // } // if(eventType == TEXT) { // result = getText(); // next(); // } else if(onStartTag && eventType == END_TAG) { // result = ""; // } else { // throw new XmlPullParserException( // "parser must be on START_TAG or TEXT to read text", this, null); // } // if(eventType != END_TAG) { // throw new XmlPullParserException( // "event TEXT it must be immediately followed by END_TAG", this, null); // } // return result; if(getEventType() != START_TAG) { throw new XmlPullParserException( "parser must be on START_TAG to read next text", this, null); } int eventType = next(); if(eventType == TEXT) { final String result = getText(); eventType = next(); if(eventType != END_TAG) { throw new XmlPullParserException( "TEXT must be immediately followed by END_TAG and not " +TYPES[ getEventType() ], this, null); } return result; } else if(eventType == END_TAG) { return ""; } else { throw new XmlPullParserException( "parser must be on START_TAG or TEXT to read text", this, null); } } public int nextTag() throws XmlPullParserException, IOException { next(); if(eventType == TEXT && isWhitespace()) { // skip whitespace next(); } if (eventType != START_TAG && eventType != END_TAG) { throw new XmlPullParserException("expected START_TAG or END_TAG not " +TYPES[ getEventType() ], this, null); } return eventType; } public int next() throws XmlPullParserException, IOException { tokenize = false; return nextImpl(); } public int nextToken() throws XmlPullParserException, IOException { tokenize = true; return nextImpl(); } protected int nextImpl() throws XmlPullParserException, IOException { text = null; pcEnd = pcStart = 0; usePC = false; bufStart = posEnd; if(pastEndTag) { pastEndTag = false; --depth; namespaceEnd = elNamespaceCount[ depth ]; // less namespaces available } if(emptyElementTag) { emptyElementTag = false; pastEndTag = true; return eventType = END_TAG; } // [1] document ::= prolog element Misc* if(depth > 0) { if(seenStartTag) { seenStartTag = false; return eventType = parseStartTag(); } if(seenEndTag) { seenEndTag = false; return eventType = parseEndTag(); } // ASSUMPTION: we are _on_ first character of content or markup!!!! // [43] content ::= CharData? ((element | Reference | CDSect | PI | Comment) CharData?)* char ch; if(seenMarkup) { // we have read ahead ... seenMarkup = false; ch = '<'; } else if(seenAmpersand) { seenAmpersand = false; ch = '&'; } else { ch = more(); } posStart = pos - 1; // VERY IMPORTANT: this is correct start of event!!! // when true there is some potential event TEXT to return - keep gathering boolean hadCharData = false; // when true TEXT data is not continuous (like ) and requires PC merging boolean needsMerging = false; MAIN_LOOP: while(true) { // work on MARKUP if(ch == '<') { if(hadCharData) { //posEnd = pos - 1; if(tokenize) { seenMarkup = true; return eventType = TEXT; } } ch = more(); if(ch == '/') { if(!tokenize && hadCharData) { seenEndTag = true; //posEnd = pos - 2; return eventType = TEXT; } return eventType = parseEndTag(); } else if(ch == '!') { ch = more(); if(ch == '-') { // note: if(tokenize == false) posStart/End is NOT changed!!!! parseComment(); if(tokenize) return eventType = COMMENT; if( !usePC && hadCharData ) { needsMerging = true; } else { posStart = pos; //completely ignore comment } } else if(ch == '[') { //posEnd = pos - 3; // must remember previous posStart/End as it merges with content of CDATA //int oldStart = posStart + bufAbsoluteStart; //int oldEnd = posEnd + bufAbsoluteStart; parseCDSect(hadCharData); if(tokenize) return eventType = CDSECT; final int cdStart = posStart; final int cdEnd = posEnd; final int cdLen = cdEnd - cdStart; if(cdLen > 0) { // was there anything inside CDATA section? hadCharData = true; if(!usePC) { needsMerging = true; } } // posStart = oldStart; // posEnd = oldEnd; // if(cdLen > 0) { // was there anything inside CDATA section? // if(hadCharData) { // // do merging if there was anything in CDSect!!!! // // if(!usePC) { // // // posEnd is correct already!!! // // if(posEnd > posStart) { // // joinPC(); // // } else { // // usePC = true; // // pcStart = pcEnd = 0; // // } // // } // // if(pcEnd + cdLen >= pc.length) ensurePC(pcEnd + cdLen); // // // copy [cdStart..cdEnd) into PC // // System.arraycopy(buf, cdStart, pc, pcEnd, cdLen); // // pcEnd += cdLen; // if(!usePC) { // needsMerging = true; // posStart = cdStart; // posEnd = cdEnd; // } // } else { // if(!usePC) { // needsMerging = true; // posStart = cdStart; // posEnd = cdEnd; // hadCharData = true; // } // } // //hadCharData = true; // } else { // if( !usePC && hadCharData ) { // needsMerging = true; // } // } } else { throw new XmlPullParserException( "unexpected character in markup "+printable(ch), this, null); } } else if(ch == '?') { parsePI(); if(tokenize) return eventType = PROCESSING_INSTRUCTION; if( !usePC && hadCharData ) { needsMerging = true; } else { posStart = pos; //completely ignore PI } } else if( isNameStartChar(ch) ) { if(!tokenize && hadCharData) { seenStartTag = true; //posEnd = pos - 2; return eventType = TEXT; } return eventType = parseStartTag(); } else { throw new XmlPullParserException( "unexpected character in markup "+printable(ch), this, null); } // do content comapctation if it makes sense!!!! } else if(ch == '&') { // work on ENTITTY //posEnd = pos - 1; if(tokenize && hadCharData) { seenAmpersand = true; return eventType = TEXT; } final int oldStart = posStart + bufAbsoluteStart; final int oldEnd = posEnd + bufAbsoluteStart; final char[] resolvedEntity = parseEntityRef(); if(tokenize) return eventType = ENTITY_REF; // check if replacement text can be resolved !!! if(resolvedEntity == null) { if(entityRefName == null) { entityRefName = newString(buf, posStart, posEnd - posStart); } throw new XmlPullParserException( "could not resolve entity named '"+printable(entityRefName)+"'", this, null); } //int entStart = posStart; //int entEnd = posEnd; posStart = oldStart - bufAbsoluteStart; posEnd = oldEnd - bufAbsoluteStart; if(!usePC) { if(hadCharData) { joinPC(); // posEnd is already set correctly!!! needsMerging = false; } else { usePC = true; pcStart = pcEnd = 0; } } //assert usePC == true; // write into PC replacement text - do merge for replacement text!!!! for ( char aResolvedEntity : resolvedEntity ) { if ( pcEnd >= pc.length ) { ensurePC( pcEnd ); } pc[pcEnd++] = aResolvedEntity; } hadCharData = true; //assert needsMerging == false; } else { if(needsMerging) { //assert usePC == false; joinPC(); // posEnd is already set correctly!!! //posStart = pos - 1; needsMerging = false; } //no MARKUP not ENTITIES so work on character data ... // [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*) hadCharData = true; boolean normalizedCR = false; final boolean normalizeInput = tokenize == false || roundtripSupported == false; // use loop locality here!!!! boolean seenBracket = false; boolean seenBracketBracket = false; do { // check that ]]> does not show in if(ch == ']') { if(seenBracket) { seenBracketBracket = true; } else { seenBracket = true; } } else if(seenBracketBracket && ch == '>') { throw new XmlPullParserException( "characters ]]> are not allowed in content", this, null); } else { if(seenBracket) { seenBracketBracket = seenBracket = false; } // assert seenTwoBrackets == seenBracket == false; } if(normalizeInput) { // deal with normalization issues ... if(ch == '\r') { normalizedCR = true; posEnd = pos -1; // posEnd is already set if(!usePC) { if(posEnd > posStart) { joinPC(); } else { usePC = true; pcStart = pcEnd = 0; } } //assert usePC == true; if(pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } else if(ch == '\n') { // if(!usePC) { joinPC(); } else { if(pcEnd >= pc.length) ensurePC(); } if(!normalizedCR && usePC) { if(pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } normalizedCR = false; } else { if(usePC) { if(pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = ch; } normalizedCR = false; } } ch = more(); } while(ch != '<' && ch != '&'); posEnd = pos - 1; continue MAIN_LOOP; // skip ch = more() from below - we are already ahead ... } ch = more(); } // endless while(true) } else { if(seenRoot) { return parseEpilog(); } else { return parseProlog(); } } } protected int parseProlog() throws XmlPullParserException, IOException { // [2] prolog: ::= XMLDecl? Misc* (doctypedecl Misc*)? and look for [39] element char ch; if(seenMarkup) { ch = buf[ pos - 1 ]; } else { ch = more(); } if(eventType == START_DOCUMENT) { // bootstrap parsing with getting first character input! // deal with BOM // detect BOM and crop it (Unicode int Order Mark) if(ch == '\uFFFE') { throw new XmlPullParserException( "first character in input was UNICODE noncharacter (0xFFFE)"+ "- input requires int swapping", this, null); } if(ch == '\uFEFF') { // skipping UNICODE int Order Mark (so called BOM) ch = more(); } } seenMarkup = false; boolean gotS = false; posStart = pos - 1; final boolean normalizeIgnorableWS = tokenize == true && roundtripSupported == false; boolean normalizedCR = false; while(true) { // deal with Misc // [27] Misc ::= Comment | PI | S // deal with docdecl --> mark it! // else parseStartTag seen <[^/] if(ch == '<') { if(gotS && tokenize) { posEnd = pos - 1; seenMarkup = true; return eventType = IGNORABLE_WHITESPACE; } ch = more(); if(ch == '?') { // check if it is 'xml' // deal with XMLDecl boolean isXMLDecl = parsePI(); if(tokenize) { if (isXMLDecl) { return eventType = START_DOCUMENT; } return eventType = PROCESSING_INSTRUCTION; } } else if(ch == '!') { ch = more(); if(ch == 'D') { if(seenDocdecl) { throw new XmlPullParserException( "only one docdecl allowed in XML document", this, null); } seenDocdecl = true; parseDocdecl(); if(tokenize) return eventType = DOCDECL; } else if(ch == '-') { parseComment(); if(tokenize) return eventType = COMMENT; } else { throw new XmlPullParserException( "unexpected markup posStart) { joinPC(); } else { usePC = true; pcStart = pcEnd = 0; } } //assert usePC == true; if(pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } else if(ch == '\n') { if(!normalizedCR && usePC) { if(pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } normalizedCR = false; } else { if(usePC) { if(pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = ch; } normalizedCR = false; } } } else { throw new XmlPullParserException( "only whitespace content allowed before start tag and not "+printable(ch), this, null); } ch = more(); } } protected int parseEpilog() throws XmlPullParserException, IOException { if(eventType == END_DOCUMENT) { throw new XmlPullParserException("already reached end of XML input", this, null); } if(reachedEnd) { return eventType = END_DOCUMENT; } boolean gotS = false; final boolean normalizeIgnorableWS = tokenize == true && roundtripSupported == false; boolean normalizedCR = false; try { // epilog: Misc* char ch; if(seenMarkup) { ch = buf[ pos - 1 ]; } else { ch = more(); } seenMarkup = false; posStart = pos - 1; if(!reachedEnd) { while(true) { // deal with Misc // [27] Misc ::= Comment | PI | S if(ch == '<') { if(gotS && tokenize) { posEnd = pos - 1; seenMarkup = true; return eventType = IGNORABLE_WHITESPACE; } ch = more(); if(reachedEnd) { break; } if(ch == '?') { // check if it is 'xml' // deal with XMLDecl parsePI(); if(tokenize) return eventType = PROCESSING_INSTRUCTION; } else if(ch == '!') { ch = more(); if(reachedEnd) { break; } if(ch == 'D') { parseDocdecl(); //FIXME if(tokenize) return eventType = DOCDECL; } else if(ch == '-') { parseComment(); if(tokenize) return eventType = COMMENT; } else { throw new XmlPullParserException( "unexpected markup posStart) { joinPC(); } else { usePC = true; pcStart = pcEnd = 0; } } //assert usePC == true; if(pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } else if(ch == '\n') { if(!normalizedCR && usePC) { if(pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } normalizedCR = false; } else { if(usePC) { if(pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = ch; } normalizedCR = false; } } } else { throw new XmlPullParserException( "in epilog non whitespace content is not allowed but got "+printable(ch), this, null); } ch = more(); if(reachedEnd) { break; } } } // throw Exception("unexpected content in epilog // catch EOFException return END_DOCUMENT //try { } catch(EOFException ex) { reachedEnd = true; } if(reachedEnd) { if(tokenize && gotS) { posEnd = pos; // well - this is LAST available character pos return eventType = IGNORABLE_WHITESPACE; } return eventType = END_DOCUMENT; } else { throw new XmlPullParserException("internal error in parseEpilog"); } } public int parseEndTag() throws XmlPullParserException, IOException { //ASSUMPTION ch is past "' char ch = more(); if(!isNameStartChar(ch)) { throw new XmlPullParserException( "expected name start and not "+printable(ch), this, null); } posStart = pos - 3; final int nameStart = pos - 1 + bufAbsoluteStart; do { ch = more(); } while(isNameChar(ch)); // now we go one level down -- do checks //--depth; //FIXME // check that end tag name is the same as start tag //String name = new String(buf, nameStart - bufAbsoluteStart, // (pos - 1) - (nameStart - bufAbsoluteStart)); //int last = pos - 1; int off = nameStart - bufAbsoluteStart; //final int len = last - off; final int len = (pos - 1) - off; final char[] cbuf = elRawName[depth]; if(elRawNameEnd[depth] != len) { // construct strings for exception final String startname = new String(cbuf, 0, elRawNameEnd[depth]); final String endname = new String(buf, off, len); throw new XmlPullParserException( "end tag name must match start tag name <"+startname+">" +" from line "+elRawNameLine[depth], this, null); } for (int i = 0; i < len; i++) { if(buf[off++] != cbuf[i]) { // construct strings for exception final String startname = new String(cbuf, 0, len); final String endname = new String(buf, off - i - 1, len); throw new XmlPullParserException( "end tag name must be the same as start tag <"+startname+">" +" from line "+elRawNameLine[depth], this, null); } } while(isS(ch)) { ch = more(); } // skip additional white spaces if(ch != '>') { throw new XmlPullParserException( "expected > to finsh end tag not "+printable(ch) +" from line "+elRawNameLine[depth], this, null); } //namespaceEnd = elNamespaceCount[ depth ]; //FIXME posEnd = pos; pastEndTag = true; return eventType = END_TAG; } public int parseStartTag() throws XmlPullParserException, IOException { //ASSUMPTION ch is past ' // [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>' ++depth; //FIXME posStart = pos - 2; emptyElementTag = false; attributeCount = 0; // retrieve name final int nameStart = pos - 1 + bufAbsoluteStart; int colonPos = -1; char ch = buf[ pos - 1]; if(ch == ':' && processNamespaces) throw new XmlPullParserException( "when namespaces processing enabled colon can not be at element name start", this, null); while(true) { ch = more(); if(!isNameChar(ch)) break; if(ch == ':' && processNamespaces) { if(colonPos != -1) throw new XmlPullParserException( "only one colon is allowed in name of element when namespaces are enabled", this, null); colonPos = pos - 1 + bufAbsoluteStart; } } // retrieve name ensureElementsCapacity(); //TODO check for efficient interning and then use elRawNameInterned!!!! int elLen = (pos - 1) - (nameStart - bufAbsoluteStart); if(elRawName[ depth ] == null || elRawName[ depth ].length < elLen) { elRawName[ depth ] = new char[ 2 * elLen ]; } System.arraycopy(buf, nameStart - bufAbsoluteStart, elRawName[ depth ], 0, elLen); elRawNameEnd[ depth ] = elLen; elRawNameLine[ depth ] = lineNumber; String name = null; // work on prefixes and namespace URI String prefix = null; if(processNamespaces) { if(colonPos != -1) { prefix = elPrefix[ depth ] = newString(buf, nameStart - bufAbsoluteStart, colonPos - nameStart); name = elName[ depth ] = newString(buf, colonPos + 1 - bufAbsoluteStart, //(pos -1) - (colonPos + 1)); pos - 2 - (colonPos - bufAbsoluteStart)); } else { prefix = elPrefix[ depth ] = null; name = elName[ depth ] = newString(buf, nameStart - bufAbsoluteStart, elLen); } } else { name = elName[ depth ] = newString(buf, nameStart - bufAbsoluteStart, elLen); } while(true) { while(isS(ch)) { ch = more(); } // skip additional white spaces if(ch == '>') { break; } else if(ch == '/') { if(emptyElementTag) throw new XmlPullParserException( "repeated / in tag declaration", this, null); emptyElementTag = true; ch = more(); if(ch != '>') throw new XmlPullParserException( "expected > to end empty tag not "+printable(ch), this, null); break; } else if(isNameStartChar(ch)) { ch = parseAttribute(); ch = more(); continue; } else { throw new XmlPullParserException( "start tag unexpected character "+printable(ch), this, null); } //ch = more(); // skip space } // now when namespaces were declared we can resolve them if(processNamespaces) { String uri = getNamespace(prefix); if(uri == null) { if(prefix == null) { // no prefix and no uri => use default namespace uri = NO_NAMESPACE; } else { throw new XmlPullParserException( "could not determine namespace bound to element prefix "+prefix, this, null); } } elUri[ depth ] = uri; //String uri = getNamespace(prefix); //if(uri == null && prefix == null) { // no prefix and no uri => use default namespace // uri = ""; //} // resolve attribute namespaces for (int i = 0; i < attributeCount; i++) { final String attrPrefix = attributePrefix[ i ]; if(attrPrefix != null) { final String attrUri = getNamespace(attrPrefix); if(attrUri == null) { throw new XmlPullParserException( "could not determine namespace bound to attribute prefix "+attrPrefix, this, null); } attributeUri[ i ] = attrUri; } else { attributeUri[ i ] = NO_NAMESPACE; } } //TODO //[ WFC: Unique Att Spec ] // check namespaced attribute uniqueness contraint!!! for (int i = 1; i < attributeCount; i++) { for (int j = 0; j < i; j++) { if( attributeUri[j] == attributeUri[i] && (allStringsInterned && attributeName[j].equals(attributeName[i]) || (!allStringsInterned && attributeNameHash[ j ] == attributeNameHash[ i ] && attributeName[j].equals(attributeName[i])) ) ) { // prepare data for nice error messgae? String attr1 = attributeName[j]; if(attributeUri[j] != null) attr1 = attributeUri[j]+":"+attr1; String attr2 = attributeName[i]; if(attributeUri[i] != null) attr2 = attributeUri[i]+":"+attr2; throw new XmlPullParserException( "duplicated attributes "+attr1+" and "+attr2, this, null); } } } } else { // ! processNamespaces //[ WFC: Unique Att Spec ] // check raw attribute uniqueness contraint!!! for (int i = 1; i < attributeCount; i++) { for (int j = 0; j < i; j++) { if((allStringsInterned && attributeName[j].equals(attributeName[i]) || (!allStringsInterned && attributeNameHash[ j ] == attributeNameHash[ i ] && attributeName[j].equals(attributeName[i])) ) ) { // prepare data for nice error messgae? final String attr1 = attributeName[j]; final String attr2 = attributeName[i]; throw new XmlPullParserException( "duplicated attributes "+attr1+" and "+attr2, this, null); } } } } elNamespaceCount[ depth ] = namespaceEnd; posEnd = pos; return eventType = START_TAG; } protected char parseAttribute() throws XmlPullParserException, IOException { // parse attribute // [41] Attribute ::= Name Eq AttValue // [WFC: No External Entity References] // [WFC: No < in Attribute Values] final int prevPosStart = posStart + bufAbsoluteStart; final int nameStart = pos - 1 + bufAbsoluteStart; int colonPos = -1; char ch = buf[ pos - 1 ]; if(ch == ':' && processNamespaces) throw new XmlPullParserException( "when namespaces processing enabled colon can not be at attribute name start", this, null); boolean startsWithXmlns = processNamespaces && ch == 'x'; int xmlnsPos = 0; ch = more(); while(isNameChar(ch)) { if(processNamespaces) { if(startsWithXmlns && xmlnsPos < 5) { ++xmlnsPos; if(xmlnsPos == 1) { if(ch != 'm') startsWithXmlns = false; } else if(xmlnsPos == 2) { if(ch != 'l') startsWithXmlns = false; } else if(xmlnsPos == 3) { if(ch != 'n') startsWithXmlns = false; } else if(xmlnsPos == 4) { if(ch != 's') startsWithXmlns = false; } else if(xmlnsPos == 5) { if(ch != ':') throw new XmlPullParserException( "after xmlns in attribute name must be colon" +"when namespaces are enabled", this, null); //colonPos = pos - 1 + bufAbsoluteStart; } } if(ch == ':') { if(colonPos != -1) throw new XmlPullParserException( "only one colon is allowed in attribute name" +" when namespaces are enabled", this, null); colonPos = pos - 1 + bufAbsoluteStart; } } ch = more(); } ensureAttributesCapacity(attributeCount); // --- start processing attributes String name = null; String prefix = null; // work on prefixes and namespace URI if(processNamespaces) { if(xmlnsPos < 4) startsWithXmlns = false; if(startsWithXmlns) { if(colonPos != -1) { //prefix = attributePrefix[ attributeCount ] = null; final int nameLen = pos - 2 - (colonPos - bufAbsoluteStart); if(nameLen == 0) { throw new XmlPullParserException( "namespace prefix is required after xmlns: " +" when namespaces are enabled", this, null); } name = //attributeName[ attributeCount ] = newString(buf, colonPos - bufAbsoluteStart + 1, nameLen); //pos - 1 - (colonPos + 1 - bufAbsoluteStart) } } else { if(colonPos != -1) { int prefixLen = colonPos - nameStart; prefix = attributePrefix[ attributeCount ] = newString(buf, nameStart - bufAbsoluteStart,prefixLen); //colonPos - (nameStart - bufAbsoluteStart)); int nameLen = pos - 2 - (colonPos - bufAbsoluteStart); name = attributeName[ attributeCount ] = newString(buf, colonPos - bufAbsoluteStart + 1, nameLen); //pos - 1 - (colonPos + 1 - bufAbsoluteStart)); //name.substring(0, colonPos-nameStart); } else { prefix = attributePrefix[ attributeCount ] = null; name = attributeName[ attributeCount ] = newString(buf, nameStart - bufAbsoluteStart, pos - 1 - (nameStart - bufAbsoluteStart)); } if(!allStringsInterned) { attributeNameHash[ attributeCount ] = name.hashCode(); } } } else { // retrieve name name = attributeName[ attributeCount ] = newString(buf, nameStart - bufAbsoluteStart, pos - 1 - (nameStart - bufAbsoluteStart)); ////assert name != null; if(!allStringsInterned) { attributeNameHash[ attributeCount ] = name.hashCode(); } } // [25] Eq ::= S? '=' S? while(isS(ch)) { ch = more(); } // skip additional spaces if(ch != '=') throw new XmlPullParserException( "expected = after attribute name", this, null); ch = more(); while(isS(ch)) { ch = more(); } // skip additional spaces // [10] AttValue ::= '"' ([^<&"] | Reference)* '"' // | "'" ([^<&'] | Reference)* "'" final char delimit = ch; if(delimit != '"' && delimit != '\'') throw new XmlPullParserException( "attribute value must start with quotation or apostrophe not " +printable(delimit), this, null); // parse until delimit or < and resolve Reference //[67] Reference ::= EntityRef | CharRef //int valueStart = pos + bufAbsoluteStart; boolean normalizedCR = false; usePC = false; pcStart = pcEnd; posStart = pos; while(true) { ch = more(); if(ch == delimit) { break; } if(ch == '<') { throw new XmlPullParserException( "markup not allowed inside attribute value - illegal < ", this, null); } if(ch == '&') { // extractEntityRef posEnd = pos - 1; if(!usePC) { final boolean hadCharData = posEnd > posStart; if(hadCharData) { // posEnd is already set correctly!!! joinPC(); } else { usePC = true; pcStart = pcEnd = 0; } } //assert usePC == true; final char[] resolvedEntity = parseEntityRef(); // check if replacement text can be resolved !!! if(resolvedEntity == null) { if(entityRefName == null) { entityRefName = newString(buf, posStart, posEnd - posStart); } throw new XmlPullParserException( "could not resolve entity named '"+printable(entityRefName)+"'", this, null); } // write into PC replacement text - do merge for replacement text!!!! for ( char aResolvedEntity : resolvedEntity ) { if ( pcEnd >= pc.length ) { ensurePC( pcEnd ); } pc[pcEnd++] = aResolvedEntity; } } else if(ch == '\t' || ch == '\n' || ch == '\r') { // do attribute value normalization // as described in http://www.w3.org/TR/REC-xml#AVNormalize // TODO add test for it form spec ... // handle EOL normalization ... if(!usePC) { posEnd = pos - 1; if(posEnd > posStart) { joinPC(); } else { usePC = true; pcEnd = pcStart = 0; } } //assert usePC == true; if(pcEnd >= pc.length) ensurePC(pcEnd); if(ch != '\n' || !normalizedCR) { pc[pcEnd++] = ' '; //'\n'; } } else { if(usePC) { if(pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = ch; } } normalizedCR = ch == '\r'; } if(processNamespaces && startsWithXmlns) { String ns = null; if(!usePC) { ns = newStringIntern(buf, posStart, pos - 1 - posStart); } else { ns = newStringIntern(pc, pcStart, pcEnd - pcStart); } ensureNamespacesCapacity(namespaceEnd); int prefixHash = -1; if(colonPos != -1) { if(ns.length() == 0) { throw new XmlPullParserException( "non-default namespace can not be declared to be empty string", this, null); } // declare new namespace namespacePrefix[ namespaceEnd ] = name; if(!allStringsInterned) { prefixHash = namespacePrefixHash[ namespaceEnd ] = name.hashCode(); } } else { // declare new default namespace... namespacePrefix[ namespaceEnd ] = null; //""; //null; //TODO check FIXME Alek if(!allStringsInterned) { prefixHash = namespacePrefixHash[ namespaceEnd ] = -1; } } namespaceUri[ namespaceEnd ] = ns; // detect duplicate namespace declarations!!! final int startNs = elNamespaceCount[ depth - 1 ]; for (int i = namespaceEnd - 1; i >= startNs; --i) { if(((allStringsInterned || name == null) && namespacePrefix[ i ] == name) || (!allStringsInterned && name != null && namespacePrefixHash[ i ] == prefixHash && name.equals(namespacePrefix[ i ]) )) { final String s = name == null ? "default" : "'"+name+"'"; throw new XmlPullParserException( "duplicated namespace declaration for "+s+" prefix", this, null); } } ++namespaceEnd; } else { if(!usePC) { attributeValue[ attributeCount ] = new String(buf, posStart, pos - 1 - posStart); } else { attributeValue[ attributeCount ] = new String(pc, pcStart, pcEnd - pcStart); } ++attributeCount; } posStart = prevPosStart - bufAbsoluteStart; return ch; } protected char[] charRefOneCharBuf = new char[1]; protected char[] parseEntityRef() throws XmlPullParserException, IOException { // entity reference http://www.w3.org/TR/2000/REC-xml-20001006#NT-Reference // [67] Reference ::= EntityRef | CharRef // ASSUMPTION just after & entityRefName = null; posStart = pos; char ch = more(); StringBuilder sb = new StringBuilder(); if(ch == '#') { // parse character reference char charRef = 0; ch = more(); if(ch == 'x') { //encoded in hex while(true) { ch = more(); if(ch >= '0' && ch <= '9') { charRef = (char)(charRef * 16 + (ch - '0')); sb.append( ch ); } else if(ch >= 'a' && ch <= 'f') { charRef = (char)(charRef * 16 + (ch - ('a' - 10))); sb.append( ch ); } else if(ch >= 'A' && ch <= 'F') { charRef = (char)(charRef * 16 + (ch - ('A' - 10))); sb.append( ch ); } else if(ch == ';') { break; } else { throw new XmlPullParserException( "character reference (with hex value) may not contain " +printable(ch), this, null); } } } else { // encoded in decimal while(true) { if(ch >= '0' && ch <= '9') { charRef = (char)(charRef * 10 + (ch - '0')); } else if(ch == ';') { break; } else { throw new XmlPullParserException( "character reference (with decimal value) may not contain " +printable(ch), this, null); } ch = more(); } } posEnd = pos - 1; if ( sb.length() > 0 ) { char[] tmp = toChars( Integer.parseInt( sb.toString(), 16 ) ); charRefOneCharBuf = tmp; if ( tokenize ) { text = newString( charRefOneCharBuf, 0, charRefOneCharBuf.length ); } return charRefOneCharBuf; } charRefOneCharBuf[0] = charRef; if(tokenize) { text = newString(charRefOneCharBuf, 0, 1); } return charRefOneCharBuf; } else { // [68] EntityRef ::= '&' Name ';' // scan anem until ; if(!isNameStartChar(ch)) { throw new XmlPullParserException( "entity reference names can not start with character '" +printable(ch)+"'", this, null); } while(true) { ch = more(); if(ch == ';') { break; } if(!isNameChar(ch)) { throw new XmlPullParserException( "entity reference name can not contain character " +printable(ch)+"'", this, null); } } posEnd = pos - 1; // determine what name maps to final int len = posEnd - posStart; if(len == 2 && buf[posStart] == 'l' && buf[posStart+1] == 't') { if(tokenize) { text = "<"; } charRefOneCharBuf[0] = '<'; return charRefOneCharBuf; //if(paramPC || isParserTokenizing) { // if(pcEnd >= pc.length) ensurePC(); // pc[pcEnd++] = '<'; //} } else if(len == 3 && buf[posStart] == 'a' && buf[posStart+1] == 'm' && buf[posStart+2] == 'p') { if(tokenize) { text = "&"; } charRefOneCharBuf[0] = '&'; return charRefOneCharBuf; } else if(len == 2 && buf[posStart] == 'g' && buf[posStart+1] == 't') { if(tokenize) { text = ">"; } charRefOneCharBuf[0] = '>'; return charRefOneCharBuf; } else if(len == 4 && buf[posStart] == 'a' && buf[posStart+1] == 'p' && buf[posStart+2] == 'o' && buf[posStart+3] == 's') { if(tokenize) { text = "'"; } charRefOneCharBuf[0] = '\''; return charRefOneCharBuf; } else if(len == 4 && buf[posStart] == 'q' && buf[posStart+1] == 'u' && buf[posStart+2] == 'o' && buf[posStart+3] == 't') { if(tokenize) { text = "\""; } charRefOneCharBuf[0] = '"'; return charRefOneCharBuf; } else { final char[] result = lookuEntityReplacement(len); if(result != null) { return result; } } if(tokenize) text = null; return null; } } protected char[] lookuEntityReplacement(int entitNameLen) throws XmlPullParserException, IOException { if(!allStringsInterned) { final int hash = fastHash(buf, posStart, posEnd - posStart); LOOP: for (int i = entityEnd - 1; i >= 0; --i) { if(hash == entityNameHash[ i ] && entitNameLen == entityNameBuf[ i ].length) { final char[] entityBuf = entityNameBuf[ i ]; for (int j = 0; j < entitNameLen; j++) { if(buf[posStart + j] != entityBuf[j]) continue LOOP; } if(tokenize) text = entityReplacement[ i ]; return entityReplacementBuf[ i ]; } } } else { entityRefName = newString(buf, posStart, posEnd - posStart); for (int i = entityEnd - 1; i >= 0; --i) { // take advantage that interning for newStirng is enforced if(entityRefName == entityName[ i ]) { if(tokenize) text = entityReplacement[ i ]; return entityReplacementBuf[ i ]; } } } return null; } protected void parseComment() throws XmlPullParserException, IOException { // implements XML 1.0 Section 2.5 Comments //ASSUMPTION: seen ch = more(); if(seenDashDash && ch != '>') { throw new XmlPullParserException( "in comment after two dashes (--) next character must be >" +" not "+printable(ch), this, null); } if(ch == '-') { if(!seenDash) { seenDash = true; } else { seenDashDash = true; seenDash = false; } } else if(ch == '>') { if(seenDashDash) { break; // found end sequence!!!! } else { seenDashDash = false; } seenDash = false; } else { seenDash = false; } if(normalizeIgnorableWS) { if(ch == '\r') { normalizedCR = true; //posEnd = pos -1; //joinPC(); // posEnd is alreadys set if(!usePC) { posEnd = pos -1; if(posEnd > posStart) { joinPC(); } else { usePC = true; pcStart = pcEnd = 0; } } //assert usePC == true; if(pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } else if(ch == '\n') { if(!normalizedCR && usePC) { if(pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } normalizedCR = false; } else { if(usePC) { if(pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = ch; } normalizedCR = false; } } } } catch(EOFException ex) { // detect EOF and create meaningful error ... throw new XmlPullParserException( "comment started on line "+curLine+" and column "+curColumn+" was not closed", this, ex); } if(tokenize) { posEnd = pos - 3; if(usePC) { pcEnd -= 2; } } } protected boolean parsePI() throws XmlPullParserException, IOException { // implements XML 1.0 Section 2.6 Processing Instructions // [16] PI ::= '' Char*)))? '?>' // [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l')) //ASSUMPTION: seen //ch = more(); if(ch == '?') { seenQ = true; } else if(ch == '>') { if(seenQ) { break; // found end sequence!!!! } seenQ = false; } else { if(piTargetEnd == -1 && isS(ch)) { piTargetEnd = pos - 1 + bufAbsoluteStart; // [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l')) if((piTargetEnd - piTargetStart) == 3) { if((buf[piTargetStart] == 'x' || buf[piTargetStart] == 'X') && (buf[piTargetStart+1] == 'm' || buf[piTargetStart+1] == 'M') && (buf[piTargetStart+2] == 'l' || buf[piTargetStart+2] == 'L') ) { if(piTargetStart > 3) { // posStart) { joinPC(); } else { usePC = true; pcStart = pcEnd = 0; } } //assert usePC == true; if(pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } else if(ch == '\n') { if(!normalizedCR && usePC) { if(pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } normalizedCR = false; } else { if(usePC) { if(pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = ch; } normalizedCR = false; } } ch = more(); } } catch(EOFException ex) { // detect EOF and create meaningful error ... throw new XmlPullParserException( "processing instruction started on line "+curLine+" and column "+curColumn +" was not closed", this, ex); } if(piTargetEnd == -1) { piTargetEnd = pos - 2 + bufAbsoluteStart; //throw new XmlPullParserException( // "processing instruction must have PITarget name", this, null); } piTargetStart -= bufAbsoluteStart; piTargetEnd -= bufAbsoluteStart; if(tokenize) { posEnd = pos - 2; if(normalizeIgnorableWS) { --pcEnd; } } return true; } // protected final static char[] VERSION = {'v','e','r','s','i','o','n'}; // protected final static char[] NCODING = {'n','c','o','d','i','n','g'}; // protected final static char[] TANDALONE = {'t','a','n','d','a','l','o','n','e'}; // protected final static char[] YES = {'y','e','s'}; // protected final static char[] NO = {'n','o'}; protected final static char[] VERSION = "version".toCharArray(); protected final static char[] NCODING = "ncoding".toCharArray(); protected final static char[] TANDALONE = "tandalone".toCharArray(); protected final static char[] YES = "yes".toCharArray(); protected final static char[] NO = "no".toCharArray(); protected void parseXmlDecl(char ch) throws XmlPullParserException, IOException { // [23] XMLDecl ::= '' // first make sure that relative positions will stay OK preventBufferCompaction = true; bufStart = 0; // necessary to keep pos unchanged during expansion! // --- parse VersionInfo // [24] VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"') // parse is positioned just on first S past 'z') && (ch < 'A' || ch > 'Z') && (ch < '0' || ch > '9') && ch != '_' && ch != '.' && ch != ':' && ch != '-') { throw new XmlPullParserException( " 'z') && (ch < 'A' || ch > 'Z')) { throw new XmlPullParserException( " 'z') && (ch < 'A' || ch > 'Z') && (ch < '0' || ch > '9') && ch != '.' && ch != '_' && ch != '-') { throw new XmlPullParserException( " as last part of ') { throw new XmlPullParserException( "expected ?> as last part of ' int bracketLevel = 0; final boolean normalizeIgnorableWS = tokenize == true && roundtripSupported == false; boolean normalizedCR = false; while(true) { ch = more(); if(ch == '[') ++bracketLevel; if(ch == ']') --bracketLevel; if(ch == '>' && bracketLevel == 0) break; if(normalizeIgnorableWS) { if(ch == '\r') { normalizedCR = true; //posEnd = pos -1; //joinPC(); // posEnd is alreadys set if(!usePC) { posEnd = pos -1; if(posEnd > posStart) { joinPC(); } else { usePC = true; pcStart = pcEnd = 0; } } //assert usePC == true; if(pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } else if(ch == '\n') { if(!normalizedCR && usePC) { if(pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } normalizedCR = false; } else { if(usePC) { if(pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = ch; } normalizedCR = false; } } } posEnd = pos - 1; } protected void parseCDSect(boolean hadCharData) throws XmlPullParserException, IOException { // implements XML 1.0 Section 2.7 CDATA Sections // [18] CDSect ::= CDStart CData CDEnd // [19] CDStart ::= '' Char*)) // [21] CDEnd ::= ']]>' //ASSUMPTION: seen posStart) { joinPC(); } else { usePC = true; pcStart = pcEnd = 0; } } } } boolean seenBracket = false; boolean seenBracketBracket = false; boolean normalizedCR = false; while(true) { // scan until it hits "]]>" ch = more(); if(ch == ']') { if(!seenBracket) { seenBracket = true; } else { seenBracketBracket = true; //seenBracket = false; } } else if(ch == '>') { if(seenBracket && seenBracketBracket) { break; // found end sequence!!!! } else { seenBracketBracket = false; } seenBracket = false; } else { if(seenBracket) { seenBracket = false; } } if(normalizeInput) { // deal with normalization issues ... if(ch == '\r') { normalizedCR = true; posStart = cdStart - bufAbsoluteStart; posEnd = pos - 1; // posEnd is alreadys set if(!usePC) { if(posEnd > posStart) { joinPC(); } else { usePC = true; pcStart = pcEnd = 0; } } //assert usePC == true; if(pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } else if(ch == '\n') { if(!normalizedCR && usePC) { if(pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = '\n'; } normalizedCR = false; } else { if(usePC) { if(pcEnd >= pc.length) ensurePC(pcEnd); pc[pcEnd++] = ch; } normalizedCR = false; } } } } catch(EOFException ex) { // detect EOF and create meaningful error ... throw new XmlPullParserException( "CDATA section started on line "+curLine+" and column "+curColumn+" was not closed", this, ex); } if(normalizeInput) { if(usePC) { pcEnd = pcEnd - 2; } } posStart = cdStart - bufAbsoluteStart; posEnd = pos - 3; } protected void fillBuf() throws IOException, XmlPullParserException { if(reader == null) throw new XmlPullParserException( "reader must be set before parsing is started"); // see if we are in compaction area if(bufEnd > bufSoftLimit) { // expand buffer it makes sense!!!! boolean compact = bufStart > bufSoftLimit; boolean expand = false; if(preventBufferCompaction) { compact = false; expand = true; } else if(!compact) { //freeSpace if(bufStart < buf.length / 2) { // less then half buffer available forcompactin --> expand instead!!! expand = true; } else { // at least half of buffer can be reclaimed --> worthwhile effort!!! compact = true; } } // if buffer almost full then compact it if(compact) { //TODO: look on trashing // //assert bufStart > 0 System.arraycopy(buf, bufStart, buf, 0, bufEnd - bufStart); if(TRACE_SIZING) System.out.println( "TRACE_SIZING fillBuf() compacting "+bufStart +" bufEnd="+bufEnd +" pos="+pos+" posStart="+posStart+" posEnd="+posEnd +" buf first 100 chars:"+new String(buf, bufStart, bufEnd - bufStart < 100 ? bufEnd - bufStart : 100 )); } else if(expand) { final int newSize = 2 * buf.length; final char newBuf[] = new char[ newSize ]; if(TRACE_SIZING) System.out.println("TRACE_SIZING fillBuf() "+buf.length+" => "+newSize); System.arraycopy(buf, bufStart, newBuf, 0, bufEnd - bufStart); buf = newBuf; if(bufLoadFactor > 0) { bufSoftLimit = ( bufLoadFactor * buf.length ) /100; } } else { throw new XmlPullParserException("internal error in fillBuffer()"); } bufEnd -= bufStart; pos -= bufStart; posStart -= bufStart; posEnd -= bufStart; bufAbsoluteStart += bufStart; bufStart = 0; if(TRACE_SIZING) System.out.println( "TRACE_SIZING fillBuf() after bufEnd="+bufEnd +" pos="+pos+" posStart="+posStart+" posEnd="+posEnd +" buf first 100 chars:"+new String(buf, 0, bufEnd < 100 ? bufEnd : 100)); } // at least one charcter must be read or error final int len = buf.length - bufEnd > READ_CHUNK_SIZE ? READ_CHUNK_SIZE : buf.length - bufEnd; final int ret = reader.read(buf, bufEnd, len); if(ret > 0) { bufEnd += ret; if(TRACE_SIZING) System.out.println( "TRACE_SIZING fillBuf() after filling in buffer" +" buf first 100 chars:"+new String(buf, 0, bufEnd < 100 ? bufEnd : 100)); return; } if(ret == -1) { if(bufAbsoluteStart == 0 && pos == 0) { throw new EOFException("input contained no data"); } else { if(seenRoot && depth == 0) { // inside parsing epilog!!! reachedEnd = true; return; } else { StringBuilder expectedTagStack = new StringBuilder(); if(depth > 0) { //final char[] cbuf = elRawName[depth]; //final String startname = new String(cbuf, 0, elRawNameEnd[depth]); expectedTagStack.append(" - expected end tag"); if(depth > 1) { expectedTagStack.append("s"); //more than one end tag } expectedTagStack.append(" "); for (int i = depth; i > 0; i--) { String tagName = new String(elRawName[i], 0, elRawNameEnd[i]); expectedTagStack.append("'); } expectedTagStack.append(" to close"); for (int i = depth; i > 0; i--) { if(i != depth) { expectedTagStack.append(" and"); //more than one end tag } String tagName = new String(elRawName[i], 0, elRawNameEnd[i]); expectedTagStack.append( " start tag <" ).append( tagName ).append( ">" ); expectedTagStack.append( " from line " ).append( elRawNameLine[i] ); } expectedTagStack.append(", parser stopped on"); } throw new EOFException("no more data available" +expectedTagStack.toString()+getPositionDescription()); } } } else { throw new IOException("error reading input, returned "+ret); } } protected char more() throws IOException, XmlPullParserException { if(pos >= bufEnd) { fillBuf(); // this return value should be ignonored as it is used in epilog parsing ... if(reachedEnd) return (char)-1; } final char ch = buf[pos++]; //line/columnNumber if(ch == '\n') { ++lineNumber; columnNumber = 1; } else { ++columnNumber; } //System.out.print(ch); return ch; } // /** // * This function returns position of parser in XML input stream // * (how many characters were processed. // *

          NOTE: this logical position and not byte offset as encodings // * such as UTF8 may use more than one byte to encode one character. // */ // public int getCurrentInputPosition() { // return pos + bufAbsoluteStart; // } protected void ensurePC(int end) { //assert end >= pc.length; final int newSize = end > READ_CHUNK_SIZE ? 2 * end : 2 * READ_CHUNK_SIZE; final char[] newPC = new char[ newSize ]; if(TRACE_SIZING) System.out.println("TRACE_SIZING ensurePC() "+pc.length+" ==> "+newSize+" end="+end); System.arraycopy(pc, 0, newPC, 0, pcEnd); pc = newPC; //assert end < pc.length; } protected void joinPC() { //assert usePC == false; //assert posEnd > posStart; final int len = posEnd - posStart; final int newEnd = pcEnd + len + 1; if(newEnd >= pc.length) ensurePC(newEnd); // add 1 for extra space for one char //assert newEnd < pc.length; System.arraycopy(buf, posStart, pc, pcEnd, len); pcEnd += len; usePC = true; } protected char requireInput(char ch, char[] input) throws XmlPullParserException, IOException { for ( char anInput : input ) { if ( ch != anInput ) { throw new XmlPullParserException( "expected " + printable( anInput ) + " in " + new String( input ) + " and not " + printable( ch ), this, null ); } ch = more(); } return ch; } protected char requireNextS() throws XmlPullParserException, IOException { final char ch = more(); if(!isS(ch)) { throw new XmlPullParserException( "white space is required and not "+printable(ch), this, null); } return skipS(ch); } protected char skipS(char ch) throws XmlPullParserException, IOException { while(isS(ch)) { ch = more(); } // skip additional spaces return ch; } // nameStart / name lookup tables based on XML 1.1 http://www.w3.org/TR/2001/WD-xml11-20011213/ protected static final int LOOKUP_MAX = 0x400; protected static final char LOOKUP_MAX_CHAR = (char)LOOKUP_MAX; // protected static int lookupNameStartChar[] = new int[ LOOKUP_MAX_CHAR / 32 ]; // protected static int lookupNameChar[] = new int[ LOOKUP_MAX_CHAR / 32 ]; protected static boolean lookupNameStartChar[] = new boolean[ LOOKUP_MAX ]; protected static boolean lookupNameChar[] = new boolean[ LOOKUP_MAX ]; private static final void setName(char ch) //{ lookupNameChar[ (int)ch / 32 ] |= (1 << (ch % 32)); } { lookupNameChar[ ch ] = true; } private static final void setNameStart(char ch) //{ lookupNameStartChar[ (int)ch / 32 ] |= (1 << (ch % 32)); setName(ch); } { lookupNameStartChar[ ch ] = true; setName(ch); } static { setNameStart(':'); for (char ch = 'A'; ch <= 'Z'; ++ch) setNameStart(ch); setNameStart('_'); for (char ch = 'a'; ch <= 'z'; ++ch) setNameStart(ch); for (char ch = '\u00c0'; ch <= '\u02FF'; ++ch) setNameStart(ch); for (char ch = '\u0370'; ch <= '\u037d'; ++ch) setNameStart(ch); for (char ch = '\u037f'; ch < '\u0400'; ++ch) setNameStart(ch); setName('-'); setName('.'); for (char ch = '0'; ch <= '9'; ++ch) setName(ch); setName('\u00b7'); for (char ch = '\u0300'; ch <= '\u036f'; ++ch) setName(ch); } //private final static boolean isNameStartChar(char ch) { protected boolean isNameStartChar(char ch) { return (ch < LOOKUP_MAX_CHAR && lookupNameStartChar[ ch ]) || (ch >= LOOKUP_MAX_CHAR && ch <= '\u2027') || (ch >= '\u202A' && ch <= '\u218F') || (ch >= '\u2800' && ch <= '\uFFEF') ; // if(ch < LOOKUP_MAX_CHAR) return lookupNameStartChar[ ch ]; // else return ch <= '\u2027' // || (ch >= '\u202A' && ch <= '\u218F') // || (ch >= '\u2800' && ch <= '\uFFEF') // ; //return false; // return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == ':' // || (ch >= '0' && ch <= '9'); // if(ch < LOOKUP_MAX_CHAR) return (lookupNameStartChar[ (int)ch / 32 ] & (1 << (ch % 32))) != 0; // if(ch <= '\u2027') return true; // //[#x202A-#x218F] // if(ch < '\u202A') return false; // if(ch <= '\u218F') return true; // // added pairts [#x2800-#xD7FF] | [#xE000-#xFDCF] | [#xFDE0-#xFFEF] | [#x10000-#x10FFFF] // if(ch < '\u2800') return false; // if(ch <= '\uFFEF') return true; // return false; // else return (supportXml11 && ( (ch < '\u2027') || (ch > '\u2029' && ch < '\u2200') ... } //private final static boolean isNameChar(char ch) { protected boolean isNameChar(char ch) { //return isNameStartChar(ch); // if(ch < LOOKUP_MAX_CHAR) return (lookupNameChar[ (int)ch / 32 ] & (1 << (ch % 32))) != 0; return (ch < LOOKUP_MAX_CHAR && lookupNameChar[ ch ]) || (ch >= LOOKUP_MAX_CHAR && ch <= '\u2027') || (ch >= '\u202A' && ch <= '\u218F') || (ch >= '\u2800' && ch <= '\uFFEF') ; //return false; // return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == ':' // || (ch >= '0' && ch <= '9'); // if(ch < LOOKUP_MAX_CHAR) return (lookupNameStartChar[ (int)ch / 32 ] & (1 << (ch % 32))) != 0; //else return // else if(ch <= '\u2027') return true; // //[#x202A-#x218F] // else if(ch < '\u202A') return false; // else if(ch <= '\u218F') return true; // // added pairts [#x2800-#xD7FF] | [#xE000-#xFDCF] | [#xFDE0-#xFFEF] | [#x10000-#x10FFFF] // else if(ch < '\u2800') return false; // else if(ch <= '\uFFEF') return true; //else return false; } protected boolean isS(char ch) { return (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'); // || (supportXml11 && (ch == '\u0085' || ch == '\u2028'); } //protected boolean isChar(char ch) { return (ch < '\uD800' || ch > '\uDFFF') // ch != '\u0000' ch < '\uFFFE' //protected char printable(char ch) { return ch; } protected String printable(char ch) { if(ch == '\n') { return "\\n"; } else if(ch == '\r') { return "\\r"; } else if(ch == '\t') { return "\\t"; } else if(ch == '\'') { return "\\'"; } if(ch > 127 || ch < 32) { return "\\u"+Integer.toHexString((int)ch); } return ""+ch; } protected String printable(String s) { if(s == null) return null; final int sLen = s.length(); StringBuilder buf = new StringBuilder(sLen + 10); for(int i = 0; i < sLen; ++i) { buf.append(printable(s.charAt(i))); } s = buf.toString(); return s; } // // Imported code from ASF Harmony project rev 770909 // http://svn.apache.org/repos/asf/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/lang/Character.java // private static int toCodePoint( char high, char low ) { // See RFC 2781, Section 2.2 // http://www.faqs.org/rfcs/rfc2781.html int h = ( high & 0x3FF ) << 10; int l = low & 0x3FF; return ( h | l ) + 0x10000; } private static final char MIN_HIGH_SURROGATE = '\uD800'; private static final char MAX_HIGH_SURROGATE = '\uDBFF'; private static boolean isHighSurrogate( char ch ) { return ( MIN_HIGH_SURROGATE <= ch && MAX_HIGH_SURROGATE >= ch ); } private static final int MIN_CODE_POINT = 0x000000; private static final int MAX_CODE_POINT = 0x10FFFF; private static final int MIN_SUPPLEMENTARY_CODE_POINT = 0x10000; private static boolean isValidCodePoint( int codePoint ) { return ( MIN_CODE_POINT <= codePoint && MAX_CODE_POINT >= codePoint ); } private static boolean isSupplementaryCodePoint( int codePoint ) { return ( MIN_SUPPLEMENTARY_CODE_POINT <= codePoint && MAX_CODE_POINT >= codePoint ); } /** * TODO add javadoc * * @param codePoint * @return */ public static char[] toChars( int codePoint ) { if ( !isValidCodePoint( codePoint ) ) { throw new IllegalArgumentException(); } if ( isSupplementaryCodePoint( codePoint ) ) { int cpPrime = codePoint - 0x10000; int high = 0xD800 | ( ( cpPrime >> 10 ) & 0x3FF ); int low = 0xDC00 | ( cpPrime & 0x3FF ); return new char[] { (char) high, (char) low }; } return new char[] { (char) codePoint }; } } /* * Indiana University Extreme! Lab Software License, Version 1.2 * * Copyright (C) 2003 The Trustees of Indiana University. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * 1) All redistributions of source code must retain the above * copyright notice, the list of authors in the original source * code, this list of conditions and the disclaimer listed in this * license; * * 2) All redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the disclaimer * listed in this license in the documentation and/or other * materials provided with the distribution; * * 3) Any documentation included with all redistributions must include * the following acknowledgement: * * "This product includes software developed by the Indiana * University Extreme! Lab. For further information please visit * http://www.extreme.indiana.edu/" * * Alternatively, this acknowledgment may appear in the software * itself, and wherever such third-party acknowledgments normally * appear. * * 4) The name "Indiana University" or "Indiana University * Extreme! Lab" shall not be used to endorse or promote * products derived from this software without prior written * permission from Indiana University. For written permission, * please contact http://www.extreme.indiana.edu/. * * 5) Products derived from this software may not use "Indiana * University" name nor may "Indiana University" appear in their name, * without prior written permission of the Indiana University. * * Indiana University provides no reassurances that the source code * provided does not infringe the patent or any other intellectual * property rights of any other entity. Indiana University disclaims any * liability to any recipient for claims brought by any other entity * based on infringement of intellectual property rights or otherwise. * * LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH * NO WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA * UNIVERSITY GIVES NO WARRANTIES AND MAKES NO REPRESENTATION THAT * SOFTWARE IS FREE OF INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR * OTHER PROPRIETARY RIGHTS. INDIANA UNIVERSITY MAKES NO WARRANTIES THAT * SOFTWARE IS FREE FROM "BUGS", "VIRUSES", "TROJAN HORSES", "TRAP * DOORS", "WORMS", OR OTHER HARMFUL CODE. LICENSEE ASSUMES THE ENTIRE * RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR ASSOCIATED MATERIALS, * AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION GENERATED USING * SOFTWARE. */ plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/xml/pull/MXSerializer.java000066400000000000000000001217061251077732300332560ustar00rootroot00000000000000/* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- //------100-columns-wide------>|*/ // for license please see accompanying LICENSE.txt file (available also at http://www.xmlpull.org/) package org.codehaus.plexus.util.xml.pull; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; /** * Implementation of XmlSerializer interface from XmlPull V1 API. * This implementation is optimized for performance and low memory footprint. * *

          Implemented features:

            *
          • FEATURE_NAMES_INTERNED - when enabled all returned names * (namespaces, prefixes) will be interned and it is required that * all names passed as arguments MUST be interned *
          • FEATURE_SERIALIZER_ATTVALUE_USE_APOSTROPHE *
          *

          Implemented properties:

            *
          • PROPERTY_SERIALIZER_INDENTATION *
          • PROPERTY_SERIALIZER_LINE_SEPARATOR *
          * */ public class MXSerializer implements XmlSerializer { protected final static String XML_URI = "http://www.w3.org/XML/1998/namespace"; protected final static String XMLNS_URI = "http://www.w3.org/2000/xmlns/"; private static final boolean TRACE_SIZING = false; protected final String FEATURE_SERIALIZER_ATTVALUE_USE_APOSTROPHE = "http://xmlpull.org/v1/doc/features.html#serializer-attvalue-use-apostrophe"; protected final String FEATURE_NAMES_INTERNED = "http://xmlpull.org/v1/doc/features.html#names-interned"; protected final String PROPERTY_SERIALIZER_INDENTATION = "http://xmlpull.org/v1/doc/properties.html#serializer-indentation"; protected final String PROPERTY_SERIALIZER_LINE_SEPARATOR = "http://xmlpull.org/v1/doc/properties.html#serializer-line-separator"; protected final static String PROPERTY_LOCATION = "http://xmlpull.org/v1/doc/properties.html#location"; // properties/features protected boolean namesInterned; protected boolean attributeUseApostrophe; protected String indentationString = null; //" "; protected String lineSeparator = "\n"; protected String location; protected Writer out; protected int autoDeclaredPrefixes; protected int depth = 0; // element stack protected String elNamespace[] = new String[ 2 ]; protected String elName[] = new String[ elNamespace.length ]; protected int elNamespaceCount[] = new int[ elNamespace.length ]; //namespace stack protected int namespaceEnd = 0; protected String namespacePrefix[] = new String[ 8 ]; protected String namespaceUri[] = new String[ namespacePrefix.length ]; protected boolean finished; protected boolean pastRoot; protected boolean setPrefixCalled; protected boolean startTagIncomplete; protected boolean doIndent; protected boolean seenTag; protected boolean seenBracket; protected boolean seenBracketBracket; // buffer output if needed to write escaped String see text(String) private static final int BUF_LEN = Runtime.getRuntime().freeMemory() > 1000000L ? 8*1024 : 256; protected char buf[] = new char[ BUF_LEN ]; protected static final String precomputedPrefixes[]; static { precomputedPrefixes = new String[32]; //arbitrary number ... for (int i = 0; i < precomputedPrefixes.length; i++) { precomputedPrefixes[i] = ("n"+i).intern(); } } private boolean checkNamesInterned = false; private void checkInterning(String name) { if(namesInterned && name != name.intern()) { throw new IllegalArgumentException( "all names passed as arguments must be interned" +"when NAMES INTERNED feature is enabled"); } } protected void reset() { location = null; out = null; autoDeclaredPrefixes = 0; depth = 0; // nullify references on all levels to allow it to be GCed for (int i = 0; i < elNamespaceCount.length; i++) { elName[ i ] = null; elNamespace[ i ] = null; elNamespaceCount[ i ] = 2; } namespaceEnd = 0; //NOTE: no need to intern() as all literal strings and string-valued constant expressions //are interned. String literals are defined in 3.10.5 of the Java Language Specification // just checking ... //assert "xmlns" == "xmlns".intern(); //assert XMLNS_URI == XMLNS_URI.intern(); //TODO: how to prevent from reporting this namespace? // this is special namespace declared for consistency with XML infoset namespacePrefix[ namespaceEnd ] = "xmlns"; namespaceUri[ namespaceEnd ] = XMLNS_URI; ++namespaceEnd; namespacePrefix[ namespaceEnd ] = "xml"; namespaceUri[ namespaceEnd ] = XML_URI; ++namespaceEnd; finished = false; pastRoot = false; setPrefixCalled = false; startTagIncomplete = false; //doIntent is not changed seenTag = false; seenBracket = false; seenBracketBracket = false; } protected void ensureElementsCapacity() { final int elStackSize = elName.length; //assert (depth + 1) >= elName.length; // we add at least one extra slot ... final int newSize = (depth >= 7 ? 2 * depth : 8) + 2; // = lucky 7 + 1 //25 if(TRACE_SIZING) { System.err.println( getClass().getName()+" elStackSize "+elStackSize+" ==> "+newSize); } final boolean needsCopying = elStackSize > 0; String[] arr = null; // reuse arr local variable slot arr = new String[newSize]; if(needsCopying) System.arraycopy(elName, 0, arr, 0, elStackSize); elName = arr; arr = new String[newSize]; if(needsCopying) System.arraycopy(elNamespace, 0, arr, 0, elStackSize); elNamespace = arr; final int[] iarr = new int[newSize]; if(needsCopying) { System.arraycopy(elNamespaceCount, 0, iarr, 0, elStackSize); } else { // special initialization iarr[0] = 0; } elNamespaceCount = iarr; } protected void ensureNamespacesCapacity() { //int size) { //int namespaceSize = namespacePrefix != null ? namespacePrefix.length : 0; //assert (namespaceEnd >= namespacePrefix.length); //if(size >= namespaceSize) { //int newSize = size > 7 ? 2 * size : 8; // = lucky 7 + 1 //25 final int newSize = namespaceEnd > 7 ? 2 * namespaceEnd : 8; if(TRACE_SIZING) { System.err.println( getClass().getName()+" namespaceSize "+namespacePrefix.length+" ==> "+newSize); } final String[] newNamespacePrefix = new String[newSize]; final String[] newNamespaceUri = new String[newSize]; if(namespacePrefix != null) { System.arraycopy( namespacePrefix, 0, newNamespacePrefix, 0, namespaceEnd); System.arraycopy( namespaceUri, 0, newNamespaceUri, 0, namespaceEnd); } namespacePrefix = newNamespacePrefix; namespaceUri = newNamespaceUri; // TODO use hashes for quick namespace->prefix lookups // if( ! allStringsInterned ) { // int[] newNamespacePrefixHash = new int[newSize]; // if(namespacePrefixHash != null) { // System.arraycopy( // namespacePrefixHash, 0, newNamespacePrefixHash, 0, namespaceEnd); // } // namespacePrefixHash = newNamespacePrefixHash; // } //prefixesSize = newSize; // ////assert nsPrefixes.length > size && nsPrefixes.length == newSize //} } public void setFeature(String name, boolean state) throws IllegalArgumentException, IllegalStateException { if(name == null) { throw new IllegalArgumentException("feature name can not be null"); } if(FEATURE_NAMES_INTERNED.equals(name)) { namesInterned = state; } else if(FEATURE_SERIALIZER_ATTVALUE_USE_APOSTROPHE.equals(name)) { attributeUseApostrophe = state; } else { throw new IllegalStateException("unsupported feature "+name); } } public boolean getFeature(String name) throws IllegalArgumentException { if(name == null) { throw new IllegalArgumentException("feature name can not be null"); } if(FEATURE_NAMES_INTERNED.equals(name)) { return namesInterned; } else if(FEATURE_SERIALIZER_ATTVALUE_USE_APOSTROPHE.equals(name)) { return attributeUseApostrophe; } else { return false; } } // precomputed variables to simplify writing indentation protected int offsetNewLine; protected int indentationJump; protected char[] indentationBuf; protected int maxIndentLevel; protected boolean writeLineSepartor; //should end-of-line be written protected boolean writeIndentation; // is indentation used? /** * For maximum efficiency when writing indents the required output is pre-computed * This is internal function that recomputes buffer after user requested chnages. */ protected void rebuildIndentationBuf() { if(doIndent == false) return; final int maxIndent = 65; //hardcoded maximum indentation size in characters int bufSize = 0; offsetNewLine = 0; if(writeLineSepartor) { offsetNewLine = lineSeparator.length(); bufSize += offsetNewLine; } maxIndentLevel = 0; if(writeIndentation) { indentationJump = indentationString.length(); maxIndentLevel = maxIndent / indentationJump; bufSize += maxIndentLevel * indentationJump; } if(indentationBuf == null || indentationBuf.length < bufSize) { indentationBuf = new char[bufSize + 8]; } int bufPos = 0; if(writeLineSepartor) { for (int i = 0; i < lineSeparator.length(); i++) { indentationBuf[ bufPos++ ] = lineSeparator.charAt(i); } } if(writeIndentation) { for (int i = 0; i < maxIndentLevel; i++) { for (int j = 0; j < indentationString.length(); j++) { indentationBuf[ bufPos++ ] = indentationString.charAt(j); } } } } // if(doIndent) writeIndent(); protected void writeIndent() throws IOException { final int start = writeLineSepartor ? 0 : offsetNewLine; final int level = (depth > maxIndentLevel) ? maxIndentLevel : depth; out.write( indentationBuf, start, (level * indentationJump) + offsetNewLine); } public void setProperty(String name, Object value) throws IllegalArgumentException, IllegalStateException { if(name == null) { throw new IllegalArgumentException("property name can not be null"); } if(PROPERTY_SERIALIZER_INDENTATION.equals(name)) { indentationString = (String)value; } else if(PROPERTY_SERIALIZER_LINE_SEPARATOR.equals(name)) { lineSeparator = (String)value; } else if(PROPERTY_LOCATION.equals(name)) { location = (String) value; } else { throw new IllegalStateException("unsupported property "+name); } writeLineSepartor = lineSeparator != null && lineSeparator.length() > 0; writeIndentation = indentationString != null && indentationString.length() > 0; // optimize - do not write when nothing to write ... doIndent = indentationString != null && (writeLineSepartor || writeIndentation); //NOTE: when indentationString == null there is no indentation // (even though writeLineSeparator may be true ...) rebuildIndentationBuf(); seenTag = false; // for consistency } public Object getProperty(String name) throws IllegalArgumentException { if(name == null) { throw new IllegalArgumentException("property name can not be null"); } if(PROPERTY_SERIALIZER_INDENTATION.equals(name)) { return indentationString; } else if(PROPERTY_SERIALIZER_LINE_SEPARATOR.equals(name)) { return lineSeparator; } else if(PROPERTY_LOCATION.equals(name)) { return location; } else { return null; } } private String getLocation() { return location != null ? " @"+location : ""; } // this is special method that can be accessed directly to retrieve Writer serializer is using public Writer getWriter() { return out; } public void setOutput(Writer writer) { reset(); out = writer; } public void setOutput(OutputStream os, String encoding) throws IOException { if(os == null) throw new IllegalArgumentException("output stream can not be null"); reset(); if(encoding != null) { out = new OutputStreamWriter(os, encoding); } else { out = new OutputStreamWriter(os); } } public void startDocument (String encoding, Boolean standalone) throws IOException { char apos = attributeUseApostrophe ? '\'' : '"'; if(attributeUseApostrophe) { out.write(""); if(writeLineSepartor) { out.write(lineSeparator); } } public void endDocument() throws IOException { // close all unclosed tag; while(depth > 0) { endTag(elNamespace[ depth ], elName[ depth ]); } if(writeLineSepartor) { out.write(lineSeparator); } //assert depth == 0; //assert startTagIncomplete == false; finished = pastRoot = startTagIncomplete = true; out.flush(); } public void setPrefix(String prefix, String namespace) throws IOException { if(startTagIncomplete) closeStartTag(); //assert prefix != null; //assert namespace != null; if (prefix == null) { prefix = ""; } if(!namesInterned) { prefix = prefix.intern(); //will throw NPE if prefix==null } else if(checkNamesInterned) { checkInterning(prefix); } else if(prefix == null) { throw new IllegalArgumentException("prefix must be not null"+getLocation()); } //check that prefix is not duplicated ... for (int i = elNamespaceCount[ depth ]; i < namespaceEnd; i++) { if(prefix == namespacePrefix[ i ]) { throw new IllegalStateException("duplicated prefix "+printable(prefix)+getLocation()); } } if(!namesInterned) { namespace = namespace.intern(); } else if(checkNamesInterned) { checkInterning(namespace); } else if(namespace == null) { throw new IllegalArgumentException("namespace must be not null"+getLocation()); } if(namespaceEnd >= namespacePrefix.length) { ensureNamespacesCapacity(); } namespacePrefix[ namespaceEnd ] = prefix; namespaceUri[ namespaceEnd ] = namespace; ++namespaceEnd; setPrefixCalled = true; } protected String lookupOrDeclarePrefix( String namespace ) { return getPrefix(namespace, true); } public String getPrefix(String namespace, boolean generatePrefix) { //assert namespace != null; if(!namesInterned) { // when String is interned we can do much faster namespace stack lookups ... namespace = namespace.intern(); } else if(checkNamesInterned) { checkInterning(namespace); //assert namespace != namespace.intern(); } if(namespace == null) { throw new IllegalArgumentException("namespace must be not null"+getLocation()); } else if(namespace.length() == 0) { throw new IllegalArgumentException("default namespace cannot have prefix"+getLocation()); } // first check if namespace is already in scope for (int i = namespaceEnd - 1; i >= 0 ; --i) { if(namespace == namespaceUri[ i ]) { final String prefix = namespacePrefix[ i ]; // now check that prefix is still in scope for (int p = namespaceEnd - 1; p > i ; --p) { if(prefix == namespacePrefix[ p ]) continue; // too bad - prefix is redeclared with different namespace } return prefix; } } // so not found it ... if(!generatePrefix) { return null; } return generatePrefix(namespace); } private String generatePrefix(String namespace) { //assert namespace == namespace.intern(); while(true) { ++autoDeclaredPrefixes; //fast lookup uses table that was pre-initialized in static{} .... final String prefix = autoDeclaredPrefixes < precomputedPrefixes.length ? precomputedPrefixes[autoDeclaredPrefixes] : ("n"+autoDeclaredPrefixes).intern(); // make sure this prefix is not declared in any scope (avoid hiding in-scope prefixes)! for (int i = namespaceEnd - 1; i >= 0 ; --i) { if(prefix == namespacePrefix[ i ]) { continue; // prefix is already declared - generate new and try again } } // declare prefix if(namespaceEnd >= namespacePrefix.length) { ensureNamespacesCapacity(); } namespacePrefix[ namespaceEnd ] = prefix; namespaceUri[ namespaceEnd ] = namespace; ++namespaceEnd; return prefix; } } public int getDepth() { return depth; } public String getNamespace () { return elNamespace[depth]; } public String getName() { return elName[depth]; } public XmlSerializer startTag (String namespace, String name) throws IOException { if(startTagIncomplete) { closeStartTag(); } seenBracket = seenBracketBracket = false; if(doIndent && depth > 0 && seenTag) { writeIndent(); } seenTag = true; setPrefixCalled = false; startTagIncomplete = true; ++depth; if( (depth + 1) >= elName.length) { ensureElementsCapacity(); } ////assert namespace != null; if(checkNamesInterned && namesInterned) checkInterning(namespace); elNamespace[ depth ] = (namesInterned || namespace == null) ? namespace : namespace.intern(); //assert name != null; //elName[ depth ] = name; if(checkNamesInterned && namesInterned) checkInterning(name); elName[ depth ] = (namesInterned || name == null) ? name : name.intern(); if(out == null) { throw new IllegalStateException("setOutput() must called set before serialization can start"); } out.write('<'); if(namespace != null) { if(namespace.length() > 0) { //ALEK: in future make it as feature on serializer String prefix = null; if(depth > 0 && (namespaceEnd - elNamespaceCount[depth-1]) == 1) { // if only one prefix was declared un-declare it if prefix is already declared on parent el with the same URI String uri = namespaceUri[namespaceEnd-1]; if(uri == namespace || uri.equals(namespace)) { String elPfx = namespacePrefix[namespaceEnd-1]; // 2 == to skip predefined namespaces (xml and xmlns ...) for(int pos = elNamespaceCount[depth-1] - 1; pos >= 2; --pos ) { String pf = namespacePrefix[pos]; if(pf == elPfx || pf.equals(elPfx)) { String n = namespaceUri[pos]; if(n == uri || n.equals(uri)) { --namespaceEnd; //un-declare namespace prefix = elPfx; } break; } } } } if(prefix == null) { prefix = lookupOrDeclarePrefix( namespace ); } //assert prefix != null; // make sure that default ("") namespace to not print ":" if(prefix.length() > 0) { out.write(prefix); out.write(':'); } } else { // make sure that default namespace can be declared for (int i = namespaceEnd - 1; i >= 0 ; --i) { if(namespacePrefix[ i ] == "") { final String uri = namespaceUri[ i ]; if(uri == null) { // declare default namespace setPrefix("", ""); } else if(uri.length() > 0) { throw new IllegalStateException( "start tag can not be written in empty default namespace "+ "as default namespace is currently bound to '"+uri+"'"+getLocation()); } break; } } } } out.write(name); return this; } public XmlSerializer attribute (String namespace, String name, String value) throws IOException { if(!startTagIncomplete) { throw new IllegalArgumentException("startTag() must be called before attribute()"+getLocation()); } //assert setPrefixCalled == false; out.write(' '); ////assert namespace != null; if(namespace != null && namespace.length() > 0) { //namespace = namespace.intern(); if(!namesInterned) { namespace = namespace.intern(); } else if(checkNamesInterned) { checkInterning(namespace); } String prefix = lookupOrDeclarePrefix( namespace ); //assert( prefix != null); if(prefix.length() == 0) { // needs to declare prefix to hold default namespace //NOTE: attributes such as a='b' are in NO namespace prefix = generatePrefix(namespace); } out.write(prefix); out.write(':'); // if(prefix.length() > 0) { // out.write(prefix); // out.write(':'); // } } //assert name != null; out.write(name); out.write('='); //assert value != null; out.write( attributeUseApostrophe ? '\'' : '"'); writeAttributeValue(value, out); out.write( attributeUseApostrophe ? '\'' : '"'); return this; } protected void closeStartTag() throws IOException { if(finished) { throw new IllegalArgumentException("trying to write past already finished output"+getLocation()); } if(seenBracket) { seenBracket = seenBracketBracket = false; } if( startTagIncomplete || setPrefixCalled ) { if(setPrefixCalled) { throw new IllegalArgumentException( "startTag() must be called immediately after setPrefix()"+getLocation()); } if(!startTagIncomplete) { throw new IllegalArgumentException("trying to close start tag that is not opened"+getLocation()); } // write all namespace declarations! writeNamespaceDeclarations(); out.write('>'); elNamespaceCount[ depth ] = namespaceEnd; startTagIncomplete = false; } } private void writeNamespaceDeclarations() throws IOException { //int start = elNamespaceCount[ depth - 1 ]; for (int i = elNamespaceCount[ depth - 1 ]; i < namespaceEnd; i++) { if(doIndent && namespaceUri[ i ].length() > 40) { writeIndent(); out.write(" "); } if(namespacePrefix[ i ] != "") { out.write(" xmlns:"); out.write(namespacePrefix[ i ]); out.write('='); } else { out.write(" xmlns="); } out.write( attributeUseApostrophe ? '\'' : '"'); //NOTE: escaping of namespace value the same way as attributes!!!! writeAttributeValue(namespaceUri[ i ], out); out.write( attributeUseApostrophe ? '\'' : '"'); } } public XmlSerializer endTag(String namespace, String name) throws IOException { // check that level is valid ////assert namespace != null; //if(namespace != null) { // namespace = namespace.intern(); //} seenBracket = seenBracketBracket = false; if(namespace != null) { if(!namesInterned) { namespace = namespace.intern(); } else if(checkNamesInterned) { checkInterning(namespace); } } if(namespace != elNamespace[ depth ]) { throw new IllegalArgumentException( "expected namespace "+printable(elNamespace[ depth ]) +" and not "+printable(namespace)+getLocation()); } if(name == null) { throw new IllegalArgumentException("end tag name can not be null"+getLocation()); } if(checkNamesInterned && namesInterned) { checkInterning(name); } if((!namesInterned && !name.equals(elName[ depth ])) || (namesInterned && name != elName[ depth ])) { throw new IllegalArgumentException( "expected element name "+printable(elName[ depth ])+" and not "+printable(name)+getLocation()); } if(startTagIncomplete) { writeNamespaceDeclarations(); out.write(" />"); //space is added to make it easier to work in XHTML!!! --depth; } else { --depth; //assert startTagIncomplete == false; if(doIndent && seenTag) { writeIndent(); } out.write(" 0) { //TODO prefix should be alredy known from matching start tag ... final String prefix = lookupOrDeclarePrefix( namespace ); //assert( prefix != null); if(prefix.length() > 0) { out.write(prefix); out.write(':'); } } out.write(name); out.write('>'); } namespaceEnd = elNamespaceCount[ depth ]; startTagIncomplete = false; seenTag = true; return this; } public XmlSerializer text (String text) throws IOException { //assert text != null; if(startTagIncomplete || setPrefixCalled) closeStartTag(); if(doIndent && seenTag) seenTag = false; writeElementContent(text, out); return this; } public XmlSerializer text (char [] buf, int start, int len) throws IOException { if(startTagIncomplete || setPrefixCalled) closeStartTag(); if(doIndent && seenTag) seenTag = false; writeElementContent(buf, start, len, out); return this; } public void cdsect (String text) throws IOException { if(startTagIncomplete || setPrefixCalled || seenBracket) closeStartTag(); if(doIndent && seenTag) seenTag = false; out.write(""); } public void entityRef (String text) throws IOException { if(startTagIncomplete || setPrefixCalled || seenBracket) closeStartTag(); if(doIndent && seenTag) seenTag = false; out.write('&'); out.write(text); //escape? out.write(';'); } public void processingInstruction (String text) throws IOException { if(startTagIncomplete || setPrefixCalled || seenBracket) closeStartTag(); if(doIndent && seenTag) seenTag = false; out.write(""); } public void comment (String text) throws IOException { if(startTagIncomplete || setPrefixCalled || seenBracket) closeStartTag(); if(doIndent && seenTag) seenTag = false; out.write(""); } public void docdecl (String text) throws IOException { if(startTagIncomplete || setPrefixCalled || seenBracket) closeStartTag(); if(doIndent && seenTag) seenTag = false; out.write(""); } public void ignorableWhitespace (String text) throws IOException { if(startTagIncomplete || setPrefixCalled || seenBracket) closeStartTag(); if(doIndent && seenTag) seenTag = false; if(text.length() == 0) { throw new IllegalArgumentException( "empty string is not allowed for ignorable whitespace"+getLocation()); } out.write(text); //no escape? } public void flush () throws IOException { if(!finished && startTagIncomplete) closeStartTag(); out.flush(); } // --- utility methods protected void writeAttributeValue(String value, Writer out) throws IOException { //.[apostrophe and <, & escaped], final char quot = attributeUseApostrophe ? '\'' : '"'; final String quotEntity = attributeUseApostrophe ? "'" : """; int pos = 0; for (int i = 0; i < value.length(); i++) { char ch = value.charAt(i); if(ch == '&') { if(i > pos) out.write(value.substring(pos, i)); out.write("&"); pos = i + 1; } if(ch == '<') { if(i > pos) out.write(value.substring(pos, i)); out.write("<"); pos = i + 1; }else if(ch == quot) { if(i > pos) out.write(value.substring(pos, i)); out.write(quotEntity); pos = i + 1; } else if(ch < 32) { //in XML 1.0 only legal character are #x9 | #xA | #xD // and they must be escaped otherwise in attribute value they are normalized to spaces if(ch == 13 || ch == 10 || ch == 9) { if(i > pos) out.write(value.substring(pos, i)); out.write("&#"); out.write(Integer.toString(ch)); out.write(';'); pos = i + 1; } else { throw new IllegalStateException( "character "+Integer.toString(ch)+" is not allowed in output"+getLocation()); // in XML 1.1 legal are [#x1-#xD7FF] // if(ch > 0) { // if(i > pos) out.write(text.substring(pos, i)); // out.write("&#"); // out.write(Integer.toString(ch)); // out.write(';'); // pos = i + 1; // } else { // throw new IllegalStateException( // "character zero is not allowed in XML 1.1 output"+getLocation()); // } } } } if(pos > 0) { out.write(value.substring(pos)); } else { out.write(value); // this is shortcut to the most common case } } protected void writeElementContent(String text, Writer out) throws IOException { // escape '<', '&', ']]>', <32 if necessary int pos = 0; for (int i = 0; i < text.length(); i++) { //TODO: check if doing char[] text.getChars() would be faster than getCharAt(i) ... char ch = text.charAt(i); if(ch == ']') { if(seenBracket) { seenBracketBracket = true; } else { seenBracket = true; } } else { if(ch == '&') { if(i > pos) out.write(text.substring(pos, i)); out.write("&"); pos = i + 1; } else if(ch == '<') { if(i > pos) out.write(text.substring(pos, i)); out.write("<"); pos = i + 1; } else if(seenBracketBracket && ch == '>') { if(i > pos) out.write(text.substring(pos, i)); out.write(">"); pos = i + 1; } else if(ch < 32) { //in XML 1.0 only legal character are #x9 | #xA | #xD if( ch == 9 || ch == 10 || ch == 13) { // pass through // } else if(ch == 13) { //escape // if(i > pos) out.write(text.substring(pos, i)); // out.write("&#"); // out.write(Integer.toString(ch)); // out.write(';'); // pos = i + 1; } else { throw new IllegalStateException( "character "+Integer.toString(ch)+" is not allowed in output"+getLocation()); // in XML 1.1 legal are [#x1-#xD7FF] // if(ch > 0) { // if(i > pos) out.write(text.substring(pos, i)); // out.write("&#"); // out.write(Integer.toString(ch)); // out.write(';'); // pos = i + 1; // } else { // throw new IllegalStateException( // "character zero is not allowed in XML 1.1 output"+getLocation()); // } } } if(seenBracket) { seenBracketBracket = seenBracket = false; } } } if(pos > 0) { out.write(text.substring(pos)); } else { out.write(text); // this is shortcut to the most common case } } protected void writeElementContent(char[] buf, int off, int len, Writer out) throws IOException { // escape '<', '&', ']]>' final int end = off + len; int pos = off; for (int i = off; i < end; i++) { final char ch = buf[i]; if(ch == ']') { if(seenBracket) { seenBracketBracket = true; } else { seenBracket = true; } } else { if(ch == '&') { if(i > pos) { out.write(buf, pos, i - pos); } out.write("&"); pos = i + 1; } else if(ch == '<') { if(i > pos) { out.write(buf, pos, i - pos); } out.write("<"); pos = i + 1; } else if(seenBracketBracket && ch == '>') { if(i > pos) { out.write(buf, pos, i - pos); } out.write(">"); pos = i + 1; } else if(ch < 32) { //in XML 1.0 only legal character are #x9 | #xA | #xD if( ch == 9 || ch == 10 || ch == 13) { // pass through // } else if(ch == 13 ) { //if(ch == '\r') { // if(i > pos) { // out.write(buf, pos, i - pos); // } // out.write("&#"); // out.write(Integer.toString(ch)); // out.write(';'); // pos = i + 1; } else { throw new IllegalStateException( "character "+Integer.toString(ch)+" is not allowed in output"+getLocation()); // in XML 1.1 legal are [#x1-#xD7FF] // if(ch > 0) { // if(i > pos) out.write(text.substring(pos, i)); // out.write("&#"); // out.write(Integer.toString(ch)); // out.write(';'); // pos = i + 1; // } else { // throw new IllegalStateException( // "character zero is not allowed in XML 1.1 output"+getLocation()); // } } } if(seenBracket) { seenBracketBracket = seenBracket = false; } // assert seenBracketBracket == seenBracket == false; } } if(end > pos) { out.write(buf, pos, end - pos); } } /** simple utility method -- good for debugging */ protected static final String printable(String s) { if(s == null) return "null"; StringBuilder retval = new StringBuilder(s.length() + 16); retval.append("'"); char ch; for (int i = 0; i < s.length(); i++) { addPrintable(retval, s.charAt(i)); } retval.append("'"); return retval.toString(); } protected static final String printable(char ch) { StringBuilder retval = new StringBuilder(); addPrintable(retval, ch); return retval.toString(); } private static void addPrintable(StringBuilder retval, char ch) { switch (ch) { case '\b': retval.append("\\b"); break; case '\t': retval.append("\\t"); break; case '\n': retval.append("\\n"); break; case '\f': retval.append("\\f"); break; case '\r': retval.append("\\r"); break; case '\"': retval.append("\\\""); break; case '\'': retval.append("\\\'"); break; case '\\': retval.append("\\\\"); break; default: if (ch < 0x20 || ch > 0x7e) { final String ss = "0000" + Integer.toString(ch, 16); retval.append( "\\u" ).append( ss, ss.length() - 4, ss.length()); } else { retval.append(ch); } } } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/xml/pull/XmlPullParser.java000066400000000000000000001277301251077732300334550ustar00rootroot00000000000000/* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- //------100-columns-wide------>|*/ // for license please see accompanying LICENSE.txt file (available also at http://www.xmlpull.org/) package org.codehaus.plexus.util.xml.pull; import java.io.InputStream; import java.io.IOException; import java.io.Reader; /** * XML Pull Parser is an interface that defines parsing functionality provided * in XMLPULL V1 API (visit this website to * learn more about API and its implementations). * *

          There are following different * kinds of parser depending on which features are set:

            *
          • non-validating parser as defined in XML 1.0 spec when * FEATURE_PROCESS_DOCDECL is set to true *
          • validating parser as defined in XML 1.0 spec when * FEATURE_VALIDATION is true (and that implies that FEATURE_PROCESS_DOCDECL is true) *
          • when FEATURE_PROCESS_DOCDECL is false (this is default and * if different value is required necessary must be changed before parsing is started) * then parser behaves like XML 1.0 compliant non-validating parser under condition that * no DOCDECL is present in XML documents * (internal entities can still be defined with defineEntityReplacementText()). * This mode of operation is intended for operation in constrained environments such as J2ME. *
          * * *

          There are two key methods: next() and nextToken(). While next() provides * access to high level parsing events, nextToken() allows access to lower * level tokens. * *

          The current event state of the parser * can be determined by calling the * getEventType() method. * Initially, the parser is in the START_DOCUMENT * state. * *

          The method next() advances the parser to the * next event. The int value returned from next determines the current parser * state and is identical to the value returned from following calls to * getEventType (). * *

          The following event types are seen by next()

          *
          START_TAG
          An XML start tag was read. *
          TEXT
          Text content was read; * the text content can be retrieved using the getText() method. * (when in validating mode next() will not report ignorable whitespaces, use nextToken() instead) *
          END_TAG
          An end tag was read *
          END_DOCUMENT
          No more events are available *
          * *

          after first next() or nextToken() (or any other next*() method) * is called user application can obtain * XML version, standalone and encoding from XML declaration * in following ways:

            *
          • version: * getProperty("http://xmlpull.org/v1/doc/properties.html#xmldecl-version") * returns String ("1.0") or null if XMLDecl was not read or if property is not supported *
          • standalone: * getProperty("http://xmlpull.org/v1/doc/features.html#xmldecl-standalone") * returns Boolean: null if there was no standalone declaration * or if property is not supported * otherwise returns Boolean(true) if standalone="yes" and Boolean(false) when standalone="no" *
          • encoding: obtained from getInputEncoding() * null if stream had unknown encoding (not set in setInputStream) * and it was not declared in XMLDecl *
          * * A minimal example for using this API may look as follows: *
           * import java.io.IOException;
           * import java.io.StringReader;
           *
           * import org.xmlpull.v1.XmlPullParser;
           * import org.xmlpull.v1.XmlPullParserException.html;
           * import org.xmlpull.v1.XmlPullParserFactory;
           *
           * public class SimpleXmlPullApp
           * {
           *
           *     public static void main (String args[])
           *         throws XmlPullParserException, IOException
           *     {
           *         XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
           *         factory.setNamespaceAware(true);
           *         XmlPullParser xpp = factory.newPullParser();
           *
           *         xpp.setInput( new StringReader ( "<foo>Hello World!</foo>" ) );
           *         int eventType = xpp.getEventType();
           *         while (eventType != xpp.END_DOCUMENT) {
           *          if(eventType == xpp.START_DOCUMENT) {
           *              System.out.println("Start document");
           *          } else if(eventType == xpp.END_DOCUMENT) {
           *              System.out.println("End document");
           *          } else if(eventType == xpp.START_TAG) {
           *              System.out.println("Start tag "+xpp.getName());
           *          } else if(eventType == xpp.END_TAG) {
           *              System.out.println("End tag "+xpp.getName());
           *          } else if(eventType == xpp.TEXT) {
           *              System.out.println("Text "+xpp.getText());
           *          }
           *          eventType = xpp.next();
           *         }
           *     }
           * }
           * 
          * *

          The above example will generate the following output: *

           * Start document
           * Start tag foo
           * Text Hello World!
           * End tag foo
           * 
          * *

          For more details on API usage, please refer to the * quick Introduction available at http://www.xmlpull.org * * @see #defineEntityReplacementText * @see #getName * @see #getNamespace * @see #getText * @see #next * @see #nextToken * @see #setInput * @see #FEATURE_PROCESS_DOCDECL * @see #FEATURE_VALIDATION * @see #START_DOCUMENT * @see #START_TAG * @see #TEXT * @see #END_TAG * @see #END_DOCUMENT * * @author Stefan Haustein * @author Aleksander Slominski */ public interface XmlPullParser { /** This constant represents the default namespace (empty string "") */ String NO_NAMESPACE = ""; // ---------------------------------------------------------------------------- // EVENT TYPES as reported by next() /** * Signalize that parser is at the very beginning of the document * and nothing was read yet. * This event type can only be observed by calling getEvent() * before the first call to next(), nextToken, or nextTag()). * * @see #next * @see #nextToken */ int START_DOCUMENT = 0; /** * Logical end of the xml document. Returned from getEventType, next() * and nextToken() * when the end of the input document has been reached. *

          NOTE: calling again * next() or nextToken() * will result in exception being thrown. * * @see #next * @see #nextToken */ int END_DOCUMENT = 1; /** * Returned from getEventType(), * next(), nextToken() when * a start tag was read. * The name of start tag is available from getName(), its namespace and prefix are * available from getNamespace() and getPrefix() * if namespaces are enabled. * See getAttribute* methods to retrieve element attributes. * See getNamespace* methods to retrieve newly declared namespaces. * * @see #next * @see #nextToken * @see #getName * @see #getPrefix * @see #getNamespace * @see #getAttributeCount * @see #getDepth * @see #getNamespaceCount * @see #getNamespace * @see #FEATURE_PROCESS_NAMESPACES */ int START_TAG = 2; /** * Returned from getEventType(), next(), or * nextToken() when an end tag was read. * The name of start tag is available from getName(), its * namespace and prefix are * available from getNamespace() and getPrefix(). * * @see #next * @see #nextToken * @see #getName * @see #getPrefix * @see #getNamespace * @see #FEATURE_PROCESS_NAMESPACES */ int END_TAG = 3; /** * Character data was read and will is available by calling getText(). *

          Please note: next() will * accumulate multiple * events into one TEXT event, skipping IGNORABLE_WHITESPACE, * PROCESSING_INSTRUCTION and COMMENT events, * In contrast, nextToken() will stop reading * text when any other event is observed. * Also, when the state was reached by calling next(), the text value will * be normalized, whereas getText() will * return unnormalized content in the case of nextToken(). This allows * an exact roundtrip without changing line ends when examining low * level events, whereas for high level applications the text is * normalized appropriately. * * @see #next * @see #nextToken * @see #getText */ int TEXT = 4; // ---------------------------------------------------------------------------- // additional events exposed by lower level nextToken() /** * A CDATA sections was just read; * this token is available only from calls to nextToken(). * A call to next() will accumulate various text events into a single event * of type TEXT. The text contained in the CDATA section is available * by calling getText(). * * @see #nextToken * @see #getText */ int CDSECT = 5; /** * An entity reference was just read; * this token is available from nextToken() * only. The entity name is available by calling getName(). If available, * the replacement text can be obtained by calling getTextt(); otherwise, * the user is responsible for resolving the entity reference. * This event type is never returned from next(); next() will * accumulate the replacement text and other text * events to a single TEXT event. * * @see #nextToken * @see #getText */ int ENTITY_REF = 6; /** * Ignorable whitespace was just read. * This token is available only from nextToken()). * For non-validating * parsers, this event is only reported by nextToken() when outside * the root element. * Validating parsers may be able to detect ignorable whitespace at * other locations. * The ignorable whitespace string is available by calling getText() * *

          NOTE: this is different from calling the * isWhitespace() method, since text content * may be whitespace but not ignorable. * * Ignorable whitespace is skipped by next() automatically; this event * type is never returned from next(). * * @see #nextToken * @see #getText */ int IGNORABLE_WHITESPACE = 7; /** * An XML processing instruction declaration was just read. This * event type is available only via nextToken(). * getText() will return text that is inside the processing instruction. * Calls to next() will skip processing instructions automatically. * @see #nextToken * @see #getText */ int PROCESSING_INSTRUCTION = 8; /** * An XML comment was just read. This event type is this token is * available via nextToken() only; * calls to next() will skip comments automatically. * The content of the comment can be accessed using the getText() * method. * * @see #nextToken * @see #getText */ int COMMENT = 9; /** * An XML document type declaration was just read. This token is * available from nextToken() only. * The unparsed text inside the doctype is available via * the getText() method. * * @see #nextToken * @see #getText */ int DOCDECL = 10; /** * This array can be used to convert the event type integer constants * such as START_TAG or TEXT to * to a string. For example, the value of TYPES[START_TAG] is * the string "START_TAG". * * This array is intended for diagnostic output only. Relying * on the contents of the array may be dangerous since malicious * applications may alter the array, although it is final, due * to limitations of the Java language. */ String [] TYPES = { "START_DOCUMENT", "END_DOCUMENT", "START_TAG", "END_TAG", "TEXT", "CDSECT", "ENTITY_REF", "IGNORABLE_WHITESPACE", "PROCESSING_INSTRUCTION", "COMMENT", "DOCDECL" }; // ---------------------------------------------------------------------------- // namespace related features /** * This feature determines whether the parser processes * namespaces. As for all features, the default value is false. *

          NOTE: The value can not be changed during * parsing an must be set before parsing. * * @see #getFeature * @see #setFeature */ String FEATURE_PROCESS_NAMESPACES = "http://xmlpull.org/v1/doc/features.html#process-namespaces"; /** * This feature determines whether namespace attributes are * exposed via the attribute access methods. Like all features, * the default value is false. This feature cannot be changed * during parsing. * * @see #getFeature * @see #setFeature */ String FEATURE_REPORT_NAMESPACE_ATTRIBUTES = "http://xmlpull.org/v1/doc/features.html#report-namespace-prefixes"; /** * This feature determines whether the document declaration * is processed. If set to false, * the DOCDECL event type is reported by nextToken() * and ignored by next(). * * If this featue is activated, then the document declaration * must be processed by the parser. * *

          Please note: If the document type declaration * was ignored, entity references may cause exceptions * later in the parsing process. * The default value of this feature is false. It cannot be changed * during parsing. * * @see #getFeature * @see #setFeature */ String FEATURE_PROCESS_DOCDECL = "http://xmlpull.org/v1/doc/features.html#process-docdecl"; /** * If this feature is activated, all validation errors as * defined in the XML 1.0 sepcification are reported. * This implies that FEATURE_PROCESS_DOCDECL is true and both, the * internal and external document type declaration will be processed. *

          Please Note: This feature can not be changed * during parsing. The default value is false. * * @see #getFeature * @see #setFeature */ String FEATURE_VALIDATION = "http://xmlpull.org/v1/doc/features.html#validation"; /** * Use this call to change the general behaviour of the parser, * such as namespace processing or doctype declaration handling. * This method must be called before the first call to next or * nextToken. Otherwise, an exception is thrown. *

          Example: call setFeature(FEATURE_PROCESS_NAMESPACES, true) in order * to switch on namespace processing. The initial settings correspond * to the properties requested from the XML Pull Parser factory. * If none were requested, all feautures are deactivated by default. * * @exception XmlPullParserException If the feature is not supported or can not be set * @exception IllegalArgumentException If string with the feature name is null */ void setFeature(String name, boolean state) throws XmlPullParserException; /** * Returns the current value of the given feature. *

          Please note: unknown features are * always returned as false. * * @param name The name of feature to be retrieved. * @return The value of the feature. * @exception IllegalArgumentException if string the feature name is null */ boolean getFeature(String name); /** * Set the value of a property. * * The property name is any fully-qualified URI. * * @exception XmlPullParserException If the property is not supported or can not be set * @exception IllegalArgumentException If string with the property name is null */ void setProperty(String name, Object value) throws XmlPullParserException; /** * Look up the value of a property. * * The property name is any fully-qualified URI. *

          NOTE: unknown properties are always * returned as null. * * @param name The name of property to be retrieved. * @return The value of named property. */ Object getProperty(String name); /** * Set the input source for parser to the given reader and * resets the parser. The event type is set to the initial value * START_DOCUMENT. * Setting the reader to null will just stop parsing and * reset parser state, * allowing the parser to free internal resources * such as parsing buffers. */ void setInput(Reader in) throws XmlPullParserException; /** * Sets the input stream the parser is going to process. * This call resets the parser state and sets the event type * to the initial value START_DOCUMENT. * *

          NOTE: If an input encoding string is passed, * it MUST be used. Otherwise, * if inputEncoding is null, the parser SHOULD try to determine * input encoding following XML 1.0 specification (see below). * If encoding detection is supported then following feature * http://xmlpull.org/v1/doc/features.html#detect-encoding * MUST be true amd otherwise it must be false * * @param inputStream contains a raw byte input stream of possibly * unknown encoding (when inputEncoding is null). * * @param inputEncoding if not null it MUST be used as encoding for inputStream */ void setInput(InputStream inputStream, String inputEncoding) throws XmlPullParserException; /** * Returns the input encoding if known, null otherwise. * If setInput(InputStream, inputEncoding) was called with an inputEncoding * value other than null, this value must be returned * from this method. Otherwise, if inputEncoding is null and * the parser suppports the encoding detection feature * (http://xmlpull.org/v1/doc/features.html#detect-encoding), * it must return the detected encoding. * If setInput(Reader) was called, null is returned. * After first call to next if XML declaration was present this method * will return encoding declared. */ String getInputEncoding(); /** * Set new value for entity replacement text as defined in * XML 1.0 Section 4.5 * Construction of Internal Entity Replacement Text. * If FEATURE_PROCESS_DOCDECL or FEATURE_VALIDATION are set, calling this * function will result in an exception -- when processing of DOCDECL is * enabled, there is no need to the entity replacement text manually. * *

          The motivation for this function is to allow very small * implementations of XMLPULL that will work in J2ME environments. * Though these implementations may not be able to process the document type * declaration, they still can work with known DTDs by using this function. * *

          Please notes: The given value is used literally as replacement text * and it corresponds to declaring entity in DTD that has all special characters * escaped: left angle bracket is replaced with &lt;, ampersnad with &amp; * and so on. * *

          Note: The given value is the literal replacement text and must not * contain any other entity reference (if it contains any entity reference * there will be no further replacement). * *

          Note: The list of pre-defined entity names will * always contain standard XML entities such as * amp (&amp;), lt (&lt;), gt (&gt;), quot (&quot;), and apos (&apos;). * Those cannot be redefined by this method! * * @see #setInput * @see #FEATURE_PROCESS_DOCDECL * @see #FEATURE_VALIDATION */ void defineEntityReplacementText( String entityName, String replacementText ) throws XmlPullParserException; /** * Returns the numbers of elements in the namespace stack for the given * depth. * If namespaces are not enabled, 0 is returned. * *

          NOTE: when parser is on END_TAG then it is allowed to call * this function with getDepth()+1 argument to retrieve position of namespace * prefixes and URIs that were declared on corresponding START_TAG. *

          NOTE: to retrieve lsit of namespaces declared in current element:

               *       XmlPullParser pp = ...
               *       int nsStart = pp.getNamespaceCount(pp.getDepth()-1);
               *       int nsEnd = pp.getNamespaceCount(pp.getDepth());
               *       for (int i = nsStart; i < nsEnd; i++) {
               *          String prefix = pp.getNamespacePrefix(i);
               *          String ns = pp.getNamespaceUri(i);
               *           // ...
               *      }
               * 
          * * @see #getNamespacePrefix * @see #getNamespaceUri * @see #getNamespace() * @see #getNamespace(String) */ int getNamespaceCount(int depth) throws XmlPullParserException; /** * Returns the namespace prefixe for the given position * in the namespace stack. * Default namespace declaration (xmlns='...') will have null as prefix. * If the given index is out of range, an exception is thrown. *

          Please note: when the parser is on an END_TAG, * namespace prefixes that were declared * in the corresponding START_TAG are still accessible * although they are no longer in scope. */ String getNamespacePrefix(int pos) throws XmlPullParserException; /** * Returns the namespace URI for the given position in the * namespace stack * If the position is out of range, an exception is thrown. *

          NOTE: when parser is on END_TAG then namespace prefixes that were declared * in corresponding START_TAG are still accessible even though they are not in scope */ String getNamespaceUri(int pos) throws XmlPullParserException; /** * Returns the URI corresponding to the given prefix, * depending on current state of the parser. * *

          If the prefix was not declared in the current scope, * null is returned. The default namespace is included * in the namespace table and is available via * getNamespace (null). * *

          This method is a convenience method for * *

               *  for (int i = getNamespaceCount(getDepth ())-1; i >= 0; i--) {
               *   if (getNamespacePrefix(i).equals( prefix )) {
               *     return getNamespaceUri(i);
               *   }
               *  }
               *  return null;
               * 
          * *

          Please note: parser implementations * may provide more efifcient lookup, e.g. using a Hashtable. * The 'xml' prefix is bound to "http://www.w3.org/XML/1998/namespace", as * defined in the * Namespaces in XML * specification. Analogous, the 'xmlns' prefix is resolved to * http://www.w3.org/2000/xmlns/ * * @see #getNamespaceCount * @see #getNamespacePrefix * @see #getNamespaceUri */ String getNamespace (String prefix); // -------------------------------------------------------------------------- // miscellaneous reporting methods /** * Returns the current depth of the element. * Outside the root element, the depth is 0. The * depth is incremented by 1 when a start tag is reached. * The depth is decremented AFTER the end tag * event was observed. * *

               * <!-- outside -->     0
               * <root>                  1
               *   sometext                 1
               *     <foobar>         2
               *     </foobar>        2
               * </root>              1
               * <!-- outside -->     0
               * 
          */ int getDepth(); /** * Returns a short text describing the current parser state, including * the position, a * description of the current event and the data source if known. * This method is especially useful to provide meaningful * error messages and for debugging purposes. */ String getPositionDescription (); /** * Returns the current line number, starting from 1. * When the parser does not know the current line number * or can not determine it, -1 is returned (e.g. for WBXML). * * @return current line number or -1 if unknown. */ int getLineNumber(); /** * Returns the current column number, starting from 0. * When the parser does not know the current column number * or can not determine it, -1 is returned (e.g. for WBXML). * * @return current column number or -1 if unknown. */ int getColumnNumber(); // -------------------------------------------------------------------------- // TEXT related methods /** * Checks whether the current TEXT event contains only whitespace * characters. * For IGNORABLE_WHITESPACE, this is always true. * For TEXT and CDSECT, false is returned when the current event text * contains at least one non-white space character. For any other * event type an exception is thrown. * *

          Please note: non-validating parsers are not * able to distinguish whitespace and ignorable whitespace, * except from whitespace outside the root element. Ignorable * whitespace is reported as separate event, which is exposed * via nextToken only. * */ boolean isWhitespace() throws XmlPullParserException; /** * Returns the text content of the current event as String. * The value returned depends on current event type, * for example for TEXT event it is element content * (this is typical case when next() is used). * * See description of nextToken() for detailed description of * possible returned values for different types of events. * *

          NOTE: in case of ENTITY_REF, this method returns * the entity replacement text (or null if not available). This is * the only case where * getText() and getTextCharacters() return different values. * * @see #getEventType * @see #next * @see #nextToken */ String getText (); /** * Returns the buffer that contains the text of the current event, * as well as the start offset and length relevant for the current * event. See getText(), next() and nextToken() for description of possible returned values. * *

          Please note: this buffer must not * be modified and its content MAY change after a call to * next() or nextToken(). This method will always return the * same value as getText(), except for ENTITY_REF. In the case * of ENTITY ref, getText() returns the replacement text and * this method returns the actual input buffer containing the * entity name. * If getText() returns null, this method returns null as well and * the values returned in the holder array MUST be -1 (both start * and length). * * @see #getText * @see #next * @see #nextToken * * @param holderForStartAndLength Must hold an 2-element int array * into which the start offset and length values will be written. * @return char buffer that contains the text of the current event * (null if the current event has no text associated). */ char[] getTextCharacters(int [] holderForStartAndLength); // -------------------------------------------------------------------------- // START_TAG / END_TAG shared methods /** * Returns the namespace URI of the current element. * The default namespace is represented * as empty string. * If namespaces are not enabled, an empty String ("") is always returned. * The current event must be START_TAG or END_TAG; otherwise, * null is returned. */ String getNamespace (); /** * For START_TAG or END_TAG events, the (local) name of the current * element is returned when namespaces are enabled. When namespace * processing is disabled, the raw name is returned. * For ENTITY_REF events, the entity name is returned. * If the current event is not START_TAG, END_TAG, or ENTITY_REF, * null is returned. *

          Please note: To reconstruct the raw element name * when namespaces are enabled and the prefix is not null, * you will need to add the prefix and a colon to localName.. * */ String getName(); /** * Returns the prefix of the current element. * If the element is in the default namespace (has no prefix), * null is returned. * If namespaces are not enabled, or the current event * is not START_TAG or END_TAG, null is returned. */ String getPrefix(); /** * Returns true if the current event is START_TAG and the tag * is degenerated * (e.g. <foobar/>). *

          NOTE: if the parser is not on START_TAG, an exception * will be thrown. */ boolean isEmptyElementTag() throws XmlPullParserException; // -------------------------------------------------------------------------- // START_TAG Attributes retrieval methods /** * Returns the number of attributes of the current start tag, or * -1 if the current event type is not START_TAG * * @see #getAttributeNamespace * @see #getAttributeName * @see #getAttributePrefix * @see #getAttributeValue */ int getAttributeCount(); /** * Returns the namespace URI of the attribute * with the given index (starts from 0). * Returns an empty string ("") if namespaces are not enabled * or the attribute has no namespace. * Throws an IndexOutOfBoundsException if the index is out of range * or the current event type is not START_TAG. * *

          NOTE: if FEATURE_REPORT_NAMESPACE_ATTRIBUTES is set * then namespace attributes (xmlns:ns='...') must be reported * with namespace * http://www.w3.org/2000/xmlns/ * (visit this URL for description!). * The default namespace attribute (xmlns="...") will be reported with empty namespace. *

          NOTE:The xml prefix is bound as defined in * Namespaces in XML * specification to "http://www.w3.org/XML/1998/namespace". * * @param index zero based index of attribute * @return attribute namespace, * empty string ("") is returned if namesapces processing is not enabled or * namespaces processing is enabled but attribute has no namespace (it has no prefix). */ String getAttributeNamespace (int index); /** * Returns the local name of the specified attribute * if namespaces are enabled or just attribute name if namespaces are disabled. * Throws an IndexOutOfBoundsException if the index is out of range * or current event type is not START_TAG. * * @param index zero based index of attribute * @return attribute name (null is never returned) */ String getAttributeName (int index); /** * Returns the prefix of the specified attribute * Returns null if the element has no prefix. * If namespaces are disabled it will always return null. * Throws an IndexOutOfBoundsException if the index is out of range * or current event type is not START_TAG. * * @param index zero based index of attribute * @return attribute prefix or null if namespaces processing is not enabled. */ String getAttributePrefix(int index); /** * Returns the type of the specified attribute * If parser is non-validating it MUST return CDATA. * * @param index zero based index of attribute * @return attribute type (null is never returned) */ String getAttributeType(int index); /** * Returns if the specified attribute was not in input was declared in XML. * If parser is non-validating it MUST always return false. * This information is part of XML infoset: * * @param index zero based index of attribute * @return false if attribute was in input */ boolean isAttributeDefault(int index); /** * Returns the given attributes value. * Throws an IndexOutOfBoundsException if the index is out of range * or current event type is not START_TAG. * *

          NOTE: attribute value must be normalized * (including entity replacement text if PROCESS_DOCDECL is false) as described in * XML 1.0 section * 3.3.3 Attribute-Value Normalization * * @see #defineEntityReplacementText * * @param index zero based index of attribute * @return value of attribute (null is never returned) */ String getAttributeValue(int index); /** * Returns the attributes value identified by namespace URI and namespace localName. * If namespaces are disabled namespace must be null. * If current event type is not START_TAG then IndexOutOfBoundsException will be thrown. * *

          NOTE: attribute value must be normalized * (including entity replacement text if PROCESS_DOCDECL is false) as described in * XML 1.0 section * 3.3.3 Attribute-Value Normalization * * @see #defineEntityReplacementText * * @param namespace Namespace of the attribute if namespaces are enabled otherwise must be null * @param name If namespaces enabled local name of attribute otherwise just attribute name * @return value of attribute or null if attribute with given name does not exist */ String getAttributeValue(String namespace, String name); // -------------------------------------------------------------------------- // actual parsing methods /** * Returns the type of the current event (START_TAG, END_TAG, TEXT, etc.) * * @see #next() * @see #nextToken() */ int getEventType() throws XmlPullParserException; /** * Get next parsing event - element content wil be coalesced and only one * TEXT event must be returned for whole element content * (comments and processing instructions will be ignored and emtity references * must be expanded or exception mus be thrown if entity reerence can not be exapnded). * If element content is empty (content is "") then no TEXT event will be reported. * *

          NOTE: empty element (such as <tag/>) will be reported * with two separate events: START_TAG, END_TAG - it must be so to preserve * parsing equivalency of empty element to <tag></tag>. * (see isEmptyElementTag ()) * * @see #isEmptyElementTag * @see #START_TAG * @see #TEXT * @see #END_TAG * @see #END_DOCUMENT */ int next() throws XmlPullParserException, IOException; /** * This method works similarly to next() but will expose * additional event types (COMMENT, CDSECT, DOCDECL, ENTITY_REF, PROCESSING_INSTRUCTION, or * IGNORABLE_WHITESPACE) if they are available in input. * *

          If special feature * FEATURE_XML_ROUNDTRIP * (identified by URI: http://xmlpull.org/v1/doc/features.html#xml-roundtrip) * is enabled it is possible to do XML document round trip ie. reproduce * exectly on output the XML input using getText(): * returned content is always unnormalized (exactly as in input). * Otherwise returned content is end-of-line normalized as described * XML 1.0 End-of-Line Handling * and. Also when this feature is enabled exact content of START_TAG, END_TAG, * DOCDECL and PROCESSING_INSTRUCTION is available. * *

          Here is the list of tokens that can be returned from nextToken() * and what getText() and getTextCharacters() returns:

          *
          START_DOCUMENT
          null *
          END_DOCUMENT
          null *
          START_TAG
          null unless FEATURE_XML_ROUNDTRIP * enabled and then returns XML tag, ex: <tag attr='val'> *
          END_TAG
          null unless FEATURE_XML_ROUNDTRIP * id enabled and then returns XML tag, ex: </tag> *
          TEXT
          return element content. *
          Note: that element content may be delivered in multiple consecutive TEXT events. *
          IGNORABLE_WHITESPACE
          return characters that are determined to be ignorable white * space. If the FEATURE_XML_ROUNDTRIP is enabled all whitespace content outside root * element will always reported as IGNORABLE_WHITESPACE otherise rteporting is optional. *
          Note: that element content may be delevered in multiple consecutive IGNORABLE_WHITESPACE events. *
          CDSECT
          * return text inside CDATA * (ex. 'fo<o' from <!CDATA[fo<o]]>) *
          PROCESSING_INSTRUCTION
          * if FEATURE_XML_ROUNDTRIP is true * return exact PI content ex: 'pi foo' from <?pi foo?> * otherwise it may be exact PI content or concatenation of PI target, * space and data so for example for * <?target data?> string "target data" may * be returned if FEATURE_XML_ROUNDTRIP is false. *
          COMMENT
          return comment content ex. 'foo bar' from <!--foo bar--> *
          ENTITY_REF
          getText() MUST return entity replacement text if PROCESS_DOCDECL is false * otherwise getText() MAY return null, * additionally getTextCharacters() MUST return entity name * (for example 'entity_name' for &entity_name;). *
          NOTE: this is the only place where value returned from getText() and * getTextCharacters() are different *
          NOTE: it is user responsibility to resolve entity reference * if PROCESS_DOCDECL is false and there is no entity replacement text set in * defineEntityReplacementText() method (getText() will be null) *
          NOTE: character entities (ex. &#32;) and standard entities such as * &amp; &lt; &gt; &quot; &apos; are reported as well * and are not reported as TEXT tokens but as ENTITY_REF tokens! * This requirement is added to allow to do roundtrip of XML documents! *
          DOCDECL
          * if FEATURE_XML_ROUNDTRIP is true or PROCESS_DOCDECL is false * then return what is inside of DOCDECL for example it returns:
               * " titlepage SYSTEM "http://www.foo.bar/dtds/typo.dtd"
               * [<!ENTITY % active.links "INCLUDE">]"
          *

          for input document that contained:

               * <!DOCTYPE titlepage SYSTEM "http://www.foo.bar/dtds/typo.dtd"
               * [<!ENTITY % active.links "INCLUDE">]>
          * otherwise if FEATURE_XML_ROUNDTRIP is false and PROCESS_DOCDECL is true * then what is returned is undefined (it may be even null) *
          *
          * *

          NOTE: there is no gurantee that there will only one TEXT or * IGNORABLE_WHITESPACE event from nextToken() as parser may chose to deliver element content in * multiple tokens (dividing element content into chunks) * *

          NOTE: whether returned text of token is end-of-line normalized * is depending on FEATURE_XML_ROUNDTRIP. * *

          NOTE: XMLDecl (<?xml ...?>) is not reported but its content * is available through optional properties (see class description above). * * @see #next * @see #START_TAG * @see #TEXT * @see #END_TAG * @see #END_DOCUMENT * @see #COMMENT * @see #DOCDECL * @see #PROCESSING_INSTRUCTION * @see #ENTITY_REF * @see #IGNORABLE_WHITESPACE */ int nextToken() throws XmlPullParserException, IOException; //----------------------------------------------------------------------------- // utility methods to mak XML parsing easier ... /** * Test if the current event is of the given type and if the * namespace and name do match. null will match any namespace * and any name. If the test is not passed, an exception is * thrown. The exception text indicates the parser position, * the expected event and the current event that is not meeting the * requirement. * *

          Essentially it does this *

               *  if (type != getEventType()
               *  || (namespace != null &&  !namespace.equals( getNamespace () ) )
               *  || (name != null &&  !name.equals( getName() ) ) )
               *     throw new XmlPullParserException( "expected "+ TYPES[ type ]+getPositionDescription());
               * 
          */ void require(int type, String namespace, String name) throws XmlPullParserException, IOException; /** * If current event is START_TAG then if next element is TEXT then element content is returned * or if next event is END_TAG then empty string is returned, otherwise exception is thrown. * After calling this function successfully parser will be positioned on END_TAG. * *

          The motivation for this function is to allow to parse consistently both * empty elements and elements that has non empty content, for example for input:

            *
          1. <tag>foo</tag> *
          2. <tag></tag> (which is equivalent to <tag/> * both input can be parsed with the same code: *
                 *   p.nextTag()
                 *   p.requireEvent(p.START_TAG, "", "tag");
                 *   String content = p.nextText();
                 *   p.requireEvent(p.END_TAG, "", "tag");
                 * 
            * This function together with nextTag make it very easy to parse XML that has * no mixed content. * * *

            Essentially it does this *

                 *  if(getEventType() != START_TAG) {
                 *     throw new XmlPullParserException(
                 *       "parser must be on START_TAG to read next text", this, null);
                 *  }
                 *  int eventType = next();
                 *  if(eventType == TEXT) {
                 *     String result = getText();
                 *     eventType = next();
                 *     if(eventType != END_TAG) {
                 *       throw new XmlPullParserException(
                 *          "event TEXT it must be immediately followed by END_TAG", this, null);
                 *      }
                 *      return result;
                 *  } else if(eventType == END_TAG) {
                 *     return "";
                 *  } else {
                 *     throw new XmlPullParserException(
                 *       "parser must be on START_TAG or TEXT to read text", this, null);
                 *  }
                 * 
            */ String nextText() throws XmlPullParserException, IOException; /** * Call next() and return event if it is START_TAG or END_TAG * otherwise throw an exception. * It will skip whitespace TEXT before actual tag if any. * *

            essentially it does this *

                 *   int eventType = next();
                 *   if(eventType == TEXT &&  isWhitespace()) {   // skip whitespace
                 *      eventType = next();
                 *   }
                 *   if (eventType != START_TAG &&  eventType != END_TAG) {
                 *      throw new XmlPullParserException("expected start or end tag", this, null);
                 *   }
                 *   return eventType;
                 * 
            */ int nextTag() throws XmlPullParserException, IOException; } XmlPullParserException.java000066400000000000000000000046441251077732300352530ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/xml/pull/* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- //------100-columns-wide------>|*/ // for license please see accompanying LICENSE.txt file (available also at http://www.xmlpull.org/) package org.codehaus.plexus.util.xml.pull; /** * This exception is thrown to signal XML Pull Parser related faults. * * @author Aleksander Slominski */ public class XmlPullParserException extends Exception { /** * @deprecated use generic getCause() method */ protected Throwable detail; protected int row = -1; protected int column = -1; /* public XmlPullParserException() { }*/ public XmlPullParserException(String s) { super(s); } /* public XmlPullParserException(String s, Throwable thrwble) { super(s); this.detail = thrwble; } public XmlPullParserException(String s, int row, int column) { super(s); this.row = row; this.column = column; } */ public XmlPullParserException(String msg, XmlPullParser parser, Throwable chain) { super ((msg == null ? "" : msg+" ") + (parser == null ? "" : "(position:"+parser.getPositionDescription()+") ") + (chain == null ? "" : "caused by: "+chain), chain); if (parser != null) { this.row = parser.getLineNumber(); this.column = parser.getColumnNumber(); } this.detail = chain; } /** * @deprecated Use the generic getCause() method * @return */ public Throwable getDetail() { return getCause(); } // public void setDetail(Throwable cause) { this.detail = cause; } public int getLineNumber() { return row; } public int getColumnNumber() { return column; } /* public String getMessage() { if(detail == null) return super.getMessage(); else return super.getMessage() + "; nested exception is: \n\t" + detail.getMessage(); } */ //NOTE: code that prints this and detail is difficult in J2ME public void printStackTrace() { if (getCause() == null) { super.printStackTrace(); } else { synchronized(System.err) { System.err.println(super.getMessage() + "; nested exception is:"); getCause().printStackTrace(); } } } } plexus-utils-plexus-utils-3.0.22/src/main/java/org/codehaus/plexus/util/xml/pull/XmlSerializer.java000066400000000000000000000352551251077732300334750ustar00rootroot00000000000000/* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- //------100-columns-wide------>|*/ // for license please see accompanying LICENSE.txt file (available also at http://www.xmlpull.org/) package org.codehaus.plexus.util.xml.pull; import java.io.IOException; import java.io.OutputStream; import java.io.Writer; /** * Define an interface to serialization of XML Infoset. * This interface abstracts away if serialized XML is XML 1.0 compatible text or * other formats of XML 1.0 serializations (such as binary XML for example with WBXML). * *

            PLEASE NOTE: This interface will be part of XmlPull 1.2 API. * It is included as basis for discussion. It may change in any way. * *

            Exceptions that may be thrown are: IOException or runtime exception * (more runtime exceptions can be thrown but are not declared and as such * have no semantics defined for this interface): *

              *
            • IllegalArgumentException - for almost all methods to signal that * argument is illegal *
            • IllegalStateException - to signal that call has good arguments but * is not expected here (violation of contract) and for features/properties * when requesting setting unimplemented feature/property * (UnsupportedOperationException would be better but it is not in MIDP) *
            * *

            NOTE: writing CDSECT, ENTITY_REF, IGNORABLE_WHITESPACE, * PROCESSING_INSTRUCTION, COMMENT, and DOCDECL in some implementations * may not be supported (for example when serializing to WBXML). * In such case IllegalStateException will be thrown and it is recommended * to use an optional feature to signal that implementation is not * supporting this kind of output. */ public interface XmlSerializer { /** * Set feature identified by name (recommended to be URI for uniqueness). * Some well known optional features are defined in * * http://www.xmlpull.org/v1/doc/features.html. * * If feature is not recognized or can not be set * then IllegalStateException MUST be thrown. * * @exception IllegalStateException If the feature is not supported or can not be set */ void setFeature(String name, boolean state) throws IllegalArgumentException, IllegalStateException; /** * Return the current value of the feature with given name. *

            NOTE: unknown properties are always returned as null * * @param name The name of feature to be retrieved. * @return The value of named feature. * @exception IllegalArgumentException if feature string is null */ boolean getFeature(String name); /** * Set the value of a property. * (the property name is recommended to be URI for uniqueness). * Some well known optional properties are defined in * * http://www.xmlpull.org/v1/doc/properties.html. * * If property is not recognized or can not be set * then IllegalStateException MUST be thrown. * * @exception IllegalStateException if the property is not supported or can not be set */ void setProperty(String name, Object value) throws IllegalArgumentException, IllegalStateException; /** * Look up the value of a property. * * The property name is any fully-qualified URI. I *

            NOTE: unknown properties are always returned as null * * @param name The name of property to be retrieved. * @return The value of named property. */ Object getProperty(String name); /** * Set to use binary output stream with given encoding. */ void setOutput (OutputStream os, String encoding) throws IOException, IllegalArgumentException, IllegalStateException; /** * Set the output to the given writer. *

            WARNING no information about encoding is available! */ void setOutput (Writer writer) throws IOException, IllegalArgumentException, IllegalStateException; /** * Write <?xml declaration with encoding (if encoding not null) * and standalone flag (if standalone not null) * This method can only be called just after setOutput. */ void startDocument (String encoding, Boolean standalone) throws IOException, IllegalArgumentException, IllegalStateException; /** * Finish writing. All unclosed start tags will be closed and output * will be flushed. After calling this method no more output can be * serialized until next call to setOutput() */ void endDocument () throws IOException, IllegalArgumentException, IllegalStateException; /** * Binds the given prefix to the given namespace. * This call is valid for the next element including child elements. * The prefix and namespace MUST be always declared even if prefix * is not used in element (startTag() or attribute()) - for XML 1.0 * it must result in declaring xmlns:prefix='namespace' * (or xmlns:prefix="namespace" depending what character is used * to quote attribute value). * *

            NOTE: this method MUST be called directly before startTag() * and if anything but startTag() or setPrefix() is called next there will be exception. *

            NOTE: prefixes "xml" and "xmlns" are already bound * and can not be redefined see: * Namespaces in XML Errata. *

            NOTE: to set default namespace use as prefix empty string. * * @param prefix must be not null (or IllegalArgumentException is thrown) * @param namespace must be not null */ void setPrefix (String prefix, String namespace) throws IOException, IllegalArgumentException, IllegalStateException; /** * Return namespace that corresponds to given prefix * If there is no prefix bound to this namespace return null * but if generatePrefix is false then return generated prefix. * *

            NOTE: if the prefix is empty string "" and default namespace is bound * to this prefix then empty string ("") is returned. * *

            NOTE: prefixes "xml" and "xmlns" are already bound * will have values as defined * Namespaces in XML specification */ String getPrefix (String namespace, boolean generatePrefix) throws IllegalArgumentException; /** * Returns the current depth of the element. * Outside the root element, the depth is 0. The * depth is incremented by 1 when startTag() is called. * The depth is decremented after the call to endTag() * event was observed. * *

                 * <!-- outside -->     0
                 * <root>               1
                 *   sometext                 1
                 *     <foobar>         2
                 *     </foobar>        2
                 * </root>              1
                 * <!-- outside -->     0
                 * 
            */ int getDepth(); /** * Returns the namespace URI of the current element as set by startTag(). * *

            NOTE: that means in particular that:

              *
            • if there was startTag("", ...) then getNamespace() returns "" *
            • if there was startTag(null, ...) then getNamespace() returns null *
            * * @return namespace set by startTag() that is currently in scope */ String getNamespace (); /** * Returns the name of the current element as set by startTag(). * It can only be null before first call to startTag() * or when last endTag() is called to close first startTag(). * * @return namespace set by startTag() that is currently in scope */ String getName(); /** * Writes a start tag with the given namespace and name. * If there is no prefix defined for the given namespace, * a prefix will be defined automatically. * The explicit prefixes for namespaces can be established by calling setPrefix() * immediately before this method. * If namespace is null no namespace prefix is printed but just name. * If namespace is empty string then serializer will make sure that * default empty namespace is declared (in XML 1.0 xmlns='') * or throw IllegalStateException if default namespace is already bound * to non-empty string. */ XmlSerializer startTag (String namespace, String name) throws IOException, IllegalArgumentException, IllegalStateException; /** * Write an attribute. Calls to attribute() MUST follow a call to * startTag() immediately. If there is no prefix defined for the * given namespace, a prefix will be defined automatically. * If namespace is null or empty string * no namespace prefix is printed but just name. */ XmlSerializer attribute (String namespace, String name, String value) throws IOException, IllegalArgumentException, IllegalStateException; /** * Write end tag. Repetition of namespace and name is just for avoiding errors. *

            Background: in kXML endTag had no arguments, and non matching tags were * very difficult to find... * If namespace is null no namespace prefix is printed but just name. * If namespace is empty string then serializer will make sure that * default empty namespace is declared (in XML 1.0 xmlns=''). */ XmlSerializer endTag (String namespace, String name) throws IOException, IllegalArgumentException, IllegalStateException; // /** // * Writes a start tag with the given namespace and name. // *
            If there is no prefix defined (prefix == null) for the given namespace, // * a prefix will be defined automatically. // *
            If explicit prefixes is passed (prefix != null) then it will be used // *and namespace declared if not already declared or // * throw IllegalStateException the same prefix was already set on this // * element (setPrefix()) and was bound to different namespace. // *
            If namespace is null then prefix must be null too or IllegalStateException is thrown. // *
            If namespace is null then no namespace prefix is printed but just name. // *
            If namespace is empty string then serializer will make sure that // * default empty namespace is declared (in XML 1.0 xmlns='') // * or throw IllegalStateException if default namespace is already bound // * to non-empty string. // */ // XmlSerializer startTag (String prefix, String namespace, String name) // throws IOException, IllegalArgumentException, IllegalStateException; // // /** // * Write an attribute. Calls to attribute() MUST follow a call to // * startTag() immediately. // *
            If there is no prefix defined (prefix == null) for the given namespace, // * a prefix will be defined automatically. // *
            If explicit prefixes is passed (prefix != null) then it will be used // * and namespace declared if not already declared or // * throw IllegalStateException the same prefix was already set on this // * element (setPrefix()) and was bound to different namespace. // *
            If namespace is null then prefix must be null too or IllegalStateException is thrown. // *
            If namespace is null then no namespace prefix is printed but just name. // *
            If namespace is empty string then serializer will make sure that // * default empty namespace is declared (in XML 1.0 xmlns='') // * or throw IllegalStateException if default namespace is already bound // * to non-empty string. // */ // XmlSerializer attribute (String prefix, String namespace, String name, String value) // throws IOException, IllegalArgumentException, IllegalStateException; // // /** // * Write end tag. Repetition of namespace, prefix, and name is just for avoiding errors. // *
            If namespace or name arguments are different from corresponding startTag call // * then IllegalArgumentException is thrown, if prefix argument is not null and is different // * from corresponding starTag then IllegalArgumentException is thrown. // *
            If namespace is null then prefix must be null too or IllegalStateException is thrown. // *
            If namespace is null then no namespace prefix is printed but just name. // *
            If namespace is empty string then serializer will make sure that // * default empty namespace is declared (in XML 1.0 xmlns=''). // *

            Background: in kXML endTag had no arguments, and non matching tags were // * very difficult to find...

            // */ // ALEK: This is really optional as prefix in end tag MUST correspond to start tag but good for error checking // XmlSerializer endTag (String prefix, String namespace, String name) // throws IOException, IllegalArgumentException, IllegalStateException; /** * Writes text, where special XML chars are escaped automatically */ XmlSerializer text (String text) throws IOException, IllegalArgumentException, IllegalStateException; /** * Writes text, where special XML chars are escaped automatically */ XmlSerializer text (char [] buf, int start, int len) throws IOException, IllegalArgumentException, IllegalStateException; void cdsect (String text) throws IOException, IllegalArgumentException, IllegalStateException; void entityRef (String text) throws IOException, IllegalArgumentException, IllegalStateException; void processingInstruction (String text) throws IOException, IllegalArgumentException, IllegalStateException; void comment (String text) throws IOException, IllegalArgumentException, IllegalStateException; void docdecl (String text) throws IOException, IllegalArgumentException, IllegalStateException; void ignorableWhitespace (String text) throws IOException, IllegalArgumentException, IllegalStateException; /** * Write all pending output to the stream. * If method startTag() or attribute() was called then start tag is closed (final >) * before flush() is called on underlying output stream. * *

            NOTE: if there is need to close start tag * (so no more attribute() calls are allowed) but without flushing output * call method text() with empty string (text("")). * */ void flush () throws IOException; } plexus-utils-plexus-utils-3.0.22/src/main/javadoc/000077500000000000000000000000001251077732300220615ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/javadoc/org/000077500000000000000000000000001251077732300226505ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/javadoc/org/codehaus/000077500000000000000000000000001251077732300244435ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/javadoc/org/codehaus/plexus/000077500000000000000000000000001251077732300257635ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/javadoc/org/codehaus/plexus/util/000077500000000000000000000000001251077732300267405ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/javadoc/org/codehaus/plexus/util/cli/000077500000000000000000000000001251077732300275075ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/javadoc/org/codehaus/plexus/util/cli/package.html000066400000000000000000000000461251077732300317700ustar00rootroot00000000000000 Command-line utilities. plexus-utils-plexus-utils-3.0.22/src/main/javadoc/org/codehaus/plexus/util/cli/shell/000077500000000000000000000000001251077732300306165ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/javadoc/org/codehaus/plexus/util/cli/shell/package.html000066400000000000000000000000371251077732300330770ustar00rootroot00000000000000 Shell utilities. plexus-utils-plexus-utils-3.0.22/src/main/javadoc/org/codehaus/plexus/util/dag/000077500000000000000000000000001251077732300274735ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/javadoc/org/codehaus/plexus/util/dag/package.html000066400000000000000000000000601251077732300317500ustar00rootroot00000000000000 Directed Acyclic Graph utilities. plexus-utils-plexus-utils-3.0.22/src/main/javadoc/org/codehaus/plexus/util/interpolation/000077500000000000000000000000001251077732300316275ustar00rootroot00000000000000package.html000066400000000000000000000000471251077732300340320ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/javadoc/org/codehaus/plexus/util/interpolation Interpolation utilities. plexus-utils-plexus-utils-3.0.22/src/main/javadoc/org/codehaus/plexus/util/introspection/000077500000000000000000000000001251077732300316405ustar00rootroot00000000000000package.html000066400000000000000000000000471251077732300340430ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/javadoc/org/codehaus/plexus/util/introspection Introspection utilities. plexus-utils-plexus-utils-3.0.22/src/main/javadoc/org/codehaus/plexus/util/io/000077500000000000000000000000001251077732300273475ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/javadoc/org/codehaus/plexus/util/io/package.html000066400000000000000000000015331251077732300316320ustar00rootroot00000000000000 Facades to create {@code InputStream}s representing various kinds of data sources, identically. plexus-utils-plexus-utils-3.0.22/src/main/javadoc/org/codehaus/plexus/util/package.html000066400000000000000000000001331251077732300312160ustar00rootroot00000000000000 Miscellaneous utilities, mainly dealing with I/O, strings, and filesystems. plexus-utils-plexus-utils-3.0.22/src/main/javadoc/org/codehaus/plexus/util/reflection/000077500000000000000000000000001251077732300310725ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/javadoc/org/codehaus/plexus/util/reflection/package.html000066400000000000000000000000441251077732300333510ustar00rootroot00000000000000 Reflection utilities. plexus-utils-plexus-utils-3.0.22/src/main/javadoc/org/codehaus/plexus/util/xml/000077500000000000000000000000001251077732300275405ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/javadoc/org/codehaus/plexus/util/xml/package.html000066400000000000000000000000351251077732300320170ustar00rootroot00000000000000 XML utilities. plexus-utils-plexus-utils-3.0.22/src/main/javadoc/org/codehaus/plexus/util/xml/pull/000077500000000000000000000000001251077732300305145ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/javadoc/org/codehaus/plexus/util/xml/pull/package.html000066400000000000000000000004541251077732300330000ustar00rootroot00000000000000 XML Pull Parser interface and implementation. XML Pull Parser is an interface that defines parsing functionlity provided in XMLPULL V1 API (visit this website to learn more about API and its implementations). plexus-utils-plexus-utils-3.0.22/src/main/resources/000077500000000000000000000000001251077732300224645ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/resources/META-INF/000077500000000000000000000000001251077732300236245ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/resources/META-INF/LICENSE000066400000000000000000000261361251077732300246410ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. plexus-utils-plexus-utils-3.0.22/src/main/resources/META-INF/NOTICE000066400000000000000000000007321251077732300245320ustar00rootroot00000000000000This product includes software developed by the Indiana University Extreme! Lab (http://www.extreme.indiana.edu/). This product includes software developed by The Apache Software Foundation (http://www.apache.org/). This product includes software developed by ThoughtWorks (http://www.thoughtworks.com). This product includes software developed by javolution (http://javolution.org/). This product includes software developed by Rome (https://rome.dev.java.net/).plexus-utils-plexus-utils-3.0.22/src/main/resources/licenses/000077500000000000000000000000001251077732300242715ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/main/resources/licenses/extreme.indiana.edu.license.TXT000066400000000000000000000042201251077732300321400ustar00rootroot00000000000000Indiana University Extreme! Lab Software License Version 1.1.1 Copyright (c) 2002 Extreme! Lab, Indiana University. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The end-user documentation included with the redistribution, if any, must include the following acknowledgment: "This product includes software developed by the Indiana University Extreme! Lab (http://www.extreme.indiana.edu/)." Alternately, this acknowledgment may appear in the software itself, if and wherever such third-party acknowledgments normally appear. 4. The names "Indiana Univeristy" and "Indiana Univeristy Extreme! Lab" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact http://www.extreme.indiana.edu/. 5. Products derived from this software may not use "Indiana Univeristy" name nor may "Indiana Univeristy" appear in their name, without prior written permission of the Indiana University. THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS, COPYRIGHT HOLDERS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. plexus-utils-plexus-utils-3.0.22/src/main/resources/licenses/javolution.license.TXT000066400000000000000000000026001251077732300305030ustar00rootroot00000000000000Javolution - Java(TM) Solution for Real-Time and Embedded Systems Copyright (c) 2006, Javolution (http://javolution.org) All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. plexus-utils-plexus-utils-3.0.22/src/main/resources/licenses/thoughtworks.TXT000066400000000000000000000035721251077732300274510ustar00rootroot00000000000000 /******************************************************************************** * CruiseControl, a Continuous Integration Toolkit * Copyright (c) 2001-2003, ThoughtWorks, Inc. * 651 W Washington Ave. Suite 500 * Chicago, IL 60661 USA * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * + Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * + Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the * names of its contributors may be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ********************************************************************************/plexus-utils-plexus-utils-3.0.22/src/site/000077500000000000000000000000001251077732300204725ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/site/site.xml000066400000000000000000000011261251077732300221600ustar00rootroot00000000000000

            plexus-utils-plexus-utils-3.0.22/src/test/000077500000000000000000000000001251077732300205055ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/java/000077500000000000000000000000001251077732300214265ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/java/org/000077500000000000000000000000001251077732300222155ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/000077500000000000000000000000001251077732300240105ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/000077500000000000000000000000001251077732300253305ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/000077500000000000000000000000001251077732300263055ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/AbstractTestThread.java000066400000000000000000000135761251077732300327170ustar00rootroot00000000000000package 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. */ /** * A thread which is registered with a ThreadRegistry and notifies it when it has completed * running. Collects any errors and makes it available for analysis. * *

            Created on 1/07/2003

            * * @author Bert van Brakel * @version $Revision$ */ public abstract class AbstractTestThread implements Runnable { //~ Instance fields ---------------------------------------------------------------------------- private String name; public static final boolean DEBUG = true; private boolean isRunning = false; /** Error msg provided by implementing class (of why the test failed) */ private String errorMsg = null; /** The registry to notify on completion */ private TestThreadManager registry; /** The error thrown when running the test. Not neccesarily a test failuer as some tests * may test for an exception */ private Throwable error; /** If the thread has been run */ private boolean hasRun = false; /** Flag indicating if the test has passed. Some test might require an * exception so using the error to determine if the test has passed is * not sufficient. */ private boolean passed = false; //~ Constructors ------------------------------------------------------------------------------- /** * Constructor * *

            Remember to call setThreadRegistry(ThreadRegistry) */ public AbstractTestThread() { super(); } public AbstractTestThread( TestThreadManager registry ) { super(); setThreadRegistry( registry ); } //~ Methods ------------------------------------------------------------------------------------ /** * @return */ public Throwable getError() { return error; } /** * Resets the test back to it's state before starting. If the test * is currently running this method will block until the test has * finished running. Subclasses should call this method if * overriding it. * * */ public void reset() { //shouldn't reset until the test has finished running synchronized ( this ) { while ( isRunning ) { try { wait(); } catch ( InterruptedException e ) { } } errorMsg = null; error = null; hasRun = false; passed = false; } } /** * Start this TestThread running. If the test is currently running then * this method does nothing. * */ public final void start() { //shouldn't have multiple threads running this test at the same time synchronized ( this ) { if ( isRunning == false ) { isRunning = true; Thread t = new Thread( this ); t.start(); } } } /** * @return */ public String getErrorMsg() { return errorMsg; } /** * @return */ public boolean hasFailed() { return !passed; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public boolean hasPassed() { return passed; } /** * Don't override this. Calls doRun() * * @see java.lang.Runnable#run() */ public final void run() { if ( registry == null ) { throw new IllegalArgumentException( "The ThreadRegistry is null. Ensure this is set before running this thread" ); } passed = false; try { doRun(); } catch ( Throwable t ) { error = t; } registry.completed( this ); hasRun = true; isRunning = false; //notify objects with blocked methods which are waiting //on this test to complete running synchronized ( this ) { notifyAll(); } } /** * Override this to run your custom test * * @throws Throwable */ public abstract void doRun() throws Throwable; /** * Set the registry this thread should notify when it has completed running * * @param registry */ public void setThreadRegistry( TestThreadManager registry ) { this.registry = registry; } /** * Test if the test has run * * @return */ public boolean hasRun() { return hasRun; } /** * @param throwable */ public void setError( Throwable throwable ) { error = throwable; } /** * @param string */ public void setErrorMsg( String string ) { errorMsg = string; } /** * @param b */ public void setPassed( boolean b ) { passed = b; } /** * @return */ public String getName() { return name; } /** * @param string */ public void setName( String string ) { name = string; } private final void debug( String msg ) { if ( DEBUG ) { System.out.println( this + ":" + msg ); } } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/CollectionUtilsTest.java000066400000000000000000000173221251077732300331310ustar00rootroot00000000000000package 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.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import junit.framework.TestCase; public class CollectionUtilsTest extends TestCase { public void testMergeMaps() { Map dominantMap = new HashMap(); dominantMap.put( "a", "a" ); dominantMap.put( "b", "b" ); dominantMap.put( "c", "c" ); dominantMap.put( "d", "d" ); dominantMap.put( "e", "e" ); dominantMap.put( "f", "f" ); Map recessiveMap = new HashMap(); recessiveMap.put( "a", "invalid" ); recessiveMap.put( "b", "invalid" ); recessiveMap.put( "c", "invalid" ); recessiveMap.put( "x", "x" ); recessiveMap.put( "y", "y" ); recessiveMap.put( "z", "z" ); Map result = CollectionUtils.mergeMaps( dominantMap, recessiveMap ); // We should have 9 elements assertEquals( 9, result.keySet().size() ); // Check the elements. assertEquals( "a", result.get( "a" ) ); assertEquals( "b", result.get( "b" ) ); assertEquals( "c", result.get( "c" ) ); assertEquals( "d", result.get( "d" ) ); assertEquals( "e", result.get( "e" ) ); assertEquals( "f", result.get( "f" ) ); assertEquals( "x", result.get( "x" ) ); assertEquals( "y", result.get( "y" ) ); assertEquals( "z", result.get( "z" ) ); } @SuppressWarnings( "unchecked" ) public void testMergeMapArray() { // Test empty array of Maps Map result0 = CollectionUtils.mergeMaps( new Map[] { } ); assertNull( result0 ); // Test with an array with a single element. Map map1 = new HashMap (); map1.put( "a", "a" ); Map result1 = CollectionUtils.mergeMaps( new Map[] { map1 } ); assertEquals( "a", result1.get( "a" ) ); // Test with an array with two elements. Map map2 = new HashMap (); map2.put( "a", "aa" ); map2.put( "b", "bb" ); Map result2 = CollectionUtils.mergeMaps( new Map[] { map1, map2 } ); assertEquals( "a", result2.get( "a" ) ); assertEquals( "bb", result2.get( "b" ) ); // Now swap the dominant order. Map result3 = CollectionUtils.mergeMaps( new Map[] { map2, map1 } ); assertEquals( "aa", result3.get( "a" ) ); assertEquals( "bb", result3.get( "b" ) ); // Test with an array with three elements. Map map3 = new HashMap (); map3.put( "a", "aaa" ); map3.put( "b", "bbb" ); map3.put( "c", "ccc" ); Map result4 = CollectionUtils.mergeMaps( new Map[] { map1, map2, map3 } ); assertEquals( "a", result4.get( "a" ) ); assertEquals( "bb", result4.get( "b" ) ); assertEquals( "ccc", result4.get( "c" ) ); // Now swap the dominant order. Map result5 = CollectionUtils.mergeMaps( new Map[] { map3, map2, map1 } ); assertEquals( "aaa", result5.get( "a" ) ); assertEquals( "bbb", result5.get( "b" ) ); assertEquals( "ccc", result5.get( "c" ) ); } public void testMavenPropertiesLoading() { // Mimic MavenSession properties loading. Properties listed // in dominant order. Properties systemProperties = new Properties(); Properties userBuildProperties = new Properties(); Properties projectBuildProperties = new Properties(); Properties projectProperties = new Properties(); Properties driverProperties = new Properties(); // System properties systemProperties.setProperty( "maven.home", "/projects/maven" ); // User build properties userBuildProperties.setProperty( "maven.username", "jvanzyl" ); userBuildProperties.setProperty( "maven.repo.remote.enabled", "false" ); userBuildProperties.setProperty( "maven.repo.local", "/opt/maven/artifact" ); // Project build properties projectBuildProperties.setProperty( "maven.final.name", "maven" ); String mavenRepoRemote = "http://www.ibiblio.org/maven,http://foo/bar"; // Project properties projectProperties.setProperty( "maven.repo.remote", mavenRepoRemote ); String basedir = "/home/jvanzyl/projects/maven"; // Driver properties driverProperties.setProperty( "basedir", basedir ); driverProperties.setProperty( "maven.build.src", "${basedir}/src" ); driverProperties.setProperty( "maven.build.dir", "${basedir}/target" ); driverProperties.setProperty( "maven.build.dest", "${maven.build.dir}/classes" ); driverProperties.setProperty( "maven.repo.remote", "http://www.ibiblio.org/maven" ); driverProperties.setProperty( "maven.final.name", "maven-1.0" ); driverProperties.setProperty( "maven.repo.remote.enabled", "true" ); driverProperties.setProperty( "maven.repo.local", "${maven.home}/artifact" ); Map result = CollectionUtils.mergeMaps( new Map[] { systemProperties, userBuildProperties, projectBuildProperties, projectProperties, driverProperties } ); // Values that should be taken from systemProperties. assertEquals( "/projects/maven", (String) result.get( "maven.home" ) ); // Values that should be taken from userBuildProperties. assertEquals( "/opt/maven/artifact", (String) result.get( "maven.repo.local" ) ); assertEquals( "false", (String) result.get( "maven.repo.remote.enabled" ) ); assertEquals( "jvanzyl", (String) result.get( "maven.username" ) ); // Values take from projectBuildProperties. assertEquals( "maven", (String) result.get( "maven.final.name" ) ); // Values take from projectProperties. assertEquals( mavenRepoRemote, (String) result.get( "maven.repo.remote" ) ); } public void testIteratorToListWithAPopulatedList() { List original = new ArrayList(); original.add( "en" ); original.add( "to" ); original.add( "tre" ); List copy = CollectionUtils.iteratorToList( original.iterator() ); assertNotNull( copy ); assertEquals( 3, copy.size() ); assertEquals( "en", copy.get( 0 ) ); assertEquals( "to", copy.get( 1 ) ); assertEquals( "tre", copy.get( 2 ) ); } public void testIteratorToListWithAEmptyList() { List original = new ArrayList(); List copy = CollectionUtils.iteratorToList( original.iterator() ); assertNotNull( copy ); assertEquals( 0, copy.size() ); } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/DirectoryScannerTest.java000066400000000000000000000412031251077732300332660ustar00rootroot00000000000000package 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.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * Base class for testcases doing tests with files. * * @author Dan T. Tran */ public class DirectoryScannerTest extends FileBasedTestCase { private static String testDir = getTestDirectory().getPath(); public void testCrossPlatformIncludesString() throws IOException, URISyntaxException { DirectoryScanner ds = new DirectoryScanner(); ds.setBasedir( new File( getTestResourcesDir() + File.separator + "directory-scanner" ).getCanonicalFile() ); String fs; if ( File.separatorChar == '/' ) { fs = "\\"; } else { fs = "/"; } ds.setIncludes( new String[] { "foo" + fs } ); ds.addDefaultExcludes(); ds.scan(); String[] files = ds.getIncludedFiles(); assertEquals( 1, files.length ); } public void testCrossPlatformExcludesString() throws IOException, URISyntaxException { DirectoryScanner ds = new DirectoryScanner(); ds.setBasedir( new File( getTestResourcesDir() + File.separator + "directory-scanner" ).getCanonicalFile() ); ds.setIncludes( new String[] { "**" } ); String fs; if ( File.separatorChar == '/' ) { fs = "\\"; } else { fs = "/"; } ds.setExcludes( new String[] { "foo" + fs } ); ds.addDefaultExcludes(); ds.scan(); String[] files = ds.getIncludedFiles(); assertEquals( 0, files.length ); } private String getTestResourcesDir() throws URISyntaxException { ClassLoader cloader = Thread.currentThread().getContextClassLoader(); URL resource = cloader.getResource( "test.txt" ); if ( resource == null ) { fail( "Cannot locate test-resources directory containing 'test.txt' in the classloader." ); } File file = new File( new URI( resource.toExternalForm() ).normalize().getPath() ); return file.getParent(); } private void createTestFiles() throws IOException { FileUtils.mkdir( testDir ); this.createFile( new File( testDir + "/scanner1.dat" ), 0 ); this.createFile( new File( testDir + "/scanner2.dat" ), 0 ); this.createFile( new File( testDir + "/scanner3.dat" ), 0 ); this.createFile( new File( testDir + "/scanner4.dat" ), 0 ); this.createFile( new File( testDir + "/scanner5.dat" ), 0 ); } public void testGeneral() throws IOException { this.createTestFiles(); String includes = "scanner1.dat,scanner2.dat,scanner3.dat,scanner4.dat,scanner5.dat"; String excludes = "scanner1.dat,scanner2.dat"; List fileNames = FileUtils.getFiles( new File( testDir ), includes, excludes, false ); assertEquals( "Wrong number of results.", 3, fileNames.size() ); assertTrue( "3 not found.", fileNames.contains( new File( "scanner3.dat" ) ) ); assertTrue( "4 not found.", fileNames.contains( new File( "scanner4.dat" ) ) ); assertTrue( "5 not found.", fileNames.contains( new File( "scanner5.dat" ) ) ); } public void testIncludesExcludesWithWhiteSpaces() throws IOException { this.createTestFiles(); String includes = "scanner1.dat,\n \n,scanner2.dat \n\r, scanner3.dat\n, \tscanner4.dat,scanner5.dat\n,"; String excludes = "scanner1.dat,\n \n,scanner2.dat \n\r,,"; List fileNames = FileUtils.getFiles( new File( testDir ), includes, excludes, false ); assertEquals( "Wrong number of results.", 3, fileNames.size() ); assertTrue( "3 not found.", fileNames.contains( new File( "scanner3.dat" ) ) ); assertTrue( "4 not found.", fileNames.contains( new File( "scanner4.dat" ) ) ); assertTrue( "5 not found.", fileNames.contains( new File( "scanner5.dat" ) ) ); } public void testFollowSymlinksFalse() { DirectoryScanner ds = new DirectoryScanner(); ds.setBasedir( new File( "src/test/resources/symlinks/src/" ) ); ds.setFollowSymlinks( false ); ds.scan(); List included = Arrays.asList( ds.getIncludedFiles() ); assertAlwaysIncluded( included ); assertEquals( 9, included.size() ); List includedDirs = Arrays.asList( ds.getIncludedDirectories() ); assertTrue( includedDirs.contains( "" ) ); // w00t ! assertTrue( includedDirs.contains( "aRegularDir" ) ); assertTrue( includedDirs.contains( "symDir" ) ); assertTrue( includedDirs.contains( "symLinkToDirOnTheOutside" ) ); assertTrue( includedDirs.contains( "targetDir" ) ); assertEquals( 5, includedDirs.size() ); } private void assertAlwaysIncluded( List included ) { assertTrue( included.contains( "aRegularDir/aRegularFile.txt" ) ); assertTrue( included.contains( "targetDir/targetFile.txt" ) ); assertTrue( included.contains( "fileR.txt" ) ); assertTrue( included.contains( "fileW.txt" ) ); assertTrue( included.contains( "fileX.txt" ) ); assertTrue( included.contains( "symR" ) ); assertTrue( included.contains( "symW" ) ); assertTrue( included.contains( "symX" ) ); assertTrue( included.contains( "symLinkToFileOnTheOutside" ) ); } public void testFollowSymlinks() { DirectoryScanner ds = new DirectoryScanner(); ds.setBasedir( new File( "src/test/resources/symlinks/src/" ) ); ds.setFollowSymlinks( true ); ds.scan(); List included = Arrays.asList( ds.getIncludedFiles() ); assertAlwaysIncluded( included ); assertTrue( included.contains( "symDir/targetFile.txt" ) ); assertTrue( included.contains( "symLinkToDirOnTheOutside/FileInDirOnTheOutside.txt" ) ); assertEquals( 11, included.size() ); List includedDirs = Arrays.asList( ds.getIncludedDirectories() ); assertTrue( includedDirs.contains( "" ) ); // w00t ! assertTrue( includedDirs.contains( "aRegularDir" ) ); assertTrue( includedDirs.contains( "symDir" ) ); assertTrue( includedDirs.contains( "symLinkToDirOnTheOutside" ) ); assertTrue( includedDirs.contains( "targetDir" ) ); assertEquals( 5, includedDirs.size() ); } private void createTestDirectories() throws IOException { FileUtils.mkdir( testDir + File.separator + "directoryTest" ); FileUtils.mkdir( testDir + File.separator + "directoryTest" + File.separator + "testDir123" ); FileUtils.mkdir( testDir + File.separator + "directoryTest" + File.separator + "test_dir_123" ); FileUtils.mkdir( testDir + File.separator + "directoryTest" + File.separator + "test-dir-123" ); this.createFile( new File( testDir + File.separator + "directoryTest" + File.separator + "testDir123" + File.separator + "file1.dat" ), 0 ); this.createFile( new File( testDir + File.separator + "directoryTest" + File.separator + "test_dir_123" + File.separator + "file1.dat" ), 0 ); this.createFile( new File( testDir + File.separator + "directoryTest" + File.separator + "test-dir-123" + File.separator + "file1.dat" ), 0 ); } public void testDirectoriesWithHyphens() throws IOException { this.createTestDirectories(); DirectoryScanner ds = new DirectoryScanner(); String[] includes = { "**/*.dat" }; String[] excludes = { "" }; ds.setIncludes( includes ); ds.setExcludes( excludes ); ds.setBasedir( new File( testDir + File.separator + "directoryTest" ) ); ds.setCaseSensitive( true ); ds.scan(); String[] files = ds.getIncludedFiles(); assertEquals( "Wrong number of results.", 3, files.length ); } public void testAntExcludesOverrideIncludes() throws IOException { printTestHeader(); File dir = new File( testDir, "regex-dir" ); dir.mkdirs(); String[] excludedPaths = { "target/foo.txt" }; createFiles( dir, excludedPaths ); String[] includedPaths = { "src/main/resources/project/target/foo.txt" }; createFiles( dir, includedPaths ); DirectoryScanner ds = new DirectoryScanner(); String[] includes = { "**/target/*" }; String[] excludes = { "target/*" }; // This doesn't work, since excluded patterns refine included ones, meaning they operate on // the list of paths that passed the included patterns, and can override them. // String[] includes = {"**src/**/target/**/*" }; // String[] excludes = { "**/target/**/*" }; ds.setIncludes( includes ); ds.setExcludes( excludes ); ds.setBasedir( dir ); ds.scan(); assertInclusionsAndExclusions( ds.getIncludedFiles(), excludedPaths, includedPaths ); } public void testAntExcludesOverrideIncludesWithExplicitAntPrefix() throws IOException { printTestHeader(); File dir = new File( testDir, "regex-dir" ); dir.mkdirs(); String[] excludedPaths = { "target/foo.txt" }; createFiles( dir, excludedPaths ); String[] includedPaths = { "src/main/resources/project/target/foo.txt" }; createFiles( dir, includedPaths ); DirectoryScanner ds = new DirectoryScanner(); String[] includes = { SelectorUtils.ANT_HANDLER_PREFIX + "**/target/**/*" + SelectorUtils.PATTERN_HANDLER_SUFFIX }; String[] excludes = { SelectorUtils.ANT_HANDLER_PREFIX + "target/**/*" + SelectorUtils.PATTERN_HANDLER_SUFFIX }; // This doesn't work, since excluded patterns refine included ones, meaning they operate on // the list of paths that passed the included patterns, and can override them. // String[] includes = {"**src/**/target/**/*" }; // String[] excludes = { "**/target/**/*" }; ds.setIncludes( includes ); ds.setExcludes( excludes ); ds.setBasedir( dir ); ds.scan(); assertInclusionsAndExclusions( ds.getIncludedFiles(), excludedPaths, includedPaths ); } public void testRegexIncludeWithExcludedPrefixDirs() throws IOException { printTestHeader(); File dir = new File( testDir, "regex-dir" ); dir.mkdirs(); String[] excludedPaths = { "src/main/foo.txt" }; createFiles( dir, excludedPaths ); String[] includedPaths = { "src/main/resources/project/target/foo.txt" }; createFiles( dir, includedPaths ); String regex = ".+/target.*"; DirectoryScanner ds = new DirectoryScanner(); String includeExpr = SelectorUtils.REGEX_HANDLER_PREFIX + regex + SelectorUtils.PATTERN_HANDLER_SUFFIX; String[] includes = { includeExpr }; ds.setIncludes( includes ); ds.setBasedir( dir ); ds.scan(); assertInclusionsAndExclusions( ds.getIncludedFiles(), excludedPaths, includedPaths ); } public void testRegexExcludeWithNegativeLookahead() throws IOException { printTestHeader(); File dir = new File( testDir, "regex-dir" ); try { FileUtils.deleteDirectory( dir ); } catch ( IOException e ) { } dir.mkdirs(); String[] excludedPaths = { "target/foo.txt" }; createFiles( dir, excludedPaths ); String[] includedPaths = { "src/main/resources/project/target/foo.txt" }; createFiles( dir, includedPaths ); String regex = "(?!.*src/).*target.*"; DirectoryScanner ds = new DirectoryScanner(); String excludeExpr = SelectorUtils.REGEX_HANDLER_PREFIX + regex + SelectorUtils.PATTERN_HANDLER_SUFFIX; String[] excludes = { excludeExpr }; ds.setExcludes( excludes ); ds.setBasedir( dir ); ds.scan(); assertInclusionsAndExclusions( ds.getIncludedFiles(), excludedPaths, includedPaths ); } public void testRegexWithSlashInsideCharacterClass() throws IOException { printTestHeader(); File dir = new File( testDir, "regex-dir" ); try { FileUtils.deleteDirectory( dir ); } catch ( IOException e ) { } dir.mkdirs(); String[] excludedPaths = { "target/foo.txt", "target/src/main/target/foo.txt" }; createFiles( dir, excludedPaths ); String[] includedPaths = { "module/src/main/target/foo.txt" }; createFiles( dir, includedPaths ); // NOTE: The portion "[^/]" is the interesting part of this pattern. String regex = "(?!((?!target/)[^/]+/)*src/).*target.*"; DirectoryScanner ds = new DirectoryScanner(); String excludeExpr = SelectorUtils.REGEX_HANDLER_PREFIX + regex + SelectorUtils.PATTERN_HANDLER_SUFFIX; String[] excludes = { excludeExpr }; ds.setExcludes( excludes ); ds.setBasedir( dir ); ds.scan(); assertInclusionsAndExclusions( ds.getIncludedFiles(), excludedPaths, includedPaths ); } private void printTestHeader() { StackTraceElement ste = new Throwable().getStackTrace()[1]; System.out.println( "Test: " + ste.getMethodName() ); } private void assertInclusionsAndExclusions( String[] files, String[] excludedPaths, String... includedPaths ) { Arrays.sort( files ); System.out.println( "Included files: " ); for ( String file : files ) { System.out.println( file ); } List failedToExclude = new ArrayList(); for ( String excludedPath : excludedPaths ) { String alt = excludedPath.replace( '/', '\\' ); System.out.println( "Searching for exclusion as: " + excludedPath + "\nor: " + alt ); if ( Arrays.binarySearch( files, excludedPath ) > -1 || Arrays.binarySearch( files, alt ) > -1 ) { failedToExclude.add( excludedPath ); } } List failedToInclude = new ArrayList(); for ( String includedPath : includedPaths ) { String alt = includedPath.replace( '/', '\\' ); System.out.println( "Searching for inclusion as: " + includedPath + "\nor: " + alt ); if ( Arrays.binarySearch( files, includedPath ) < 0 && Arrays.binarySearch( files, alt ) < 0 ) { failedToInclude.add( includedPath ); } } StringBuilder buffer = new StringBuilder(); if ( !failedToExclude.isEmpty() ) { buffer.append( "Should NOT have included:\n" ).append( StringUtils.join( failedToExclude.iterator(), "\n\t- " ) ); } if ( !failedToInclude.isEmpty() ) { if ( buffer.length() > 0 ) { buffer.append( "\n\n" ); } buffer.append( "Should have included:\n" ) .append( StringUtils.join( failedToInclude.iterator(), "\n\t- " ) ); } if ( buffer.length() > 0 ) { fail( buffer.toString() ); } } private void createFiles( File dir, String... paths ) throws IOException { for ( String path1 : paths ) { String path = path1.replace( '/', File.separatorChar ).replace( '\\', File.separatorChar ); File file = new File( dir, path ); if ( path.endsWith( File.separator ) ) { file.mkdirs(); } else { if ( file.getParentFile() != null ) { file.getParentFile().mkdirs(); } createFile( file, 0 ); } } } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/DirectoryWalkerTest.java000066400000000000000000000031251251077732300331230ustar00rootroot00000000000000package 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 junit.framework.TestCase; public class DirectoryWalkerTest extends TestCase { public void testDirectoryWalk() { DirectoryWalker walker = new DirectoryWalker(); walker.addSCMExcludes(); walker.setBaseDir( new File("src/test/resources/directorywalker") ); WalkCollector collector = new WalkCollector(); walker.addDirectoryWalkListener( collector ); walker.scan(); assertEquals( "Walk Collector / Starting Count", 1, collector.startCount ); assertNotNull( "Walk Collector / Starting Dir", collector.startingDir ); assertEquals( "Walk Collector / Finish Count", 1, collector.finishCount ); assertEquals( "Walk Collector / Steps Count", 4, collector.steps.size() ); assertTrue( "Walk Collector / percentage low >= 0", collector.percentageLow >= 0 ); assertTrue( "Walk Collector / percentage high <= 100", collector.percentageHigh <= 100 ); } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/FileBasedTestCase.java000066400000000000000000000174521251077732300324330ustar00rootroot00000000000000package 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.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.io.PrintWriter; import java.io.Writer; import java.util.Arrays; import junit.framework.AssertionFailedError; import junit.framework.TestCase; /** * Base class for testcases doing tests with files. * * @author Jeremias Maerki */ public abstract class FileBasedTestCase extends TestCase { private static File testDir; public static File getTestDirectory() { if ( testDir == null ) { testDir = ( new File( "target/test/io/" ) ).getAbsoluteFile(); } return testDir; } protected byte[] createFile( final File file, final long size ) throws IOException { if ( !file.getParentFile().exists() ) { throw new IOException( "Cannot create file " + file + " as the parent directory does not exist" ); } byte[] data = generateTestData( size ); final BufferedOutputStream output = new BufferedOutputStream( new FileOutputStream( file ) ); try { output.write( data ); return data; } finally { output.close(); } } protected boolean createSymlink( final File link, final File target ) { try { String[] args = { "ln", "-s", target.getAbsolutePath(), link.getAbsolutePath() }; Process process = Runtime.getRuntime().exec( args ); process.waitFor(); if ( 0 != process.exitValue() ) { return false; } } catch ( Exception e ) { // assume platform does not support "ln" command, tests should be skipped return false; } return true; } protected byte[] generateTestData( final long size ) { try { ByteArrayOutputStream baout = new ByteArrayOutputStream(); generateTestData( baout, size ); return baout.toByteArray(); } catch ( IOException ioe ) { throw new RuntimeException( "This should never happen: " + ioe.getMessage() ); } } protected void generateTestData( final OutputStream out, final long size ) throws IOException { for ( int i = 0; i < size; i++ ) { //output.write((byte)'X'); // nice varied byte pattern compatible with Readers and Writers out.write( (byte) ( ( i % 127 ) + 1 ) ); } } protected File newFile( String filename ) throws IOException { final File destination = new File( getTestDirectory(), filename ); /* assertTrue( filename + "Test output data file shouldn't previously exist", !destination.exists() ); */ if ( destination.exists() ) { FileUtils.forceDelete( destination ); } return destination; } protected void checkFile( final File file, final File referenceFile ) throws Exception { assertTrue( "Check existence of output file", file.exists() ); assertEqualContent( referenceFile, file ); } protected void checkWrite( final OutputStream output ) throws Exception { try { new PrintStream( output ).write( 0 ); } catch ( final Throwable t ) { throw new AssertionFailedError( "The copy() method closed the stream " + "when it shouldn't have. " + t.getMessage() ); } } protected void checkWrite( final Writer output ) throws Exception { try { new PrintWriter( output ).write( 'a' ); } catch ( final Throwable t ) { throw new AssertionFailedError( "The copy() method closed the stream " + "when it shouldn't have. " + t.getMessage() ); } } protected void deleteFile( final File file ) throws Exception { if ( file.exists() ) { assertTrue( "Couldn't delete file: " + file, file.delete() ); } } // ---------------------------------------------------------------------- // Assertions // ---------------------------------------------------------------------- /** Assert that the content of two files is the same. */ private void assertEqualContent( final File f0, final File f1 ) throws IOException { /* This doesn't work because the filesize isn't updated until the file * is closed. assertTrue( "The files " + f0 + " and " + f1 + " have differing file sizes (" + f0.length() + " vs " + f1.length() + ")", ( f0.length() == f1.length() ) ); */ final InputStream is0 = new FileInputStream( f0 ); try { final InputStream is1 = new FileInputStream( f1 ); try { final byte[] buf0 = new byte[1024]; final byte[] buf1 = new byte[1024]; int n0 = 0; int n1 = 0; while ( -1 != n0 ) { n0 = is0.read( buf0 ); n1 = is1.read( buf1 ); assertTrue( "The files " + f0 + " and " + f1 + " have differing number of bytes available (" + n0 + " vs " + n1 + ")", ( n0 == n1 ) ); assertTrue( "The files " + f0 + " and " + f1 + " have different content", Arrays.equals( buf0, buf1 ) ); } } finally { is1.close(); } } finally { is0.close(); } } /** Assert that the content of a file is equal to that in a byte[]. */ protected void assertEqualContent( final byte[] b0, final File file ) throws IOException { final InputStream is = new FileInputStream( file ); try { byte[] b1 = new byte[b0.length]; int numRead = is.read( b1 ); assertTrue( "Different number of bytes", numRead == b0.length && is.available() == 0 ); for ( int i = 0; i < numRead; assertTrue( "Byte " + i + " differs (" + b0[i] + " != " + b1[i] + ")", b0[i] == b1[i] ), i++ ) ; } finally { is.close(); } } protected void assertIsDirectory( File file ) { assertTrue( "The File doesn't exists: " + file.getAbsolutePath(), file.exists() ); assertTrue( "The File isn't a directory: " + file.getAbsolutePath(), file.isDirectory() ); } protected void assertIsFile( File file ) { assertTrue( "The File doesn't exists: " + file.getAbsolutePath(), file.exists() ); assertTrue( "The File isn't a file: " + file.getAbsolutePath(), file.isFile() ); } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/FileUtilsTest.java000066400000000000000000001312731251077732300317170ustar00rootroot00000000000000package 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.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; import java.net.URL; import java.util.Properties; /** * This is used to test FileUtils for correctness. * * @author Peter Donald * @author Matthew Hawthorne * @version $Id$ * @see FileUtils */ public final class FileUtilsTest extends FileBasedTestCase { // Test data /** * Size of test directory. */ private static final int TEST_DIRECTORY_SIZE = 0; private final File testFile1; private final File testFile2; private static int testFile1Size; private static int testFile2Size; public FileUtilsTest() throws Exception { testFile1 = new File( getTestDirectory(), "file1-test.txt" ); testFile2 = new File( getTestDirectory(), "file1a-test.txt" ); testFile1Size = (int) testFile1.length(); testFile2Size = (int) testFile2.length(); } /** * @see junit.framework.TestCase#setUp() */ protected void setUp() throws Exception { getTestDirectory().mkdirs(); createFile( testFile1, testFile1Size ); createFile( testFile2, testFile2Size ); FileUtils.deleteDirectory( getTestDirectory() ); getTestDirectory().mkdirs(); createFile( testFile1, testFile1Size ); createFile( testFile2, testFile2Size ); } // byteCountToDisplaySize public void testByteCountToDisplaySize() { assertEquals( FileUtils.byteCountToDisplaySize( 0 ), "0 bytes" ); assertEquals( FileUtils.byteCountToDisplaySize( 1024 ), "1 KB" ); assertEquals( FileUtils.byteCountToDisplaySize( 1024 * 1024 ), "1 MB" ); assertEquals( FileUtils.byteCountToDisplaySize( 1024 * 1024 * 1024 ), "1 GB" ); } // waitFor public void testWaitFor() { FileUtils.waitFor( "", -1 ); FileUtils.waitFor( "", 2 ); } public void testToFile() throws Exception { URL url = getClass().getResource( "/test.txt" ); url = new URL( url.toString() + "/name%20%23%2520%3F%7B%7D%5B%5D%3C%3E.txt" ); File file = FileUtils.toFile( url ); assertEquals( "name #%20?{}[]<>.txt", file.getName() ); } public void testToFileBadProtocol() throws Exception { URL url = new URL( "http://maven.apache.org/" ); File file = FileUtils.toFile( url ); assertNull( file ); } public void testToFileNull() throws Exception { File file = FileUtils.toFile( null ); assertNull( file ); } // Hacked to sanity by Trygve public void testToURLs() throws Exception { File[] files = new File[]{ new File( "file1" ), new File( "file2" ), }; URL[] urls = FileUtils.toURLs( files ); assertEquals( "The length of the generated URL's is not equals to the length of files. " + "Was " + files.length + ", expected " + urls.length, files.length, urls.length ); for ( int i = 0; i < urls.length; i++ ) { assertEquals( files[i].toURL(), urls[i] ); } } public void testGetFilesFromExtension() { // TODO I'm not sure what is supposed to happen here FileUtils.getFilesFromExtension( "dir", null ); // Non-existent files final String[] emptyFileNames = FileUtils.getFilesFromExtension( getTestDirectory().getAbsolutePath(), new String[]{ "java" } ); assertTrue( emptyFileNames.length == 0 ); // Existing files // TODO Figure out how to test this /* final String[] fileNames = FileUtils.getFilesFromExtension( getClass().getResource("/java/util/").getFile(), new String[] { "class" }); assertTrue(fileNames.length > 0); */ } // mkdir public void testMkdir() { final File dir = new File( getTestDirectory(), "testdir" ); FileUtils.mkdir( dir.getAbsolutePath() ); dir.deleteOnExit(); if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) { try { File winFile = new File( getTestDirectory(), "bla*bla" ); winFile.deleteOnExit(); FileUtils.mkdir( winFile.getAbsolutePath() ); assertTrue( false ); } catch ( IllegalArgumentException e ) { assertTrue( true ); } } } // contentEquals public void testContentEquals() throws Exception { // Non-existent files final File file = new File( getTestDirectory(), getName() ); assertTrue( FileUtils.contentEquals( file, file ) ); // TODO Should comparing 2 directories throw an Exception instead of returning false? // Directories assertTrue( !FileUtils.contentEquals( getTestDirectory(), getTestDirectory() ) ); // Different files final File objFile1 = new File( getTestDirectory(), getName() + ".object" ); objFile1.deleteOnExit(); FileUtils.copyURLToFile( getClass().getResource( "/java/lang/Object.class" ), objFile1 ); final File objFile2 = new File( getTestDirectory(), getName() + ".collection" ); objFile2.deleteOnExit(); FileUtils.copyURLToFile( getClass().getResource( "/java/util/Collection.class" ), objFile2 ); assertTrue( "Files should not be equal.", !FileUtils.contentEquals( objFile1, objFile2 ) ); // Equal files file.createNewFile(); assertTrue( FileUtils.contentEquals( file, file ) ); } // removePath public void testRemovePath() { final String fileName = FileUtils.removePath( new File( getTestDirectory(), getName() ).getAbsolutePath() ); assertEquals( getName(), fileName ); } // getPath public void testGetPath() { final String fileName = FileUtils.getPath( new File( getTestDirectory(), getName() ).getAbsolutePath() ); assertEquals( getTestDirectory().getAbsolutePath(), fileName ); } // copyURLToFile public void testCopyURLToFile() throws Exception { // Creates file final File file = new File( getTestDirectory(), getName() ); file.deleteOnExit(); // Loads resource final String resourceName = "/java/lang/Object.class"; FileUtils.copyURLToFile( getClass().getResource( resourceName ), file ); // Tests that resource was copied correctly final FileInputStream fis = new FileInputStream( file ); try { assertTrue( "Content is not equal.", IOUtil.contentEquals( getClass().getResourceAsStream( resourceName ), fis ) ); } finally { fis.close(); } } // catPath public void testCatPath() { // TODO StringIndexOutOfBoundsException thrown if file doesn't contain slash. // Is this acceptable? //assertEquals("", FileUtils.catPath("a", "b")); assertEquals( "/a/c", FileUtils.catPath( "/a/b", "c" ) ); assertEquals( "/a/d", FileUtils.catPath( "/a/b/c", "../d" ) ); } // forceMkdir public void testForceMkdir() throws Exception { // Tests with existing directory FileUtils.forceMkdir( getTestDirectory() ); // Creates test file final File testFile = new File( getTestDirectory(), getName() ); testFile.deleteOnExit(); testFile.createNewFile(); assertTrue( "Test file does not exist.", testFile.exists() ); // Tests with existing file try { FileUtils.forceMkdir( testFile ); fail( "Exception expected." ); } catch ( IOException ex ) { } testFile.delete(); // Tests with non-existent directory FileUtils.forceMkdir( testFile ); assertTrue( "Directory was not created.", testFile.exists() ); if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) { try { File winFile = new File( getTestDirectory(), "bla*bla" ); winFile.deleteOnExit(); FileUtils.forceMkdir( winFile ); assertTrue( false ); } catch ( IllegalArgumentException e ) { assertTrue( true ); } } } // sizeOfDirectory public void testSizeOfDirectory() throws Exception { final File file = new File( getTestDirectory(), getName() ); // Non-existent file try { FileUtils.sizeOfDirectory( file ); fail( "Exception expected." ); } catch ( IllegalArgumentException ex ) { } // Creates file file.createNewFile(); file.deleteOnExit(); // Existing file try { FileUtils.sizeOfDirectory( file ); fail( "Exception expected." ); } catch ( IllegalArgumentException ex ) { } // Existing directory file.delete(); file.mkdir(); assertEquals( "Unexpected directory size", TEST_DIRECTORY_SIZE, FileUtils.sizeOfDirectory( file ) ); } // isFileNewer // TODO Finish test public void XtestIsFileNewer() { } // copyFile public void testCopyFile1() throws Exception { final File destination = new File( getTestDirectory(), "copy1.txt" ); FileUtils.copyFile( testFile1, destination ); assertTrue( "Check Exist", destination.exists() ); assertTrue( "Check Full copy", destination.length() == testFile1Size ); } public void testCopyFile2() throws Exception { final File destination = new File( getTestDirectory(), "copy2.txt" ); FileUtils.copyFile( testFile1, destination ); assertTrue( "Check Exist", destination.exists() ); assertTrue( "Check Full copy", destination.length() == testFile2Size ); } /** * ensure we create directory tree for destination * * @throws Exception */ public void testCopyFile3() throws Exception { File destDirectory = new File( getTestDirectory(), "foo/bar/testcopy" ); if ( destDirectory.exists() ) { destDirectory.delete(); } final File destination = new File( destDirectory, "copy2.txt" ); FileUtils.copyFile( testFile1, destination ); assertTrue( "Check Exist", destination.exists() ); assertTrue( "Check Full copy", destination.length() == testFile2Size ); } // copyFileIfModified public void testCopyIfModifiedWhenSourceIsNewer() throws Exception { FileUtils.forceMkdir( new File( getTestDirectory() + "/temp" ) ); // Place destination File destination = new File( getTestDirectory() + "/temp/copy1.txt" ); FileUtils.copyFile( testFile1, destination ); // Make sure source is newer reallySleep( 1000 ); // Place source File source = new File( getTestDirectory(), "copy1.txt" ); FileUtils.copyFile( testFile1, source ); source.setLastModified( System.currentTimeMillis() ); // Copy will occur when source is newer assertTrue( "Failed copy. Target file should have been updated.", FileUtils.copyFileIfModified( source, destination ) ); } public void testCopyIfModifiedWhenSourceIsOlder() throws Exception { FileUtils.forceMkdir( new File( getTestDirectory() + "/temp" ) ); // Place source File source = new File( getTestDirectory() + "copy1.txt" ); FileUtils.copyFile( testFile1, source ); // Make sure desintation is newer reallySleep( 1000 ); // Place destination File desintation = new File( getTestDirectory(), "/temp/copy1.txt" ); FileUtils.copyFile( testFile1, desintation ); // Copy will occur when desintation is newer assertFalse( "Source file should not have been copied.", FileUtils.copyFileIfModified( source, desintation ) ); } // forceDelete public void testForceDeleteAFile1() throws Exception { final File destination = new File( getTestDirectory(), "copy1.txt" ); destination.createNewFile(); assertTrue( "Copy1.txt doesn't exist to delete", destination.exists() ); FileUtils.forceDelete( destination ); assertTrue( "Check No Exist", !destination.exists() ); } public void testForceDeleteAFile2() throws Exception { final File destination = new File( getTestDirectory(), "copy2.txt" ); destination.createNewFile(); assertTrue( "Copy2.txt doesn't exist to delete", destination.exists() ); FileUtils.forceDelete( destination ); assertTrue( "Check No Exist", !destination.exists() ); } // copyFileToDirectory public void testCopyFile1ToDir() throws Exception { final File directory = new File( getTestDirectory(), "subdir" ); if ( !directory.exists() ) { directory.mkdirs(); } final File destination = new File( directory, testFile1.getName() ); FileUtils.copyFileToDirectory( testFile1, directory ); assertTrue( "Check Exist", destination.exists() ); assertTrue( "Check Full copy", destination.length() == testFile1Size ); } public void testCopyFile2ToDir() throws Exception { final File directory = new File( getTestDirectory(), "subdir" ); if ( !directory.exists() ) { directory.mkdirs(); } final File destination = new File( directory, testFile1.getName() ); FileUtils.copyFileToDirectory( testFile1, directory ); assertTrue( "Check Exist", destination.exists() ); assertTrue( "Check Full copy", destination.length() == testFile2Size ); } // copyFileToDirectoryIfModified public void testCopyFile1ToDirIfModified() throws Exception { final File directory = new File( getTestDirectory(), "subdir" ); if ( directory.exists() ) { FileUtils.forceDelete( directory ); } directory.mkdirs(); final File destination = new File( directory, testFile1.getName() ); FileUtils.copyFileToDirectoryIfModified( testFile1, directory ); final File target = new File( getTestDirectory() + "/subdir", testFile1.getName() ); long timestamp = target.lastModified(); assertTrue( "Check Exist", destination.exists() ); assertTrue( "Check Full copy", destination.length() == testFile1Size ); FileUtils.copyFileToDirectoryIfModified( testFile1, directory ); assertTrue( "Timestamp was changed", timestamp == target.lastModified() ); } public void testCopyFile2ToDirIfModified() throws Exception { final File directory = new File( getTestDirectory(), "subdir" ); if ( directory.exists() ) { FileUtils.forceDelete( directory ); } directory.mkdirs(); final File destination = new File( directory, testFile2.getName() ); FileUtils.copyFileToDirectoryIfModified( testFile2, directory ); final File target = new File( getTestDirectory() + "/subdir", testFile2.getName() ); long timestamp = target.lastModified(); assertTrue( "Check Exist", destination.exists() ); assertTrue( "Check Full copy", destination.length() == testFile2Size ); FileUtils.copyFileToDirectoryIfModified( testFile2, directory ); assertTrue( "Timestamp was changed", timestamp == target.lastModified() ); } // forceDelete public void testForceDeleteDir() throws Exception { FileUtils.forceDelete( getTestDirectory().getParentFile() ); assertTrue( "Check No Exist", !getTestDirectory().getParentFile().exists() ); } // resolveFile public void testResolveFileDotDot() throws Exception { final File file = FileUtils.resolveFile( getTestDirectory(), ".." ); assertEquals( "Check .. operator", file, getTestDirectory().getParentFile() ); } public void testResolveFileDot() throws Exception { final File file = FileUtils.resolveFile( getTestDirectory(), "." ); assertEquals( "Check . operator", file, getTestDirectory() ); } // normalize public void testNormalize() throws Exception { final String[] src = { "", "/", "///", "/foo", "/foo//", "/./", "/foo/./", "/foo/./bar", "/foo/../bar", "/foo/../bar/../baz", "/foo/bar/../../baz", "/././", "/foo/./../bar", "/foo/.././bar/", "//foo//./bar", "/../", "/foo/../../" }; final String[] dest = { "", "/", "/", "/foo", "/foo/", "/", "/foo/", "/foo/bar", "/bar", "/baz", "/baz", "/", "/bar", "/bar/", "/foo/bar", null, null }; assertEquals( "Oops, test writer goofed", src.length, dest.length ); for ( int i = 0; i < src.length; i++ ) { assertEquals( "Check if '" + src[i] + "' normalized to '" + dest[i] + "'", dest[i], FileUtils.normalize( src[i] ) ); } } private String replaceAll( String text, String lookFor, String replaceWith ) { StringBuilder sb = new StringBuilder( text ); while ( true ) { int idx = sb.indexOf( lookFor ); if ( idx < 0 ) { break; } sb.replace( idx, idx + lookFor.length(), replaceWith ); } return sb.toString(); } /** * Test the FileUtils implementation. */ // Used to exist as IOTestCase class public void testFileUtils() throws Exception { // Loads file from classpath final String path = "/test.txt"; final URL url = this.getClass().getResource( path ); assertNotNull( path + " was not found.", url ); String filename = url.getFile(); //The following line applies a fix for spaces in a path filename = replaceAll( filename, "%20", " " ); final String filename2 = "test2.txt"; assertTrue( "test.txt extension == \"txt\"", FileUtils.getExtension( filename ).equals( "txt" ) ); assertTrue( "Test file does not exist: " + filename, FileUtils.fileExists( filename ) ); assertTrue( "Second test file does not exist", !FileUtils.fileExists( filename2 ) ); FileUtils.fileWrite( filename2, filename ); assertTrue( "Second file was written", FileUtils.fileExists( filename2 ) ); final String file2contents = FileUtils.fileRead( filename2 ); assertTrue( "Second file's contents correct", FileUtils.fileRead( filename2 ).equals( file2contents ) ); FileUtils.fileAppend( filename2, filename ); assertTrue( "Second file's contents correct", FileUtils.fileRead( filename2 ).equals( file2contents + file2contents ) ); FileUtils.fileDelete( filename2 ); assertTrue( "Second test file does not exist", !FileUtils.fileExists( filename2 ) ); final String contents = FileUtils.fileRead( filename ); assertTrue( "FileUtils.fileRead()", contents.equals( "This is a test" ) ); } public void testGetExtension() { final String[][] tests = { { "filename.ext", "ext" }, { "README", "" }, { "domain.dot.com", "com" }, { "image.jpeg", "jpeg" }, { "folder" + File.separator + "image.jpeg", "jpeg" }, { "folder" + File.separator + "README", "" } }; for ( String[] test : tests ) { assertEquals( test[1], FileUtils.getExtension( test[0] ) ); //assertEquals(tests[i][1], FileUtils.extension(tests[i][0])); } } public void testGetExtensionWithPaths() { // Since the utilities are based on the separator for the platform // running the test, ensure we are using the right separator final String sep = File.separator; final String[][] testsWithPaths = { { sep + "tmp" + sep + "foo" + sep + "filename.ext", "ext" }, { "C:" + sep + "temp" + sep + "foo" + sep + "filename.ext", "ext" }, { "" + sep + "tmp" + sep + "foo.bar" + sep + "filename.ext", "ext" }, { "C:" + sep + "temp" + sep + "foo.bar" + sep + "filename.ext", "ext" }, { "" + sep + "tmp" + sep + "foo.bar" + sep + "README", "" }, { "C:" + sep + "temp" + sep + "foo.bar" + sep + "README", "" }, { ".." + sep + "filename.ext", "ext" }, { "blabla", "" } }; for ( String[] testsWithPath : testsWithPaths ) { assertEquals( testsWithPath[1], FileUtils.getExtension( testsWithPath[0] ) ); //assertEquals(testsWithPaths[i][1], FileUtils.extension(testsWithPaths[i][0])); } } public void testRemoveExtension() { final String[][] tests = { { "filename.ext", "filename" }, { "first.second.third.ext", "first.second.third" }, { "README", "README" }, { "domain.dot.com", "domain.dot" }, { "image.jpeg", "image" } }; for ( String[] test : tests ) { assertEquals( test[1], FileUtils.removeExtension( test[0] ) ); //assertEquals(tests[i][1], FileUtils.basename(tests[i][0])); } } /* TODO: Reenable this test */ public void testRemoveExtensionWithPaths() { // Since the utilities are based on the separator for the platform // running the test, ensure we are using the right separator final String sep = File.separator; final String[][] testsWithPaths = { { sep + "tmp" + sep + "foo" + sep + "filename.ext", sep + "tmp" + sep + "foo" + sep + "filename" }, { "C:" + sep + "temp" + sep + "foo" + sep + "filename.ext", "C:" + sep + "temp" + sep + "foo" + sep + "filename" }, { sep + "tmp" + sep + "foo.bar" + sep + "filename.ext", sep + "tmp" + sep + "foo.bar" + sep + "filename" }, { "C:" + sep + "temp" + sep + "foo.bar" + sep + "filename.ext", "C:" + sep + "temp" + sep + "foo.bar" + sep + "filename" }, { sep + "tmp" + sep + "foo.bar" + sep + "README", sep + "tmp" + sep + "foo.bar" + sep + "README" }, { "C:" + sep + "temp" + sep + "foo.bar" + sep + "README", "C:" + sep + "temp" + sep + "foo.bar" + sep + "README" }, { ".." + sep + "filename.ext", ".." + sep + "filename" } }; for ( String[] testsWithPath : testsWithPaths ) { assertEquals( testsWithPath[1], FileUtils.removeExtension( testsWithPath[0] ) ); //assertEquals(testsWithPaths[i][1], FileUtils.basename(testsWithPaths[i][0])); } } public void testCopyDirectoryStructureWithAEmptyDirectoryStruture() throws Exception { File from = new File( getTestDirectory(), "from" ); FileUtils.deleteDirectory( from ); assertTrue( from.mkdirs() ); File to = new File( getTestDirectory(), "to" ); assertTrue( to.mkdirs() ); FileUtils.copyDirectoryStructure( from, to ); } public void testCopyDirectoryStructureWithAPopulatedStructure() throws Exception { // Make a structure to copy File from = new File( getTestDirectory(), "from" ); FileUtils.deleteDirectory( from ); File fRoot = new File( from, "root.txt" ); File d1 = new File( from, "1" ); File d1_1 = new File( d1, "1_1" ); File d2 = new File( from, "2" ); File f2 = new File( d2, "2.txt" ); File d2_1 = new File( d2, "2_1" ); File f2_1 = new File( d2_1, "2_1.txt" ); assertTrue( from.mkdir() ); assertTrue( d1.mkdir() ); assertTrue( d1_1.mkdir() ); assertTrue( d2.mkdir() ); assertTrue( d2_1.mkdir() ); createFile( fRoot, 100 ); createFile( f2, 100 ); createFile( f2_1, 100 ); File to = new File( getTestDirectory(), "to" ); assertTrue( to.mkdirs() ); FileUtils.copyDirectoryStructure( from, to ); checkFile( fRoot, new File( to, "root.txt" ) ); assertIsDirectory( new File( to, "1" ) ); assertIsDirectory( new File( to, "1/1_1" ) ); assertIsDirectory( new File( to, "2" ) ); assertIsDirectory( new File( to, "2/2_1" ) ); checkFile( f2, new File( to, "2/2.txt" ) ); checkFile( f2_1, new File( to, "2/2_1/2_1.txt" ) ); } public void testCopyDirectoryStructureIfModified() throws Exception { // Make a structure to copy File from = new File( getTestDirectory(), "from" ); FileUtils.deleteDirectory( from ); File fRoot = new File( from, "root.txt" ); File d1 = new File( from, "1" ); File d1_1 = new File( d1, "1_1" ); File d2 = new File( from, "2" ); File f2 = new File( d2, "2.txt" ); File d2_1 = new File( d2, "2_1" ); File f2_1 = new File( d2_1, "2_1.txt" ); assertTrue( from.mkdir() ); assertTrue( d1.mkdir() ); assertTrue( d1_1.mkdir() ); assertTrue( d2.mkdir() ); assertTrue( d2_1.mkdir() ); createFile( fRoot, 100 ); createFile( f2, 100 ); createFile( f2_1, 100 ); File to = new File( getTestDirectory(), "to" ); assertTrue( to.mkdirs() ); FileUtils.copyDirectoryStructureIfModified( from, to ); File files[] = { new File( to, "root.txt" ), new File( to, "2/2.txt" ), new File( to, "2/2_1/2_1.txt" ) }; long timestamps[] = { files[0].lastModified(), files[1].lastModified(), files[2].lastModified() }; checkFile( fRoot, files[0] ); assertIsDirectory( new File( to, "1" ) ); assertIsDirectory( new File( to, "1/1_1" ) ); assertIsDirectory( new File( to, "2" ) ); assertIsDirectory( new File( to, "2/2_1" ) ); checkFile( f2, files[1] ); checkFile( f2_1, files[2] ); FileUtils.copyDirectoryStructureIfModified( from, to ); assertTrue( "Unmodified file was overwritten", timestamps[0] == files[0].lastModified() ); assertTrue( "Unmodified file was overwritten", timestamps[1] == files[1].lastModified() ); assertTrue( "Unmodified file was overwritten", timestamps[2] == files[2].lastModified() ); files[1].setLastModified( f2.lastModified() - 5000L ); timestamps[1] = files[1].lastModified(); FileUtils.copyDirectoryStructureIfModified( from, to ); assertTrue( "Unmodified file was overwritten", timestamps[0] == files[0].lastModified() ); assertTrue( "Outdated file was not overwritten", timestamps[1] < files[1].lastModified() ); assertTrue( "Unmodified file was overwritten", timestamps[2] == files[2].lastModified() ); } public void testCopyDirectoryStructureToSelf() throws Exception { // Make a structure to copy File toFrom = new File( getTestDirectory(), "tofrom" ); FileUtils.deleteDirectory( toFrom ); File fRoot = new File( toFrom, "root.txt" ); File dSub = new File( toFrom, "subdir" ); File f1 = new File( dSub, "notempty.txt" ); File dSubSub = new File( dSub, "subsubdir" ); File f2 = new File( dSubSub, "notemptytoo.txt" ); assertTrue( toFrom.mkdir() ); assertTrue( dSub.mkdir() ); assertTrue( dSubSub.mkdir() ); createFile( fRoot, 100 ); createFile( f1, 100 ); createFile( f2, 100 ); try { FileUtils.copyDirectoryStructure( toFrom, toFrom ); fail( "An exception must be thrown." ); } catch ( IOException e ) { // expected } } public void testFilteredFileCopy() throws Exception { File compareFile = new File( getTestDirectory(), "compare.txt" ); FileUtils.fileWrite( compareFile.getAbsolutePath(), "UTF-8", "This is a test. Test sample text\n" ); File destFile = new File( getTestDirectory(), "target.txt" ); final Properties filterProperties = new Properties(); filterProperties.setProperty( "s", "sample text" ); // test ${token} FileUtils.FilterWrapper[] wrappers1 = new FileUtils.FilterWrapper[]{ new FileUtils.FilterWrapper() { public Reader getReader( Reader reader ) { return new InterpolationFilterReader( reader, filterProperties, "${", "}" ); } } }; File srcFile = new File( getTestDirectory(), "root.txt" ); FileUtils.fileWrite( srcFile.getAbsolutePath(), "UTF-8", "This is a test. Test ${s}\n" ); FileUtils.copyFile( srcFile, destFile, "UTF-8", wrappers1 ); assertTrue( "Files should be equal.", FileUtils.contentEquals( compareFile, destFile ) ); srcFile.delete(); destFile.delete(); compareFile.delete(); } public void testFilteredWithoutFilterAndOlderFile() throws Exception { String content = "This is a test."; File sourceFile = new File( getTestDirectory(), "source.txt" ); FileUtils.fileWrite( sourceFile.getAbsolutePath(), "UTF-8", content ); File destFile = new File( getTestDirectory(), "target.txt" ); if ( destFile.exists() ) { destFile.delete(); } FileUtils.copyFile( sourceFile, destFile, null, null ); assertEqualContent( content.getBytes( "UTF-8" ), destFile ); String newercontent = "oldercontent"; File olderFile = new File( getTestDirectory(), "oldersource.txt" ); FileUtils.fileWrite( olderFile.getAbsolutePath(), "UTF-8", newercontent ); // very old file ;-) olderFile.setLastModified( 1 ); destFile = new File( getTestDirectory(), "target.txt" ); FileUtils.copyFile( olderFile, destFile, null, null ); String destFileContent = FileUtils.fileRead( destFile, "UTF-8" ); assertEquals( content, destFileContent ); } public void testFilteredWithoutFilterAndOlderFileAndOverwrite() throws Exception { String content = "This is a test."; File sourceFile = new File( getTestDirectory(), "source.txt" ); FileUtils.fileWrite( sourceFile.getAbsolutePath(), "UTF-8", content ); File destFile = new File( getTestDirectory(), "target.txt" ); if ( destFile.exists() ) { destFile.delete(); } FileUtils.copyFile( sourceFile, destFile, null, null ); assertEqualContent( content.getBytes( "UTF-8" ), destFile ); String newercontent = "oldercontent"; File olderFile = new File( getTestDirectory(), "oldersource.txt" ); FileUtils.fileWrite( olderFile.getAbsolutePath(), "UTF-8", newercontent ); // very old file ;-) olderFile.setLastModified( 1 ); destFile = new File( getTestDirectory(), "target.txt" ); FileUtils.copyFile( olderFile, destFile, null, null, true ); String destFileContent = FileUtils.fileRead( destFile, "UTF-8" ); assertEquals( newercontent, destFileContent ); } public void testFileRead() throws IOException { File testFile = new File( getTestDirectory(), "testFileRead.txt" ); String testFileName = testFile.getAbsolutePath(); /* * NOTE: The method under test uses the JVM's default encoding which by its nature varies from machine to * machine. As a consequence, we cannot know in advance which characters are supported by the effective encoding * of the test runner. Therefore this test must be restricted to ASCII characters which are reasonably safe to * survive the roundtrip test. */ String testString = "Only US-ASCII characters here, see comment above!"; Writer writer = null; try { writer = new OutputStreamWriter( new FileOutputStream( testFile ) ); writer.write( testString ); writer.flush(); } finally { IOUtil.close( writer ); } assertEquals( "testString should be equal", testString, FileUtils.fileRead( testFile ) ); assertEquals( "testString should be equal", testString, FileUtils.fileRead( testFileName ) ); testFile.delete(); } public void testFileReadWithEncoding() throws IOException { String encoding = "UTF-8"; File testFile = new File( getTestDirectory(), "testFileRead.txt" ); String testFileName = testFile.getAbsolutePath(); // unicode escaped Japanese hiragana, "aiueo" + Umlaut a String testString = "\u3042\u3044\u3046\u3048\u304a\u00e4"; Writer writer = null; try { writer = new OutputStreamWriter( new FileOutputStream( testFile ), encoding ); writer.write( testString ); writer.flush(); } finally { IOUtil.close( writer ); } assertEquals( "testString should be equal", testString, FileUtils.fileRead( testFile, "UTF-8" ) ); assertEquals( "testString should be equal", testString, FileUtils.fileRead( testFileName, "UTF-8" ) ); testFile.delete(); } public void testFileAppend() throws IOException { String baseString = "abc"; File testFile = new File( getTestDirectory(), "testFileAppend.txt" ); String testFileName = testFile.getAbsolutePath(); Writer writer = null; try { writer = new OutputStreamWriter( new FileOutputStream( testFile ) ); writer.write( baseString ); writer.flush(); } finally { IOUtil.close( writer ); } // unicode escaped Japanese hiragana, "aiueo" + Umlaut a String testString = "\u3042\u3044\u3046\u3048\u304a\u00e4"; FileUtils.fileAppend( testFileName, testString ); assertEqualContent( ( baseString + testString ).getBytes(), testFile ); testFile.delete(); } public void testFileAppendWithEncoding() throws IOException { String baseString = "abc"; String encoding = "UTF-8"; File testFile = new File( getTestDirectory(), "testFileAppend.txt" ); String testFileName = testFile.getAbsolutePath(); Writer writer = null; try { writer = new OutputStreamWriter( new FileOutputStream( testFile ), encoding ); writer.write( baseString ); writer.flush(); } finally { IOUtil.close( writer ); } // unicode escaped Japanese hiragana, "aiueo" + Umlaut a String testString = "\u3042\u3044\u3046\u3048\u304a\u00e4"; FileUtils.fileAppend( testFileName, encoding, testString ); assertEqualContent( ( baseString + testString ).getBytes( encoding ), testFile ); testFile.delete(); } public void testFileWrite() throws IOException { File testFile = new File( getTestDirectory(), "testFileWrite.txt" ); String testFileName = testFile.getAbsolutePath(); // unicode escaped Japanese hiragana, "aiueo" + Umlaut a String testString = "\u3042\u3044\u3046\u3048\u304a\u00e4"; FileUtils.fileWrite( testFileName, testString ); assertEqualContent( testString.getBytes(), testFile ); testFile.delete(); } public void testFileWriteWithEncoding() throws IOException { String encoding = "UTF-8"; File testFile = new File( getTestDirectory(), "testFileWrite.txt" ); String testFileName = testFile.getAbsolutePath(); // unicode escaped Japanese hiragana, "aiueo" + Umlaut a String testString = "\u3042\u3044\u3046\u3048\u304a\u00e4"; FileUtils.fileWrite( testFileName, encoding, testString ); assertEqualContent( testString.getBytes( encoding ), testFile ); testFile.delete(); } /** * Workaround for the following Sun bugs. They are fixed in JDK 6u1 and JDK 5u11. * * @throws Exception * @see Sun bug id=4403166 * @see Sun bug id=6182812 * @see Sun bug id=6481955 */ public void testDeleteLongPathOnWindows() throws Exception { if ( !Os.isFamily( Os.FAMILY_WINDOWS ) ) { return; } File a = new File( getTestDirectory(), "longpath" ); a.mkdir(); File a1 = new File( a, "a" ); a1.mkdir(); StringBuilder path = new StringBuilder( "" ); for ( int i = 0; i < 100; i++ ) { path.append( "../a/" ); } File f = new File( a1, path.toString() + "test.txt" ); InputStream is = new ByteArrayInputStream( "Blabla".getBytes( "UTF-8" ) ); OutputStream os = new FileOutputStream( f.getCanonicalFile() ); IOUtil.copy( is, os ); IOUtil.close( is ); IOUtil.close( os ); FileUtils.forceDelete( f ); File f1 = new File( a1, "test.txt" ); if ( f1.exists() ) { throw new Exception( "Unable to delete the file :" + f1.getAbsolutePath() ); } } //Test for bug PLXUTILS-10 public void testCopyFileOnSameFile() throws IOException { String content = "ggrgreeeeeeeeeeeeeeeeeeeeeeeoierjgioejrgiojregioejrgufcdxivbsdibgfizgerfyaezgv!zeez"; final File theFile = File.createTempFile( "test", ".txt" ); theFile.deleteOnExit(); FileUtils.fileAppend( theFile.getAbsolutePath(), content ); assertTrue( theFile.length() > 0 ); // Now copy file over itself FileUtils.copyFile( theFile, theFile ); // This should not fail assertTrue( theFile.length() > 0 ); } public void testExtensions() throws Exception { String[][] values = { { "fry.frozen", "frozen" }, { "fry", "" }, { "fry.", "" }, { "/turanga/leela/meets.fry", "fry" }, { "/3000/turanga.leela.fry/zoidberg.helps", "helps" }, { "/3000/turanga.leela.fry/zoidberg.", "" }, { "/3000/turanga.leela.fry/zoidberg", "" }, { "/3000/leela.fry.bender/", "" }, { "/3000/leela.fry.bdner/.", "" }, { "/3000/leela.fry.bdner/foo.bar.txt", "txt" } }; for ( int i = 0; i < values.length; i++ ) { String fileName = values[i][0].replace( '/', File.separatorChar ); String ext = values[i][1]; String computed = FileUtils.extension( fileName ); assertEquals( "case [" + i + "]:" + fileName + " -> " + ext + ", computed : " + computed, ext, computed ); } } public void testIsValidWindowsFileName() throws Exception { File f = new File( "c:\test" ); assertTrue( FileUtils.isValidWindowsFileName( f ) ); if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) { f = new File( "c:\test\bla:bla" ); assertFalse( FileUtils.isValidWindowsFileName( f ) ); f = new File( "c:\test\bla*bla" ); assertFalse( FileUtils.isValidWindowsFileName( f ) ); f = new File( "c:\test\bla\"bla" ); assertFalse( FileUtils.isValidWindowsFileName( f ) ); f = new File( "c:\test\blabla" ); assertFalse( FileUtils.isValidWindowsFileName( f ) ); f = new File( "c:\test\bla|bla" ); assertFalse( FileUtils.isValidWindowsFileName( f ) ); f = new File( "c:\test\bla*bla" ); assertFalse( FileUtils.isValidWindowsFileName( f ) ); } } public void testDeleteDirectoryWithValidFileSymlink() throws Exception { File symlinkTarget = new File( getTestDirectory(), "fileSymlinkTarget" ); createFile( symlinkTarget, 1 ); File symlink = new File( getTestDirectory(), "fileSymlink" ); createSymlink( symlink, symlinkTarget ); try { FileUtils.deleteDirectory( getTestDirectory() ); } finally { /* * Ensure to cleanup problematic symlink or "mvn clean" will fail */ symlink.delete(); } assertTrue( "Failed to delete test directory", !getTestDirectory().exists() ); } public void testDeleteDirectoryWithValidDirSymlink() throws Exception { File symlinkTarget = new File( getTestDirectory(), "dirSymlinkTarget" ); symlinkTarget.mkdir(); File symlink = new File( getTestDirectory(), "dirSymlink" ); createSymlink( symlink, symlinkTarget ); try { FileUtils.deleteDirectory( getTestDirectory() ); } finally { /* * Ensure to cleanup problematic symlink or "mvn clean" will fail */ symlink.delete(); } assertTrue( "Failed to delete test directory", !getTestDirectory().exists() ); } public void testDeleteDirectoryWithDanglingSymlink() throws Exception { File symlinkTarget = new File( getTestDirectory(), "missingSymlinkTarget" ); File symlink = new File( getTestDirectory(), "danglingSymlink" ); createSymlink( symlink, symlinkTarget ); try { FileUtils.deleteDirectory( getTestDirectory() ); } finally { /* * Ensure to cleanup problematic symlink or "mvn clean" will fail */ symlink.delete(); } assertTrue( "Failed to delete test directory", !getTestDirectory().exists() ); } public void testcopyDirectoryLayoutWithExcludesIncludes() throws Exception { File destination = new File( "target", "copyDirectoryStructureWithExcludesIncludes" ); if ( !destination.exists() ) { destination.mkdirs(); } FileUtils.cleanDirectory( destination ); File source = new File( "src/test/resources/dir-layout-copy" ); FileUtils.copyDirectoryLayout( source, destination, null, null ); assertTrue( destination.exists() ); File[] childs = destination.listFiles(); assertEquals( 2, childs.length ); for ( File current : childs ) { if ( current.getName().endsWith( "empty-dir" ) || current.getName().endsWith( "dir1" ) ) { if ( current.getName().endsWith( "dir1" ) ) { assertEquals( 1, current.listFiles().length ); assertTrue( current.listFiles()[0].getName().endsWith( "dir2" ) ); } } else { fail( "not empty-dir or dir1" ); } } } /** * Be sure that {@link FileUtils#createTempFile(String, String, File)} is always unique. * * @throws Exception if any */ public void testCreateTempFile() throws Exception { File last = FileUtils.createTempFile( "unique", ".tmp", null ); for ( int i = 0; i < 10; i++ ) { File current = FileUtils.createTempFile( "unique", ".tmp", null ); assertTrue( "No unique name: " + current.getName(), !current.getName().equals( last.getName() ) ); last = current; } } /** * Because windows(tm) quite frequently sleeps less than the advertised time * * @param time The amount of time to sleep * @throws InterruptedException */ private void reallySleep( int time ) throws InterruptedException { long until = System.currentTimeMillis() + time; Thread.sleep( time ); while ( System.currentTimeMillis() < until ) { Thread.sleep( time / 10 ); Thread.yield(); } } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/IOUtilTest.java000066400000000000000000000401661251077732300311640ustar00rootroot00000000000000package 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.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.io.PrintWriter; import java.io.Reader; import java.io.Writer; import java.util.Arrays; import junit.framework.AssertionFailedError; import junit.framework.TestCase; /** * This is used to test IOUtil for correctness. The following checks are performed: *

              *
            • The return must not be null, must be the same type and equals() to the method's second arg
            • *
            • All bytes must have been read from the source (available() == 0)
            • *
            • The source and destination content must be identical (byte-wise comparison check)
            • *
            • The output stream must not have been closed (a byte/char is written to test this, and * subsequent size checked)
            • *
            * Due to interdependencies in IOUtils and IOUtilsTestlet, one bug may cause * multiple tests to fail. * * @author Jeff Turner */ public final class IOUtilTest extends TestCase { /* * Note: this is not particularly beautiful code. A better way to check for * flush and close status would be to implement "trojan horse" wrapper * implementations of the various stream classes, which set a flag when * relevant methods are called. (JT) */ private int FILE_SIZE = 1024 * 4 + 1; private File testDirectory; private File testFile; public void setUp() { try { testDirectory = ( new File( "target/test/io/" ) ).getAbsoluteFile(); if ( !testDirectory.exists() ) { testDirectory.mkdirs(); } testFile = new File( testDirectory, "file2-test.txt" ); createFile( testFile, FILE_SIZE ); } catch ( IOException ioe ) { throw new RuntimeException( "Can't run this test because environment could not be built" ); } } public void tearDown() { testFile.delete(); testDirectory.delete(); } public IOUtilTest( String name ) { super( name ); } private void createFile( File file, long size ) throws IOException { BufferedOutputStream output = new BufferedOutputStream( new FileOutputStream( file ) ); for ( int i = 0; i < size; i++ ) { output.write( (byte) ( i % 128 ) ); // nice varied byte pattern compatible with Readers and Writers } output.close(); } /** Assert that the contents of two byte arrays are the same. */ private void assertEqualContent( byte[] b0, byte[] b1 ) { assertTrue( "Content not equal according to java.util.Arrays#equals()", Arrays.equals( b0, b1 ) ); } /** Assert that the content of two files is the same. */ private void assertEqualContent( File f0, File f1 ) throws IOException { FileInputStream is0 = new FileInputStream( f0 ); FileInputStream is1 = new FileInputStream( f1 ); byte[] buf0 = new byte[FILE_SIZE]; byte[] buf1 = new byte[FILE_SIZE]; int n0 = 0; int n1 = 0; try { while ( -1 != n0 ) { n0 = is0.read( buf0 ); n1 = is1.read( buf1 ); assertTrue( "The files " + f0 + " and " + f1 + " have differing number of bytes available (" + n0 + " vs " + n1 + ")", ( n0 == n1 ) ); assertTrue( "The files " + f0 + " and " + f1 + " have different content", Arrays.equals( buf0, buf1 ) ); } } finally { is0.close(); is1.close(); } } /** Assert that the content of a file is equal to that in a byte[]. */ private void assertEqualContent( byte[] b0, File file ) throws IOException { FileInputStream is = new FileInputStream( file ); byte[] b1 = new byte[b0.length]; int numRead = is.read( b1 ); assertTrue( "Different number of bytes", numRead == b0.length && is.available() == 0 ); for ( int i = 0; i < numRead; assertTrue( "Byte " + i + " differs (" + b0[i] + " != " + b1[i] + ")", b0[i] == b1[i] ), i++ ) ; is.close(); } public void testInputStreamToOutputStream() throws Exception { File destination = newFile( "copy1.txt" ); FileInputStream fin = new FileInputStream( testFile ); FileOutputStream fout = new FileOutputStream( destination ); IOUtil.copy( fin, fout ); assertTrue( "Not all bytes were read", fin.available() == 0 ); fout.flush(); checkFile( destination ); checkWrite( fout ); fout.close(); fin.close(); deleteFile( destination ); } public void testInputStreamToWriter() throws Exception { File destination = newFile( "copy2.txt" ); FileInputStream fin = new FileInputStream( testFile ); FileWriter fout = new FileWriter( destination ); IOUtil.copy( fin, fout ); assertTrue( "Not all bytes were read", fin.available() == 0 ); fout.flush(); checkFile( destination ); checkWrite( fout ); fout.close(); fin.close(); deleteFile( destination ); } public void testInputStreamToString() throws Exception { FileInputStream fin = new FileInputStream( testFile ); String out = IOUtil.toString( fin ); assertNotNull( out ); assertTrue( "Not all bytes were read", fin.available() == 0 ); assertTrue( "Wrong output size: out.length()=" + out.length() + "!=" + FILE_SIZE, out.length() == FILE_SIZE ); fin.close(); } public void testReaderToOutputStream() throws Exception { File destination = newFile( "copy3.txt" ); FileReader fin = new FileReader( testFile ); FileOutputStream fout = new FileOutputStream( destination ); IOUtil.copy( fin, fout ); //Note: this method *does* flush. It is equivalent to: // OutputStreamWriter _out = new OutputStreamWriter(fout); // IOUtil.copy( fin, _out, 4096 ); // copy( Reader, Writer, int ); // _out.flush(); // out = fout; // Note: rely on the method to flush checkFile( destination ); checkWrite( fout ); fout.close(); fin.close(); deleteFile( destination ); } public void testReaderToWriter() throws Exception { File destination = newFile( "copy4.txt" ); FileReader fin = new FileReader( testFile ); FileWriter fout = new FileWriter( destination ); IOUtil.copy( fin, fout ); fout.flush(); checkFile( destination ); checkWrite( fout ); fout.close(); fin.close(); deleteFile( destination ); } public void testReaderToString() throws Exception { FileReader fin = new FileReader( testFile ); String out = IOUtil.toString( fin ); assertNotNull( out ); assertTrue( "Wrong output size: out.length()=" + out.length() + "!=" + FILE_SIZE, out.length() == FILE_SIZE ); fin.close(); } public void testStringToOutputStream() throws Exception { File destination = newFile( "copy5.txt" ); FileReader fin = new FileReader( testFile ); // Create our String. Rely on testReaderToString() to make sure this is valid. String str = IOUtil.toString( fin ); FileOutputStream fout = new FileOutputStream( destination ); IOUtil.copy( str, fout ); //Note: this method *does* flush. It is equivalent to: // OutputStreamWriter _out = new OutputStreamWriter(fout); // IOUtil.copy( str, _out, 4096 ); // copy( Reader, Writer, int ); // _out.flush(); // out = fout; // note: we don't flush here; this IOUtils method does it for us checkFile( destination ); checkWrite( fout ); fout.close(); fin.close(); deleteFile( destination ); } public void testStringToWriter() throws Exception { File destination = newFile( "copy6.txt" ); FileReader fin = new FileReader( testFile ); // Create our String. Rely on testReaderToString() to make sure this is valid. String str = IOUtil.toString( fin ); FileWriter fout = new FileWriter( destination ); IOUtil.copy( str, fout ); fout.flush(); checkFile( destination ); checkWrite( fout ); fout.close(); fin.close(); deleteFile( destination ); } public void testInputStreamToByteArray() throws Exception { FileInputStream fin = new FileInputStream( testFile ); byte[] out = IOUtil.toByteArray( fin ); assertNotNull( out ); assertTrue( "Not all bytes were read", fin.available() == 0 ); assertTrue( "Wrong output size: out.length=" + out.length + "!=" + FILE_SIZE, out.length == FILE_SIZE ); assertEqualContent( out, testFile ); fin.close(); } public void testStringToByteArray() throws Exception { FileReader fin = new FileReader( testFile ); // Create our String. Rely on testReaderToString() to make sure this is valid. String str = IOUtil.toString( fin ); byte[] out = IOUtil.toByteArray( str ); assertEqualContent( str.getBytes(), out ); fin.close(); } public void testByteArrayToWriter() throws Exception { File destination = newFile( "copy7.txt" ); FileWriter fout = new FileWriter( destination ); FileInputStream fin = new FileInputStream( testFile ); // Create our byte[]. Rely on testInputStreamToByteArray() to make sure this is valid. byte[] in = IOUtil.toByteArray( fin ); IOUtil.copy( in, fout ); fout.flush(); checkFile( destination ); checkWrite( fout ); fout.close(); fin.close(); deleteFile( destination ); } public void testByteArrayToString() throws Exception { FileInputStream fin = new FileInputStream( testFile ); byte[] in = IOUtil.toByteArray( fin ); // Create our byte[]. Rely on testInputStreamToByteArray() to make sure this is valid. String str = IOUtil.toString( in ); assertEqualContent( in, str.getBytes() ); fin.close(); } public void testByteArrayToOutputStream() throws Exception { File destination = newFile( "copy8.txt" ); FileOutputStream fout = new FileOutputStream( destination ); FileInputStream fin = new FileInputStream( testFile ); // Create our byte[]. Rely on testInputStreamToByteArray() to make sure this is valid. byte[] in = IOUtil.toByteArray( fin ); IOUtil.copy( in, fout ); fout.flush(); checkFile( destination ); checkWrite( fout ); fout.close(); fin.close(); deleteFile( destination ); } // ---------------------------------------------------------------------- // Test closeXXX() // ---------------------------------------------------------------------- public void testCloseInputStream() throws Exception { IOUtil.close( (InputStream) null ); TestInputStream inputStream = new TestInputStream(); IOUtil.close( inputStream ); assertTrue( inputStream.closed ); } public void testCloseOutputStream() throws Exception { IOUtil.close( (OutputStream) null ); TestOutputStream outputStream = new TestOutputStream(); IOUtil.close( outputStream ); assertTrue( outputStream.closed ); } public void testCloseReader() throws Exception { IOUtil.close( (Reader) null ); TestReader reader = new TestReader(); IOUtil.close( reader ); assertTrue( reader.closed ); } public void testCloseWriter() throws Exception { IOUtil.close( (Writer) null ); TestWriter writer = new TestWriter(); IOUtil.close( writer ); assertTrue( writer.closed ); } private class TestInputStream extends InputStream { boolean closed; public void close() { closed = true; } public int read() { fail( "This method shouldn't be called" ); return 0; } } private class TestOutputStream extends OutputStream { boolean closed; public void close() { closed = true; } public void write( int value ) { fail( "This method shouldn't be called" ); } } private class TestReader extends Reader { boolean closed; public void close() { closed = true; } public int read( char cbuf[], int off, int len ) { fail( "This method shouldn't be called" ); return 0; } } private class TestWriter extends Writer { boolean closed; public void close() { closed = true; } public void write( char cbuf[], int off, int len ) { fail( "This method shouldn't be called" ); } public void flush() { fail( "This method shouldn't be called" ); } } // ---------------------------------------------------------------------- // Utility methods // ---------------------------------------------------------------------- private File newFile( String filename ) throws Exception { File destination = new File( testDirectory, filename ); assertTrue( filename + "Test output data file shouldn't previously exist", !destination.exists() ); return destination; } private void checkFile( File file ) throws Exception { assertTrue( "Check existence of output file", file.exists() ); assertEqualContent( testFile, file ); } private void checkWrite( OutputStream output ) throws Exception { try { new PrintStream( output ).write( 0 ); } catch ( Throwable t ) { throw new AssertionFailedError( "The copy() method closed the stream " + "when it shouldn't have. " + t.getMessage() ); } } private void checkWrite( Writer output ) throws Exception { try { new PrintWriter( output ).write( 'a' ); } catch ( Throwable t ) { throw new AssertionFailedError( "The copy() method closed the stream " + "when it shouldn't have. " + t.getMessage() ); } } private void deleteFile( File file ) throws Exception { assertTrue( "Wrong output size: file.length()=" + file.length() + "!=" + FILE_SIZE + 1, file.length() == FILE_SIZE + 1 ); assertTrue( "File would not delete", ( file.delete() || ( !file.exists() ) ) ); } } InterpolationFilterReaderTest.java000066400000000000000000000133161251077732300350550ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/utilpackage 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.StringReader; import java.util.HashMap; import java.util.Map; import junit.framework.TestCase; public class InterpolationFilterReaderTest extends TestCase { /* * Added and commented by jdcasey@03-Feb-2005 because it is a bug in the * InterpolationFilterReader. * kenneyw@15-04-2005 fixed the bug. */ public void testShouldNotInterpolateExpressionAtEndOfDataWithInvalidEndToken() throws Exception { Map m = new HashMap(); m.put( "test", "TestValue" ); String testStr = "This is a ${test"; assertEquals( "This is a ${test", interpolate( testStr, m ) ); } /* * kenneyw@14-04-2005 Added test to check above fix. */ public void testShouldNotInterpolateExpressionWithMissingEndToken() throws Exception { Map m = new HashMap(); m.put( "test", "TestValue" ); String testStr = "This is a ${test, really"; assertEquals( "This is a ${test, really", interpolate( testStr, m ) ); } public void testShouldNotInterpolateWithMalformedStartToken() throws Exception { Map m = new HashMap(); m.put( "test", "testValue" ); String foo = "This is a $!test} again"; assertEquals( "This is a $!test} again", interpolate( foo, m ) ); } public void testShouldNotInterpolateWithMalformedEndToken() throws Exception { Map m = new HashMap(); m.put( "test", "testValue" ); String foo = "This is a ${test!} again"; assertEquals( "This is a ${test!} again", interpolate( foo, m, "${", "$}" ) ); } public void testInterpolationWithMulticharDelimiters() throws Exception { Map m = new HashMap(); m.put( "test", "testValue" ); String foo = "This is a ${test$} again"; assertEquals( "This is a testValue again", interpolate( foo, m, "${", "$}" ) ); } public void testDefaultInterpolationWithNonInterpolatedValueAtEnd() throws Exception { Map m = new HashMap(); m.put( "name", "jason" ); m.put( "noun", "asshole" ); String foo = "${name} is an ${noun}. ${not.interpolated}"; assertEquals( "jason is an asshole. ${not.interpolated}", interpolate( foo, m ) ); } public void testDefaultInterpolationWithInterpolatedValueAtEnd() throws Exception { Map m = new HashMap(); m.put( "name", "jason" ); m.put( "noun", "asshole" ); String foo = "${name} is an ${noun}"; assertEquals( "jason is an asshole", interpolate( foo, m ) ); } public void testInterpolationWithSpecifiedBoundaryTokens() throws Exception { Map m = new HashMap(); m.put( "name", "jason" ); m.put( "noun", "asshole" ); String foo = "@name@ is an @noun@. @not.interpolated@ baby @foo@. @bar@"; assertEquals( "jason is an asshole. @not.interpolated@ baby @foo@. @bar@", interpolate( foo, m, "@", "@" ) ); } public void testInterpolationWithSpecifiedBoundaryTokensWithNonInterpolatedValueAtEnd() throws Exception { Map m = new HashMap(); m.put( "name", "jason" ); m.put( "noun", "asshole" ); String foo = "@name@ is an @foobarred@"; assertEquals( "jason is an @foobarred@", interpolate( foo, m, "@", "@" ) ); } public void testInterpolationWithSpecifiedBoundaryTokensWithInterpolatedValueAtEnd() throws Exception { Map m = new HashMap(); m.put( "name", "jason" ); m.put( "noun", "asshole" ); String foo = "@name@ is an @noun@"; assertEquals( "jason is an asshole", interpolate( foo, m, "@", "@" ) ); } public void testInterpolationWithSpecifiedBoundaryTokensAndAdditionalTokenCharacter() throws Exception { Map m = new HashMap(); m.put( "name", "jason" ); m.put( "noun", "asshole" ); String foo = "@name@ (known as jason@somewhere) is an @noun@"; assertEquals( "jason (known as jason@somewhere) is an asshole", interpolate( foo, m, "@", "@" ) ); } // ---------------------------------------------------------------------- // // ---------------------------------------------------------------------- private String interpolate( String input, Map context ) throws Exception { return IOUtil.toString( new InterpolationFilterReader( new StringReader( input ), context ) ); } private String interpolate( String input, Map context, String startToken, String endToken ) throws Exception { return IOUtil.toString( new InterpolationFilterReader( new StringReader( input ), context, startToken, endToken ) ); } } LineOrientedInterpolatingReaderTest.java000066400000000000000000000141451251077732300362020ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/utilpackage 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.BufferedReader; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import java.util.Collections; import java.util.HashMap; import java.util.Map; import junit.framework.TestCase; /** * Generated by JUnitDoclet, a tool provided by ObjectFab GmbH under LGPL. * Please see www.junitdoclet.org, www.gnu.org and www.objectfab.de for * informations about the tool, the licence and the authors. */ public class LineOrientedInterpolatingReaderTest extends TestCase { public LineOrientedInterpolatingReaderTest( String name ) { super( name ); } /** * The JUnit setup method */ protected void setUp() throws Exception { } /** * The teardown method for JUnit */ protected void tearDown() throws Exception { } /* * Added and commented by jdcasey@03-Feb-2005 because it is a bug in the * InterpolationFilterReader. */ public void testShouldInterpolateExpressionAtEndOfDataWithInvalidEndToken() throws IOException { String testStr = "This is a ${test"; LineOrientedInterpolatingReader iReader = new LineOrientedInterpolatingReader( new StringReader( testStr ), Collections .singletonMap( "test", "TestValue" ) ); BufferedReader reader = new BufferedReader( iReader ); String result = reader.readLine(); assertEquals( "This is a ${test", result ); } public void testDefaultInterpolationWithNonInterpolatedValueAtEnd() throws Exception { Map m = getStandardMap(); String foo = "${name} is an ${noun}. ${not.interpolated}"; LineOrientedInterpolatingReader reader = new LineOrientedInterpolatingReader( new StringReader( foo ), m ); StringWriter writer = new StringWriter(); IOUtil.copy( reader, writer ); String bar = writer.toString(); assertEquals( "jason is an asshole. ${not.interpolated}", bar ); } private Map getStandardMap() { Map m = new HashMap(); m.put( "name", "jason" ); m.put( "noun", "asshole" ); return m; } public void testDefaultInterpolationWithEscapedExpression() throws Exception { Map m = getStandardMap(); String foo = "${name} is an ${noun}. \\${noun} value"; LineOrientedInterpolatingReader reader = new LineOrientedInterpolatingReader( new StringReader( foo ), m ); StringWriter writer = new StringWriter(); IOUtil.copy( reader, writer ); String bar = writer.toString(); assertEquals( "jason is an asshole. ${noun} value", bar ); } public void testDefaultInterpolationWithInterpolatedValueAtEnd() throws Exception { Map m = getStandardMap(); String foo = "${name} is an ${noun}"; LineOrientedInterpolatingReader reader = new LineOrientedInterpolatingReader( new StringReader( foo ), m ); StringWriter writer = new StringWriter(); IOUtil.copy( reader, writer ); String bar = writer.toString(); assertEquals( "jason is an asshole", bar ); } public void testInterpolationWithSpecifiedBoundaryTokens() throws Exception { Map m = getStandardMap(); String foo = "@name@ is an @noun@. @not.interpolated@ baby @foo@. @bar@"; LineOrientedInterpolatingReader reader = new LineOrientedInterpolatingReader( new StringReader( foo ), m, "@", "@" ); StringWriter writer = new StringWriter(); IOUtil.copy( reader, writer ); String bar = writer.toString(); assertEquals( "jason is an asshole. @not.interpolated@ baby @foo@. @bar@", bar ); } public void testInterpolationWithSpecifiedBoundaryTokensWithNonInterpolatedValueAtEnd() throws Exception { Map m = getStandardMap(); String foo = "@name@ is an @foobarred@"; LineOrientedInterpolatingReader reader = new LineOrientedInterpolatingReader( new StringReader( foo ), m, "@", "@" ); StringWriter writer = new StringWriter(); IOUtil.copy( reader, writer ); String bar = writer.toString(); assertEquals( "jason is an @foobarred@", bar ); } public void testInterpolationWithSpecifiedBoundaryTokensWithInterpolatedValueAtEnd() throws Exception { Map m = getStandardMap(); String foo = "@name@ is an @noun@"; LineOrientedInterpolatingReader reader = new LineOrientedInterpolatingReader( new StringReader( foo ), m, "@", "@" ); StringWriter writer = new StringWriter(); IOUtil.copy( reader, writer ); String bar = writer.toString(); assertEquals( "jason is an asshole", bar ); } }plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/MatchPatternTest.java000066400000000000000000000016621251077732300324070ustar00rootroot00000000000000package 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 junit.framework.TestCase; /** * @author Kristian Rosenvold */ public class MatchPatternTest extends TestCase { public void testMatchPath() throws Exception { MatchPattern mp = MatchPattern.fromString( "ABC*" ); assertTrue(mp.matchPath( "ABCD", true )); } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/MatchPatternsTest.java000066400000000000000000000017761251077732300326000ustar00rootroot00000000000000package 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 junit.framework.TestCase; public class MatchPatternsTest extends TestCase { public void testMatches() throws Exception { MatchPatterns from = MatchPatterns.from( "ABC**", "CDE**" ); assertTrue( from.matches( "ABCDE", true ) ); assertTrue( from.matches( "CDEF", true ) ); assertFalse( from.matches( "XYZ", true ) ); } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/OsTest.java000066400000000000000000000050751251077732300304000ustar00rootroot00000000000000package 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.util.Iterator; import junit.framework.TestCase; /** * Test Case for Os */ public class OsTest extends TestCase { public void testUndefinedFamily() { assertFalse( Os.isFamily( "bogus family" ) ); } public void testOs() { Iterator iter = Os.getValidFamilies().iterator(); String currentFamily = null; String notCurrentFamily = null; while ( iter.hasNext() && ( currentFamily == null || notCurrentFamily == null ) ) { String fam = iter.next(); if ( Os.isFamily( fam ) ) { currentFamily = fam; } else { notCurrentFamily = fam; } } //make sure the OS_FAMILY is set right. assertEquals( currentFamily, Os.OS_FAMILY ); // check the current family and one of the others assertTrue( Os.isOs( currentFamily, null, null, null ) ); assertFalse( Os.isOs( notCurrentFamily, null, null, null ) ); // check for junk assertFalse( Os.isOs( "junk", null, null, null ) ); // check the current name assertTrue( Os.isOs( currentFamily, Os.OS_NAME, null, null ) ); // check some other name assertFalse( Os.isOs( currentFamily, "myos", null, null ) ); // check the arch assertTrue( Os.isOs( currentFamily, Os.OS_NAME, Os.OS_ARCH, null ) ); assertFalse( Os.isOs( currentFamily, Os.OS_NAME, "myarch", null ) ); // check the version assertTrue( Os.isOs( currentFamily, Os.OS_NAME, Os.OS_ARCH, Os.OS_VERSION ) ); assertFalse( Os.isOs( currentFamily, Os.OS_NAME, Os.OS_ARCH, "myversion" ) ); } public void testValidList() { assertTrue(Os.isValidFamily( "dos" ) ); assertFalse( Os.isValidFamily( "" ) ); assertFalse( Os.isValidFamily( null ) ); assertFalse( Os.isValidFamily( "something" ) ); } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/PathToolTest.java000066400000000000000000000140501251077732300315420ustar00rootroot00000000000000package 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 junit.framework.TestCase; /** * @author Vincent Siveton * @version $Id$ */ public class PathToolTest extends TestCase { /** * @throws Exception */ public void testGetRelativePath() throws Exception { assertEquals( PathTool.getRelativePath( null, null ), "" ); assertEquals( PathTool.getRelativePath( null, "/usr/local/java/bin" ), "" ); assertEquals( PathTool.getRelativePath( "/usr/local/", null ), "" ); assertEquals( PathTool.getRelativePath( "/usr/local/", "/usr/local/java/bin" ), ".." ); assertEquals( PathTool.getRelativePath( "/usr/local/", "/usr/local/java/bin/java.sh" ), "../.." ); assertEquals( PathTool.getRelativePath( "/usr/local/java/bin/java.sh", "/usr/local/" ), "" ); } /** * @throws Exception */ public void testGetDirectoryComponent() throws Exception { assertEquals( PathTool.getDirectoryComponent( null ), "" ); assertEquals( PathTool.getDirectoryComponent( "/usr/local/java/bin" ), "/usr/local/java" ); assertEquals( PathTool.getDirectoryComponent( "/usr/local/java/bin/" ), "/usr/local/java/bin" ); assertEquals( PathTool.getDirectoryComponent( "/usr/local/java/bin/java.sh" ), "/usr/local/java/bin" ); } /** * @throws Exception */ public void testCalculateLink() throws Exception { assertEquals( PathTool.calculateLink( "/index.html", "../.." ), "../../index.html" ); assertEquals( PathTool.calculateLink( "http://plexus.codehaus.org/plexus-utils/index.html", "../.." ), "http://plexus.codehaus.org/plexus-utils/index.html" ); assertEquals( PathTool.calculateLink( "/usr/local/java/bin/java.sh", "../.." ), "../../usr/local/java/bin/java.sh" ); assertEquals( PathTool.calculateLink( "../index.html", "/usr/local/java/bin" ), "/usr/local/java/bin/../index.html" ); assertEquals( PathTool.calculateLink( "../index.html", "http://plexus.codehaus.org/plexus-utils" ), "http://plexus.codehaus.org/plexus-utils/../index.html" ); } /** * @throws Exception */ public void testGetRelativeWebPath() throws Exception { assertEquals( PathTool.getRelativeWebPath( null, null ), "" ); assertEquals( PathTool.getRelativeWebPath( null, "http://plexus.codehaus.org/" ), "" ); assertEquals( PathTool.getRelativeWebPath( "http://plexus.codehaus.org/", null ), "" ); assertEquals( PathTool.getRelativeWebPath( "http://plexus.codehaus.org/", "http://plexus.codehaus.org/plexus-utils/index.html" ), "plexus-utils/index.html" ); assertEquals( PathTool.getRelativeWebPath( "http://plexus.codehaus.org/plexus-utils/index.html", "http://plexus.codehaus.org/" ), "../../" ); } /** * @throws Exception */ public void testGetRelativeFilePath() throws Exception { if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) { assertEquals( PathTool.getRelativeFilePath( null, null ), "" ); assertEquals( PathTool.getRelativeFilePath( null, "c:\\tools\\java\\bin" ), "" ); assertEquals( PathTool.getRelativeFilePath( "c:\\tools\\java", null ), "" ); assertEquals( PathTool.getRelativeFilePath( "c:\\tools", "c:\\tools\\java\\bin" ), "java\\bin" ); assertEquals( PathTool.getRelativeFilePath( "c:\\tools", "c:\\tools\\java\\bin\\" ), "java\\bin\\" ); assertEquals( PathTool.getRelativeFilePath( "c:\\tools\\java\\bin", "c:\\tools" ), "..\\.." ); assertEquals( PathTool.getRelativeFilePath( "c:\\tools\\", "c:\\tools\\java\\bin\\java.exe" ), "java\\bin\\java.exe" ); assertEquals( PathTool.getRelativeFilePath( "c:\\tools\\java\\bin\\java.sh", "c:\\tools" ), "..\\..\\.." ); assertEquals( PathTool.getRelativeFilePath( "c:\\tools", "c:\\bin" ), "..\\bin" ); assertEquals( PathTool.getRelativeFilePath( "c:\\bin", "c:\\tools" ), "..\\tools" ); assertEquals( PathTool.getRelativeFilePath( "c:\\bin", "c:\\bin" ), "" ); } else { assertEquals( PathTool.getRelativeFilePath( null, null ), "" ); assertEquals( PathTool.getRelativeFilePath( null, "/usr/local/java/bin" ), "" ); assertEquals( PathTool.getRelativeFilePath( "/usr/local", null ), "" ); assertEquals( PathTool.getRelativeFilePath( "/usr/local", "/usr/local/java/bin" ), "java/bin" ); assertEquals( PathTool.getRelativeFilePath( "/usr/local", "/usr/local/java/bin/" ), "java/bin/" ); assertEquals( PathTool.getRelativeFilePath( "/usr/local/java/bin", "/usr/local/" ), "../../" ); assertEquals( PathTool.getRelativeFilePath( "/usr/local/", "/usr/local/java/bin/java.sh" ), "java/bin/java.sh" ); assertEquals( PathTool.getRelativeFilePath( "/usr/local/java/bin/java.sh", "/usr/local/" ), "../../../" ); assertEquals( PathTool.getRelativeFilePath( "/usr/local/", "/bin" ), "../../bin" ); assertEquals( PathTool.getRelativeFilePath( "/bin", "/usr/local" ), "../usr/local" ); assertEquals( PathTool.getRelativeFilePath( "/bin", "/bin" ), "" ); } } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/PerfTest.java000066400000000000000000000031301251077732300307010ustar00rootroot00000000000000package org.codehaus.plexus.util; import junit.framework.TestCase; /* * 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. */ public class PerfTest extends TestCase { String src = "012345578901234556789012345678901234456789012345678901234567890"; private final int oops = 100; public void testSubString() { StringBuilder res = new StringBuilder(); int len = src.length(); for ( int cnt = 0; cnt < oops; cnt++ ) { for ( int i = 0; i < len - 5; i++ ) { res.append( src.substring( i, i+4 ) ); } } int i = res.length(); System.out.println( "i = " + i ); } public void testResDir() { StringBuilder res = new StringBuilder(); int len = src.length(); for ( int cnt = 0; cnt < oops; cnt++ ) { for ( int i = 0; i < len - 5; i++ ) { res.append( src, i, i+4 ); } } int i = res.length(); System.out.println( "i = " + i ); } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/ReflectionUtilsTest.java000066400000000000000000000057731251077732300331370ustar00rootroot00000000000000package 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 junit.framework.TestCase; import java.util.Map; import java.util.HashMap; /** * This is used to test ReflectionUtils for correctness. * * @author Jesse McConnell * @version $Id:$ * @see org.codehaus.plexus.util.ReflectionUtils */ public final class ReflectionUtilsTest extends TestCase { public ReflectionUtilsTestClass testClass = new ReflectionUtilsTestClass(); protected void setUp() throws Exception { } public void testSimpleVariableAccess() throws IllegalAccessException { assertEquals("woohoo", (String)ReflectionUtils.getValueIncludingSuperclasses( "myString", testClass ) ); } public void testComplexVariableAccess() throws IllegalAccessException { Map map = ReflectionUtils.getVariablesAndValuesIncludingSuperclasses( testClass ); Map myMap = (Map)map.get( "myMap" ); assertEquals( "myValue", (String)myMap.get( "myKey" ) ); assertEquals( "myOtherValue", (String)myMap.get( "myOtherKey") ); } public void testSuperClassVariableAccess() throws IllegalAccessException { assertEquals("super-duper", (String)ReflectionUtils.getValueIncludingSuperclasses( "mySuperString", testClass ) ); } public void testSettingVariableValue() throws IllegalAccessException { ReflectionUtils.setVariableValueInObject( testClass, "mySettableString", "mySetString" ); assertEquals("mySetString", (String)ReflectionUtils.getValueIncludingSuperclasses( "mySettableString", testClass ) ); ReflectionUtils.setVariableValueInObject( testClass, "myParentsSettableString", "myParentsSetString" ); assertEquals("myParentsSetString", (String)ReflectionUtils.getValueIncludingSuperclasses( "myParentsSettableString", testClass ) ); } private class ReflectionUtilsTestClass extends AbstractReflectionUtilsTestClass { private String myString = "woohoo"; private String mySettableString; private Map myMap = new HashMap(); public ReflectionUtilsTestClass() { myMap.put("myKey", "myValue"); myMap.put( "myOtherKey", "myOtherValue" ); } } private class AbstractReflectionUtilsTestClass { private String mySuperString = "super-duper"; private String myParentsSettableString; } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/SelectorUtilsTest.java000066400000000000000000000067301251077732300326170ustar00rootroot00000000000000package org.codehaus.plexus.util; import java.io.File; import junit.framework.TestCase; /* * 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. */ public class SelectorUtilsTest extends TestCase { public void testMatchPath_DefaultFileSeparator() { String separator = File.separator; // Pattern and target start with file separator assertTrue( SelectorUtils.matchPath( separator + "*" + separator + "a.txt", separator + "b" + separator + "a.txt" ) ); // Pattern starts with file separator, target doesn't assertFalse( SelectorUtils.matchPath( separator + "*" + separator + "a.txt", "b" + separator + "a.txt" ) ); // Pattern doesn't start with file separator, target does assertFalse( SelectorUtils.matchPath( "*" + separator + "a.txt", separator + "b" + separator + "a.txt" ) ); // Pattern and target don't start with file separator assertTrue( SelectorUtils.matchPath( "*" + separator + "a.txt", "b" + separator + "a.txt" ) ); } public void testMatchPath_UnixFileSeparator() { String separator = "/"; // Pattern and target start with file separator assertTrue( SelectorUtils.matchPath( separator + "*" + separator + "a.txt", separator + "b" + separator + "a.txt", separator, false ) ); // Pattern starts with file separator, target doesn't assertFalse( SelectorUtils.matchPath( separator + "*" + separator + "a.txt", "b" + separator + "a.txt", separator, false ) ); // Pattern doesn't start with file separator, target does assertFalse( SelectorUtils.matchPath( "*" + separator + "a.txt", separator + "b" + separator + "a.txt", separator, false ) ); // Pattern and target don't start with file separator assertTrue( SelectorUtils.matchPath( "*" + separator + "a.txt", "b" + separator + "a.txt", separator, false ) ); } public void testMatchPath_WindowsFileSeparator() { String separator = "\\"; // Pattern and target start with file separator assertTrue( SelectorUtils.matchPath( separator + "*" + separator + "a.txt", separator + "b" + separator + "a.txt", separator, false ) ); // Pattern starts with file separator, target doesn't assertFalse( SelectorUtils.matchPath( separator + "*" + separator + "a.txt", "b" + separator + "a.txt", separator, false ) ); // Pattern doesn't start with file separator, target does assertFalse( SelectorUtils.matchPath( "*" + separator + "a.txt", separator + "b" + separator + "a.txt", separator, false ) ); // Pattern and target don't start with file separator assertTrue( SelectorUtils.matchPath( "*" + separator + "a.txt", "b" + separator + "a.txt", separator, false ) ); } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/StringInputStreamTest.java000066400000000000000000000014601251077732300334530ustar00rootroot00000000000000package 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 junit.framework.TestCase; /** * @author Ben Walding * @version $Id$ */ public class StringInputStreamTest extends TestCase { public void testFoo() { } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/StringUtilsTest.java000066400000000000000000000211351251077732300323010ustar00rootroot00000000000000package 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.util.Arrays; import java.util.Locale; import junit.framework.TestCase; /** * Test string utils. * * @author Brett Porter * @version $Id$ */ public class StringUtilsTest extends TestCase { public void testIsEmpty() { assertEquals( true, StringUtils.isEmpty( null ) ); assertEquals( true, StringUtils.isEmpty( "" ) ); assertEquals( true, StringUtils.isEmpty( " " ) ); assertEquals( false, StringUtils.isEmpty( "foo" ) ); assertEquals( false, StringUtils.isEmpty( " foo " ) ); } public void testIsNotEmpty() { assertEquals( false, StringUtils.isNotEmpty( null ) ); assertEquals( false, StringUtils.isNotEmpty( "" ) ); assertEquals( true, StringUtils.isNotEmpty( " " ) ); assertEquals( true, StringUtils.isNotEmpty( "foo" ) ); assertEquals( true, StringUtils.isNotEmpty( " foo " ) ); } public void testIsBlank() { assertEquals( true, StringUtils.isBlank( null ) ); assertEquals( true, StringUtils.isBlank( "" ) ); assertEquals( true, StringUtils.isBlank( " \t\r\n" ) ); assertEquals( false, StringUtils.isBlank( "foo" ) ); assertEquals( false, StringUtils.isBlank( " foo " ) ); } public void testIsNotBlank() { assertEquals( false, StringUtils.isNotBlank( null ) ); assertEquals( false, StringUtils.isNotBlank( "" ) ); assertEquals( false, StringUtils.isNotBlank( " \t\r\n" ) ); assertEquals( true, StringUtils.isNotBlank( "foo" ) ); assertEquals( true, StringUtils.isNotBlank( " foo " ) ); } public void testCapitalizeFirstLetter() { assertEquals( "Id", StringUtils.capitalizeFirstLetter( "id" ) ); assertEquals( "Id", StringUtils.capitalizeFirstLetter( "Id" ) ); } public void testCapitalizeFirstLetterTurkish() { Locale l = Locale.getDefault(); Locale.setDefault( new Locale( "tr" ) ); assertEquals( "Id", StringUtils.capitalizeFirstLetter( "id" ) ); assertEquals( "Id", StringUtils.capitalizeFirstLetter( "Id" ) ); Locale.setDefault( l ); } public void testLowerCaseFirstLetter() { assertEquals( "id", StringUtils.lowercaseFirstLetter( "id" ) ); assertEquals( "id", StringUtils.lowercaseFirstLetter( "Id" ) ); } public void testLowerCaseFirstLetterTurkish() { Locale l = Locale.getDefault(); Locale.setDefault( new Locale( "tr" ) ); assertEquals( "id", StringUtils.lowercaseFirstLetter( "id" ) ); assertEquals( "id", StringUtils.lowercaseFirstLetter( "Id" ) ); Locale.setDefault( l ); } public void testRemoveAndHump() { assertEquals( "Id", StringUtils.removeAndHump( "id", "-" ) ); assertEquals( "SomeId", StringUtils.removeAndHump( "some-id", "-" ) ); } public void testRemoveAndHumpTurkish() { Locale l = Locale.getDefault(); Locale.setDefault( new Locale( "tr" ) ); assertEquals( "Id", StringUtils.removeAndHump( "id", "-" ) ); assertEquals( "SomeId", StringUtils.removeAndHump( "some-id", "-" ) ); Locale.setDefault( l ); } public void testQuote_EscapeEmbeddedSingleQuotes() { String src = "This \'is a\' test"; String check = "\'This \\\'is a\\\' test\'"; char[] escaped = { '\'', '\"' }; String result = StringUtils.quoteAndEscape( src, '\'', escaped, '\\', false ); assertEquals( check, result ); } public void testQuote_EscapeEmbeddedSingleQuotesWithPattern() { String src = "This \'is a\' test"; String check = "\'This pre'postis apre'post test\'"; char[] escaped = { '\'', '\"' }; String result = StringUtils.quoteAndEscape( src, '\'', escaped, new char[]{ ' ' }, "pre%spost", false ); assertEquals( check, result ); } public void testQuote_EscapeEmbeddedDoubleQuotesAndSpaces() { String src = "This \"is a\" test"; String check = "\'This\\ \\\"is\\ a\\\"\\ test\'"; char[] escaped = { '\'', '\"', ' ' }; String result = StringUtils.quoteAndEscape( src, '\'', escaped, '\\', false ); assertEquals( check, result ); } public void testQuote_DontQuoteIfUnneeded() { String src = "ThisIsATest"; char[] escaped = { '\'', '\"' }; String result = StringUtils.quoteAndEscape( src, '\'', escaped, '\\', false ); assertEquals( src, result ); } public void testQuote_WrapWithSingleQuotes() { String src = "This is a test"; String check = "\'This is a test\'"; char[] escaped = { '\'', '\"' }; String result = StringUtils.quoteAndEscape( src, '\'', escaped, '\\', false ); assertEquals( check, result ); } public void testQuote_PreserveExistingQuotes() { String src = "\'This is a test\'"; char[] escaped = { '\'', '\"' }; String result = StringUtils.quoteAndEscape( src, '\'', escaped, '\\', false ); assertEquals( src, result ); } public void testQuote_WrapExistingQuotesWhenForceIsTrue() { String src = "\'This is a test\'"; String check = "\'\\\'This is a test\\\'\'"; char[] escaped = { '\'', '\"' }; String result = StringUtils.quoteAndEscape( src, '\'', escaped, '\\', true ); assertEquals( check, result ); } public void testQuote_ShortVersion_SingleQuotesPreserved() { String src = "\'This is a test\'"; String result = StringUtils.quoteAndEscape( src, '\'' ); assertEquals( src, result ); } public void testSplit() { String[] tokens; tokens = StringUtils.split( "", ", " ); assertNotNull( tokens ); assertEquals( Arrays.asList( new String[0] ), Arrays.asList( tokens ) ); tokens = StringUtils.split( ", ,,, ,", ", " ); assertNotNull( tokens ); assertEquals( Arrays.asList( new String[0] ), Arrays.asList( tokens ) ); tokens = StringUtils.split( "this", ", " ); assertNotNull( tokens ); assertEquals( Arrays.asList( new String[] { "this" } ), Arrays.asList( tokens ) ); tokens = StringUtils.split( "this is a test", ", " ); assertNotNull( tokens ); assertEquals( Arrays.asList( new String[] { "this", "is", "a", "test" } ), Arrays.asList( tokens ) ); tokens = StringUtils.split( " this is a test ", ", " ); assertNotNull( tokens ); assertEquals( Arrays.asList( new String[] { "this", "is", "a", "test" } ), Arrays.asList( tokens ) ); tokens = StringUtils.split( "this is a test, really", ", " ); assertNotNull( tokens ); assertEquals( Arrays.asList( new String[] { "this", "is", "a", "test", "really" } ), Arrays.asList( tokens ) ); } public void testRemoveDuplicateWhitespace() throws Exception { String s = "this is test "; assertEquals( "this is test ", StringUtils.removeDuplicateWhitespace( s ) ); s = "this \r\n is \n \r test "; assertEquals( "this is test ", StringUtils.removeDuplicateWhitespace( s ) ); s = " this \r\n is \n \r test"; assertEquals( " this is test", StringUtils.removeDuplicateWhitespace( s ) ); s = "this \r\n is \n \r test \n "; assertEquals( "this is test ", StringUtils.removeDuplicateWhitespace( s ) ); } public void testUnifyLineSeparators() throws Exception { String s = "this\r\nis\na\r\ntest"; try { StringUtils.unifyLineSeparators( s, "abs" ); assertTrue( "Exception NOT catched", false ); } catch ( IllegalArgumentException e) { assertTrue( "Exception catched", true ); } assertEquals( "this\nis\na\ntest", StringUtils.unifyLineSeparators( s, "\n" ) ); assertEquals( "this\r\nis\r\na\r\ntest", StringUtils.unifyLineSeparators( s, "\r\n" ) ); } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/SweeperPoolTest.java000066400000000000000000000126601251077732300322610ustar00rootroot00000000000000package 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 junit.framework.TestCase; import java.util.Vector; /** * Created on 21/06/2003 * * @author Bert van Brakel * @version $Revision$ */ public class SweeperPoolTest extends TestCase { /** The pool under test */ TestObjectPool pool; /** A bunch of object to pool */ Object o1; Object o2; Object o3; Object o4; Object o5; Object o6; /** * Constructor * * */ public SweeperPoolTest() { super(); } /** * Constructor * * @param arg0 */ public SweeperPoolTest( String arg0 ) { super( arg0 ); } /** * Test the pool limits it's size, and disposes unneeded objects correctly * */ public void testMaxSize() { int sweepInterval = 0; int initialCapacity = 5; int maxSize = 2; int minSize = 1; int triggerSize = 2; pool = new TestObjectPool( maxSize, minSize, initialCapacity, sweepInterval, triggerSize ); Object tmp = pool.get(); assertNull( "Expected object from pool to be null", tmp ); pool.put( o1 ); assertEquals( "Expected pool to contain 1 object", 1, pool.getSize() ); tmp = pool.get(); assertSame( "Expected returned pool object to be the same as the one put in", tmp, o1 ); pool.put( o1 ); pool.put( o2 ); assertEquals( "Expected pool to contain 2 objects", 2, pool.getSize() ); pool.put( o3 ); assertEquals( "Expected pool to contain only a maximuim of 2 objects.", 2, pool.getSize() ); assertEquals( "Expected 1 disposed pool object", 1, pool.testGetDisposedObjects().size() ); tmp = pool.testGetDisposedObjects().iterator().next(); tmp = pool.get(); assertEquals( "Expected pool size to be 1 after removing one object", 1, pool.getSize() ); Object tmp2 = pool.get(); assertEquals( "Expected pool size to be 0 after removing 2 objects", 0, pool.getSize() ); assertNotSame( "Expected returned objects to be differnet", tmp, tmp2 ); } public void testSweepAndTrim1() { //test trigger int sweepInterval = 1; int initialCapacity = 5; int maxSize = 5; int minSize = 1; int triggerSize = 2; pool = new TestObjectPool( maxSize, minSize, initialCapacity, sweepInterval, triggerSize ); pool.put( o1 ); pool.put( o2 ); pool.put( o3 ); pool.put( o4 ); //give the seeper some time to run synchronized ( this ) { try { wait( 2 * 1000 ); } catch ( InterruptedException e ) { fail( "Unexpected exception thrown. e=" + Tracer.traceToString( e ) ); } } assertEquals( "Expected pool to only contain 1 object", 1, pool.getSize() ); assertEquals( "Expected 3 diposed objects", 3, pool.testGetDisposedObjects().size() ); } /** * @see junit.framework.TestCase#setUp() */ protected void setUp() throws Exception { o1 = new Object(); o2 = new Object(); o3 = new Object(); o4 = new Object(); o5 = new Object(); o6 = new Object(); super.setUp(); } /** * @see junit.framework.TestCase#tearDown() */ protected void tearDown() throws Exception { pool.dispose(); assertTrue( pool.isDisposed() ); pool = null; super.tearDown(); } class TestObjectPool extends SweeperPool { private Vector disposedObjects = new Vector(); public TestObjectPool( int maxSize, int minSize, int intialCapacity, int sweepInterval, int triggerSize ) { super( maxSize, minSize, intialCapacity, sweepInterval, triggerSize ); } public void reset() { disposedObjects.clear(); } /** * @see nz.co.bonzo.beans.castor.pool.ObjectPool#objectDisposed(java.lang.Object) */ public void objectDisposed( Object obj ) { disposedObjects.add( obj ); } public Vector testGetDisposedObjects() { return disposedObjects; } } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/TestThreadManager.java000066400000000000000000000120041251077732300325070ustar00rootroot00000000000000package 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.util.Collection; import java.util.Iterator; import java.util.Vector; import java.util.logging.Logger; /** * Manages a number of test threads, which notify this manager when they have * completed. Allows TestCases to easily start and manage multiple test threads. * *

            Created on 9/06/2003

            * * @author Bert van Brakel * @version $Revision$ * */ public class TestThreadManager { //~ Instance fields ---------------------------------------------------------------------------- /** Test threads which have completed running */ private Collection runThreads = new Vector(); /** Test threads still needing to be run, or are currently running*/ private Collection toRunThreads = new Vector(); private Logger logger = null; /** Any test threads which failed */ private Vector failedThreads = new Vector(); /**The object to notify when all the test threads have complleted. Clients use this * to lock on (wait) while waiting for the tests to complete*/ private Object notify = null; //~ Constructors ------------------------------------------------------------------------------- public TestThreadManager( Object notify ) { super(); this.notify = notify; } //~ Methods ------------------------------------------------------------------------------------ /** * @return */ public Collection getRunThreads() { return runThreads; } public void runTestThreads() { failedThreads.clear(); //use an array as the tests may run very quickly //and modify the toRunThreads vector and hence //cause a Concurrent ModificationException on an //iterator for ( AbstractTestThread toRunThread : toRunThreads ) { toRunThread.start(); } } public Collection getFailedTests() { return failedThreads; } /** * Return the object which threads can wait on to be notified * when all the test threads have completed running * * @return */ public Object getNotifyObject() { return notify; } public boolean hasFailedThreads() { return !failedThreads.isEmpty(); } /** * Determine if any threads are still running! * * @return DOCUMENT ME! */ public boolean isStillRunningThreads() { return !toRunThreads.isEmpty(); } /** * @return */ public Collection getToRunThreads() { return toRunThreads; } /** * DOCUMENT ME! */ public void clear() { toRunThreads.clear(); runThreads.clear(); failedThreads.clear(); } /* (non-Javadoc) * @see java.util.Collection#remove(java.lang.Object) */ public synchronized void completed( AbstractTestThread thread ) { toRunThreads.remove( thread ); runThreads.add( thread ); if ( thread.hasFailed() ) { failedThreads.add( thread ); } //wakeup thread which is waiting for the threads to complete //execution if ( toRunThreads.isEmpty() ) { synchronized ( notify ) { notify.notify(); } } } /** * Overide this to add your own stuff. Called after * registerThread(Object) * * @param thread DOCUMENT ME! */ public void doRegisterThread( AbstractTestThread thread ) { } public final void registerThread( AbstractTestThread thread ) { thread.setThreadRegistry( this ); if ( toRunThreads.contains( thread ) == false ) { toRunThreads.add( thread ); doRegisterThread( thread ); } } /** * Put all the runThreads back in the que to be run again and * clear the failedTest collection */ public void reset() { toRunThreads.clear(); for ( Object runThread : runThreads ) { AbstractTestThread test = (AbstractTestThread) runThread; test.reset(); registerThread( test ); } runThreads.clear(); failedThreads.clear(); } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/Tracer.java000066400000000000000000000025031251077732300303700ustar00rootroot00000000000000package 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.PrintWriter; import java.io.StringWriter; /** * Convenience class to handle throwable stacktraces * *

            Created on 18/06/2003

            * * @author Bert van Brakel * @version $Revision$ */ public class Tracer { /** * Constructor * * */ private Tracer() { super(); } /** * Return the throwable stack trace as a string * */ public static String traceToString( Throwable t ) { if ( t == null ) { return null; } StringWriter sw = new StringWriter(); t.printStackTrace( new PrintWriter( sw ) ); return sw.toString(); } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/WalkCollector.java000066400000000000000000000034031251077732300317150ustar00rootroot00000000000000package 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; class WalkCollector implements DirectoryWalkListener { public List steps; public File startingDir; public int startCount; public int finishCount; public int percentageLow; public int percentageHigh; public WalkCollector() { steps = new ArrayList(); startCount = 0; finishCount = 0; percentageLow = 0; percentageHigh = 0; } public void directoryWalkStarting( File basedir ) { debug( "Walk Starting: " + basedir ); startCount++; startingDir = basedir; } public void directoryWalkStep( int percentage, File file ) { percentageLow = Math.min( percentageLow, percentage ); percentageHigh = Math.max( percentageHigh, percentage ); debug( "Walk Step: [" + percentage + "%] " + file ); steps.add( file ); } public void directoryWalkFinished() { debug( "Walk Finished." ); finishCount++; } public void debug( String message ) { System.out.println( message ); } }plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/cli/000077500000000000000000000000001251077732300270545ustar00rootroot00000000000000CommandLineUtilsTest.java000066400000000000000000000074311251077732300337140ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/clipackage 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 junit.framework.TestCase; import org.codehaus.plexus.util.Os; import java.util.Arrays; import java.util.Locale; import java.util.Properties; @SuppressWarnings( { "JavaDoc", "deprecation" } ) public class CommandLineUtilsTest extends TestCase { public void testQuoteArguments() { try { String result = CommandLineUtils.quote( "Hello" ); System.out.println( result ); assertEquals( "Hello", result ); result = CommandLineUtils.quote( "Hello World" ); System.out.println( result ); assertEquals( "\"Hello World\"", result ); result = CommandLineUtils.quote( "\"Hello World\"" ); System.out.println( result ); assertEquals( "\'\"Hello World\"\'", result ); } catch ( Exception e ) { fail( e.getMessage() ); } try { CommandLineUtils.quote( "\"Hello \'World\'\'" ); fail(); } catch ( Exception e ) { } } /** * Tests that case-insensitive environment variables are normalized to upper case. */ public void testGetSystemEnvVarsCaseInsensitive() throws Exception { Properties vars = CommandLineUtils.getSystemEnvVars( false ); for ( Object o : vars.keySet() ) { String variable = (String) o; assertEquals( variable.toUpperCase( Locale.ENGLISH ), variable ); } } /** * Tests that environment variables on Windows are normalized to upper case. Does nothing on Unix platforms. */ public void testGetSystemEnvVarsWindows() throws Exception { if ( !Os.isFamily( Os.FAMILY_WINDOWS ) ) { return; } Properties vars = CommandLineUtils.getSystemEnvVars(); for ( Object o : vars.keySet() ) { String variable = (String) o; assertEquals( variable.toUpperCase( Locale.ENGLISH ), variable ); } } /** * Tests the splitting of a command line into distinct arguments. */ public void testTranslateCommandline() throws Exception { assertCmdLineArgs( new String[] {}, null ); assertCmdLineArgs( new String[] {}, "" ); assertCmdLineArgs( new String[] { "foo", "bar" }, "foo bar" ); assertCmdLineArgs( new String[] { "foo", "bar" }, " foo bar " ); assertCmdLineArgs( new String[] { "foo", " double quotes ", "bar" }, "foo \" double quotes \" bar" ); assertCmdLineArgs( new String[] { "foo", " single quotes ", "bar" }, "foo ' single quotes ' bar" ); assertCmdLineArgs( new String[] { "foo", " \" ", "bar" }, "foo ' \" ' bar" ); assertCmdLineArgs( new String[] { "foo", " ' ", "bar" }, "foo \" ' \" bar" ); } private void assertCmdLineArgs( String[] expected, String cmdLine ) throws Exception { String[] actual = CommandLineUtils.translateCommandline( cmdLine ); assertNotNull( actual ); assertEquals( expected.length, actual.length ); assertEquals( Arrays.asList( expected ), Arrays.asList( actual ) ); } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/cli/CommandlineTest.java000066400000000000000000000472251251077732300330170ustar00rootroot00000000000000package 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 junit.framework.TestCase; import org.codehaus.plexus.util.IOUtil; import org.codehaus.plexus.util.Os; import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.util.cli.shell.BourneShell; import org.codehaus.plexus.util.cli.shell.CmdShell; import org.codehaus.plexus.util.cli.shell.Shell; import java.io.*; public class CommandlineTest extends TestCase { private String baseDir; /** * @param testName */ public CommandlineTest( final String testName ) { super( testName ); } /* * @see TestCase#setUp() */ public void setUp() throws Exception { super.setUp(); baseDir = System.getProperty( "basedir" ); if ( baseDir == null ) { baseDir = new File( "." ).getCanonicalPath(); } } public void testCommandlineWithoutCommandInConstructor() { try { Commandline cmd = new Commandline( new Shell() ); cmd.setWorkingDirectory( baseDir ); cmd.createArgument().setValue( "cd" ); cmd.createArgument().setValue( "." ); // NOTE: cmd.toString() uses CommandLineUtils.toString( String[] ), which *quotes* the result. assertEquals( "cd .", cmd.toString() ); } catch ( Exception e ) { fail( e.getMessage() ); } } public void testCommandlineWithCommandInConstructor() { try { Commandline cmd = new Commandline( "cd .", new Shell() ); cmd.setWorkingDirectory( baseDir ); // NOTE: cmd.toString() uses CommandLineUtils.toString( String[] ), which *quotes* the result. assertEquals( "cd .", cmd.toString() ); } catch ( Exception e ) { fail( e.getMessage() ); } } public void testExecute() { try { // allow it to detect the proper shell here. Commandline cmd = new Commandline(); cmd.setWorkingDirectory( baseDir ); cmd.setExecutable( "echo" ); assertEquals( "echo", cmd.getShell().getOriginalExecutable() ); cmd.createArgument().setValue( "Hello" ); StringWriter swriter = new StringWriter(); Process process = cmd.execute(); Reader reader = new InputStreamReader( process.getInputStream() ); char[] chars = new char[16]; int read = -1; while ( ( read = reader.read( chars ) ) > -1 ) { swriter.write( chars, 0, read ); } String output = swriter.toString().trim(); assertEquals( "Hello", output ); } catch ( Exception e ) { fail( e.getMessage() ); } } public void testSetLine() { try { Commandline cmd = new Commandline( new Shell() ); cmd.setWorkingDirectory( baseDir ); cmd.setExecutable( "echo" ); cmd.createArgument().setLine( null ); cmd.createArgument().setLine( "Hello" ); // NOTE: cmd.toString() uses CommandLineUtils.toString( String[] ), which *quotes* the result. assertEquals( "echo Hello", cmd.toString() ); } catch ( Exception e ) { fail( e.getMessage() ); } } public void testCreateCommandInReverseOrder() { try { Commandline cmd = new Commandline( new Shell() ); cmd.setWorkingDirectory( baseDir ); cmd.createArgument().setValue( "." ); cmd.createArgument( true ).setValue( "cd" ); // NOTE: cmd.toString() uses CommandLineUtils.toString( String[] ), which *quotes* the result. assertEquals( "cd .", cmd.toString() ); } catch ( Exception e ) { fail( e.getMessage() ); } } public void testSetFile() { try { Commandline cmd = new Commandline( new Shell() ); cmd.setWorkingDirectory( baseDir ); cmd.createArgument().setValue( "more" ); File f = new File( "test.txt" ); cmd.createArgument().setFile( f ); String fileName = f.getAbsolutePath(); if ( fileName.contains( " " ) ) { fileName = "\"" + fileName + "\""; } // NOTE: cmd.toString() uses CommandLineUtils.toString( String[] ), which *quotes* the result. assertEquals( "more " + fileName, cmd.toString() ); } catch ( Exception e ) { fail( e.getMessage() ); } } public void testGetShellCommandLineWindows() throws Exception { Commandline cmd = new Commandline( new CmdShell() ); cmd.setExecutable( "c:\\Program Files\\xxx" ); cmd.addArguments( new String[] { "a", "b" } ); String[] shellCommandline = cmd.getShellCommandline(); assertEquals( "Command line size", 4, shellCommandline.length ); assertEquals( "cmd.exe", shellCommandline[0] ); assertEquals( "/X", shellCommandline[1] ); assertEquals( "/C", shellCommandline[2] ); String expectedShellCmd = "\"c:" + File.separator + "Program Files" + File.separator + "xxx\" a b"; expectedShellCmd = "\"" + expectedShellCmd + "\""; assertEquals( expectedShellCmd, shellCommandline[3] ); } public void testGetShellCommandLineWindowsWithSeveralQuotes() throws Exception { Commandline cmd = new Commandline( new CmdShell() ); cmd.setExecutable( "c:\\Program Files\\xxx" ); cmd.addArguments( new String[] { "c:\\Documents and Settings\\whatever", "b" } ); String[] shellCommandline = cmd.getShellCommandline(); assertEquals( "Command line size", 4, shellCommandline.length ); assertEquals( "cmd.exe", shellCommandline[0] ); assertEquals( "/X", shellCommandline[1] ); assertEquals( "/C", shellCommandline[2] ); String expectedShellCmd = "\"c:" + File.separator + "Program Files" + File.separator + "xxx\" \"c:\\Documents and Settings\\whatever\" b"; expectedShellCmd = "\"" + expectedShellCmd + "\""; assertEquals( expectedShellCmd, shellCommandline[3] ); } /** * Test the command line generated for the bash shell * @throws Exception */ public void testGetShellCommandLineBash() throws Exception { Commandline cmd = new Commandline( new BourneShell() ); cmd.setExecutable( "/bin/echo" ); cmd.addArguments( new String[] { "hello world" } ); String[] shellCommandline = cmd.getShellCommandline(); assertEquals( "Command line size", 3, shellCommandline.length ); assertEquals( "/bin/sh", shellCommandline[0] ); assertEquals( "-c", shellCommandline[1] ); String expectedShellCmd = "'/bin/echo' 'hello world'"; if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) { expectedShellCmd = "\\bin\\echo \'hello world\'"; } assertEquals( expectedShellCmd, shellCommandline[2] ); } /** * Test the command line generated for the bash shell * @throws Exception */ public void testGetShellCommandLineBash_WithWorkingDirectory() throws Exception { Commandline cmd = new Commandline( new BourneShell() ); cmd.setExecutable( "/bin/echo" ); cmd.addArguments( new String[] { "hello world" } ); File root = File.listRoots()[0]; File workingDirectory = new File( root, "path with spaces" ); cmd.setWorkingDirectory( workingDirectory ); String[] shellCommandline = cmd.getShellCommandline(); assertEquals( "Command line size", 3, shellCommandline.length ); assertEquals( "/bin/sh", shellCommandline[0] ); assertEquals( "-c", shellCommandline[1] ); String expectedShellCmd = "cd '" + root.getAbsolutePath() + "path with spaces' && '/bin/echo' 'hello world'"; if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) { expectedShellCmd = "cd '" + root.getAbsolutePath() + "path with spaces' && '\\bin\\echo' 'hello world'"; } assertEquals( expectedShellCmd, shellCommandline[2] ); } /** * Test the command line generated for the bash shell * @throws Exception */ public void testGetShellCommandLineBash_WithSingleQuotedArg() throws Exception { Commandline cmd = new Commandline( new BourneShell() ); cmd.setExecutable( "/bin/echo" ); cmd.addArguments( new String[] { "\'hello world\'" } ); String[] shellCommandline = cmd.getShellCommandline(); assertEquals( "Command line size", 3, shellCommandline.length ); assertEquals( "/bin/sh", shellCommandline[0] ); assertEquals( "-c", shellCommandline[1] ); String expectedShellCmd = "'/bin/echo' ''\"'\"'hello world'\"'\"''"; if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) { expectedShellCmd = "\\bin\\echo \'hello world\'"; } assertEquals( expectedShellCmd, shellCommandline[2] ); } public void testGetShellCommandLineNonWindows() throws Exception { Commandline cmd = new Commandline( new BourneShell() ); cmd.setExecutable( "/usr/bin" ); cmd.addArguments( new String[] { "a", "b" } ); String[] shellCommandline = cmd.getShellCommandline(); assertEquals( "Command line size", 3, shellCommandline.length ); assertEquals( "/bin/sh", shellCommandline[0] ); assertEquals( "-c", shellCommandline[1] ); if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) { assertEquals( "\\usr\\bin a b", shellCommandline[2] ); } else { assertEquals( "'/usr/bin' 'a' 'b'", shellCommandline[2] ); } } public void testEnvironment() throws Exception { Commandline cmd = new Commandline(); cmd.addEnvironment( "name", "value" ); assertEquals( "name=value", cmd.getEnvironmentVariables()[0] ); } public void testEnvironmentWitOverrideSystemEnvironment() throws Exception { Commandline cmd = new Commandline(); cmd.addSystemEnvironment(); cmd.addEnvironment( "JAVA_HOME", "/usr/jdk1.5" ); String[] environmentVariables = cmd.getEnvironmentVariables(); for ( String environmentVariable : environmentVariables ) { if ( "JAVA_HOME=/usr/jdk1.5".equals( environmentVariable ) ) { return; } } fail( "can't find JAVA_HOME=/usr/jdk1.5" ); } /** * Test an executable with a single apostrophe ' in its path * * @throws Exception */ public void testQuotedPathWithSingleApostrophe() throws Exception { File dir = new File( System.getProperty( "basedir" ), "target/test/quotedpath'test" ); createAndCallScript( dir, "echo Quoted" ); dir = new File( System.getProperty( "basedir" ), "target/test/quoted path'test" ); createAndCallScript( dir, "echo Quoted" ); } /** * Test an executable with shell-expandable content in its path. * * @throws Exception */ public void testPathWithShellExpansionStrings() throws Exception { File dir = new File( System.getProperty( "basedir" ), "target/test/dollar$test" ); createAndCallScript( dir, "echo Quoted" ); } /** * Test an executable with a single quotation mark \" in its path only for non Windows box. * * @throws Exception */ public void testQuotedPathWithQuotationMark() throws Exception { if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) { System.out.println( "testQuotedPathWithQuotationMark() skipped on Windows" ); return; } File dir = new File( System.getProperty( "basedir" ), "target/test/quotedpath\"test" ); createAndCallScript( dir, "echo Quoted" ); dir = new File( System.getProperty( "basedir" ), "target/test/quoted path\"test" ); createAndCallScript( dir, "echo Quoted" ); } /** * Test an executable with a single quotation mark \" and ' in its path only for non * Windows box. * * @throws Exception */ public void testQuotedPathWithQuotationMarkAndApostrophe() throws Exception { if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) { System.out.println( "testQuotedPathWithQuotationMarkAndApostrophe() skipped on Windows" ); return; } File dir = new File( System.getProperty( "basedir" ), "target/test/quotedpath\"'test" ); createAndCallScript( dir, "echo Quoted" ); dir = new File( System.getProperty( "basedir" ), "target/test/quoted path\"'test" ); createAndCallScript( dir, "echo Quoted" ); } /** * Test an executable with a quote in its path and no space * * @throws Exception */ public void testOnlyQuotedPath() throws Exception { File dir = new File( System.getProperty( "basedir" ), "target/test/quotedpath\'test" ); File javaHome = new File( System.getProperty( "java.home" ) ); File java; if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) { java = new File( javaHome, "/bin/java.exe" ); } else { java = new File( javaHome, "/bin/java" ); } if ( !java.exists() ) { throw new IOException( java.getAbsolutePath() + " doesn't exist" ); } createAndCallScript( dir, java.getAbsolutePath() + " -version" ); } public void testDollarSignInArgumentPath() throws Exception { File dir = new File( System.getProperty( "basedir" ), "target/test" ); if ( !dir.exists() ) { assertTrue( "Can't create dir:" + dir.getAbsolutePath(), dir.mkdirs() ); } FileWriter writer = null; try { writer = new FileWriter( new File( dir, "test$1.txt" ) ); IOUtil.copy( "Success", writer ); } finally { IOUtil.close( writer ); } Commandline cmd = new Commandline(); //cmd.getShell().setShellCommand( "/bin/sh" ); cmd.getShell().setQuotedArgumentsEnabled( true ); cmd.setExecutable( "cat" ); if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) { cmd.setExecutable( "dir" ); } cmd.setWorkingDirectory( dir ); cmd.createArg().setLine( "test$1.txt" ); executeCommandLine( cmd ); } public void testTimeOutException() throws Exception { File javaHome = new File( System.getProperty( "java.home" ) ); File java; if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) { java = new File( javaHome, "/bin/java.exe" ); } else { java = new File( javaHome, "/bin/java" ); } if ( !java.exists() ) { throw new IOException( java.getAbsolutePath() + " doesn't exist" ); } Commandline cli = new Commandline(); cli.setExecutable( java.getAbsolutePath() ); cli.createArg().setLine( "-version" ); CommandLineUtils.StringStreamConsumer err = new CommandLineUtils.StringStreamConsumer(); try { // if the os is faster than 1s to execute java -version the unit will fail :-) CommandLineUtils.executeCommandLine( cli, new DefaultConsumer(), err, 1 ); } catch ( CommandLineTimeOutException e ) { // it works } } /** * Make the file executable for Unix box. * * @param path not null * @throws IOException if any */ private static void makeExecutable( File path ) throws IOException { if ( path == null ) { throw new IllegalArgumentException( "The file is null" ); } if ( !path.isFile() ) { throw new IllegalArgumentException( "The file '" + path.getAbsolutePath() + "' should be a file" ); } if ( !Os.isFamily( Os.FAMILY_WINDOWS ) ) { Process proc = Runtime.getRuntime().exec( new String[] { "chmod", "a+x", path.getAbsolutePath() } ); while ( true ) { try { proc.waitFor(); break; } catch ( InterruptedException e ) { // ignore } } } } /** * Create and execute a script file in the given dir with the given content. The script file will be called * echo.bat for Windows box, otherwise echo. * * @param dir the parent dir where echo.bat or echo will be created * @param content the content of the script file * @throws Exception if any */ private static void createAndCallScript( File dir, String content ) throws Exception { if ( !dir.exists() ) { assertTrue( "Can't create dir:" + dir.getAbsolutePath(), dir.mkdirs() ); } // Create a script file File bat; if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) { bat = new File( dir, "echo.bat" ); } else { bat = new File( dir, "echo" ); } Writer w = new FileWriter( bat ); try { IOUtil.copy( content, w ); } finally { IOUtil.close( w ); } // Change permission makeExecutable( bat ); Commandline cmd = new Commandline(); cmd.setExecutable( bat.getAbsolutePath() ); cmd.setWorkingDirectory( dir ); // Execute the script file executeCommandLine( cmd ); } /** * Execute the command line * * @param cmd not null * @throws Exception if any */ private static void executeCommandLine( Commandline cmd ) throws Exception { CommandLineUtils.StringStreamConsumer err = new CommandLineUtils.StringStreamConsumer(); try { System.out.println( "Command line is: " + StringUtils.join( cmd.getShellCommandline(), " " ) ); int exitCode = CommandLineUtils.executeCommandLine( cmd, new DefaultConsumer(), err ); if ( exitCode != 0 ) { String msg = "Exit code: " + exitCode + " - " + err.getOutput(); throw new Exception( msg.toString() ); } } catch ( CommandLineException e ) { throw new Exception( "Unable to execute command: " + e.getMessage(), e ); } } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/cli/DefaultConsumerTest.java000066400000000000000000000021711251077732300336600ustar00rootroot00000000000000package 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 junit.framework.TestCase; public class DefaultConsumerTest extends TestCase { /** * @param testName */ public DefaultConsumerTest( String testName ) { super( testName ); } /* * @see TestCase#setUp() */ public void setUp() throws Exception { super.setUp(); } public void testConsumeLine() { DefaultConsumer cons = new DefaultConsumer(); cons.consumeLine( "Test DefaultConsumer consumeLine" ); } }EnhancedStringTokenizerTest.java000066400000000000000000000074051251077732300352750ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/clipackage 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 junit.framework.TestCase; public class EnhancedStringTokenizerTest extends TestCase { /** * @param testName */ public EnhancedStringTokenizerTest( final String testName ) { super( testName ); } /* * @see TestCase#setUp() */ public void setUp() throws Exception { super.setUp(); } public void test1() { EnhancedStringTokenizer est = new EnhancedStringTokenizer( "this is a test string" ); StringBuilder sb = new StringBuilder(); while ( est.hasMoreTokens() ) { sb.append( est.nextToken() ); sb.append( " " ); } assertEquals( "this is a test string ", sb.toString() ); } public void test2() { EnhancedStringTokenizer est = new EnhancedStringTokenizer( "1,,,3,,4", "," ); assertEquals( "Token 1", "1", est.nextToken() ); assertEquals( "Token 2", "", est.nextToken() ); assertEquals( "Token 3", "", est.nextToken() ); assertEquals( "Token 4", "3", est.nextToken() ); assertEquals( "Token 5", "", est.nextToken() ); assertEquals( "Token 6", "4", est.nextToken() ); } public void test3() { EnhancedStringTokenizer est = new EnhancedStringTokenizer( "1,,,3,,4", ",", true ); assertEquals( "Token 1", "1", est.nextToken() ); assertEquals( "Token 2", ",", est.nextToken() ); assertEquals( "Token 3", "", est.nextToken() ); assertEquals( "Token 4", ",", est.nextToken() ); assertEquals( "Token 5", "", est.nextToken() ); assertEquals( "Token 6", ",", est.nextToken() ); assertEquals( "Token 7", "3", est.nextToken() ); assertEquals( "Token 8", ",", est.nextToken() ); assertEquals( "Token 9", "", est.nextToken() ); assertEquals( "Token 10", ",", est.nextToken() ); assertEquals( "Token 11", "4", est.nextToken() ); } public void testMultipleDelim() { EnhancedStringTokenizer est = new EnhancedStringTokenizer( "1 2|3|4", " |", true ); assertEquals( "Token 1", "1", est.nextToken() ); assertEquals( "Token 2", " ", est.nextToken() ); assertEquals( "Token 3", "2", est.nextToken() ); assertEquals( "Token 4", "|", est.nextToken() ); assertEquals( "Token 5", "3", est.nextToken() ); assertEquals( "Token 6", "|", est.nextToken() ); assertEquals( "Token 7", "4", est.nextToken() ); assertEquals( "est.hasMoreTokens()", false, est.hasMoreTokens() ); } public void testEmptyString() { EnhancedStringTokenizer est = new EnhancedStringTokenizer( "" ); assertEquals( "est.hasMoreTokens()", false, est.hasMoreTokens() ); try { est.nextToken(); fail(); } catch ( Exception e ) { } } public void testSimpleString() { EnhancedStringTokenizer est = new EnhancedStringTokenizer( "a " ); assertEquals( "Token 1", "a", est.nextToken() ); assertEquals( "Token 2", "", est.nextToken() ); assertEquals( "est.hasMoreTokens()", false, est.hasMoreTokens() ); } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/cli/StreamPumperTest.java000066400000000000000000000200251251077732300332020ustar00rootroot00000000000000/******************************************************************************** * CruiseControl, a Continuous Integration Toolkit * Copyright (c) 2003, ThoughtWorks, Inc. * 651 W Washington Ave. Suite 500 * Chicago, IL 60661 USA * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * + Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * + Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the * names of its contributors may be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ********************************************************************************/ 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 junit.framework.TestCase; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.List; /** * @author Paul Julius */ public class StreamPumperTest extends TestCase { private String lineSeparator; /** * @param testName */ public StreamPumperTest( String testName ) { super( testName ); } /* * @see TestCase#setUp() */ public void setUp() throws Exception { super.setUp(); lineSeparator = System.getProperty( "line.separator" ); } public void testPumping() { String line1 = "line1"; String line2 = "line2"; String lines = line1 + "\n" + line2; ByteArrayInputStream inputStream = new ByteArrayInputStream( lines.getBytes() ); TestConsumer consumer = new TestConsumer(); StreamPumper pumper = new StreamPumper( inputStream, consumer ); new Thread( pumper ).run(); //Check the consumer to see if it got both lines. assertTrue( consumer.wasLineConsumed( line1, 1000 ) ); assertTrue( consumer.wasLineConsumed( line2, 1000 ) ); } public void testPumpingWithPrintWriter() { String inputString = "This a test string"; ByteArrayInputStream bais = new ByteArrayInputStream( inputString.getBytes() ); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter( sw ); StreamPumper pumper = new StreamPumper( bais, pw ); pumper.run(); pumper.flush(); System.out.println( "aaa" + sw.toString() ); assertEquals( "This a test string" + lineSeparator, sw.toString() ); pumper.close(); } public void testPumperReadsInputStreamUntilEndEvenIfConsumerFails() { // the number of bytes generated should surely exceed the read buffer used by the pumper GeneratorInputStream gis = new GeneratorInputStream( 1024 * 1024 * 4 ); StreamPumper pumper = new StreamPumper( gis, new FailingConsumer() ); pumper.run(); assertEquals( "input stream was not fully consumed, producer deadlocks", gis.size, gis.read ); assertTrue( gis.closed ); assertNotNull( pumper.getException() ); } static class GeneratorInputStream extends InputStream { final int size; int read = 0; boolean closed = false; public GeneratorInputStream( int size ) { this.size = size; } public int read() throws IOException { if ( read < size ) { read++; return '\n'; } else { return -1; } } public void close() throws IOException { closed = true; } } static class FailingConsumer implements StreamConsumer { public void consumeLine( String line ) { throw new NullPointerException( "too bad, the consumer is badly implemented..." ); } } /** * Used by the test to track whether a line actually got consumed or not. */ static class TestConsumer implements StreamConsumer { private List lines = new ArrayList(); /** * Checks to see if this consumer consumed a particular line. This method will wait up to timeout number of * milliseconds for the line to get consumed. * * @param testLine Line to test for. * @param timeout Number of milliseconds to wait for the line. * @return true if the line gets consumed, else false. */ public boolean wasLineConsumed( String testLine, long timeout ) { long start = System.currentTimeMillis(); long trialTime = 0; do { if ( lines.contains( testLine ) ) { return true; } // Sleep a bit. try { Thread.sleep( 10 ); } catch ( InterruptedException e ) { // ignoring... } // How long have been waiting for the line? trialTime = System.currentTimeMillis() - start; } while ( trialTime < timeout ); // If we got here, then the line wasn't consumed within the timeout return false; } public void consumeLine( String line ) { lines.add( line ); } } public void testEnabled() { ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( "AB\nCE\nEF".getBytes() ); TestConsumer streamConsumer = new TestConsumer(); StreamPumper streamPumper = new StreamPumper( byteArrayInputStream, streamConsumer ); streamPumper.run(); assertEquals( 3, streamConsumer.lines.size() ); } public void testDisabled() { ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( "AB\nCE\nEF".getBytes() ); TestConsumer streamConsumer = new TestConsumer(); StreamPumper streamPumper = new StreamPumper( byteArrayInputStream, streamConsumer ); streamPumper.disable(); streamPumper.run(); assertEquals( 0, streamConsumer.lines.size() ); } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/cli/shell/000077500000000000000000000000001251077732300301635ustar00rootroot00000000000000BourneShellTest.java000066400000000000000000000167701251077732300340440ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/cli/shellpackage org.codehaus.plexus.util.cli.shell; /* * 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 junit.framework.TestCase; import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.util.cli.Commandline; import java.util.Arrays; import java.util.List; public class BourneShellTest extends TestCase { protected Shell newShell() { return new BourneShell(); } public void testQuoteWorkingDirectoryAndExecutable() { Shell sh = newShell(); sh.setWorkingDirectory( "/usr/local/bin" ); sh.setExecutable( "chmod" ); String executable = StringUtils.join( sh.getShellCommandLine( new String[]{} ).iterator(), " " ); assertEquals( "/bin/sh -c cd '/usr/local/bin' && 'chmod'", executable ); } public void testQuoteWorkingDirectoryAndExecutable_WDPathWithSingleQuotes() { Shell sh = newShell(); sh.setWorkingDirectory( "/usr/local/'something else'" ); sh.setExecutable( "chmod" ); String executable = StringUtils.join( sh.getShellCommandLine( new String[]{} ).iterator(), " " ); assertEquals( "/bin/sh -c cd '/usr/local/'\"'\"'something else'\"'\"'' && 'chmod'", executable ); } public void testQuoteWorkingDirectoryAndExecutable_WDPathWithSingleQuotes_BackslashFileSep() { Shell sh = newShell(); sh.setWorkingDirectory( "\\usr\\local\\'something else'" ); sh.setExecutable( "chmod" ); String executable = StringUtils.join( sh.getShellCommandLine( new String[]{} ).iterator(), " " ); assertEquals( "/bin/sh -c cd '\\usr\\local\\\'\"'\"'something else'\"'\"'' && 'chmod'", executable ); } public void testPreserveSingleQuotesOnArgument() { Shell sh = newShell(); sh.setWorkingDirectory( "/usr/bin" ); sh.setExecutable( "chmod" ); String[] args = { "\'some arg with spaces\'" }; List shellCommandLine = sh.getShellCommandLine( args ); String cli = StringUtils.join( shellCommandLine.iterator(), " " ); System.out.println( cli ); assertTrue( cli.endsWith("''\"'\"'some arg with spaces'\"'\"''")); } public void testAddSingleQuotesOnArgumentWithSpaces() { Shell sh = newShell(); sh.setWorkingDirectory( "/usr/bin" ); sh.setExecutable( "chmod" ); String[] args = { "some arg with spaces" }; List shellCommandLine = sh.getShellCommandLine( args ); String cli = StringUtils.join( shellCommandLine.iterator(), " " ); System.out.println( cli ); assertTrue( cli.endsWith( "\'" + args[0] + "\'" ) ); } public void testEscapeSingleQuotesOnArgument() { Shell sh = newShell(); sh.setWorkingDirectory( "/usr/bin" ); sh.setExecutable( "chmod" ); String[] args = { "arg'withquote" }; List shellCommandLine = sh.getShellCommandLine( args ); String cli = StringUtils.join( shellCommandLine.iterator(), " " ); System.out.println( cli ); assertEquals("cd '/usr/bin' && 'chmod' 'arg'\"'\"'withquote'", shellCommandLine.get(shellCommandLine.size() - 1)); } public void testArgumentsWithsemicolon() { System.out.println( "---- semi colon tests ----" ); Shell sh = newShell(); sh.setWorkingDirectory( "/usr/bin" ); sh.setExecutable( "chmod" ); String[] args = { ";some&argwithunix$chars" }; List shellCommandLine = sh.getShellCommandLine( args ); String cli = StringUtils.join( shellCommandLine.iterator(), " " ); System.out.println( cli ); assertTrue( cli.endsWith( "\'" + args[0] + "\'" ) ); Commandline commandline = new Commandline( newShell() ); commandline.setExecutable( "chmod" ); commandline.getShell().setQuotedArgumentsEnabled( true ); commandline.createArg().setValue( "--password" ); commandline.createArg().setValue( ";password" ); String[] lines = commandline.getShellCommandline(); System.out.println( Arrays.asList( lines ) ); assertEquals( "/bin/sh", lines[0] ); assertEquals( "-c", lines[1] ); assertEquals( "'chmod' '--password' ';password'", lines[2] ); commandline = new Commandline( newShell() ); commandline.setExecutable( "chmod" ); commandline.getShell().setQuotedArgumentsEnabled( true ); commandline.createArg().setValue( "--password" ); commandline.createArg().setValue( ";password" ); lines = commandline.getShellCommandline(); System.out.println( Arrays.asList( lines ) ); assertEquals( "/bin/sh", lines[0] ); assertEquals( "-c", lines[1] ); assertEquals( "'chmod' '--password' ';password'", lines[2] ); commandline = new Commandline( new CmdShell() ); commandline.getShell().setQuotedArgumentsEnabled( true ); commandline.createArg().setValue( "--password" ); commandline.createArg().setValue( ";password" ); lines = commandline.getShellCommandline(); System.out.println( Arrays.asList( lines ) ); assertEquals( "cmd.exe", lines[0] ); assertEquals( "/X", lines[1] ); assertEquals( "/C", lines[2] ); assertEquals( "\"--password ;password\"", lines[3] ); } public void testBourneShellQuotingCharacters() throws Exception { // { ' ', '$', ';', '&', '|', '<', '>', '*', '?', '(', ')' }; // test with values http://steve-parker.org/sh/bourne.shtml Appendix B - Meta-characters and Reserved Words Commandline commandline = new Commandline( newShell() ); commandline.setExecutable( "chmod" ); commandline.getShell().setQuotedArgumentsEnabled( true ); commandline.createArg().setValue( " " ); commandline.createArg().setValue( "|" ); commandline.createArg().setValue( "&&" ); commandline.createArg().setValue( "||" ); commandline.createArg().setValue( ";" ); commandline.createArg().setValue( ";;" ); commandline.createArg().setValue( "&" ); commandline.createArg().setValue( "()" ); commandline.createArg().setValue( "<" ); commandline.createArg().setValue( "<<" ); commandline.createArg().setValue( ">" ); commandline.createArg().setValue( ">>" ); commandline.createArg().setValue( "*" ); commandline.createArg().setValue( "?" ); commandline.createArg().setValue( "[" ); commandline.createArg().setValue( "]" ); commandline.createArg().setValue( "{" ); commandline.createArg().setValue( "}" ); commandline.createArg().setValue( "`" ); String[] lines = commandline.getShellCommandline(); System.out.println( Arrays.asList( lines ) ); assertEquals( "/bin/sh", lines[0] ); assertEquals( "-c", lines[1] ); assertEquals( "'chmod' ' ' '|' '&&' '||' ';' ';;' '&' '()' '<' '<<' '>' '>>' '*' '?' '[' ']' '{' '}' '`'", lines[2] ); } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/dag/000077500000000000000000000000001251077732300270405ustar00rootroot00000000000000CycleDetectedExceptionTest.java000066400000000000000000000023301251077732300350420ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/dagpackage org.codehaus.plexus.util.dag; /* * 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 junit.framework.TestCase; import java.util.ArrayList; import java.util.List; /** * @author Jason van Zyl * @version $Id$ */ public class CycleDetectedExceptionTest extends TestCase { public void testException() { final List cycle = new ArrayList(); cycle.add( "a" ); cycle.add( "b" ); cycle.add( "a" ); final CycleDetectedException e = new CycleDetectedException( "Cycle detected", cycle ); assertEquals( "Cycle detected a --> b --> a", e.getMessage() ); } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/dag/CycleDetectorTest.java000066400000000000000000000121211251077732300332710ustar00rootroot00000000000000package org.codehaus.plexus.util.dag; /* * 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 junit.framework.TestCase; import java.util.List; /** * @author Michal Maczka * @version $Id$ */ public class CycleDetectorTest extends TestCase { public void testCycyleDetection() { // No cycle // // a --> b --->c // try { final DAG dag1 = new DAG(); dag1.addEdge( "a", "b" ); dag1.addEdge( "b", "c" ); } catch ( CycleDetectedException e ) { fail( "Cycle should not be detected" ); } // // a --> b --->c // ^ | // | | // -----------| try { final DAG dag2 = new DAG(); dag2.addEdge( "a", "b" ); dag2.addEdge( "b", "c" ); dag2.addEdge( "c", "a" ); fail( "Cycle should be detected" ); } catch ( CycleDetectedException e ) { final List cycle = e.getCycle(); assertNotNull( "Cycle should be not null", cycle ); assertTrue( "Cycle contains 'a'", cycle.contains( "a" ) ); assertTrue( "Cycle contains 'b'", cycle.contains( "b" ) ); assertTrue( "Cycle contains 'c'", cycle.contains( "c" ) ); } // | --> c // a --> b // | | --> d // ---------> try { final DAG dag3 = new DAG(); dag3.addEdge( "a", "b" ); dag3.addEdge( "b", "c" ); dag3.addEdge( "b", "d" ); dag3.addEdge( "a", "d" ); } catch ( CycleDetectedException e ) { fail( "Cycle should not be detected" ); } // ------------ // | | // V | --> c // a --> b // | | --> d // ---------> try { final DAG dag4 = new DAG(); dag4.addEdge( "a", "b" ); dag4.addEdge( "b", "c" ); dag4.addEdge( "b", "d" ); dag4.addEdge( "a", "d" ); dag4.addEdge( "c", "a" ); fail( "Cycle should be detected" ); } catch ( CycleDetectedException e ) { final List cycle = e.getCycle(); assertNotNull( "Cycle should be not null", cycle ); assertEquals( "Cycle contains 'a'", "a", ( String ) cycle.get( 0 ) ); assertEquals( "Cycle contains 'b'", "b", cycle.get( 1 ) ); assertEquals( "Cycle contains 'c'", "c", cycle.get( 2 ) ); assertEquals( "Cycle contains 'a'", "a", ( String ) cycle.get( 3 ) ); } // f --> g --> h // | // | // a --> b ---> c --> d // ^ | // | V // ------------ e final DAG dag5 = new DAG(); try { dag5.addEdge( "a", "b" ); dag5.addEdge( "b", "c" ); dag5.addEdge( "b", "f" ); dag5.addEdge( "f", "g" ); dag5.addEdge( "g", "h" ); dag5.addEdge( "c", "d" ); dag5.addEdge( "d", "e" ); dag5.addEdge( "e", "b" ); fail( "Cycle should be detected" ); } catch ( CycleDetectedException e ) { final List cycle = e.getCycle(); assertNotNull( "Cycle should be not null", cycle ); assertEquals( "Cycle contains 5 elements", 5, cycle.size() ); assertEquals( "Cycle contains 'b'", "b", ( String ) cycle.get( 0 ) ); assertEquals( "Cycle contains 'c'", "c", cycle.get( 1 ) ); assertEquals( "Cycle contains 'd'", "d", cycle.get( 2 ) ); assertEquals( "Cycle contains 'e'", "e", ( String ) cycle.get( 3 ) ); assertEquals( "Cycle contains 'b'", "b", ( String ) cycle.get( 4 ) ); assertTrue( "Edge exixst", dag5.hasEdge( "a", "b" ) ); assertTrue( "Edge exixst", dag5.hasEdge( "b", "c" ) ); assertTrue( "Edge exixst", dag5.hasEdge( "b", "f" ) ); assertTrue( "Edge exixst", dag5.hasEdge( "f", "g" ) ); assertTrue( "Edge exixst", dag5.hasEdge( "g", "h" ) ); assertTrue( "Edge exixst", dag5.hasEdge( "c", "d" ) ); assertTrue( "Edge exixst", dag5.hasEdge( "d", "e" ) ); assertFalse( dag5.hasEdge( "e", "b" ) ); } } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/dag/DAGTest.java000066400000000000000000000105031251077732300311350ustar00rootroot00000000000000package org.codehaus.plexus.util.dag; /* * 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 junit.framework.TestCase; import java.util.ArrayList; import java.util.List; import java.util.Set; /** * @author Michal Maczka * @version $Id$ */ public class DAGTest extends TestCase { public void testDAG() throws CycleDetectedException { final DAG dag = new DAG(); dag.addVertex( "a" ); assertEquals( 1, dag.getVerticies().size() ); assertEquals( "a", dag.getVertex( "a" ).getLabel() ); dag.addVertex( "a" ); assertEquals( 1, dag.getVerticies().size() ); assertEquals( "a", dag.getVertex( "a" ).getLabel() ); dag.addVertex( "b" ); assertEquals( 2, dag.getVerticies().size() ); assertFalse( dag.hasEdge( "a", "b" ) ); assertFalse( dag.hasEdge( "b", "a" ) ); final Vertex a = dag.getVertex( "a" ); final Vertex b = dag.getVertex( "b" ); assertEquals( "a", a.getLabel() ); assertEquals( "b", b.getLabel() ); dag.addEdge( "a", "b" ); assertTrue( a.getChildren().contains( b ) ); assertTrue( b.getParents().contains( a ) ); assertTrue( dag.hasEdge( "a", "b" ) ); assertFalse( dag.hasEdge( "b", "a" ) ); dag.addEdge( "c", "d" ); assertEquals( 4, dag.getVerticies().size() ); final Vertex c = dag.getVertex( "c" ); final Vertex d = dag.getVertex( "d" ); assertEquals( "a", a.getLabel() ); assertEquals( "b", b.getLabel() ); assertEquals( "c", c.getLabel() ); assertEquals( "d", d.getLabel() ); assertFalse( dag.hasEdge( "b", "a" ) ); assertFalse( dag.hasEdge( "a", "c" ) ); assertFalse( dag.hasEdge( "a", "d" ) ); assertTrue( dag.hasEdge( "c", "d" ) ); assertFalse( dag.hasEdge( "d", "c" ) ); final Set labels = dag.getLabels(); assertEquals( 4, labels.size() ); assertTrue( labels.contains( "a" ) ); assertTrue( labels.contains( "b" ) ); assertTrue( labels.contains( "c" ) ); assertTrue( labels.contains( "d" ) ); dag.addEdge( "a", "d" ); assertTrue( a.getChildren().contains( d ) ); assertTrue( d.getParents().contains( a ) ); // "b" and "d" are children of "a" assertEquals( 2, a.getChildren().size() ); assertTrue( a.getChildLabels().contains( "b" ) ); assertTrue( a.getChildLabels().contains( "d" ) ); // "a" and "c" are parents of "d" assertEquals( 2, d.getParents().size() ); assertTrue( d.getParentLabels().contains( "a" ) ); assertTrue( d.getParentLabels().contains( "c" ) ); } public void testGetPredessors() throws CycleDetectedException { final DAG dag = new DAG(); dag.addEdge( "a", "b" ); // // a --> b --> c --> e // | | | // | V V // --> d <-- f --> g // result d, g, f, c, b, a //force order of nodes dag.addVertex( "c" ); dag.addVertex( "d" ); dag.addEdge( "a", "b" ); dag.addEdge( "b", "c" ); dag.addEdge( "b", "d" ); dag.addEdge( "c", "d" ); dag.addEdge( "c", "e" ); dag.addEdge( "f", "d" ); dag.addEdge( "e", "f" ); dag.addEdge( "f", "g" ); final List actual = dag.getSuccessorLabels( "b" ); final List expected = new ArrayList(); expected.add( "d" ); expected.add( "g" ); expected.add( "f" ); expected.add( "e" ); expected.add( "c" ); expected.add( "b" ); assertEquals( expected, actual ); } } TopologicalSorterTest.java000066400000000000000000000102701251077732300341370ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/dagpackage org.codehaus.plexus.util.dag; /* * 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 junit.framework.TestCase; import java.util.ArrayList; import java.util.List; /** * @author Michal Maczka * @version $Id$ */ public class TopologicalSorterTest extends TestCase { public void testDfs() throws CycleDetectedException { // a --> b --->c // // result a,b,c final DAG dag1 = new DAG(); dag1.addEdge( "a", "b" ); dag1.addEdge( "b", "c" ); final List expected1 = new ArrayList(); expected1.add( "c" ); expected1.add( "b" ); expected1.add( "a" ); final List actual1 = TopologicalSorter.sort( dag1 ); assertEquals( "Order is different then expected", expected1, actual1 ); // // a <-- b <---c // // result c, b, a final DAG dag2 = new DAG(); dag2.addVertex( "a" ); dag2.addVertex( "b" ); dag2.addVertex( "c" ); dag2.addEdge( "b", "a" ); dag2.addEdge( "c", "b" ); final List expected2 = new ArrayList(); expected2.add( "a" ); expected2.add( "b" ); expected2.add( "c" ); final List actual2 = TopologicalSorter.sort( dag2 ); assertEquals( "Order is different then expected", expected2, actual2 ); // // a --> b --> c --> e // | | | // | V V // --> d <-- f --> g // result d, g, f, c, b, a final DAG dag3 = new DAG(); // force order of nodes in the graph dag3.addVertex( "a" ); dag3.addVertex( "b" ); dag3.addVertex( "c" ); dag3.addVertex( "d" ); dag3.addVertex( "e" ); dag3.addVertex( "f" ); dag3.addEdge( "a", "b" ); dag3.addEdge( "b", "c" ); dag3.addEdge( "b", "d" ); dag3.addEdge( "c", "d" ); dag3.addEdge( "c", "e" ); dag3.addEdge( "f", "d" ); dag3.addEdge( "e", "f" ); dag3.addEdge( "f", "g" ); final List expected3 = new ArrayList(); expected3.add( "d" ); expected3.add( "g" ); expected3.add( "f" ); expected3.add( "e" ); expected3.add( "c" ); expected3.add( "b" ); expected3.add( "a" ); final List actual3 = TopologicalSorter.sort( dag3 ); assertEquals( "Order is different then expected", expected3, actual3 ); // // a --> b --> c --> e // | | | // | V V // --> d <-- f // result d, f, e, c, b, a final DAG dag4 = new DAG(); // force order of nodes in the graph dag4.addVertex( "f" ); dag4.addVertex( "e" ); dag4.addVertex( "d" ); dag4.addVertex( "c" ); dag4.addVertex( "a" ); dag4.addVertex( "b" ); dag4.addEdge( "a", "b" ); dag4.addEdge( "b", "c" ); dag4.addEdge( "b", "d" ); dag4.addEdge( "c", "d" ); dag4.addEdge( "c", "e" ); dag4.addEdge( "f", "d" ); dag4.addEdge( "e", "f" ); final List expected4 = new ArrayList(); expected4.add( "d" ); expected4.add( "f" ); expected4.add( "e" ); expected4.add( "c" ); expected4.add( "b" ); expected4.add( "a" ); final List actual4 = TopologicalSorter.sort( dag4 ); assertEquals( "Order is different then expected", expected4, actual4 ); } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/dag/VertexTest.java000066400000000000000000000026711251077732300320260ustar00rootroot00000000000000package org.codehaus.plexus.util.dag; /* * 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 junit.framework.TestCase; /** * @author Michal Maczka * @version $Id$ */ public class VertexTest extends TestCase { public void testVertex() { final Vertex vertex1 = new Vertex( "a" ); assertEquals( "a", vertex1.getLabel() ); assertEquals( 0, vertex1.getChildren().size() ); assertEquals( 0, vertex1.getChildLabels().size() ); final Vertex vertex2 = new Vertex( "b" ); assertEquals( "b", vertex2.getLabel() ); vertex1.addEdgeTo( vertex2 ); assertEquals( 1, vertex1.getChildren().size() ); assertEquals( 1, vertex1.getChildLabels().size() ); assertEquals( vertex2, vertex1.getChildren().get( 0 ) ); assertEquals( "b", vertex1.getChildLabels().get( 0 ) ); } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/introspection/000077500000000000000000000000001251077732300312055ustar00rootroot00000000000000ReflectionValueExtractorTest.java000066400000000000000000000365141251077732300376250ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/introspectionpackage org.codehaus.plexus.util.introspection; /* * 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.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import junit.framework.Assert; import junit.framework.TestCase; import org.apache.maven.plugin.testing.stubs.MavenProjectStub; /** * @author Jason van Zyl * @version $Id$ */ public class ReflectionValueExtractorTest extends TestCase { private Project project; protected void setUp() throws Exception { super.setUp(); Dependency dependency1 = new Dependency(); dependency1.setArtifactId( "dep1" ); Dependency dependency2 = new Dependency(); dependency2.setArtifactId( "dep2" ); project = new Project(); project.setModelVersion( "4.0.0" ); project.setGroupId( "org.apache.maven" ); project.setArtifactId( "maven-core" ); project.setName( "Maven" ); project.setVersion( "2.0-SNAPSHOT" ); project.setScm( new Scm() ); project.getScm().setConnection( "scm-connection" ); project.addDependency( dependency1 ); project.addDependency( dependency2 ); project.setBuild( new Build() ); // Build up an artifactMap project.addArtifact( new Artifact("g0","a0","v0","e0","c0") ); project.addArtifact( new Artifact("g1","a1","v1","e1","c1") ); project.addArtifact( new Artifact("g2","a2","v2","e2","c2") ); } public void testValueExtraction() throws Exception { // ---------------------------------------------------------------------- // Top level values // ---------------------------------------------------------------------- assertEquals( "4.0.0", ReflectionValueExtractor.evaluate( "project.modelVersion", project ) ); assertEquals( "org.apache.maven", ReflectionValueExtractor.evaluate( "project.groupId", project ) ); assertEquals( "maven-core", ReflectionValueExtractor.evaluate( "project.artifactId", project ) ); assertEquals( "Maven", ReflectionValueExtractor.evaluate( "project.name", project ) ); assertEquals( "2.0-SNAPSHOT", ReflectionValueExtractor.evaluate( "project.version", project ) ); // ---------------------------------------------------------------------- // SCM // ---------------------------------------------------------------------- assertEquals( "scm-connection", ReflectionValueExtractor.evaluate( "project.scm.connection", project ) ); // ---------------------------------------------------------------------- // Dependencies // ---------------------------------------------------------------------- List dependencies = (List) ReflectionValueExtractor.evaluate( "project.dependencies", project ); Assert.assertNotNull( dependencies ); Assert.assertEquals( 2, dependencies.size() ); // ---------------------------------------------------------------------- // Dependencies - using index notation // ---------------------------------------------------------------------- // List Dependency dependency = (Dependency) ReflectionValueExtractor.evaluate( "project.dependencies[0]", project ); Assert.assertNotNull( dependency ); Assert.assertTrue( "dep1".equals( dependency.getArtifactId() ) ); String artifactId = (String) ReflectionValueExtractor.evaluate( "project.dependencies[1].artifactId", project ); Assert.assertTrue( "dep2".equals( artifactId ) ); // Array dependency = (Dependency) ReflectionValueExtractor.evaluate( "project.dependenciesAsArray[0]", project ); Assert.assertNotNull( dependency ); Assert.assertTrue( "dep1".equals( dependency.getArtifactId() ) ); artifactId = (String) ReflectionValueExtractor.evaluate( "project.dependenciesAsArray[1].artifactId", project ); Assert.assertTrue( "dep2".equals( artifactId ) ); // Map dependency = (Dependency) ReflectionValueExtractor.evaluate( "project.dependenciesAsMap(dep1)", project ); Assert.assertNotNull( dependency ); Assert.assertTrue( "dep1".equals( dependency.getArtifactId() ) ); artifactId = (String) ReflectionValueExtractor.evaluate( "project.dependenciesAsMap(dep2).artifactId", project ); Assert.assertTrue( "dep2".equals( artifactId ) ); // ---------------------------------------------------------------------- // Build // ---------------------------------------------------------------------- Build build = (Build) ReflectionValueExtractor.evaluate( "project.build", project ); Assert.assertNotNull( build ); } public void testValueExtractorWithAInvalidExpression() throws Exception { Assert.assertNull( ReflectionValueExtractor.evaluate( "project.foo", project ) ); Assert.assertNull( ReflectionValueExtractor.evaluate( "project.dependencies[10]", project ) ); Assert.assertNull( ReflectionValueExtractor.evaluate( "project.dependencies[0].foo", project ) ); } public void testMappedDottedKey() throws Exception { Map map = new HashMap(); map.put( "a.b", "a.b-value" ); Assert.assertEquals( "a.b-value", ReflectionValueExtractor.evaluate( "h.value(a.b)", new ValueHolder( map ) ) ); } public void testIndexedMapped() throws Exception { Map map = new HashMap(); map.put( "a", "a-value" ); List list = new ArrayList(); list.add( map ); Assert.assertEquals( "a-value", ReflectionValueExtractor.evaluate( "h.value[0](a)", new ValueHolder( list ) ) ); } public void testMappedIndexed() throws Exception { List list = new ArrayList(); list.add( "a-value" ); Map map = new HashMap(); map.put( "a", list ); Assert.assertEquals( "a-value", ReflectionValueExtractor.evaluate( "h.value(a)[0]", new ValueHolder( map ) ) ); } public void testMappedMissingDot() throws Exception { Map map = new HashMap(); map.put( "a", new ValueHolder( "a-value" ) ); Assert.assertNull( ReflectionValueExtractor.evaluate( "h.value(a)value", new ValueHolder( map ) ) ); } public void testIndexedMissingDot() throws Exception { List list = new ArrayList(); list.add( new ValueHolder( "a-value" ) ); Assert.assertNull( ReflectionValueExtractor.evaluate( "h.value[0]value", new ValueHolder( list ) ) ); } public void testDotDot() throws Exception { Assert.assertNull( ReflectionValueExtractor.evaluate( "h..value", new ValueHolder( "value" ) ) ); } public void testBadIndexedSyntax() throws Exception { List list = new ArrayList(); list.add( "a-value" ); Object value = new ValueHolder( list ); Assert.assertNull( ReflectionValueExtractor.evaluate( "h.value[", value ) ); Assert.assertNull( ReflectionValueExtractor.evaluate( "h.value[]", value ) ); Assert.assertNull( ReflectionValueExtractor.evaluate( "h.value[a]", value ) ); Assert.assertNull( ReflectionValueExtractor.evaluate( "h.value[0", value ) ); Assert.assertNull( ReflectionValueExtractor.evaluate( "h.value[0)", value ) ); Assert.assertNull( ReflectionValueExtractor.evaluate( "h.value[-1]", value ) ); } public void testBadMappedSyntax() throws Exception { Map map = new HashMap(); map.put( "a", "a-value" ); Object value = new ValueHolder( map ); Assert.assertNull( ReflectionValueExtractor.evaluate( "h.value(", value ) ); Assert.assertNull( ReflectionValueExtractor.evaluate( "h.value()", value ) ); Assert.assertNull( ReflectionValueExtractor.evaluate( "h.value(a", value ) ); Assert.assertNull( ReflectionValueExtractor.evaluate( "h.value(a]", value ) ); } public void testIllegalIndexedType() throws Exception { try { ReflectionValueExtractor.evaluate( "h.value[1]", new ValueHolder( "string" ) ); } catch ( Exception e ) { // TODO assert exception message } } public void testIllegalMappedType() throws Exception { try { ReflectionValueExtractor.evaluate( "h.value(key)", new ValueHolder( "string" ) ); } catch ( Exception e ) { // TODO assert exception message } } public void testTrimRootToken() throws Exception { Assert.assertNull( ReflectionValueExtractor.evaluate( "project", project, true ) ); } public void testArtifactMap() throws Exception { assertEquals( "g0", ((Artifact) ReflectionValueExtractor.evaluate( "project.artifactMap(g0:a0:c0)", project )).getGroupId() ); assertEquals( "a1", ((Artifact) ReflectionValueExtractor.evaluate( "project.artifactMap(g1:a1:c1)", project )).getArtifactId() ); assertEquals( "c2", ((Artifact) ReflectionValueExtractor.evaluate( "project.artifactMap(g2:a2:c2)", project )).getClassifier() ); } public static class Artifact { private String groupId; private String artifactId; private String version; private String extension; private String classifier; public Artifact( String groupId, String artifactId, String version, String extension, String classifier ) { this.groupId = groupId; this.artifactId = artifactId; this.version = version; this.extension = extension; this.classifier = classifier; } public String getGroupId() { return groupId; } public void setGroupId( String groupId ) { this.groupId = groupId; } public String getArtifactId() { return artifactId; } public void setArtifactId( String artifactId ) { this.artifactId = artifactId; } public String getVersion() { return version; } public void setVersion( String version ) { this.version = version; } public String getExtension() { return extension; } public void setExtension( String extension ) { this.extension = extension; } public String getClassifier() { return classifier; } public void setClassifier( String classifier ) { this.classifier = classifier; } } public static class Project { private String modelVersion; private String groupId; private Scm scm; private List dependencies = new ArrayList(); private Build build; private String artifactId; private String name; private String version; private Map artifactMap = new HashMap(); public void setModelVersion( String modelVersion ) { this.modelVersion = modelVersion; } public void setGroupId( String groupId ) { this.groupId = groupId; } public void setScm( Scm scm ) { this.scm = scm; } public void addDependency( Dependency dependency ) { this.dependencies.add( dependency ); } public void setBuild( Build build ) { this.build = build; } public void setArtifactId( String artifactId ) { this.artifactId = artifactId; } public void setName( String name ) { this.name = name; } public void setVersion( String version ) { this.version = version; } public Scm getScm() { return scm; } public String getModelVersion() { return modelVersion; } public String getGroupId() { return groupId; } public List getDependencies() { return dependencies; } public Build getBuild() { return build; } public String getArtifactId() { return artifactId; } public String getName() { return name; } public String getVersion() { return version; } public Dependency[] getDependenciesAsArray() { return (Dependency[]) getDependencies().toArray( new Dependency[0] ); } public Map getDependenciesAsMap() { Map ret = new HashMap(); for ( Object o : getDependencies() ) { Dependency dep = (Dependency) o; ret.put( dep.getArtifactId(), dep ); } return ret; } // ${project.artifactMap(g:a:v)} public void addArtifact(Artifact a) { artifactMap.put( a.getGroupId() + ":" + a.getArtifactId() + ":" + a.getClassifier(), a ); } public Map getArtifactMap() { return artifactMap; } } public static class Build { } public static class Dependency { private String artifactId; public String getArtifactId() { return artifactId; } public void setArtifactId( String id ) { artifactId = id; } } public static class Scm { private String connection; public void setConnection( String connection ) { this.connection = connection; } public String getConnection() { return connection; } } public static class ValueHolder { private final Object value; public ValueHolder( Object value ) { this.value = value; } public Object getValue() { return value; } } public void testRootPropertyRegression() throws Exception { MavenProjectStub project = new MavenProjectStub( ); project.setDescription( "c:\\\\org\\apache\\test" ); Object evalued = ReflectionValueExtractor.evaluate( "description", project ); assertNotNull( evalued); } }plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/reflection/000077500000000000000000000000001251077732300304375ustar00rootroot00000000000000ReflectorTest.java000066400000000000000000000041071251077732300340120ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/reflectionpackage org.codehaus.plexus.util.reflection; /* * 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 junit.framework.TestCase; /** * @author Jörg Schaible * @version $Id$ */ public class ReflectorTest extends TestCase { private Project project; private Reflector reflector; protected void setUp() throws Exception { super.setUp(); project = new Project(); project.setModelVersion( "1.0.0" ); project.setVersion( "42" ); reflector = new Reflector(); } public void testObjectPropertyFromName() throws Exception { assertEquals( "1.0.0", reflector.getObjectProperty( project, "modelVersion" ) ); } public void testObjectPropertyFromBean() throws Exception { assertEquals( "Foo", reflector.getObjectProperty( project, "name" ) ); } public void testObjectPropertyFromField() throws Exception { assertEquals( "42", reflector.getObjectProperty( project, "version" ) ); } public static class Project { private String model; private String name; private String version; public void setModelVersion( String modelVersion ) { this.model = modelVersion; } public void setVersion( String version ) { this.version = version; } public String modelVersion() { return model; } public String getName() { return "Foo"; } } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/xml/000077500000000000000000000000001251077732300271055ustar00rootroot00000000000000PrettyPrintXMLWriterTest.java000066400000000000000000000144431251077732300346210ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/xmlpackage org.codehaus.plexus.util.xml; /* * 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.StringWriter; import javax.swing.text.html.HTML.Tag; import org.codehaus.plexus.util.StringUtils; import junit.framework.TestCase; /** * Test of {@link PrettyPrintXMLWriter} * * @author Vincent Siveton * @version $Id$ */ public class PrettyPrintXMLWriterTest extends TestCase { StringWriter w; PrettyPrintXMLWriter writer; /** {@inheritDoc} */ protected void setUp() throws Exception { super.setUp(); initWriter(); } /** {@inheritDoc} */ protected void tearDown() throws Exception { super.tearDown(); writer = null; w = null; } private void initWriter() { w = new StringWriter(); writer = new PrettyPrintXMLWriter( w ); } public void testDefaultPrettyPrintXMLWriter() { writer.startElement( Tag.HTML.toString() ); writeXhtmlHead( writer ); writeXhtmlBody( writer ); writer.endElement(); // Tag.HTML assertEquals( expectedResult( PrettyPrintXMLWriter.LS ), w.toString() ); } public void testPrettyPrintXMLWriterWithGivenLineSeparator() { writer.setLineSeparator( "\n" ); writer.startElement( Tag.HTML.toString() ); writeXhtmlHead( writer ); writeXhtmlBody( writer ); writer.endElement(); // Tag.HTML assertEquals( expectedResult( "\n" ), w.toString() ); } public void testPrettyPrintXMLWriterWithGivenLineIndenter() { writer.setLineIndenter( " " ); writer.startElement( Tag.HTML.toString() ); writeXhtmlHead( writer ); writeXhtmlBody( writer ); writer.endElement(); // Tag.HTML assertEquals( expectedResult( " ", PrettyPrintXMLWriter.LS ), w.toString() ); } public void testEscapeXmlAttribute() { // Windows writer.startElement( Tag.DIV.toString() ); writer.addAttribute( "class", "sect\r\nion" ); writer.endElement(); // Tag.DIV assertEquals( "
            ", w.toString() ); // Mac initWriter(); writer.startElement( Tag.DIV.toString() ); writer.addAttribute( "class", "sect\rion" ); writer.endElement(); // Tag.DIV assertEquals( "
            ", w.toString() ); // Unix initWriter(); writer.startElement( Tag.DIV.toString() ); writer.addAttribute( "class", "sect\nion" ); writer.endElement(); // Tag.DIV assertEquals( "
            ", w.toString() ); } private void writeXhtmlHead( XMLWriter writer ) { writer.startElement( Tag.HEAD.toString() ); writer.startElement( Tag.TITLE.toString() ); writer.writeText( "title" ); writer.endElement(); // Tag.TITLE writer.startElement( Tag.META.toString() ); writer.addAttribute( "name", "author" ); writer.addAttribute( "content", "Author" ); writer.endElement(); // Tag.META writer.startElement( Tag.META.toString() ); writer.addAttribute( "name", "date" ); writer.addAttribute( "content", "Date" ); writer.endElement(); // Tag.META writer.endElement(); // Tag.HEAD } private void writeXhtmlBody( XMLWriter writer ) { writer.startElement( Tag.BODY.toString() ); writer.startElement( Tag.P.toString() ); writer.writeText( "Paragraph 1, line 1. Paragraph 1, line 2." ); writer.endElement(); // Tag.P writer.startElement( Tag.DIV.toString() ); writer.addAttribute( "class", "section" ); writer.startElement( Tag.H2.toString() ); writer.writeText( "Section title" ); writer.endElement(); // Tag.H2 writer.endElement(); // Tag.DIV writer.endElement(); // Tag.BODY } private String expectedResult( String lineSeparator ) { return expectedResult( " ", lineSeparator ); } private String expectedResult( String lineIndenter, String lineSeparator ) { StringBuilder expected = new StringBuilder(); expected.append( "" ).append( lineSeparator ); expected.append( StringUtils.repeat( lineIndenter, 1 ) ).append( "" ).append( lineSeparator ); expected.append( StringUtils.repeat( lineIndenter, 2 ) ).append( "title" ) .append( lineSeparator ); expected.append( StringUtils.repeat( lineIndenter, 2 ) ) .append( "" ).append( lineSeparator ); expected.append( StringUtils.repeat( lineIndenter, 2 ) ).append( "" ) .append( lineSeparator ); expected.append( StringUtils.repeat( lineIndenter, 1 ) ).append( "" ).append( lineSeparator ); expected.append( StringUtils.repeat( lineIndenter, 1 ) ).append( "" ).append( lineSeparator ); expected.append( StringUtils.repeat( lineIndenter, 2 ) ) .append( "

            Paragraph 1, line 1. Paragraph 1, line 2.

            " ).append( lineSeparator ); expected.append( StringUtils.repeat( lineIndenter, 2 ) ).append( "
            " ) .append( lineSeparator ); expected.append( StringUtils.repeat( lineIndenter, 3 ) ).append( "

            Section title

            " ) .append( lineSeparator ); expected.append( StringUtils.repeat( lineIndenter, 2 ) ).append( "
            " ).append( lineSeparator ); expected.append( StringUtils.repeat( lineIndenter, 1 ) ).append( "" ).append( lineSeparator ); expected.append( "" ); return expected.toString(); } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/xml/XmlStreamReaderTest.java000066400000000000000000000156001251077732300336510ustar00rootroot00000000000000package org.codehaus.plexus.util.xml; /* * 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.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.SequenceInputStream; import org.codehaus.plexus.util.IOUtil; import junit.framework.ComparisonFailure; import junit.framework.TestCase; public class XmlStreamReaderTest extends TestCase { /** french */ private static final String TEXT_LATIN1 = "eacute: \u00E9"; /** greek */ private static final String TEXT_LATIN7 = "alpha: \u03B1"; /** euro support */ private static final String TEXT_LATIN15 = "euro: \u20AC"; /** japanese */ private static final String TEXT_EUC_JP = "hiragana A: \u3042"; /** Unicode: support everything */ private static final String TEXT_UNICODE = TEXT_LATIN1 + ", " + TEXT_LATIN7 + ", " + TEXT_LATIN15 + ", " + TEXT_EUC_JP; /** see http://unicode.org/faq/utf_bom.html#BOM */ private static final byte[] BOM_UTF8 = { (byte)0xEF, (byte)0xBB, (byte)0xBF }; private static final byte[] BOM_UTF16BE = { (byte)0xFE, (byte)0xFF }; private static final byte[] BOM_UTF16LE = { (byte)0xFF, (byte)0xFE }; private static final byte[] BOM_UTF32BE = { (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0xFE }; private static final byte[] BOM_UTF32LE = { (byte)0xFF, (byte)0xFE, (byte)0x00, (byte)0x00 }; private static String createXmlContent( String text, String encoding ) { String xmlDecl = ""; if ( encoding != null ) { xmlDecl = ""; } String xml = xmlDecl + "\n" + text + ""; return xml; } private static void checkXmlContent( String xml, String encoding ) throws IOException { checkXmlContent( xml, encoding, null ); } private static void checkXmlContent( String xml, String encoding, byte... bom ) throws IOException { byte[] xmlContent = xml.getBytes( encoding ); InputStream in = new ByteArrayInputStream( xmlContent ); if ( bom != null ) { in = new SequenceInputStream( new ByteArrayInputStream( bom ), in ); } XmlStreamReader reader = new XmlStreamReader( in ); assertEquals( encoding, reader.getEncoding() ); String result = IOUtil.toString( reader ); assertEquals( xml, result ); } private static void checkXmlStreamReader( String text, String encoding, String effectiveEncoding ) throws IOException { checkXmlStreamReader( text, encoding, effectiveEncoding, null ); } private static void checkXmlStreamReader( String text, String encoding ) throws IOException { checkXmlStreamReader( text, encoding, encoding, null ); } private static void checkXmlStreamReader( String text, String encoding, byte... bom ) throws IOException { checkXmlStreamReader( text, encoding, encoding, bom ); } private static void checkXmlStreamReader( String text, String encoding, String effectiveEncoding, byte... bom ) throws IOException { String xml = createXmlContent( text, encoding ); checkXmlContent( xml, effectiveEncoding, bom ); } public void testNoXmlHeader() throws IOException { String xml = "text with no XML header"; checkXmlContent( xml, "UTF-8" ); checkXmlContent( xml, "UTF-8", BOM_UTF8 ); } public void testDefaultEncoding() throws IOException { checkXmlStreamReader( TEXT_UNICODE, null, "UTF-8" ); checkXmlStreamReader( TEXT_UNICODE, null, "UTF-8", BOM_UTF8 ); } public void testUTF8Encoding() throws IOException { checkXmlStreamReader( TEXT_UNICODE, "UTF-8" ); checkXmlStreamReader( TEXT_UNICODE, "UTF-8", BOM_UTF8 ); } public void testUTF16Encoding() throws IOException { checkXmlStreamReader( TEXT_UNICODE, "UTF-16", "UTF-16BE", null ); checkXmlStreamReader( TEXT_UNICODE, "UTF-16", "UTF-16LE", BOM_UTF16LE ); checkXmlStreamReader( TEXT_UNICODE, "UTF-16", "UTF-16BE", BOM_UTF16BE ); } public void testUTF16BEEncoding() throws IOException { checkXmlStreamReader( TEXT_UNICODE, "UTF-16BE" ); } public void testUTF16LEEncoding() throws IOException { checkXmlStreamReader( TEXT_UNICODE, "UTF-16LE" ); } public void testLatin1Encoding() throws IOException { checkXmlStreamReader( TEXT_LATIN1, "ISO-8859-1" ); } public void testLatin7Encoding() throws IOException { checkXmlStreamReader( TEXT_LATIN7, "ISO-8859-7" ); } public void testLatin15Encoding() throws IOException { checkXmlStreamReader( TEXT_LATIN15, "ISO-8859-15" ); } public void testEUC_JPEncoding() throws IOException { checkXmlStreamReader( TEXT_EUC_JP, "EUC-JP" ); } public void testEBCDICEncoding() throws IOException { checkXmlStreamReader( "simple text in EBCDIC", "CP1047" ); } public void testInappropriateEncoding() throws IOException { try { checkXmlStreamReader( TEXT_UNICODE, "ISO-8859-2" ); fail( "Check should have failed, since some characters are not available in the specified encoding" ); } catch ( ComparisonFailure cf ) { // expected failure, since the encoding does not contain some characters } } public void testEncodingAttribute() throws IOException { String xml = ""; checkXmlContent( xml, "US-ASCII" ); xml = ""; checkXmlContent( xml, "US-ASCII" ); xml = ""; checkXmlContent( xml, "UTF-8" ); xml = "\n"; checkXmlContent( xml, "US-ASCII" ); xml = "\n"; checkXmlContent( xml, "UTF-8" ); xml = ""; checkXmlContent( xml, "UTF-8" ); } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/xml/XmlStreamWriterTest.java000066400000000000000000000101201251077732300337130ustar00rootroot00000000000000package org.codehaus.plexus.util.xml; /* * 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.ByteArrayOutputStream; import java.io.IOException; import junit.framework.TestCase; public class XmlStreamWriterTest extends TestCase { /** french */ private static final String TEXT_LATIN1 = "eacute: \u00E9"; /** greek */ private static final String TEXT_LATIN7 = "alpha: \u03B1"; /** euro support */ private static final String TEXT_LATIN15 = "euro: \u20AC"; /** japanese */ private static final String TEXT_EUC_JP = "hiragana A: \u3042"; /** Unicode: support everything */ private static final String TEXT_UNICODE = TEXT_LATIN1 + ", " + TEXT_LATIN7 + ", " + TEXT_LATIN15 + ", " + TEXT_EUC_JP; private static String createXmlContent( String text, String encoding ) { String xmlDecl = ""; if ( encoding != null ) { xmlDecl = ""; } String xml = xmlDecl + "\n" + text + ""; return xml; } private static void checkXmlContent( String xml, String encoding ) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); XmlStreamWriter writer = new XmlStreamWriter( out ); writer.write( xml ); writer.close(); byte[] xmlContent = out.toByteArray(); String result = new String( xmlContent, encoding ); assertEquals( xml, result ); } private static void checkXmlWriter( String text, String encoding ) throws IOException { String xml = createXmlContent( text, encoding ); String effectiveEncoding = ( encoding == null ) ? "UTF-8" : encoding; checkXmlContent( xml, effectiveEncoding ); } public void testNoXmlHeader() throws IOException { String xml = "text with no XML header"; checkXmlContent( xml, "UTF-8" ); } public void testEmpty() throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); XmlStreamWriter writer = new XmlStreamWriter( out ); writer.flush(); writer.write( "" ); writer.flush(); writer.write( "." ); writer.flush(); writer.close(); } public void testDefaultEncoding() throws IOException { checkXmlWriter( TEXT_UNICODE, null ); } public void testUTF8Encoding() throws IOException { checkXmlWriter( TEXT_UNICODE, "UTF-8" ); } public void testUTF16Encoding() throws IOException { checkXmlWriter( TEXT_UNICODE, "UTF-16" ); } public void testUTF16BEEncoding() throws IOException { checkXmlWriter( TEXT_UNICODE, "UTF-16BE" ); } public void testUTF16LEEncoding() throws IOException { checkXmlWriter( TEXT_UNICODE, "UTF-16LE" ); } public void testLatin1Encoding() throws IOException { checkXmlWriter( TEXT_LATIN1, "ISO-8859-1" ); } public void testLatin7Encoding() throws IOException { checkXmlWriter( TEXT_LATIN7, "ISO-8859-7" ); } public void testLatin15Encoding() throws IOException { checkXmlWriter( TEXT_LATIN15, "ISO-8859-15" ); } public void testEUC_JPEncoding() throws IOException { checkXmlWriter( TEXT_EUC_JP, "EUC-JP" ); } public void testEBCDICEncoding() throws IOException { checkXmlWriter( "simple text in EBCDIC", "CP1047" ); } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/xml/XmlUtilTest.java000066400000000000000000000123111251077732300322040ustar00rootroot00000000000000package org.codehaus.plexus.util.xml; /* * 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.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; import java.io.StringWriter; import java.io.Writer; import junit.framework.TestCase; import org.codehaus.plexus.util.IOUtil; import org.codehaus.plexus.util.ReaderFactory; import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.util.WriterFactory; /** * Test the {@link XmlUtil} class. * * @author Vincent Siveton * @version $Id$ */ public class XmlUtilTest extends TestCase { private String basedir; public final String getBasedir() { if ( null == basedir ) { basedir = System.getProperty( "basedir", new File( "" ).getAbsolutePath() ); } return basedir; } private File getTestOutputFile( String relPath ) throws IOException { final File file = new File( getBasedir(), relPath ); final File parentFile = file.getParentFile(); if ( !parentFile.isDirectory() && !parentFile.mkdirs() ) { throw new IOException( "Could not create test directory " + parentFile ); } return file; } /** {@inheritDoc} */ protected void setUp() throws Exception { super.setUp(); } /** {@inheritDoc} */ protected void tearDown() throws Exception { super.tearDown(); } public void testPrettyFormatInputStreamOutputStream() throws Exception { File testDocument = new File( getBasedir(), "src/test/resources/testDocument.xhtml" ); assertTrue( testDocument.exists() ); InputStream is = null; OutputStream os = null; try { is = new FileInputStream( testDocument ); os = new FileOutputStream( getTestOutputFile( "target/test/prettyFormatTestDocumentOutputStream.xml" ) ); assertNotNull( is ); assertNotNull( os ); XmlUtil.prettyFormat( is, os ); } finally { IOUtil.close( is ); IOUtil.close( os ); } } public void testPrettyFormatReaderWriter() throws Exception { File testDocument = new File( getBasedir(), "src/test/resources/testDocument.xhtml" ); assertTrue( testDocument.exists() ); Reader reader = null; Writer writer = null; try { reader = ReaderFactory.newXmlReader( testDocument ); writer = WriterFactory.newXmlWriter( getTestOutputFile( "target/test/prettyFormatTestDocumentWriter.xml" ) ); assertNotNull( reader ); assertNotNull( writer ); XmlUtil.prettyFormat( reader, writer ); } finally { IOUtil.close( reader ); IOUtil.close( writer ); } } public void testPrettyFormatString() throws Exception { File testDocument = new File( getBasedir(), "src/test/resources/testDocument.xhtml" ); assertTrue( testDocument.exists() ); Reader reader = null; Writer writer = null; String content; try { reader = ReaderFactory.newXmlReader( testDocument ); content = IOUtil.toString( reader ); reader = ReaderFactory.newXmlReader( testDocument ); writer = new StringWriter(); XmlUtil.prettyFormat( reader, writer ); } finally { IOUtil.close( reader ); IOUtil.close( writer ); } assertNotNull( content ); int countEOL = StringUtils.countMatches( content, XmlUtil.DEFAULT_LINE_SEPARATOR ); assertTrue( countEOL < StringUtils.countMatches( writer.toString(), XmlUtil.DEFAULT_LINE_SEPARATOR ) ); } public void testPrettyFormatReaderWriter2() throws Exception { File testDocument = new File( getBasedir(), "src/test/resources/test.xdoc.xhtml" ); assertTrue( testDocument.exists() ); Reader reader = null; Writer writer = null; try { reader = ReaderFactory.newXmlReader( testDocument ); writer = WriterFactory.newXmlWriter( getTestOutputFile( "target/test/prettyFormatTestXdocWriter.xml" ) ); assertNotNull( reader ); assertNotNull( writer ); XmlUtil.prettyFormat( reader, writer ); } finally { IOUtil.close( reader ); IOUtil.close( writer ); } } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/xml/XmlWriterUtilTest.java000066400000000000000000000445101251077732300334070ustar00rootroot00000000000000package org.codehaus.plexus.util.xml; /* * 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.ByteArrayOutputStream; import java.io.OutputStream; import java.io.Writer; import junit.framework.TestCase; import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.util.WriterFactory; /** * @author Vincent Siveton * @version $Id$ */ public class XmlWriterUtilTest extends TestCase { private OutputStream output; private Writer writer; private XMLWriter xmlWriter; /** {@inheritDoc} */ protected void setUp() throws Exception { super.setUp(); output = new ByteArrayOutputStream(); writer = WriterFactory.newXmlWriter( output ); xmlWriter = new PrettyPrintXMLWriter( writer ); } /** {@inheritDoc} */ protected void tearDown() throws Exception { super.tearDown(); xmlWriter = null; writer = null; output = null; } /** * Test method for {@link org.codehaus.plexus.util.xml.XmlWriterUtil#writeLineBreak(org.codehaus.plexus.util.xml.XMLWriter)}. * * @throws Exception if any */ public void testWriteLineBreakXMLWriter() throws Exception { XmlWriterUtil.writeLineBreak( xmlWriter ); writer.close(); assertTrue( StringUtils.countMatches( output.toString(), XmlWriterUtil.LS ) == 1 ); } /** * Test method for {@link org.codehaus.plexus.util.xml.XmlWriterUtil#writeLineBreak(org.codehaus.plexus.util.xml.XMLWriter, int)}. * * @throws Exception if any */ public void testWriteLineBreakXMLWriterInt() throws Exception { XmlWriterUtil.writeLineBreak( xmlWriter, 10 ); writer.close(); assertTrue( StringUtils.countMatches( output.toString(), XmlWriterUtil.LS ) == 10 ); } /** * Test method for {@link org.codehaus.plexus.util.xml.XmlWriterUtil#writeLineBreak(org.codehaus.plexus.util.xml.XMLWriter, int, int)}. * * @throws Exception if any */ public void testWriteLineBreakXMLWriterIntInt() throws Exception { XmlWriterUtil.writeLineBreak( xmlWriter, 10, 2 ); writer.close(); assertTrue( StringUtils.countMatches( output.toString(), XmlWriterUtil.LS ) == 10 ); assertTrue( StringUtils.countMatches( output.toString(), StringUtils .repeat( " ", 2 * XmlWriterUtil.DEFAULT_INDENTATION_SIZE ) ) == 1 ); } /** * Test method for {@link org.codehaus.plexus.util.xml.XmlWriterUtil#writeLineBreak(org.codehaus.plexus.util.xml.XMLWriter, int, int, int)}. * * @throws Exception if any */ public void testWriteLineBreakXMLWriterIntIntInt() throws Exception { XmlWriterUtil.writeLineBreak( xmlWriter, 10, 2, 4 ); writer.close(); assertTrue( StringUtils.countMatches( output.toString(), XmlWriterUtil.LS ) == 10 ); assertTrue( StringUtils.countMatches( output.toString(), StringUtils.repeat( " ", 2 * 4 ) ) == 1 ); } /** * Test method for {@link org.codehaus.plexus.util.xml.XmlWriterUtil#writeCommentLineBreak(org.codehaus.plexus.util.xml.XMLWriter)}. * * @throws Exception if any */ public void testWriteCommentLineBreakXMLWriter() throws Exception { XmlWriterUtil.writeCommentLineBreak( xmlWriter ); writer.close(); StringBuilder sb = new StringBuilder(); sb.append( "" ).append( XmlWriterUtil.LS ); assertEquals( output.toString(), sb.toString() ); assertTrue( output.toString().length() == XmlWriterUtil.DEFAULT_COLUMN_LINE - 1 + XmlWriterUtil.LS.length() ); } /** * Test method for {@link org.codehaus.plexus.util.xml.XmlWriterUtil#writeCommentLineBreak(org.codehaus.plexus.util.xml.XMLWriter, int)}. * * @throws Exception if any */ public void testWriteCommentLineBreakXMLWriterInt() throws Exception { XmlWriterUtil.writeCommentLineBreak( xmlWriter, 20 ); writer.close(); assertEquals( output.toString(), "" + XmlWriterUtil.LS ); tearDown(); setUp(); XmlWriterUtil.writeCommentLineBreak( xmlWriter, 10 ); writer.close(); assertEquals( output.toString(), output.toString(), "" + XmlWriterUtil.LS ); } /** * Test method for {@link org.codehaus.plexus.util.xml.XmlWriterUtil#writeComment(org.codehaus.plexus.util.xml.XMLWriter, java.lang.String)}. * * @throws Exception if any */ public void testWriteCommentXMLWriterString() throws Exception { XmlWriterUtil.writeComment( xmlWriter, "hello" ); writer.close(); StringBuffer sb = new StringBuffer(); sb.append( "" ).append( XmlWriterUtil.LS ); assertEquals( output.toString(), sb.toString() ); assertTrue( output.toString().length() == XmlWriterUtil.DEFAULT_COLUMN_LINE - 1 + XmlWriterUtil.LS.length() ); tearDown(); setUp(); XmlWriterUtil.writeComment( xmlWriter, "hellooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" ); writer.close(); sb = new StringBuffer(); sb.append( "" ) .append( XmlWriterUtil.LS ); assertEquals( output.toString(), sb.toString() ); assertTrue( output.toString().length() >= XmlWriterUtil.DEFAULT_COLUMN_LINE ); tearDown(); setUp(); XmlWriterUtil.writeComment( xmlWriter, "hello\nworld" ); writer.close(); sb = new StringBuffer(); sb.append( "" ).append( XmlWriterUtil.LS ); sb.append( "" ).append( XmlWriterUtil.LS ); assertEquals( output.toString(), sb.toString() ); assertTrue( output.toString().length() == 2 * ( XmlWriterUtil.DEFAULT_COLUMN_LINE - 1 + XmlWriterUtil.LS.length() ) ); } /** * Test method for {@link org.codehaus.plexus.util.xml.XmlWriterUtil#writeComment(org.codehaus.plexus.util.xml.XMLWriter, java.lang.String, int)}. * * @throws Exception if any */ public void testWriteCommentXMLWriterStringInt() throws Exception { String indent = StringUtils.repeat( " ", 2 * XmlWriterUtil.DEFAULT_INDENTATION_SIZE ); XmlWriterUtil.writeComment( xmlWriter, "hello", 2 ); writer.close(); StringBuffer sb = new StringBuffer(); sb.append( indent ); sb.append( "" ).append( XmlWriterUtil.LS ); assertEquals( output.toString(), sb.toString() ); assertTrue( output.toString().length() == XmlWriterUtil.DEFAULT_COLUMN_LINE - 1 + XmlWriterUtil.LS.length() + 2 * XmlWriterUtil.DEFAULT_INDENTATION_SIZE ); tearDown(); setUp(); XmlWriterUtil.writeComment( xmlWriter, "hello\nworld", 2 ); writer.close(); sb = new StringBuffer(); sb.append( indent ); sb.append( "" ).append( XmlWriterUtil.LS ); sb.append( indent ); sb.append( "" ).append( XmlWriterUtil.LS ); assertEquals( output.toString(), sb.toString() ); assertTrue( output.toString().length() == 2 * ( XmlWriterUtil.DEFAULT_COLUMN_LINE - 1 + XmlWriterUtil.LS.length() ) + 2 * indent.length() ); } /** * Test method for {@link org.codehaus.plexus.util.xml.XmlWriterUtil#writeComment(org.codehaus.plexus.util.xml.XMLWriter, java.lang.String, int, int)}. * * @throws Exception if any */ public void testWriteCommentXMLWriterStringIntInt() throws Exception { String repeat = StringUtils.repeat( " ", 2 * 4 ); XmlWriterUtil.writeComment( xmlWriter, "hello", 2, 4 ); writer.close(); StringBuffer sb = new StringBuffer(); sb.append( repeat ); sb.append( "" ).append( XmlWriterUtil.LS ); assertEquals( output.toString(), sb.toString() ); assertTrue( output.toString().length() == XmlWriterUtil.DEFAULT_COLUMN_LINE - 1 + XmlWriterUtil.LS.length() + 2 * 4 ); tearDown(); setUp(); XmlWriterUtil.writeComment( xmlWriter, "hello\nworld", 2, 4 ); writer.close(); sb = new StringBuffer(); sb.append( repeat ); sb.append( "" ).append( XmlWriterUtil.LS ); sb.append( repeat ); sb.append( "" ).append( XmlWriterUtil.LS ); assertEquals( output.toString(), sb.toString() ); assertTrue( output.toString().length() == 2 * ( XmlWriterUtil.DEFAULT_COLUMN_LINE - 1 + XmlWriterUtil.LS.length() ) + 2 * repeat.length() ); } /** * Test method for {@link org.codehaus.plexus.util.xml.XmlWriterUtil#writeComment(org.codehaus.plexus.util.xml.XMLWriter, java.lang.String, int, int, int)}. * * @throws Exception if any */ public void testWriteCommentXMLWriterStringIntIntInt() throws Exception { String indent = StringUtils.repeat( " ", 2 * 4 ); XmlWriterUtil.writeComment( xmlWriter, "hello", 2, 4, 50 ); writer.close(); StringBuffer sb = new StringBuffer(); sb.append( indent ); sb.append( "" ).append( XmlWriterUtil.LS ); assertEquals( output.toString(), sb.toString() ); assertTrue( output.toString().length() == 50 - 1 + XmlWriterUtil.LS.length() + 2 * 4 ); tearDown(); setUp(); XmlWriterUtil.writeComment( xmlWriter, "hello", 2, 4, 10 ); writer.close(); sb = new StringBuffer(); sb.append( indent ); sb.append( "" ).append( XmlWriterUtil.LS ); assertEquals( output.toString(), sb.toString() ); assertTrue( output.toString().length() >= 10 + 2 * 4 ); } /** * Test method for {@link org.codehaus.plexus.util.xml.XmlWriterUtil#writeCommentText(org.codehaus.plexus.util.xml.XMLWriter, java.lang.String, int)}. * * @throws Exception if any */ public void testWriteCommentTextXMLWriterStringInt() throws Exception { XmlWriterUtil.writeCommentText( xmlWriter, "hello", 0 ); writer.close(); StringBuffer sb = new StringBuffer(); sb.append( XmlWriterUtil.LS ); sb.append( "" ).append( XmlWriterUtil.LS ); sb.append( "" ).append( XmlWriterUtil.LS ); sb.append( "" ).append( XmlWriterUtil.LS ); sb.append( XmlWriterUtil.LS ); assertEquals( output.toString(), sb.toString() ); assertTrue( output.toString().length() == 3 * ( 80 - 1 + XmlWriterUtil.LS.length() ) + 2 * XmlWriterUtil.LS.length() ); tearDown(); setUp(); String indent = StringUtils.repeat( " ", 2 * 2 ); XmlWriterUtil.writeCommentText( xmlWriter, "hello world with end of line\n and " + "loooooooooooooooooooooooooooooooooooooooooooooooooooooonnnnnnnnnnong line", 2 ); writer.close(); sb = new StringBuffer(); sb.append( XmlWriterUtil.LS ); sb.append( indent ).append( "" ) .append( XmlWriterUtil.LS ); sb.append( indent ).append( "" ) .append( XmlWriterUtil.LS ); sb.append( indent ).append( "" ) .append( XmlWriterUtil.LS ); sb.append( indent ).append( "" ) .append( XmlWriterUtil.LS ); sb.append( indent ).append( "" ) .append( XmlWriterUtil.LS ); sb.append( indent ).append( "" ) .append( XmlWriterUtil.LS ); sb.append( XmlWriterUtil.LS ); sb.append( indent ); assertEquals( output.toString(), sb.toString() ); } /** * Test method for {@link org.codehaus.plexus.util.xml.XmlWriterUtil#writeCommentText(org.codehaus.plexus.util.xml.XMLWriter, java.lang.String, int, int)}. * * @throws Exception if any */ public void testWriteCommentTextXMLWriterStringIntInt() throws Exception { String indent = StringUtils.repeat( " ", 2 * 4 ); XmlWriterUtil.writeCommentText( xmlWriter, "hello", 2, 4 ); writer.close(); StringBuilder sb = new StringBuilder(); sb.append( XmlWriterUtil.LS ); sb.append( indent ).append( "" ) .append( XmlWriterUtil.LS ); sb.append( indent ).append( "" ) .append( XmlWriterUtil.LS ); sb.append( indent ).append( "" ) .append( XmlWriterUtil.LS ); sb.append( XmlWriterUtil.LS ); sb.append( indent ); assertEquals( output.toString(), sb.toString() ); assertTrue( output.toString().length() == 3 * ( 80 - 1 + XmlWriterUtil.LS.length() ) + 4 * 2 * 4 + 2 * XmlWriterUtil.LS.length() ); } /** * Test method for {@link org.codehaus.plexus.util.xml.XmlWriterUtil#writeCommentText(org.codehaus.plexus.util.xml.XMLWriter, java.lang.String, int, int, int)}. * * @throws Exception if any */ public void testWriteCommentTextXMLWriterStringIntIntInt() throws Exception { String indent = StringUtils.repeat( " ", 2 * 4 ); XmlWriterUtil.writeCommentText( xmlWriter, "hello", 2, 4, 50 ); writer.close(); StringBuilder sb = new StringBuilder(); sb.append( XmlWriterUtil.LS ); sb.append( indent ).append( "" ).append( XmlWriterUtil.LS ); sb.append( indent ).append( "" ).append( XmlWriterUtil.LS ); sb.append( indent ).append( "" ).append( XmlWriterUtil.LS ); sb.append( XmlWriterUtil.LS ); sb.append( indent ); assertEquals( output.toString(), sb.toString() ); assertTrue( output.toString().length() == 3 * ( 50 - 1 + XmlWriterUtil.LS.length() ) + 4 * 2 * 4 + 2 * XmlWriterUtil.LS.length() ); } /** * Test method for {@link org.codehaus.plexus.util.xml.XmlWriterUtil#writeComment(org.codehaus.plexus.util.xml.XMLWriter, java.lang.String)}. * * @throws Exception if any */ public void testWriteCommentNull() throws Exception { XmlWriterUtil.writeComment( xmlWriter, null ); writer.close(); StringBuilder sb = new StringBuilder(); sb.append( "" ).append( XmlWriterUtil.LS ); assertEquals( output.toString(), sb.toString() ); } /** * Test method for {@link org.codehaus.plexus.util.xml.XmlWriterUtil#writeComment(org.codehaus.plexus.util.xml.XMLWriter, java.lang.String)}. * * @throws Exception if any */ public void testWriteCommentShort() throws Exception { XmlWriterUtil.writeComment( xmlWriter, "This is a short text" ); writer.close(); StringBuilder sb = new StringBuilder(); sb.append( "" ).append( XmlWriterUtil.LS ); assertEquals( output.toString(), sb.toString() ); } /** * Test method for {@link org.codehaus.plexus.util.xml.XmlWriterUtil#writeComment(org.codehaus.plexus.util.xml.XMLWriter, java.lang.String)}. * * @throws Exception if any */ public void testWriteCommentLong() throws Exception { XmlWriterUtil.writeComment( xmlWriter, "Maven is a software project management and comprehension tool. " + "Based on the concept of a project object model (POM), Maven can manage a project's build, reporting " + "and documentation from a central piece of information." ); writer.close(); StringBuilder sb = new StringBuilder(); sb.append( "" ).append( XmlWriterUtil.LS ); sb.append( "" ).append( XmlWriterUtil.LS ); sb.append( "" ).append( XmlWriterUtil.LS ); sb.append( "" ).append( XmlWriterUtil.LS ); assertEquals( output.toString(), sb.toString() ); } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomBuilderTest.java000066400000000000000000000203271251077732300334150ustar00rootroot00000000000000package org.codehaus.plexus.util.xml; /* * 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 junit.framework.TestCase; import org.codehaus.plexus.util.xml.pull.MXParser; import org.codehaus.plexus.util.xml.pull.XmlPullParser; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; /** * Test the Xpp3DomBuilder. * * @author Brett Porter * @version $Id$ */ public class Xpp3DomBuilderTest extends TestCase { private static final String LS = System.getProperty( "line.separator" ); public void testBuildFromReader() throws Exception { String domString = createDomString(); Xpp3Dom dom = Xpp3DomBuilder.build( new StringReader( domString ) ); Xpp3Dom expectedDom = createExpectedDom(); assertEquals( "check DOMs match", expectedDom, dom ); } public void testBuildTrimming() throws Exception { String domString = createDomString(); Xpp3Dom dom = Xpp3DomBuilder.build( new StringReader( domString ), true ); assertEquals( "test with trimming on", "element1", dom.getChild( "el1" ).getValue() ); dom = Xpp3DomBuilder.build( new StringReader( domString ), false ); assertEquals( "test with trimming off", " element1\n ", dom.getChild( "el1" ).getValue() ); } public void testBuildFromXpp3Dom() throws Exception { Xpp3Dom expectedDom = createExpectedDom(); Xpp3Dom dom = null; XmlPullParser parser = new MXParser(); String domString = "" + createDomString() + ""; parser.setInput( new StringReader( domString ) ); int eventType = parser.getEventType(); boolean configurationClosed = false; boolean newRootClosed = false; boolean rootClosed = false; while ( eventType != XmlPullParser.END_DOCUMENT ) { if ( eventType == XmlPullParser.START_TAG ) { String rawName = parser.getName(); if ( "root".equals( rawName ) ) { dom = Xpp3DomBuilder.build( parser ); } } else if ( eventType == XmlPullParser.END_TAG ) { String rawName = parser.getName(); if ( "configuration".equals( rawName ) ) { configurationClosed = true; } else if ( "newRoot".equals( rawName ) ) { newRootClosed = true; } else if ( "root".equals( rawName ) ) { rootClosed = true; } } eventType = parser.next(); } assertEquals( "Check DOM matches", expectedDom, dom ); assertFalse( "Check closing root was consumed", rootClosed ); assertTrue( "Check continued to parse configuration", configurationClosed ); assertTrue( "Check continued to parse newRoot", newRootClosed ); } /** * Test we get an error from the parser, and don't hit the IllegalStateException. */ public void testUnclosedXml() { String domString = "" + createDomString(); try { Xpp3DomBuilder.build( new StringReader( domString ) ); } catch ( XmlPullParserException expected ) { // correct assertTrue( true ); } catch ( IOException expected ) { // this will do too assertTrue( true ); } } public void testEscapingInContent() throws IOException, XmlPullParserException { Xpp3Dom dom = Xpp3DomBuilder.build( new StringReader( getEncodedString() ) ); assertEquals( "Check content value", "\"text\"", dom.getChild( "el" ).getValue() ); assertEquals( "Check content value", "\"text\"", dom.getChild( "ela" ).getValue() ); assertEquals( "Check content value", "\"text\"", dom.getChild( "elb" ).getValue() ); StringWriter w = new StringWriter(); Xpp3DomWriter.write( w, dom ); assertEquals( "Compare stringified DOMs", getExpectedString(), w.toString() ); } public void testEscapingInAttributes() throws IOException, XmlPullParserException { String s = getAttributeEncodedString(); Xpp3Dom dom = Xpp3DomBuilder.build( new StringReader( s ) ); assertEquals( "Check attribute value", "", dom.getChild( "el" ).getAttribute( "att" ) ); StringWriter w = new StringWriter(); Xpp3DomWriter.write( w, dom ); String newString = w.toString(); assertEquals( "Compare stringified DOMs", newString, s ); } private static String getAttributeEncodedString() { StringBuilder domString = new StringBuilder(); domString.append( "" ); domString.append( LS ); domString.append( " bar" ); domString.append( LS ); domString.append( "" ); return domString.toString(); } private static String getEncodedString() { StringBuilder domString = new StringBuilder(); domString.append( "\n" ); domString.append( " \"text\"\n" ); domString.append( " \"text\"]]>\n" ); domString.append( " <b>"text"</b>\n" ); domString.append( "" ); return domString.toString(); } private static String getExpectedString() { StringBuilder domString = new StringBuilder(); domString.append( "" ); domString.append( LS ); domString.append( " "text"" ); domString.append( LS ); domString.append( " <b>"text"</b>" ); domString.append( LS ); domString.append( " <b>"text"</b>" ); domString.append( LS ); domString.append( "" ); return domString.toString(); } // // HELPER METHODS // private static String createDomString() { StringBuilder buf = new StringBuilder(); buf.append( "\n" ); buf.append( " element1\n \n" ); buf.append( " \n" ); buf.append( " element3\n" ); buf.append( " \n" ); buf.append( " \n" ); buf.append( " \n" ); buf.append( " do not trim \n" ); buf.append( "\n" ); return buf.toString(); } private static Xpp3Dom createExpectedDom() { Xpp3Dom expectedDom = new Xpp3Dom( "root" ); Xpp3Dom el1 = new Xpp3Dom( "el1" ); el1.setValue( "element1" ); expectedDom.addChild( el1 ); Xpp3Dom el2 = new Xpp3Dom( "el2" ); el2.setAttribute( "att2", "attribute2\nnextline" ); expectedDom.addChild( el2 ); Xpp3Dom el3 = new Xpp3Dom( "el3" ); el3.setAttribute( "att3", "attribute3" ); el3.setValue( "element3" ); el2.addChild( el3 ); Xpp3Dom el4 = new Xpp3Dom( "el4" ); el4.setValue( "" ); expectedDom.addChild( el4 ); Xpp3Dom el5 = new Xpp3Dom( "el5" ); expectedDom.addChild( el5 ); Xpp3Dom el6 = new Xpp3Dom( "el6" ); el6.setAttribute( "xml:space", "preserve" ); el6.setValue( " do not trim " ); expectedDom.addChild( el6 ); return expectedDom; } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomTest.java000066400000000000000000000227311251077732300321070ustar00rootroot00000000000000package org.codehaus.plexus.util.xml; /* * 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 org.codehaus.plexus.util.xml.pull.XmlPullParserException; import java.io.IOException; import java.io.StringReader; import java.util.HashMap; import junit.framework.TestCase; public class Xpp3DomTest extends TestCase { public void testShouldPerformAppendAtFirstSubElementLevel() { // create the dominant DOM Xpp3Dom t1 = new Xpp3Dom( "top" ); t1.setAttribute( Xpp3Dom.CHILDREN_COMBINATION_MODE_ATTRIBUTE, Xpp3Dom.CHILDREN_COMBINATION_APPEND ); Xpp3Dom t1s1 = new Xpp3Dom( "topsub1" ); t1s1.setValue( "t1s1Value" ); t1.addChild( t1s1 ); // create the recessive DOM Xpp3Dom t2 = new Xpp3Dom( "top" ); Xpp3Dom t2s1 = new Xpp3Dom( "topsub1" ); t2s1.setValue( "t2s1Value" ); t2.addChild( t2s1 ); // merge and check results. Xpp3Dom result = Xpp3Dom.mergeXpp3Dom( t1, t2 ); assertEquals( 2, result.getChildren( "topsub1" ).length ); } public void testShouldOverrideAppendAndDeepMerge() { // create the dominant DOM Xpp3Dom t1 = new Xpp3Dom( "top" ); t1.setAttribute( Xpp3Dom.CHILDREN_COMBINATION_MODE_ATTRIBUTE, Xpp3Dom.CHILDREN_COMBINATION_APPEND ); Xpp3Dom t1s1 = new Xpp3Dom( "topsub1" ); t1s1.setValue( "t1s1Value" ); t1.addChild( t1s1 ); // create the recessive DOM Xpp3Dom t2 = new Xpp3Dom( "top" ); Xpp3Dom t2s1 = new Xpp3Dom( "topsub1" ); t2s1.setValue( "t2s1Value" ); t2.addChild( t2s1 ); // merge and check results. Xpp3Dom result = Xpp3Dom.mergeXpp3Dom( t1, t2, Boolean.TRUE ); assertEquals( 1, result.getChildren( "topsub1" ).length ); } public void testShouldPerformSelfOverrideAtTopLevel() { // create the dominant DOM Xpp3Dom t1 = new Xpp3Dom( "top" ); t1.setAttribute( "attr", "value" ); t1.setAttribute( Xpp3Dom.SELF_COMBINATION_MODE_ATTRIBUTE, Xpp3Dom.SELF_COMBINATION_OVERRIDE ); // create the recessive DOM Xpp3Dom t2 = new Xpp3Dom( "top" ); t2.setAttribute( "attr2", "value2" ); t2.setValue( "t2Value" ); // merge and check results. Xpp3Dom result = Xpp3Dom.mergeXpp3Dom( t1, t2 ); assertEquals( 2, result.getAttributeNames().length ); assertNull( result.getValue() ); } public void testShouldMergeValuesAtTopLevelByDefault() { // create the dominant DOM Xpp3Dom t1 = new Xpp3Dom( "top" ); t1.setAttribute( "attr", "value" ); // create the recessive DOM Xpp3Dom t2 = new Xpp3Dom( "top" ); t2.setAttribute( "attr2", "value2" ); t2.setValue( "t2Value" ); // merge and check results. Xpp3Dom result = Xpp3Dom.mergeXpp3Dom( t1, t2 ); // this is still 2, since we're not using the merge-control attribute. assertEquals( 2, result.getAttributeNames().length ); assertEquals( result.getValue(), t2.getValue() ); } public void testShouldMergeValuesAtTopLevel() { // create the dominant DOM Xpp3Dom t1 = new Xpp3Dom( "top" ); t1.setAttribute( "attr", "value" ); t1.setAttribute( Xpp3Dom.SELF_COMBINATION_MODE_ATTRIBUTE, Xpp3Dom.SELF_COMBINATION_MERGE ); // create the recessive DOM Xpp3Dom t2 = new Xpp3Dom( "top" ); t2.setAttribute( "attr2", "value2" ); t2.setValue( "t2Value" ); // merge and check results. Xpp3Dom result = Xpp3Dom.mergeXpp3Dom( t1, t2 ); assertEquals( 3, result.getAttributeNames().length ); assertEquals( result.getValue(), t2.getValue() ); } public void testNullAttributeNameOrValue() { Xpp3Dom t1 = new Xpp3Dom( "top" ); try { t1.setAttribute( "attr", null ); fail( "null attribute values shouldn't be allowed" ); } catch ( NullPointerException e ) { } t1.toString(); try { t1.setAttribute( null, "value" ); fail( "null attribute names shouldn't be allowed" ); } catch ( NullPointerException e ) { } t1.toString(); } public void testEquals() { Xpp3Dom dom = new Xpp3Dom( "top" ); assertEquals( dom, dom ); assertFalse( dom.equals( null ) ); assertFalse( dom.equals( new Xpp3Dom( (String) null ) ) ); } public void testEqualsIsNullSafe() throws XmlPullParserException, IOException { String testDom = "onetwo"; Xpp3Dom dom = Xpp3DomBuilder.build( new StringReader( testDom ) ); Xpp3Dom dom2 = Xpp3DomBuilder.build( new StringReader( testDom ) ); try { dom2.attributes = new HashMap(); dom2.attributes.put( "nullValue", null ); dom2.attributes.put( null, "nullKey" ); dom2.childList.clear(); dom2.childList.add( null ); assertFalse( dom.equals( dom2 ) ); assertFalse( dom2.equals( dom ) ); } catch ( NullPointerException ex ) { ex.printStackTrace(); fail( "\nNullPointerExceptions should not be thrown." ); } } public void testShouldOverwritePluginConfigurationSubItemsByDefault() throws XmlPullParserException, IOException { String parentConfigStr = "onetwo"; Xpp3Dom parentConfig = Xpp3DomBuilder.build( new StringReader( parentConfigStr ) ); String childConfigStr = "three"; Xpp3Dom childConfig = Xpp3DomBuilder.build( new StringReader( childConfigStr ) ); Xpp3Dom result = Xpp3Dom.mergeXpp3Dom( childConfig, parentConfig ); Xpp3Dom items = result.getChild( "items" ); assertEquals( 1, items.getChildCount() ); Xpp3Dom item = items.getChild( 0 ); assertEquals( "three", item.getValue() ); } public void testShouldMergePluginConfigurationSubItemsWithMergeAttributeSet() throws XmlPullParserException, IOException { String parentConfigStr = "onetwo"; Xpp3Dom parentConfig = Xpp3DomBuilder.build( new StringReader( parentConfigStr ) ); String childConfigStr = "three"; Xpp3Dom childConfig = Xpp3DomBuilder.build( new StringReader( childConfigStr ) ); Xpp3Dom result = Xpp3Dom.mergeXpp3Dom( childConfig, parentConfig ); Xpp3Dom items = result.getChild( "items" ); assertEquals( 3, items.getChildCount() ); Xpp3Dom[] item = items.getChildren(); assertEquals( "one", item[0].getValue() ); assertEquals( "two", item[1].getValue() ); assertEquals( "three", item[2].getValue() ); } public void testShouldNotChangeUponMergeWithItselfWhenFirstOrLastSubItemIsEmpty() throws Exception { String configStr = "test"; Xpp3Dom dominantConfig = Xpp3DomBuilder.build( new StringReader( configStr ) ); Xpp3Dom recessiveConfig = Xpp3DomBuilder.build( new StringReader( configStr ) ); Xpp3Dom result = Xpp3Dom.mergeXpp3Dom( dominantConfig, recessiveConfig ); Xpp3Dom items = result.getChild( "items" ); assertEquals( 3, items.getChildCount() ); assertEquals( null, items.getChild( 0 ).getValue() ); assertEquals( "test", items.getChild( 1 ).getValue() ); assertEquals( null, items.getChild( 2 ).getValue() ); } public void testShouldCopyRecessiveChildrenNotPresentInTarget() throws Exception { String dominantStr = "x"; String recessiveStr = "y"; Xpp3Dom dominantConfig = Xpp3DomBuilder.build( new StringReader( dominantStr ) ); Xpp3Dom recessiveConfig = Xpp3DomBuilder.build( new StringReader( recessiveStr ) ); Xpp3Dom result = Xpp3Dom.mergeXpp3Dom( dominantConfig, recessiveConfig ); assertEquals( 2, result.getChildCount() ); assertEquals( "x", result.getChild( "foo" ).getValue() ); assertEquals( "y", result.getChild( "bar" ).getValue() ); assertNotSame( result.getChild( "bar" ), recessiveConfig.getChild( "bar" ) ); } public void testDupeChildren() throws IOException, XmlPullParserException { String dupes = "xy"; Xpp3Dom dom = Xpp3DomBuilder.build( new StringReader( dupes ) ); assertNotNull( dom); assertEquals("y", dom.getChild("foo").getValue()); } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomUtilsTest.java000066400000000000000000000045241251077732300331300ustar00rootroot00000000000000package org.codehaus.plexus.util.xml; /* * 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.StringReader; import junit.framework.TestCase; public class Xpp3DomUtilsTest extends TestCase { public void testCombineId() throws Exception { String lhs = "" + "LHS-ONLYLHS" + "TOOVERWRITELHS" + ""; String rhs = "" + "RHS-ONLYRHS" + "TOOVERWRITERHS" + ""; Xpp3Dom leftDom = Xpp3DomBuilder.build( new StringReader( lhs ) ); Xpp3Dom rightDom = Xpp3DomBuilder.build( new StringReader( rhs ) ); Xpp3Dom mergeResult = Xpp3DomUtils.mergeXpp3Dom( leftDom, rightDom, true ); assertEquals( 3, mergeResult.getChildren( "property" ).length ); assertEquals( "LHS-ONLY", mergeResult.getChildren( "property" )[0].getChild( "name" ).getValue() ); assertEquals( "LHS", mergeResult.getChildren( "property" )[0].getChild( "value" ).getValue() ); assertEquals( "TOOVERWRITE", mergeResult.getChildren( "property" )[1].getChild( "name" ).getValue() ); assertEquals( "LHS", mergeResult.getChildren( "property" )[1].getChild( "value" ).getValue() ); assertEquals( "RHS-ONLY", mergeResult.getChildren( "property" )[2].getChild( "name" ).getValue() ); assertEquals( "RHS", mergeResult.getChildren( "property" )[2].getChild( "value" ).getValue() ); } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomWriterTest.java000066400000000000000000000067101251077732300333030ustar00rootroot00000000000000package org.codehaus.plexus.util.xml; /* * 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 junit.framework.TestCase; import java.io.StringWriter; /** * @author Edwin Punzalan */ public class Xpp3DomWriterTest extends TestCase { private static final String LS = System.getProperty( "line.separator" ); public void testWriter() { StringWriter writer = new StringWriter(); Xpp3DomWriter.write( writer, createXpp3Dom() ); assertEquals( "Check if output matches", createExpectedXML( true ), writer.toString() ); } public void testWriterNoEscape() { StringWriter writer = new StringWriter(); Xpp3DomWriter.write( new PrettyPrintXMLWriter( writer ), createXpp3Dom(), false ); assertEquals( "Check if output matches", createExpectedXML( false ), writer.toString() ); } private String createExpectedXML( boolean escape ) { StringBuilder buf = new StringBuilder(); buf.append( "" ); buf.append( LS ); buf.append( " element1" ); buf.append( LS ); buf.append( " " ); buf.append( LS ); buf.append( " element3" ); buf.append( LS ); buf.append( " " ); buf.append( LS ); buf.append( " " ); buf.append( LS ); buf.append( " " ); buf.append( LS ); buf.append( " " ); buf.append( LS ); if ( escape ) { buf.append( " element7" ).append( LS ).append( "&"'<>" ); } else { buf.append( " element7" ).append( LS ).append( "&\"\'<>" ); } buf.append( LS ); buf.append( " " ); buf.append( LS ); buf.append( "" ); return buf.toString(); } private Xpp3Dom createXpp3Dom() { Xpp3Dom dom = new Xpp3Dom( "root" ); Xpp3Dom el1 = new Xpp3Dom( "el1" ); el1.setValue( "element1" ); dom.addChild( el1 ); Xpp3Dom el2 = new Xpp3Dom( "el2" ); el2.setAttribute( "att2", "attribute2\nnextline" ); dom.addChild( el2 ); Xpp3Dom el3 = new Xpp3Dom( "el3" ); el3.setAttribute( "att3", "attribute3" ); el3.setValue( "element3" ); el2.addChild( el3 ); Xpp3Dom el4 = new Xpp3Dom( "el4" ); el4.setValue( "" ); dom.addChild( el4 ); Xpp3Dom el5 = new Xpp3Dom( "el5" ); dom.addChild( el5 ); // test escaping Xpp3Dom el6 = new Xpp3Dom( "el6" ); el6.setAttribute( "att6", "attribute6\n&\"'<>" ); dom.addChild( el6 ); Xpp3Dom el7 = new Xpp3Dom( "el7" ); el7.setValue( "element7\n&\"\'<>" ); el6.addChild( el7 ); return dom; } } plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/xml/pull/000077500000000000000000000000001251077732300300615ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/java/org/codehaus/plexus/util/xml/pull/MXParserTest.java000066400000000000000000000126601251077732300332720ustar00rootroot00000000000000package org.codehaus.plexus.util.xml.pull; /* * 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 junit.framework.TestCase; import java.io.IOException; import java.io.StringReader; /** * @author Trygve Laugstøl * @version $Id$ */ public class MXParserTest extends TestCase { public void testHexadecimalEntities() throws Exception { MXParser parser = new MXParser(); parser.defineEntityReplacementText( "test", "replacement" ); String input = "A"; parser.setInput( new StringReader( input ) ); assertEquals( XmlPullParser.START_TAG, parser.next() ); assertEquals( XmlPullParser.TEXT, parser.next() ); assertEquals( "A", parser.getText() ); assertEquals( XmlPullParser.END_TAG, parser.next() ); } public void testDecimalEntities() throws Exception { MXParser parser = new MXParser(); parser.defineEntityReplacementText( "test", "replacement" ); String input = "A"; parser.setInput( new StringReader( input ) ); assertEquals( XmlPullParser.START_TAG, parser.next() ); assertEquals( XmlPullParser.TEXT, parser.next() ); assertEquals( "A", parser.getText() ); assertEquals( XmlPullParser.END_TAG, parser.next() ); } public void testPredefinedEntities() throws Exception { MXParser parser = new MXParser(); parser.defineEntityReplacementText( "test", "replacement" ); String input = "<>&'""; parser.setInput( new StringReader( input ) ); assertEquals( XmlPullParser.START_TAG, parser.next() ); assertEquals( XmlPullParser.TEXT, parser.next() ); assertEquals( "<>&'\"", parser.getText() ); assertEquals( XmlPullParser.END_TAG, parser.next() ); } public void testEntityReplacementMap() throws XmlPullParserException, IOException { EntityReplacementMap erm = new EntityReplacementMap( new String[][]{ { "abc", "CDE" }, { "EFG", "HIJ" } } ); MXParser parser = new MXParser( erm ); String input = "&EFG;"; parser.setInput( new StringReader( input ) ); assertEquals( XmlPullParser.START_TAG, parser.next() ); assertEquals( XmlPullParser.TEXT, parser.next() ); assertEquals( "HIJ", parser.getText() ); assertEquals( XmlPullParser.END_TAG, parser.next() ); } public void testCustomEntities() throws Exception { MXParser parser = new MXParser(); String input = "&myentity;"; parser.setInput( new StringReader( input ) ); parser.defineEntityReplacementText( "myentity", "replacement" ); assertEquals( XmlPullParser.START_TAG, parser.next() ); assertEquals( XmlPullParser.TEXT, parser.next() ); assertEquals( "replacement", parser.getText() ); assertEquals( XmlPullParser.END_TAG, parser.next() ); parser = new MXParser(); input = "&myCustom;"; parser.setInput( new StringReader( input ) ); parser.defineEntityReplacementText( "fo", "A" ); parser.defineEntityReplacementText( "myCustom", "&fo;" ); assertEquals( XmlPullParser.START_TAG, parser.next() ); assertEquals( XmlPullParser.TEXT, parser.next() ); assertEquals( "A", parser.getText() ); assertEquals( XmlPullParser.END_TAG, parser.next() ); } public void testUnicodeEntities() throws Exception { MXParser parser = new MXParser(); String input = "𝟭"; parser.setInput( new StringReader( input ) ); assertEquals( XmlPullParser.START_TAG, parser.nextToken() ); assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); assertEquals( "\uD835\uDFED", parser.getText() ); assertEquals( XmlPullParser.END_TAG, parser.nextToken() ); parser = new MXParser(); input = "ř"; parser.setInput( new StringReader( input ) ); assertEquals( XmlPullParser.START_TAG, parser.nextToken() ); assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); assertEquals( "\u0159", parser.getText() ); assertEquals( XmlPullParser.END_TAG, parser.nextToken() ); } public void testProcessingInstruction() throws Exception { String input = "nnn"; MXParser parser = new MXParser(); parser.setInput( new StringReader( input ) ); assertEquals( XmlPullParser.PROCESSING_INSTRUCTION, parser.nextToken() ); assertEquals( XmlPullParser.START_TAG, parser.nextToken() ); assertEquals( XmlPullParser.TEXT, parser.nextToken() ); assertEquals( XmlPullParser.END_TAG, parser.nextToken() ); } } plexus-utils-plexus-utils-3.0.22/src/test/resources/000077500000000000000000000000001251077732300225175ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/dir-layout-copy/000077500000000000000000000000001251077732300255605ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/dir-layout-copy/dir1/000077500000000000000000000000001251077732300264175ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/dir-layout-copy/dir1/dir2/000077500000000000000000000000001251077732300272575ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/dir-layout-copy/dir1/dir2/.gitignore000066400000000000000000000000541251077732300312460ustar00rootroot00000000000000# just here to make the directory non-empty plexus-utils-plexus-utils-3.0.22/src/test/resources/dir-layout-copy/dir1/foo.txt000066400000000000000000000000151251077732300277370ustar00rootroot00000000000000nothing here plexus-utils-plexus-utils-3.0.22/src/test/resources/dir-layout-copy/empty-dir/000077500000000000000000000000001251077732300274725ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/dir-layout-copy/empty-dir/.gitignore000066400000000000000000000000541251077732300314610ustar00rootroot00000000000000# just here to make the directory non-empty plexus-utils-plexus-utils-3.0.22/src/test/resources/directory-scanner/000077500000000000000000000000001251077732300261525ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/directory-scanner/foo/000077500000000000000000000000001251077732300267355ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/directory-scanner/foo/bar/000077500000000000000000000000001251077732300275015ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/directory-scanner/foo/bar/munchy.txt000066400000000000000000000000001251077732300315330ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/directorywalker/000077500000000000000000000000001251077732300257315ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/directorywalker/directory1/000077500000000000000000000000001251077732300300165ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/directorywalker/directory1/file1.txt000066400000000000000000000000001251077732300315450ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/directorywalker/directory2/000077500000000000000000000000001251077732300300175ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/directorywalker/directory2/directory21/000077500000000000000000000000001251077732300321665ustar00rootroot00000000000000file21.txt000066400000000000000000000000001251077732300337200ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/directorywalker/directory2/directory21plexus-utils-plexus-utils-3.0.22/src/test/resources/directorywalker/directory2/file2.txt000066400000000000000000000000001251077732300315470ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/directorywalker/file.txt000066400000000000000000000000001251077732300273770ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/symlinks/000077500000000000000000000000001251077732300243705ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/symlinks/dirOnTheOutside/000077500000000000000000000000001251077732300274415ustar00rootroot00000000000000FileInDirOnTheOutside.txt000066400000000000000000000000271251077732300342220ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/symlinks/dirOnTheOutsideI am on the outside... plexus-utils-plexus-utils-3.0.22/src/test/resources/symlinks/onTheOutside.txt000066400000000000000000000000371251077732300275430ustar00rootroot00000000000000I am on the outside of the src plexus-utils-plexus-utils-3.0.22/src/test/resources/symlinks/regen.sh000077500000000000000000000002121251077732300260220ustar00rootroot00000000000000rm symlinks.zip rm symlinks.tar cd src zip --symlinks ../symlinks.zip file* targetDir sym* tar -cvf ../symlinks.tar file* targetDir sym* plexus-utils-plexus-utils-3.0.22/src/test/resources/symlinks/src/000077500000000000000000000000001251077732300251575ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/symlinks/src/aRegularDir/000077500000000000000000000000001251077732300273605ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/symlinks/src/aRegularDir/aRegularFile.txt000066400000000000000000000000331251077732300324570ustar00rootroot00000000000000I am just an ordinary file plexus-utils-plexus-utils-3.0.22/src/test/resources/symlinks/src/fileR.txt000066400000000000000000000000461251077732300267610ustar00rootroot00000000000000This file is a source. r r r filemode plexus-utils-plexus-utils-3.0.22/src/test/resources/symlinks/src/fileW.txt000077500000000000000000000000061251077732300267650ustar00rootroot00000000000000all w plexus-utils-plexus-utils-3.0.22/src/test/resources/symlinks/src/fileX.txt000077500000000000000000000000041251077732300267640ustar00rootroot00000000000000xxx plexus-utils-plexus-utils-3.0.22/src/test/resources/symlinks/src/symDir000077700000000000000000000000001251077732300302732targetDir/ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/symlinks/src/symLinkToDirOnTheOutside000077700000000000000000000000001251077732300352462../dirOnTheOutside/ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/symlinks/src/symLinkToFileOnTheOutside000077700000000000000000000000001251077732300355072../onTheOutside.txtustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/symlinks/src/symR000077700000000000000000000000001251077732300276312fileR.txtustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/symlinks/src/symW000077700000000000000000000000001251077732300276432fileW.txtustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/symlinks/src/symX000077700000000000000000000000001251077732300276452fileX.txtustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/symlinks/src/targetDir/000077500000000000000000000000001251077732300271045ustar00rootroot00000000000000plexus-utils-plexus-utils-3.0.22/src/test/resources/symlinks/src/targetDir/targetFile.txt000066400000000000000000000000261251077732300317310ustar00rootroot00000000000000This is a target file plexus-utils-plexus-utils-3.0.22/src/test/resources/symlinks/symlinks.tar000066400000000000000000000330001251077732300267450ustar00rootroot00000000000000./._fileR.txt000644 001750 000024 00000000610 12411334750 014211 0ustar00kristianstaff000000 000000 Mac OS X  2VˆATTRˆ˜ð˜ðcom.apple.acl.text!#acl 1 user:0425E5EE-3DA8-474E-B5A2-D69541A03758:kristian:1000:allow:write,append,writeattr,writeextattr,writesecurity user:FFFFEEEE-DDDD-CCCC-BBBB-AAAA00000059:_spotlight:89:allow,inherited:read,execute,readattr,readextattr,readsecurity fileR.txt000644 001750 000024 00000000046 12411334750 013642 0ustar00kristianstaff000000 000000 This file is a source. r r r filemode ./._fileW.txt000755 001750 000024 00000000610 12411334750 014221 0ustar00kristianstaff000000 000000 Mac OS X  2VˆATTRˆ˜ð˜ðcom.apple.acl.text!#acl 1 user:0425E5EE-3DA8-474E-B5A2-D69541A03758:kristian:1000:allow:write,append,writeattr,writeextattr,writesecurity user:FFFFEEEE-DDDD-CCCC-BBBB-AAAA00000059:_spotlight:89:allow,inherited:read,execute,readattr,readextattr,readsecurity fileW.txt000755 001750 000024 00000000006 12411334750 013646 0ustar00kristianstaff000000 000000 all w ./._fileX.txt000755 001750 000024 00000000610 12411334750 014222 0ustar00kristianstaff000000 000000 Mac OS X  2VˆATTRˆ˜ð˜ðcom.apple.acl.text!#acl 1 user:0425E5EE-3DA8-474E-B5A2-D69541A03758:kristian:1000:allow:write,append,writeattr,writeextattr,writesecurity user:FFFFEEEE-DDDD-CCCC-BBBB-AAAA00000059:_spotlight:89:allow,inherited:read,execute,readattr,readextattr,readsecurity fileX.txt000755 001750 000024 00000000004 12411334750 013645 0ustar00kristianstaff000000 000000 xxx ./._targetDir000755 001750 000024 00000000467 12411334750 014274 0ustar00kristianstaff000000 000000 Mac OS X  27ATTR7˜Ÿ˜Ÿcom.apple.acl.text!#acl 1 user:FFFFEEEE-DDDD-CCCC-BBBB-AAAA00000059:_spotlight:89:allow,inherited,file_inherit,directory_inherit:read,execute,readattr,readextattr,readsecurity targetDir/000755 001750 000024 00000000000 12411334750 013765 5ustar00kristianstaff000000 000000 targetDir/._targetFile.txt000644 001750 000024 00000000430 12411334750 017026 0ustar00kristianstaff000000 000000 Mac OS X  2æATTR˜€˜€com.apple.acl.text!#acl 1 user:FFFFEEEE-DDDD-CCCC-BBBB-AAAA00000059:_spotlight:89:allow,inherited:read,execute,readattr,readextattr,readsecurity targetDir/targetFile.txt000644 001750 000024 00000000026 12411334750 016612 0ustar00kristianstaff000000 000000 This is a target file symDir000755 001750 000024 00000000000 12411473174 015156 2targetDir/ustar00kristianstaff000000 000000 symLinkToDirOnTheOutside000755 001750 000024 00000000000 12411473174 022131 2../dirOnTheOutside/ustar00kristianstaff000000 000000 symLinkToFileOnTheOutside000755 001750 000024 00000000000 12411473174 022372 2../onTheOutside.txtustar00kristianstaff000000 000000 symR000755 001750 000024 00000000000 12411473174 014514 2fileR.txtustar00kristianstaff000000 000000 symW000755 001750 000024 00000000000 12411473174 014526 2fileW.txtustar00kristianstaff000000 000000 symX000755 001750 000024 00000000000 12411473174 014530 2fileX.txtustar00kristianstaff000000 000000 plexus-utils-plexus-utils-3.0.22/src/test/resources/symlinks/symlinks.zip000066400000000000000000000031341251077732300267660ustar00rootroot00000000000000PK.©:EùÉ8Æ!& fileR.txtUT è¹%TŠu&Tux è ÉÈ,VHËÌIUÒ‰ Åù¥EÉ©z E`ÏÍOIåPK .©:Edï¾ç fileW.txtUT è¹%TŠu&Tux èall w PK .©:EgtÒ fileX.txtUT è¹%TŠu&Tux èxxx PK .©:E targetDir/UT è¹%TŽu&Tux èPK BT;Eûý—F symDirUT |v&T|v&Tux ètargetDir/PK BT;E•°<‹symLinkToDirOnTheOutsideUT |v&T|v&Tux è../dirOnTheOutside/PK BT;E¿¦¹£symLinkToFileOnTheOutsideUT |v&T|v&Tux è../onTheOutside.txtPK BT;E™-³ó symRUT |v&T|v&Tux èfileR.txtPK BT;Eé¢S; symWUT |v&T|v&Tux èfileW.txtPK BT;E85¹ symXUT |v&T|v&Tux èfileX.txtPK.©:EùÉ8Æ!& ¤fileR.txtUTè¹%Tux èPK .©:Edï¾ç ídfileW.txtUTè¹%Tux èPK .©:EgtÒ í­fileX.txtUTè¹%Tux èPK .©:E íAôtargetDir/UTè¹%Tux èPK BT;Eûý—F í¡8symDirUT|v&Tux èPK BT;E•°<‹í¡‚symLinkToDirOnTheOutsideUT|v&Tux èPK BT;E¿¦¹£í¡çsymLinkToFileOnTheOutsideUT|v&Tux èPK BT;E™-³ó í¡MsymRUT|v&Tux èPK BT;Eé¢S; í¡”symWUT|v&Tux èPK BT;E85¹ í¡ÛsymXUT|v&Tux èPK $"plexus-utils-plexus-utils-3.0.22/src/test/resources/test.txt000066400000000000000000000000161251077732300242340ustar00rootroot00000000000000This is a testplexus-utils-plexus-utils-3.0.22/src/test/resources/test.xdoc.xhtml000066400000000000000000000106131251077732300255110ustar00rootroot00000000000000 Title

            Paragraph 1, line 1. Paragraph 1, line 2.

            Paragraph 2, line 1. Paragraph 2, line 2.

            Section title

            Sub-section title

            Sub-sub-section title

            Sub-sub-sub-section
            Sub-sub-sub-sub-section
            • List item 1.
            • List item 2.

              Paragraph contained in list item 2.

              • Sub-list item 1.
              • Sub-list item 2.
            • List item 3. Force end of list:
            Verbatim text not contained in list item 3
            1. Numbered item 1.
              1. Numbered item A.
              2. Numbered item B.
            2. Numbered item 2.

            List numbering schemes: [[1]], [[a]], [[A]], [[i]], [[I]].

            Defined term 1
            of definition list.
            Defined term 2
            of definition list.
            Verbatim text
                                        in a box        

            --- instead of +-- suppresses the box around verbatim text.

            Figure caption
            Centered
            cell 1,1
            Left-aligned
            cell 1,2
            Right-aligned
            cell 1,3
            cell 2,1 cell 2,2 cell 2,3

            Table caption

            No grid, no caption:

            cell cell
            cell cell

            Horizontal line:


            New page.

            Italic font. Bold font. Monospaced font.

            Anchor. Link to Anchor. Link to http://www.pixware.fr. Link to showing alternate text. Link to Pixware home page.

            Force line
            break.

            Non breaking space.

            Escaped special characters:
            ~
            =
            -
            +
            *
            [
            ]
            <
            >
            {
            }
            \

            Copyright symbol: ©©©.

            plexus-utils-plexus-utils-3.0.22/src/test/resources/testDocument.xhtml000066400000000000000000000061311251077732300262540ustar00rootroot00000000000000Title

            Paragraph 1, line 1. Paragraph 1, line 2.

            Paragraph 2, line 1. Paragraph 2, line 2.

            Section title

            Sub-section title

            Sub-sub-section title

            Sub-sub-sub-section title
            Sub-sub-sub-sub-section title
            • List item 1.
            • List item 2.

              Paragraph contained in list item 2.

              • Sub-list item 1.
              • Sub-list item 2.
            • List item 3. Force end of list:
            Verbatim text not contained in list item 3
            1. Numbered item 1.
              1. Numbered item A.
              2. Numbered item B.
            2. Numbered item 2.

            List numbering schemes: [[1]], [[a]], [[A]], [[i]], [[I]].

            Defined term 1
            of definition list.
            Defined term 2
            of definition list.
            Verbatim text
                                    in a box        

            --- instead of +-- suppresses the box around verbatim text.

            Figure caption

            Table caption
            Centered
            cell 1,1
            Left-aligned
            cell 1,2
            Right-aligned
            cell 1,3
            cell Bold2,1cell 2,2cell 2,3

            No grid, no caption:

            cellcell
            cellcell
            headerheader
            cellcell

            Horizontal line:


            New page.

            Italic font. Bold font. Monospaced font.

            Anchor. Link to Anchor. Link to http://www.pixware.fr. Link to showing alternate text. Link to Pixware home page.

            Force line
            break.

            Non breaking space.

            Escaped special characters:
            ~
            =
            -
            +
            *
            [
            ]
            <
            >
            {
            }
            \

            Copyright symbol: ©, ©, ©.