001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020 package org.apache.directory.server.core.avltree; 021 022 023 import java.io.ByteArrayInputStream; 024 import java.io.ByteArrayOutputStream; 025 import java.io.DataInputStream; 026 import java.io.DataOutputStream; 027 import java.io.IOException; 028 import java.util.Comparator; 029 030 import org.apache.directory.server.i18n.I18n; 031 import org.apache.directory.shared.ldap.util.StringTools; 032 import org.slf4j.Logger; 033 import org.slf4j.LoggerFactory; 034 035 036 /** 037 * Class to serialize the Array data. 038 * 039 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 040 * @version $Rev$, $Date$ 041 */ 042 @SuppressWarnings("unchecked") 043 public class ArrayMarshaller<E> implements Marshaller<ArrayTree<E>> 044 { 045 /** static logger */ 046 private static final Logger LOG = LoggerFactory.getLogger( ArrayMarshaller.class ); 047 048 /** used for serialized form of an empty AvlTree */ 049 private static final byte[] EMPTY_TREE = new byte[1]; 050 051 /** marshaller to be used for marshalling the keys */ 052 private Marshaller<E> keyMarshaller; 053 054 /** key Comparator for the AvlTree */ 055 private Comparator<E> comparator; 056 057 058 /** 059 * Creates a new instance of AvlTreeMarshaller with a custom key 060 * Marshaller. 061 * 062 * @param comparator Comparator to be used for key comparision 063 * @param keyMarshaller marshaller for keys 064 */ 065 public ArrayMarshaller( Comparator<E> comparator, Marshaller<E> keyMarshaller ) 066 { 067 this.comparator = comparator; 068 this.keyMarshaller = keyMarshaller; 069 } 070 071 072 /** 073 * Creates a new instance of AvlTreeMarshaller with the default key 074 * Marshaller which uses Java Serialization. 075 * 076 * @param comparator Comparator to be used for key comparision 077 */ 078 public ArrayMarshaller( Comparator<E> comparator ) 079 { 080 this.comparator = comparator; 081 this.keyMarshaller = ( Marshaller<E> ) DefaultMarshaller.INSTANCE; 082 } 083 084 085 /** 086 * Marshals the given tree to bytes 087 * @param tree the tree to be marshalled 088 */ 089 public byte[] serialize( ArrayTree<E> tree ) 090 { 091 if ( ( tree == null ) || ( tree.size() == 0 ) ) 092 { 093 return EMPTY_TREE; 094 } 095 096 ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); 097 DataOutputStream out = new DataOutputStream( byteStream ); 098 byte[] data = null; 099 100 try 101 { 102 out.writeByte( 0 ); // represents the start of an Array byte stream 103 out.writeInt( tree.size() ); 104 105 for ( int position = 0; position < tree.size(); position++ ) 106 { 107 E value = tree.get( position ); 108 byte[] bytes = keyMarshaller.serialize( value ); 109 110 // Write the key length 111 out.writeInt( bytes.length ); 112 113 // Write the key if its length is not null 114 if ( bytes.length != 0 ) 115 { 116 out.write( bytes ); 117 } 118 } 119 120 out.flush(); 121 data = byteStream.toByteArray(); 122 123 // Try to deserialize, just to see 124 try 125 { 126 deserialize( data ); 127 } 128 catch (NullPointerException npe ) 129 { 130 System.out.println( I18n.err( I18n.ERR_438, StringTools.dumpBytes( data ) ) ); 131 throw npe; 132 } 133 134 out.close(); 135 } 136 catch( IOException e ) 137 { 138 e.printStackTrace(); 139 } 140 141 return data; 142 } 143 144 145 /** 146 * Creates an Array from given bytes of data. 147 * 148 * @param data byte array to be converted into an array 149 */ 150 public ArrayTree<E> deserialize( byte[] data ) throws IOException 151 { 152 //LOG.debug( "Deserializing the tree, called by {}", Reflection.getCallerClass( 2 ).getSimpleName() ); 153 154 try 155 { 156 if ( ( data == null ) || ( data.length == 0 ) ) 157 { 158 throw new IOException( I18n.err( I18n.ERR_439 ) ); 159 } 160 161 if ( ( data.length == 1 ) && ( data[0] == 0 ) ) 162 { 163 E[] array = (E[])new Object[]{}; 164 ArrayTree<E> tree = new ArrayTree<E>( comparator, array ); 165 return tree; 166 } 167 168 ByteArrayInputStream bin = new ByteArrayInputStream( data ); 169 DataInputStream din = new DataInputStream( bin ); 170 171 byte startByte = din.readByte(); 172 173 if( startByte != 0 ) 174 { 175 throw new IOException( I18n.err( I18n.ERR_440 ) ); 176 } 177 178 int size = din.readInt(); 179 E[] nodes = (E[])new Object[size]; 180 181 for ( int i = 0; i < size; i++ ) 182 { 183 // Read the object's size 184 int dataSize = din.readInt(); 185 186 if ( dataSize != 0 ) 187 { 188 byte[] bytes = new byte[ dataSize ]; 189 190 din.read( bytes ); 191 E key = keyMarshaller.deserialize( bytes ); 192 nodes[i] = key; 193 } 194 } 195 196 ArrayTree<E> arrayTree = new ArrayTree<E>( comparator, nodes ); 197 198 return arrayTree; 199 } 200 catch (NullPointerException npe ) 201 { 202 System.out.println( I18n.err( I18n.ERR_441, StringTools.dumpBytes( data ) ) ); 203 throw npe; 204 } 205 } 206 }