diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:18 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:18 -0800 |
commit | e5d9544310b857f3ee9ec172bdbff8077323f9a1 (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /src/org/apache/commons | |
parent | 8b7d40049e7f35f9770fc024363a9fa6e88dff15 (diff) | |
download | external_apache-http-e5d9544310b857f3ee9ec172bdbff8077323f9a1.zip external_apache-http-e5d9544310b857f3ee9ec172bdbff8077323f9a1.tar.gz external_apache-http-e5d9544310b857f3ee9ec172bdbff8077323f9a1.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'src/org/apache/commons')
39 files changed, 0 insertions, 10786 deletions
diff --git a/src/org/apache/commons/codec/BinaryDecoder.java b/src/org/apache/commons/codec/BinaryDecoder.java deleted file mode 100644 index 7aebabf..0000000 --- a/src/org/apache/commons/codec/BinaryDecoder.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.codec; - -/** - * Defines common decoding methods for byte array decoders. - * - * @author Apache Software Foundation - * @version $Id: BinaryDecoder.java,v 1.10 2004/06/15 18:14:15 ggregory Exp $ - */ -public interface BinaryDecoder extends Decoder { - - /** - * Decodes a byte array and returns the results as a byte array. - * - * @param pArray A byte array which has been encoded with the - * appropriate encoder - * - * @return a byte array that contains decoded content - * - * @throws DecoderException A decoder exception is thrown - * if a Decoder encounters a failure condition during - * the decode process. - */ - byte[] decode(byte[] pArray) throws DecoderException; -} - diff --git a/src/org/apache/commons/codec/BinaryEncoder.java b/src/org/apache/commons/codec/BinaryEncoder.java deleted file mode 100644 index 52859ed..0000000 --- a/src/org/apache/commons/codec/BinaryEncoder.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.codec; - -/** - * Defines common encoding methods for byte array encoders. - * - * @author Apache Software Foundation - * @version $Id: BinaryEncoder.java,v 1.10 2004/02/29 04:08:31 tobrien Exp $ - */ -public interface BinaryEncoder extends Encoder { - - /** - * Encodes a byte array and return the encoded data - * as a byte array. - * - * @param pArray Data to be encoded - * - * @return A byte array containing the encoded data - * - * @throws EncoderException thrown if the Encoder - * encounters a failure condition during the - * encoding process. - */ - byte[] encode(byte[] pArray) throws EncoderException; -} - diff --git a/src/org/apache/commons/codec/Decoder.java b/src/org/apache/commons/codec/Decoder.java deleted file mode 100644 index 184920c..0000000 --- a/src/org/apache/commons/codec/Decoder.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.codec; - -/** - * <p>Provides the highest level of abstraction for Decoders. - * This is the sister interface of {@link Encoder}. All - * Decoders implement this common generic interface.</p> - * - * <p>Allows a user to pass a generic Object to any Decoder - * implementation in the codec package.</p> - * - * <p>One of the two interfaces at the center of the codec package.</p> - * - * @author Apache Software Foundation - * @version $Id: Decoder.java,v 1.9 2004/02/29 04:08:31 tobrien Exp $ - */ -public interface Decoder { - - /** - * Decodes an "encoded" Object and returns a "decoded" - * Object. Note that the implementation of this - * interface will try to cast the Object parameter - * to the specific type expected by a particular Decoder - * implementation. If a {@link java.lang.ClassCastException} occurs - * this decode method will throw a DecoderException. - * - * @param pObject an object to "decode" - * - * @return a 'decoded" object - * - * @throws DecoderException a decoder exception can - * be thrown for any number of reasons. Some good - * candidates are that the parameter passed to this - * method is null, a param cannot be cast to the - * appropriate type for a specific encoder. - */ - Object decode(Object pObject) throws DecoderException; -} - diff --git a/src/org/apache/commons/codec/DecoderException.java b/src/org/apache/commons/codec/DecoderException.java deleted file mode 100644 index f35c016..0000000 --- a/src/org/apache/commons/codec/DecoderException.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.codec; - -/** - * Thrown when a Decoder has encountered a failure condition during a decode. - * - * @author Apache Software Foundation - * @version $Id: DecoderException.java,v 1.9 2004/02/29 04:08:31 tobrien Exp $ - */ -public class DecoderException extends Exception { - - /** - * Creates a DecoderException - * - * @param pMessage A message with meaning to a human - */ - public DecoderException(String pMessage) { - super(pMessage); - } - -} - diff --git a/src/org/apache/commons/codec/Encoder.java b/src/org/apache/commons/codec/Encoder.java deleted file mode 100644 index fa339ee..0000000 --- a/src/org/apache/commons/codec/Encoder.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.codec; - -/** - * <p>Provides the highest level of abstraction for Encoders. - * This is the sister interface of {@link Decoder}. Every implementation of - * Encoder provides this common generic interface whic allows a user to pass a - * generic Object to any Encoder implementation in the codec package.</p> - * - * @author Apache Software Foundation - * @version $Id: Encoder.java,v 1.10 2004/02/29 04:08:31 tobrien Exp $ - */ -public interface Encoder { - - /** - * Encodes an "Object" and returns the encoded content - * as an Object. The Objects here may just be <code>byte[]</code> - * or <code>String</code>s depending on the implementation used. - * - * @param pObject An object ot encode - * - * @return An "encoded" Object - * - * @throws EncoderException an encoder exception is - * thrown if the encoder experiences a failure - * condition during the encoding process. - */ - Object encode(Object pObject) throws EncoderException; -} - diff --git a/src/org/apache/commons/codec/EncoderException.java b/src/org/apache/commons/codec/EncoderException.java deleted file mode 100644 index 0e202c1..0000000 --- a/src/org/apache/commons/codec/EncoderException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.codec; - -/** - * Thrown when there is a failure condition during the encoding process. This - * exception is thrown when an Encoder encounters a encoding specific exception - * such as invalid data, inability to calculate a checksum, characters outside of the - * expected range. - * - * @author Apache Software Foundation - * @version $Id: EncoderException.java,v 1.10 2004/02/29 04:08:31 tobrien Exp $ - */ -public class EncoderException extends Exception { - - /** - * Creates a new instance of this exception with an useful message. - * - * @param pMessage a useful message relating to the encoder specific error. - */ - public EncoderException(String pMessage) { - super(pMessage); - } -} - diff --git a/src/org/apache/commons/codec/StringDecoder.java b/src/org/apache/commons/codec/StringDecoder.java deleted file mode 100644 index 9b1a0cd..0000000 --- a/src/org/apache/commons/codec/StringDecoder.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.codec; - -/** - * Decodes a String into a String. - * - * @author Apache Software Foundation - * @version $Id: StringDecoder.java,v 1.9 2004/02/29 04:08:31 tobrien Exp $ - */ -public interface StringDecoder extends Decoder { - - /** - * Decodes a String and returns a String. - * - * @param pString a String to encode - * - * @return the encoded String - * - * @throws DecoderException thrown if there is - * an error conidition during the Encoding process. - */ - String decode(String pString) throws DecoderException; -} - diff --git a/src/org/apache/commons/codec/StringEncoder.java b/src/org/apache/commons/codec/StringEncoder.java deleted file mode 100644 index 46f5404..0000000 --- a/src/org/apache/commons/codec/StringEncoder.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.codec; - -/** - * Encodes a String into a String. - * - * @author Apache Software Foundation - * @version $Id: StringEncoder.java,v 1.9 2004/02/29 04:08:31 tobrien Exp $ - */ -public interface StringEncoder extends Encoder { - - /** - * Encodes a String and returns a String. - * - * @param pString a String to encode - * - * @return the encoded String - * - * @throws EncoderException thrown if there is - * an error conidition during the Encoding process. - */ - String encode(String pString) throws EncoderException; -} - diff --git a/src/org/apache/commons/codec/StringEncoderComparator.java b/src/org/apache/commons/codec/StringEncoderComparator.java deleted file mode 100644 index 6d29af2..0000000 --- a/src/org/apache/commons/codec/StringEncoderComparator.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.codec; - -import java.util.Comparator; - -/** - * Strings are comparable, and this comparator allows - * you to configure it with an instance of a class - * which implements StringEncoder. This comparator - * is used to sort Strings by an encoding scheme such - * as Soundex, Metaphone, etc. This class can come in - * handy if one need to sort Strings by an encoded - * form of a name such as Soundex. - * - * @author Apache Software Foundation - * @version $Id: StringEncoderComparator.java,v 1.14 2004/06/21 23:24:17 ggregory Exp $ - */ -public class StringEncoderComparator implements Comparator { - - /** - * Internal encoder instance. - */ - private StringEncoder stringEncoder; - - /** - * Constructs a new instance. - */ - public StringEncoderComparator() { - // no init. - } - - /** - * Constructs a new instance with the given algorithm. - * @param stringEncoder the StringEncoder used for comparisons. - */ - public StringEncoderComparator(StringEncoder stringEncoder) { - this.stringEncoder = stringEncoder; - } - - /** - * Compares two strings based not on the strings - * themselves, but on an encoding of the two - * strings using the StringEncoder this Comparator - * was created with. - * - * If an {@link EncoderException} is encountered, return <code>0</code>. - * - * @param o1 the object to compare - * @param o2 the object to compare to - * @return the Comparable.compareTo() return code or 0 if an encoding error was caught. - * @see Comparable - */ - public int compare(Object o1, Object o2) { - - int compareCode = 0; - - try { - Comparable s1 = (Comparable) ((Encoder) this.stringEncoder).encode(o1); - Comparable s2 = (Comparable) ((Encoder) this.stringEncoder).encode(o2); - compareCode = s1.compareTo(s2); - } - catch (EncoderException ee) { - compareCode = 0; - } - return compareCode; - } - -} diff --git a/src/org/apache/commons/codec/binary/Base64.java b/src/org/apache/commons/codec/binary/Base64.java deleted file mode 100644 index ea479e9..0000000 --- a/src/org/apache/commons/codec/binary/Base64.java +++ /dev/null @@ -1,524 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.codec.binary; - -import org.apache.commons.codec.BinaryDecoder; -import org.apache.commons.codec.BinaryEncoder; -import org.apache.commons.codec.DecoderException; -import org.apache.commons.codec.EncoderException; - -/** - * Provides Base64 encoding and decoding as defined by RFC 2045. - * - * <p>This class implements section <cite>6.8. Base64 Content-Transfer-Encoding</cite> - * from RFC 2045 <cite>Multipurpose Internet Mail Extensions (MIME) Part One: - * Format of Internet Message Bodies</cite> by Freed and Borenstein.</p> - * - * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a> - * @author Apache Software Foundation - * @since 1.0-dev - * @version $Id: Base64.java,v 1.20 2004/05/24 00:21:24 ggregory Exp $ - */ -public class Base64 implements BinaryEncoder, BinaryDecoder { - - /** - * Chunk size per RFC 2045 section 6.8. - * - * <p>The {@value} character limit does not count the trailing CRLF, but counts - * all other characters, including any equal signs.</p> - * - * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 6.8</a> - */ - static final int CHUNK_SIZE = 76; - - /** - * Chunk separator per RFC 2045 section 2.1. - * - * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 2.1</a> - */ - 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) '='; - - // Create arrays to hold the base64 characters and a - // lookup for base64 chars - private static byte[] base64Alphabet = new byte[BASELENGTH]; - private static byte[] lookUpBase64Alphabet = new byte[LOOKUPLENGTH]; - - // Populating the lookup and character arrays - static { - for (int i = 0; i < BASELENGTH; i++) { - base64Alphabet[i] = (byte) -1; - } - for (int i = 'Z'; i >= 'A'; i--) { - base64Alphabet[i] = (byte) (i - 'A'); - } - for (int i = 'z'; i >= 'a'; i--) { - base64Alphabet[i] = (byte) (i - 'a' + 26); - } - for (int i = '9'; i >= '0'; i--) { - base64Alphabet[i] = (byte) (i - '0' + 52); - } - - base64Alphabet['+'] = 62; - base64Alphabet['/'] = 63; - - for (int i = 0; i <= 25; i++) { - lookUpBase64Alphabet[i] = (byte) ('A' + i); - } - - for (int i = 26, j = 0; i <= 51; i++, j++) { - lookUpBase64Alphabet[i] = (byte) ('a' + j); - } - - for (int i = 52, j = 0; i <= 61; i++, j++) { - lookUpBase64Alphabet[i] = (byte) ('0' + j); - } - - lookUpBase64Alphabet[62] = (byte) '+'; - lookUpBase64Alphabet[63] = (byte) '/'; - } - - private static boolean isBase64(byte octect) { - if (octect == PAD) { - return true; - } else if (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 (int i = 0; i < length; i++) { - if (!isBase64(arrayOctect[i])) { - 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 an Object using the base64 algorithm. This method - * is provided in order to satisfy the requirements of the - * Decoder interface, and will throw a DecoderException if the - * supplied object is not of type byte[]. - * - * @param pObject Object to decode - * @return An object (of type byte[]) containing the - * binary data which corresponds to the byte[] supplied. - * @throws DecoderException if the parameter supplied is not - * of type byte[] - */ - public Object decode(Object pObject) throws DecoderException { - if (!(pObject instanceof byte[])) { - throw new DecoderException("Parameter supplied to Base64 decode is not a byte[]"); - } - return decode((byte[]) pObject); - } - - /** - * 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 isChunked is 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 (int i = 0; i < data.length; i++) { - switch (data[i]) { - case (byte) ' ' : - case (byte) '\n' : - case (byte) '\r' : - case (byte) '\t' : - break; - default: - groomedData[bytesCopied++] = data[i]; - } - } - - 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 (int i = 0; i < data.length; i++) { - if (isBase64(data[i])) { - groomedData[bytesCopied++] = data[i]; - } - } - - byte packedData[] = new byte[bytesCopied]; - - System.arraycopy(groomedData, 0, packedData, 0, bytesCopied); - - return packedData; - } - - - // Implementation of the Encoder Interface - - /** - * Encodes an Object using the base64 algorithm. This method - * is provided in order to satisfy the requirements of the - * Encoder interface, and will throw an EncoderException if the - * supplied object is not of type byte[]. - * - * @param pObject Object to encode - * @return An object (of type byte[]) containing the - * base64 encoded data which corresponds to the byte[] supplied. - * @throws EncoderException if the parameter supplied is not - * of type byte[] - */ - public Object encode(Object pObject) throws EncoderException { - if (!(pObject instanceof byte[])) { - throw new EncoderException( - "Parameter supplied to Base64 encode is not a byte[]"); - } - return encode((byte[]) pObject); - } - - /** - * 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); - } - -} diff --git a/src/org/apache/commons/codec/binary/BinaryCodec.java b/src/org/apache/commons/codec/binary/BinaryCodec.java deleted file mode 100644 index 98c6409..0000000 --- a/src/org/apache/commons/codec/binary/BinaryCodec.java +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.codec.binary; - -import org.apache.commons.codec.BinaryDecoder; -import org.apache.commons.codec.BinaryEncoder; -import org.apache.commons.codec.DecoderException; -import org.apache.commons.codec.EncoderException; - -/** - * Translates between byte arrays and strings of "0"s and "1"s. - * - * <b>TODO:</b> may want to add more bit vector functions like and/or/xor/nand. - * <B>TODO:</b> also might be good to generate boolean[] - * from byte[] et. cetera. - * - * @author Apache Software Foundation - * @since 1.3 - * @version $Id $ - */ -public class BinaryCodec implements BinaryDecoder, BinaryEncoder { - /* - * tried to avoid using ArrayUtils to minimize dependencies while using these empty arrays - dep is just not worth - * it. - */ - /** Empty char array. */ - private static final char[] EMPTY_CHAR_ARRAY = new char[0]; - - /** Empty byte array. */ - private static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; - - /** Mask for bit 0 of a byte. */ - private static final int BIT_0 = 1; - - /** Mask for bit 1 of a byte. */ - private static final int BIT_1 = 0x02; - - /** Mask for bit 2 of a byte. */ - private static final int BIT_2 = 0x04; - - /** Mask for bit 3 of a byte. */ - private static final int BIT_3 = 0x08; - - /** Mask for bit 4 of a byte. */ - private static final int BIT_4 = 0x10; - - /** Mask for bit 5 of a byte. */ - private static final int BIT_5 = 0x20; - - /** Mask for bit 6 of a byte. */ - private static final int BIT_6 = 0x40; - - /** Mask for bit 7 of a byte. */ - private static final int BIT_7 = 0x80; - - private static final int[] BITS = {BIT_0, BIT_1, BIT_2, BIT_3, BIT_4, BIT_5, BIT_6, BIT_7}; - - /** - * Converts an array of raw binary data into an array of ascii 0 and 1 characters. - * - * @param raw - * the raw binary data to convert - * @return 0 and 1 ascii character bytes one for each bit of the argument - * @see org.apache.commons.codec.BinaryEncoder#encode(byte[]) - */ - public byte[] encode(byte[] raw) { - return toAsciiBytes(raw); - } - - /** - * Converts an array of raw binary data into an array of ascii 0 and 1 chars. - * - * @param raw - * the raw binary data to convert - * @return 0 and 1 ascii character chars one for each bit of the argument - * @throws EncoderException - * if the argument is not a byte[] - * @see org.apache.commons.codec.Encoder#encode(java.lang.Object) - */ - public Object encode(Object raw) throws EncoderException { - if (!(raw instanceof byte[])) { - throw new EncoderException("argument not a byte array"); - } - return toAsciiChars((byte[]) raw); - } - - /** - * Decodes a byte array where each byte represents an ascii '0' or '1'. - * - * @param ascii - * each byte represents an ascii '0' or '1' - * @return the raw encoded binary where each bit corresponds to a byte in the byte array argument - * @throws DecoderException - * if argument is not a byte[], char[] or String - * @see org.apache.commons.codec.Decoder#decode(java.lang.Object) - */ - public Object decode(Object ascii) throws DecoderException { - if (ascii == null) { - return EMPTY_BYTE_ARRAY; - } - if (ascii instanceof byte[]) { - return fromAscii((byte[]) ascii); - } - if (ascii instanceof char[]) { - return fromAscii((char[]) ascii); - } - if (ascii instanceof String) { - return fromAscii(((String) ascii).toCharArray()); - } - throw new DecoderException("argument not a byte array"); - } - - /** - * Decodes a byte array where each byte represents an ascii '0' or '1'. - * - * @param ascii - * each byte represents an ascii '0' or '1' - * @return the raw encoded binary where each bit corresponds to a byte in the byte array argument - * @see org.apache.commons.codec.Decoder#decode(Object) - */ - public byte[] decode(byte[] ascii) { - return fromAscii(ascii); - } - - /** - * Decodes a String where each char of the String represents an ascii '0' or '1'. - * - * @param ascii - * String of '0' and '1' characters - * @return the raw encoded binary where each bit corresponds to a byte in the byte array argument - * @see org.apache.commons.codec.Decoder#decode(Object) - */ - public byte[] toByteArray(String ascii) { - if (ascii == null) { - return EMPTY_BYTE_ARRAY; - } - return fromAscii(ascii.toCharArray()); - } - - // ------------------------------------------------------------------------ - // - // static codec operations - // - // ------------------------------------------------------------------------ - /** - * Decodes a byte array where each char represents an ascii '0' or '1'. - * - * @param ascii - * each char represents an ascii '0' or '1' - * @return the raw encoded binary where each bit corresponds to a char in the char array argument - */ - public static byte[] fromAscii(char[] ascii) { - if (ascii == null || ascii.length == 0) { - return EMPTY_BYTE_ARRAY; - } - // get length/8 times bytes with 3 bit shifts to the right of the length - byte[] l_raw = new byte[ascii.length >> 3]; - /* - * We decr index jj by 8 as we go along to not recompute indices using multiplication every time inside the - * loop. - */ - for (int ii = 0, jj = ascii.length - 1; ii < l_raw.length; ii++, jj -= 8) { - for (int bits = 0; bits < BITS.length; ++bits) { - if (ascii[jj - bits] == '1') { - l_raw[ii] |= BITS[bits]; - } - } - } - return l_raw; - } - - /** - * Decodes a byte array where each byte represents an ascii '0' or '1'. - * - * @param ascii - * each byte represents an ascii '0' or '1' - * @return the raw encoded binary where each bit corresponds to a byte in the byte array argument - */ - public static byte[] fromAscii(byte[] ascii) { - if (ascii == null || ascii.length == 0) { - return EMPTY_BYTE_ARRAY; - } - // get length/8 times bytes with 3 bit shifts to the right of the length - byte[] l_raw = new byte[ascii.length >> 3]; - /* - * We decr index jj by 8 as we go along to not recompute indices using multiplication every time inside the - * loop. - */ - for (int ii = 0, jj = ascii.length - 1; ii < l_raw.length; ii++, jj -= 8) { - for (int bits = 0; bits < BITS.length; ++bits) { - if (ascii[jj - bits] == '1') { - l_raw[ii] |= BITS[bits]; - } - } - } - return l_raw; - } - - /** - * Converts an array of raw binary data into an array of ascii 0 and 1 character bytes - each byte is a truncated - * char. - * - * @param raw - * the raw binary data to convert - * @return an array of 0 and 1 character bytes for each bit of the argument - * @see org.apache.commons.codec.BinaryEncoder#encode(byte[]) - */ - public static byte[] toAsciiBytes(byte[] raw) { - if (raw == null || raw.length == 0) { - return EMPTY_BYTE_ARRAY; - } - // get 8 times the bytes with 3 bit shifts to the left of the length - byte[] l_ascii = new byte[raw.length << 3]; - /* - * We decr index jj by 8 as we go along to not recompute indices using multiplication every time inside the - * loop. - */ - for (int ii = 0, jj = l_ascii.length - 1; ii < raw.length; ii++, jj -= 8) { - for (int bits = 0; bits < BITS.length; ++bits) { - if ((raw[ii] & BITS[bits]) == 0) { - l_ascii[jj - bits] = '0'; - } else { - l_ascii[jj - bits] = '1'; - } - } - } - return l_ascii; - } - - /** - * Converts an array of raw binary data into an array of ascii 0 and 1 characters. - * - * @param raw - * the raw binary data to convert - * @return an array of 0 and 1 characters for each bit of the argument - * @see org.apache.commons.codec.BinaryEncoder#encode(byte[]) - */ - public static char[] toAsciiChars(byte[] raw) { - if (raw == null || raw.length == 0) { - return EMPTY_CHAR_ARRAY; - } - // get 8 times the bytes with 3 bit shifts to the left of the length - char[] l_ascii = new char[raw.length << 3]; - /* - * We decr index jj by 8 as we go along to not recompute indices using multiplication every time inside the - * loop. - */ - for (int ii = 0, jj = l_ascii.length - 1; ii < raw.length; ii++, jj -= 8) { - for (int bits = 0; bits < BITS.length; ++bits) { - if ((raw[ii] & BITS[bits]) == 0) { - l_ascii[jj - bits] = '0'; - } else { - l_ascii[jj - bits] = '1'; - } - } - } - return l_ascii; - } - - /** - * Converts an array of raw binary data into a String of ascii 0 and 1 characters. - * - * @param raw - * the raw binary data to convert - * @return a String of 0 and 1 characters representing the binary data - * @see org.apache.commons.codec.BinaryEncoder#encode(byte[]) - */ - public static String toAsciiString(byte[] raw) { - return new String(toAsciiChars(raw)); - } -} diff --git a/src/org/apache/commons/codec/binary/Hex.java b/src/org/apache/commons/codec/binary/Hex.java deleted file mode 100644 index 78f5510..0000000 --- a/src/org/apache/commons/codec/binary/Hex.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.codec.binary; - -import org.apache.commons.codec.BinaryDecoder; -import org.apache.commons.codec.BinaryEncoder; -import org.apache.commons.codec.DecoderException; -import org.apache.commons.codec.EncoderException; - -/** - * Hex encoder and decoder. - * - * @since 1.1 - * @author Apache Software Foundation - * @version $Id: Hex.java,v 1.13 2004/04/18 18:22:33 ggregory Exp $ - */ -public class Hex implements BinaryEncoder, BinaryDecoder { - - /** - * Used building output as Hex - */ - private static final char[] DIGITS = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' - }; - - /** - * Converts an array of characters representing hexidecimal values into an - * array of bytes of those same values. The returned array will be half the - * length of the passed array, as it takes two characters to represent any - * given byte. An exception is thrown if the passed char array has an odd - * number of elements. - * - * @param data An array of characters containing hexidecimal digits - * @return A byte array containing binary data decoded from - * the supplied char array. - * @throws DecoderException Thrown if an odd number or illegal of characters - * is supplied - */ - public static byte[] decodeHex(char[] data) throws DecoderException { - - int len = data.length; - - if ((len & 0x01) != 0) { - throw new DecoderException("Odd number of characters."); - } - - byte[] out = new byte[len >> 1]; - - // two characters form the hex value. - for (int i = 0, j = 0; j < len; i++) { - int f = toDigit(data[j], j) << 4; - j++; - f = f | toDigit(data[j], j); - j++; - out[i] = (byte) (f & 0xFF); - } - - return out; - } - - /** - * Converts a hexadecimal character to an integer. - * - * @param ch A character to convert to an integer digit - * @param index The index of the character in the source - * @return An integer - * @throws DecoderException Thrown if ch is an illegal hex character - */ - protected static int toDigit(char ch, int index) throws DecoderException { - int digit = Character.digit(ch, 16); - if (digit == -1) { - throw new DecoderException("Illegal hexadecimal charcter " + ch + " at index " + index); - } - return digit; - } - - /** - * Converts an array of bytes into an array of characters representing the hexidecimal values of each byte in order. - * The returned array will be double the length of the passed array, as it takes two characters to represent any - * given byte. - * - * @param data - * a byte[] to convert to Hex characters - * @return A char[] containing hexidecimal characters - */ - public static char[] encodeHex(byte[] data) { - - int l = data.length; - - char[] out = new char[l << 1]; - - // two characters form the hex value. - for (int i = 0, j = 0; i < l; i++) { - out[j++] = DIGITS[(0xF0 & data[i]) >>> 4 ]; - out[j++] = DIGITS[ 0x0F & data[i] ]; - } - - return out; - } - - /** - * Converts an array of character bytes representing hexidecimal values into an - * array of bytes of those same values. The returned array will be half the - * length of the passed array, as it takes two characters to represent any - * given byte. An exception is thrown if the passed char array has an odd - * number of elements. - * - * @param array An array of character bytes containing hexidecimal digits - * @return A byte array containing binary data decoded from - * the supplied byte array (representing characters). - * @throws DecoderException Thrown if an odd number of characters is supplied - * to this function - * @see #decodeHex(char[]) - */ - public byte[] decode(byte[] array) throws DecoderException { - return decodeHex(new String(array).toCharArray()); - } - - /** - * Converts a String or an array of character bytes representing hexidecimal values into an - * array of bytes of those same values. The returned array will be half the - * length of the passed String or array, as it takes two characters to represent any - * given byte. An exception is thrown if the passed char array has an odd - * number of elements. - * - * @param object A String or, an array of character bytes containing hexidecimal digits - * @return A byte array containing binary data decoded from - * the supplied byte array (representing characters). - * @throws DecoderException Thrown if an odd number of characters is supplied - * to this function or the object is not a String or char[] - * @see #decodeHex(char[]) - */ - public Object decode(Object object) throws DecoderException { - try { - char[] charArray = object instanceof String ? ((String) object).toCharArray() : (char[]) object; - return decodeHex(charArray); - } catch (ClassCastException e) { - throw new DecoderException(e.getMessage()); - } - } - - /** - * Converts an array of bytes into an array of bytes for the characters representing the - * hexidecimal values of each byte in order. The returned array will be - * double the length of the passed array, as it takes two characters to - * represent any given byte. - * - * @param array a byte[] to convert to Hex characters - * @return A byte[] containing the bytes of the hexidecimal characters - * @see #encodeHex(byte[]) - */ - public byte[] encode(byte[] array) { - return new String(encodeHex(array)).getBytes(); - } - - /** - * Converts a String or an array of bytes into an array of characters representing the - * hexidecimal values of each byte in order. The returned array will be - * double the length of the passed String or array, as it takes two characters to - * represent any given byte. - * - * @param object a String, or byte[] to convert to Hex characters - * @return A char[] containing hexidecimal characters - * @throws EncoderException Thrown if the given object is not a String or byte[] - * @see #encodeHex(byte[]) - */ - public Object encode(Object object) throws EncoderException { - try { - byte[] byteArray = object instanceof String ? ((String) object).getBytes() : (byte[]) object; - return encodeHex(byteArray); - } catch (ClassCastException e) { - throw new EncoderException(e.getMessage()); - } - } - -} - diff --git a/src/org/apache/commons/codec/binary/package.html b/src/org/apache/commons/codec/binary/package.html deleted file mode 100644 index 844d918..0000000 --- a/src/org/apache/commons/codec/binary/package.html +++ /dev/null @@ -1,20 +0,0 @@ -<!-- -Copyright 2003-2004 The Apache Software Foundation. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. ---> -<html> - <body> - Base64, Binary, and Hexadecimal String encoding and decoding. - </body> -</html> diff --git a/src/org/apache/commons/codec/language/DoubleMetaphone.java b/src/org/apache/commons/codec/language/DoubleMetaphone.java deleted file mode 100644 index 1cad991..0000000 --- a/src/org/apache/commons/codec/language/DoubleMetaphone.java +++ /dev/null @@ -1,1103 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.codec.language; - -import org.apache.commons.codec.EncoderException; -import org.apache.commons.codec.StringEncoder; - -/** - * Encodes a string into a double metaphone value. - * This Implementation is based on the algorithm by <CITE>Lawrence Philips</CITE>. - * <ul> - * <li>Original Article: <a - * href="http://www.cuj.com/documents/s=8038/cuj0006philips/"> - * http://www.cuj.com/documents/s=8038/cuj0006philips/</a></li> - * <li>Original Source Code: <a href="ftp://ftp.cuj.com/pub/2000/1806/philips.zip"> - * ftp://ftp.cuj.com/pub/2000/1806/philips.zip</a></li> - * </ul> - * - * @author Apache Software Foundation - * @version $Id: DoubleMetaphone.java,v 1.24 2004/06/05 18:32:04 ggregory Exp $ - */ -public class DoubleMetaphone implements StringEncoder { - - /** - * "Vowels" to test for - */ - private static final String VOWELS = "AEIOUY"; - - /** - * Prefixes when present which are not pronounced - */ - private static final String[] SILENT_START = - { "GN", "KN", "PN", "WR", "PS" }; - private static final String[] L_R_N_M_B_H_F_V_W_SPACE = - { "L", "R", "N", "M", "B", "H", "F", "V", "W", " " }; - private static final String[] ES_EP_EB_EL_EY_IB_IL_IN_IE_EI_ER = - { "ES", "EP", "EB", "EL", "EY", "IB", "IL", "IN", "IE", "EI", "ER" }; - private static final String[] L_T_K_S_N_M_B_Z = - { "L", "T", "K", "S", "N", "M", "B", "Z" }; - - /** - * Maximum length of an encoding, default is 4 - */ - protected int maxCodeLen = 4; - - /** - * Creates an instance of this DoubleMetaphone encoder - */ - public DoubleMetaphone() { - super(); - } - - /** - * Encode a value with Double Metaphone - * - * @param value String to encode - * @return an encoded string - */ - public String doubleMetaphone(String value) { - return doubleMetaphone(value, false); - } - - /** - * Encode a value with Double Metaphone, optionally using the alternate - * encoding. - * - * @param value String to encode - * @param alternate use alternate encode - * @return an encoded string - */ - public String doubleMetaphone(String value, boolean alternate) { - value = cleanInput(value); - if (value == null) { - return null; - } - - boolean slavoGermanic = isSlavoGermanic(value); - int index = isSilentStart(value) ? 1 : 0; - - DoubleMetaphoneResult result = new DoubleMetaphoneResult(this.getMaxCodeLen()); - - while (!result.isComplete() && index <= value.length() - 1) { - switch (value.charAt(index)) { - case 'A': - case 'E': - case 'I': - case 'O': - case 'U': - case 'Y': - index = handleAEIOUY(value, result, index); - break; - case 'B': - result.append('P'); - index = charAt(value, index + 1) == 'B' ? index + 2 : index + 1; - break; - case '\u00C7': - // A C with a Cedilla - result.append('S'); - index++; - break; - case 'C': - index = handleC(value, result, index); - break; - case 'D': - index = handleD(value, result, index); - break; - case 'F': - result.append('F'); - index = charAt(value, index + 1) == 'F' ? index + 2 : index + 1; - break; - case 'G': - index = handleG(value, result, index, slavoGermanic); - break; - case 'H': - index = handleH(value, result, index); - break; - case 'J': - index = handleJ(value, result, index, slavoGermanic); - break; - case 'K': - result.append('K'); - index = charAt(value, index + 1) == 'K' ? index + 2 : index + 1; - break; - case 'L': - index = handleL(value, result, index); - break; - case 'M': - result.append('M'); - index = conditionM0(value, index) ? index + 2 : index + 1; - break; - case 'N': - result.append('N'); - index = charAt(value, index + 1) == 'N' ? index + 2 : index + 1; - break; - case '\u00D1': - // N with a tilde (spanish ene) - result.append('N'); - index++; - break; - case 'P': - index = handleP(value, result, index); - break; - case 'Q': - result.append('K'); - index = charAt(value, index + 1) == 'Q' ? index + 2 : index + 1; - break; - case 'R': - index = handleR(value, result, index, slavoGermanic); - break; - case 'S': - index = handleS(value, result, index, slavoGermanic); - break; - case 'T': - index = handleT(value, result, index); - break; - case 'V': - result.append('F'); - index = charAt(value, index + 1) == 'V' ? index + 2 : index + 1; - break; - case 'W': - index = handleW(value, result, index); - break; - case 'X': - index = handleX(value, result, index); - break; - case 'Z': - index = handleZ(value, result, index, slavoGermanic); - break; - default: - index++; - break; - } - } - - return alternate ? result.getAlternate() : result.getPrimary(); - } - - /** - * Encode the value using DoubleMetaphone. It will only work if - * <code>obj</code> is a <code>String</code> (like <code>Metaphone</code>). - * - * @param obj Object to encode (should be of type String) - * @return An encoded Object (will be of type String) - * @throws EncoderException encode parameter is not of type String - */ - public Object encode(Object obj) throws EncoderException { - if (!(obj instanceof String)) { - throw new EncoderException("DoubleMetaphone encode parameter is not of type String"); - } - return doubleMetaphone((String) obj); - } - - /** - * Encode the value using DoubleMetaphone. - * - * @param value String to encode - * @return An encoded String - */ - public String encode(String value) { - return doubleMetaphone(value); - } - - /** - * Check if the Double Metaphone values of two <code>String</code> values - * are equal. - * - * @param value1 The left-hand side of the encoded {@link String#equals(Object)}. - * @param value2 The right-hand side of the encoded {@link String#equals(Object)}. - * @return <code>true</code> if the encoded <code>String</code>s are equal; - * <code>false</code> otherwise. - * @see #isDoubleMetaphoneEqual(String,String,boolean) - */ - public boolean isDoubleMetaphoneEqual(String value1, String value2) { - return isDoubleMetaphoneEqual(value1, value2, false); - } - - /** - * Check if the Double Metaphone values of two <code>String</code> values - * are equal, optionally using the alternate value. - * - * @param value1 The left-hand side of the encoded {@link String#equals(Object)}. - * @param value2 The right-hand side of the encoded {@link String#equals(Object)}. - * @param alternate use the alternate value if <code>true</code>. - * @return <code>true</code> if the encoded <code>String</code>s are equal; - * <code>false</code> otherwise. - */ - public boolean isDoubleMetaphoneEqual(String value1, - String value2, - boolean alternate) { - return doubleMetaphone(value1, alternate).equals(doubleMetaphone - (value2, alternate)); - } - - /** - * Returns the maxCodeLen. - * @return int - */ - public int getMaxCodeLen() { - return this.maxCodeLen; - } - - /** - * Sets the maxCodeLen. - * @param maxCodeLen The maxCodeLen to set - */ - public void setMaxCodeLen(int maxCodeLen) { - this.maxCodeLen = maxCodeLen; - } - - //-- BEGIN HANDLERS --// - - /** - * Handles 'A', 'E', 'I', 'O', 'U', and 'Y' cases - */ - private int handleAEIOUY(String value, DoubleMetaphoneResult result, int - index) { - if (index == 0) { - result.append('A'); - } - return index + 1; - } - - /** - * Handles 'C' cases - */ - private int handleC(String value, - DoubleMetaphoneResult result, - int index) { - if (conditionC0(value, index)) { // very confusing, moved out - result.append('K'); - index += 2; - } else if (index == 0 && contains(value, index, 6, "CAESAR")) { - result.append('S'); - index += 2; - } else if (contains(value, index, 2, "CH")) { - index = handleCH(value, result, index); - } else if (contains(value, index, 2, "CZ") && - !contains(value, index - 2, 4, "WICZ")) { - //-- "Czerny" --// - result.append('S', 'X'); - index += 2; - } else if (contains(value, index + 1, 3, "CIA")) { - //-- "focaccia" --// - result.append('X'); - index += 3; - } else if (contains(value, index, 2, "CC") && - !(index == 1 && charAt(value, 0) == 'M')) { - //-- double "cc" but not "McClelland" --// - return handleCC(value, result, index); - } else if (contains(value, index, 2, "CK", "CG", "CQ")) { - result.append('K'); - index += 2; - } else if (contains(value, index, 2, "CI", "CE", "CY")) { - //-- Italian vs. English --// - if (contains(value, index, 3, "CIO", "CIE", "CIA")) { - result.append('S', 'X'); - } else { - result.append('S'); - } - index += 2; - } else { - result.append('K'); - if (contains(value, index + 1, 2, " C", " Q", " G")) { - //-- Mac Caffrey, Mac Gregor --// - index += 3; - } else if (contains(value, index + 1, 1, "C", "K", "Q") && - !contains(value, index + 1, 2, "CE", "CI")) { - index += 2; - } else { - index++; - } - } - - return index; - } - - /** - * Handles 'CC' cases - */ - private int handleCC(String value, - DoubleMetaphoneResult result, - int index) { - if (contains(value, index + 2, 1, "I", "E", "H") && - !contains(value, index + 2, 2, "HU")) { - //-- "bellocchio" but not "bacchus" --// - if ((index == 1 && charAt(value, index - 1) == 'A') || - contains(value, index - 1, 5, "UCCEE", "UCCES")) { - //-- "accident", "accede", "succeed" --// - result.append("KS"); - } else { - //-- "bacci", "bertucci", other Italian --// - result.append('X'); - } - index += 3; - } else { // Pierce's rule - result.append('K'); - index += 2; - } - - return index; - } - - /** - * Handles 'CH' cases - */ - private int handleCH(String value, - DoubleMetaphoneResult result, - int index) { - if (index > 0 && contains(value, index, 4, "CHAE")) { // Michael - result.append('K', 'X'); - return index + 2; - } else if (conditionCH0(value, index)) { - //-- Greek roots ("chemistry", "chorus", etc.) --// - result.append('K'); - return index + 2; - } else if (conditionCH1(value, index)) { - //-- Germanic, Greek, or otherwise 'ch' for 'kh' sound --// - result.append('K'); - return index + 2; - } else { - if (index > 0) { - if (contains(value, 0, 2, "MC")) { - result.append('K'); - } else { - result.append('X', 'K'); - } - } else { - result.append('X'); - } - return index + 2; - } - } - - /** - * Handles 'D' cases - */ - private int handleD(String value, - DoubleMetaphoneResult result, - int index) { - if (contains(value, index, 2, "DG")) { - //-- "Edge" --// - if (contains(value, index + 2, 1, "I", "E", "Y")) { - result.append('J'); - index += 3; - //-- "Edgar" --// - } else { - result.append("TK"); - index += 2; - } - } else if (contains(value, index, 2, "DT", "DD")) { - result.append('T'); - index += 2; - } else { - result.append('T'); - index++; - } - return index; - } - - /** - * Handles 'G' cases - */ - private int handleG(String value, - DoubleMetaphoneResult result, - int index, - boolean slavoGermanic) { - if (charAt(value, index + 1) == 'H') { - index = handleGH(value, result, index); - } else if (charAt(value, index + 1) == 'N') { - if (index == 1 && isVowel(charAt(value, 0)) && !slavoGermanic) { - result.append("KN", "N"); - } else if (!contains(value, index + 2, 2, "EY") && - charAt(value, index + 1) != 'Y' && !slavoGermanic) { - result.append("N", "KN"); - } else { - result.append("KN"); - } - index = index + 2; - } else if (contains(value, index + 1, 2, "LI") && !slavoGermanic) { - result.append("KL", "L"); - index += 2; - } else if (index == 0 && (charAt(value, index + 1) == 'Y' || contains(value, index + 1, 2, ES_EP_EB_EL_EY_IB_IL_IN_IE_EI_ER))) { - //-- -ges-, -gep-, -gel-, -gie- at beginning --// - result.append('K', 'J'); - index += 2; - } else if ((contains(value, index + 1, 2, "ER") || - charAt(value, index + 1) == 'Y') && - !contains(value, 0, 6, "DANGER", "RANGER", "MANGER") && - !contains(value, index - 1, 1, "E", "I") && - !contains(value, index - 1, 3, "RGY", "OGY")) { - //-- -ger-, -gy- --// - result.append('K', 'J'); - index += 2; - } else if (contains(value, index + 1, 1, "E", "I", "Y") || - contains(value, index - 1, 4, "AGGI", "OGGI")) { - //-- Italian "biaggi" --// - if ((contains(value, 0 ,4, "VAN ", "VON ") || contains(value, 0, 3, "SCH")) || contains(value, index + 1, 2, "ET")) { - //-- obvious germanic --// - result.append('K'); - } else if (contains(value, index + 1, 4, "IER")) { - result.append('J'); - } else { - result.append('J', 'K'); - } - index += 2; - } else if (charAt(value, index + 1) == 'G') { - index += 2; - result.append('K'); - } else { - index++; - result.append('K'); - } - return index; - } - - /** - * Handles 'GH' cases - */ - private int handleGH(String value, - DoubleMetaphoneResult result, - int index) { - if (index > 0 && !isVowel(charAt(value, index - 1))) { - result.append('K'); - index += 2; - } else if (index == 0) { - if (charAt(value, index + 2) == 'I') { - result.append('J'); - } else { - result.append('K'); - } - index += 2; - } else if ((index > 1 && contains(value, index - 2, 1, "B", "H", "D")) || - (index > 2 && contains(value, index - 3, 1, "B", "H", "D")) || - (index > 3 && contains(value, index - 4, 1, "B", "H"))) { - //-- Parker's rule (with some further refinements) - "hugh" - index += 2; - } else { - if (index > 2 && charAt(value, index - 1) == 'U' && - contains(value, index - 3, 1, "C", "G", "L", "R", "T")) { - //-- "laugh", "McLaughlin", "cough", "gough", "rough", "tough" - result.append('F'); - } else if (index > 0 && charAt(value, index - 1) != 'I') { - result.append('K'); - } - index += 2; - } - return index; - } - - /** - * Handles 'H' cases - */ - private int handleH(String value, - DoubleMetaphoneResult result, - int index) { - //-- only keep if first & before vowel or between 2 vowels --// - if ((index == 0 || isVowel(charAt(value, index - 1))) && - isVowel(charAt(value, index + 1))) { - result.append('H'); - index += 2; - //-- also takes car of "HH" --// - } else { - index++; - } - return index; - } - - /** - * Handles 'J' cases - */ - private int handleJ(String value, DoubleMetaphoneResult result, int index, - boolean slavoGermanic) { - if (contains(value, index, 4, "JOSE") || contains(value, 0, 4, "SAN ")) { - //-- obvious Spanish, "Jose", "San Jacinto" --// - if ((index == 0 && (charAt(value, index + 4) == ' ') || - value.length() == 4) || contains(value, 0, 4, "SAN ")) { - result.append('H'); - } else { - result.append('J', 'H'); - } - index++; - } else { - if (index == 0 && !contains(value, index, 4, "JOSE")) { - result.append('J', 'A'); - } else if (isVowel(charAt(value, index - 1)) && !slavoGermanic && - (charAt(value, index + 1) == 'A' || charAt(value, index + 1) == 'O')) { - result.append('J', 'H'); - } else if (index == value.length() - 1) { - result.append('J', ' '); - } else if (!contains(value, index + 1, 1, L_T_K_S_N_M_B_Z) && !contains(value, index - 1, 1, "S", "K", "L")) { - result.append('J'); - } - - if (charAt(value, index + 1) == 'J') { - index += 2; - } else { - index++; - } - } - return index; - } - - /** - * Handles 'L' cases - */ - private int handleL(String value, - DoubleMetaphoneResult result, - int index) { - result.append('L'); - if (charAt(value, index + 1) == 'L') { - if (conditionL0(value, index)) { - result.appendAlternate(' '); - } - index += 2; - } else { - index++; - } - return index; - } - - /** - * Handles 'P' cases - */ - private int handleP(String value, - DoubleMetaphoneResult result, - int index) { - if (charAt(value, index + 1) == 'H') { - result.append('F'); - index += 2; - } else { - result.append('P'); - index = contains(value, index + 1, 1, "P", "B") ? index + 2 : index + 1; - } - return index; - } - - /** - * Handles 'R' cases - */ - private int handleR(String value, - DoubleMetaphoneResult result, - int index, - boolean slavoGermanic) { - if (index == value.length() - 1 && !slavoGermanic && - contains(value, index - 2, 2, "IE") && - !contains(value, index - 4, 2, "ME", "MA")) { - result.appendAlternate('R'); - } else { - result.append('R'); - } - return charAt(value, index + 1) == 'R' ? index + 2 : index + 1; - } - - /** - * Handles 'S' cases - */ - private int handleS(String value, - DoubleMetaphoneResult result, - int index, - boolean slavoGermanic) { - if (contains(value, index - 1, 3, "ISL", "YSL")) { - //-- special cases "island", "isle", "carlisle", "carlysle" --// - index++; - } else if (index == 0 && contains(value, index, 5, "SUGAR")) { - //-- special case "sugar-" --// - result.append('X', 'S'); - index++; - } else if (contains(value, index, 2, "SH")) { - if (contains(value, index + 1, 4, - "HEIM", "HOEK", "HOLM", "HOLZ")) { - //-- germanic --// - result.append('S'); - } else { - result.append('X'); - } - index += 2; - } else if (contains(value, index, 3, "SIO", "SIA") || contains(value, index, 4, "SIAN")) { - //-- Italian and Armenian --// - if (slavoGermanic) { - result.append('S'); - } else { - result.append('S', 'X'); - } - index += 3; - } else if ((index == 0 && contains(value, index + 1, 1, "M", "N", "L", "W")) || contains(value, index + 1, 1, "Z")) { - //-- german & anglicisations, e.g. "smith" match "schmidt" // - // "snider" match "schneider" --// - //-- also, -sz- in slavic language altho in hungarian it // - // is pronounced "s" --// - result.append('S', 'X'); - index = contains(value, index + 1, 1, "Z") ? index + 2 : index + 1; - } else if (contains(value, index, 2, "SC")) { - index = handleSC(value, result, index); - } else { - if (index == value.length() - 1 && contains(value, index - 2, - 2, "AI", "OI")){ - //-- french e.g. "resnais", "artois" --// - result.appendAlternate('S'); - } else { - result.append('S'); - } - index = contains(value, index + 1, 1, "S", "Z") ? index + 2 : index + 1; - } - return index; - } - - /** - * Handles 'SC' cases - */ - private int handleSC(String value, - DoubleMetaphoneResult result, - int index) { - if (charAt(value, index + 2) == 'H') { - //-- Schlesinger's rule --// - if (contains(value, index + 3, - 2, "OO", "ER", "EN", "UY", "ED", "EM")) { - //-- Dutch origin, e.g. "school", "schooner" --// - if (contains(value, index + 3, 2, "ER", "EN")) { - //-- "schermerhorn", "schenker" --// - result.append("X", "SK"); - } else { - result.append("SK"); - } - } else { - if (index == 0 && !isVowel(charAt(value, 3)) && charAt(value, 3) != 'W') { - result.append('X', 'S'); - } else { - result.append('X'); - } - } - } else if (contains(value, index + 2, 1, "I", "E", "Y")) { - result.append('S'); - } else { - result.append("SK"); - } - return index + 3; - } - - /** - * Handles 'T' cases - */ - private int handleT(String value, - DoubleMetaphoneResult result, - int index) { - if (contains(value, index, 4, "TION")) { - result.append('X'); - index += 3; - } else if (contains(value, index, 3, "TIA", "TCH")) { - result.append('X'); - index += 3; - } else if (contains(value, index, 2, "TH") || contains(value, index, - 3, "TTH")) { - if (contains(value, index + 2, 2, "OM", "AM") || - //-- special case "thomas", "thames" or germanic --// - contains(value, 0, 4, "VAN ", "VON ") || - contains(value, 0, 3, "SCH")) { - result.append('T'); - } else { - result.append('0', 'T'); - } - index += 2; - } else { - result.append('T'); - index = contains(value, index + 1, 1, "T", "D") ? index + 2 : index + 1; - } - return index; - } - - /** - * Handles 'W' cases - */ - private int handleW(String value, - DoubleMetaphoneResult result, - int index) { - if (contains(value, index, 2, "WR")) { - //-- can also be in middle of word --// - result.append('R'); - index += 2; - } else { - if (index == 0 && (isVowel(charAt(value, index + 1)) || - contains(value, index, 2, "WH"))) { - if (isVowel(charAt(value, index + 1))) { - //-- Wasserman should match Vasserman --// - result.append('A', 'F'); - } else { - //-- need Uomo to match Womo --// - result.append('A'); - } - index++; - } else if ((index == value.length() - 1 && isVowel(charAt(value, index - 1))) || - contains(value, index - 1, - 5, "EWSKI", "EWSKY", "OWSKI", "OWSKY") || - contains(value, 0, 3, "SCH")) { - //-- Arnow should match Arnoff --// - result.appendAlternate('F'); - index++; - } else if (contains(value, index, 4, "WICZ", "WITZ")) { - //-- Polish e.g. "filipowicz" --// - result.append("TS", "FX"); - index += 4; - } else { - index++; - } - } - return index; - } - - /** - * Handles 'X' cases - */ - private int handleX(String value, - DoubleMetaphoneResult result, - int index) { - if (index == 0) { - result.append('S'); - index++; - } else { - if (!((index == value.length() - 1) && - (contains(value, index - 3, 3, "IAU", "EAU") || - contains(value, index - 2, 2, "AU", "OU")))) { - //-- French e.g. breaux --// - result.append("KS"); - } - index = contains(value, index + 1, 1, "C", "X") ? index + 2 : index + 1; - } - return index; - } - - /** - * Handles 'Z' cases - */ - private int handleZ(String value, DoubleMetaphoneResult result, int index, - boolean slavoGermanic) { - if (charAt(value, index + 1) == 'H') { - //-- Chinese pinyin e.g. "zhao" or Angelina "Zhang" --// - result.append('J'); - index += 2; - } else { - if (contains(value, index + 1, 2, "ZO", "ZI", "ZA") || (slavoGermanic && (index > 0 && charAt(value, index - 1) != 'T'))) { - result.append("S", "TS"); - } else { - result.append('S'); - } - index = charAt(value, index + 1) == 'Z' ? index + 2 : index + 1; - } - return index; - } - - //-- BEGIN CONDITIONS --// - - /** - * Complex condition 0 for 'C' - */ - private boolean conditionC0(String value, int index) { - if (contains(value, index, 4, "CHIA")) { - return true; - } else if (index <= 1) { - return false; - } else if (isVowel(charAt(value, index - 2))) { - return false; - } else if (!contains(value, index - 1, 3, "ACH")) { - return false; - } else { - char c = charAt(value, index + 2); - return (c != 'I' && c != 'E') - || contains(value, index - 2, 6, "BACHER", "MACHER"); - } - } - - /** - * Complex condition 0 for 'CH' - */ - private boolean conditionCH0(String value, int index) { - if (index != 0) { - return false; - } else if (!contains(value, index + 1, 5, "HARAC", "HARIS") && - !contains(value, index + 1, 3, "HOR", "HYM", "HIA", "HEM")) { - return false; - } else if (contains(value, 0, 5, "CHORE")) { - return false; - } else { - return true; - } - } - - /** - * Complex condition 1 for 'CH' - */ - private boolean conditionCH1(String value, int index) { - return ((contains(value, 0, 4, "VAN ", "VON ") || contains(value, 0, - 3, "SCH")) || - contains(value, index - 2, 6, "ORCHES", "ARCHIT", "ORCHID") || - contains(value, index + 2, 1, "T", "S") || - ((contains(value, index - 1, 1, "A", "O", "U", "E") || index == 0) && - (contains(value, index + 2, 1, L_R_N_M_B_H_F_V_W_SPACE) || index + 1 == value.length() - 1))); - } - - /** - * Complex condition 0 for 'L' - */ - private boolean conditionL0(String value, int index) { - if (index == value.length() - 3 && - contains(value, index - 1, 4, "ILLO", "ILLA", "ALLE")) { - return true; - } else if ((contains(value, index - 1, 2, "AS", "OS") || - contains(value, value.length() - 1, 1, "A", "O")) && - contains(value, index - 1, 4, "ALLE")) { - return true; - } else { - return false; - } - } - - /** - * Complex condition 0 for 'M' - */ - private boolean conditionM0(String value, int index) { - if (charAt(value, index + 1) == 'M') { - return true; - } - return contains(value, index - 1, 3, "UMB") - && ((index + 1) == value.length() - 1 || contains(value, - index + 2, 2, "ER")); - } - - //-- BEGIN HELPER FUNCTIONS --// - - /** - * Determines whether or not a value is of slavo-germanic orgin. A value is - * of slavo-germanic origin if it contians any of 'W', 'K', 'CZ', or 'WITZ'. - */ - private boolean isSlavoGermanic(String value) { - return value.indexOf('W') > -1 || value.indexOf('K') > -1 || - value.indexOf("CZ") > -1 || value.indexOf("WITZ") > -1; - } - - /** - * Determines whether or not a character is a vowel or not - */ - private boolean isVowel(char ch) { - return VOWELS.indexOf(ch) != -1; - } - - /** - * Determines whether or not the value starts with a silent letter. It will - * return <code>true</code> if the value starts with any of 'GN', 'KN', - * 'PN', 'WR' or 'PS'. - */ - private boolean isSilentStart(String value) { - boolean result = false; - for (int i = 0; i < SILENT_START.length; i++) { - if (value.startsWith(SILENT_START[i])) { - result = true; - break; - } - } - return result; - } - - /** - * Cleans the input - */ - private String cleanInput(String input) { - if (input == null) { - return null; - } - input = input.trim(); - if (input.length() == 0) { - return null; - } - return input.toUpperCase(); - } - - /** - * Gets the character at index <code>index</code> if available, otherwise - * it returns <code>Character.MIN_VALUE</code> so that there is some sort - * of a default - */ - protected char charAt(String value, int index) { - if (index < 0 || index >= value.length()) { - return Character.MIN_VALUE; - } - return value.charAt(index); - } - - /** - * Shortcut method with 1 criteria - */ - private static boolean contains(String value, int start, int length, - String criteria) { - return contains(value, start, length, - new String[] { criteria }); - } - - /** - * Shortcut method with 2 criteria - */ - private static boolean contains(String value, int start, int length, - String criteria1, String criteria2) { - return contains(value, start, length, - new String[] { criteria1, criteria2 }); - } - - /** - * Shortcut method with 3 criteria - */ - private static boolean contains(String value, int start, int length, - String criteria1, String criteria2, - String criteria3) { - return contains(value, start, length, - new String[] { criteria1, criteria2, criteria3 }); - } - - /** - * Shortcut method with 4 criteria - */ - private static boolean contains(String value, int start, int length, - String criteria1, String criteria2, - String criteria3, String criteria4) { - return contains(value, start, length, - new String[] { criteria1, criteria2, criteria3, - criteria4 }); - } - - /** - * Shortcut method with 5 criteria - */ - private static boolean contains(String value, int start, int length, - String criteria1, String criteria2, - String criteria3, String criteria4, - String criteria5) { - return contains(value, start, length, - new String[] { criteria1, criteria2, criteria3, - criteria4, criteria5 }); - } - - /** - * Shortcut method with 6 criteria - */ - private static boolean contains(String value, int start, int length, - String criteria1, String criteria2, - String criteria3, String criteria4, - String criteria5, String criteria6) { - return contains(value, start, length, - new String[] { criteria1, criteria2, criteria3, - criteria4, criteria5, criteria6 }); - } - - /** - * Determines whether <code>value</code> contains any of the criteria - starting - * at index <code>start</code> and matching up to length <code>length</code> - */ - protected static boolean contains(String value, int start, int length, - String[] criteria) { - boolean result = false; - if (start >= 0 && start + length <= value.length()) { - String target = value.substring(start, start + length); - - for (int i = 0; i < criteria.length; i++) { - if (target.equals(criteria[i])) { - result = true; - break; - } - } - } - return result; - } - - //-- BEGIN INNER CLASSES --// - - /** - * Inner class for storing results, since there is the optional alternate - * encoding. - */ - public class DoubleMetaphoneResult { - - private StringBuffer primary = new StringBuffer(getMaxCodeLen()); - private StringBuffer alternate = new StringBuffer(getMaxCodeLen()); - private int maxLength; - - public DoubleMetaphoneResult(int maxLength) { - this.maxLength = maxLength; - } - - public void append(char value) { - appendPrimary(value); - appendAlternate(value); - } - - public void append(char primary, char alternate) { - appendPrimary(primary); - appendAlternate(alternate); - } - - public void appendPrimary(char value) { - if (this.primary.length() < this.maxLength) { - this.primary.append(value); - } - } - - public void appendAlternate(char value) { - if (this.alternate.length() < this.maxLength) { - this.alternate.append(value); - } - } - - public void append(String value) { - appendPrimary(value); - appendAlternate(value); - } - - public void append(String primary, String alternate) { - appendPrimary(primary); - appendAlternate(alternate); - } - - public void appendPrimary(String value) { - int addChars = this.maxLength - this.primary.length(); - if (value.length() <= addChars) { - this.primary.append(value); - } else { - this.primary.append(value.substring(0, addChars)); - } - } - - public void appendAlternate(String value) { - int addChars = this.maxLength - this.alternate.length(); - if (value.length() <= addChars) { - this.alternate.append(value); - } else { - this.alternate.append(value.substring(0, addChars)); - } - } - - public String getPrimary() { - return this.primary.toString(); - } - - public String getAlternate() { - return this.alternate.toString(); - } - - public boolean isComplete() { - return this.primary.length() >= this.maxLength && - this.alternate.length() >= this.maxLength; - } - } -} diff --git a/src/org/apache/commons/codec/language/Metaphone.java b/src/org/apache/commons/codec/language/Metaphone.java deleted file mode 100644 index dce2c72..0000000 --- a/src/org/apache/commons/codec/language/Metaphone.java +++ /dev/null @@ -1,399 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.codec.language; - -import org.apache.commons.codec.EncoderException; -import org.apache.commons.codec.StringEncoder; - -/** - * Encodes a string into a metaphone value. - * <p> - * Initial Java implementation by <CITE>William B. Brogden. December, 1997</CITE>. - * Permission given by <CITE>wbrogden</CITE> for code to be used anywhere. - * </p> - * <p> - * <CITE>Hanging on the Metaphone</CITE> by <CITE>Lawrence Philips</CITE> in <CITE>Computer Language of Dec. 1990, p - * 39.</CITE> - * </p> - * - * @author Apache Software Foundation - * @version $Id: Metaphone.java,v 1.20 2004/06/05 18:32:04 ggregory Exp $ - */ -public class Metaphone implements StringEncoder { - - /** - * Five values in the English language - */ - private String vowels = "AEIOU" ; - - /** - * Variable used in Metaphone algorithm - */ - private String frontv = "EIY" ; - - /** - * Variable used in Metaphone algorithm - */ - private String varson = "CSPTG" ; - - /** - * The max code length for metaphone is 4 - */ - private int maxCodeLen = 4 ; - - /** - * Creates an instance of the Metaphone encoder - */ - public Metaphone() { - super(); - } - - /** - * Find the metaphone value of a String. This is similar to the - * soundex algorithm, but better at finding similar sounding words. - * All input is converted to upper case. - * Limitations: Input format is expected to be a single ASCII word - * with only characters in the A - Z range, no punctuation or numbers. - * - * @param txt String to find the metaphone code for - * @return A metaphone code corresponding to the String supplied - */ - public String metaphone(String txt) { - boolean hard = false ; - if ((txt == null) || (txt.length() == 0)) { - return "" ; - } - // single character is itself - if (txt.length() == 1) { - return txt.toUpperCase() ; - } - - char[] inwd = txt.toUpperCase().toCharArray() ; - - StringBuffer local = new StringBuffer(40); // manipulate - StringBuffer code = new StringBuffer(10) ; // output - // handle initial 2 characters exceptions - switch(inwd[0]) { - case 'K' : - case 'G' : - case 'P' : /* looking for KN, etc*/ - if (inwd[1] == 'N') { - local.append(inwd, 1, inwd.length - 1); - } else { - local.append(inwd); - } - break; - case 'A': /* looking for AE */ - if (inwd[1] == 'E') { - local.append(inwd, 1, inwd.length - 1); - } else { - local.append(inwd); - } - break; - case 'W' : /* looking for WR or WH */ - if (inwd[1] == 'R') { // WR -> R - local.append(inwd, 1, inwd.length - 1); - break ; - } - if (inwd[1] == 'H') { - local.append(inwd, 1, inwd.length - 1); - local.setCharAt(0, 'W'); // WH -> W - } else { - local.append(inwd); - } - break; - case 'X' : /* initial X becomes S */ - inwd[0] = 'S'; - local.append(inwd); - break ; - default : - local.append(inwd); - } // now local has working string with initials fixed - - int wdsz = local.length(); - int n = 0 ; - - while ((code.length() < this.getMaxCodeLen()) && - (n < wdsz) ) { // max code size of 4 works well - char symb = local.charAt(n) ; - // remove duplicate letters except C - if ((symb != 'C') && (isPreviousChar( local, n, symb )) ) { - n++ ; - } else { // not dup - switch(symb) { - case 'A' : case 'E' : case 'I' : case 'O' : case 'U' : - if (n == 0) { - code.append(symb); - } - break ; // only use vowel if leading char - case 'B' : - if ( isPreviousChar(local, n, 'M') && - isLastChar(wdsz, n) ) { // B is silent if word ends in MB - break; - } - code.append(symb); - break; - case 'C' : // lots of C special cases - /* discard if SCI, SCE or SCY */ - if ( isPreviousChar(local, n, 'S') && - !isLastChar(wdsz, n) && - (this.frontv.indexOf(local.charAt(n + 1)) >= 0) ) { - break; - } - if (regionMatch(local, n, "CIA")) { // "CIA" -> X - code.append('X'); - break; - } - if (!isLastChar(wdsz, n) && - (this.frontv.indexOf(local.charAt(n + 1)) >= 0)) { - code.append('S'); - break; // CI,CE,CY -> S - } - if (isPreviousChar(local, n, 'S') && - isNextChar(local, n, 'H') ) { // SCH->sk - code.append('K') ; - break ; - } - if (isNextChar(local, n, 'H')) { // detect CH - if ((n == 0) && - (wdsz >= 3) && - isVowel(local,2) ) { // CH consonant -> K consonant - code.append('K'); - } else { - code.append('X'); // CHvowel -> X - } - } else { - code.append('K'); - } - break ; - case 'D' : - if (!isLastChar(wdsz, n + 1) && - isNextChar(local, n, 'G') && - (this.frontv.indexOf(local.charAt(n + 2)) >= 0)) { // DGE DGI DGY -> J - code.append('J'); n += 2 ; - } else { - code.append('T'); - } - break ; - case 'G' : // GH silent at end or before consonant - if (isLastChar(wdsz, n + 1) && - isNextChar(local, n, 'H')) { - break; - } - if (!isLastChar(wdsz, n + 1) && - isNextChar(local,n,'H') && - !isVowel(local,n+2)) { - break; - } - if ((n > 0) && - ( regionMatch(local, n, "GN") || - regionMatch(local, n, "GNED") ) ) { - break; // silent G - } - if (isPreviousChar(local, n, 'G')) { - hard = true ; - } else { - hard = false ; - } - if (!isLastChar(wdsz, n) && - (this.frontv.indexOf(local.charAt(n + 1)) >= 0) && - (!hard)) { - code.append('J'); - } else { - code.append('K'); - } - break ; - case 'H': - if (isLastChar(wdsz, n)) { - break ; // terminal H - } - if ((n > 0) && - (this.varson.indexOf(local.charAt(n - 1)) >= 0)) { - break; - } - if (isVowel(local,n+1)) { - code.append('H'); // Hvowel - } - break; - case 'F': - case 'J' : - case 'L' : - case 'M': - case 'N' : - case 'R' : - code.append(symb); - break; - case 'K' : - if (n > 0) { // not initial - if (!isPreviousChar(local, n, 'C')) { - code.append(symb); - } - } else { - code.append(symb); // initial K - } - break ; - case 'P' : - if (isNextChar(local,n,'H')) { - // PH -> F - code.append('F'); - } else { - code.append(symb); - } - break ; - case 'Q' : - code.append('K'); - break; - case 'S' : - if (regionMatch(local,n,"SH") || - regionMatch(local,n,"SIO") || - regionMatch(local,n,"SIA")) { - code.append('X'); - } else { - code.append('S'); - } - break; - case 'T' : - if (regionMatch(local,n,"TIA") || - regionMatch(local,n,"TIO")) { - code.append('X'); - break; - } - if (regionMatch(local,n,"TCH")) { - // Silent if in "TCH" - break; - } - // substitute numeral 0 for TH (resembles theta after all) - if (regionMatch(local,n,"TH")) { - code.append('0'); - } else { - code.append('T'); - } - break ; - case 'V' : - code.append('F'); break ; - case 'W' : case 'Y' : // silent if not followed by vowel - if (!isLastChar(wdsz,n) && - isVowel(local,n+1)) { - code.append(symb); - } - break ; - case 'X' : - code.append('K'); code.append('S'); - break ; - case 'Z' : - code.append('S'); break ; - } // end switch - n++ ; - } // end else from symb != 'C' - if (code.length() > this.getMaxCodeLen()) { - code.setLength(this.getMaxCodeLen()); - } - } - return code.toString(); - } - - private boolean isVowel(StringBuffer string, int index) { - return (this.vowels.indexOf(string.charAt(index)) >= 0); - } - - private boolean isPreviousChar(StringBuffer string, int index, char c) { - boolean matches = false; - if( index > 0 && - index < string.length() ) { - matches = string.charAt(index - 1) == c; - } - return matches; - } - - private boolean isNextChar(StringBuffer string, int index, char c) { - boolean matches = false; - if( index >= 0 && - index < string.length() - 1 ) { - matches = string.charAt(index + 1) == c; - } - return matches; - } - - private boolean regionMatch(StringBuffer string, int index, String test) { - boolean matches = false; - if( index >= 0 && - (index + test.length() - 1) < string.length() ) { - String substring = string.substring( index, index + test.length()); - matches = substring.equals( test ); - } - return matches; - } - - private boolean isLastChar(int wdsz, int n) { - return n + 1 == wdsz; - } - - - /** - * Encodes an Object using the metaphone algorithm. This method - * is provided in order to satisfy the requirements of the - * Encoder interface, and will throw an EncoderException if the - * supplied object is not of type java.lang.String. - * - * @param pObject Object to encode - * @return An object (or type java.lang.String) containing the - * metaphone code which corresponds to the String supplied. - * @throws EncoderException if the parameter supplied is not - * of type java.lang.String - */ - public Object encode(Object pObject) throws EncoderException { - if (!(pObject instanceof java.lang.String)) { - throw new EncoderException("Parameter supplied to Metaphone encode is not of type java.lang.String"); - } - return metaphone((String) pObject); - } - - /** - * Encodes a String using the Metaphone algorithm. - * - * @param pString String object to encode - * @return The metaphone code corresponding to the String supplied - */ - public String encode(String pString) { - return metaphone(pString); - } - - /** - * Tests is the metaphones of two strings are identical. - * - * @param str1 First of two strings to compare - * @param str2 Second of two strings to compare - * @return true if the metaphones of these strings are identical, - * false otherwise. - */ - public boolean isMetaphoneEqual(String str1, String str2) { - return metaphone(str1).equals(metaphone(str2)); - } - - /** - * Returns the maxCodeLen. - * @return int - */ - public int getMaxCodeLen() { return this.maxCodeLen; } - - /** - * Sets the maxCodeLen. - * @param maxCodeLen The maxCodeLen to set - */ - public void setMaxCodeLen(int maxCodeLen) { this.maxCodeLen = maxCodeLen; } - -} diff --git a/src/org/apache/commons/codec/language/RefinedSoundex.java b/src/org/apache/commons/codec/language/RefinedSoundex.java deleted file mode 100644 index dbf60fe..0000000 --- a/src/org/apache/commons/codec/language/RefinedSoundex.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.codec.language; - -import org.apache.commons.codec.EncoderException; -import org.apache.commons.codec.StringEncoder; - -/** - * Encodes a string into a Refined Soundex value. A refined soundex code is - * optimized for spell checking words. Soundex method originally developed by - * <CITE>Margaret Odell</CITE> and <CITE>Robert Russell</CITE>. - * - * @author Apache Software Foundation - * @version $Id: RefinedSoundex.java,v 1.21 2004/06/05 18:32:04 ggregory Exp $ - */ -public class RefinedSoundex implements StringEncoder { - - /** - * This static variable contains an instance of the RefinedSoundex using - * the US_ENGLISH mapping. - */ - public static final RefinedSoundex US_ENGLISH = new RefinedSoundex(); - - /** - * RefinedSoundex is *refined* for a number of reasons one being that the - * mappings have been altered. This implementation contains default - * mappings for US English. - */ - public static final char[] US_ENGLISH_MAPPING = "01360240043788015936020505".toCharArray(); - - /** - * Every letter of the alphabet is "mapped" to a numerical value. This char - * array holds the values to which each letter is mapped. This - * implementation contains a default map for US_ENGLISH - */ - private char[] soundexMapping; - - /** - * Creates an instance of the RefinedSoundex object using the default US - * English mapping. - */ - public RefinedSoundex() { - this(US_ENGLISH_MAPPING); - } - - /** - * Creates a refined soundex instance using a custom mapping. This - * constructor can be used to customize the mapping, and/or possibly - * provide an internationalized mapping for a non-Western character set. - * - * @param mapping - * Mapping array to use when finding the corresponding code for - * a given character - */ - public RefinedSoundex(char[] mapping) { - this.soundexMapping = mapping; - } - - // BEGIN android-note - // Removed @see reference to SoundexUtils below, since the class isn't - // public. - // END android-note - /** - * Returns the number of characters in the two encoded Strings that are the - * same. This return value ranges from 0 to the length of the shortest - * encoded String: 0 indicates little or no similarity, and 4 out of 4 (for - * example) indicates strong similarity or identical values. For refined - * Soundex, the return value can be greater than 4. - * - * @param s1 - * A String that will be encoded and compared. - * @param s2 - * A String that will be encoded and compared. - * @return The number of characters in the two encoded Strings that are the - * same from 0 to to the length of the shortest encoded String. - * - * @see <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_de-dz_8co5.asp"> - * MS T-SQL DIFFERENCE</a> - * - * @throws EncoderException - * if an error occurs encoding one of the strings - * @since 1.3 - */ - public int difference(String s1, String s2) throws EncoderException { - return SoundexUtils.difference(this, s1, s2); - } - - /** - * Encodes an Object using the refined soundex algorithm. This method is - * provided in order to satisfy the requirements of the Encoder interface, - * and will throw an EncoderException if the supplied object is not of type - * java.lang.String. - * - * @param pObject - * Object to encode - * @return An object (or type java.lang.String) containing the refined - * soundex code which corresponds to the String supplied. - * @throws EncoderException - * if the parameter supplied is not of type java.lang.String - */ - public Object encode(Object pObject) throws EncoderException { - if (!(pObject instanceof java.lang.String)) { - throw new EncoderException("Parameter supplied to RefinedSoundex encode is not of type java.lang.String"); - } - return soundex((String) pObject); - } - - /** - * Encodes a String using the refined soundex algorithm. - * - * @param pString - * A String object to encode - * @return A Soundex code corresponding to the String supplied - */ - public String encode(String pString) { - return soundex(pString); - } - - /** - * Returns the mapping code for a given character. The mapping codes are - * maintained in an internal char array named soundexMapping, and the - * default values of these mappings are US English. - * - * @param c - * char to get mapping for - * @return A character (really a numeral) to return for the given char - */ - char getMappingCode(char c) { - if (!Character.isLetter(c)) { - return 0; - } - return this.soundexMapping[Character.toUpperCase(c) - 'A']; - } - - /** - * Retreives the Refined Soundex code for a given String object. - * - * @param str - * String to encode using the Refined Soundex algorithm - * @return A soundex code for the String supplied - */ - public String soundex(String str) { - if (str == null) { - return null; - } - str = SoundexUtils.clean(str); - if (str.length() == 0) { - return str; - } - - StringBuffer sBuf = new StringBuffer(); - sBuf.append(str.charAt(0)); - - char last, current; - last = '*'; - - for (int i = 0; i < str.length(); i++) { - - current = getMappingCode(str.charAt(i)); - if (current == last) { - continue; - } else if (current != 0) { - sBuf.append(current); - } - - last = current; - - } - - return sBuf.toString(); - } -} diff --git a/src/org/apache/commons/codec/language/Soundex.java b/src/org/apache/commons/codec/language/Soundex.java deleted file mode 100644 index 61ce440..0000000 --- a/src/org/apache/commons/codec/language/Soundex.java +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.codec.language; - -import org.apache.commons.codec.EncoderException; -import org.apache.commons.codec.StringEncoder; - -/** - * Encodes a string into a Soundex value. Soundex is an encoding used to relate similar names, but can also be used as a - * general purpose scheme to find word with similar phonemes. - * - * @author Apache Software Foundation - * @version $Id: Soundex.java,v 1.26 2004/07/07 23:15:24 ggregory Exp $ - */ -public class Soundex implements StringEncoder { - - /** - * An instance of Soundex using the US_ENGLISH_MAPPING mapping. - * - * @see #US_ENGLISH_MAPPING - */ - public static final Soundex US_ENGLISH = new Soundex(); - - /** - * This is a default mapping of the 26 letters used in US English. A value of <code>0</code> for a letter position - * means do not encode. - * <p> - * (This constant is provided as both an implementation convenience and to allow Javadoc to pick - * up the value for the constant values page.) - * </p> - * - * @see #US_ENGLISH_MAPPING - */ - public static final String US_ENGLISH_MAPPING_STRING = "01230120022455012623010202"; - - /** - * This is a default mapping of the 26 letters used in US English. A value of <code>0</code> for a letter position - * means do not encode. - * - * @see Soundex#Soundex(char[]) - */ - public static final char[] US_ENGLISH_MAPPING = US_ENGLISH_MAPPING_STRING.toCharArray(); - - // BEGIN android-note - // Removed @see reference to SoundexUtils below, since the class isn't - // public. - // END android-note - /** - * Encodes the Strings and returns the number of characters in the two encoded Strings that are the same. This - * return value ranges from 0 through 4: 0 indicates little or no similarity, and 4 indicates strong similarity or - * identical values. - * - * @param s1 - * A String that will be encoded and compared. - * @param s2 - * A String that will be encoded and compared. - * @return The number of characters in the two encoded Strings that are the same from 0 to 4. - * - * @see <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_de-dz_8co5.asp"> MS - * T-SQL DIFFERENCE </a> - * - * @throws EncoderException - * if an error occurs encoding one of the strings - * @since 1.3 - */ - public int difference(String s1, String s2) throws EncoderException { - return SoundexUtils.difference(this, s1, s2); - } - - /** - * The maximum length of a Soundex code - Soundex codes are only four characters by definition. - * - * @deprecated This feature is not needed since the encoding size must be constant. Will be removed in 2.0. - */ - private int maxLength = 4; - - /** - * Every letter of the alphabet is "mapped" to a numerical value. This char array holds the values to which each - * letter is mapped. This implementation contains a default map for US_ENGLISH - */ - private char[] soundexMapping; - - /** - * Creates an instance using US_ENGLISH_MAPPING - * - * @see Soundex#Soundex(char[]) - * @see Soundex#US_ENGLISH_MAPPING - */ - public Soundex() { - this(US_ENGLISH_MAPPING); - } - - /** - * Creates a soundex instance using the given mapping. This constructor can be used to provide an internationalized - * mapping for a non-Western character set. - * - * Every letter of the alphabet is "mapped" to a numerical value. This char array holds the values to which each - * letter is mapped. This implementation contains a default map for US_ENGLISH - * - * @param mapping - * Mapping array to use when finding the corresponding code for a given character - */ - public Soundex(char[] mapping) { - this.setSoundexMapping(mapping); - } - - /** - * Encodes an Object using the soundex algorithm. This method is provided in order to satisfy the requirements of - * the Encoder interface, and will throw an EncoderException if the supplied object is not of type java.lang.String. - * - * @param pObject - * Object to encode - * @return An object (or type java.lang.String) containing the soundex code which corresponds to the String - * supplied. - * @throws EncoderException - * if the parameter supplied is not of type java.lang.String - * @throws IllegalArgumentException - * if a character is not mapped - */ - public Object encode(Object pObject) throws EncoderException { - if (!(pObject instanceof String)) { - throw new EncoderException("Parameter supplied to Soundex encode is not of type java.lang.String"); - } - return soundex((String) pObject); - } - - /** - * Encodes a String using the soundex algorithm. - * - * @param pString - * A String object to encode - * @return A Soundex code corresponding to the String supplied - * @throws IllegalArgumentException - * if a character is not mapped - */ - public String encode(String pString) { - return soundex(pString); - } - - /** - * Used internally by the SoundEx algorithm. - * - * Consonants from the same code group separated by W or H are treated as one. - * - * @param str - * the cleaned working string to encode (in upper case). - * @param index - * the character position to encode - * @return Mapping code for a particular character - * @throws IllegalArgumentException - * if the character is not mapped - */ - private char getMappingCode(String str, int index) { - char mappedChar = this.map(str.charAt(index)); - // HW rule check - if (index > 1 && mappedChar != '0') { - char hwChar = str.charAt(index - 1); - if ('H' == hwChar || 'W' == hwChar) { - char preHWChar = str.charAt(index - 2); - char firstCode = this.map(preHWChar); - if (firstCode == mappedChar || 'H' == preHWChar || 'W' == preHWChar) { - return 0; - } - } - } - return mappedChar; - } - - /** - * Returns the maxLength. Standard Soundex - * - * @deprecated This feature is not needed since the encoding size must be constant. Will be removed in 2.0. - * @return int - */ - public int getMaxLength() { - return this.maxLength; - } - - /** - * Returns the soundex mapping. - * - * @return soundexMapping. - */ - private char[] getSoundexMapping() { - return this.soundexMapping; - } - - /** - * Maps the given upper-case character to it's Soudex code. - * - * @param ch - * An upper-case character. - * @return A Soundex code. - * @throws IllegalArgumentException - * Thrown if <code>ch</code> is not mapped. - */ - private char map(char ch) { - int index = ch - 'A'; - if (index < 0 || index >= this.getSoundexMapping().length) { - throw new IllegalArgumentException("The character is not mapped: " + ch); - } - return this.getSoundexMapping()[index]; - } - - /** - * Sets the maxLength. - * - * @deprecated This feature is not needed since the encoding size must be constant. Will be removed in 2.0. - * @param maxLength - * The maxLength to set - */ - public void setMaxLength(int maxLength) { - this.maxLength = maxLength; - } - - /** - * Sets the soundexMapping. - * - * @param soundexMapping - * The soundexMapping to set. - */ - private void setSoundexMapping(char[] soundexMapping) { - this.soundexMapping = soundexMapping; - } - - /** - * Retreives the Soundex code for a given String object. - * - * @param str - * String to encode using the Soundex algorithm - * @return A soundex code for the String supplied - * @throws IllegalArgumentException - * if a character is not mapped - */ - public String soundex(String str) { - if (str == null) { - return null; - } - str = SoundexUtils.clean(str); - if (str.length() == 0) { - return str; - } - char out[] = {'0', '0', '0', '0'}; - char last, mapped; - int incount = 1, count = 1; - out[0] = str.charAt(0); - last = getMappingCode(str, 0); - while ((incount < str.length()) && (count < out.length)) { - mapped = getMappingCode(str, incount++); - if (mapped != 0) { - if ((mapped != '0') && (mapped != last)) { - out[count++] = mapped; - } - last = mapped; - } - } - return new String(out); - } - -} diff --git a/src/org/apache/commons/codec/language/SoundexUtils.java b/src/org/apache/commons/codec/language/SoundexUtils.java deleted file mode 100644 index 48f2d87..0000000 --- a/src/org/apache/commons/codec/language/SoundexUtils.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.codec.language; - -import org.apache.commons.codec.EncoderException; -import org.apache.commons.codec.StringEncoder; - -/** - * Utility methods for {@link Soundex} and {@link RefinedSoundex} classes. - * - * @author Apache Software Foundation - * @version $Id: SoundexUtils.java,v 1.5 2004/03/17 18:31:35 ggregory Exp $ - * @since 1.3 - */ -final class SoundexUtils { - - /** - * Cleans up the input string before Soundex processing by only returning - * upper case letters. - * - * @param str - * The String to clean. - * @return A clean String. - */ - static String clean(String str) { - if (str == null || str.length() == 0) { - return str; - } - int len = str.length(); - char[] chars = new char[len]; - int count = 0; - for (int i = 0; i < len; i++) { - if (Character.isLetter(str.charAt(i))) { - chars[count++] = str.charAt(i); - } - } - if (count == len) { - return str.toUpperCase(); - } - return new String(chars, 0, count).toUpperCase(); - } - - /** - * Encodes the Strings and returns the number of characters in the two - * encoded Strings that are the same. - * <ul> - * <li>For Soundex, this return value ranges from 0 through 4: 0 indicates - * little or no similarity, and 4 indicates strong similarity or identical - * values.</li> - * <li>For refined Soundex, the return value can be greater than 4.</li> - * </ul> - * - * @param encoder - * The encoder to use to encode the Strings. - * @param s1 - * A String that will be encoded and compared. - * @param s2 - * A String that will be encoded and compared. - * @return The number of characters in the two Soundex encoded Strings that - * are the same. - * - * @see #differenceEncoded(String,String) - * @see <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_de-dz_8co5.asp"> - * MS T-SQL DIFFERENCE</a> - * - * @throws EncoderException - * if an error occurs encoding one of the strings - */ - static int difference(StringEncoder encoder, String s1, String s2) throws EncoderException { - return differenceEncoded(encoder.encode(s1), encoder.encode(s2)); - } - - /** - * Returns the number of characters in the two Soundex encoded Strings that - * are the same. - * <ul> - * <li>For Soundex, this return value ranges from 0 through 4: 0 indicates - * little or no similarity, and 4 indicates strong similarity or identical - * values.</li> - * <li>For refined Soundex, the return value can be greater than 4.</li> - * </ul> - * - * @param es1 - * An encoded String. - * @param es2 - * An encoded String. - * @return The number of characters in the two Soundex encoded Strings that - * are the same. - * - * @see <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_de-dz_8co5.asp"> - * MS T-SQL DIFFERENCE</a> - */ - static int differenceEncoded(String es1, String es2) { - - if (es1 == null || es2 == null) { - return 0; - } - int lengthToMatch = Math.min(es1.length(), es2.length()); - int diff = 0; - for (int i = 0; i < lengthToMatch; i++) { - if (es1.charAt(i) == es2.charAt(i)) { - diff++; - } - } - return diff; - } - -} diff --git a/src/org/apache/commons/codec/language/package.html b/src/org/apache/commons/codec/language/package.html deleted file mode 100644 index fab8e4c..0000000 --- a/src/org/apache/commons/codec/language/package.html +++ /dev/null @@ -1,20 +0,0 @@ -<!-- -Copyright 2003-2004 The Apache Software Foundation. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. ---> -<html> - <body> - Language and phonetic encoders. - </body> -</html> diff --git a/src/org/apache/commons/codec/net/BCodec.java b/src/org/apache/commons/codec/net/BCodec.java deleted file mode 100644 index b164100..0000000 --- a/src/org/apache/commons/codec/net/BCodec.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.codec.net; - -import java.io.UnsupportedEncodingException; -import org.apache.commons.codec.DecoderException; -import org.apache.commons.codec.EncoderException; -import org.apache.commons.codec.StringDecoder; -import org.apache.commons.codec.StringEncoder; -import org.apache.commons.codec.binary.Base64; - -/** - * <p> - * Identical to the Base64 encoding defined by <a href="http://www.ietf.org/rfc/rfc1521.txt">RFC - * 1521</a> and allows a character set to be specified. - * </p> - * - * <p> - * <a href="http://www.ietf.org/rfc/rfc1522.txt">RFC 1522</a> describes techniques to allow the encoding of non-ASCII - * text in various portions of a RFC 822 [2] message header, in a manner which is unlikely to confuse existing message - * handling software. - * </p> - * - * @see <a href="http://www.ietf.org/rfc/rfc1522.txt">MIME (Multipurpose Internet Mail Extensions) Part Two: Message - * Header Extensions for Non-ASCII Text</a> - * - * @author Apache Software Foundation - * @since 1.3 - * @version $Id: BCodec.java,v 1.5 2004/04/13 22:46:37 ggregory Exp $ - */ -public class BCodec extends RFC1522Codec implements StringEncoder, StringDecoder { - /** - * The default charset used for string decoding and encoding. - */ - private String charset = StringEncodings.UTF8; - - /** - * Default constructor. - */ - public BCodec() { - super(); - } - - /** - * Constructor which allows for the selection of a default charset - * - * @param charset - * the default string charset to use. - * - * @see <a href="http://java.sun.com/j2se/1.3/docs/api/java/lang/package-summary.html#charenc">JRE character - * encoding names</a> - */ - public BCodec(final String charset) { - super(); - this.charset = charset; - } - - protected String getEncoding() { - return "B"; - } - - protected byte[] doEncoding(byte[] bytes) throws EncoderException { - if (bytes == null) { - return null; - } - return Base64.encodeBase64(bytes); - } - - protected byte[] doDecoding(byte[] bytes) throws DecoderException { - if (bytes == null) { - return null; - } - return Base64.decodeBase64(bytes); - } - - /** - * Encodes a string into its Base64 form using the specified charset. Unsafe characters are escaped. - * - * @param value - * string to convert to Base64 form - * @param charset - * the charset for pString - * @return Base64 string - * - * @throws EncoderException - * thrown if a failure condition is encountered during the encoding process. - */ - public String encode(final String value, final String charset) throws EncoderException { - if (value == null) { - return null; - } - try { - return encodeText(value, charset); - } catch (UnsupportedEncodingException e) { - throw new EncoderException(e.getMessage()); - } - } - - /** - * Encodes a string into its Base64 form using the default charset. Unsafe characters are escaped. - * - * @param value - * string to convert to Base64 form - * @return Base64 string - * - * @throws EncoderException - * thrown if a failure condition is encountered during the encoding process. - */ - public String encode(String value) throws EncoderException { - if (value == null) { - return null; - } - return encode(value, getDefaultCharset()); - } - - /** - * Decodes a Base64 string into its original form. Escaped characters are converted back to their original - * representation. - * - * @param value - * Base64 string to convert into its original form - * - * @return original string - * - * @throws DecoderException - * A decoder exception is thrown if a failure condition is encountered during the decode process. - */ - public String decode(String value) throws DecoderException { - if (value == null) { - return null; - } - try { - return decodeText(value); - } catch (UnsupportedEncodingException e) { - throw new DecoderException(e.getMessage()); - } - } - - /** - * Encodes an object into its Base64 form using the default charset. Unsafe characters are escaped. - * - * @param value - * object to convert to Base64 form - * @return Base64 object - * - * @throws EncoderException - * thrown if a failure condition is encountered during the encoding process. - */ - public Object encode(Object value) throws EncoderException { - if (value == null) { - return null; - } else if (value instanceof String) { - return encode((String) value); - } else { - throw new EncoderException("Objects of type " - + value.getClass().getName() - + " cannot be encoded using BCodec"); - } - } - - /** - * Decodes a Base64 object into its original form. Escaped characters are converted back to their original - * representation. - * - * @param value - * Base64 object to convert into its original form - * - * @return original object - * - * @throws DecoderException - * A decoder exception is thrown if a failure condition is encountered during the decode process. - */ - public Object decode(Object value) throws DecoderException { - if (value == null) { - return null; - } else if (value instanceof String) { - return decode((String) value); - } else { - throw new DecoderException("Objects of type " - + value.getClass().getName() - + " cannot be decoded using BCodec"); - } - } - - /** - * The default charset used for string decoding and encoding. - * - * @return the default string charset. - */ - public String getDefaultCharset() { - return this.charset; - } -} diff --git a/src/org/apache/commons/codec/net/QCodec.java b/src/org/apache/commons/codec/net/QCodec.java deleted file mode 100644 index 5736080..0000000 --- a/src/org/apache/commons/codec/net/QCodec.java +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.codec.net; - -import java.io.UnsupportedEncodingException; -import java.util.BitSet; - -import org.apache.commons.codec.DecoderException; -import org.apache.commons.codec.EncoderException; -import org.apache.commons.codec.StringDecoder; -import org.apache.commons.codec.StringEncoder; - -/** - * <p> - * Similar to the Quoted-Printable content-transfer-encoding defined in <a - * href="http://www.ietf.org/rfc/rfc1521.txt">RFC 1521</a> and designed to allow text containing mostly ASCII - * characters to be decipherable on an ASCII terminal without decoding. - * </p> - * - * <p> - * <a href="http://www.ietf.org/rfc/rfc1522.txt">RFC 1522</a> describes techniques to allow the encoding of non-ASCII - * text in various portions of a RFC 822 [2] message header, in a manner which is unlikely to confuse existing message - * handling software. - * </p> - * - * @see <a href="http://www.ietf.org/rfc/rfc1522.txt">MIME (Multipurpose Internet Mail Extensions) Part Two: Message - * Header Extensions for Non-ASCII Text</a> - * - * @author Apache Software Foundation - * @since 1.3 - * @version $Id: QCodec.java,v 1.6 2004/05/24 00:24:32 ggregory Exp $ - */ -public class QCodec extends RFC1522Codec implements StringEncoder, StringDecoder { - /** - * The default charset used for string decoding and encoding. - */ - private String charset = StringEncodings.UTF8; - - /** - * BitSet of printable characters as defined in RFC 1522. - */ - private static final BitSet PRINTABLE_CHARS = new BitSet(256); - // Static initializer for printable chars collection - static { - // alpha characters - PRINTABLE_CHARS.set(' '); - PRINTABLE_CHARS.set('!'); - PRINTABLE_CHARS.set('"'); - PRINTABLE_CHARS.set('#'); - PRINTABLE_CHARS.set('$'); - PRINTABLE_CHARS.set('%'); - PRINTABLE_CHARS.set('&'); - PRINTABLE_CHARS.set('\''); - PRINTABLE_CHARS.set('('); - PRINTABLE_CHARS.set(')'); - PRINTABLE_CHARS.set('*'); - PRINTABLE_CHARS.set('+'); - PRINTABLE_CHARS.set(','); - PRINTABLE_CHARS.set('-'); - PRINTABLE_CHARS.set('.'); - PRINTABLE_CHARS.set('/'); - for (int i = '0'; i <= '9'; i++) { - PRINTABLE_CHARS.set(i); - } - PRINTABLE_CHARS.set(':'); - PRINTABLE_CHARS.set(';'); - PRINTABLE_CHARS.set('<'); - PRINTABLE_CHARS.set('>'); - PRINTABLE_CHARS.set('@'); - for (int i = 'A'; i <= 'Z'; i++) { - PRINTABLE_CHARS.set(i); - } - PRINTABLE_CHARS.set('['); - PRINTABLE_CHARS.set('\\'); - PRINTABLE_CHARS.set(']'); - PRINTABLE_CHARS.set('^'); - PRINTABLE_CHARS.set('`'); - for (int i = 'a'; i <= 'z'; i++) { - PRINTABLE_CHARS.set(i); - } - PRINTABLE_CHARS.set('{'); - PRINTABLE_CHARS.set('|'); - PRINTABLE_CHARS.set('}'); - PRINTABLE_CHARS.set('~'); - } - - private static byte BLANK = 32; - - private static byte UNDERSCORE = 95; - - private boolean encodeBlanks = false; - - /** - * Default constructor. - */ - public QCodec() { - super(); - } - - /** - * Constructor which allows for the selection of a default charset - * - * @param charset - * the default string charset to use. - * - * @see <a href="http://java.sun.com/j2se/1.3/docs/api/java/lang/package-summary.html#charenc">JRE character - * encoding names</a> - */ - public QCodec(final String charset) { - super(); - this.charset = charset; - } - - protected String getEncoding() { - return "Q"; - } - - protected byte[] doEncoding(byte[] bytes) throws EncoderException { - if (bytes == null) { - return null; - } - byte[] data = QuotedPrintableCodec.encodeQuotedPrintable(PRINTABLE_CHARS, bytes); - if (this.encodeBlanks) { - for (int i = 0; i < data.length; i++) { - if (data[i] == BLANK) { - data[i] = UNDERSCORE; - } - } - } - return data; - } - - protected byte[] doDecoding(byte[] bytes) throws DecoderException { - if (bytes == null) { - return null; - } - boolean hasUnderscores = false; - for (int i = 0; i < bytes.length; i++) { - if (bytes[i] == UNDERSCORE) { - hasUnderscores = true; - break; - } - } - if (hasUnderscores) { - byte[] tmp = new byte[bytes.length]; - for (int i = 0; i < bytes.length; i++) { - byte b = bytes[i]; - if (b != UNDERSCORE) { - tmp[i] = b; - } else { - tmp[i] = BLANK; - } - } - return QuotedPrintableCodec.decodeQuotedPrintable(tmp); - } - return QuotedPrintableCodec.decodeQuotedPrintable(bytes); - } - - /** - * Encodes a string into its quoted-printable form using the specified charset. Unsafe characters are escaped. - * - * @param pString - * string to convert to quoted-printable form - * @param charset - * the charset for pString - * @return quoted-printable string - * - * @throws EncoderException - * thrown if a failure condition is encountered during the encoding process. - */ - public String encode(final String pString, final String charset) throws EncoderException { - if (pString == null) { - return null; - } - try { - return encodeText(pString, charset); - } catch (UnsupportedEncodingException e) { - throw new EncoderException(e.getMessage()); - } - } - - /** - * Encodes a string into its quoted-printable form using the default charset. Unsafe characters are escaped. - * - * @param pString - * string to convert to quoted-printable form - * @return quoted-printable string - * - * @throws EncoderException - * thrown if a failure condition is encountered during the encoding process. - */ - public String encode(String pString) throws EncoderException { - if (pString == null) { - return null; - } - return encode(pString, getDefaultCharset()); - } - - /** - * Decodes a quoted-printable string into its original form. Escaped characters are converted back to their original - * representation. - * - * @param pString - * quoted-printable string to convert into its original form - * - * @return original string - * - * @throws DecoderException - * A decoder exception is thrown if a failure condition is encountered during the decode process. - */ - public String decode(String pString) throws DecoderException { - if (pString == null) { - return null; - } - try { - return decodeText(pString); - } catch (UnsupportedEncodingException e) { - throw new DecoderException(e.getMessage()); - } - } - - /** - * Encodes an object into its quoted-printable form using the default charset. Unsafe characters are escaped. - * - * @param pObject - * object to convert to quoted-printable form - * @return quoted-printable object - * - * @throws EncoderException - * thrown if a failure condition is encountered during the encoding process. - */ - public Object encode(Object pObject) throws EncoderException { - if (pObject == null) { - return null; - } else if (pObject instanceof String) { - return encode((String) pObject); - } else { - throw new EncoderException("Objects of type " - + pObject.getClass().getName() - + " cannot be encoded using Q codec"); - } - } - - /** - * Decodes a quoted-printable object into its original form. Escaped characters are converted back to their original - * representation. - * - * @param pObject - * quoted-printable object to convert into its original form - * - * @return original object - * - * @throws DecoderException - * A decoder exception is thrown if a failure condition is encountered during the decode process. - */ - public Object decode(Object pObject) throws DecoderException { - if (pObject == null) { - return null; - } else if (pObject instanceof String) { - return decode((String) pObject); - } else { - throw new DecoderException("Objects of type " - + pObject.getClass().getName() - + " cannot be decoded using Q codec"); - } - } - - /** - * The default charset used for string decoding and encoding. - * - * @return the default string charset. - */ - public String getDefaultCharset() { - return this.charset; - } - - /** - * Tests if optional tranformation of SPACE characters is to be used - * - * @return <code>true</code> if SPACE characters are to be transformed, <code>false</code> otherwise - */ - public boolean isEncodeBlanks() { - return this.encodeBlanks; - } - - /** - * Defines whether optional tranformation of SPACE characters is to be used - * - * @param b - * <code>true</code> if SPACE characters are to be transformed, <code>false</code> otherwise - */ - public void setEncodeBlanks(boolean b) { - this.encodeBlanks = b; - } -} diff --git a/src/org/apache/commons/codec/net/QuotedPrintableCodec.java b/src/org/apache/commons/codec/net/QuotedPrintableCodec.java deleted file mode 100644 index c2fcd27..0000000 --- a/src/org/apache/commons/codec/net/QuotedPrintableCodec.java +++ /dev/null @@ -1,387 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.codec.net; - -import java.io.ByteArrayOutputStream; -import java.io.UnsupportedEncodingException; -import java.util.BitSet; -import org.apache.commons.codec.BinaryDecoder; -import org.apache.commons.codec.BinaryEncoder; -import org.apache.commons.codec.DecoderException; -import org.apache.commons.codec.EncoderException; -import org.apache.commons.codec.StringDecoder; -import org.apache.commons.codec.StringEncoder; - -/** - * <p> - * Codec for the Quoted-Printable section of <a href="http://www.ietf.org/rfc/rfc1521.txt">RFC 1521 </a>. - * </p> - * <p> - * The Quoted-Printable encoding is intended to represent data that largely consists of octets that correspond to - * printable characters in the ASCII character set. It encodes the data in such a way that the resulting octets are - * unlikely to be modified by mail transport. If the data being encoded are mostly ASCII text, the encoded form of the - * data remains largely recognizable by humans. A body which is entirely ASCII may also be encoded in Quoted-Printable - * to ensure the integrity of the data should the message pass through a character- translating, and/or line-wrapping - * gateway. - * </p> - * - * <p> - * Note: - * </p> - * <p> - * Rules #3, #4, and #5 of the quoted-printable spec are not implemented yet because the complete quoted-printable spec - * does not lend itself well into the byte[] oriented codec framework. Complete the codec once the steamable codec - * framework is ready. The motivation behind providing the codec in a partial form is that it can already come in handy - * for those applications that do not require quoted-printable line formatting (rules #3, #4, #5), for instance Q codec. - * </p> - * - * @see <a href="http://www.ietf.org/rfc/rfc1521.txt"> RFC 1521 MIME (Multipurpose Internet Mail Extensions) Part One: - * Mechanisms for Specifying and Describing the Format of Internet Message Bodies </a> - * - * @author Apache Software Foundation - * @since 1.3 - * @version $Id: QuotedPrintableCodec.java,v 1.7 2004/04/09 22:21:07 ggregory Exp $ - */ -public class QuotedPrintableCodec implements BinaryEncoder, BinaryDecoder, StringEncoder, StringDecoder { - /** - * The default charset used for string decoding and encoding. - */ - private String charset = StringEncodings.UTF8; - - /** - * BitSet of printable characters as defined in RFC 1521. - */ - private static final BitSet PRINTABLE_CHARS = new BitSet(256); - - private static byte ESCAPE_CHAR = '='; - - private static byte TAB = 9; - - private static byte SPACE = 32; - // Static initializer for printable chars collection - static { - // alpha characters - for (int i = 33; i <= 60; i++) { - PRINTABLE_CHARS.set(i); - } - for (int i = 62; i <= 126; i++) { - PRINTABLE_CHARS.set(i); - } - PRINTABLE_CHARS.set(TAB); - PRINTABLE_CHARS.set(SPACE); - } - - /** - * Default constructor. - */ - public QuotedPrintableCodec() { - super(); - } - - /** - * Constructor which allows for the selection of a default charset - * - * @param charset - * the default string charset to use. - */ - public QuotedPrintableCodec(String charset) { - super(); - this.charset = charset; - } - - /** - * Encodes byte into its quoted-printable representation. - * - * @param b - * byte to encode - * @param buffer - * the buffer to write to - */ - private static final void encodeQuotedPrintable(int b, ByteArrayOutputStream buffer) { - buffer.write(ESCAPE_CHAR); - char hex1 = Character.toUpperCase(Character.forDigit((b >> 4) & 0xF, 16)); - char hex2 = Character.toUpperCase(Character.forDigit(b & 0xF, 16)); - buffer.write(hex1); - buffer.write(hex2); - } - - /** - * Encodes an array of bytes into an array of quoted-printable 7-bit characters. Unsafe characters are escaped. - * - * <p> - * This function implements a subset of quoted-printable encoding specification (rule #1 and rule #2) as defined in - * RFC 1521 and is suitable for encoding binary data and unformatted text. - * </p> - * - * @param printable - * bitset of characters deemed quoted-printable - * @param bytes - * array of bytes to be encoded - * @return array of bytes containing quoted-printable data - */ - public static final byte[] encodeQuotedPrintable(BitSet printable, byte[] bytes) { - if (bytes == null) { - return null; - } - if (printable == null) { - printable = PRINTABLE_CHARS; - } - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - for (int i = 0; i < bytes.length; i++) { - int b = bytes[i]; - if (b < 0) { - b = 256 + b; - } - if (printable.get(b)) { - buffer.write(b); - } else { - encodeQuotedPrintable(b, buffer); - } - } - return buffer.toByteArray(); - } - - /** - * Decodes an array quoted-printable characters into an array of original bytes. Escaped characters are converted - * back to their original representation. - * - * <p> - * This function implements a subset of quoted-printable encoding specification (rule #1 and rule #2) as defined in - * RFC 1521. - * </p> - * - * @param bytes - * array of quoted-printable characters - * @return array of original bytes - * @throws DecoderException - * Thrown if quoted-printable decoding is unsuccessful - */ - public static final byte[] decodeQuotedPrintable(byte[] bytes) throws DecoderException { - if (bytes == null) { - return null; - } - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - for (int i = 0; i < bytes.length; i++) { - int b = bytes[i]; - if (b == ESCAPE_CHAR) { - try { - int u = Character.digit((char) bytes[++i], 16); - int l = Character.digit((char) bytes[++i], 16); - if (u == -1 || l == -1) { - throw new DecoderException("Invalid quoted-printable encoding"); - } - buffer.write((char) ((u << 4) + l)); - } catch (ArrayIndexOutOfBoundsException e) { - throw new DecoderException("Invalid quoted-printable encoding"); - } - } else { - buffer.write(b); - } - } - return buffer.toByteArray(); - } - - /** - * Encodes an array of bytes into an array of quoted-printable 7-bit characters. Unsafe characters are escaped. - * - * <p> - * This function implements a subset of quoted-printable encoding specification (rule #1 and rule #2) as defined in - * RFC 1521 and is suitable for encoding binary data and unformatted text. - * </p> - * - * @param bytes - * array of bytes to be encoded - * @return array of bytes containing quoted-printable data - */ - public byte[] encode(byte[] bytes) { - return encodeQuotedPrintable(PRINTABLE_CHARS, bytes); - } - - /** - * Decodes an array of quoted-printable characters into an array of original bytes. Escaped characters are converted - * back to their original representation. - * - * <p> - * This function implements a subset of quoted-printable encoding specification (rule #1 and rule #2) as defined in - * RFC 1521. - * </p> - * - * @param bytes - * array of quoted-printable characters - * @return array of original bytes - * @throws DecoderException - * Thrown if quoted-printable decoding is unsuccessful - */ - public byte[] decode(byte[] bytes) throws DecoderException { - return decodeQuotedPrintable(bytes); - } - - /** - * Encodes a string into its quoted-printable form using the default string charset. Unsafe characters are escaped. - * - * <p> - * This function implements a subset of quoted-printable encoding specification (rule #1 and rule #2) as defined in - * RFC 1521 and is suitable for encoding binary data. - * </p> - * - * @param pString - * string to convert to quoted-printable form - * @return quoted-printable string - * - * @throws EncoderException - * Thrown if quoted-printable encoding is unsuccessful - * - * @see #getDefaultCharset() - */ - public String encode(String pString) throws EncoderException { - if (pString == null) { - return null; - } - try { - return encode(pString, getDefaultCharset()); - } catch (UnsupportedEncodingException e) { - throw new EncoderException(e.getMessage()); - } - } - - /** - * Decodes a quoted-printable string into its original form using the specified string charset. Escaped characters - * are converted back to their original representation. - * - * @param pString - * quoted-printable string to convert into its original form - * @param charset - * the original string charset - * @return original string - * @throws DecoderException - * Thrown if quoted-printable decoding is unsuccessful - * @throws UnsupportedEncodingException - * Thrown if charset is not supported - */ - public String decode(String pString, String charset) throws DecoderException, UnsupportedEncodingException { - if (pString == null) { - return null; - } - return new String(decode(pString.getBytes(StringEncodings.US_ASCII)), charset); - } - - /** - * Decodes a quoted-printable string into its original form using the default string charset. Escaped characters are - * converted back to their original representation. - * - * @param pString - * quoted-printable string to convert into its original form - * @return original string - * @throws DecoderException - * Thrown if quoted-printable decoding is unsuccessful - * @throws UnsupportedEncodingException - * Thrown if charset is not supported - * @see #getDefaultCharset() - */ - public String decode(String pString) throws DecoderException { - if (pString == null) { - return null; - } - try { - return decode(pString, getDefaultCharset()); - } catch (UnsupportedEncodingException e) { - throw new DecoderException(e.getMessage()); - } - } - - /** - * Encodes an object into its quoted-printable safe form. Unsafe characters are escaped. - * - * @param pObject - * string to convert to a quoted-printable form - * @return quoted-printable object - * @throws EncoderException - * Thrown if quoted-printable encoding is not applicable to objects of this type or if encoding is - * unsuccessful - */ - public Object encode(Object pObject) throws EncoderException { - if (pObject == null) { - return null; - } else if (pObject instanceof byte[]) { - return encode((byte[]) pObject); - } else if (pObject instanceof String) { - return encode((String) pObject); - } else { - throw new EncoderException("Objects of type " - + pObject.getClass().getName() - + " cannot be quoted-printable encoded"); - } - } - - /** - * Decodes a quoted-printable object into its original form. Escaped characters are converted back to their original - * representation. - * - * @param pObject - * quoted-printable object to convert into its original form - * @return original object - * @throws DecoderException - * Thrown if quoted-printable decoding is not applicable to objects of this type if decoding is - * unsuccessful - */ - public Object decode(Object pObject) throws DecoderException { - if (pObject == null) { - return null; - } else if (pObject instanceof byte[]) { - return decode((byte[]) pObject); - } else if (pObject instanceof String) { - return decode((String) pObject); - } else { - throw new DecoderException("Objects of type " - + pObject.getClass().getName() - + " cannot be quoted-printable decoded"); - } - } - - /** - * Returns the default charset used for string decoding and encoding. - * - * @return the default string charset. - */ - public String getDefaultCharset() { - return this.charset; - } - - /** - * Encodes a string into its quoted-printable form using the specified charset. Unsafe characters are escaped. - * - * <p> - * This function implements a subset of quoted-printable encoding specification (rule #1 and rule #2) as defined in - * RFC 1521 and is suitable for encoding binary data and unformatted text. - * </p> - * - * @param pString - * string to convert to quoted-printable form - * @param charset - * the charset for pString - * @return quoted-printable string - * - * @throws UnsupportedEncodingException - * Thrown if the charset is not supported - */ - public String encode(String pString, String charset) throws UnsupportedEncodingException { - if (pString == null) { - return null; - } - return new String(encode(pString.getBytes(charset)), StringEncodings.US_ASCII); - } -} diff --git a/src/org/apache/commons/codec/net/RFC1522Codec.java b/src/org/apache/commons/codec/net/RFC1522Codec.java deleted file mode 100644 index 0acf921..0000000 --- a/src/org/apache/commons/codec/net/RFC1522Codec.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.codec.net; - -import java.io.UnsupportedEncodingException; - -import org.apache.commons.codec.DecoderException; -import org.apache.commons.codec.EncoderException; - -/** - * <p> - * Implements methods common to all codecs defined in RFC 1522. - * </p> - * - * <p> - * <a href="http://www.ietf.org/rfc/rfc1522.txt">RFC 1522</a> - * describes techniques to allow the encoding of non-ASCII text in - * various portions of a RFC 822 [2] message header, in a manner which - * is unlikely to confuse existing message handling software. - * </p> - - * @see <a href="http://www.ietf.org/rfc/rfc1522.txt"> - * MIME (Multipurpose Internet Mail Extensions) Part Two: - * Message Header Extensions for Non-ASCII Text</a> - * </p> - * - * @author Apache Software Foundation - * @since 1.3 - * @version $Id: RFC1522Codec.java,v 1.2 2004/04/09 22:21:43 ggregory Exp $ - */ -abstract class RFC1522Codec { - - /** - * Applies an RFC 1522 compliant encoding scheme to the given string of text with the - * given charset. This method constructs the "encoded-word" header common to all the - * RFC 1522 codecs and then invokes {@link #doEncoding(byte [])} method of a concrete - * class to perform the specific enconding. - * - * @param text a string to encode - * @param charset a charset to be used - * - * @return RFC 1522 compliant "encoded-word" - * - * @throws EncoderException thrown if there is an error conidition during the Encoding - * process. - * @throws UnsupportedEncodingException thrown if charset is not supported - * - * @see <a href="http://java.sun.com/j2se/1.3/docs/api/java/lang/package-summary.html#charenc">JRE character - * encoding names</a> - */ - protected String encodeText(final String text, final String charset) - throws EncoderException, UnsupportedEncodingException - { - if (text == null) { - return null; - } - StringBuffer buffer = new StringBuffer(); - buffer.append("=?"); - buffer.append(charset); - buffer.append('?'); - buffer.append(getEncoding()); - buffer.append('?'); - byte [] rawdata = doEncoding(text.getBytes(charset)); - buffer.append(new String(rawdata, StringEncodings.US_ASCII)); - buffer.append("?="); - return buffer.toString(); - } - - /** - * Applies an RFC 1522 compliant decoding scheme to the given string of text. This method - * processes the "encoded-word" header common to all the RFC 1522 codecs and then invokes - * {@link #doEncoding(byte [])} method of a concrete class to perform the specific deconding. - * - * @param text a string to decode - * - * @throws DecoderException thrown if there is an error conidition during the Decoding - * process. - * @throws UnsupportedEncodingException thrown if charset specified in the "encoded-word" - * header is not supported - */ - protected String decodeText(final String text) - throws DecoderException, UnsupportedEncodingException - { - if (text == null) { - return null; - } - if ((!text.startsWith("=?")) || (!text.endsWith("?="))) { - throw new DecoderException("RFC 1522 violation: malformed encoded content"); - } - int termnator = text.length() - 2; - int from = 2; - int to = text.indexOf("?", from); - if ((to == -1) || (to == termnator)) { - throw new DecoderException("RFC 1522 violation: charset token not found"); - } - String charset = text.substring(from, to); - if (charset.equals("")) { - throw new DecoderException("RFC 1522 violation: charset not specified"); - } - from = to + 1; - to = text.indexOf("?", from); - if ((to == -1) || (to == termnator)) { - throw new DecoderException("RFC 1522 violation: encoding token not found"); - } - String encoding = text.substring(from, to); - if (!getEncoding().equalsIgnoreCase(encoding)) { - throw new DecoderException("This codec cannot decode " + - encoding + " encoded content"); - } - from = to + 1; - to = text.indexOf("?", from); - byte[] data = text.substring(from, to).getBytes(StringEncodings.US_ASCII); - data = doDecoding(data); - return new String(data, charset); - } - - /** - * Returns the codec name (referred to as encoding in the RFC 1522) - * - * @return name of the codec - */ - protected abstract String getEncoding(); - - /** - * Encodes an array of bytes using the defined encoding scheme - * - * @param bytes Data to be encoded - * - * @return A byte array containing the encoded data - * - * @throws EncoderException thrown if the Encoder encounters a failure condition - * during the encoding process. - */ - protected abstract byte[] doEncoding(byte[] bytes) throws EncoderException; - - /** - * Decodes an array of bytes using the defined encoding scheme - * - * @param bytes Data to be decoded - * - * @return a byte array that contains decoded data - * - * @throws DecoderException A decoder exception is thrown if a Decoder encounters a - * failure condition during the decode process. - */ - protected abstract byte[] doDecoding(byte[] bytes) throws DecoderException; -} diff --git a/src/org/apache/commons/codec/net/StringEncodings.java b/src/org/apache/commons/codec/net/StringEncodings.java deleted file mode 100644 index e7f6bb8..0000000 --- a/src/org/apache/commons/codec/net/StringEncodings.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.codec.net; - -/** - * String encodings used in this package. - * - * @author Apache Software Foundation - * @since 1.3 - * @version $Id: StringEncodings.java,v 1.2 2004/04/09 22:21:07 ggregory Exp $ - */ -interface StringEncodings { - /** - * <p> - * Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block of the Unicode character set. - * </p> - * <p> - * Every implementation of the Java platform is required to support this character encoding. - * </p> - * - * @see <a href="http://java.sun.com/j2se/1.3/docs/api/java/lang/package-summary.html#charenc">JRE character - * encoding names</a> - */ - String US_ASCII = "US-ASCII"; - - /** - * <p> - * Eight-bit Unicode Transformation Format. - * </p> - * <p> - * Every implementation of the Java platform is required to support this character encoding. - * </p> - * - * @see <a href="http://java.sun.com/j2se/1.3/docs/api/java/lang/package-summary.html#charenc">JRE character - * encoding names</a> - */ - String UTF8 = "UTF-8"; -} diff --git a/src/org/apache/commons/codec/net/URLCodec.java b/src/org/apache/commons/codec/net/URLCodec.java deleted file mode 100644 index 1bc3507..0000000 --- a/src/org/apache/commons/codec/net/URLCodec.java +++ /dev/null @@ -1,364 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.codec.net; - -import java.io.ByteArrayOutputStream; -import java.io.UnsupportedEncodingException; -import java.util.BitSet; - -import org.apache.commons.codec.BinaryDecoder; -import org.apache.commons.codec.BinaryEncoder; -import org.apache.commons.codec.DecoderException; -import org.apache.commons.codec.EncoderException; -import org.apache.commons.codec.StringDecoder; -import org.apache.commons.codec.StringEncoder; - -/** - * <p>Implements the 'www-form-urlencoded' encoding scheme, - * also misleadingly known as URL encoding.</p> - * - * <p>For more detailed information please refer to - * <a href="http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1"> - * Chapter 17.13.4 'Form content types'</a> of the - * <a href="http://www.w3.org/TR/html4/">HTML 4.01 Specification<a></p> - * - * <p> - * This codec is meant to be a replacement for standard Java classes - * {@link java.net.URLEncoder} and {@link java.net.URLDecoder} - * on older Java platforms, as these classes in Java versions below - * 1.4 rely on the platform's default charset encoding. - * </p> - * - * @author Apache Software Foundation - * @since 1.2 - * @version $Id: URLCodec.java,v 1.19 2004/03/29 07:59:00 ggregory Exp $ - */ -public class URLCodec implements BinaryEncoder, BinaryDecoder, StringEncoder, StringDecoder { - - /** - * The default charset used for string decoding and encoding. - */ - protected String charset = StringEncodings.UTF8; - - protected static byte ESCAPE_CHAR = '%'; - /** - * BitSet of www-form-url safe characters. - */ - protected static final BitSet WWW_FORM_URL = new BitSet(256); - - // Static initializer for www_form_url - static { - // alpha characters - for (int i = 'a'; i <= 'z'; i++) { - WWW_FORM_URL.set(i); - } - for (int i = 'A'; i <= 'Z'; i++) { - WWW_FORM_URL.set(i); - } - // numeric characters - for (int i = '0'; i <= '9'; i++) { - WWW_FORM_URL.set(i); - } - // special chars - WWW_FORM_URL.set('-'); - WWW_FORM_URL.set('_'); - WWW_FORM_URL.set('.'); - WWW_FORM_URL.set('*'); - // blank to be replaced with + - WWW_FORM_URL.set(' '); - } - - - /** - * Default constructor. - */ - public URLCodec() { - super(); - } - - /** - * Constructor which allows for the selection of a default charset - * - * @param charset the default string charset to use. - */ - public URLCodec(String charset) { - super(); - this.charset = charset; - } - - /** - * Encodes an array of bytes into an array of URL safe 7-bit - * characters. Unsafe characters are escaped. - * - * @param urlsafe bitset of characters deemed URL safe - * @param bytes array of bytes to convert to URL safe characters - * @return array of bytes containing URL safe characters - */ - public static final byte[] encodeUrl(BitSet urlsafe, byte[] bytes) - { - if (bytes == null) { - return null; - } - if (urlsafe == null) { - urlsafe = WWW_FORM_URL; - } - - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - for (int i = 0; i < bytes.length; i++) { - int b = bytes[i]; - if (b < 0) { - b = 256 + b; - } - if (urlsafe.get(b)) { - if (b == ' ') { - b = '+'; - } - buffer.write(b); - } else { - buffer.write('%'); - char hex1 = Character.toUpperCase( - Character.forDigit((b >> 4) & 0xF, 16)); - char hex2 = Character.toUpperCase( - Character.forDigit(b & 0xF, 16)); - buffer.write(hex1); - buffer.write(hex2); - } - } - return buffer.toByteArray(); - } - - - /** - * Decodes an array of URL safe 7-bit characters into an array of - * original bytes. Escaped characters are converted back to their - * original representation. - * - * @param bytes array of URL safe characters - * @return array of original bytes - * @throws DecoderException Thrown if URL decoding is unsuccessful - */ - public static final byte[] decodeUrl(byte[] bytes) - throws DecoderException - { - if (bytes == null) { - return null; - } - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - for (int i = 0; i < bytes.length; i++) { - int b = bytes[i]; - if (b == '+') { - buffer.write(' '); - } else if (b == '%') { - try { - int u = Character.digit((char)bytes[++i], 16); - int l = Character.digit((char)bytes[++i], 16); - if (u == -1 || l == -1) { - throw new DecoderException("Invalid URL encoding"); - } - buffer.write((char)((u << 4) + l)); - } catch(ArrayIndexOutOfBoundsException e) { - throw new DecoderException("Invalid URL encoding"); - } - } else { - buffer.write(b); - } - } - return buffer.toByteArray(); - } - - - /** - * Encodes an array of bytes into an array of URL safe 7-bit - * characters. Unsafe characters are escaped. - * - * @param bytes array of bytes to convert to URL safe characters - * @return array of bytes containing URL safe characters - */ - public byte[] encode(byte[] bytes) { - return encodeUrl(WWW_FORM_URL, bytes); - } - - - /** - * Decodes an array of URL safe 7-bit characters into an array of - * original bytes. Escaped characters are converted back to their - * original representation. - * - * @param bytes array of URL safe characters - * @return array of original bytes - * @throws DecoderException Thrown if URL decoding is unsuccessful - */ - public byte[] decode(byte[] bytes) throws DecoderException { - return decodeUrl(bytes); - } - - - /** - * Encodes a string into its URL safe form using the specified - * string charset. Unsafe characters are escaped. - * - * @param pString string to convert to a URL safe form - * @param charset the charset for pString - * @return URL safe string - * @throws UnsupportedEncodingException Thrown if charset is not - * supported - */ - public String encode(String pString, String charset) - throws UnsupportedEncodingException - { - if (pString == null) { - return null; - } - return new String(encode(pString.getBytes(charset)), StringEncodings.US_ASCII); - } - - - /** - * Encodes a string into its URL safe form using the default string - * charset. Unsafe characters are escaped. - * - * @param pString string to convert to a URL safe form - * @return URL safe string - * @throws EncoderException Thrown if URL encoding is unsuccessful - * - * @see #getDefaultCharset() - */ - public String encode(String pString) throws EncoderException { - if (pString == null) { - return null; - } - try { - return encode(pString, getDefaultCharset()); - } catch(UnsupportedEncodingException e) { - throw new EncoderException(e.getMessage()); - } - } - - - /** - * Decodes a URL safe string into its original form using the - * specified encoding. Escaped characters are converted back - * to their original representation. - * - * @param pString URL safe string to convert into its original form - * @param charset the original string charset - * @return original string - * @throws DecoderException Thrown if URL decoding is unsuccessful - * @throws UnsupportedEncodingException Thrown if charset is not - * supported - */ - public String decode(String pString, String charset) - throws DecoderException, UnsupportedEncodingException - { - if (pString == null) { - return null; - } - return new String(decode(pString.getBytes(StringEncodings.US_ASCII)), charset); - } - - - /** - * Decodes a URL safe string into its original form using the default - * string charset. Escaped characters are converted back to their - * original representation. - * - * @param pString URL safe string to convert into its original form - * @return original string - * @throws DecoderException Thrown if URL decoding is unsuccessful - * - * @see #getDefaultCharset() - */ - public String decode(String pString) throws DecoderException { - if (pString == null) { - return null; - } - try { - return decode(pString, getDefaultCharset()); - } catch(UnsupportedEncodingException e) { - throw new DecoderException(e.getMessage()); - } - } - - /** - * Encodes an object into its URL safe form. Unsafe characters are - * escaped. - * - * @param pObject string to convert to a URL safe form - * @return URL safe object - * @throws EncoderException Thrown if URL encoding is not - * applicable to objects of this type or - * if encoding is unsuccessful - */ - public Object encode(Object pObject) throws EncoderException { - if (pObject == null) { - return null; - } else if (pObject instanceof byte[]) { - return encode((byte[])pObject); - } else if (pObject instanceof String) { - return encode((String)pObject); - } else { - throw new EncoderException("Objects of type " + - pObject.getClass().getName() + " cannot be URL encoded"); - - } - } - - /** - * Decodes a URL safe object into its original form. Escaped - * characters are converted back to their original representation. - * - * @param pObject URL safe object to convert into its original form - * @return original object - * @throws DecoderException Thrown if URL decoding is not - * applicable to objects of this type - * if decoding is unsuccessful - */ - public Object decode(Object pObject) throws DecoderException { - if (pObject == null) { - return null; - } else if (pObject instanceof byte[]) { - return decode((byte[])pObject); - } else if (pObject instanceof String) { - return decode((String)pObject); - } else { - throw new DecoderException("Objects of type " + - pObject.getClass().getName() + " cannot be URL decoded"); - - } - } - - /** - * The <code>String</code> encoding used for decoding and encoding. - * - * @return Returns the encoding. - * - * @deprecated use #getDefaultCharset() - */ - public String getEncoding() { - return this.charset; - } - - /** - * The default charset used for string decoding and encoding. - * - * @return the default string charset. - */ - public String getDefaultCharset() { - return this.charset; - } - -} diff --git a/src/org/apache/commons/codec/net/package.html b/src/org/apache/commons/codec/net/package.html deleted file mode 100644 index 4607c57..0000000 --- a/src/org/apache/commons/codec/net/package.html +++ /dev/null @@ -1,22 +0,0 @@ -<!-- -Copyright 2003-2004 The Apache Software Foundation. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. ---> -<html> - <body> - <p> - Network related encoding and decoding. - </p> - </body> -</html> diff --git a/src/org/apache/commons/codec/overview.html b/src/org/apache/commons/codec/overview.html deleted file mode 100644 index 6b6f6c9..0000000 --- a/src/org/apache/commons/codec/overview.html +++ /dev/null @@ -1,28 +0,0 @@ -<!-- -Copyright 2003-2004 The Apache Software Foundation. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. ---> -<!-- $Id: overview.html,v 1.6 2004/05/17 17:06:10 ggregory Exp $ --> -<html> -<body> -<p> -This document is the API specification for the Apache Jakarta Commons Codec Library, version 1.3. -</p> -<p> -This library requires a JRE version of 1.2.2 or greater. -The hypertext links originating from this document point to Sun's version 1.3 API as the 1.2.2 API documentation -is no longer on-line. -</p> -</body> -</html> diff --git a/src/org/apache/commons/codec/package.html b/src/org/apache/commons/codec/package.html deleted file mode 100644 index b7ccf03..0000000 --- a/src/org/apache/commons/codec/package.html +++ /dev/null @@ -1,99 +0,0 @@ -<!-- -Copyright 2003-2004 The Apache Software Foundation. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. ---> -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> -<html> - <head> - </head> - <body> - <p>A small set of interfaces used by - the various implementations in the sub-packages.</p> - - <p>Definitive implementations of commonly used encoders and decoders.</p> - - <p>Codec is currently comprised of a modest set of utilities and a - simple framework for String encoding and decoding in three categories: - Binary Encoders, Language Encoders, and Network Encoders. </p> - - <h4><a name="Common Encoders">Binary Encoders</a></h4> - - <table border="1" width="100%" cellspacing="2" cellpadding="3"> - <tbody> - <tr> - <td> - <a href="binary/Base64.html"> - org.apache.commons.codec.binary.Base64</a> - </td> - <td> - Provides Base64 content-transfer-encoding as defined in - <a href="http://www.ietf.org/rfc/rfc2045.txt"> RFC 2045</a> - </td> - <td>Production</td> - </tr> - <tr> - <td> - <a href="binary/Hex.html"> - org.apache.commons.codec.binary.Hex</a> - </td> - <td> - Converts an array of bytes into an array of characters - representing the hexidecimal values of each byte in order - </td> - <td>Production</td> - </tr> - </tbody> - </table> - <h4> - <a name="Language Encoders">Language Encoders</a> - </h4> - <p> - Codec contains a number of commonly used language and phonetic - encoders - </p> - <table border="1" width="100%" cellspacing="2" cellpadding="3"> - <tbody> - <tr> - <td> - <a href="#">org.apache.commons.codec.language.Soundex</a> - </td> - <td>Implementation of the Soundex algorithm.</td> - <td>Production</td> - </tr> - <tr> - <td> - <a href="#">org.apache.commons.codec.language.Metaphone</a> - </td> - <td>Implementation of the Metaphone algorithm.</td> - <td>Production</td> - </tr> - </tbody> - </table> - <h4><a name="Network_Encoders">Network Encoders</a></h4> - <h4> </h4> - <p> Codec contains network related encoders </p> - <table border="1" width="100%" cellspacing="2" cellpadding="3"> - <tbody> - <tr> - <td> - <a href="#">org.apache.commons.codec.net.URLCodec</a> - </td> - <td>Implements the 'www-form-urlencoded' encoding scheme.</td> - <td>Production</td> - </tr> - </tbody> - </table> - <br> - </body> -</html> diff --git a/src/org/apache/commons/logging/Log.java b/src/org/apache/commons/logging/Log.java deleted file mode 100644 index 9203f3f..0000000 --- a/src/org/apache/commons/logging/Log.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.commons.logging; - -/** - * <p>A simple logging interface abstracting logging APIs. In order to be - * instantiated successfully by {@link LogFactory}, classes that implement - * this interface must have a constructor that takes a single String - * parameter representing the "name" of this Log.</p> - * - * <p> The six logging levels used by <code>Log</code> are (in order): - * <ol> - * <li>trace (the least serious)</li> - * <li>debug</li> - * <li>info</li> - * <li>warn</li> - * <li>error</li> - * <li>fatal (the most serious)</li> - * </ol> - * The mapping of these log levels to the concepts used by the underlying - * logging system is implementation dependent. - * The implemention should ensure, though, that this ordering behaves - * as expected.</p> - * - * <p>Performance is often a logging concern. - * By examining the appropriate property, - * a component can avoid expensive operations (producing information - * to be logged).</p> - * - * <p> For example, - * <code><pre> - * if (log.isDebugEnabled()) { - * ... do something expensive ... - * log.debug(theResult); - * } - * </pre></code> - * </p> - * - * <p>Configuration of the underlying logging system will generally be done - * external to the Logging APIs, through whatever mechanism is supported by - * that system.</p> - * - * @author <a href="mailto:sanders@apache.org">Scott Sanders</a> - * @author Rod Waldhoff - * @version $Id: Log.java 381838 2006-02-28 23:57:11Z skitching $ - */ -public interface Log { - - - // ----------------------------------------------------- Logging Properties - - - /** - * <p> Is debug logging currently enabled? </p> - * - * <p> Call this method to prevent having to perform expensive operations - * (for example, <code>String</code> concatenation) - * when the log level is more than debug. </p> - * - * @return true if debug is enabled in the underlying logger. - */ - public boolean isDebugEnabled(); - - - /** - * <p> Is error logging currently enabled? </p> - * - * <p> Call this method to prevent having to perform expensive operations - * (for example, <code>String</code> concatenation) - * when the log level is more than error. </p> - * - * @return true if error is enabled in the underlying logger. - */ - public boolean isErrorEnabled(); - - - /** - * <p> Is fatal logging currently enabled? </p> - * - * <p> Call this method to prevent having to perform expensive operations - * (for example, <code>String</code> concatenation) - * when the log level is more than fatal. </p> - * - * @return true if fatal is enabled in the underlying logger. - */ - public boolean isFatalEnabled(); - - - /** - * <p> Is info logging currently enabled? </p> - * - * <p> Call this method to prevent having to perform expensive operations - * (for example, <code>String</code> concatenation) - * when the log level is more than info. </p> - * - * @return true if info is enabled in the underlying logger. - */ - public boolean isInfoEnabled(); - - - /** - * <p> Is trace logging currently enabled? </p> - * - * <p> Call this method to prevent having to perform expensive operations - * (for example, <code>String</code> concatenation) - * when the log level is more than trace. </p> - * - * @return true if trace is enabled in the underlying logger. - */ - public boolean isTraceEnabled(); - - - /** - * <p> Is warn logging currently enabled? </p> - * - * <p> Call this method to prevent having to perform expensive operations - * (for example, <code>String</code> concatenation) - * when the log level is more than warn. </p> - * - * @return true if warn is enabled in the underlying logger. - */ - public boolean isWarnEnabled(); - - - // -------------------------------------------------------- Logging Methods - - - /** - * <p> Log a message with trace log level. </p> - * - * @param message log this message - */ - public void trace(Object message); - - - /** - * <p> Log an error with trace log level. </p> - * - * @param message log this message - * @param t log this cause - */ - public void trace(Object message, Throwable t); - - - /** - * <p> Log a message with debug log level. </p> - * - * @param message log this message - */ - public void debug(Object message); - - - /** - * <p> Log an error with debug log level. </p> - * - * @param message log this message - * @param t log this cause - */ - public void debug(Object message, Throwable t); - - - /** - * <p> Log a message with info log level. </p> - * - * @param message log this message - */ - public void info(Object message); - - - /** - * <p> Log an error with info log level. </p> - * - * @param message log this message - * @param t log this cause - */ - public void info(Object message, Throwable t); - - - /** - * <p> Log a message with warn log level. </p> - * - * @param message log this message - */ - public void warn(Object message); - - - /** - * <p> Log an error with warn log level. </p> - * - * @param message log this message - * @param t log this cause - */ - public void warn(Object message, Throwable t); - - - /** - * <p> Log a message with error log level. </p> - * - * @param message log this message - */ - public void error(Object message); - - - /** - * <p> Log an error with error log level. </p> - * - * @param message log this message - * @param t log this cause - */ - public void error(Object message, Throwable t); - - - /** - * <p> Log a message with fatal log level. </p> - * - * @param message log this message - */ - public void fatal(Object message); - - - /** - * <p> Log an error with fatal log level. </p> - * - * @param message log this message - * @param t log this cause - */ - public void fatal(Object message, Throwable t); - - -} diff --git a/src/org/apache/commons/logging/LogConfigurationException.java b/src/org/apache/commons/logging/LogConfigurationException.java deleted file mode 100644 index b34387b..0000000 --- a/src/org/apache/commons/logging/LogConfigurationException.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.logging; - - -/** - * <p>An exception that is thrown only if a suitable <code>LogFactory</code> - * or <code>Log</code> instance cannot be created by the corresponding - * factory methods.</p> - * - * @author Craig R. McClanahan - * @version $Revision: 155426 $ $Date: 2005-02-26 13:10:49 +0000 (Sat, 26 Feb 2005) $ - */ - -public class LogConfigurationException extends RuntimeException { - - - /** - * Construct a new exception with <code>null</code> as its detail message. - */ - public LogConfigurationException() { - - super(); - - } - - - /** - * Construct a new exception with the specified detail message. - * - * @param message The detail message - */ - public LogConfigurationException(String message) { - - super(message); - - } - - - /** - * Construct a new exception with the specified cause and a derived - * detail message. - * - * @param cause The underlying cause - */ - public LogConfigurationException(Throwable cause) { - - this((cause == null) ? null : cause.toString(), cause); - - } - - - /** - * Construct a new exception with the specified detail message and cause. - * - * @param message The detail message - * @param cause The underlying cause - */ - public LogConfigurationException(String message, Throwable cause) { - - super(message + " (Caused by " + cause + ")"); - this.cause = cause; // Two-argument version requires JDK 1.4 or later - - } - - - /** - * The underlying cause of this exception. - */ - protected Throwable cause = null; - - - /** - * Return the underlying cause of this exception (if any). - */ - public Throwable getCause() { - - return (this.cause); - - } - - -} diff --git a/src/org/apache/commons/logging/LogFactory.java b/src/org/apache/commons/logging/LogFactory.java deleted file mode 100644 index 107d0f7..0000000 --- a/src/org/apache/commons/logging/LogFactory.java +++ /dev/null @@ -1,1740 +0,0 @@ -/* - * Copyright 2001-2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.logging; - - -import java.io.BufferedReader; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.PrintStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.URL; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Properties; - - -/** - * <p>Factory for creating {@link Log} instances, with discovery and - * configuration features similar to that employed by standard Java APIs - * such as JAXP.</p> - * - * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation is heavily - * based on the SAXParserFactory and DocumentBuilderFactory implementations - * (corresponding to the JAXP pluggability APIs) found in Apache Xerces.</p> - * - * @author Craig R. McClanahan - * @author Costin Manolache - * @author Richard A. Sitze - * @version $Revision: 399431 $ $Date: 2006-05-03 21:58:34 +0100 (Wed, 03 May 2006) $ - */ - -public abstract class LogFactory { - - - // ----------------------------------------------------- Manifest Constants - - /** - * The name (<code>priority</code>) of the key in the config file used to - * specify the priority of that particular config file. The associated value - * is a floating-point number; higher values take priority over lower values. - */ - public static final String PRIORITY_KEY = "priority"; - - /** - * The name (<code>use_tccl</code>) of the key in the config file used - * to specify whether logging classes should be loaded via the thread - * context class loader (TCCL), or not. By default, the TCCL is used. - */ - public static final String TCCL_KEY = "use_tccl"; - - /** - * The name (<code>org.apache.commons.logging.LogFactory</code>) of the property - * used to identify the LogFactory implementation - * class name. This can be used as a system property, or as an entry in a - * configuration properties file. - */ - public static final String FACTORY_PROPERTY = - "org.apache.commons.logging.LogFactory"; - - /** - * The fully qualified class name of the fallback <code>LogFactory</code> - * implementation class to use, if no other can be found. - */ - public static final String FACTORY_DEFAULT = - "org.apache.commons.logging.impl.LogFactoryImpl"; - - /** - * The name (<code>commons-logging.properties</code>) of the properties file to search for. - */ - public static final String FACTORY_PROPERTIES = - "commons-logging.properties"; - - /** - * JDK1.3+ <a href="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#Service%20Provider"> - * 'Service Provider' specification</a>. - * - */ - protected static final String SERVICE_ID = - "META-INF/services/org.apache.commons.logging.LogFactory"; - - /** - * The name (<code>org.apache.commons.logging.diagnostics.dest</code>) - * of the property used to enable internal commons-logging - * diagnostic output, in order to get information on what logging - * implementations are being discovered, what classloaders they - * are loaded through, etc. - * <p> - * If a system property of this name is set then the value is - * assumed to be the name of a file. The special strings - * STDOUT or STDERR (case-sensitive) indicate output to - * System.out and System.err respectively. - * <p> - * Diagnostic logging should be used only to debug problematic - * configurations and should not be set in normal production use. - */ - public static final String DIAGNOSTICS_DEST_PROPERTY = - "org.apache.commons.logging.diagnostics.dest"; - - /** - * When null (the usual case), no diagnostic output will be - * generated by LogFactory or LogFactoryImpl. When non-null, - * interesting events will be written to the specified object. - */ - private static PrintStream diagnosticsStream = null; - - /** - * A string that gets prefixed to every message output by the - * logDiagnostic method, so that users can clearly see which - * LogFactory class is generating the output. - */ - private static String diagnosticPrefix; - - /** - * <p>Setting this system property - * (<code>org.apache.commons.logging.LogFactory.HashtableImpl</code>) - * value allows the <code>Hashtable</code> used to store - * classloaders to be substituted by an alternative implementation. - * </p> - * <p> - * <strong>Note:</strong> <code>LogFactory</code> will print: - * <code><pre> - * [ERROR] LogFactory: Load of custom hashtable failed</em> - * </pre></code> - * to system error and then continue using a standard Hashtable. - * </p> - * <p> - * <strong>Usage:</strong> Set this property when Java is invoked - * and <code>LogFactory</code> will attempt to load a new instance - * of the given implementation class. - * For example, running the following ant scriplet: - * <code><pre> - * <java classname="${test.runner}" fork="yes" failonerror="${test.failonerror}"> - * ... - * <sysproperty - * key="org.apache.commons.logging.LogFactory.HashtableImpl" - * value="org.apache.commons.logging.AltHashtable"/> - * </java> - * </pre></code> - * will mean that <code>LogFactory</code> will load an instance of - * <code>org.apache.commons.logging.AltHashtable</code>. - * </p> - * <p> - * A typical use case is to allow a custom - * Hashtable implementation using weak references to be substituted. - * This will allow classloaders to be garbage collected without - * the need to release them (on 1.3+ JVMs only, of course ;) - * </p> - */ - public static final String HASHTABLE_IMPLEMENTATION_PROPERTY = - "org.apache.commons.logging.LogFactory.HashtableImpl"; - /** Name used to load the weak hashtable implementation by names */ - private static final String WEAK_HASHTABLE_CLASSNAME = - "org.apache.commons.logging.impl.WeakHashtable"; - - /** - * A reference to the classloader that loaded this class. This is the - * same as LogFactory.class.getClassLoader(). However computing this - * value isn't quite as simple as that, as we potentially need to use - * AccessControllers etc. It's more efficient to compute it once and - * cache it here. - */ - private static ClassLoader thisClassLoader; - - // ----------------------------------------------------------- Constructors - - - /** - * Protected constructor that is not available for public use. - */ - protected LogFactory() { - } - - // --------------------------------------------------------- Public Methods - - - /** - * Return the configuration attribute with the specified name (if any), - * or <code>null</code> if there is no such attribute. - * - * @param name Name of the attribute to return - */ - public abstract Object getAttribute(String name); - - - /** - * Return an array containing the names of all currently defined - * configuration attributes. If there are no such attributes, a zero - * length array is returned. - */ - public abstract String[] getAttributeNames(); - - - /** - * Convenience method to derive a name from the specified class and - * call <code>getInstance(String)</code> with it. - * - * @param clazz Class for which a suitable Log name will be derived - * - * @exception LogConfigurationException if a suitable <code>Log</code> - * instance cannot be returned - */ - public abstract Log getInstance(Class clazz) - throws LogConfigurationException; - - - /** - * <p>Construct (if necessary) and return a <code>Log</code> instance, - * using the factory's current set of configuration attributes.</p> - * - * <p><strong>NOTE</strong> - Depending upon the implementation of - * the <code>LogFactory</code> you are using, the <code>Log</code> - * instance you are returned may or may not be local to the current - * application, and may or may not be returned again on a subsequent - * call with the same name argument.</p> - * - * @param name Logical name of the <code>Log</code> instance to be - * returned (the meaning of this name is only known to the underlying - * logging implementation that is being wrapped) - * - * @exception LogConfigurationException if a suitable <code>Log</code> - * instance cannot be returned - */ - public abstract Log getInstance(String name) - throws LogConfigurationException; - - - /** - * Release any internal references to previously created {@link Log} - * instances returned by this factory. This is useful in environments - * like servlet containers, which implement application reloading by - * throwing away a ClassLoader. Dangling references to objects in that - * class loader would prevent garbage collection. - */ - public abstract void release(); - - - /** - * Remove any configuration attribute associated with the specified name. - * If there is no such attribute, no action is taken. - * - * @param name Name of the attribute to remove - */ - public abstract void removeAttribute(String name); - - - /** - * Set the configuration attribute with the specified name. Calling - * this with a <code>null</code> value is equivalent to calling - * <code>removeAttribute(name)</code>. - * - * @param name Name of the attribute to set - * @param value Value of the attribute to set, or <code>null</code> - * to remove any setting for this attribute - */ - public abstract void setAttribute(String name, Object value); - - - // ------------------------------------------------------- Static Variables - - - /** - * The previously constructed <code>LogFactory</code> instances, keyed by - * the <code>ClassLoader</code> with which it was created. - */ - protected static Hashtable factories = null; - - /** - * Prevously constructed <code>LogFactory</code> instance as in the - * <code>factories</code> map, but for the case where - * <code>getClassLoader</code> returns <code>null</code>. - * This can happen when: - * <ul> - * <li>using JDK1.1 and the calling code is loaded via the system - * classloader (very common)</li> - * <li>using JDK1.2+ and the calling code is loaded via the boot - * classloader (only likely for embedded systems work).</li> - * </ul> - * Note that <code>factories</code> is a <i>Hashtable</i> (not a HashMap), - * and hashtables don't allow null as a key. - */ - protected static LogFactory nullClassLoaderFactory = null; - - /** - * Create the hashtable which will be used to store a map of - * (context-classloader -> logfactory-object). Version 1.2+ of Java - * supports "weak references", allowing a custom Hashtable class - * to be used which uses only weak references to its keys. Using weak - * references can fix memory leaks on webapp unload in some cases (though - * not all). Version 1.1 of Java does not support weak references, so we - * must dynamically determine which we are using. And just for fun, this - * code also supports the ability for a system property to specify an - * arbitrary Hashtable implementation name. - * <p> - * Note that the correct way to ensure no memory leaks occur is to ensure - * that LogFactory.release(contextClassLoader) is called whenever a - * webapp is undeployed. - */ - private static final Hashtable createFactoryStore() { - Hashtable result = null; - String storeImplementationClass - = System.getProperty(HASHTABLE_IMPLEMENTATION_PROPERTY); - if (storeImplementationClass == null) { - storeImplementationClass = WEAK_HASHTABLE_CLASSNAME; - } - try { - Class implementationClass = Class.forName(storeImplementationClass); - result = (Hashtable) implementationClass.newInstance(); - - } catch (Throwable t) { - // ignore - if (!WEAK_HASHTABLE_CLASSNAME.equals(storeImplementationClass)) { - // if the user's trying to set up a custom implementation, give a clue - if (isDiagnosticsEnabled()) { - // use internal logging to issue the warning - logDiagnostic("[ERROR] LogFactory: Load of custom hashtable failed"); - } else { - // we *really* want this output, even if diagnostics weren't - // explicitly enabled by the user. - System.err.println("[ERROR] LogFactory: Load of custom hashtable failed"); - } - } - } - if (result == null) { - result = new Hashtable(); - } - return result; - } - - - // --------------------------------------------------------- Static Methods - - /** - * <p>Construct (if necessary) and return a <code>LogFactory</code> - * instance, using the following ordered lookup procedure to determine - * the name of the implementation class to be loaded.</p> - * <ul> - * <li>The <code>org.apache.commons.logging.LogFactory</code> system - * property.</li> - * <li>The JDK 1.3 Service Discovery mechanism</li> - * <li>Use the properties file <code>commons-logging.properties</code> - * file, if found in the class path of this class. The configuration - * file is in standard <code>java.util.Properties</code> format and - * contains the fully qualified name of the implementation class - * with the key being the system property defined above.</li> - * <li>Fall back to a default implementation class - * (<code>org.apache.commons.logging.impl.LogFactoryImpl</code>).</li> - * </ul> - * - * <p><em>NOTE</em> - If the properties file method of identifying the - * <code>LogFactory</code> implementation class is utilized, all of the - * properties defined in this file will be set as configuration attributes - * on the corresponding <code>LogFactory</code> instance.</p> - * - * <p><em>NOTE</em> - In a multithreaded environment it is possible - * that two different instances will be returned for the same - * classloader environment. - * </p> - * - * @exception LogConfigurationException if the implementation class is not - * available or cannot be instantiated. - */ - public static LogFactory getFactory() throws LogConfigurationException { - // Identify the class loader we will be using - ClassLoader contextClassLoader = getContextClassLoader(); - - if (contextClassLoader == null) { - // This is an odd enough situation to report about. This - // output will be a nuisance on JDK1.1, as the system - // classloader is null in that environment. - if (isDiagnosticsEnabled()) { - logDiagnostic("Context classloader is null."); - } - } - - // Return any previously registered factory for this class loader - LogFactory factory = getCachedFactory(contextClassLoader); - if (factory != null) { - return factory; - } - - if (isDiagnosticsEnabled()) { - logDiagnostic( - "[LOOKUP] LogFactory implementation requested for the first time for context classloader " - + objectId(contextClassLoader)); - logHierarchy("[LOOKUP] ", contextClassLoader); - } - - // Load properties file. - // - // If the properties file exists, then its contents are used as - // "attributes" on the LogFactory implementation class. One particular - // property may also control which LogFactory concrete subclass is - // used, but only if other discovery mechanisms fail.. - // - // As the properties file (if it exists) will be used one way or - // another in the end we may as well look for it first. - - Properties props = getConfigurationFile(contextClassLoader, FACTORY_PROPERTIES); - - // Determine whether we will be using the thread context class loader to - // load logging classes or not by checking the loaded properties file (if any). - ClassLoader baseClassLoader = contextClassLoader; - if (props != null) { - String useTCCLStr = props.getProperty(TCCL_KEY); - if (useTCCLStr != null) { - // The Boolean.valueOf(useTCCLStr).booleanValue() formulation - // is required for Java 1.2 compatability. - if (Boolean.valueOf(useTCCLStr).booleanValue() == false) { - // Don't use current context classloader when locating any - // LogFactory or Log classes, just use the class that loaded - // this abstract class. When this class is deployed in a shared - // classpath of a container, it means webapps cannot deploy their - // own logging implementations. It also means that it is up to the - // implementation whether to load library-specific config files - // from the TCCL or not. - baseClassLoader = thisClassLoader; - } - } - } - - // Determine which concrete LogFactory subclass to use. - // First, try a global system property - if (isDiagnosticsEnabled()) { - logDiagnostic( - "[LOOKUP] Looking for system property [" + FACTORY_PROPERTY - + "] to define the LogFactory subclass to use..."); - } - - try { - String factoryClass = System.getProperty(FACTORY_PROPERTY); - if (factoryClass != null) { - if (isDiagnosticsEnabled()) { - logDiagnostic( - "[LOOKUP] Creating an instance of LogFactory class '" + factoryClass - + "' as specified by system property " + FACTORY_PROPERTY); - } - - factory = newFactory(factoryClass, baseClassLoader, contextClassLoader); - } else { - if (isDiagnosticsEnabled()) { - logDiagnostic( - "[LOOKUP] No system property [" + FACTORY_PROPERTY - + "] defined."); - } - } - } catch (SecurityException e) { - if (isDiagnosticsEnabled()) { - logDiagnostic( - "[LOOKUP] A security exception occurred while trying to create an" - + " instance of the custom factory class" - + ": [" + e.getMessage().trim() - + "]. Trying alternative implementations..."); - } - ; // ignore - } catch(RuntimeException e) { - // This is not consistent with the behaviour when a bad LogFactory class is - // specified in a services file. - // - // One possible exception that can occur here is a ClassCastException when - // the specified class wasn't castable to this LogFactory type. - if (isDiagnosticsEnabled()) { - logDiagnostic( - "[LOOKUP] An exception occurred while trying to create an" - + " instance of the custom factory class" - + ": [" + e.getMessage().trim() - + "] as specified by a system property."); - } - throw e; - } - - - // Second, try to find a service by using the JDK1.3 class - // discovery mechanism, which involves putting a file with the name - // of an interface class in the META-INF/services directory, where the - // contents of the file is a single line specifying a concrete class - // that implements the desired interface. - - if (factory == null) { - if (isDiagnosticsEnabled()) { - logDiagnostic( - "[LOOKUP] Looking for a resource file of name [" + SERVICE_ID - + "] to define the LogFactory subclass to use..."); - } - try { - InputStream is = getResourceAsStream(contextClassLoader, - SERVICE_ID); - - if( is != null ) { - // This code is needed by EBCDIC and other strange systems. - // It's a fix for bugs reported in xerces - BufferedReader rd; - try { - rd = new BufferedReader(new InputStreamReader(is, "UTF-8")); - } catch (java.io.UnsupportedEncodingException e) { - rd = new BufferedReader(new InputStreamReader(is)); - } - - String factoryClassName = rd.readLine(); - rd.close(); - - if (factoryClassName != null && - ! "".equals(factoryClassName)) { - if (isDiagnosticsEnabled()) { - logDiagnostic( - "[LOOKUP] Creating an instance of LogFactory class " + factoryClassName - + " as specified by file '" + SERVICE_ID - + "' which was present in the path of the context" - + " classloader."); - } - factory = newFactory(factoryClassName, baseClassLoader, contextClassLoader ); - } - } else { - // is == null - if (isDiagnosticsEnabled()) { - logDiagnostic( - "[LOOKUP] No resource file with name '" + SERVICE_ID - + "' found."); - } - } - } catch( Exception ex ) { - // note: if the specified LogFactory class wasn't compatible with LogFactory - // for some reason, a ClassCastException will be caught here, and attempts will - // continue to find a compatible class. - if (isDiagnosticsEnabled()) { - logDiagnostic( - "[LOOKUP] A security exception occurred while trying to create an" - + " instance of the custom factory class" - + ": [" + ex.getMessage().trim() - + "]. Trying alternative implementations..."); - } - ; // ignore - } - } - - - // Third try looking into the properties file read earlier (if found) - - if (factory == null) { - if (props != null) { - if (isDiagnosticsEnabled()) { - logDiagnostic( - "[LOOKUP] Looking in properties file for entry with key '" - + FACTORY_PROPERTY - + "' to define the LogFactory subclass to use..."); - } - String factoryClass = props.getProperty(FACTORY_PROPERTY); - if (factoryClass != null) { - if (isDiagnosticsEnabled()) { - logDiagnostic( - "[LOOKUP] Properties file specifies LogFactory subclass '" - + factoryClass + "'"); - } - factory = newFactory(factoryClass, baseClassLoader, contextClassLoader); - - // TODO: think about whether we need to handle exceptions from newFactory - } else { - if (isDiagnosticsEnabled()) { - logDiagnostic( - "[LOOKUP] Properties file has no entry specifying LogFactory subclass."); - } - } - } else { - if (isDiagnosticsEnabled()) { - logDiagnostic( - "[LOOKUP] No properties file available to determine" - + " LogFactory subclass from.."); - } - } - } - - - // Fourth, try the fallback implementation class - - if (factory == null) { - if (isDiagnosticsEnabled()) { - logDiagnostic( - "[LOOKUP] Loading the default LogFactory implementation '" + FACTORY_DEFAULT - + "' via the same classloader that loaded this LogFactory" - + " class (ie not looking in the context classloader)."); - } - - // Note: unlike the above code which can try to load custom LogFactory - // implementations via the TCCL, we don't try to load the default LogFactory - // implementation via the context classloader because: - // * that can cause problems (see comments in newFactory method) - // * no-one should be customising the code of the default class - // Yes, we do give up the ability for the child to ship a newer - // version of the LogFactoryImpl class and have it used dynamically - // by an old LogFactory class in the parent, but that isn't - // necessarily a good idea anyway. - factory = newFactory(FACTORY_DEFAULT, thisClassLoader, contextClassLoader); - } - - if (factory != null) { - /** - * Always cache using context class loader. - */ - cacheFactory(contextClassLoader, factory); - - if( props!=null ) { - Enumeration names = props.propertyNames(); - while (names.hasMoreElements()) { - String name = (String) names.nextElement(); - String value = props.getProperty(name); - factory.setAttribute(name, value); - } - } - } - - return factory; - } - - - /** - * Convenience method to return a named logger, without the application - * having to care about factories. - * - * @param clazz Class from which a log name will be derived - * - * @exception LogConfigurationException if a suitable <code>Log</code> - * instance cannot be returned - */ - public static Log getLog(Class clazz) - throws LogConfigurationException { - - // BEGIN android-added - return getLog(clazz.getName()); - // END android-added - // BEGIN android-deleted - //return (getFactory().getInstance(clazz)); - // END android-deleted - - } - - - /** - * Convenience method to return a named logger, without the application - * having to care about factories. - * - * @param name Logical name of the <code>Log</code> instance to be - * returned (the meaning of this name is only known to the underlying - * logging implementation that is being wrapped) - * - * @exception LogConfigurationException if a suitable <code>Log</code> - * instance cannot be returned - */ - public static Log getLog(String name) - throws LogConfigurationException { - - // BEGIN android-added - return new org.apache.commons.logging.impl.Jdk14Logger(name); - // END android-added - // BEGIN android-deleted - //return (getFactory().getInstance(name)); - // END android-deleted - - } - - - /** - * Release any internal references to previously created {@link LogFactory} - * instances that have been associated with the specified class loader - * (if any), after calling the instance method <code>release()</code> on - * each of them. - * - * @param classLoader ClassLoader for which to release the LogFactory - */ - public static void release(ClassLoader classLoader) { - - if (isDiagnosticsEnabled()) { - logDiagnostic("Releasing factory for classloader " + objectId(classLoader)); - } - synchronized (factories) { - if (classLoader == null) { - if (nullClassLoaderFactory != null) { - nullClassLoaderFactory.release(); - nullClassLoaderFactory = null; - } - } else { - LogFactory factory = (LogFactory) factories.get(classLoader); - if (factory != null) { - factory.release(); - factories.remove(classLoader); - } - } - } - - } - - - /** - * Release any internal references to previously created {@link LogFactory} - * instances, after calling the instance method <code>release()</code> on - * each of them. This is useful in environments like servlet containers, - * which implement application reloading by throwing away a ClassLoader. - * Dangling references to objects in that class loader would prevent - * garbage collection. - */ - public static void releaseAll() { - - if (isDiagnosticsEnabled()) { - logDiagnostic("Releasing factory for all classloaders."); - } - synchronized (factories) { - Enumeration elements = factories.elements(); - while (elements.hasMoreElements()) { - LogFactory element = (LogFactory) elements.nextElement(); - element.release(); - } - factories.clear(); - - if (nullClassLoaderFactory != null) { - nullClassLoaderFactory.release(); - nullClassLoaderFactory = null; - } - } - - } - - - // ------------------------------------------------------ Protected Methods - - /** - * Safely get access to the classloader for the specified class. - * <p> - * Theoretically, calling getClassLoader can throw a security exception, - * and so should be done under an AccessController in order to provide - * maximum flexibility. However in practice people don't appear to use - * security policies that forbid getClassLoader calls. So for the moment - * all code is written to call this method rather than Class.getClassLoader, - * so that we could put AccessController stuff in this method without any - * disruption later if we need to. - * <p> - * Even when using an AccessController, however, this method can still - * throw SecurityException. Commons-logging basically relies on the - * ability to access classloaders, ie a policy that forbids all - * classloader access will also prevent commons-logging from working: - * currently this method will throw an exception preventing the entire app - * from starting up. Maybe it would be good to detect this situation and - * just disable all commons-logging? Not high priority though - as stated - * above, security policies that prevent classloader access aren't common. - * - * @since 1.1 - */ - protected static ClassLoader getClassLoader(Class clazz) { - try { - return clazz.getClassLoader(); - } catch(SecurityException ex) { - if (isDiagnosticsEnabled()) { - logDiagnostic( - "Unable to get classloader for class '" + clazz - + "' due to security restrictions - " + ex.getMessage()); - } - throw ex; - } - } - - /** - * Calls LogFactory.directGetContextClassLoader under the control of an - * AccessController class. This means that java code running under a - * security manager that forbids access to ClassLoaders will still work - * if this class is given appropriate privileges, even when the caller - * doesn't have such privileges. Without using an AccessController, the - * the entire call stack must have the privilege before the call is - * allowed. - * - * @return the context classloader associated with the current thread, - * or null if security doesn't allow it. - * - * @throws LogConfigurationException if there was some weird error while - * attempting to get the context classloader. - * - * @throws SecurityException if the current java security policy doesn't - * allow this class to access the context classloader. - */ - protected static ClassLoader getContextClassLoader() - throws LogConfigurationException { - - return (ClassLoader)AccessController.doPrivileged( - new PrivilegedAction() { - public Object run() { - return directGetContextClassLoader(); - } - }); - } - - /** - * Return the thread context class loader if available; otherwise return - * null. - * <p> - * Most/all code should call getContextClassLoader rather than calling - * this method directly. - * <p> - * The thread context class loader is available for JDK 1.2 - * or later, if certain security conditions are met. - * <p> - * Note that no internal logging is done within this method because - * this method is called every time LogFactory.getLogger() is called, - * and we don't want too much output generated here. - * - * @exception LogConfigurationException if a suitable class loader - * cannot be identified. - * - * @exception SecurityException if the java security policy forbids - * access to the context classloader from one of the classes in the - * current call stack. - * @since 1.1 - */ - protected static ClassLoader directGetContextClassLoader() - throws LogConfigurationException - { - ClassLoader classLoader = null; - - try { - // Are we running on a JDK 1.2 or later system? - Method method = Thread.class.getMethod("getContextClassLoader", - (Class[]) null); - - // Get the thread context class loader (if there is one) - try { - classLoader = (ClassLoader)method.invoke(Thread.currentThread(), - (Object[]) null); - } catch (IllegalAccessException e) { - throw new LogConfigurationException - ("Unexpected IllegalAccessException", e); - } catch (InvocationTargetException e) { - /** - * InvocationTargetException is thrown by 'invoke' when - * the method being invoked (getContextClassLoader) throws - * an exception. - * - * getContextClassLoader() throws SecurityException when - * the context class loader isn't an ancestor of the - * calling class's class loader, or if security - * permissions are restricted. - * - * In the first case (not related), we want to ignore and - * keep going. We cannot help but also ignore the second - * with the logic below, but other calls elsewhere (to - * obtain a class loader) will trigger this exception where - * we can make a distinction. - */ - if (e.getTargetException() instanceof SecurityException) { - ; // ignore - } else { - // Capture 'e.getTargetException()' exception for details - // alternate: log 'e.getTargetException()', and pass back 'e'. - throw new LogConfigurationException - ("Unexpected InvocationTargetException", e.getTargetException()); - } - } - } catch (NoSuchMethodException e) { - // Assume we are running on JDK 1.1 - classLoader = getClassLoader(LogFactory.class); - - // We deliberately don't log a message here to outputStream; - // this message would be output for every call to LogFactory.getLog() - // when running on JDK1.1 - // - // if (outputStream != null) { - // outputStream.println( - // "Method Thread.getContextClassLoader does not exist;" - // + " assuming this is JDK 1.1, and that the context" - // + " classloader is the same as the class that loaded" - // + " the concrete LogFactory class."); - // } - - } - - // Return the selected class loader - return classLoader; - } - - /** - * Check cached factories (keyed by contextClassLoader) - * - * @param contextClassLoader is the context classloader associated - * with the current thread. This allows separate LogFactory objects - * per component within a container, provided each component has - * a distinct context classloader set. This parameter may be null - * in JDK1.1, and in embedded systems where jcl-using code is - * placed in the bootclasspath. - * - * @return the factory associated with the specified classloader if - * one has previously been created, or null if this is the first time - * we have seen this particular classloader. - */ - private static LogFactory getCachedFactory(ClassLoader contextClassLoader) - { - LogFactory factory = null; - - if (contextClassLoader == null) { - // We have to handle this specially, as factories is a Hashtable - // and those don't accept null as a key value. - // - // nb: nullClassLoaderFactory might be null. That's ok. - factory = nullClassLoaderFactory; - } else { - factory = (LogFactory) factories.get(contextClassLoader); - } - - return factory; - } - - /** - * Remember this factory, so later calls to LogFactory.getCachedFactory - * can return the previously created object (together with all its - * cached Log objects). - * - * @param classLoader should be the current context classloader. Note that - * this can be null under some circumstances; this is ok. - * - * @param factory should be the factory to cache. This should never be null. - */ - private static void cacheFactory(ClassLoader classLoader, LogFactory factory) - { - // Ideally we would assert(factory != null) here. However reporting - // errors from within a logging implementation is a little tricky! - - if (factory != null) { - if (classLoader == null) { - nullClassLoaderFactory = factory; - } else { - factories.put(classLoader, factory); - } - } - } - - /** - * Return a new instance of the specified <code>LogFactory</code> - * implementation class, loaded by the specified class loader. - * If that fails, try the class loader used to load this - * (abstract) LogFactory. - * <p> - * <h2>ClassLoader conflicts</h2> - * Note that there can be problems if the specified ClassLoader is not the - * same as the classloader that loaded this class, ie when loading a - * concrete LogFactory subclass via a context classloader. - * <p> - * The problem is the same one that can occur when loading a concrete Log - * subclass via a context classloader. - * <p> - * The problem occurs when code running in the context classloader calls - * class X which was loaded via a parent classloader, and class X then calls - * LogFactory.getFactory (either directly or via LogFactory.getLog). Because - * class X was loaded via the parent, it binds to LogFactory loaded via - * the parent. When the code in this method finds some LogFactoryYYYY - * class in the child (context) classloader, and there also happens to be a - * LogFactory class defined in the child classloader, then LogFactoryYYYY - * will be bound to LogFactory@childloader. It cannot be cast to - * LogFactory@parentloader, ie this method cannot return the object as - * the desired type. Note that it doesn't matter if the LogFactory class - * in the child classloader is identical to the LogFactory class in the - * parent classloader, they are not compatible. - * <p> - * The solution taken here is to simply print out an error message when - * this occurs then throw an exception. The deployer of the application - * must ensure they remove all occurrences of the LogFactory class from - * the child classloader in order to resolve the issue. Note that they - * do not have to move the custom LogFactory subclass; that is ok as - * long as the only LogFactory class it can find to bind to is in the - * parent classloader. - * <p> - * @param factoryClass Fully qualified name of the <code>LogFactory</code> - * implementation class - * @param classLoader ClassLoader from which to load this class - * @param contextClassLoader is the context that this new factory will - * manage logging for. - * - * @exception LogConfigurationException if a suitable instance - * cannot be created - * @since 1.1 - */ - protected static LogFactory newFactory(final String factoryClass, - final ClassLoader classLoader, - final ClassLoader contextClassLoader) - throws LogConfigurationException - { - // Note that any unchecked exceptions thrown by the createFactory - // method will propagate out of this method; in particular a - // ClassCastException can be thrown. - Object result = AccessController.doPrivileged( - new PrivilegedAction() { - public Object run() { - return createFactory(factoryClass, classLoader); - } - }); - - if (result instanceof LogConfigurationException) { - LogConfigurationException ex = (LogConfigurationException) result; - if (isDiagnosticsEnabled()) { - logDiagnostic( - "An error occurred while loading the factory class:" - + ex.getMessage()); - } - throw ex; - } - if (isDiagnosticsEnabled()) { - logDiagnostic( - "Created object " + objectId(result) - + " to manage classloader " + objectId(contextClassLoader)); - } - return (LogFactory)result; - } - - /** - * Method provided for backwards compatibility; see newFactory version that - * takes 3 parameters. - * <p> - * This method would only ever be called in some rather odd situation. - * Note that this method is static, so overriding in a subclass doesn't - * have any effect unless this method is called from a method in that - * subclass. However this method only makes sense to use from the - * getFactory method, and as that is almost always invoked via - * LogFactory.getFactory, any custom definition in a subclass would be - * pointless. Only a class with a custom getFactory method, then invoked - * directly via CustomFactoryImpl.getFactory or similar would ever call - * this. Anyway, it's here just in case, though the "managed class loader" - * value output to the diagnostics will not report the correct value. - */ - protected static LogFactory newFactory(final String factoryClass, - final ClassLoader classLoader) { - return newFactory(factoryClass, classLoader, null); - } - - /** - * Implements the operations described in the javadoc for newFactory. - * - * @param factoryClass - * - * @param classLoader used to load the specified factory class. This is - * expected to be either the TCCL or the classloader which loaded this - * class. Note that the classloader which loaded this class might be - * "null" (ie the bootloader) for embedded systems. - * - * @return either a LogFactory object or a LogConfigurationException object. - * @since 1.1 - */ - protected static Object createFactory(String factoryClass, ClassLoader classLoader) { - - // This will be used to diagnose bad configurations - // and allow a useful message to be sent to the user - Class logFactoryClass = null; - try { - if (classLoader != null) { - try { - // First the given class loader param (thread class loader) - - // Warning: must typecast here & allow exception - // to be generated/caught & recast properly. - logFactoryClass = classLoader.loadClass(factoryClass); - if (LogFactory.class.isAssignableFrom(logFactoryClass)) { - if (isDiagnosticsEnabled()) { - logDiagnostic( - "Loaded class " + logFactoryClass.getName() - + " from classloader " + objectId(classLoader)); - } - } else { - // - // This indicates a problem with the ClassLoader tree. - // An incompatible ClassLoader was used to load the - // implementation. - // As the same classes - // must be available in multiple class loaders, - // it is very likely that multiple JCL jars are present. - // The most likely fix for this - // problem is to remove the extra JCL jars from the - // ClassLoader hierarchy. - // - if (isDiagnosticsEnabled()) { - logDiagnostic( - "Factory class " + logFactoryClass.getName() - + " loaded from classloader " + objectId(logFactoryClass.getClassLoader()) - + " does not extend '" + LogFactory.class.getName() - + "' as loaded by this classloader."); - logHierarchy("[BAD CL TREE] ", classLoader); - } - } - - return (LogFactory) logFactoryClass.newInstance(); - - } catch (ClassNotFoundException ex) { - if (classLoader == thisClassLoader) { - // Nothing more to try, onwards. - if (isDiagnosticsEnabled()) { - logDiagnostic( - "Unable to locate any class called '" + factoryClass - + "' via classloader " + objectId(classLoader)); - } - throw ex; - } - // ignore exception, continue - } catch (NoClassDefFoundError e) { - if (classLoader == thisClassLoader) { - // Nothing more to try, onwards. - if (isDiagnosticsEnabled()) { - logDiagnostic( - "Class '" + factoryClass + "' cannot be loaded" - + " via classloader " + objectId(classLoader) - + " - it depends on some other class that cannot" - + " be found."); - } - throw e; - } - // ignore exception, continue - } catch(ClassCastException e) { - if (classLoader == thisClassLoader) { - // There's no point in falling through to the code below that - // tries again with thisClassLoader, because we've just tried - // loading with that loader (not the TCCL). Just throw an - // appropriate exception here. - - final boolean implementsLogFactory = implementsLogFactory(logFactoryClass); - - // - // Construct a good message: users may not actual expect that a custom implementation - // has been specified. Several well known containers use this mechanism to adapt JCL - // to their native logging system. - // - String msg = - "The application has specified that a custom LogFactory implementation should be used but " + - "Class '" + factoryClass + "' cannot be converted to '" - + LogFactory.class.getName() + "'. "; - if (implementsLogFactory) { - msg = msg + "The conflict is caused by the presence of multiple LogFactory classes in incompatible classloaders. " + - "Background can be found in http://jakarta.apache.org/commons/logging/tech.html. " + - "If you have not explicitly specified a custom LogFactory then it is likely that " + - "the container has set one without your knowledge. " + - "In this case, consider using the commons-logging-adapters.jar file or " + - "specifying the standard LogFactory from the command line. "; - } else { - msg = msg + "Please check the custom implementation. "; - } - msg = msg + "Help can be found @http://jakarta.apache.org/commons/logging/troubleshooting.html."; - - if (isDiagnosticsEnabled()) { - logDiagnostic(msg); - } - - ClassCastException ex = new ClassCastException(msg); - throw ex; - } - - // Ignore exception, continue. Presumably the classloader was the - // TCCL; the code below will try to load the class via thisClassLoader. - // This will handle the case where the original calling class is in - // a shared classpath but the TCCL has a copy of LogFactory and the - // specified LogFactory implementation; we will fall back to using the - // LogFactory implementation from the same classloader as this class. - // - // Issue: this doesn't handle the reverse case, where this LogFactory - // is in the webapp, and the specified LogFactory implementation is - // in a shared classpath. In that case: - // (a) the class really does implement LogFactory (bad log msg above) - // (b) the fallback code will result in exactly the same problem. - } - } - - /* At this point, either classLoader == null, OR - * classLoader was unable to load factoryClass. - * - * In either case, we call Class.forName, which is equivalent - * to LogFactory.class.getClassLoader().load(name), ie we ignore - * the classloader parameter the caller passed, and fall back - * to trying the classloader associated with this class. See the - * javadoc for the newFactory method for more info on the - * consequences of this. - * - * Notes: - * * LogFactory.class.getClassLoader() may return 'null' - * if LogFactory is loaded by the bootstrap classloader. - */ - // Warning: must typecast here & allow exception - // to be generated/caught & recast properly. - if (isDiagnosticsEnabled()) { - logDiagnostic( - "Unable to load factory class via classloader " - + objectId(classLoader) - + " - trying the classloader associated with this LogFactory."); - } - logFactoryClass = Class.forName(factoryClass); - return (LogFactory) logFactoryClass.newInstance(); - } catch (Exception e) { - // Check to see if we've got a bad configuration - if (isDiagnosticsEnabled()) { - logDiagnostic("Unable to create LogFactory instance."); - } - if (logFactoryClass != null - && !LogFactory.class.isAssignableFrom(logFactoryClass)) { - - return new LogConfigurationException( - "The chosen LogFactory implementation does not extend LogFactory." - + " Please check your configuration.", - e); - } - return new LogConfigurationException(e); - } - } - - /** - * Determines whether the given class actually implements <code>LogFactory</code>. - * Diagnostic information is also logged. - * <p> - * <strong>Usage:</strong> to diagnose whether a classloader conflict is the cause - * of incompatibility. The test used is whether the class is assignable from - * the <code>LogFactory</code> class loaded by the class's classloader. - * @param logFactoryClass <code>Class</code> which may implement <code>LogFactory</code> - * @return true if the <code>logFactoryClass</code> does extend - * <code>LogFactory</code> when that class is loaded via the same - * classloader that loaded the <code>logFactoryClass</code>. - */ - private static boolean implementsLogFactory(Class logFactoryClass) { - boolean implementsLogFactory = false; - if (logFactoryClass != null) { - try { - ClassLoader logFactoryClassLoader = logFactoryClass.getClassLoader(); - if (logFactoryClassLoader == null) { - logDiagnostic("[CUSTOM LOG FACTORY] was loaded by the boot classloader"); - } else { - logHierarchy("[CUSTOM LOG FACTORY] ", logFactoryClassLoader); - Class factoryFromCustomLoader - = Class.forName("org.apache.commons.logging.LogFactory", false, logFactoryClassLoader); - implementsLogFactory = factoryFromCustomLoader.isAssignableFrom(logFactoryClass); - if (implementsLogFactory) { - logDiagnostic("[CUSTOM LOG FACTORY] " + logFactoryClass.getName() - + " implements LogFactory but was loaded by an incompatible classloader."); - } else { - logDiagnostic("[CUSTOM LOG FACTORY] " + logFactoryClass.getName() - + " does not implement LogFactory."); - } - } - } catch (SecurityException e) { - // - // The application is running within a hostile security environment. - // This will make it very hard to diagnose issues with JCL. - // Consider running less securely whilst debugging this issue. - // - logDiagnostic("[CUSTOM LOG FACTORY] SecurityException thrown whilst trying to determine whether " + - "the compatibility was caused by a classloader conflict: " - + e.getMessage()); - } catch (LinkageError e) { - // - // This should be an unusual circumstance. - // LinkageError's usually indicate that a dependent class has incompatibly changed. - // Another possibility may be an exception thrown by an initializer. - // Time for a clean rebuild? - // - logDiagnostic("[CUSTOM LOG FACTORY] LinkageError thrown whilst trying to determine whether " + - "the compatibility was caused by a classloader conflict: " - + e.getMessage()); - } catch (ClassNotFoundException e) { - // - // LogFactory cannot be loaded by the classloader which loaded the custom factory implementation. - // The custom implementation is not viable until this is corrected. - // Ensure that the JCL jar and the custom class are available from the same classloader. - // Running with diagnostics on should give information about the classloaders used - // to load the custom factory. - // - logDiagnostic("[CUSTOM LOG FACTORY] LogFactory class cannot be loaded by classloader which loaded the " + - "custom LogFactory implementation. Is the custom factory in the right classloader?"); - } - } - return implementsLogFactory; - } - - /** - * Applets may run in an environment where accessing resources of a loader is - * a secure operation, but where the commons-logging library has explicitly - * been granted permission for that operation. In this case, we need to - * run the operation using an AccessController. - */ - private static InputStream getResourceAsStream(final ClassLoader loader, - final String name) - { - return (InputStream)AccessController.doPrivileged( - new PrivilegedAction() { - public Object run() { - if (loader != null) { - return loader.getResourceAsStream(name); - } else { - return ClassLoader.getSystemResourceAsStream(name); - } - } - }); - } - - /** - * Given a filename, return an enumeration of URLs pointing to - * all the occurrences of that filename in the classpath. - * <p> - * This is just like ClassLoader.getResources except that the - * operation is done under an AccessController so that this method will - * succeed when this jarfile is privileged but the caller is not. - * This method must therefore remain private to avoid security issues. - * <p> - * If no instances are found, an Enumeration is returned whose - * hasMoreElements method returns false (ie an "empty" enumeration). - * If resources could not be listed for some reason, null is returned. - */ - private static Enumeration getResources(final ClassLoader loader, - final String name) - { - PrivilegedAction action = - new PrivilegedAction() { - public Object run() { - try { - if (loader != null) { - return loader.getResources(name); - } else { - return ClassLoader.getSystemResources(name); - } - } catch(IOException e) { - if (isDiagnosticsEnabled()) { - logDiagnostic( - "Exception while trying to find configuration file " - + name + ":" + e.getMessage()); - } - return null; - } catch(NoSuchMethodError e) { - // we must be running on a 1.1 JVM which doesn't support - // ClassLoader.getSystemResources; just return null in - // this case. - return null; - } - } - }; - Object result = AccessController.doPrivileged(action); - return (Enumeration) result; - } - - /** - * Given a URL that refers to a .properties file, load that file. - * This is done under an AccessController so that this method will - * succeed when this jarfile is privileged but the caller is not. - * This method must therefore remain private to avoid security issues. - * <p> - * Null is returned if the URL cannot be opened. - */ - private static Properties getProperties(final URL url) { - PrivilegedAction action = - new PrivilegedAction() { - public Object run() { - try { - InputStream stream = url.openStream(); - if (stream != null) { - Properties props = new Properties(); - props.load(stream); - stream.close(); - return props; - } - } catch(IOException e) { - if (isDiagnosticsEnabled()) { - logDiagnostic("Unable to read URL " + url); - } - } - - return null; - } - }; - return (Properties) AccessController.doPrivileged(action); - } - - /** - * Locate a user-provided configuration file. - * <p> - * The classpath of the specified classLoader (usually the context classloader) - * is searched for properties files of the specified name. If none is found, - * null is returned. If more than one is found, then the file with the greatest - * value for its PRIORITY property is returned. If multiple files have the - * same PRIORITY value then the first in the classpath is returned. - * <p> - * This differs from the 1.0.x releases; those always use the first one found. - * However as the priority is a new field, this change is backwards compatible. - * <p> - * The purpose of the priority field is to allow a webserver administrator to - * override logging settings in all webapps by placing a commons-logging.properties - * file in a shared classpath location with a priority > 0; this overrides any - * commons-logging.properties files without priorities which are in the - * webapps. Webapps can also use explicit priorities to override a configuration - * file in the shared classpath if needed. - */ - private static final Properties getConfigurationFile( - ClassLoader classLoader, String fileName) { - - Properties props = null; - double priority = 0.0; - URL propsUrl = null; - try { - Enumeration urls = getResources(classLoader, fileName); - - if (urls == null) { - return null; - } - - while (urls.hasMoreElements()) { - URL url = (URL) urls.nextElement(); - - Properties newProps = getProperties(url); - if (newProps != null) { - if (props == null) { - propsUrl = url; - props = newProps; - String priorityStr = props.getProperty(PRIORITY_KEY); - priority = 0.0; - if (priorityStr != null) { - priority = Double.parseDouble(priorityStr); - } - - if (isDiagnosticsEnabled()) { - logDiagnostic( - "[LOOKUP] Properties file found at '" + url + "'" - + " with priority " + priority); - } - } else { - String newPriorityStr = newProps.getProperty(PRIORITY_KEY); - double newPriority = 0.0; - if (newPriorityStr != null) { - newPriority = Double.parseDouble(newPriorityStr); - } - - if (newPriority > priority) { - if (isDiagnosticsEnabled()) { - logDiagnostic( - "[LOOKUP] Properties file at '" + url + "'" - + " with priority " + newPriority - + " overrides file at '" + propsUrl + "'" - + " with priority " + priority); - } - - propsUrl = url; - props = newProps; - priority = newPriority; - } else { - if (isDiagnosticsEnabled()) { - logDiagnostic( - "[LOOKUP] Properties file at '" + url + "'" - + " with priority " + newPriority - + " does not override file at '" + propsUrl + "'" - + " with priority " + priority); - } - } - } - - } - } - } catch (SecurityException e) { - if (isDiagnosticsEnabled()) { - logDiagnostic("SecurityException thrown while trying to find/read config files."); - } - } - - if (isDiagnosticsEnabled()) { - if (props == null) { - logDiagnostic( - "[LOOKUP] No properties file of name '" + fileName - + "' found."); - } else { - logDiagnostic( - "[LOOKUP] Properties file of name '" + fileName - + "' found at '" + propsUrl + '"'); - } - } - - return props; - } - - /** - * Determines whether the user wants internal diagnostic output. If so, - * returns an appropriate writer object. Users can enable diagnostic - * output by setting the system property named {@link #DIAGNOSTICS_DEST_PROPERTY} to - * a filename, or the special values STDOUT or STDERR. - */ - private static void initDiagnostics() { - String dest; - try { - dest = System.getProperty(DIAGNOSTICS_DEST_PROPERTY); - if (dest == null) { - return; - } - } catch(SecurityException ex) { - // We must be running in some very secure environment. - // We just have to assume output is not wanted.. - return; - } - - if (dest.equals("STDOUT")) { - diagnosticsStream = System.out; - } else if (dest.equals("STDERR")) { - diagnosticsStream = System.err; - } else { - try { - // open the file in append mode - FileOutputStream fos = new FileOutputStream(dest, true); - diagnosticsStream = new PrintStream(fos); - } catch(IOException ex) { - // We should report this to the user - but how? - return; - } - } - - // In order to avoid confusion where multiple instances of JCL are - // being used via different classloaders within the same app, we - // ensure each logged message has a prefix of form - // [LogFactory from classloader OID] - // - // Note that this prefix should be kept consistent with that - // in LogFactoryImpl. However here we don't need to output info - // about the actual *instance* of LogFactory, as all methods that - // output diagnostics from this class are static. - String classLoaderName; - try { - ClassLoader classLoader = thisClassLoader; - if (thisClassLoader == null) { - classLoaderName = "BOOTLOADER"; - } else { - classLoaderName = objectId(classLoader); - } - } catch(SecurityException e) { - classLoaderName = "UNKNOWN"; - } - diagnosticPrefix = "[LogFactory from " + classLoaderName + "] "; - } - - /** - * Indicates true if the user has enabled internal logging. - * <p> - * By the way, sorry for the incorrect grammar, but calling this method - * areDiagnosticsEnabled just isn't java beans style. - * - * @return true if calls to logDiagnostic will have any effect. - * @since 1.1 - */ - protected static boolean isDiagnosticsEnabled() { - return diagnosticsStream != null; - } - - /** - * Write the specified message to the internal logging destination. - * <p> - * Note that this method is private; concrete subclasses of this class - * should not call it because the diagnosticPrefix string this - * method puts in front of all its messages is LogFactory@...., - * while subclasses should put SomeSubClass@... - * <p> - * Subclasses should instead compute their own prefix, then call - * logRawDiagnostic. Note that calling isDiagnosticsEnabled is - * fine for subclasses. - * <p> - * Note that it is safe to call this method before initDiagnostics - * is called; any output will just be ignored (as isDiagnosticsEnabled - * will return false). - * - * @param msg is the diagnostic message to be output. - */ - private static final void logDiagnostic(String msg) { - if (diagnosticsStream != null) { - diagnosticsStream.print(diagnosticPrefix); - diagnosticsStream.println(msg); - diagnosticsStream.flush(); - } - } - - /** - * Write the specified message to the internal logging destination. - * - * @param msg is the diagnostic message to be output. - * @since 1.1 - */ - protected static final void logRawDiagnostic(String msg) { - if (diagnosticsStream != null) { - diagnosticsStream.println(msg); - diagnosticsStream.flush(); - } - } - - /** - * Generate useful diagnostics regarding the classloader tree for - * the specified class. - * <p> - * As an example, if the specified class was loaded via a webapp's - * classloader, then you may get the following output: - * <pre> - * Class com.acme.Foo was loaded via classloader 11111 - * ClassLoader tree: 11111 -> 22222 (SYSTEM) -> 33333 -> BOOT - * </pre> - * <p> - * This method returns immediately if isDiagnosticsEnabled() - * returns false. - * - * @param clazz is the class whose classloader + tree are to be - * output. - */ - private static void logClassLoaderEnvironment(Class clazz) { - if (!isDiagnosticsEnabled()) { - return; - } - - try { - logDiagnostic("[ENV] Extension directories (java.ext.dir): " + System.getProperty("java.ext.dir")); - logDiagnostic("[ENV] Application classpath (java.class.path): " + System.getProperty("java.class.path")); - } catch(SecurityException ex) { - logDiagnostic("[ENV] Security setting prevent interrogation of system classpaths."); - } - - String className = clazz.getName(); - ClassLoader classLoader; - - try { - classLoader = getClassLoader(clazz); - } catch(SecurityException ex) { - // not much useful diagnostics we can print here! - logDiagnostic( - "[ENV] Security forbids determining the classloader for " + className); - return; - } - - logDiagnostic( - "[ENV] Class " + className + " was loaded via classloader " - + objectId(classLoader)); - logHierarchy("[ENV] Ancestry of classloader which loaded " + className + " is ", classLoader); - } - - /** - * Logs diagnostic messages about the given classloader - * and it's hierarchy. The prefix is prepended to the message - * and is intended to make it easier to understand the logs. - * @param prefix - * @param classLoader - */ - private static void logHierarchy(String prefix, ClassLoader classLoader) { - if (!isDiagnosticsEnabled()) { - return; - } - ClassLoader systemClassLoader; - if (classLoader != null) { - final String classLoaderString = classLoader.toString(); - logDiagnostic(prefix + objectId(classLoader) + " == '" + classLoaderString + "'"); - } - - try { - systemClassLoader = ClassLoader.getSystemClassLoader(); - } catch(SecurityException ex) { - logDiagnostic( - prefix + "Security forbids determining the system classloader."); - return; - } - if (classLoader != null) { - StringBuffer buf = new StringBuffer(prefix + "ClassLoader tree:"); - for(;;) { - buf.append(objectId(classLoader)); - if (classLoader == systemClassLoader) { - buf.append(" (SYSTEM) "); - } - - try { - classLoader = classLoader.getParent(); - } catch(SecurityException ex) { - buf.append(" --> SECRET"); - break; - } - - buf.append(" --> "); - if (classLoader == null) { - buf.append("BOOT"); - break; - } - } - logDiagnostic(buf.toString()); - } - } - - /** - * Returns a string that uniquely identifies the specified object, including - * its class. - * <p> - * The returned string is of form "classname@hashcode", ie is the same as - * the return value of the Object.toString() method, but works even when - * the specified object's class has overidden the toString method. - * - * @param o may be null. - * @return a string of form classname@hashcode, or "null" if param o is null. - * @since 1.1 - */ - public static String objectId(Object o) { - if (o == null) { - return "null"; - } else { - return o.getClass().getName() + "@" + System.identityHashCode(o); - } - } - - // ---------------------------------------------------------------------- - // Static initialiser block to perform initialisation at class load time. - // - // We can't do this in the class constructor, as there are many - // static methods on this class that can be called before any - // LogFactory instances are created, and they depend upon this - // stuff having been set up. - // - // Note that this block must come after any variable declarations used - // by any methods called from this block, as we want any static initialiser - // associated with the variable to run first. If static initialisers for - // variables run after this code, then (a) their value might be needed - // by methods called from here, and (b) they might *override* any value - // computed here! - // - // So the wisest thing to do is just to place this code at the very end - // of the class file. - // ---------------------------------------------------------------------- - - static { - // note: it's safe to call methods before initDiagnostics. - thisClassLoader = getClassLoader(LogFactory.class); - initDiagnostics(); - logClassLoaderEnvironment(LogFactory.class); - factories = createFactoryStore(); - if (isDiagnosticsEnabled()) { - logDiagnostic("BOOTSTRAP COMPLETED"); - } - } -} diff --git a/src/org/apache/commons/logging/LogSource.java b/src/org/apache/commons/logging/LogSource.java deleted file mode 100644 index e3c0603..0000000 --- a/src/org/apache/commons/logging/LogSource.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.logging; - - -import java.lang.reflect.Constructor; -import java.util.Hashtable; - -import org.apache.commons.logging.impl.NoOpLog; - - -/** - * <p>Factory for creating {@link Log} instances. Applications should call - * the <code>makeNewLogInstance()</code> method to instantiate new instances - * of the configured {@link Log} implementation class.</p> - * - * <p>By default, calling <code>getInstance()</code> will use the following - * algorithm:</p> - * <ul> - * <li>If Log4J is available, return an instance of - * <code>org.apache.commons.logging.impl.Log4JLogger</code>.</li> - * <li>If JDK 1.4 or later is available, return an instance of - * <code>org.apache.commons.logging.impl.Jdk14Logger</code>.</li> - * <li>Otherwise, return an instance of - * <code>org.apache.commons.logging.impl.NoOpLog</code>.</li> - * </ul> - * - * <p>You can change the default behavior in one of two ways:</p> - * <ul> - * <li>On the startup command line, set the system property - * <code>org.apache.commons.logging.log</code> to the name of the - * <code>org.apache.commons.logging.Log</code> implementation class - * you want to use.</li> - * <li>At runtime, call <code>LogSource.setLogImplementation()</code>.</li> - * </ul> - * - * @deprecated Use {@link LogFactory} instead - The default factory - * implementation performs exactly the same algorithm as this class did - * - * @author Rod Waldhoff - * @version $Id: LogSource.java 155426 2005-02-26 13:10:49Z dirkv $ - */ -public class LogSource { - - // ------------------------------------------------------- Class Attributes - - static protected Hashtable logs = new Hashtable(); - - /** Is log4j available (in the current classpath) */ - static protected boolean log4jIsAvailable = false; - - /** Is JDK 1.4 logging available */ - static protected boolean jdk14IsAvailable = false; - - /** Constructor for current log class */ - static protected Constructor logImplctor = null; - - - // ----------------------------------------------------- Class Initializers - - static { - - // Is Log4J Available? - try { - if (null != Class.forName("org.apache.log4j.Logger")) { - log4jIsAvailable = true; - } else { - log4jIsAvailable = false; - } - } catch (Throwable t) { - log4jIsAvailable = false; - } - - // Is JDK 1.4 Logging Available? - try { - if ((null != Class.forName("java.util.logging.Logger")) && - (null != Class.forName("org.apache.commons.logging.impl.Jdk14Logger"))) { - jdk14IsAvailable = true; - } else { - jdk14IsAvailable = false; - } - } catch (Throwable t) { - jdk14IsAvailable = false; - } - - // Set the default Log implementation - String name = null; - try { - name = System.getProperty("org.apache.commons.logging.log"); - if (name == null) { - name = System.getProperty("org.apache.commons.logging.Log"); - } - } catch (Throwable t) { - } - if (name != null) { - try { - setLogImplementation(name); - } catch (Throwable t) { - try { - setLogImplementation - ("org.apache.commons.logging.impl.NoOpLog"); - } catch (Throwable u) { - ; - } - } - } else { - try { - if (log4jIsAvailable) { - setLogImplementation - ("org.apache.commons.logging.impl.Log4JLogger"); - } else if (jdk14IsAvailable) { - setLogImplementation - ("org.apache.commons.logging.impl.Jdk14Logger"); - } else { - setLogImplementation - ("org.apache.commons.logging.impl.NoOpLog"); - } - } catch (Throwable t) { - try { - setLogImplementation - ("org.apache.commons.logging.impl.NoOpLog"); - } catch (Throwable u) { - ; - } - } - } - - } - - - // ------------------------------------------------------------ Constructor - - - /** Don't allow others to create instances */ - private LogSource() { - } - - - // ---------------------------------------------------------- Class Methods - - - /** - * Set the log implementation/log implementation factory - * by the name of the class. The given class - * must implement {@link Log}, and provide a constructor that - * takes a single {@link String} argument (containing the name - * of the log). - */ - static public void setLogImplementation(String classname) throws - LinkageError, ExceptionInInitializerError, - NoSuchMethodException, SecurityException, - ClassNotFoundException { - try { - Class logclass = Class.forName(classname); - Class[] argtypes = new Class[1]; - argtypes[0] = "".getClass(); - logImplctor = logclass.getConstructor(argtypes); - } catch (Throwable t) { - logImplctor = null; - } - } - - - /** - * Set the log implementation/log implementation factory - * by class. The given class must implement {@link Log}, - * and provide a constructor that takes a single {@link String} - * argument (containing the name of the log). - */ - static public void setLogImplementation(Class logclass) throws - LinkageError, ExceptionInInitializerError, - NoSuchMethodException, SecurityException { - Class[] argtypes = new Class[1]; - argtypes[0] = "".getClass(); - logImplctor = logclass.getConstructor(argtypes); - } - - - /** Get a <code>Log</code> instance by class name */ - static public Log getInstance(String name) { - Log log = (Log) (logs.get(name)); - if (null == log) { - log = makeNewLogInstance(name); - logs.put(name, log); - } - return log; - } - - - /** Get a <code>Log</code> instance by class */ - static public Log getInstance(Class clazz) { - return getInstance(clazz.getName()); - } - - - /** - * Create a new {@link Log} implementation, based - * on the given <i>name</i>. - * <p> - * The specific {@link Log} implementation returned - * is determined by the value of the - * <tt>org.apache.commons.logging.log</tt> property. - * The value of <tt>org.apache.commons.logging.log</tt> may be set to - * the fully specified name of a class that implements - * the {@link Log} interface. This class must also - * have a public constructor that takes a single - * {@link String} argument (containing the <i>name</i> - * of the {@link Log} to be constructed. - * <p> - * When <tt>org.apache.commons.logging.log</tt> is not set, - * or when no corresponding class can be found, - * this method will return a Log4JLogger - * if the log4j Logger class is - * available in the {@link LogSource}'s classpath, or a - * Jdk14Logger if we are on a JDK 1.4 or later system, or - * NoOpLog if neither of the above conditions is true. - * - * @param name the log name (or category) - */ - static public Log makeNewLogInstance(String name) { - - Log log = null; - try { - Object[] args = new Object[1]; - args[0] = name; - log = (Log) (logImplctor.newInstance(args)); - } catch (Throwable t) { - log = null; - } - if (null == log) { - log = new NoOpLog(name); - } - return log; - - } - - - /** - * Returns a {@link String} array containing the names of - * all logs known to me. - */ - static public String[] getLogNames() { - return (String[]) (logs.keySet().toArray(new String[logs.size()])); - } - - -} diff --git a/src/org/apache/commons/logging/impl/Jdk14Logger.java b/src/org/apache/commons/logging/impl/Jdk14Logger.java deleted file mode 100644 index d4f840c..0000000 --- a/src/org/apache/commons/logging/impl/Jdk14Logger.java +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.commons.logging.impl; - - -import java.io.Serializable; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.apache.commons.logging.Log; - - -/** - * <p>Implementation of the <code>org.apache.commons.logging.Log</code> - * interface that wraps the standard JDK logging mechanisms that were - * introduced in the Merlin release (JDK 1.4).</p> - * - * @author <a href="mailto:sanders@apache.org">Scott Sanders</a> - * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a> - * @author <a href="mailto:donaldp@apache.org">Peter Donald</a> - * @version $Revision: 370652 $ $Date: 2006-01-19 22:23:48 +0000 (Thu, 19 Jan 2006) $ - */ - -public class Jdk14Logger implements Log, Serializable { - - /** - * This member variable simply ensures that any attempt to initialise - * this class in a pre-1.4 JVM will result in an ExceptionInInitializerError. - * It must not be private, as an optimising compiler could detect that it - * is not used and optimise it away. - */ - protected static final Level dummyLevel = Level.FINE; - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a named instance of this Logger. - * - * @param name Name of the logger to be constructed - */ - public Jdk14Logger(String name) { - - this.name = name; - logger = getLogger(); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The underlying Logger implementation we are using. - */ - protected transient Logger logger = null; - - - /** - * The name of the logger we are wrapping. - */ - protected String name = null; - - - // --------------------------------------------------------- Public Methods - - private void log( Level level, String msg, Throwable ex ) { - - Logger logger = getLogger(); - if (logger.isLoggable(level)) { - // Hack (?) to get the stack trace. - Throwable dummyException=new Throwable(); - StackTraceElement locations[]=dummyException.getStackTrace(); - // Caller will be the third element - String cname="unknown"; - String method="unknown"; - if( locations!=null && locations.length >2 ) { - StackTraceElement caller=locations[2]; - cname=caller.getClassName(); - method=caller.getMethodName(); - } - if( ex==null ) { - logger.logp( level, cname, method, msg ); - } else { - logger.logp( level, cname, method, msg, ex ); - } - } - - } - - /** - * Logs a message with <code>java.util.logging.Level.FINE</code>. - * - * @param message to log - * @see org.apache.commons.logging.Log#debug(Object) - */ - public void debug(Object message) { - log(Level.FINE, String.valueOf(message), null); - } - - - /** - * Logs a message with <code>java.util.logging.Level.FINE</code>. - * - * @param message to log - * @param exception log this cause - * @see org.apache.commons.logging.Log#debug(Object, Throwable) - */ - public void debug(Object message, Throwable exception) { - log(Level.FINE, String.valueOf(message), exception); - } - - - /** - * Logs a message with <code>java.util.logging.Level.SEVERE</code>. - * - * @param message to log - * @see org.apache.commons.logging.Log#error(Object) - */ - public void error(Object message) { - log(Level.SEVERE, String.valueOf(message), null); - } - - - /** - * Logs a message with <code>java.util.logging.Level.SEVERE</code>. - * - * @param message to log - * @param exception log this cause - * @see org.apache.commons.logging.Log#error(Object, Throwable) - */ - public void error(Object message, Throwable exception) { - log(Level.SEVERE, String.valueOf(message), exception); - } - - - /** - * Logs a message with <code>java.util.logging.Level.SEVERE</code>. - * - * @param message to log - * @see org.apache.commons.logging.Log#fatal(Object) - */ - public void fatal(Object message) { - log(Level.SEVERE, String.valueOf(message), null); - } - - - /** - * Logs a message with <code>java.util.logging.Level.SEVERE</code>. - * - * @param message to log - * @param exception log this cause - * @see org.apache.commons.logging.Log#fatal(Object, Throwable) - */ - public void fatal(Object message, Throwable exception) { - log(Level.SEVERE, String.valueOf(message), exception); - } - - - /** - * Return the native Logger instance we are using. - */ - public Logger getLogger() { - if (logger == null) { - logger = Logger.getLogger(name); - } - return (logger); - } - - - /** - * Logs a message with <code>java.util.logging.Level.INFO</code>. - * - * @param message to log - * @see org.apache.commons.logging.Log#info(Object) - */ - public void info(Object message) { - log(Level.INFO, String.valueOf(message), null); - } - - - /** - * Logs a message with <code>java.util.logging.Level.INFO</code>. - * - * @param message to log - * @param exception log this cause - * @see org.apache.commons.logging.Log#info(Object, Throwable) - */ - public void info(Object message, Throwable exception) { - log(Level.INFO, String.valueOf(message), exception); - } - - - /** - * Is debug logging currently enabled? - */ - public boolean isDebugEnabled() { - return (getLogger().isLoggable(Level.FINE)); - } - - - /** - * Is error logging currently enabled? - */ - public boolean isErrorEnabled() { - return (getLogger().isLoggable(Level.SEVERE)); - } - - - /** - * Is fatal logging currently enabled? - */ - public boolean isFatalEnabled() { - return (getLogger().isLoggable(Level.SEVERE)); - } - - - /** - * Is info logging currently enabled? - */ - public boolean isInfoEnabled() { - return (getLogger().isLoggable(Level.INFO)); - } - - - /** - * Is trace logging currently enabled? - */ - public boolean isTraceEnabled() { - return (getLogger().isLoggable(Level.FINEST)); - } - - - /** - * Is warn logging currently enabled? - */ - public boolean isWarnEnabled() { - return (getLogger().isLoggable(Level.WARNING)); - } - - - /** - * Logs a message with <code>java.util.logging.Level.FINEST</code>. - * - * @param message to log - * @see org.apache.commons.logging.Log#trace(Object) - */ - public void trace(Object message) { - log(Level.FINEST, String.valueOf(message), null); - } - - - /** - * Logs a message with <code>java.util.logging.Level.FINEST</code>. - * - * @param message to log - * @param exception log this cause - * @see org.apache.commons.logging.Log#trace(Object, Throwable) - */ - public void trace(Object message, Throwable exception) { - log(Level.FINEST, String.valueOf(message), exception); - } - - - /** - * Logs a message with <code>java.util.logging.Level.WARNING</code>. - * - * @param message to log - * @see org.apache.commons.logging.Log#warn(Object) - */ - public void warn(Object message) { - log(Level.WARNING, String.valueOf(message), null); - } - - - /** - * Logs a message with <code>java.util.logging.Level.WARNING</code>. - * - * @param message to log - * @param exception log this cause - * @see org.apache.commons.logging.Log#warn(Object, Throwable) - */ - public void warn(Object message, Throwable exception) { - log(Level.WARNING, String.valueOf(message), exception); - } - - -} diff --git a/src/org/apache/commons/logging/impl/LogFactoryImpl.java b/src/org/apache/commons/logging/impl/LogFactoryImpl.java deleted file mode 100644 index 8937b2f..0000000 --- a/src/org/apache/commons/logging/impl/LogFactoryImpl.java +++ /dev/null @@ -1,1400 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.logging.impl; - - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.URL; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Vector; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogConfigurationException; -import org.apache.commons.logging.LogFactory; - - -/** - * <p>Concrete subclass of {@link LogFactory} that implements the - * following algorithm to dynamically select a logging implementation - * class to instantiate a wrapper for.</p> - * <ul> - * <li>Use a factory configuration attribute named - * <code>org.apache.commons.logging.Log</code> to identify the - * requested implementation class.</li> - * <li>Use the <code>org.apache.commons.logging.Log</code> system property - * to identify the requested implementation class.</li> - * <li>If <em>Log4J</em> is available, return an instance of - * <code>org.apache.commons.logging.impl.Log4JLogger</code>.</li> - * <li>If <em>JDK 1.4 or later</em> is available, return an instance of - * <code>org.apache.commons.logging.impl.Jdk14Logger</code>.</li> - * <li>Otherwise, return an instance of - * <code>org.apache.commons.logging.impl.SimpleLog</code>.</li> - * </ul> - * - * <p>If the selected {@link Log} implementation class has a - * <code>setLogFactory()</code> method that accepts a {@link LogFactory} - * parameter, this method will be called on each newly created instance - * to identify the associated factory. This makes factory configuration - * attributes available to the Log instance, if it so desires.</p> - * - * <p>This factory will remember previously created <code>Log</code> instances - * for the same name, and will return them on repeated requests to the - * <code>getInstance()</code> method.</p> - * - * @author Rod Waldhoff - * @author Craig R. McClanahan - * @author Richard A. Sitze - * @author Brian Stansberry - * @version $Revision: 399224 $ $Date: 2006-05-03 10:25:54 +0100 (Wed, 03 May 2006) $ - */ - -public class LogFactoryImpl extends LogFactory { - - - /** Log4JLogger class name */ - private static final String LOGGING_IMPL_LOG4J_LOGGER = "org.apache.commons.logging.impl.Log4JLogger"; - /** Jdk14Logger class name */ - private static final String LOGGING_IMPL_JDK14_LOGGER = "org.apache.commons.logging.impl.Jdk14Logger"; - /** Jdk13LumberjackLogger class name */ - private static final String LOGGING_IMPL_LUMBERJACK_LOGGER = "org.apache.commons.logging.impl.Jdk13LumberjackLogger"; - /** SimpleLog class name */ - private static final String LOGGING_IMPL_SIMPLE_LOGGER = "org.apache.commons.logging.impl.SimpleLog"; - - private static final String PKG_IMPL="org.apache.commons.logging.impl."; - private static final int PKG_LEN = PKG_IMPL.length(); - - // ----------------------------------------------------------- Constructors - - - - /** - * Public no-arguments constructor required by the lookup mechanism. - */ - public LogFactoryImpl() { - super(); - initDiagnostics(); // method on this object - if (isDiagnosticsEnabled()) { - logDiagnostic("Instance created."); - } - } - - - // ----------------------------------------------------- Manifest Constants - - - /** - * The name (<code>org.apache.commons.logging.Log</code>) of the system - * property identifying our {@link Log} implementation class. - */ - public static final String LOG_PROPERTY = - "org.apache.commons.logging.Log"; - - - /** - * The deprecated system property used for backwards compatibility with - * old versions of JCL. - */ - protected static final String LOG_PROPERTY_OLD = - "org.apache.commons.logging.log"; - - /** - * The name (<code>org.apache.commons.logging.Log.allowFlawedContext</code>) - * of the system property which can be set true/false to - * determine system behaviour when a bad context-classloader is encountered. - * When set to false, a LogConfigurationException is thrown if - * LogFactoryImpl is loaded via a child classloader of the TCCL (this - * should never happen in sane systems). - * - * Default behaviour: true (tolerates bad context classloaders) - * - * See also method setAttribute. - */ - public static final String ALLOW_FLAWED_CONTEXT_PROPERTY = - "org.apache.commons.logging.Log.allowFlawedContext"; - - /** - * The name (<code>org.apache.commons.logging.Log.allowFlawedDiscovery</code>) - * of the system property which can be set true/false to - * determine system behaviour when a bad logging adapter class is - * encountered during logging discovery. When set to false, an - * exception will be thrown and the app will fail to start. When set - * to true, discovery will continue (though the user might end up - * with a different logging implementation than they expected). - * - * Default behaviour: true (tolerates bad logging adapters) - * - * See also method setAttribute. - */ - public static final String ALLOW_FLAWED_DISCOVERY_PROPERTY = - "org.apache.commons.logging.Log.allowFlawedDiscovery"; - - /** - * The name (<code>org.apache.commons.logging.Log.allowFlawedHierarchy</code>) - * of the system property which can be set true/false to - * determine system behaviour when a logging adapter class is - * encountered which has bound to the wrong Log class implementation. - * When set to false, an exception will be thrown and the app will fail - * to start. When set to true, discovery will continue (though the user - * might end up with a different logging implementation than they expected). - * - * Default behaviour: true (tolerates bad Log class hierarchy) - * - * See also method setAttribute. - */ - public static final String ALLOW_FLAWED_HIERARCHY_PROPERTY = - "org.apache.commons.logging.Log.allowFlawedHierarchy"; - - - /** - * The names of classes that will be tried (in order) as logging - * adapters. Each class is expected to implement the Log interface, - * and to throw NoClassDefFound or ExceptionInInitializerError when - * loaded if the underlying logging library is not available. Any - * other error indicates that the underlying logging library is available - * but broken/unusable for some reason. - */ - private static final String[] classesToDiscover = { - LOGGING_IMPL_LOG4J_LOGGER, - "org.apache.commons.logging.impl.Jdk14Logger", - "org.apache.commons.logging.impl.Jdk13LumberjackLogger", - "org.apache.commons.logging.impl.SimpleLog" - }; - - - // ----------------------------------------------------- Instance Variables - - /** - * Determines whether logging classes should be loaded using the thread-context - * classloader, or via the classloader that loaded this LogFactoryImpl class. - */ - private boolean useTCCL = true; - - /** - * The string prefixed to every message output by the logDiagnostic method. - */ - private String diagnosticPrefix; - - - /** - * Configuration attributes. - */ - protected Hashtable attributes = new Hashtable(); - - - /** - * The {@link org.apache.commons.logging.Log} instances that have - * already been created, keyed by logger name. - */ - protected Hashtable instances = new Hashtable(); - - - /** - * Name of the class implementing the Log interface. - */ - private String logClassName; - - - /** - * The one-argument constructor of the - * {@link org.apache.commons.logging.Log} - * implementation class that will be used to create new instances. - * This value is initialized by <code>getLogConstructor()</code>, - * and then returned repeatedly. - */ - protected Constructor logConstructor = null; - - - /** - * The signature of the Constructor to be used. - */ - protected Class logConstructorSignature[] = - { java.lang.String.class }; - - - /** - * The one-argument <code>setLogFactory</code> method of the selected - * {@link org.apache.commons.logging.Log} method, if it exists. - */ - protected Method logMethod = null; - - - /** - * The signature of the <code>setLogFactory</code> method to be used. - */ - protected Class logMethodSignature[] = - { LogFactory.class }; - - /** - * See getBaseClassLoader and initConfiguration. - */ - private boolean allowFlawedContext; - - /** - * See handleFlawedDiscovery and initConfiguration. - */ - private boolean allowFlawedDiscovery; - - /** - * See handleFlawedHierarchy and initConfiguration. - */ - private boolean allowFlawedHierarchy; - - // --------------------------------------------------------- Public Methods - - - /** - * Return the configuration attribute with the specified name (if any), - * or <code>null</code> if there is no such attribute. - * - * @param name Name of the attribute to return - */ - public Object getAttribute(String name) { - - return (attributes.get(name)); - - } - - - /** - * Return an array containing the names of all currently defined - * configuration attributes. If there are no such attributes, a zero - * length array is returned. - */ - public String[] getAttributeNames() { - - Vector names = new Vector(); - Enumeration keys = attributes.keys(); - while (keys.hasMoreElements()) { - names.addElement((String) keys.nextElement()); - } - String results[] = new String[names.size()]; - for (int i = 0; i < results.length; i++) { - results[i] = (String) names.elementAt(i); - } - return (results); - - } - - - /** - * Convenience method to derive a name from the specified class and - * call <code>getInstance(String)</code> with it. - * - * @param clazz Class for which a suitable Log name will be derived - * - * @exception LogConfigurationException if a suitable <code>Log</code> - * instance cannot be returned - */ - public Log getInstance(Class clazz) throws LogConfigurationException { - - return (getInstance(clazz.getName())); - - } - - - /** - * <p>Construct (if necessary) and return a <code>Log</code> instance, - * using the factory's current set of configuration attributes.</p> - * - * <p><strong>NOTE</strong> - Depending upon the implementation of - * the <code>LogFactory</code> you are using, the <code>Log</code> - * instance you are returned may or may not be local to the current - * application, and may or may not be returned again on a subsequent - * call with the same name argument.</p> - * - * @param name Logical name of the <code>Log</code> instance to be - * returned (the meaning of this name is only known to the underlying - * logging implementation that is being wrapped) - * - * @exception LogConfigurationException if a suitable <code>Log</code> - * instance cannot be returned - */ - public Log getInstance(String name) throws LogConfigurationException { - - Log instance = (Log) instances.get(name); - if (instance == null) { - instance = newInstance(name); - instances.put(name, instance); - } - return (instance); - - } - - - /** - * Release any internal references to previously created - * {@link org.apache.commons.logging.Log} - * instances returned by this factory. This is useful in environments - * like servlet containers, which implement application reloading by - * throwing away a ClassLoader. Dangling references to objects in that - * class loader would prevent garbage collection. - */ - public void release() { - - logDiagnostic("Releasing all known loggers"); - instances.clear(); - } - - - /** - * Remove any configuration attribute associated with the specified name. - * If there is no such attribute, no action is taken. - * - * @param name Name of the attribute to remove - */ - public void removeAttribute(String name) { - - attributes.remove(name); - - } - - - /** - * Set the configuration attribute with the specified name. Calling - * this with a <code>null</code> value is equivalent to calling - * <code>removeAttribute(name)</code>. - * <p> - * This method can be used to set logging configuration programmatically - * rather than via system properties. It can also be used in code running - * within a container (such as a webapp) to configure behaviour on a - * per-component level instead of globally as system properties would do. - * To use this method instead of a system property, call - * <pre> - * LogFactory.getFactory().setAttribute(...) - * </pre> - * This must be done before the first Log object is created; configuration - * changes after that point will be ignored. - * <p> - * This method is also called automatically if LogFactory detects a - * commons-logging.properties file; every entry in that file is set - * automatically as an attribute here. - * - * @param name Name of the attribute to set - * @param value Value of the attribute to set, or <code>null</code> - * to remove any setting for this attribute - */ - public void setAttribute(String name, Object value) { - - if (logConstructor != null) { - logDiagnostic("setAttribute: call too late; configuration already performed."); - } - - if (value == null) { - attributes.remove(name); - } else { - attributes.put(name, value); - } - - if (name.equals(TCCL_KEY)) { - useTCCL = Boolean.valueOf(value.toString()).booleanValue(); - } - - } - - - // ------------------------------------------------------ - // Static Methods - // - // These methods only defined as workarounds for a java 1.2 bug; - // theoretically none of these are needed. - // ------------------------------------------------------ - - /** - * Gets the context classloader. - * This method is a workaround for a java 1.2 compiler bug. - * @since 1.1 - */ - protected static ClassLoader getContextClassLoader() throws LogConfigurationException { - return LogFactory.getContextClassLoader(); - } - - - /** - * Workaround for bug in Java1.2; in theory this method is not needed. - * See LogFactory.isDiagnosticsEnabled. - */ - protected static boolean isDiagnosticsEnabled() { - return LogFactory.isDiagnosticsEnabled(); - } - - - /** - * Workaround for bug in Java1.2; in theory this method is not needed. - * See LogFactory.getClassLoader. - * @since 1.1 - */ - protected static ClassLoader getClassLoader(Class clazz) { - return LogFactory.getClassLoader(clazz); - } - - - // ------------------------------------------------------ Protected Methods - - /** - * Calculate and cache a string that uniquely identifies this instance, - * including which classloader the object was loaded from. - * <p> - * This string will later be prefixed to each "internal logging" message - * emitted, so that users can clearly see any unexpected behaviour. - * <p> - * Note that this method does not detect whether internal logging is - * enabled or not, nor where to output stuff if it is; that is all - * handled by the parent LogFactory class. This method just computes - * its own unique prefix for log messages. - */ - private void initDiagnostics() { - // It would be nice to include an identifier of the context classloader - // that this LogFactoryImpl object is responsible for. However that - // isn't possible as that information isn't available. It is possible - // to figure this out by looking at the logging from LogFactory to - // see the context & impl ids from when this object was instantiated, - // in order to link the impl id output as this object's prefix back to - // the context it is intended to manage. - // Note that this prefix should be kept consistent with that - // in LogFactory. - Class clazz = this.getClass(); - ClassLoader classLoader = getClassLoader(clazz); - String classLoaderName; - try { - if (classLoader == null) { - classLoaderName = "BOOTLOADER"; - } else { - classLoaderName = objectId(classLoader); - } - } catch(SecurityException e) { - classLoaderName = "UNKNOWN"; - } - diagnosticPrefix = "[LogFactoryImpl@" + System.identityHashCode(this) + " from " + classLoaderName + "] "; - } - - - /** - * Output a diagnostic message to a user-specified destination (if the - * user has enabled diagnostic logging). - * - * @param msg diagnostic message - * @since 1.1 - */ - protected void logDiagnostic(String msg) { - if (isDiagnosticsEnabled()) { - logRawDiagnostic(diagnosticPrefix + msg); - } - } - - /** - * Return the fully qualified Java classname of the {@link Log} - * implementation we will be using. - * - * @deprecated Never invoked by this class; subclasses should not assume - * it will be. - */ - protected String getLogClassName() { - - if (logClassName == null) { - discoverLogImplementation(getClass().getName()); - } - - return logClassName; - } - - - /** - * <p>Return the <code>Constructor</code> that can be called to instantiate - * new {@link org.apache.commons.logging.Log} instances.</p> - * - * <p><strong>IMPLEMENTATION NOTE</strong> - Race conditions caused by - * calling this method from more than one thread are ignored, because - * the same <code>Constructor</code> instance will ultimately be derived - * in all circumstances.</p> - * - * @exception LogConfigurationException if a suitable constructor - * cannot be returned - * - * @deprecated Never invoked by this class; subclasses should not assume - * it will be. - */ - protected Constructor getLogConstructor() - throws LogConfigurationException { - - // Return the previously identified Constructor (if any) - if (logConstructor == null) { - discoverLogImplementation(getClass().getName()); - } - - return logConstructor; - } - - - /** - * Is <em>JDK 1.3 with Lumberjack</em> logging available? - * - * @deprecated Never invoked by this class; subclasses should not assume - * it will be. - */ - protected boolean isJdk13LumberjackAvailable() { - return isLogLibraryAvailable( - "Jdk13Lumberjack", - "org.apache.commons.logging.impl.Jdk13LumberjackLogger"); - } - - - /** - * <p>Return <code>true</code> if <em>JDK 1.4 or later</em> logging - * is available. Also checks that the <code>Throwable</code> class - * supports <code>getStackTrace()</code>, which is required by - * Jdk14Logger.</p> - * - * @deprecated Never invoked by this class; subclasses should not assume - * it will be. - */ - protected boolean isJdk14Available() { - return isLogLibraryAvailable( - "Jdk14", - "org.apache.commons.logging.impl.Jdk14Logger"); - } - - - /** - * Is a <em>Log4J</em> implementation available? - * - * @deprecated Never invoked by this class; subclasses should not assume - * it will be. - */ - protected boolean isLog4JAvailable() { - return isLogLibraryAvailable( - "Log4J", - LOGGING_IMPL_LOG4J_LOGGER); - } - - - /** - * Create and return a new {@link org.apache.commons.logging.Log} - * instance for the specified name. - * - * @param name Name of the new logger - * - * @exception LogConfigurationException if a new instance cannot - * be created - */ - protected Log newInstance(String name) throws LogConfigurationException { - - Log instance = null; - try { - if (logConstructor == null) { - instance = discoverLogImplementation(name); - } - else { - Object params[] = { name }; - instance = (Log) logConstructor.newInstance(params); - } - - if (logMethod != null) { - Object params[] = { this }; - logMethod.invoke(instance, params); - } - - return (instance); - - } catch (LogConfigurationException lce) { - - // this type of exception means there was a problem in discovery - // and we've already output diagnostics about the issue, etc.; - // just pass it on - throw (LogConfigurationException) lce; - - } catch (InvocationTargetException e) { - // A problem occurred invoking the Constructor or Method - // previously discovered - Throwable c = e.getTargetException(); - if (c != null) { - throw new LogConfigurationException(c); - } else { - throw new LogConfigurationException(e); - } - } catch (Throwable t) { - // A problem occurred invoking the Constructor or Method - // previously discovered - throw new LogConfigurationException(t); - } - } - - - // ------------------------------------------------------ Private Methods - - /** - * Utility method to check whether a particular logging library is - * present and available for use. Note that this does <i>not</i> - * affect the future behaviour of this class. - */ - private boolean isLogLibraryAvailable(String name, String classname) { - if (isDiagnosticsEnabled()) { - logDiagnostic("Checking for '" + name + "'."); - } - try { - Log log = createLogFromClass( - classname, - this.getClass().getName(), // dummy category - false); - - if (log == null) { - if (isDiagnosticsEnabled()) { - logDiagnostic("Did not find '" + name + "'."); - } - return false; - } else { - if (isDiagnosticsEnabled()) { - logDiagnostic("Found '" + name + "'."); - } - return true; - } - } catch(LogConfigurationException e) { - if (isDiagnosticsEnabled()) { - logDiagnostic("Logging system '" + name + "' is available but not useable."); - } - return false; - } - } - - /** - * Attempt to find an attribute (see method setAttribute) or a - * system property with the provided name and return its value. - * <p> - * The attributes associated with this object are checked before - * system properties in case someone has explicitly called setAttribute, - * or a configuration property has been set in a commons-logging.properties - * file. - * - * @return the value associated with the property, or null. - */ - private String getConfigurationValue(String property) { - if (isDiagnosticsEnabled()) { - logDiagnostic("[ENV] Trying to get configuration for item " + property); - } - - Object valueObj = getAttribute(property); - if (valueObj != null) { - if (isDiagnosticsEnabled()) { - logDiagnostic("[ENV] Found LogFactory attribute [" + valueObj + "] for " + property); - } - return valueObj.toString(); - } - - if (isDiagnosticsEnabled()) { - logDiagnostic("[ENV] No LogFactory attribute found for " + property); - } - - try { - String value = System.getProperty(property); - if (value != null) { - if (isDiagnosticsEnabled()) { - logDiagnostic("[ENV] Found system property [" + value + "] for " + property); - } - return value; - } - - if (isDiagnosticsEnabled()) { - logDiagnostic("[ENV] No system property found for property " + property); - } - } catch (SecurityException e) { - if (isDiagnosticsEnabled()) { - logDiagnostic("[ENV] Security prevented reading system property " + property); - } - } - - if (isDiagnosticsEnabled()) { - logDiagnostic("[ENV] No configuration defined for item " + property); - } - - return null; - } - - /** - * Get the setting for the user-configurable behaviour specified by key. - * If nothing has explicitly been set, then return dflt. - */ - private boolean getBooleanConfiguration(String key, boolean dflt) { - String val = getConfigurationValue(key); - if (val == null) - return dflt; - return Boolean.valueOf(val).booleanValue(); - } - - /** - * Initialize a number of variables that control the behaviour of this - * class and that can be tweaked by the user. This is done when the first - * logger is created, not in the constructor of this class, because we - * need to give the user a chance to call method setAttribute in order to - * configure this object. - */ - private void initConfiguration() { - allowFlawedContext = getBooleanConfiguration(ALLOW_FLAWED_CONTEXT_PROPERTY, true); - allowFlawedDiscovery = getBooleanConfiguration(ALLOW_FLAWED_DISCOVERY_PROPERTY, true); - allowFlawedHierarchy = getBooleanConfiguration(ALLOW_FLAWED_HIERARCHY_PROPERTY, true); - } - - - /** - * Attempts to create a Log instance for the given category name. - * Follows the discovery process described in the class javadoc. - * - * @param logCategory the name of the log category - * - * @throws LogConfigurationException if an error in discovery occurs, - * or if no adapter at all can be instantiated - */ - private Log discoverLogImplementation(String logCategory) - throws LogConfigurationException - { - if (isDiagnosticsEnabled()) { - logDiagnostic("Discovering a Log implementation..."); - } - - initConfiguration(); - - Log result = null; - - // See if the user specified the Log implementation to use - String specifiedLogClassName = findUserSpecifiedLogClassName(); - - if (specifiedLogClassName != null) { - if (isDiagnosticsEnabled()) { - logDiagnostic("Attempting to load user-specified log class '" + - specifiedLogClassName + "'..."); - } - - result = createLogFromClass(specifiedLogClassName, - logCategory, - true); - if (result == null) { - StringBuffer messageBuffer = new StringBuffer("User-specified log class '"); - messageBuffer.append(specifiedLogClassName); - messageBuffer.append("' cannot be found or is not useable."); - - // Mistyping or misspelling names is a common fault. - // Construct a good error message, if we can - if (specifiedLogClassName != null) { - informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_LOG4J_LOGGER); - informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_JDK14_LOGGER); - informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_LUMBERJACK_LOGGER); - informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_SIMPLE_LOGGER); - } - throw new LogConfigurationException(messageBuffer.toString()); - } - - return result; - } - - // No user specified log; try to discover what's on the classpath - // - // Note that we deliberately loop here over classesToDiscover and - // expect method createLogFromClass to loop over the possible source - // classloaders. The effect is: - // for each discoverable log adapter - // for each possible classloader - // see if it works - // - // It appears reasonable at first glance to do the opposite: - // for each possible classloader - // for each discoverable log adapter - // see if it works - // - // The latter certainly has advantages for user-installable logging - // libraries such as log4j; in a webapp for example this code should - // first check whether the user has provided any of the possible - // logging libraries before looking in the parent classloader. - // Unfortunately, however, Jdk14Logger will always work in jvm>=1.4, - // and SimpleLog will always work in any JVM. So the loop would never - // ever look for logging libraries in the parent classpath. Yet many - // users would expect that putting log4j there would cause it to be - // detected (and this is the historical JCL behaviour). So we go with - // the first approach. A user that has bundled a specific logging lib - // in a webapp should use a commons-logging.properties file or a - // service file in META-INF to force use of that logging lib anyway, - // rather than relying on discovery. - - if (isDiagnosticsEnabled()) { - logDiagnostic( - "No user-specified Log implementation; performing discovery" + - " using the standard supported logging implementations..."); - } - for(int i=0; (i<classesToDiscover.length) && (result == null); ++i) { - result = createLogFromClass(classesToDiscover[i], logCategory, true); - } - - if (result == null) { - throw new LogConfigurationException - ("No suitable Log implementation"); - } - - return result; - } - - - /** - * Appends message if the given name is similar to the candidate. - * @param messageBuffer <code>StringBuffer</code> the message should be appended to, - * not null - * @param name the (trimmed) name to be test against the candidate, not null - * @param candidate the candidate name (not null) - */ - private void informUponSimilarName(final StringBuffer messageBuffer, final String name, - final String candidate) { - if (name.equals(candidate)) { - // Don't suggest a name that is exactly the same as the one the - // user tried... - return; - } - - // If the user provides a name that is in the right package, and gets - // the first 5 characters of the adapter class right (ignoring case), - // then suggest the candidate adapter class name. - if (name.regionMatches(true, 0, candidate, 0, PKG_LEN + 5)) { - messageBuffer.append(" Did you mean '"); - messageBuffer.append(candidate); - messageBuffer.append("'?"); - } - } - - - /** - * Checks system properties and the attribute map for - * a Log implementation specified by the user under the - * property names {@link #LOG_PROPERTY} or {@link #LOG_PROPERTY_OLD}. - * - * @return classname specified by the user, or <code>null</code> - */ - private String findUserSpecifiedLogClassName() - { - if (isDiagnosticsEnabled()) { - logDiagnostic("Trying to get log class from attribute '" + LOG_PROPERTY + "'"); - } - String specifiedClass = (String) getAttribute(LOG_PROPERTY); - - if (specifiedClass == null) { // @deprecated - if (isDiagnosticsEnabled()) { - logDiagnostic("Trying to get log class from attribute '" + - LOG_PROPERTY_OLD + "'"); - } - specifiedClass = (String) getAttribute(LOG_PROPERTY_OLD); - } - - if (specifiedClass == null) { - if (isDiagnosticsEnabled()) { - logDiagnostic("Trying to get log class from system property '" + - LOG_PROPERTY + "'"); - } - try { - specifiedClass = System.getProperty(LOG_PROPERTY); - } catch (SecurityException e) { - if (isDiagnosticsEnabled()) { - logDiagnostic("No access allowed to system property '" + - LOG_PROPERTY + "' - " + e.getMessage()); - } - } - } - - if (specifiedClass == null) { // @deprecated - if (isDiagnosticsEnabled()) { - logDiagnostic("Trying to get log class from system property '" + - LOG_PROPERTY_OLD + "'"); - } - try { - specifiedClass = System.getProperty(LOG_PROPERTY_OLD); - } catch (SecurityException e) { - if (isDiagnosticsEnabled()) { - logDiagnostic("No access allowed to system property '" + - LOG_PROPERTY_OLD + "' - " + e.getMessage()); - } - } - } - - // Remove any whitespace; it's never valid in a classname so its - // presence just means a user mistake. As we know what they meant, - // we may as well strip the spaces. - if (specifiedClass != null) { - specifiedClass = specifiedClass.trim(); - } - - return specifiedClass; - } - - - /** - * Attempts to load the given class, find a suitable constructor, - * and instantiate an instance of Log. - * - * @param logAdapterClassName classname of the Log implementation - * - * @param logCategory argument to pass to the Log implementation's - * constructor - * - * @param affectState <code>true</code> if this object's state should - * be affected by this method call, <code>false</code> otherwise. - * - * @return an instance of the given class, or null if the logging - * library associated with the specified adapter is not available. - * - * @throws LogConfigurationException if there was a serious error with - * configuration and the handleFlawedDiscovery method decided this - * problem was fatal. - */ - private Log createLogFromClass(String logAdapterClassName, - String logCategory, - boolean affectState) - throws LogConfigurationException { - - if (isDiagnosticsEnabled()) { - logDiagnostic("Attempting to instantiate '" + logAdapterClassName + "'"); - } - - Object[] params = { logCategory }; - Log logAdapter = null; - Constructor constructor = null; - - Class logAdapterClass = null; - ClassLoader currentCL = getBaseClassLoader(); - - for(;;) { - // Loop through the classloader hierarchy trying to find - // a viable classloader. - logDiagnostic( - "Trying to load '" - + logAdapterClassName - + "' from classloader " - + objectId(currentCL)); - try { - if (isDiagnosticsEnabled()) { - // Show the location of the first occurrence of the .class file - // in the classpath. This is the location that ClassLoader.loadClass - // will load the class from -- unless the classloader is doing - // something weird. - URL url; - String resourceName = logAdapterClassName.replace('.', '/') + ".class"; - if (currentCL != null) { - url = currentCL.getResource(resourceName ); - } else { - url = ClassLoader.getSystemResource(resourceName + ".class"); - } - - if (url == null) { - logDiagnostic("Class '" + logAdapterClassName + "' [" + resourceName + "] cannot be found."); - } else { - logDiagnostic("Class '" + logAdapterClassName + "' was found at '" + url + "'"); - } - } - - Class c = null; - try { - c = Class.forName(logAdapterClassName, true, currentCL); - } catch (ClassNotFoundException originalClassNotFoundException) { - // The current classloader was unable to find the log adapter - // in this or any ancestor classloader. There's no point in - // trying higher up in the hierarchy in this case.. - String msg = "" + originalClassNotFoundException.getMessage(); - logDiagnostic( - "The log adapter '" - + logAdapterClassName - + "' is not available via classloader " - + objectId(currentCL) - + ": " - + msg.trim()); - try { - // Try the class classloader. - // This may work in cases where the TCCL - // does not contain the code executed or JCL. - // This behaviour indicates that the application - // classloading strategy is not consistent with the - // Java 1.2 classloading guidelines but JCL can - // and so should handle this case. - c = Class.forName(logAdapterClassName); - } catch (ClassNotFoundException secondaryClassNotFoundException) { - // no point continuing: this adapter isn't available - msg = "" + secondaryClassNotFoundException.getMessage(); - logDiagnostic( - "The log adapter '" - + logAdapterClassName - + "' is not available via the LogFactoryImpl class classloader: " - + msg.trim()); - break; - } - } - - constructor = c.getConstructor(logConstructorSignature); - Object o = constructor.newInstance(params); - - // Note that we do this test after trying to create an instance - // [rather than testing Log.class.isAssignableFrom(c)] so that - // we don't complain about Log hierarchy problems when the - // adapter couldn't be instantiated anyway. - if (o instanceof Log) { - logAdapterClass = c; - logAdapter = (Log) o; - break; - } - - // Oops, we have a potential problem here. An adapter class - // has been found and its underlying lib is present too, but - // there are multiple Log interface classes available making it - // impossible to cast to the type the caller wanted. We - // certainly can't use this logger, but we need to know whether - // to keep on discovering or terminate now. - // - // The handleFlawedHierarchy method will throw - // LogConfigurationException if it regards this problem as - // fatal, and just return if not. - handleFlawedHierarchy(currentCL, c); - } catch (NoClassDefFoundError e) { - // We were able to load the adapter but it had references to - // other classes that could not be found. This simply means that - // the underlying logger library is not present in this or any - // ancestor classloader. There's no point in trying higher up - // in the hierarchy in this case.. - String msg = "" + e.getMessage(); - logDiagnostic( - "The log adapter '" - + logAdapterClassName - + "' is missing dependencies when loaded via classloader " - + objectId(currentCL) - + ": " - + msg.trim()); - break; - } catch (ExceptionInInitializerError e) { - // A static initializer block or the initializer code associated - // with a static variable on the log adapter class has thrown - // an exception. - // - // We treat this as meaning the adapter's underlying logging - // library could not be found. - String msg = "" + e.getMessage(); - logDiagnostic( - "The log adapter '" - + logAdapterClassName - + "' is unable to initialize itself when loaded via classloader " - + objectId(currentCL) - + ": " - + msg.trim()); - break; - } catch(LogConfigurationException e) { - // call to handleFlawedHierarchy above must have thrown - // a LogConfigurationException, so just throw it on - throw e; - } catch(Throwable t) { - // handleFlawedDiscovery will determine whether this is a fatal - // problem or not. If it is fatal, then a LogConfigurationException - // will be thrown. - handleFlawedDiscovery(logAdapterClassName, currentCL, t); - } - - if (currentCL == null) { - break; - } - - // try the parent classloader - currentCL = currentCL.getParent(); - } - - if ((logAdapter != null) && affectState) { - // We've succeeded, so set instance fields - this.logClassName = logAdapterClassName; - this.logConstructor = constructor; - - // Identify the <code>setLogFactory</code> method (if there is one) - try { - this.logMethod = logAdapterClass.getMethod("setLogFactory", - logMethodSignature); - logDiagnostic("Found method setLogFactory(LogFactory) in '" - + logAdapterClassName + "'"); - } catch (Throwable t) { - this.logMethod = null; - logDiagnostic( - "[INFO] '" + logAdapterClassName - + "' from classloader " + objectId(currentCL) - + " does not declare optional method " - + "setLogFactory(LogFactory)"); - } - - logDiagnostic( - "Log adapter '" + logAdapterClassName - + "' from classloader " + objectId(logAdapterClass.getClassLoader()) - + " has been selected for use."); - } - - return logAdapter; - } - - - /** - * Return the classloader from which we should try to load the logging - * adapter classes. - * <p> - * This method usually returns the context classloader. However if it - * is discovered that the classloader which loaded this class is a child - * of the context classloader <i>and</i> the allowFlawedContext option - * has been set then the classloader which loaded this class is returned - * instead. - * <p> - * The only time when the classloader which loaded this class is a - * descendant (rather than the same as or an ancestor of the context - * classloader) is when an app has created custom classloaders but - * failed to correctly set the context classloader. This is a bug in - * the calling application; however we provide the option for JCL to - * simply generate a warning rather than fail outright. - * - */ - private ClassLoader getBaseClassLoader() throws LogConfigurationException { - ClassLoader thisClassLoader = getClassLoader(LogFactoryImpl.class); - - if (useTCCL == false) { - return thisClassLoader; - } - - ClassLoader contextClassLoader = getContextClassLoader(); - - ClassLoader baseClassLoader = getLowestClassLoader( - contextClassLoader, thisClassLoader); - - if (baseClassLoader == null) { - // The two classloaders are not part of a parent child relationship. - // In some classloading setups (e.g. JBoss with its - // UnifiedLoaderRepository) this can still work, so if user hasn't - // forbidden it, just return the contextClassLoader. - if (allowFlawedContext) { - if (isDiagnosticsEnabled()) { - logDiagnostic( - "[WARNING] the context classloader is not part of a" - + " parent-child relationship with the classloader that" - + " loaded LogFactoryImpl."); - } - // If contextClassLoader were null, getLowestClassLoader() would - // have returned thisClassLoader. The fact we are here means - // contextClassLoader is not null, so we can just return it. - return contextClassLoader; - } - else { - throw new LogConfigurationException( - "Bad classloader hierarchy; LogFactoryImpl was loaded via" - + " a classloader that is not related to the current context" - + " classloader."); - } - } - - if (baseClassLoader != contextClassLoader) { - // We really should just use the contextClassLoader as the starting - // point for scanning for log adapter classes. However it is expected - // that there are a number of broken systems out there which create - // custom classloaders but fail to set the context classloader so - // we handle those flawed systems anyway. - if (allowFlawedContext) { - if (isDiagnosticsEnabled()) { - logDiagnostic( - "Warning: the context classloader is an ancestor of the" - + " classloader that loaded LogFactoryImpl; it should be" - + " the same or a descendant. The application using" - + " commons-logging should ensure the context classloader" - + " is used correctly."); - } - } else { - throw new LogConfigurationException( - "Bad classloader hierarchy; LogFactoryImpl was loaded via" - + " a classloader that is not related to the current context" - + " classloader."); - } - } - - return baseClassLoader; - } - - /** - * Given two related classloaders, return the one which is a child of - * the other. - * <p> - * @param c1 is a classloader (including the null classloader) - * @param c2 is a classloader (including the null classloader) - * - * @return c1 if it has c2 as an ancestor, c2 if it has c1 as an ancestor, - * and null if neither is an ancestor of the other. - */ - private ClassLoader getLowestClassLoader(ClassLoader c1, ClassLoader c2) { - // TODO: use AccessController when dealing with classloaders here - - if (c1 == null) - return c2; - - if (c2 == null) - return c1; - - ClassLoader current; - - // scan c1's ancestors to find c2 - current = c1; - while (current != null) { - if (current == c2) - return c1; - current = current.getParent(); - } - - // scan c2's ancestors to find c1 - current = c2; - while (current != null) { - if (current == c1) - return c2; - current = current.getParent(); - } - - return null; - } - - /** - * Generates an internal diagnostic logging of the discovery failure and - * then throws a <code>LogConfigurationException</code> that wraps - * the passed <code>Throwable</code>. - * - * @param logAdapterClassName is the class name of the Log implementation - * that could not be instantiated. Cannot be <code>null</code>. - * - * @param classLoader is the classloader that we were trying to load the - * logAdapterClassName from when the exception occurred. - * - * @param discoveryFlaw is the Throwable created by the classloader - * - * @throws LogConfigurationException ALWAYS - */ - private void handleFlawedDiscovery(String logAdapterClassName, - ClassLoader classLoader, - Throwable discoveryFlaw) { - - if (isDiagnosticsEnabled()) { - logDiagnostic("Could not instantiate Log '" - + logAdapterClassName + "' -- " - + discoveryFlaw.getClass().getName() + ": " - + discoveryFlaw.getLocalizedMessage()); - } - - if (!allowFlawedDiscovery) { - throw new LogConfigurationException(discoveryFlaw); - } - } - - - /** - * Report a problem loading the log adapter, then either return - * (if the situation is considered recoverable) or throw a - * LogConfigurationException. - * <p> - * There are two possible reasons why we successfully loaded the - * specified log adapter class then failed to cast it to a Log object: - * <ol> - * <li>the specific class just doesn't implement the Log interface - * (user screwed up), or - * <li> the specified class has bound to a Log class loaded by some other - * classloader; Log@classloaderX cannot be cast to Log@classloaderY. - * </ol> - * <p> - * Here we try to figure out which case has occurred so we can give the - * user some reasonable feedback. - * - * @param badClassLoader is the classloader we loaded the problem class from, - * ie it is equivalent to badClass.getClassLoader(). - * - * @param badClass is a Class object with the desired name, but which - * does not implement Log correctly. - * - * @throws LogConfigurationException when the situation - * should not be recovered from. - */ - private void handleFlawedHierarchy(ClassLoader badClassLoader, Class badClass) - throws LogConfigurationException { - - boolean implementsLog = false; - String logInterfaceName = Log.class.getName(); - Class interfaces[] = badClass.getInterfaces(); - for (int i = 0; i < interfaces.length; i++) { - if (logInterfaceName.equals(interfaces[i].getName())) { - implementsLog = true; - break; - } - } - - if (implementsLog) { - // the class does implement an interface called Log, but - // it is in the wrong classloader - if (isDiagnosticsEnabled()) { - try { - ClassLoader logInterfaceClassLoader = getClassLoader(Log.class); - logDiagnostic( - "Class '" + badClass.getName() - + "' was found in classloader " - + objectId(badClassLoader) - + ". It is bound to a Log interface which is not" - + " the one loaded from classloader " - + objectId(logInterfaceClassLoader)); - } catch (Throwable t) { - logDiagnostic( - "Error while trying to output diagnostics about" - + " bad class '" + badClass + "'"); - } - } - - if (!allowFlawedHierarchy) { - StringBuffer msg = new StringBuffer(); - msg.append("Terminating logging for this context "); - msg.append("due to bad log hierarchy. "); - msg.append("You have more than one version of '"); - msg.append(Log.class.getName()); - msg.append("' visible."); - if (isDiagnosticsEnabled()) { - logDiagnostic(msg.toString()); - } - throw new LogConfigurationException(msg.toString()); - } - - if (isDiagnosticsEnabled()) { - StringBuffer msg = new StringBuffer(); - msg.append("Warning: bad log hierarchy. "); - msg.append("You have more than one version of '"); - msg.append(Log.class.getName()); - msg.append("' visible."); - logDiagnostic(msg.toString()); - } - } else { - // this is just a bad adapter class - if (!allowFlawedDiscovery) { - StringBuffer msg = new StringBuffer(); - msg.append("Terminating logging for this context. "); - msg.append("Log class '"); - msg.append(badClass.getName()); - msg.append("' does not implement the Log interface."); - if (isDiagnosticsEnabled()) { - logDiagnostic(msg.toString()); - } - - throw new LogConfigurationException(msg.toString()); - } - - if (isDiagnosticsEnabled()) { - StringBuffer msg = new StringBuffer(); - msg.append("[WARNING] Log class '"); - msg.append(badClass.getName()); - msg.append("' does not implement the Log interface."); - logDiagnostic(msg.toString()); - } - } - } -} diff --git a/src/org/apache/commons/logging/impl/NoOpLog.java b/src/org/apache/commons/logging/impl/NoOpLog.java deleted file mode 100644 index b698813..0000000 --- a/src/org/apache/commons/logging/impl/NoOpLog.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.commons.logging.impl; - - -import java.io.Serializable; -import org.apache.commons.logging.Log; - - -/** - * <p>Trivial implementation of Log that throws away all messages. No - * configurable system properties are supported.</p> - * - * @author <a href="mailto:sanders@apache.org">Scott Sanders</a> - * @author Rod Waldhoff - * @version $Id: NoOpLog.java 155426 2005-02-26 13:10:49Z dirkv $ - */ -public class NoOpLog implements Log, Serializable { - - /** Convenience constructor */ - public NoOpLog() { } - /** Base constructor */ - public NoOpLog(String name) { } - /** Do nothing */ - public void trace(Object message) { } - /** Do nothing */ - public void trace(Object message, Throwable t) { } - /** Do nothing */ - public void debug(Object message) { } - /** Do nothing */ - public void debug(Object message, Throwable t) { } - /** Do nothing */ - public void info(Object message) { } - /** Do nothing */ - public void info(Object message, Throwable t) { } - /** Do nothing */ - public void warn(Object message) { } - /** Do nothing */ - public void warn(Object message, Throwable t) { } - /** Do nothing */ - public void error(Object message) { } - /** Do nothing */ - public void error(Object message, Throwable t) { } - /** Do nothing */ - public void fatal(Object message) { } - /** Do nothing */ - public void fatal(Object message, Throwable t) { } - - /** - * Debug is never enabled. - * - * @return false - */ - public final boolean isDebugEnabled() { return false; } - - /** - * Error is never enabled. - * - * @return false - */ - public final boolean isErrorEnabled() { return false; } - - /** - * Fatal is never enabled. - * - * @return false - */ - public final boolean isFatalEnabled() { return false; } - - /** - * Info is never enabled. - * - * @return false - */ - public final boolean isInfoEnabled() { return false; } - - /** - * Trace is never enabled. - * - * @return false - */ - public final boolean isTraceEnabled() { return false; } - - /** - * Warn is never enabled. - * - * @return false - */ - public final boolean isWarnEnabled() { return false; } - -} diff --git a/src/org/apache/commons/logging/impl/SimpleLog.java b/src/org/apache/commons/logging/impl/SimpleLog.java deleted file mode 100644 index 6b643d3..0000000 --- a/src/org/apache/commons/logging/impl/SimpleLog.java +++ /dev/null @@ -1,709 +0,0 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.commons.logging.impl; - -import java.io.InputStream; -import java.io.Serializable; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Properties; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogConfigurationException; - -/** - * <p>Simple implementation of Log that sends all enabled log messages, - * for all defined loggers, to System.err. The following system properties - * are supported to configure the behavior of this logger:</p> - * <ul> - * <li><code>org.apache.commons.logging.simplelog.defaultlog</code> - - * Default logging detail level for all instances of SimpleLog. - * Must be one of ("trace", "debug", "info", "warn", "error", or "fatal"). - * If not specified, defaults to "info". </li> - * <li><code>org.apache.commons.logging.simplelog.log.xxxxx</code> - - * Logging detail level for a SimpleLog instance named "xxxxx". - * Must be one of ("trace", "debug", "info", "warn", "error", or "fatal"). - * If not specified, the default logging detail level is used.</li> - * <li><code>org.apache.commons.logging.simplelog.showlogname</code> - - * Set to <code>true</code> if you want the Log instance name to be - * included in output messages. Defaults to <code>false</code>.</li> - * <li><code>org.apache.commons.logging.simplelog.showShortLogname</code> - - * Set to <code>true</code> if you want the last component of the name to be - * included in output messages. Defaults to <code>true</code>.</li> - * <li><code>org.apache.commons.logging.simplelog.showdatetime</code> - - * Set to <code>true</code> if you want the current date and time - * to be included in output messages. Default is <code>false</code>.</li> - * <li><code>org.apache.commons.logging.simplelog.dateTimeFormat</code> - - * The date and time format to be used in the output messages. - * The pattern describing the date and time format is the same that is - * used in <code>java.text.SimpleDateFormat</code>. If the format is not - * specified or is invalid, the default format is used. - * The default format is <code>yyyy/MM/dd HH:mm:ss:SSS zzz</code>.</li> - * </ul> - * - * <p>In addition to looking for system properties with the names specified - * above, this implementation also checks for a class loader resource named - * <code>"simplelog.properties"</code>, and includes any matching definitions - * from this resource (if it exists).</p> - * - * @author <a href="mailto:sanders@apache.org">Scott Sanders</a> - * @author Rod Waldhoff - * @author Robert Burrell Donkin - * - * @version $Id: SimpleLog.java 399221 2006-05-03 09:20:24Z dennisl $ - */ -public class SimpleLog implements Log, Serializable { - - - // ------------------------------------------------------- Class Attributes - - /** All system properties used by <code>SimpleLog</code> start with this */ - static protected final String systemPrefix = - "org.apache.commons.logging.simplelog."; - - /** Properties loaded from simplelog.properties */ - static protected final Properties simpleLogProps = new Properties(); - - /** The default format to use when formating dates */ - static protected final String DEFAULT_DATE_TIME_FORMAT = - "yyyy/MM/dd HH:mm:ss:SSS zzz"; - - /** Include the instance name in the log message? */ - static protected boolean showLogName = false; - /** Include the short name ( last component ) of the logger in the log - * message. Defaults to true - otherwise we'll be lost in a flood of - * messages without knowing who sends them. - */ - static protected boolean showShortName = true; - /** Include the current time in the log message */ - static protected boolean showDateTime = false; - /** The date and time format to use in the log message */ - static protected String dateTimeFormat = DEFAULT_DATE_TIME_FORMAT; - /** Used to format times */ - static protected DateFormat dateFormatter = null; - - // ---------------------------------------------------- Log Level Constants - - - /** "Trace" level logging. */ - public static final int LOG_LEVEL_TRACE = 1; - /** "Debug" level logging. */ - public static final int LOG_LEVEL_DEBUG = 2; - /** "Info" level logging. */ - public static final int LOG_LEVEL_INFO = 3; - /** "Warn" level logging. */ - public static final int LOG_LEVEL_WARN = 4; - /** "Error" level logging. */ - public static final int LOG_LEVEL_ERROR = 5; - /** "Fatal" level logging. */ - public static final int LOG_LEVEL_FATAL = 6; - - /** Enable all logging levels */ - public static final int LOG_LEVEL_ALL = (LOG_LEVEL_TRACE - 1); - - /** Enable no logging levels */ - public static final int LOG_LEVEL_OFF = (LOG_LEVEL_FATAL + 1); - - // ------------------------------------------------------------ Initializer - - private static String getStringProperty(String name) { - String prop = null; - try { - prop = System.getProperty(name); - } catch (SecurityException e) { - ; // Ignore - } - return (prop == null) ? simpleLogProps.getProperty(name) : prop; - } - - private static String getStringProperty(String name, String dephault) { - String prop = getStringProperty(name); - return (prop == null) ? dephault : prop; - } - - private static boolean getBooleanProperty(String name, boolean dephault) { - String prop = getStringProperty(name); - return (prop == null) ? dephault : "true".equalsIgnoreCase(prop); - } - - // Initialize class attributes. - // Load properties file, if found. - // Override with system properties. - static { - // Add props from the resource simplelog.properties - InputStream in = getResourceAsStream("simplelog.properties"); - if(null != in) { - try { - simpleLogProps.load(in); - in.close(); - } catch(java.io.IOException e) { - // ignored - } - } - - showLogName = getBooleanProperty( systemPrefix + "showlogname", showLogName); - showShortName = getBooleanProperty( systemPrefix + "showShortLogname", showShortName); - showDateTime = getBooleanProperty( systemPrefix + "showdatetime", showDateTime); - - if(showDateTime) { - dateTimeFormat = getStringProperty(systemPrefix + "dateTimeFormat", - dateTimeFormat); - try { - dateFormatter = new SimpleDateFormat(dateTimeFormat); - } catch(IllegalArgumentException e) { - // If the format pattern is invalid - use the default format - dateTimeFormat = DEFAULT_DATE_TIME_FORMAT; - dateFormatter = new SimpleDateFormat(dateTimeFormat); - } - } - } - - - // ------------------------------------------------------------- Attributes - - /** The name of this simple log instance */ - protected String logName = null; - /** The current log level */ - protected int currentLogLevel; - /** The short name of this simple log instance */ - private String shortLogName = null; - - - // ------------------------------------------------------------ Constructor - - /** - * Construct a simple log with given name. - * - * @param name log name - */ - public SimpleLog(String name) { - - logName = name; - - // Set initial log level - // Used to be: set default log level to ERROR - // IMHO it should be lower, but at least info ( costin ). - setLevel(SimpleLog.LOG_LEVEL_INFO); - - // Set log level from properties - String lvl = getStringProperty(systemPrefix + "log." + logName); - int i = String.valueOf(name).lastIndexOf("."); - while(null == lvl && i > -1) { - name = name.substring(0,i); - lvl = getStringProperty(systemPrefix + "log." + name); - i = String.valueOf(name).lastIndexOf("."); - } - - if(null == lvl) { - lvl = getStringProperty(systemPrefix + "defaultlog"); - } - - if("all".equalsIgnoreCase(lvl)) { - setLevel(SimpleLog.LOG_LEVEL_ALL); - } else if("trace".equalsIgnoreCase(lvl)) { - setLevel(SimpleLog.LOG_LEVEL_TRACE); - } else if("debug".equalsIgnoreCase(lvl)) { - setLevel(SimpleLog.LOG_LEVEL_DEBUG); - } else if("info".equalsIgnoreCase(lvl)) { - setLevel(SimpleLog.LOG_LEVEL_INFO); - } else if("warn".equalsIgnoreCase(lvl)) { - setLevel(SimpleLog.LOG_LEVEL_WARN); - } else if("error".equalsIgnoreCase(lvl)) { - setLevel(SimpleLog.LOG_LEVEL_ERROR); - } else if("fatal".equalsIgnoreCase(lvl)) { - setLevel(SimpleLog.LOG_LEVEL_FATAL); - } else if("off".equalsIgnoreCase(lvl)) { - setLevel(SimpleLog.LOG_LEVEL_OFF); - } - - } - - - // -------------------------------------------------------- Properties - - /** - * <p> Set logging level. </p> - * - * @param currentLogLevel new logging level - */ - public void setLevel(int currentLogLevel) { - - this.currentLogLevel = currentLogLevel; - - } - - - /** - * <p> Get logging level. </p> - */ - public int getLevel() { - - return currentLogLevel; - } - - - // -------------------------------------------------------- Logging Methods - - - /** - * <p> Do the actual logging. - * This method assembles the message - * and then calls <code>write()</code> to cause it to be written.</p> - * - * @param type One of the LOG_LEVEL_XXX constants defining the log level - * @param message The message itself (typically a String) - * @param t The exception whose stack trace should be logged - */ - protected void log(int type, Object message, Throwable t) { - // Use a string buffer for better performance - StringBuffer buf = new StringBuffer(); - - // Append date-time if so configured - if(showDateTime) { - buf.append(dateFormatter.format(new Date())); - buf.append(" "); - } - - // Append a readable representation of the log level - switch(type) { - case SimpleLog.LOG_LEVEL_TRACE: buf.append("[TRACE] "); break; - case SimpleLog.LOG_LEVEL_DEBUG: buf.append("[DEBUG] "); break; - case SimpleLog.LOG_LEVEL_INFO: buf.append("[INFO] "); break; - case SimpleLog.LOG_LEVEL_WARN: buf.append("[WARN] "); break; - case SimpleLog.LOG_LEVEL_ERROR: buf.append("[ERROR] "); break; - case SimpleLog.LOG_LEVEL_FATAL: buf.append("[FATAL] "); break; - } - - // Append the name of the log instance if so configured - if( showShortName) { - if( shortLogName==null ) { - // Cut all but the last component of the name for both styles - shortLogName = logName.substring(logName.lastIndexOf(".") + 1); - shortLogName = - shortLogName.substring(shortLogName.lastIndexOf("/") + 1); - } - buf.append(String.valueOf(shortLogName)).append(" - "); - } else if(showLogName) { - buf.append(String.valueOf(logName)).append(" - "); - } - - // Append the message - buf.append(String.valueOf(message)); - - // Append stack trace if not null - if(t != null) { - buf.append(" <"); - buf.append(t.toString()); - buf.append(">"); - - java.io.StringWriter sw= new java.io.StringWriter(1024); - java.io.PrintWriter pw= new java.io.PrintWriter(sw); - t.printStackTrace(pw); - pw.close(); - buf.append(sw.toString()); - } - - // Print to the appropriate destination - write(buf); - - } - - - /** - * <p>Write the content of the message accumulated in the specified - * <code>StringBuffer</code> to the appropriate output destination. The - * default implementation writes to <code>System.err</code>.</p> - * - * @param buffer A <code>StringBuffer</code> containing the accumulated - * text to be logged - */ - protected void write(StringBuffer buffer) { - - System.err.println(buffer.toString()); - - } - - - /** - * Is the given log level currently enabled? - * - * @param logLevel is this level enabled? - */ - protected boolean isLevelEnabled(int logLevel) { - // log level are numerically ordered so can use simple numeric - // comparison - return (logLevel >= currentLogLevel); - } - - - // -------------------------------------------------------- Log Implementation - - - /** - * Logs a message with - * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_DEBUG</code>. - * - * @param message to log - * @see org.apache.commons.logging.Log#debug(Object) - */ - public final void debug(Object message) { - - if (isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG)) { - log(SimpleLog.LOG_LEVEL_DEBUG, message, null); - } - } - - - /** - * Logs a message with - * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_DEBUG</code>. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#debug(Object, Throwable) - */ - public final void debug(Object message, Throwable t) { - - if (isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG)) { - log(SimpleLog.LOG_LEVEL_DEBUG, message, t); - } - } - - - /** - * Logs a message with - * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_TRACE</code>. - * - * @param message to log - * @see org.apache.commons.logging.Log#trace(Object) - */ - public final void trace(Object message) { - - if (isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE)) { - log(SimpleLog.LOG_LEVEL_TRACE, message, null); - } - } - - - /** - * Logs a message with - * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_TRACE</code>. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#trace(Object, Throwable) - */ - public final void trace(Object message, Throwable t) { - - if (isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE)) { - log(SimpleLog.LOG_LEVEL_TRACE, message, t); - } - } - - - /** - * Logs a message with - * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_INFO</code>. - * - * @param message to log - * @see org.apache.commons.logging.Log#info(Object) - */ - public final void info(Object message) { - - if (isLevelEnabled(SimpleLog.LOG_LEVEL_INFO)) { - log(SimpleLog.LOG_LEVEL_INFO,message,null); - } - } - - - /** - * Logs a message with - * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_INFO</code>. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#info(Object, Throwable) - */ - public final void info(Object message, Throwable t) { - - if (isLevelEnabled(SimpleLog.LOG_LEVEL_INFO)) { - log(SimpleLog.LOG_LEVEL_INFO, message, t); - } - } - - - /** - * Logs a message with - * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_WARN</code>. - * - * @param message to log - * @see org.apache.commons.logging.Log#warn(Object) - */ - public final void warn(Object message) { - - if (isLevelEnabled(SimpleLog.LOG_LEVEL_WARN)) { - log(SimpleLog.LOG_LEVEL_WARN, message, null); - } - } - - - /** - * Logs a message with - * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_WARN</code>. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#warn(Object, Throwable) - */ - public final void warn(Object message, Throwable t) { - - if (isLevelEnabled(SimpleLog.LOG_LEVEL_WARN)) { - log(SimpleLog.LOG_LEVEL_WARN, message, t); - } - } - - - /** - * Logs a message with - * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_ERROR</code>. - * - * @param message to log - * @see org.apache.commons.logging.Log#error(Object) - */ - public final void error(Object message) { - - if (isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR)) { - log(SimpleLog.LOG_LEVEL_ERROR, message, null); - } - } - - - /** - * Logs a message with - * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_ERROR</code>. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#error(Object, Throwable) - */ - public final void error(Object message, Throwable t) { - - if (isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR)) { - log(SimpleLog.LOG_LEVEL_ERROR, message, t); - } - } - - - /** - * Log a message with - * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_FATAL</code>. - * - * @param message to log - * @see org.apache.commons.logging.Log#fatal(Object) - */ - public final void fatal(Object message) { - - if (isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL)) { - log(SimpleLog.LOG_LEVEL_FATAL, message, null); - } - } - - - /** - * Logs a message with - * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_FATAL</code>. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#fatal(Object, Throwable) - */ - public final void fatal(Object message, Throwable t) { - - if (isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL)) { - log(SimpleLog.LOG_LEVEL_FATAL, message, t); - } - } - - - /** - * <p> Are debug messages currently enabled? </p> - * - * <p> This allows expensive operations such as <code>String</code> - * concatenation to be avoided when the message will be ignored by the - * logger. </p> - */ - public final boolean isDebugEnabled() { - - return isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG); - } - - - /** - * <p> Are error messages currently enabled? </p> - * - * <p> This allows expensive operations such as <code>String</code> - * concatenation to be avoided when the message will be ignored by the - * logger. </p> - */ - public final boolean isErrorEnabled() { - - return isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR); - } - - - /** - * <p> Are fatal messages currently enabled? </p> - * - * <p> This allows expensive operations such as <code>String</code> - * concatenation to be avoided when the message will be ignored by the - * logger. </p> - */ - public final boolean isFatalEnabled() { - - return isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL); - } - - - /** - * <p> Are info messages currently enabled? </p> - * - * <p> This allows expensive operations such as <code>String</code> - * concatenation to be avoided when the message will be ignored by the - * logger. </p> - */ - public final boolean isInfoEnabled() { - - return isLevelEnabled(SimpleLog.LOG_LEVEL_INFO); - } - - - /** - * <p> Are trace messages currently enabled? </p> - * - * <p> This allows expensive operations such as <code>String</code> - * concatenation to be avoided when the message will be ignored by the - * logger. </p> - */ - public final boolean isTraceEnabled() { - - return isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE); - } - - - /** - * <p> Are warn messages currently enabled? </p> - * - * <p> This allows expensive operations such as <code>String</code> - * concatenation to be avoided when the message will be ignored by the - * logger. </p> - */ - public final boolean isWarnEnabled() { - - return isLevelEnabled(SimpleLog.LOG_LEVEL_WARN); - } - - - /** - * Return the thread context class loader if available. - * Otherwise return null. - * - * The thread context class loader is available for JDK 1.2 - * or later, if certain security conditions are met. - * - * @exception LogConfigurationException if a suitable class loader - * cannot be identified. - */ - private static ClassLoader getContextClassLoader() - { - ClassLoader classLoader = null; - - if (classLoader == null) { - try { - // Are we running on a JDK 1.2 or later system? - Method method = Thread.class.getMethod("getContextClassLoader", - (Class[]) null); - - // Get the thread context class loader (if there is one) - try { - classLoader = (ClassLoader)method.invoke(Thread.currentThread(), - (Object[]) null); - - } catch (IllegalAccessException e) { - ; // ignore - } catch (InvocationTargetException e) { - /** - * InvocationTargetException is thrown by 'invoke' when - * the method being invoked (getContextClassLoader) throws - * an exception. - * - * getContextClassLoader() throws SecurityException when - * the context class loader isn't an ancestor of the - * calling class's class loader, or if security - * permissions are restricted. - * - * In the first case (not related), we want to ignore and - * keep going. We cannot help but also ignore the second - * with the logic below, but other calls elsewhere (to - * obtain a class loader) will trigger this exception where - * we can make a distinction. - */ - if (e.getTargetException() instanceof SecurityException) { - ; // ignore - } else { - // Capture 'e.getTargetException()' exception for details - // alternate: log 'e.getTargetException()', and pass back 'e'. - throw new LogConfigurationException - ("Unexpected InvocationTargetException", e.getTargetException()); - } - } - } catch (NoSuchMethodException e) { - // Assume we are running on JDK 1.1 - ; // ignore - } - } - - if (classLoader == null) { - classLoader = SimpleLog.class.getClassLoader(); - } - - // Return the selected class loader - return classLoader; - } - - private static InputStream getResourceAsStream(final String name) - { - return (InputStream)AccessController.doPrivileged( - new PrivilegedAction() { - public Object run() { - ClassLoader threadCL = getContextClassLoader(); - - if (threadCL != null) { - return threadCL.getResourceAsStream(name); - } else { - return ClassLoader.getSystemResourceAsStream(name); - } - } - }); - } -} - diff --git a/src/org/apache/commons/logging/impl/WeakHashtable.java b/src/org/apache/commons/logging/impl/WeakHashtable.java deleted file mode 100644 index e4749b6..0000000 --- a/src/org/apache/commons/logging/impl/WeakHashtable.java +++ /dev/null @@ -1,478 +0,0 @@ -/* - * Copyright 2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.commons.logging.impl; - -import java.lang.ref.ReferenceQueue; -import java.lang.ref.WeakReference; -import java.util.*; - -/** - * <p>Implementation of <code>Hashtable</code> that uses <code>WeakReference</code>'s - * to hold its keys thus allowing them to be reclaimed by the garbage collector. - * The associated values are retained using strong references.</p> - * - * <p>This class follows the symantics of <code>Hashtable</code> as closely as - * possible. It therefore does not accept null values or keys.</p> - * - * <p><strong>Note:</strong> - * This is <em>not</em> intended to be a general purpose hash table replacement. - * This implementation is also tuned towards a particular purpose: for use as a replacement - * for <code>Hashtable</code> in <code>LogFactory</code>. This application requires - * good liveliness for <code>get</code> and <code>put</code>. Various tradeoffs - * have been made with this in mind. - * </p> - * <p> - * <strong>Usage:</strong> typical use case is as a drop-in replacement - * for the <code>Hashtable</code> used in <code>LogFactory</code> for J2EE enviroments - * running 1.3+ JVMs. Use of this class <i>in most cases</i> (see below) will - * allow classloaders to be collected by the garbage collector without the need - * to call {@link org.apache.commons.logging.LogFactory#release(ClassLoader) LogFactory.release(ClassLoader)}. - * </p> - * - * <p><code>org.apache.commons.logging.LogFactory</code> checks whether this class - * can be supported by the current JVM, and if so then uses it to store - * references to the <code>LogFactory</code> implementationd it loads - * (rather than using a standard Hashtable instance). - * Having this class used instead of <code>Hashtable</code> solves - * certain issues related to dynamic reloading of applications in J2EE-style - * environments. However this class requires java 1.3 or later (due to its use - * of <code>java.lang.ref.WeakReference</code> and associates). - * And by the way, this extends <code>Hashtable</code> rather than <code>HashMap</code> - * for backwards compatibility reasons. See the documentation - * for method <code>LogFactory.createFactoryStore</code> for more details.</p> - * - * <p>The reason all this is necessary is due to a issue which - * arises during hot deploy in a J2EE-like containers. - * Each component running in the container owns one or more classloaders; when - * the component loads a LogFactory instance via the component classloader - * a reference to it gets stored in the static LogFactory.factories member, - * keyed by the component's classloader so different components don't - * stomp on each other. When the component is later unloaded, the container - * sets the component's classloader to null with the intent that all the - * component's classes get garbage-collected. However there's still a - * reference to the component's classloader from a key in the "global" - * <code>LogFactory</code>'s factories member! If <code>LogFactory.release()</code> - * is called whenever component is unloaded, the classloaders will be correctly - * garbage collected; this <i>should</i> be done by any container that - * bundles commons-logging by default. However, holding the classloader - * references weakly ensures that the classloader will be garbage collected - * without the container performing this step. </p> - * - * <p> - * <strong>Limitations:</strong> - * There is still one (unusual) scenario in which a component will not - * be correctly unloaded without an explicit release. Though weak references - * are used for its keys, it is necessary to use strong references for its values. - * </p> - * - * <p> If the abstract class <code>LogFactory</code> is - * loaded by the container classloader but a subclass of - * <code>LogFactory</code> [LogFactory1] is loaded by the component's - * classloader and an instance stored in the static map associated with the - * base LogFactory class, then there is a strong reference from the LogFactory - * class to the LogFactory1 instance (as normal) and a strong reference from - * the LogFactory1 instance to the component classloader via - * <code>getClass().getClassLoader()</code>. This chain of references will prevent - * collection of the child classloader.</p> - * - * <p> - * Such a situation occurs when the commons-logging.jar is - * loaded by a parent classloader (e.g. a server level classloader in a - * servlet container) and a custom <code>LogFactory</code> implementation is - * loaded by a child classloader (e.g. a web app classloader).</p> - * - * <p>To avoid this scenario, ensure - * that any custom LogFactory subclass is loaded by the same classloader as - * the base <code>LogFactory</code>. Creating custom LogFactory subclasses is, - * however, rare. The standard LogFactoryImpl class should be sufficient - * for most or all users.</p> - * - * - * @author Brian Stansberry - * - * @since 1.1 - */ -public final class WeakHashtable extends Hashtable { - - /** - * The maximum number of times put() or remove() can be called before - * the map will be purged of all cleared entries. - */ - private static final int MAX_CHANGES_BEFORE_PURGE = 100; - - /** - * The maximum number of times put() or remove() can be called before - * the map will be purged of one cleared entry. - */ - private static final int PARTIAL_PURGE_COUNT = 10; - - /* ReferenceQueue we check for gc'd keys */ - private ReferenceQueue queue = new ReferenceQueue(); - /* Counter used to control how often we purge gc'd entries */ - private int changeCount = 0; - - /** - * Constructs a WeakHashtable with the Hashtable default - * capacity and load factor. - */ - public WeakHashtable() {} - - - /** - *@see Hashtable - */ - public boolean containsKey(Object key) { - // purge should not be required - Referenced referenced = new Referenced(key); - return super.containsKey(referenced); - } - - /** - *@see Hashtable - */ - public Enumeration elements() { - purge(); - return super.elements(); - } - - /** - *@see Hashtable - */ - public Set entrySet() { - purge(); - Set referencedEntries = super.entrySet(); - Set unreferencedEntries = new HashSet(); - for (Iterator it=referencedEntries.iterator(); it.hasNext();) { - Map.Entry entry = (Map.Entry) it.next(); - Referenced referencedKey = (Referenced) entry.getKey(); - Object key = referencedKey.getValue(); - Object value = entry.getValue(); - if (key != null) { - Entry dereferencedEntry = new Entry(key, value); - unreferencedEntries.add(dereferencedEntry); - } - } - return unreferencedEntries; - } - - /** - *@see Hashtable - */ - public Object get(Object key) { - // for performance reasons, no purge - Referenced referenceKey = new Referenced(key); - return super.get(referenceKey); - } - - /** - *@see Hashtable - */ - public Enumeration keys() { - purge(); - final Enumeration enumer = super.keys(); - return new Enumeration() { - public boolean hasMoreElements() { - return enumer.hasMoreElements(); - } - public Object nextElement() { - Referenced nextReference = (Referenced) enumer.nextElement(); - return nextReference.getValue(); - } - }; - } - - - /** - *@see Hashtable - */ - public Set keySet() { - purge(); - Set referencedKeys = super.keySet(); - Set unreferencedKeys = new HashSet(); - for (Iterator it=referencedKeys.iterator(); it.hasNext();) { - Referenced referenceKey = (Referenced) it.next(); - Object keyValue = referenceKey.getValue(); - if (keyValue != null) { - unreferencedKeys.add(keyValue); - } - } - return unreferencedKeys; - } - - /** - *@see Hashtable - */ - public Object put(Object key, Object value) { - // check for nulls, ensuring symantics match superclass - if (key == null) { - throw new NullPointerException("Null keys are not allowed"); - } - if (value == null) { - throw new NullPointerException("Null values are not allowed"); - } - - // for performance reasons, only purge every - // MAX_CHANGES_BEFORE_PURGE times - if (changeCount++ > MAX_CHANGES_BEFORE_PURGE) { - purge(); - changeCount = 0; - } - // do a partial purge more often - else if ((changeCount % PARTIAL_PURGE_COUNT) == 0) { - purgeOne(); - } - - Object result = null; - Referenced keyRef = new Referenced(key, queue); - return super.put(keyRef, value); - } - - /** - *@see Hashtable - */ - public void putAll(Map t) { - if (t != null) { - Set entrySet = t.entrySet(); - for (Iterator it=entrySet.iterator(); it.hasNext();) { - Map.Entry entry = (Map.Entry) it.next(); - put(entry.getKey(), entry.getValue()); - } - } - } - - /** - *@see Hashtable - */ - public Collection values() { - purge(); - return super.values(); - } - - /** - *@see Hashtable - */ - public Object remove(Object key) { - // for performance reasons, only purge every - // MAX_CHANGES_BEFORE_PURGE times - if (changeCount++ > MAX_CHANGES_BEFORE_PURGE) { - purge(); - changeCount = 0; - } - // do a partial purge more often - else if ((changeCount % PARTIAL_PURGE_COUNT) == 0) { - purgeOne(); - } - return super.remove(new Referenced(key)); - } - - /** - *@see Hashtable - */ - public boolean isEmpty() { - purge(); - return super.isEmpty(); - } - - /** - *@see Hashtable - */ - public int size() { - purge(); - return super.size(); - } - - /** - *@see Hashtable - */ - public String toString() { - purge(); - return super.toString(); - } - - /** - * @see Hashtable - */ - protected void rehash() { - // purge here to save the effort of rehashing dead entries - purge(); - super.rehash(); - } - - /** - * Purges all entries whose wrapped keys - * have been garbage collected. - */ - private void purge() { - synchronized (queue) { - WeakKey key; - while ((key = (WeakKey) queue.poll()) != null) { - super.remove(key.getReferenced()); - } - } - } - - /** - * Purges one entry whose wrapped key - * has been garbage collected. - */ - private void purgeOne() { - - synchronized (queue) { - WeakKey key = (WeakKey) queue.poll(); - if (key != null) { - super.remove(key.getReferenced()); - } - } - } - - /** Entry implementation */ - private final static class Entry implements Map.Entry { - - private final Object key; - private final Object value; - - private Entry(Object key, Object value) { - this.key = key; - this.value = value; - } - - public boolean equals(Object o) { - boolean result = false; - if (o != null && o instanceof Map.Entry) { - Map.Entry entry = (Map.Entry) o; - result = (getKey()==null ? - entry.getKey() == null : - getKey().equals(entry.getKey())) - && - (getValue()==null ? - entry.getValue() == null : - getValue().equals(entry.getValue())); - } - return result; - } - - public int hashCode() { - - return (getKey()==null ? 0 : getKey().hashCode()) ^ - (getValue()==null ? 0 : getValue().hashCode()); - } - - public Object setValue(Object value) { - throw new UnsupportedOperationException("Entry.setValue is not supported."); - } - - public Object getValue() { - return value; - } - - public Object getKey() { - return key; - } - } - - - /** Wrapper giving correct symantics for equals and hashcode */ - private final static class Referenced { - - private final WeakReference reference; - private final int hashCode; - - /** - * - * @throws NullPointerException if referant is <code>null</code> - */ - private Referenced(Object referant) { - reference = new WeakReference(referant); - // Calc a permanent hashCode so calls to Hashtable.remove() - // work if the WeakReference has been cleared - hashCode = referant.hashCode(); - } - - /** - * - * @throws NullPointerException if key is <code>null</code> - */ - private Referenced(Object key, ReferenceQueue queue) { - reference = new WeakKey(key, queue, this); - // Calc a permanent hashCode so calls to Hashtable.remove() - // work if the WeakReference has been cleared - hashCode = key.hashCode(); - - } - - public int hashCode() { - return hashCode; - } - - private Object getValue() { - return reference.get(); - } - - public boolean equals(Object o) { - boolean result = false; - if (o instanceof Referenced) { - Referenced otherKey = (Referenced) o; - Object thisKeyValue = getValue(); - Object otherKeyValue = otherKey.getValue(); - if (thisKeyValue == null) { - result = (otherKeyValue == null); - - // Since our hashcode was calculated from the original - // non-null referant, the above check breaks the - // hashcode/equals contract, as two cleared Referenced - // objects could test equal but have different hashcodes. - // We can reduce (not eliminate) the chance of this - // happening by comparing hashcodes. - if (result == true) { - result = (this.hashCode() == otherKey.hashCode()); - } - // In any case, as our c'tor does not allow null referants - // and Hashtable does not do equality checks between - // existing keys, normal hashtable operations should never - // result in an equals comparison between null referants - } - else - { - result = thisKeyValue.equals(otherKeyValue); - } - } - return result; - } - } - - /** - * WeakReference subclass that holds a hard reference to an - * associated <code>value</code> and also makes accessible - * the Referenced object holding it. - */ - private final static class WeakKey extends WeakReference { - - private final Referenced referenced; - - private WeakKey(Object key, - ReferenceQueue queue, - Referenced referenced) { - super(key, queue); - this.referenced = referenced; - } - - private Referenced getReferenced() { - return referenced; - } - } -} diff --git a/src/org/apache/commons/logging/impl/package.html b/src/org/apache/commons/logging/impl/package.html deleted file mode 100644 index eb26b76..0000000 --- a/src/org/apache/commons/logging/impl/package.html +++ /dev/null @@ -1,21 +0,0 @@ -<!-- - - Copyright 2001-2004 The Apache Software Foundation. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ---> - -<body> -<p>Concrete implementations of commons-logging wrapper APIs.</p> -</body> diff --git a/src/org/apache/commons/logging/package.html b/src/org/apache/commons/logging/package.html deleted file mode 100644 index cfde4f0..0000000 --- a/src/org/apache/commons/logging/package.html +++ /dev/null @@ -1,254 +0,0 @@ -<!-- - - Copyright 2001-2004 The Apache Software Foundation. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ---> - -<body> -<p>Simple wrapper API around multiple logging APIs.</p> - - -<h3>Overview</h3> - -<p>This package provides an API for logging in server-based applications that -can be used around a variety of different logging implementations, including -prebuilt support for the following:</p> -<ul> -<li><a href="http://logging.apache.org/log4j/">Log4J</a> (version 1.2 or later) - from Apache's Jakarta project. Each named <a href="Log.html">Log</a> - instance is connected to a corresponding Log4J Logger.</li> -<li><a href="http://java.sun.com/j2se/1.4/docs/guide/util/logging/index.html"> - JDK Logging API</a>, included in JDK 1.4 or later systems. Each named - <a href="Log.html">Log</a> instance is connected to a corresponding - <code>java.util.logging.Logger</code> instance.</li> -<li><a href="http://avalon.apache.org/logkit/">LogKit</a> from Apache's - Avalon project. Each named <a href="Log.html">Log</a> instance is - connected to a corresponding LogKit <code>Logger</code>.</li> -<li><a href="impl/NoOpLog.html">NoOpLog</a> implementation that simply swallows - all log output, for all named <a href="Log.html">Log</a> instances.</li> -<li><a href="impl/SimpleLog.html">SimpleLog</a> implementation that writes all - log output, for all named <a href="Log.html">Log</a> instances, to - System.err.</li> -</ul> - - -<h3>Quick Start Guide</h3> - -<p>For those impatient to just get on with it, the following example -illustrates the typical declaration and use of a logger that is named (by -convention) after the calling class: - -<pre> - import org.apache.commons.logging.Log; - import org.apache.commons.logging.LogFactory; - - public class Foo { - - private Log log = LogFactory.getLog(Foo.class); - - public void foo() { - ... - try { - if (log.isDebugEnabled()) { - log.debug("About to do something to object " + name); - } - name.bar(); - } catch (IllegalStateException e) { - log.error("Something bad happened to " + name, e); - } - ... - } -</pre> - -<p>Unless you configure things differently, all log output will be written -to System.err. Therefore, you really will want to review the remainder of -this page in order to understand how to configure logging for your -application.</p> - - -<h3>Configuring the Commons Logging Package</h3> - - -<h4>Choosing a <code>LogFactory</code> Implementation</h4> - -<p>From an application perspective, the first requirement is to retrieve an -object reference to the <code>LogFactory</code> instance that will be used -to create <code><a href="Log.html">Log</a></code> instances for this -application. This is normally accomplished by calling the static -<code>getFactory()</code> method. This method implements the following -discovery algorithm to select the name of the <code>LogFactory</code> -implementation class this application wants to use:</p> -<ul> -<li>Check for a system property named - <code>org.apache.commons.logging.LogFactory</code>.</li> -<li>Use the JDK 1.3 JAR Services Discovery mechanism (see - <a href="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html"> - http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html</a> for - more information) to look for a resource named - <code>META-INF/services/org.apache.commons.logging.LogFactory</code> - whose first line is assumed to contain the desired class name.</li> -<li>Look for a properties file named <code>commons-logging.properties</code> - visible in the application class path, with a property named - <code>org.apache.commons.logging.LogFactory</code> defining the - desired implementation class name.</li> -<li>Fall back to a default implementation, which is described - further below.</li> -</ul> - -<p>If a <code>commons-logging.properties</code> file is found, all of the -properties defined there are also used to set configuration attributes on -the instantiated <code>LogFactory</code> instance.</p> - -<p>Once an implementation class name is selected, the corresponding class is -loaded from the current Thread context class loader (if there is one), or -from the class loader that loaded the <code>LogFactory</code> class itself -otherwise. This allows a copy of <code>commons-logging.jar</code> to be -shared in a multiple class loader environment (such as a servlet container), -but still allow each web application to provide its own <code>LogFactory</code> -implementation, if it so desires. An instance of this class will then be -created, and cached per class loader. - - -<h4>The Default <code>LogFactory</code> Implementation</h4> - -<p>The Logging Package APIs include a default <code>LogFactory</code> -implementation class (<a href="impl/LogFactoryImpl.html"> -org.apache.commons.logging.impl.LogFactoryImpl</a>) that is selected if no -other implementation class name can be discovered. Its primary purpose is -to create (as necessary) and return <a href="Log.html">Log</a> instances -in response to calls to the <code>getInstance()</code> method. The default -implementation uses the following rules:</p> -<ul> -<li>At most one <code>Log</code> instance of the same name will be created. - Subsequent <code>getInstance()</code> calls to the same - <code>LogFactory</code> instance, with the same name or <code>Class</code> - parameter, will return the same <code>Log</code> instance.</li> -<li>When a new <code>Log</code> instance must be created, the default - <code>LogFactory</code> implementation uses the following discovery - process: - <ul> - <li>Look for a configuration attribute of this factory named - <code>org.apache.commons.logging.Log</code> (for backwards - compatibility to pre-1.0 versions of this API, an attribute - <code>org.apache.commons.logging.log</code> is also consulted).</li> - <li>Look for a system property named - <code>org.apache.commons.logging.Log</code> (for backwards - compatibility to pre-1.0 versions of this API, a system property - <code>org.apache.commons.logging.log</code> is also consulted).</li> - <li>If the Log4J logging system is available in the application - class path, use the corresponding wrapper class - (<a href="impl/Log4JLogger.html">Log4JLogger</a>).</li> - <li>If the application is executing on a JDK 1.4 system, use - the corresponding wrapper class - (<a href="impl/Jdk14Logger.html">Jdk14Logger</a>).</li> - <li>Fall back to the default simple logging implementation - (<a href="impl/SimpleLog.html">SimpleLog</a>).</li> - </ul></li> -<li>Load the class of the specified name from the thread context class - loader (if any), or from the class loader that loaded the - <code>LogFactory</code> class otherwise.</li> -<li>Instantiate an instance of the selected <code>Log</code> - implementation class, passing the specified name as the single - argument to its constructor.</li> -</ul> - -<p>See the <a href="impl/SimpleLog.html">SimpleLog</a> JavaDocs for detailed -configuration information for this default implementation.</p> - - -<h4>Configuring the Underlying Logging System</h4> - -<p>The basic principle is that the user is totally responsible for the -configuration of the underlying logging system. -Commons-logging should not change the existing configuration.</p> - -<p>Each individual <a href="Log.html">Log</a> implementation may -support its own configuration properties. These will be documented in the -class descriptions for the corresponding implementation class.</p> - -<p>Finally, some <code>Log</code> implementations (such as the one for Log4J) -require an external configuration file for the entire logging environment. -This file should be prepared in a manner that is specific to the actual logging -technology being used.</p> - - -<h3>Using the Logging Package APIs</h3> - -<p>Use of the Logging Package APIs, from the perspective of an application -component, consists of the following steps:</p> -<ol> -<li>Acquire a reference to an instance of - <a href="Log.html">org.apache.commons.logging.Log</a>, by calling the - factory method - <a href="LogFactory.html#getInstance(java.lang.String)"> - LogFactory.getInstance(String name)</a>. Your application can contain - references to multiple loggers that are used for different - purposes. A typical scenario for a server application is to have each - major component of the server use its own Log instance.</li> -<li>Cause messages to be logged (if the corresponding detail level is enabled) - by calling appropriate methods (<code>trace()</code>, <code>debug()</code>, - <code>info()</code>, <code>warn()</code>, <code>error</code>, and - <code>fatal()</code>).</li> -</ol> - -<p>For convenience, <code>LogFactory</code> also offers a static method -<code>getLog()</code> that combines the typical two-step pattern:</p> -<pre> - Log log = LogFactory.getFactory().getInstance(Foo.class); -</pre> -<p>into a single method call:</p> -<pre> - Log log = LogFactory.getLog(Foo.class); -</pre> - -<p>For example, you might use the following technique to initialize and -use a <a href="Log.html">Log</a> instance in an application component:</p> -<pre> -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -public class MyComponent { - - protected Log log = - LogFactory.getLog(MyComponent.class); - - // Called once at startup time - public void start() { - ... - log.info("MyComponent started"); - ... - } - - // Called once at shutdown time - public void stop() { - ... - log.info("MyComponent stopped"); - ... - } - - // Called repeatedly to process a particular argument value - // which you want logged if debugging is enabled - public void process(String value) { - ... - // Do the string concatenation only if logging is enabled - if (log.isDebugEnabled()) - log.debug("MyComponent processing " + value); - ... - } - -} -</pre> - -</body> |