KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > gwt > user > server > rpc > impl > ServerSerializableTypeOracleImpl


1 /*
2  * Copyright 2006 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */

16 package com.google.gwt.user.server.rpc.impl;
17
18 import com.google.gwt.user.client.rpc.IsSerializable;
19
20 import java.io.Serializable JavaDoc;
21 import java.lang.reflect.Field JavaDoc;
22 import java.lang.reflect.Modifier JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.Arrays JavaDoc;
25 import java.util.Comparator JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.HashSet JavaDoc;
28 import java.util.Map JavaDoc;
29 import java.util.Set JavaDoc;
30 import java.util.zip.CRC32 JavaDoc;
31
32 /**
33  * This class defines an implementation of a serializable type oracle that can
34  * be used by the rpc servlet.
35  */

36 public class ServerSerializableTypeOracleImpl implements
37     ServerSerializableTypeOracle {
38
39   /**
40    * A permanent cache of all computed CRCs on classes. This is safe to do
41    * because a Class is guaranteed not to change within the lifetime of a
42    * ClassLoader (and thus, this Map). Access must be synchronized.
43    */

44   private static final Map JavaDoc classCRC32Cache = new HashMap JavaDoc();
45
46   /**
47    * A permanent cache of all which classes onto custom field serializers. This
48    * is safe to do because a Class is guaranteed not to change within the
49    * lifetime of a ClassLoader (and thus, this Map). Access must be
50    * synchronized.
51    */

52   private static final Map JavaDoc classCustomSerializerCache = new HashMap JavaDoc();
53
54   private static final Map JavaDoc SERIALIZED_PRIMITIVE_TYPE_NAMES = new HashMap JavaDoc();
55   private static final Set JavaDoc TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES = new HashSet JavaDoc();
56
57   static {
58
59     SERIALIZED_PRIMITIVE_TYPE_NAMES.put(boolean.class.getName(), "Z");
60     SERIALIZED_PRIMITIVE_TYPE_NAMES.put(byte.class.getName(), "B");
61     SERIALIZED_PRIMITIVE_TYPE_NAMES.put(char.class.getName(), "C");
62     SERIALIZED_PRIMITIVE_TYPE_NAMES.put(double.class.getName(), "D");
63     SERIALIZED_PRIMITIVE_TYPE_NAMES.put(float.class.getName(), "F");
64     SERIALIZED_PRIMITIVE_TYPE_NAMES.put(int.class.getName(), "I");
65     SERIALIZED_PRIMITIVE_TYPE_NAMES.put(long.class.getName(), "J");
66     SERIALIZED_PRIMITIVE_TYPE_NAMES.put(short.class.getName(), "S");
67
68     TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add(Boolean JavaDoc.class);
69     TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add(Byte JavaDoc.class);
70     TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add(Character JavaDoc.class);
71     TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add(Double JavaDoc.class);
72     TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add(Exception JavaDoc.class);
73     TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add(Float JavaDoc.class);
74     TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add(Integer JavaDoc.class);
75     TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add(Long JavaDoc.class);
76     TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add(Object JavaDoc.class);
77     TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add(Short JavaDoc.class);
78     TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add(String JavaDoc.class);
79     TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add(Throwable JavaDoc.class);
80   }
81
82   private static boolean containsCachedSerializerForClass(Class JavaDoc instanceType) {
83     synchronized (classCustomSerializerCache) {
84       return classCustomSerializerCache.containsKey(instanceType);
85     }
86   }
87
88   private static String JavaDoc getCachedCRCForClass(Class JavaDoc instanceType) {
89     synchronized (classCRC32Cache) {
90       return (String JavaDoc) classCRC32Cache.get(instanceType);
91     }
92   }
93
94   private static Class JavaDoc getCachedSerializerForClass(Class JavaDoc instanceType) {
95     synchronized (classCustomSerializerCache) {
96       return (Class JavaDoc) classCustomSerializerCache.get(instanceType);
97     }
98   }
99
100   private static void putCachedCRCForClass(Class JavaDoc instanceType, String JavaDoc crc32) {
101     synchronized (classCRC32Cache) {
102       classCRC32Cache.put(instanceType, crc32);
103     }
104   }
105
106   private static void putCachedSerializerForClass(Class JavaDoc instanceType,
107       Class JavaDoc customFieldSerializer) {
108     synchronized (classCustomSerializerCache) {
109       classCustomSerializerCache.put(instanceType, customFieldSerializer);
110     }
111   }
112
113   private String JavaDoc[] packagePaths;
114
115   public ServerSerializableTypeOracleImpl(String JavaDoc[] packagePaths) {
116     this.packagePaths = packagePaths;
117   }
118
119   public Field JavaDoc[] applyFieldSerializationPolicy(Field JavaDoc[] fields) {
120     ArrayList JavaDoc fieldList = new ArrayList JavaDoc();
121     for (int index = 0; index < fields.length; ++index) {
122       Field JavaDoc field = fields[index];
123       assert (field != null);
124
125       int fieldModifiers = field.getModifiers();
126       if (Modifier.isStatic(fieldModifiers)
127           || Modifier.isTransient(fieldModifiers)
128           || Modifier.isFinal(fieldModifiers)) {
129         continue;
130       }
131
132       fieldList.add(field);
133     }
134
135     Field JavaDoc[] fieldSubset = (Field JavaDoc[]) fieldList.toArray(new Field JavaDoc[fieldList.size()]);
136
137     // sort the fields by name
138
Comparator JavaDoc comparator = new Comparator JavaDoc() {
139       public int compare(Object JavaDoc o1, Object JavaDoc o2) {
140         Field JavaDoc f1 = (Field JavaDoc) o1;
141         Field JavaDoc f2 = (Field JavaDoc) o2;
142
143         return f1.getName().compareTo(f2.getName());
144       }
145     };
146     Arrays.sort(fieldSubset, 0, fieldSubset.length, comparator);
147
148     return fieldSubset;
149   }
150
151   public SerializedInstanceReference decodeSerializedInstanceReference(
152       String JavaDoc encodedSerializedInstanceReference) {
153     final String JavaDoc[] components = encodedSerializedInstanceReference.split(SerializedInstanceReference.SERIALIZED_REFERENCE_SEPARATOR);
154     return new SerializedInstanceReference() {
155       public String JavaDoc getName() {
156         return components.length > 0 ? components[0] : "";
157       }
158
159       public String JavaDoc getSignature() {
160         return components.length > 1 ? components[1] : "";
161       }
162     };
163   }
164
165   public String JavaDoc encodeSerializedInstanceReference(Class JavaDoc instanceType) {
166     return instanceType.getName()
167         + SerializedInstanceReference.SERIALIZED_REFERENCE_SEPARATOR
168         + getSerializationSignature(instanceType);
169   }
170
171   public String JavaDoc getSerializationSignature(Class JavaDoc instanceType) {
172     String JavaDoc result = getCachedCRCForClass(instanceType);
173     if (result == null) {
174       CRC32 JavaDoc crc = new CRC32 JavaDoc();
175       generateSerializationSignature(instanceType, crc);
176       result = Long.toString(crc.getValue());
177       putCachedCRCForClass(instanceType, result);
178     }
179     return result;
180   }
181
182   public String JavaDoc getSerializedTypeName(Class JavaDoc instanceType) {
183     if (instanceType.isPrimitive()) {
184       return (String JavaDoc) SERIALIZED_PRIMITIVE_TYPE_NAMES.get(instanceType.getName());
185     }
186
187     return instanceType.getName();
188   }
189
190   /**
191    * This method treats arrays in a special way.
192    */

193   public Class JavaDoc hasCustomFieldSerializer(Class JavaDoc instanceType) {
194     assert (instanceType != null);
195     Class JavaDoc result = getCachedSerializerForClass(instanceType);
196     if (result != null) {
197       // this class has a custom serializer
198
return result;
199     }
200     if (containsCachedSerializerForClass(instanceType)) {
201       // this class definitely has no custom serializer
202
return null;
203     }
204     // compute whether this class has a custom serializer
205
result = computeHasCustomFieldSerializer(instanceType);
206     putCachedSerializerForClass(instanceType, result);
207     return result;
208   }
209
210   public boolean isSerializable(Class JavaDoc instanceType) {
211     if (instanceType.isArray()) {
212       return isSerializable(instanceType.getComponentType());
213     }
214     if (instanceType.isPrimitive()) {
215       return true;
216     }
217     if (IsSerializable.class.isAssignableFrom(instanceType) ||
218         Serializable.class.isAssignableFrom(instanceType)) {
219       return true;
220     }
221     return hasCustomFieldSerializer(instanceType) != null;
222   }
223
224   /**
225    * This method treats arrays in a special way.
226    */

227   private Class JavaDoc computeHasCustomFieldSerializer(Class JavaDoc instanceType) {
228     assert (instanceType != null);
229
230     String JavaDoc qualifiedTypeName;
231
232     if (instanceType.isArray()) {
233       Class JavaDoc componentType = instanceType.getComponentType();
234
235       if (componentType.isPrimitive()) {
236         qualifiedTypeName = "java.lang." + componentType.getName();
237       } else {
238         qualifiedTypeName = Object JavaDoc.class.getName();
239       }
240
241       qualifiedTypeName += "_Array";
242
243     } else {
244       qualifiedTypeName = instanceType.getName();
245     }
246
247     Class JavaDoc customSerializer = getCustomFieldSerializer(qualifiedTypeName
248         + "_CustomFieldSerializer");
249     if (customSerializer != null) {
250       return customSerializer;
251     }
252
253     // Try with the regular name
254
String JavaDoc simpleSerializerName = qualifiedTypeName + "_CustomFieldSerializer";
255     for (int i = 0; i < packagePaths.length; ++i) {
256       Class JavaDoc customSerializerClass = getCustomFieldSerializer(packagePaths[i]
257           + "." + simpleSerializerName);
258       if (customSerializerClass != null) {
259         return customSerializerClass;
260       }
261     }
262
263     return null;
264   }
265
266   private boolean excludeImplementationFromSerializationSignature(
267       Class JavaDoc instanceType) {
268     if (TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.contains(instanceType)) {
269       return true;
270     }
271     return false;
272   }
273
274   private void generateSerializationSignature(Class JavaDoc instanceType, CRC32 JavaDoc crc) {
275     crc.update(getSerializedTypeName(instanceType).getBytes());
276
277     if (excludeImplementationFromSerializationSignature(instanceType)) {
278       return;
279     }
280
281     Class JavaDoc customSerializer = hasCustomFieldSerializer(instanceType);
282     if (customSerializer != null) {
283       generateSerializationSignature(customSerializer, crc);
284     } else if (instanceType.isArray()) {
285       generateSerializationSignature(instanceType.getComponentType(), crc);
286     } else if (!instanceType.isPrimitive()) {
287       Field JavaDoc[] fields = applyFieldSerializationPolicy(instanceType.getDeclaredFields());
288       for (int i = 0; i < fields.length; ++i) {
289         Field JavaDoc field = fields[i];
290         assert (field != null);
291
292         crc.update(field.getName().getBytes());
293         crc.update(getSerializedTypeName(field.getType()).getBytes());
294       }
295
296       Class JavaDoc superClass = instanceType.getSuperclass();
297       if (superClass != null) {
298         generateSerializationSignature(superClass, crc);
299       }
300     }
301   }
302
303   private Class JavaDoc getCustomFieldSerializer(String JavaDoc qualifiedSerialzierName) {
304     Class JavaDoc customSerializerClass;
305     try {
306       customSerializerClass = Class.forName(qualifiedSerialzierName, false,
307           this.getClass().getClassLoader());
308       return customSerializerClass;
309     } catch (ClassNotFoundException JavaDoc e) {
310       return null;
311     }
312   }
313
314   private String JavaDoc[] getPackagePaths() {
315     return packagePaths;
316   }
317 }
318
Popular Tags