Author: akarasulu
Date: Tue Jul 13 23:50:25 2004
New Revision: 22902
Added:
incubator/directory/snickers/trunk/ber-codec/src/test/org/apache/snickers/ber/BEREncoderTest.java
Modified:
incubator/directory/snickers/trunk/ber-codec/src/java/org/apache/snickers/ber/BEREncoder.java
Log:
implemented encoder and test cases
Modified:
incubator/directory/snickers/trunk/ber-codec/src/java/org/apache/snickers/ber/BEREncoder.java
==============================================================================
---
incubator/directory/snickers/trunk/ber-codec/src/java/org/apache/snickers/ber/BEREncoder.java
(original)
+++
incubator/directory/snickers/trunk/ber-codec/src/java/org/apache/snickers/ber/BEREncoder.java
Tue Jul 13 23:50:25 2004
@@ -17,22 +17,153 @@
package org.apache.snickers.ber;
-import org.apache.commons.codec.EncoderException;
import org.apache.commons.codec.stateful.AbstractStatefulEncoder;
+import org.apache.commons.codec.stateful.StatefulEncoder;
+
+import java.nio.ByteBuffer;
/**
- * Document me.
+ * A BER TLV tuple encoder. This encoder receives events via some BEREncoder
+ *
*
* @author <a href="mailto:[EMAIL PROTECTED]"> Apache Directory
* Project</a> $Rev$
*/
public class BEREncoder extends AbstractStatefulEncoder
{
- public void encode( Object obj ) throws EncoderException
+ private static final int DEFAULT_BUFSZ = 32;
+ private ByteBuffer buf = null;
+ private BEREncoderCallback berCb;
+
+
+ /**
+ * Creates a BEREncoder with the default buffer size.
+ */
+ public BEREncoder()
+ {
+ this( DEFAULT_BUFSZ );
+ }
+
+
+ /**
+ * Creates a BEREncoder with a specific buffer size.
+ *
+ * @param bufSz the size of the buffer
+ */
+ public BEREncoder( int bufSz )
+ {
+ buf = ByteBuffer.allocateDirect( bufSz );
+ berCb = new Callback();
+ }
+
+
+ /**
+ * Overriden encode method which does nothing but throw an exception. This
+ * has been done to prevent interference with the stream of TLV events
+ * processed by this encoder. A special BEREncoderCallback implementation
+ * is used by this class to recieve events. This callback is not the same
+ * as the callback used to inform of encode events which emits ByteBuffer
+ * objects.
+ *
+ * @param obj the object to encode
+ * @throws UnsupportedOperationException every time
+ */
+ public void encode( Object obj )
+ {
+ throw new UnsupportedOperationException(
+ "This encoder receives tuples ONLY via callback methods" );
+ }
+
+
+ /**
+ * Gets the BEREncoderCallback used to send BER TLV Tuple events to this
+ * encoder. This is separate from the traditional encoder callback used
+ * to emit encode events.
+ *
+ * @return the encoder's BER TLV event callback
+ */
+ public BEREncoderCallback getBERCallback()
{
+ return berCb;
}
+ /**
+ * Specific callback interface used to send TLV tuple events to this
+ * encoder.
+ */
+ class Callback implements BEREncoderCallback
+ {
+ public void tagEncoded( Tuple tlv )
+ {
+ if ( buf.remaining() >= tlv.getTagLength() )
+ {
+ tlv.setTag( buf, tlv.getTagLength() );
+ }
+ else
+ {
+ buf.flip();
+ BEREncoder.this.encodeOccurred( buf );
+ buf.clear();
+ tlv.setTag( buf, tlv.getTagLength() );
+ }
+ }
+
+
+ public void lengthEncoded( Tuple tlv )
+ {
+ if ( buf.remaining() >= tlv.getLengthLength() )
+ {
+ tlv.setLength( buf, tlv.getLengthLength() );
+ }
+ else
+ {
+ buf.flip();
+ BEREncoder.this.encodeOccurred( buf );
+ buf.clear();
+ tlv.setLength( buf, tlv.getLengthLength() );
+ }
+ }
+
+
+ public void partialValueEncoded( Tuple tlv )
+ {
+ if ( buf.position() > 0 )
+ {
+ buf.flip();
+ BEREncoder.this.encodeOccurred( buf );
+ buf.clear();
+ }
+ BEREncoder.this.encodeOccurred( tlv.getLastValueChunk() );
+ }
+
+
+ public void encodeOccurred( StatefulEncoder encoder, Object encoded )
+ {
+ Tuple tlv = ( Tuple ) encoded;
+
+ if ( tlv.isPrimitive() )
+ {
+ return;
+ }
+
+ if ( tlv.isIndefinate() )
+ {
+ if ( buf.remaining() < 2 )
+ {
+ buf.flip();
+ BEREncoder.this.encodeOccurred( buf );
+ buf.clear();
+ }
+
+ buf.put( (byte) 0 );
+ buf.put( (byte) 0 );
+ buf.flip();
+ BEREncoder.this.encodeOccurred( buf );
+ buf.clear();
+ }
+ }
+ }
}
Added:
incubator/directory/snickers/trunk/ber-codec/src/test/org/apache/snickers/ber/BEREncoderTest.java
==============================================================================
--- (empty file)
+++
incubator/directory/snickers/trunk/ber-codec/src/test/org/apache/snickers/ber/BEREncoderTest.java
Tue Jul 13 23:50:25 2004
@@ -0,0 +1,128 @@
+/*
+ * 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.snickers.ber;
+
+
+import junit.framework.TestCase;
+import org.apache.snickers.ber.primitives.UniversalTag;
+import org.apache.commons.codec.stateful.EncoderCallback;
+import org.apache.commons.codec.stateful.StatefulEncoder;
+import org.apache.commons.lang.ArrayUtils;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+
+/**
+ * Tests the BEREncoder for correct operation.
+ *
+ * @author <a href="mailto:[EMAIL PROTECTED]"> Apache Directory
+ * Project</a> $Rev$
+ */
+public class BEREncoderTest extends TestCase implements EncoderCallback
+{
+ private BEREncoder encoder = null;
+ private ByteBuffer collector = null;
+
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ encoder = new BEREncoder();
+ encoder.setCallback( this );
+ collector = ByteBuffer.wrap( new byte[32] );
+ }
+
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ encoder.setCallback( null );
+ encoder = null;
+ collector = null;
+ }
+
+
+ public void encodeOccurred( StatefulEncoder encoder, Object encoded )
+ {
+ ByteBuffer buf = ( ByteBuffer ) encoded;
+ collector.put( buf );
+ }
+
+
+ public void testPrimitives()
+ {
+ Tuple tlv = new Tuple();
+ tlv.setTag( UniversalTag.INTEGER );
+ encoder.getBERCallback().tagEncoded( tlv );
+
+ tlv.setLength( 1 );
+ encoder.getBERCallback().lengthEncoded( tlv );
+
+ tlv.setLastValueChunk( ByteBuffer.wrap( new byte[] { (byte) 10 }) );
+ encoder.getBERCallback().partialValueEncoded( tlv );
+
+ ArrayList list = new ArrayList();
+ list.add( tlv.getLastValueChunk() );
+ ByteBuffer buf = tlv.toEncodedBuffer( list );
+
+ byte[] correctBytes = new byte[buf.remaining()];
+ buf.get( correctBytes );
+
+ byte[] encodedBytes = new byte[collector.remaining()];
+ collector.get( encodedBytes );
+
+ ArrayUtils.isEquals( correctBytes, encodedBytes );
+ }
+
+
+ public void testConstructedDefinateLength()
+ {
+ Tuple top = new Tuple();
+ top.setTag( UniversalTag.SEQUENCE_SEQUENCE_OF );
+ encoder.getBERCallback().tagEncoded( top );
+ top.setLength( 3 );
+ encoder.getBERCallback().lengthEncoded( top );
+
+ Tuple tlv = new Tuple();
+ tlv.setTag( UniversalTag.INTEGER );
+ encoder.getBERCallback().tagEncoded( tlv );
+
+ tlv.setLength( 1 );
+ encoder.getBERCallback().lengthEncoded( tlv );
+
+ tlv.setLastValueChunk( ByteBuffer.wrap( new byte[] { (byte) 10 }) );
+ encoder.getBERCallback().partialValueEncoded( tlv );
+
+ encoder.getBERCallback().encodeOccurred( encoder, top );
+
+ ArrayList list = new ArrayList();
+ ByteBuffer all = ByteBuffer.wrap( new byte[64] ) ;
+ all.put( top.toEncodedBuffer( list ) );
+
+ list.add( tlv.getLastValueChunk() );
+ all.put( tlv.toEncodedBuffer( list ) );
+
+ byte[] correctBytes = new byte[all.remaining()];
+ all.get( correctBytes );
+
+ byte[] encodedBytes = new byte[collector.remaining()];
+ collector.get( encodedBytes );
+
+ ArrayUtils.isEquals( correctBytes, encodedBytes );
+ }
+}