blob: e4c1a11afc4f6865862a9c8958732b530a4bd15f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.directory.server.core.avltree;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Comparator;
import org.apache.directory.api.util.Strings;
import org.apache.directory.server.i18n.I18n;
/**
* Class to serialize the Array data.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
@SuppressWarnings("unchecked")
public class ArrayMarshaller<E> implements Marshaller<ArrayTree<E>>
{
/** used for serialized form of an empty AvlTree */
private static final byte[] EMPTY_TREE = new byte[1];
/** marshaller to be used for marshalling the keys */
private Marshaller<E> keyMarshaller;
/** key Comparator for the AvlTree */
private Comparator<E> comparator;
/**
* Creates a new instance of AvlTreeMarshaller with a custom key
* Marshaller.
*
* @param comparator Comparator to be used for key comparision
* @param keyMarshaller marshaller for keys
*/
public ArrayMarshaller( Comparator<E> comparator, Marshaller<E> keyMarshaller )
{
this.comparator = comparator;
this.keyMarshaller = keyMarshaller;
}
/**
* Creates a new instance of AvlTreeMarshaller with the default key
* Marshaller which uses Java Serialization.
*
* @param comparator Comparator to be used for key comparision
*/
public ArrayMarshaller( Comparator<E> comparator )
{
this.comparator = comparator;
this.keyMarshaller = ( Marshaller<E> ) DefaultMarshaller.INSTANCE;
}
/**
* Marshals the given tree to bytes
* @param tree the tree to be marshalled
*/
public byte[] serialize( ArrayTree<E> tree )
{
if ( ( tree == null ) || ( tree.size() == 0 ) )
{
return EMPTY_TREE;
}
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream( byteStream );
byte[] data = null;
try
{
out.writeByte( 0 ); // represents the start of an Array byte stream
out.writeInt( tree.size() );
for ( int position = 0; position < tree.size(); position++ )
{
E value = tree.get( position );
byte[] bytes = keyMarshaller.serialize( value );
// Write the key length
out.writeInt( bytes.length );
// Write the key if its length is not null
if ( bytes.length != 0 )
{
out.write( bytes );
}
}
out.flush();
data = byteStream.toByteArray();
// Try to deserialize, just to see
/*
try
{
deserialize( data );
}
catch ( NullPointerException npe )
{
System.out.println( I18n.err( I18n.ERR_438, Strings.dumpBytes( data ) ) );
throw npe;
}
*/
out.close();
}
catch ( IOException e )
{
e.printStackTrace();
}
return data;
}
/**
* Creates an Array from given bytes of data.
*
* @param data byte array to be converted into an array
*/
public ArrayTree<E> deserialize( byte[] data ) throws IOException
{
//LOG.debug( "Deserializing the tree, called by {}", Reflection.getCallerClass( 2 ).getSimpleName() );
try
{
if ( ( data == null ) || ( data.length == 0 ) )
{
throw new IOException( I18n.err( I18n.ERR_439 ) );
}
if ( ( data.length == 1 ) && ( data[0] == 0 ) )
{
E[] array = ( E[] ) new Object[]
{};
ArrayTree<E> tree = new ArrayTree<E>( comparator, array );
return tree;
}
ByteArrayInputStream bin = new ByteArrayInputStream( data );
DataInputStream din = new DataInputStream( bin );
byte startByte = din.readByte();
if ( startByte != 0 )
{
throw new IOException( I18n.err( I18n.ERR_440 ) );
}
int size = din.readInt();
E[] nodes = ( E[] ) new Object[size];
for ( int i = 0; i < size; i++ )
{
// Read the object's size
int dataSize = din.readInt();
if ( dataSize != 0 )
{
byte[] bytes = new byte[dataSize];
din.readFully( bytes );
E key = keyMarshaller.deserialize( bytes );
nodes[i] = key;
}
}
ArrayTree<E> arrayTree = new ArrayTree<E>( comparator, nodes );
return arrayTree;
}
catch ( NullPointerException npe )
{
System.out.println( I18n.err( I18n.ERR_441, Strings.dumpBytes( data ) ) );
throw npe;
}
}
}