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.jndi;
21  
22  
23  import org.apache.directory.server.core.entry.DefaultServerAttribute;
24  import org.apache.directory.server.core.entry.ServerAttribute;
25  import org.apache.directory.server.core.entry.ServerEntry;
26  import org.apache.directory.server.schema.registries.Registries;
27  import org.apache.directory.shared.ldap.constants.SchemaConstants;
28  import org.apache.directory.shared.ldap.schema.AttributeType;
29  
30  import java.io.ByteArrayInputStream;
31  import java.io.ByteArrayOutputStream;
32  import java.io.IOException;
33  import java.io.ObjectInputStream;
34  import java.io.ObjectOutputStream;
35  
36  import javax.naming.NamingException;
37  
38  
39  /**
40   * Contains constants and serialization methods used to implement functionality
41   * associated with RFC 2713 which enables the storage and representation of Java
42   * objects within an LDAP directory.
43   *
44   * @see <a href="http://www.faqs.org/rfcs/rfc2713.html">RFC 2713</a>
45   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
46   * @version $Rev: 679219 $
47   */
48  class JavaLdapSupport
49  {
50      // ------------------------------------------------------------------------
51      // Attribute Id Constants Used By The Java LDAP BootstrapSchema
52      // ------------------------------------------------------------------------
53  
54      /** the javaObject attribute */
55      public static final String JOBJECT_ATTR = "javaObject";
56      /** the javaContainer attribute */
57      public static final String JCONTAINER_ATTR = "javaContainer";
58      /** the javaSerializedObject attribute */
59      public static final String JSERIALIZEDOBJ_ATTR = "javaSerializedObject";
60  
61      /** the javaClassName attribute */
62      public static final String JCLASSNAME_ATTR = "javaClassName";
63      /** the javaClassNames attribute */
64      public static final String JCLASSNAMES_ATTR = "javaClassNames";
65      /** the javaSerializedData attribute */
66      public static final String JSERIALDATA_ATTR = "javaSerializedData";
67  
68  
69      // ------------------------------------------------------------------------
70      // Package Friendly & Private Utility Methods 
71      // ------------------------------------------------------------------------
72  
73      /**
74       * Resusitates an object from a serialized attribute in an entry that 
75       * conforms to the specifications for representing Java Objects in an LDAP 
76       * Directory (RFC 2713).
77       *
78       * @param attributes the entry representing a serialized object
79       * @return the deserialized object
80       * @throws NamingException if the object cannot be serialized
81       */
82      static Object deserialize( ServerEntry serverEntry ) throws NamingException
83      {
84          ObjectInputStream in = null;
85          String className = ( String ) serverEntry.get( JCLASSNAME_ATTR ).getString();
86  
87          try
88          {
89              byte[] data = ( byte[] ) serverEntry.get( JSERIALDATA_ATTR ).getBytes();
90              in = new ObjectInputStream( new ByteArrayInputStream( data ) );
91              return in.readObject();
92          }
93          catch ( Exception e )
94          {
95              NamingException ne = new NamingException( "De-serialization of '" + className + "' instance failed:\n"
96                  + e.getMessage() );
97              ne.setRootCause( e );
98              throw ne;
99          }
100         finally
101         {
102             try
103             {
104                 if ( in != null )
105                 {
106                     in.close();
107                 }
108             }
109             catch ( IOException e )
110             {
111                 throw new NamingException( "object deserialization stream close() failure" );
112             }
113         }
114     }
115 
116 
117     /**
118      * Serializes an object into a byte array.
119      *
120      * @param obj the object to serialize
121      * @return the object's serialized byte array form
122      * @throws NamingException of the object cannot be serialized
123      */
124     static byte[] serialize( Object obj ) throws NamingException
125     {
126         ByteArrayOutputStream bytesOut = null;
127         ObjectOutputStream out = null;
128 
129         try
130         {
131             bytesOut = new ByteArrayOutputStream();
132             out = new ObjectOutputStream( bytesOut );
133             out.writeObject( obj );
134             return bytesOut.toByteArray();
135         }
136         catch ( Exception e )
137         {
138             NamingException ne = new NamingException( "Serialization of '" + obj + "' failed:\n" + e.getMessage() );
139             ne.setRootCause( e );
140             throw ne;
141         }
142         finally
143         {
144             try
145             {
146                 if ( out != null )
147                 {
148                     out.close();
149                 }
150             }
151             catch ( IOException e )
152             {
153                 throw new NamingException( "object serialization stream close() failure" );
154             }
155         }
156     }
157 
158 
159     /**
160      * Serializes an object into an entry using the attributes specified in
161      * RFC 2713 to represent the serialized object.
162      *
163      * @param entry the set of attributes representing entry
164      * @param obj the object to serialize
165      * @throws NamingException if the object cannot be serialized
166      */
167     static void serialize( ServerEntry entry, Object obj, Registries registries ) throws NamingException
168     {
169         /* Let's add the object classes first:
170          * objectClass: top
171          * objectClass: javaObject
172          * objectClass: javaContainer
173          * objectClass: javaSerializedObject
174          */
175         entry.put( SchemaConstants.OBJECT_CLASS_AT,
176                 SchemaConstants.TOP_OC,
177                 JOBJECT_ATTR,
178                 JCONTAINER_ATTR,
179                 JSERIALIZEDOBJ_ATTR );
180 
181         // Add the javaClassName and javaSerializedData attributes
182         entry.put( JCLASSNAME_ATTR, obj.getClass().getName() );
183         entry.put( JSERIALDATA_ATTR, serialize( obj ) );
184 
185         // Add all the class names this object can be cast to:
186         Class<?>[] classes = obj.getClass().getClasses();
187         AttributeType attributeType = registries.getAttributeTypeRegistry().lookup( JCLASSNAMES_ATTR );
188         ServerAttribute javaClassNames = new DefaultServerAttribute( attributeType, JCLASSNAMES_ATTR );
189 
190         for ( int ii = 0; ii < classes.length; ii++ )
191         {
192             javaClassNames.add( classes[ii].getName() );
193         }
194 
195         entry.put( javaClassNames );
196     }
197 }