plexus-utils-plexus-utils-3.0.22/ 0000775 0000000 0000000 00000000000 12510777323 0016737 5 ustar 00root root 0000000 0000000 plexus-utils-plexus-utils-3.0.22/.gitattributes 0000664 0000000 0000000 00000000244 12510777323 0021632 0 ustar 00root root 0000000 0000000 # 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/.gitignore 0000664 0000000 0000000 00000000162 12510777323 0020726 0 ustar 00root root 0000000 0000000 target/
.project
.classpath
.settings/
bin
*.iml
*.ipr
*.iws
*.idea
release.properties
.java-version
plexus-utils-plexus-utils-3.0.22/NOTICE.txt 0000664 0000000 0000000 00000000145 12510777323 0020461 0 ustar 00root root 0000000 0000000 This product includes software developed by
The Apache Software Foundation (http://www.apache.org/).
plexus-utils-plexus-utils-3.0.22/README.md 0000664 0000000 0000000 00000000156 12510777323 0020220 0 ustar 00root root 0000000 0000000 Plexus-archiver
===============
The current master is now at https://github.com/codehaus-plexus/plexus-utils
plexus-utils-plexus-utils-3.0.22/pom.xml 0000664 0000000 0000000 00000007367 12510777323 0020271 0 ustar 00root root 0000000 0000000
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: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: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.java 0000664 0000000 0000000 00000040715 12510777323 0030150 0 ustar 00root root 0000000 0000000 package org.codehaus.plexus.util;
/*
* Copyright The Codehaus Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* 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 values0 through 63 accessed by using character encodings as
* indices.
*
* For example, base64Alphabet['+'] returns 62.
*
* The value of undefined encodings is -1.
*
* 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 '+'.
*
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.java 0000664 0000000 0000000 00000033711 12510777323 0030727 0 ustar 00root root 0000000 0000000 /*
* 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.java 0000664 0000000 0000000 00000017141 12510777323 0032235 0 ustar 00root root 0000000 0000000 package org.codehaus.plexus.util;
/*
* Copyright The Codehaus Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.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 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
* 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 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. 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. 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. 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. Adds to the list of method names used in the search for Introspects the specified The method searches for methods with specific names that return a
* In the absence of any such method, the object is inspected for a
* If none of the above is found, returns Introspects the specified Walks through the exception chain to the last element -- the
* "root" of the tree -- using {@link #getCause(Throwable)}, and
* returns that exception. Uses Find a throwable by method name. Find a throwable by field name. Returns the number of Returns the list of Delegates to {@link #indexOfThrowable(Throwable, Class, int)},
* starting the search at the beginning of the exception chain. Returns the (zero based) index, of the first
*
* 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 This class represents a Our benchmark
* indicates that {@link FastMap#put FastMap.put(key, value)} is up to
* 5x faster than {@link FastMap} has a predictable iteration order, which is the order
* in which keys were inserted into the map (similar to
* 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 This class is public domain (not copyrighted). Methods exist to retrieve the components of a typical file path. For example
* 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 VectorFile.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 Vectornull.
* @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 )
{
ArrayListfalse 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;
}
/**
* ExceptionUtils provides utilities for manipulating
* Throwable objects.ExceptionUtils. Protected to
* discourage instantiation.
*/
protected ExceptionUtils()
{
}
/**
* Throwable
* objects.Throwable to obtain the cause.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()
* detail field assignable to a Throwable.null.Throwable.
* @throws NullPointerException if the throwable is null
*/
public static Throwable getCause( Throwable throwable )
{
return getCause( throwable, CAUSE_METHOD_NAMES );
}
/**
* Throwable to obtain the cause
* using a supplied array of method names.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;
}
/**
* 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;
}
/**
* instanceof checks to examine the exception,
* looking for well known types which could contain chained or
* wrapped exceptions.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;
}
}
/**
* 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;
}
/**
* 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;
}
/**
* Throwable objects in the
* exception chain.Throwable objects in the
* exception chain.Throwable objects.
*/
public static Throwable[] getThrowables( Throwable throwable )
{
ListThrowable 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.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.
* printRootCauseStackTrace(Throwable t, PrintStream s)
*/
public static String[] getRootCauseStackTrace( Throwable t )
{
Throwable[] throwables = getThrowables( t );
int count = throwables.length;
ArrayListThrowable.
* @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 );
ListMap 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.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).java.util.LinkedHashMap collection class).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.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) {
EntryImplnull 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 extends K, ? extends V> map) {
for ( Entry extends K, ? extends V> 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) {
EntryImpltrue 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 EntryImpltrue 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.java 0000664 0000000 0000000 00000230373 12510777323 0031025 0 ustar 00root root 0000000 0000000 package 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
* Path-related methods
*
* /www/hosted/mysite/index.html, can be broken into:
*
*
* There are also methods to {@link #catPath concatenate two paths}, {@link #resolveFile resolve a
* path relative to a File} and {@link #normalize} a path.
* /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}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.
*
":", "*", "?", "\"", "<", ">", "|"
*
* @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 ListFile 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 )
{
ListURL 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 openeddestination cannot be written tosource 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 openeddestination cannot be written tonull 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
*
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 ListsourceDirectory must exists.
* sourceDirectory must exists.
* sourceDirectory must exists.
* This will remove to (if it exists), ensure that
* to's parent directory exists and move
* from, which involves deleting from as
* well.
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":", "*", "?", "\"", "<", ">", "|"
*
* @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.java 0000664 0000000 0000000 00000071306 12510777323 0030271 0 ustar 00root root 0000000 0000000 package 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
*
* 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).
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.java 0000664 0000000 0000000 00000027121 12510777323 0034161 0 ustar 00root root 0000000 0000000 plexus-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
* * When a possible keyword token is recognized (by detecting the starting and * ending token delimiters): *
*