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.shared; 021 022 023import java.io.ByteArrayInputStream; 024import java.io.ByteArrayOutputStream; 025import java.io.IOException; 026import java.io.ObjectInputStream; 027import java.io.ObjectOutput; 028import java.io.ObjectOutputStream; 029 030import jdbm.helper.Serializer; 031 032import org.apache.directory.api.ldap.model.entry.Attribute; 033import org.apache.directory.api.ldap.model.entry.DefaultAttribute; 034import org.apache.directory.api.ldap.model.entry.DefaultEntry; 035import org.apache.directory.api.ldap.model.entry.Entry; 036import org.apache.directory.api.ldap.model.exception.LdapException; 037import org.apache.directory.api.ldap.model.name.Dn; 038import org.apache.directory.api.ldap.model.schema.AttributeType; 039import org.apache.directory.api.ldap.model.schema.SchemaManager; 040import org.apache.directory.server.i18n.I18n; 041import org.slf4j.Logger; 042import org.slf4j.LoggerFactory; 043 044 045/** 046 * Serialize and deserialize a ServerEntry. 047 * 048 * WARNING: This serializer stores the complete DN as well (unlike other entry 049 * serializers which store only RDN). 050 * 051 * <b>This class must *not* be used anywhere else other than for storing sorted entries in server.</b> 052 * 053 * Note: this was initially used by Mavibot tree, but changed to use in JDBM later. 054 * This will again be ported to Mavibot as soon as it gets ready. 055 * 056 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 057 */ 058public class SortedEntrySerializer implements Serializer 059{ 060 /** The serialVersionUID */ 061 private static final long serialVersionUID = 1L; 062 063 /** the logger for this class */ 064 private static final Logger LOG = LoggerFactory.getLogger( SortedEntrySerializer.class ); 065 066 /** 067 * Speedup for logs 068 */ 069 private static final boolean IS_DEBUG = LOG.isDebugEnabled(); 070 071 /** The schemaManager reference */ 072 private static SchemaManager schemaManager; 073 074 075 /** 076 * Creates a new instance of ServerEntrySerializer. 077 * The schemaManager MUST be set explicitly set using the static {@link #setSchemaManager(SchemaManager)} 078 */ 079 public SortedEntrySerializer() 080 { 081 } 082 083 084 @Override 085 public byte[] serialize( Object obj ) throws IOException 086 { 087 return serialize( ( Entry ) obj ); 088 } 089 090 091 092 @Override 093 public Object deserialize( byte[] serialized ) throws IOException 094 { 095 ObjectInputStream in = new ObjectInputStream( new ByteArrayInputStream( serialized ) ); 096 097 try 098 { 099 Entry entry = new DefaultEntry( schemaManager ); 100 101 Dn dn = new Dn( schemaManager ); 102 dn.readExternal( in ); 103 entry.setDn( dn ); 104 105 // Read the number of attributes 106 int nbAttributes = in.readInt(); 107 108 // Read the attributes 109 for ( int i = 0; i < nbAttributes; i++ ) 110 { 111 // Read the attribute's OID 112 String oid = in.readUTF(); 113 114 try 115 { 116 AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( oid ); 117 118 // Create the attribute we will read 119 Attribute attribute = new DefaultAttribute( attributeType ); 120 121 // Read the attribute 122 attribute.readExternal( in ); 123 124 entry.add( attribute ); 125 } 126 catch ( LdapException ne ) 127 { 128 // We weren't able to find the OID. The attribute will not be added 129 throw new ClassNotFoundException( ne.getMessage(), ne ); 130 } 131 } 132 133 return entry; 134 } 135 catch ( ClassNotFoundException cnfe ) 136 { 137 LOG.error( I18n.err( I18n.ERR_134, cnfe.getLocalizedMessage() ) ); 138 throw new IOException( cnfe.getLocalizedMessage() ); 139 } 140 } 141 142 143 144 /** 145 * <p> 146 * 147 * This is the place where we serialize entries, and all theirs 148 * elements. the reason why we don't call the underlying methods 149 * (<code>ServerAttribute.write(), Value.write()</code>) is that we need 150 * access to the registries to read back the values. 151 * <p> 152 * The structure used to store the entry is the following : 153 * <ul> 154 * <li><b>[Dn]</b> : The entry's Rdn.</li> 155 * <li><b>[numberAttr]</b> : the bumber of attributes. Can be 0</li> 156 * <li>For each Attribute : 157 * <ul> 158 * <li><b>[attribute's oid]</b> : The attribute's OID to get back 159 * the attributeType on deserialization</li> 160 * <li><b>[Attribute]</b> The attribute</li> 161 * </ul> 162 * </li> 163 * </ul> 164 * 165 * @param entry The entry to serialize 166 * @return The byte[] containing the serialized entry 167 */ 168 public byte[] serialize( Entry entry ) 169 { 170 try 171 { 172 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 173 174 ObjectOutput out = new ObjectOutputStream( baos ); 175 176 // First, the Dn 177 Dn dn = entry.getDn(); 178 179 // Write the Dn 180 dn.writeExternal( out ); 181 182 // Then the attributes. 183 out.writeInt( entry.getAttributes().size() ); 184 185 // Iterate through the keys. We store the Attribute 186 // here, to be able to restore it in the readExternal : 187 // we need access to the registries, which are not available 188 // in the ServerAttribute class. 189 for ( Attribute attribute : entry.getAttributes() ) 190 { 191 AttributeType attributeType = attribute.getAttributeType(); 192 193 // Write the oid to be able to restore the AttributeType when deserializing 194 // the attribute 195 String oid = attributeType.getOid(); 196 197 out.writeUTF( oid ); 198 199 // Write the attribute 200 attribute.writeExternal( out ); 201 } 202 203 out.flush(); 204 205 // Note : we don't store the ObjectClassAttribute. It has already 206 // been stored as an attribute. 207 208 if ( IS_DEBUG ) 209 { 210 LOG.debug( ">------------------------------------------------" ); 211 LOG.debug( "Serialize {}", entry ); 212 } 213 214 return baos.toByteArray(); 215 } 216 catch ( Exception e ) 217 { 218 throw new RuntimeException( e ); 219 } 220 } 221 222 223 public static void setSchemaManager( SchemaManager schemaManager ) 224 { 225 SortedEntrySerializer.schemaManager = schemaManager; 226 } 227 228}