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 }