View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.core.shared;
21  
22  
23  import java.io.ByteArrayInputStream;
24  import java.io.ByteArrayOutputStream;
25  import java.io.IOException;
26  import java.io.ObjectInputStream;
27  import java.io.ObjectOutput;
28  import java.io.ObjectOutputStream;
29  
30  import jdbm.helper.Serializer;
31  
32  import org.apache.directory.api.ldap.model.entry.Attribute;
33  import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
34  import org.apache.directory.api.ldap.model.entry.DefaultEntry;
35  import org.apache.directory.api.ldap.model.entry.Entry;
36  import org.apache.directory.api.ldap.model.exception.LdapException;
37  import org.apache.directory.api.ldap.model.name.Dn;
38  import org.apache.directory.api.ldap.model.schema.AttributeType;
39  import org.apache.directory.api.ldap.model.schema.SchemaManager;
40  import org.apache.directory.server.i18n.I18n;
41  import org.slf4j.Logger;
42  import org.slf4j.LoggerFactory;
43  
44  
45  /**
46   * Serialize and deserialize a ServerEntry. 
47   * 
48   * WARNING: This serializer stores the complete DN as well (unlike other entry 
49   *          serializers which store only RDN).
50   * 
51   * <b>This class must *not* be used anywhere else other than for storing sorted entries in server.</b>
52   *  
53   *  Note: this was initially used by Mavibot tree, but changed to use in JDBM later.
54   *        This will again be ported to Mavibot as soon as it gets ready.
55   *        
56   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
57   */
58  public class SortedEntrySerializer implements Serializer
59  {
60      /** The serialVersionUID */
61      private static final long serialVersionUID = 1L;
62  
63      /** the logger for this class */
64      private static final Logger LOG = LoggerFactory.getLogger( SortedEntrySerializer.class );
65  
66      /**
67       * Speedup for logs
68       */
69      private static final boolean IS_DEBUG = LOG.isDebugEnabled();
70  
71      /** The schemaManager reference */
72      private static SchemaManager schemaManager;
73  
74  
75      /**
76       * Creates a new instance of ServerEntrySerializer.
77       * The schemaManager MUST be set explicitly set using the static {@link #setSchemaManager(SchemaManager)}
78       */
79      public SortedEntrySerializer()
80      {
81      }
82  
83  
84      @Override
85      public byte[] serialize( Object obj ) throws IOException
86      {
87          return serialize( ( Entry ) obj );
88      }
89  
90  
91  
92      @Override
93      public Object deserialize( byte[] serialized ) throws IOException
94      {
95          ObjectInputStream in = new ObjectInputStream( new ByteArrayInputStream( serialized ) );
96  
97          try
98          {
99              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 }