Author: akarasulu Date: Mon Jul 5 20:42:13 2004 New Revision: 22607 Added: incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/EncoderCallback.java (contents, props changed) incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/EncoderMonitor.java (contents, props changed) incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/EncoderMonitorAdapter.java (contents, props changed) incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/StatefulEncoder.java (contents, props changed) incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/examples/ incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/examples/HexDecoder.java (contents, props changed) incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/examples/HexEncoder.java (contents, props changed) incubator/directory/snickers/trunk/codec-stateful/src/test/org/apache/commons/codec/stateful/examples/ incubator/directory/snickers/trunk/codec-stateful/src/test/org/apache/commons/codec/stateful/examples/HexDecoderTest.java (contents, props changed) incubator/directory/snickers/trunk/codec-stateful/src/test/org/apache/commons/codec/stateful/examples/HexEncoderTest.java (contents, props changed) Modified: incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/CallbackHistory.java Log: Commit changes ...
o created symetric encoder analogs for decoder entities o created an example encoder/decoder pair for a streaming Hex codec o added test cases for example Modified: incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/CallbackHistory.java ============================================================================== --- incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/CallbackHistory.java (original) +++ incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/CallbackHistory.java Mon Jul 5 20:42:13 2004 @@ -21,16 +21,16 @@ /** - * A convenience callback which collects decoded objects to audit a decoder's - * activity. The callback also comes in handy when data is to be pushed - * through a decoder and grabed immediately afterwords to serialize decoder + * A convenience callback which collects decoded or encoded objects to audit a + * codecs's activity. The callback also comes in handy when data is to be + * pushed through a codec and grabed immediately afterwords to serialize codec * operation. * * @author <a href="mailto:[EMAIL PROTECTED]"> * Apache Directory Project</a> * @version $Rev$ */ -public class CallbackHistory implements DecoderCallback +public class CallbackHistory implements DecoderCallback, EncoderCallback { /** history of decoded objects in cronological order */ private final LinkedList history ; @@ -79,8 +79,28 @@ history.addFirst( decoded ) ; } - - + + + /** + * Callback to deliver a fully encoded object. + * + * @param encoder the stateful encoder driving the callback + * @param encoded the object that was encoded + */ + public void encodeOccurred( StatefulEncoder encoder, Object encoded ) + { + if ( length > 0 ) + { + while ( history.size() >= length ) + { + history.removeLast() ; + } + } + + history.addFirst( encoded ) ; + } + + /** * Gets the most recent decoded object if one exists. * Added: incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/EncoderCallback.java ============================================================================== --- (empty file) +++ incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/EncoderCallback.java Mon Jul 5 20:42:13 2004 @@ -0,0 +1,34 @@ +/* + * 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.codec.stateful; + +/** + * Document me. + * + * @author <a href="mailto:[EMAIL PROTECTED]"> Apache Directory + * Project</a> $Rev$ + */ +public interface EncoderCallback +{ + /** + * Callback to deliver a fully encoded object. + * + * @param encoder the stateful encoder driving the callback + * @param encoded the object that was encoded + */ + void encodeOccurred( StatefulEncoder encoder, Object encoded ) ; +} Added: incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/EncoderMonitor.java ============================================================================== --- (empty file) +++ incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/EncoderMonitor.java Mon Jul 5 20:42:13 2004 @@ -0,0 +1,78 @@ +/* + * 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.codec.stateful; + +/** + * Document me. + * + * @author <a href="mailto:[EMAIL PROTECTED]"> Apache Directory + * Project</a> $Rev$ + */ +public interface EncoderMonitor +{ + /** + * Receive notification of a recoverable error. This callback is used to + * denote a failure to handle a unit of data to be encoded or decoded. The + * entire [en|de]codable unit is lost but the [en|de]coding operation can + * still proceed. + * + * @param encoder the encoder that had the error + * @param exception the error information encapsulated in an exception + */ + void error( StatefulEncoder encoder, Exception exception ) ; + + /** + * Receive notification of a non-recoverable error. The application must + * assume that the stream data is unusable after the encoder has invoked + * this method, and should continue (if at all) only for the sake of + * collecting addition error messages: in fact, encoders are free to stop + * reporting any other events once this method has been invoked. + * + * @param encoder the encoder that had the failure + * @param exception the warning information encapsulated in an exception + */ + void fatalError( StatefulEncoder encoder, Exception exception ) ; + + /** + * Receive notification of a warning. The encoder must continue to provide + * normal callbacks after invoking this method: it should still be possible + * for the application to process the encoded data through to the end. + * + * @param encoder the encoder that had the error + * @param exception the warning information encapsulated in an exception + */ + void warning( StatefulEncoder encoder, Exception exception ) ; + + /** + * Monitors callbacks that deliver a fully decoded object. + * + * @param encoder the stateful encoder driving the callback + * @param decoded the object that was decoded + */ + void callbackOccured( StatefulEncoder encoder, EncoderCallback cb, + Object decoded ) ; + + /** + * Monitors changes to the callback. + * + * @param encoder the encoder whose callback was set + * @param oldcb the unset old callback, or null if none was set + * @param newcb the newly set callback, or null if callback is cleared + */ + void callbackSet( StatefulEncoder encoder, EncoderCallback oldcb, + EncoderCallback newcb ) ; +} Added: incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/EncoderMonitorAdapter.java ============================================================================== --- (empty file) +++ incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/EncoderMonitorAdapter.java Mon Jul 5 20:42:13 2004 @@ -0,0 +1,87 @@ +/* + * 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.codec.stateful; + + +/** + * Document me. + * + * @author <a href="mailto:[EMAIL PROTECTED]"> Apache Directory + * Project</a> $Rev$ + */ +public class EncoderMonitorAdapter implements EncoderMonitor +{ + /** + * Receive notification of a recoverable error. This callback is used to + * denote a failure to handle a unit of data to be encoded or decoded. The + * entire [en|de]codable unit is lost but the [en|de]coding operation can + * still proceed. + * + * @param encoder the encoder that had the error + * @param exception the error information encapsulated in an exception + */ + public void error( StatefulEncoder encoder, Exception exception ) + { + } + + /** + * Receive notification of a non-recoverable error. The application must + * assume that the stream data is unusable after the encoder has invoked + * this method, and should continue (if at all) only for the sake of + * collecting addition error messages: in fact, encoders are free to stop + * reporting any other events once this method has been invoked. + * + * @param encoder the encoder that had the failure + * @param exception the warning information encapsulated in an exception + */ + public void fatalError( StatefulEncoder encoder, Exception exception ) + { + } + + /** + * Receive notification of a warning. The encoder must continue to provide + * normal callbacks after invoking this method: it should still be possible + * for the application to process the encoded data through to the end. + * + * @param encoder the encoder that had the error + * @param exception the warning information encapsulated in an exception + */ + public void warning( StatefulEncoder encoder, Exception exception ) + { + } + + /** + * Monitors callbacks that deliver a fully decoded object. + * + * @param encoder the stateful encoder driving the callback + * @param decoded the object that was decoded + */ + public void callbackOccured( StatefulEncoder encoder, EncoderCallback cb, Object decoded ) + { + } + + /** + * Monitors changes to the callback. + * + * @param encoder the encoder whose callback was set + * @param oldcb the unset old callback, or null if none was set + * @param newcb the newly set callback, or null if callback is cleared + */ + public void callbackSet( StatefulEncoder encoder, EncoderCallback oldcb, EncoderCallback newcb ) + { + } +} Added: incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/StatefulEncoder.java ============================================================================== --- (empty file) +++ incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/StatefulEncoder.java Mon Jul 5 20:42:13 2004 @@ -0,0 +1,39 @@ +/* + * 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.codec.stateful ; + + +import org.apache.commons.codec.EncoderException ; + + +/** + * The StatefulEncoder interface. + * + * @author <a href="mailto:[EMAIL PROTECTED]"> Apache Directory + * Project</a> $Rev$ + */ +public interface StatefulEncoder +{ + public void encode( Object obj ) throws EncoderException ; + + + public void setCallback( EncoderCallback cb ) ; + + + public void setEncoderMonitor( EncoderMonitor monitor ) ; + +} Added: incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/examples/HexDecoder.java ============================================================================== --- (empty file) +++ incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/examples/HexDecoder.java Mon Jul 5 20:42:13 2004 @@ -0,0 +1,140 @@ +/* + * 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.codec.stateful.examples; + +import org.apache.commons.codec.stateful.AbstractStatefulDecoder; +import org.apache.commons.codec.DecoderException; + +import java.nio.ByteBuffer; + +/** + * Document me. + * + * @author <a href="mailto:[EMAIL PROTECTED]"> Apache Directory + * Project</a> $Rev$ + */ +public class HexDecoder extends AbstractStatefulDecoder +{ + private ByteBuffer decoded = ByteBuffer.allocate( 128 ) ; + private byte lsn ; + private byte msn ; + private boolean expectingMsn = true ; + + + public void decode( Object chunk ) throws DecoderException + { + ByteBuffer encoded = ( ByteBuffer ) chunk; + + if ( encoded == null || !encoded.hasRemaining() ) + { + return; + } + + while ( encoded.hasRemaining() ) + { + if ( ! decoded.hasRemaining() ) + { + decoded.flip(); + super.decodeOccurred( decoded ); + decoded.clear(); + } + + if ( expectingMsn ) + { + msn = encoded.get(); + expectingMsn = false; + } + else + { + lsn = encoded.get(); + expectingMsn = true; + } + + /* if we've hit the most significant nibble then we have two hex + * characters as bytes so we need to compute and add the byte to + * the buffer + */ + if ( expectingMsn ) + { + byte bite = getNibble( lsn ); + bite |= ( getNibble( msn ) << 4 ); + decoded.put( bite ); + } + } + + /* only trigger a decode callback if we have seen an even number of + * hex character bytes in which case we're in the expectingMsn state + * this will flush out what's siting in the buffer automatically + */ + if ( expectingMsn ) + { + decoded.flip(); + super.decodeOccurred( decoded ); + decoded.clear(); + } + } + + + + private byte getNibble( byte ch ) throws DecoderException + { + // lowercase the character if it is in upper case + if ( ch > 64 && ch < 91 ) + { + ch -= 32; + } + + switch(ch) + { + case 48: + return 0 ; + case 49: + return 1 ; + case 50: + return 2 ; + case 51: + return 3 ; + case 52: + return 4 ; + case 53: + return 5 ; + case 54: + return 6 ; + case 55: + return 7 ; + case 56: + return 8 ; + case 57: + return 9 ; + case 97: + return 10 ; + case 98: + return 11 ; + case 99: + return 12 ; + case 100: + return 13 ; + case 101: + return 14 ; + case 102: + return 15 ; + default: + throw new DecoderException( "non-hex character '" + (char) ch + + "' encountered" ); + } + } +} Added: incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/examples/HexEncoder.java ============================================================================== --- (empty file) +++ incubator/directory/snickers/trunk/codec-stateful/src/java/org/apache/commons/codec/stateful/examples/HexEncoder.java Mon Jul 5 20:42:13 2004 @@ -0,0 +1,105 @@ +/* + * 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.codec.stateful.examples; + +import org.apache.commons.codec.stateful.StatefulEncoder; +import org.apache.commons.codec.stateful.EncoderCallback; +import org.apache.commons.codec.stateful.EncoderMonitor; +import org.apache.commons.codec.stateful.EncoderMonitorAdapter; +import org.apache.commons.codec.EncoderException; + +import java.nio.ByteBuffer; + + +/** + * Document me. + * + * @author <a href="mailto:[EMAIL PROTECTED]"> Apache Directory + * Project</a> $Rev$ + */ +public class HexEncoder implements StatefulEncoder +{ + private static final int CHUNK_SZ = 128; + private ByteBuffer buf = ByteBuffer.allocate( CHUNK_SZ ); + private EncoderMonitor monitor = new EncoderMonitorAdapter(); + private EncoderCallback cb = new EncoderCallback() { + public void encodeOccurred( StatefulEncoder encoder, Object encoded ) + { + } + }; + private final byte[] HEXCHAR_LUT = { + (byte)'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f' + }; + + + /** + * Transforms a decoded ByteArray of binary data into a stream of ASCII hex + * characters. + * + * @param obj + * @throws EncoderException + */ + public void encode( Object obj ) throws EncoderException + { + ByteBuffer raw = ( ByteBuffer ) obj; + + if ( raw == null || ! raw.hasRemaining() ) + { + return; + } + + /* + * Keep encoding one byte at a time if we have remaining bytes in the + * raw buffer and there's space for 2 hex character bytes in the + * resultant hex encoded buffer. + */ + while( raw.hasRemaining() ) + { + if ( ! buf.hasRemaining() ) + { + buf.flip(); + cb.encodeOccurred( this, buf ); + monitor.callbackOccured( this, cb, buf ); + buf.clear(); + } + + byte bite = raw.get(); + buf.put( HEXCHAR_LUT[( bite >> 4 ) & 0x0000000F] ); + buf.put( HEXCHAR_LUT[bite & 0x0000000F] ); + } + + buf.flip(); + cb.encodeOccurred( this, buf ); + monitor.callbackOccured( this, cb, buf ); + buf.clear(); + } + + + public void setCallback( EncoderCallback cb ) + { + EncoderCallback old = this.cb; + this.cb = cb; + monitor.callbackSet( this, old, cb ); + } + + + public void setEncoderMonitor( EncoderMonitor monitor ) + { + this.monitor = monitor; + } +} Added: incubator/directory/snickers/trunk/codec-stateful/src/test/org/apache/commons/codec/stateful/examples/HexDecoderTest.java ============================================================================== --- (empty file) +++ incubator/directory/snickers/trunk/codec-stateful/src/test/org/apache/commons/codec/stateful/examples/HexDecoderTest.java Mon Jul 5 20:42:13 2004 @@ -0,0 +1,220 @@ +/* + * 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.codec.stateful.examples; + +import junit.framework.TestCase; + +import java.util.Random; +import java.nio.ByteBuffer; + +import org.apache.commons.codec.binary.Hex; +import org.apache.commons.codec.stateful.DecoderCallback; +import org.apache.commons.codec.stateful.StatefulDecoder; +import org.apache.commons.codec.DecoderException; + +/** + * Document me. + * + * @author <a href="mailto:[EMAIL PROTECTED]"> Apache Directory + * Project</a> $Rev$ + */ +public class HexDecoderTest extends TestCase implements DecoderCallback +{ + private HexDecoder decoder = null; + byte[] encoded = null; + byte[] decoded = null; + byte[] original = null; + + + protected void setUp() throws Exception + { + super.setUp(); + decoder = new HexDecoder(); + decoder.setCallback( this ); + } + + + protected void tearDown() throws Exception + { + super.tearDown(); + decoder = null; + encoded = null; + decoded = null; + original = null; + } + + + private void generateData( int amount ) + { + Random rand = new Random( System.currentTimeMillis() ) ; + original = new byte[amount/2]; + rand.nextBytes( original ); + char[] chars = Hex.encodeHex( original ); + encoded = new byte[amount]; + for ( int ii = 0; ii < amount; ii++ ) + { + encoded[ii] = (byte) chars[ii]; + } + } + + + public void decodeOccurred( StatefulDecoder decoder, Object obj ) + { + ByteBuffer decodedBuf = ( ByteBuffer ) obj ; + + if ( decoded == null ) + { + decoded = new byte[decodedBuf.remaining()]; + decodedBuf.get( decoded ) ; + } + else + { + byte[] temp = decoded ; + decoded = new byte[decodedBuf.remaining() + temp.length]; + System.arraycopy( temp, 0, decoded, 0, temp.length ); + decodedBuf.get( decoded, temp.length, decodedBuf.remaining() ); + } + } + + + public void testDecode0() throws DecoderException + { + generateData( 0 ); + decoder.decode( ByteBuffer.wrap( encoded ) ); + + if ( decoded == null ) + { + decoded = new byte[0]; + } + + assertDecoded(); + } + + + public void testDecode2() throws DecoderException + { + generateData( 2 ); + decoder.decode( ByteBuffer.wrap( encoded ) ); + assertDecoded(); + } + + + public void testDecode26() throws DecoderException + { + generateData( 26 ); + decoder.decode( ByteBuffer.wrap( encoded ) ); + assertDecoded(); + } + + + public void testDecode254() throws DecoderException + { + generateData( 254 ); + decoder.decode( ByteBuffer.wrap( encoded ) ); + assertDecoded(); + } + + + public void testDecode256() throws DecoderException + { + generateData( 256 ); + decoder.decode( ByteBuffer.wrap( encoded ) ); + assertDecoded(); + } + + + public void testDecode258() throws DecoderException + { + generateData( 258 ); + decoder.decode( ByteBuffer.wrap( encoded ) ); + assertDecoded(); + } + + + public void testDecode2048() throws DecoderException + { + generateData( 2048 ); + decoder.decode( ByteBuffer.wrap( encoded ) ); + assertDecoded(); + } + + + public void testPartialDecode2() throws DecoderException + { + generateData( 2 ); + + decoder.decode( ByteBuffer.wrap( encoded, 0, 1 ) ); + + try + { + assertDecoded(); + fail( "should not get here" ) ; + } + catch( NullPointerException e ) + { + } + + decoder.decode( ByteBuffer.wrap( encoded, 1, 1 ) ); + + assertDecoded(); + } + + + public void testPartialDecode30() throws DecoderException + { + generateData( 30 ); + + for ( int ii = 0; ii < 30; ii += 3 ) + { + decoder.decode( ByteBuffer.wrap( encoded, ii, 3 ) ); + } + + assertDecoded(); + } + + + public void testPartialDecode300() throws DecoderException + { + generateData( 300 ); + + for ( int ii = 0; ii < 300; ii += 5 ) + { + decoder.decode( ByteBuffer.wrap( encoded, ii, 5 ) ); + } + + assertDecoded(); + } + + + private void assertDecoded() + { + if ( decoded.length != original.length ) + { + fail( "decoded length of " + decoded.length + + " did not match expected original data length of " + + original.length ) ; + } + + for ( int ii = 0; ii < decoded.length; ii++ ) + { + if ( decoded[ii] != original[ii] ) + { + fail( "decode failed - decoded array does not match" ) ; + } + } + } +} Added: incubator/directory/snickers/trunk/codec-stateful/src/test/org/apache/commons/codec/stateful/examples/HexEncoderTest.java ============================================================================== --- (empty file) +++ incubator/directory/snickers/trunk/codec-stateful/src/test/org/apache/commons/codec/stateful/examples/HexEncoderTest.java Mon Jul 5 20:42:13 2004 @@ -0,0 +1,170 @@ +/* + * 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.codec.stateful.examples; + +import junit.framework.TestCase; +import org.apache.commons.codec.EncoderException; +import org.apache.commons.codec.binary.Hex; +import org.apache.commons.codec.stateful.EncoderCallback; +import org.apache.commons.codec.stateful.StatefulEncoder; + +import java.util.Random; +import java.nio.ByteBuffer; + +/** + * Document me. + * + * @author <a href="mailto:[EMAIL PROTECTED]"> Apache Directory + * Project</a> $Rev$ + */ +public class HexEncoderTest extends TestCase implements EncoderCallback +{ + HexEncoder encoder = null; + byte[] encoded = null; + byte[] data = null; + + + protected void setUp() throws Exception + { + super.setUp(); + encoder = new HexEncoder(); + encoder.setCallback( this ); + } + + + protected void tearDown() throws Exception + { + super.tearDown(); + data = null; + encoder = null; + encoded = null; + } + + + private void generateData( int amount ) + { + Random rand = new Random(System.currentTimeMillis()) ; + data = new byte[amount]; + rand.nextBytes( data ); + } + + + public void encodeOccurred( StatefulEncoder encoder, Object encodedObj ) + { + ByteBuffer encodedBuf = ( ByteBuffer ) encodedObj ; + + if ( encoded == null ) + { + encoded = new byte[encodedBuf.remaining()]; + encodedBuf.get( encoded ) ; + } + else + { + byte[] temp = encoded ; + encoded = new byte[encodedBuf.remaining() + temp.length]; + System.arraycopy( temp, 0, encoded, 0, temp.length ); + encodedBuf.get( encoded, temp.length, encodedBuf.remaining() ); + } + } + + + public void testEncode0() throws EncoderException + { + generateData( 0 ); + encoder.encode( ByteBuffer.wrap( data ) ); + if ( encoded == null ) + { + encoded = new byte[0]; + } + assertEncoded( encoded, Hex.encodeHex( data ) ); + } + + + public void testEncode1() throws EncoderException + { + generateData( 1 ); + encoder.encode( ByteBuffer.wrap( data ) ); + assertEncoded( encoded, Hex.encodeHex( data ) ); + } + + + public void testEncode25() throws EncoderException + { + generateData( 25 ); + encoder.encode( ByteBuffer.wrap( data ) ); + assertEncoded( encoded, Hex.encodeHex( data ) ); + } + + + public void testEncode63() throws EncoderException + { + generateData( 63 ); + encoder.encode( ByteBuffer.wrap( data ) ); + assertEncoded( encoded, Hex.encodeHex( data ) ); + } + + + public void testEncode64() throws EncoderException + { + generateData( 64 ); + encoder.encode( ByteBuffer.wrap( data ) ); + assertEncoded( encoded, Hex.encodeHex( data ) ); + } + + + public void testEncode65() throws EncoderException + { + generateData( 65 ); + encoder.encode( ByteBuffer.wrap( data ) ); + assertEncoded( encoded, Hex.encodeHex( data ) ); + } + + + public void testEncode66() throws EncoderException + { + generateData( 66 ); + encoder.encode( ByteBuffer.wrap( data ) ); + assertEncoded( encoded, Hex.encodeHex( data ) ); + } + + + public void testEncode512() throws EncoderException + { + generateData( 512 ); + encoder.encode( ByteBuffer.wrap( data ) ); + assertEncoded( encoded, Hex.encodeHex( data ) ); + } + + + private void assertEncoded( byte[] encoded, char[] hex ) + { + if ( encoded.length != hex.length ) + { + fail( "encoded length of " + encoded.length + + " did not match expected hex char length of " + + hex.length ) ; + } + + for ( int ii = 0; ii < encoded.length; ii++ ) + { + if ( encoded[ii] != hex[ii] ) + { + fail( "encoding failed - encoded array does not match" ) ; + } + } + } +}
