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 */ 020package org.apache.directory.server.core.avltree; 021 022 023import java.io.ByteArrayInputStream; 024import java.io.ByteArrayOutputStream; 025import java.io.DataInputStream; 026import java.io.DataOutputStream; 027import java.io.IOException; 028import java.util.Comparator; 029 030import org.apache.directory.api.util.Strings; 031import org.apache.directory.server.i18n.I18n; 032 033 034/** 035 * Class to serialize the Array data. 036 * 037 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 038 */ 039@SuppressWarnings("unchecked") 040public class ArrayMarshaller<E> implements Marshaller<ArrayTree<E>> 041{ 042 /** used for serialized form of an empty AvlTree */ 043 private static final byte[] EMPTY_TREE = new byte[1]; 044 045 /** marshaller to be used for marshalling the keys */ 046 private Marshaller<E> keyMarshaller; 047 048 /** key Comparator for the AvlTree */ 049 private Comparator<E> comparator; 050 051 052 /** 053 * Creates a new instance of AvlTreeMarshaller with a custom key 054 * Marshaller. 055 * 056 * @param comparator Comparator to be used for key comparision 057 * @param keyMarshaller marshaller for keys 058 */ 059 public ArrayMarshaller( Comparator<E> comparator, Marshaller<E> keyMarshaller ) 060 { 061 this.comparator = comparator; 062 this.keyMarshaller = keyMarshaller; 063 } 064 065 066 /** 067 * Creates a new instance of AvlTreeMarshaller with the default key 068 * Marshaller which uses Java Serialization. 069 * 070 * @param comparator Comparator to be used for key comparision 071 */ 072 public ArrayMarshaller( Comparator<E> comparator ) 073 { 074 this.comparator = comparator; 075 this.keyMarshaller = ( Marshaller<E> ) DefaultMarshaller.INSTANCE; 076 } 077 078 079 /** 080 * Marshals the given tree to bytes 081 * @param tree the tree to be marshalled 082 */ 083 public byte[] serialize( ArrayTree<E> tree ) 084 { 085 if ( ( tree == null ) || ( tree.size() == 0 ) ) 086 { 087 return EMPTY_TREE; 088 } 089 090 ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); 091 DataOutputStream out = new DataOutputStream( byteStream ); 092 byte[] data = null; 093 094 try 095 { 096 out.writeByte( 0 ); // represents the start of an Array byte stream 097 out.writeInt( tree.size() ); 098 099 for ( int position = 0; position < tree.size(); position++ ) 100 { 101 E value = tree.get( position ); 102 byte[] bytes = keyMarshaller.serialize( value ); 103 104 // Write the key length 105 out.writeInt( bytes.length ); 106 107 // Write the key if its length is not null 108 if ( bytes.length != 0 ) 109 { 110 out.write( bytes ); 111 } 112 } 113 114 out.flush(); 115 data = byteStream.toByteArray(); 116 117 out.close(); 118 } 119 catch ( IOException e ) 120 { 121 e.printStackTrace(); 122 } 123 124 return data; 125 } 126 127 128 /** 129 * Creates an Array from given bytes of data. 130 * 131 * @param data byte array to be converted into an array 132 */ 133 public ArrayTree<E> deserialize( byte[] data ) throws IOException 134 { 135 try 136 { 137 if ( ( data == null ) || ( data.length == 0 ) ) 138 { 139 throw new IOException( I18n.err( I18n.ERR_439 ) ); 140 } 141 142 if ( ( data.length == 1 ) && ( data[0] == 0 ) ) 143 { 144 E[] array = ( E[] ) new Object[] 145 {}; 146 return new ArrayTree<>( comparator, array ); 147 } 148 149 ByteArrayInputStream bin = new ByteArrayInputStream( data ); 150 DataInputStream din = new DataInputStream( bin ); 151 152 byte startByte = din.readByte(); 153 154 if ( startByte != 0 ) 155 { 156 throw new IOException( I18n.err( I18n.ERR_440 ) ); 157 } 158 159 int size = din.readInt(); 160 E[] nodes = ( E[] ) new Object[size]; 161 162 for ( int i = 0; i < size; i++ ) 163 { 164 // Read the object's size 165 int dataSize = din.readInt(); 166 167 if ( dataSize != 0 ) 168 { 169 byte[] bytes = new byte[dataSize]; 170 171 din.readFully( bytes ); 172 E key = keyMarshaller.deserialize( bytes ); 173 nodes[i] = key; 174 } 175 } 176 177 return new ArrayTree<>( comparator, nodes ); 178 } 179 catch ( NullPointerException npe ) 180 { 181 System.out.println( I18n.err( I18n.ERR_441, Strings.dumpBytes( data ) ) ); 182 throw npe; 183 } 184 } 185}