KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > gwt > user > rebind > rpc > TypeSerializerCreator


1 /*
2  * Copyright 2007 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
17 package com.google.gwt.user.rebind.rpc;
18
19 import com.google.gwt.core.client.JavaScriptObject;
20 import com.google.gwt.core.ext.GeneratorContext;
21 import com.google.gwt.core.ext.TreeLogger;
22 import com.google.gwt.core.ext.typeinfo.JArrayType;
23 import com.google.gwt.core.ext.typeinfo.JClassType;
24 import com.google.gwt.core.ext.typeinfo.JMethod;
25 import com.google.gwt.core.ext.typeinfo.JPackage;
26 import com.google.gwt.core.ext.typeinfo.JParameterizedType;
27 import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
28 import com.google.gwt.core.ext.typeinfo.JType;
29 import com.google.gwt.core.ext.typeinfo.TypeOracle;
30 import com.google.gwt.user.client.rpc.SerializationException;
31 import com.google.gwt.user.client.rpc.SerializationStreamReader;
32 import com.google.gwt.user.client.rpc.SerializationStreamWriter;
33 import com.google.gwt.user.client.rpc.impl.Serializer;
34 import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
35 import com.google.gwt.user.rebind.SourceWriter;
36
37 import java.io.PrintWriter JavaDoc;
38
39 /**
40  * This class generates a class that is able to serialize and deserialize a set
41  * of types into or out of a stream.
42  */

43 public class TypeSerializerCreator {
44
45   private static final String JavaDoc DESERIALIZE_METHOD_SIGNATURE = "public native void deserialize("
46       + "SerializationStreamReader streamReader, Object instance, String typeSignature)"
47       + " throws SerializationException";
48
49   private static final String JavaDoc INSTANTIATE_METHOD_SIGNATURE = "public native Object instantiate("
50       + "SerializationStreamReader streamReader, String typeSignature)"
51       + " throws SerializationException";
52
53   private static final String JavaDoc SERIALIZE_METHOD_SIGNATURE = "public native void serialize("
54       + "SerializationStreamWriter streamWriter, Object instance, String typeSignature)"
55       + " throws SerializationException";
56
57   private final GeneratorContext context;
58
59   private final boolean enforceTypeVersioning;
60
61   private final JClassType remoteService;
62
63   private final JType[] serializableTypes;
64
65   private final SerializableTypeOracle serializationOracle;
66
67   private final SourceWriter srcWriter;
68
69   private final TypeOracle typeOracle;
70
71   public TypeSerializerCreator(TreeLogger logger,
72       SerializableTypeOracle serializationOracle, GeneratorContext context,
73       JClassType remoteService) {
74     this.context = context;
75     this.remoteService = remoteService;
76     this.serializationOracle = serializationOracle;
77     this.typeOracle = context.getTypeOracle();
78
79     enforceTypeVersioning = Shared.shouldEnforceTypeVersioning(logger,
80         context.getPropertyOracle());
81
82     serializableTypes = serializationOracle.getSerializableTypes();
83
84     srcWriter = getSourceWriter(logger, context);
85   }
86
87   public String JavaDoc realize(TreeLogger logger) {
88     logger = logger.branch(TreeLogger.DEBUG,
89         "Generating TypeSerializer for service interface '"
90             + getServiceInterface().getQualifiedSourceName() + "'", null);
91     String JavaDoc typeSerializerName = serializationOracle.getTypeSerializerQualifiedName(getServiceInterface());
92     if (srcWriter == null) {
93       return typeSerializerName;
94     }
95     
96     createFieldSerializers(logger, context);
97     
98     writeStaticFields();
99
100     writeCreateMethods();
101
102     writeCreateMethodMapMethod();
103
104     if (shouldEnforceTypeVersioning()) {
105       writeCreateSignatureMapMethod();
106     }
107
108     writeRaiseSerializationException();
109
110     writeDeserializeMethod();
111
112     writeGetSerializationSignatureMethod();
113
114     writeInstantiateMethod();
115
116     writeSerializeMethod();
117
118     srcWriter.commit(logger);
119
120     return typeSerializerName;
121   }
122
123   private String JavaDoc buildArrayInstantiationExpression(JArrayType array) {
124     String JavaDoc expression = "[rank]";
125     JType componentType = array.getComponentType();
126     while (true) {
127       array = componentType.isArray();
128       if (array == null) {
129         break;
130       }
131
132       expression += "[0]";
133
134       componentType = array.getComponentType();
135     }
136
137     expression = componentType.getQualifiedSourceName() + expression;
138
139     return expression;
140   }
141
142   /*
143    * Create a field serializer for a type if it does not have a custom
144    * serializer.
145    */

146   private void createFieldSerializer(TreeLogger logger, GeneratorContext ctx,
147       JType type) {
148     assert (type != null);
149     assert (serializationOracle.isSerializable(type));
150
151     JParameterizedType parameterizedType = type.isParameterized();
152     if (parameterizedType != null) {
153       createFieldSerializer(logger, ctx, parameterizedType.getRawType());
154       return;
155     }
156
157     JClassType customFieldSerializer = serializationOracle.hasCustomFieldSerializer(type);
158     if (customFieldSerializer != null) {
159       customFieldSerializer.getQualifiedSourceName();
160       return;
161     }
162
163     /*
164      * Only a JClassType can reach this point in the code. JPrimitives have been
165      * removed because their serialization is built in, interfaces have been
166      * removed because they are not an instantiable type, JArrays have custom
167      * field serializers, and parameterized types have been broken down into
168      * their raw types.
169      */

170     assert (type.isClass() != null);
171
172     FieldSerializerCreator creator = new FieldSerializerCreator(
173         serializationOracle, type.isClass());
174     creator.realize(logger, ctx);
175   }
176
177   /*
178    * Create all of the necessary field serializers.
179    */

180   private void createFieldSerializers(TreeLogger logger, GeneratorContext ctx) {
181     JType[] types = getSerializableTypes();
182     int typeCount = types.length;
183     for (int typeIndex = 0; typeIndex < typeCount; ++typeIndex) {
184       JType type = types[typeIndex];
185       assert (type != null);
186
187       createFieldSerializer(logger, ctx, type);
188     }
189   }
190
191   private JMethod getCustomInstantiateMethod(JType type) {
192     JClassType serializer = serializationOracle.hasCustomFieldSerializer(type);
193     if (serializer == null) {
194       return null;
195     }
196
197     JMethod instantiate = serializer.findMethod(
198         "instantiate",
199         new JType[] {typeOracle.findType(SerializationStreamReader.class.getName())});
200     return instantiate;
201   }
202
203   private String JavaDoc getInstantiationMethodName(JType type) {
204     JArrayType arrayType = type.isArray();
205     if (arrayType != null) {
206       JType leafType = arrayType.getLeafType();
207       return "create_" + leafType.getQualifiedSourceName().replace('.', '_')
208           + "_Array_Rank_" + arrayType.getRank();
209     }
210
211     return "create_"
212         + serializationOracle.getFieldSerializerName(type).replace('.', '_');
213   }
214
215   private JType[] getSerializableTypes() {
216     return serializableTypes;
217   }
218
219   private JClassType getServiceInterface() {
220     return remoteService;
221   }
222
223   private SourceWriter getSourceWriter(TreeLogger logger, GeneratorContext ctx) {
224     JClassType serviceIntf = getServiceInterface();
225     JPackage serviceIntfPackage = serviceIntf.getPackage();
226     String JavaDoc packageName = serviceIntfPackage != null
227         ? serviceIntfPackage.getName() : "";
228     String JavaDoc className = serializationOracle.getTypeSerializerSimpleName(getServiceInterface());
229     PrintWriter JavaDoc printWriter = ctx.tryCreate(logger, packageName, className);
230     if (printWriter == null) {
231       return null;
232     }
233
234     ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory(
235         packageName, className);
236
237     composerFactory.addImport(JavaScriptObject.class.getName());
238     composerFactory.addImport(Serializer.class.getName());
239     composerFactory.addImport(SerializationException.class.getName());
240     composerFactory.addImport(SerializationStreamReader.class.getName());
241     composerFactory.addImport(SerializationStreamWriter.class.getName());
242
243     composerFactory.addImplementedInterface("Serializer");
244     return composerFactory.createSourceWriter(ctx, printWriter);
245   }
246
247   private boolean isAbstractType(JType type) {
248     JClassType classType = type.isClassOrInterface();
249     if (classType != null) {
250       if (classType.isAbstract()) {
251         return true;
252       }
253     }
254
255     // Primitives, arrays, and non-abstract classes fall-through to here.
256
//
257
return false;
258   }
259
260   /**
261    * Given a type determine what JSNI signature to use in the serialize or
262    * deserialize method of a custom serializer.
263    *
264    * @param type
265    */

266   private String JavaDoc normalizeJSNIInstanceSerializationMethodSignature(JType type) {
267     String JavaDoc jsniSignature;
268     JArrayType arrayType = type.isArray();
269
270     if (arrayType != null) {
271       JType componentType = arrayType.getComponentType();
272       JPrimitiveType primitiveType = componentType.isPrimitive();
273       if (primitiveType != null) {
274         jsniSignature = "[" + primitiveType.getJNISignature();
275       } else {
276         jsniSignature = "[" + "Ljava/lang/Object;";
277       }
278     } else {
279       jsniSignature = type.getJNISignature();
280     }
281
282     return jsniSignature;
283   }
284
285   private boolean shouldEnforceTypeVersioning() {
286     return enforceTypeVersioning;
287   }
288
289   private void writeArrayInstantiationMethod(JArrayType array) {
290     srcWriter.println("int rank = streamReader.readInt();");
291     srcWriter.println("return new " + buildArrayInstantiationExpression(array)
292         + ";");
293   }
294
295   private void writeCreateMethodMapMethod() {
296     srcWriter.println("private static native JavaScriptObject createMethodMap() /*-" + '{');
297     {
298       srcWriter.indent();
299       srcWriter.println("return {");
300       JType[] types = getSerializableTypes();
301       boolean needComma = false;
302       for (int index = 0; index < types.length; ++index) {
303         JType type = types[index];
304         if (isAbstractType(type)) {
305           continue;
306         }
307
308         if (needComma) {
309           srcWriter.println(",");
310         } else {
311           needComma = true;
312         }
313
314         String JavaDoc typeString = serializationOracle.getSerializedTypeName(type);
315         if (shouldEnforceTypeVersioning()) {
316           typeString += "/"
317               + serializationOracle.getSerializationSignature(type);
318         }
319
320         srcWriter.print("\"" + typeString + "\":");
321
322         // Make a JSON array
323
srcWriter.println("[");
324         {
325           srcWriter.indent();
326           {
327             // First the initialization method
328
JMethod instantiationMethod = getCustomInstantiateMethod(type);
329             srcWriter.print("function(x){ return ");
330             if (instantiationMethod != null) {
331               srcWriter.print("@"
332                   + instantiationMethod.getEnclosingType().getQualifiedSourceName());
333               srcWriter.print("::");
334               srcWriter.print(instantiationMethod.getName());
335             } else {
336               srcWriter.print("@"
337                   + serializationOracle.getTypeSerializerQualifiedName(getServiceInterface()));
338               srcWriter.print("::");
339               srcWriter.print(getInstantiationMethodName(type));
340             }
341             srcWriter.print("(L"
342                 + SerializationStreamReader.class.getName().replace('.', '/')
343                 + ";)");
344             srcWriter.print("(x);}");
345             srcWriter.println(",");
346           }
347
348           String JavaDoc jsniSignature = normalizeJSNIInstanceSerializationMethodSignature(type);
349           String JavaDoc serializerName = serializationOracle.getFieldSerializerName(type);
350           {
351             // Now the deserialization method
352
srcWriter.print("function(x,y){");
353             srcWriter.print("@" + serializerName);
354             srcWriter.print("::deserialize(L"
355                 + SerializationStreamReader.class.getName().replace('.', '/')
356                 + ";" + jsniSignature + ")");
357             srcWriter.print("(x,y);}");
358             srcWriter.println(",");
359           }
360           {
361             // Now the serialization method
362
srcWriter.print("function(x,y){");
363             srcWriter.print("@" + serializerName);
364             srcWriter.print("::serialize(L"
365                 + SerializationStreamWriter.class.getName().replace('.', '/')
366                 + ";" + jsniSignature + ")");
367             srcWriter.print("(x,y);}");
368             srcWriter.println();
369           }
370           srcWriter.outdent();
371         }
372         srcWriter.print("]");
373       }
374       srcWriter.println();
375       srcWriter.println("};");
376       srcWriter.outdent();
377     }
378     srcWriter.println("}-*/;");
379     srcWriter.println();
380   }
381
382   private void writeCreateMethods() {
383     JType[] types = getSerializableTypes();
384     for (int typeIndex = 0; typeIndex < types.length; ++typeIndex) {
385       JType type = types[typeIndex];
386       assert (serializationOracle.isSerializable(type));
387
388       // If this type is abstract it will not be serialized into the stream
389
//
390
if (isAbstractType(type)) {
391         continue;
392       }
393
394       JMethod customInstantiate = getCustomInstantiateMethod(type);
395       if (customInstantiate != null) {
396         continue;
397       }
398
399       srcWriter.print("private static ");
400       srcWriter.print(type.getQualifiedSourceName());
401       srcWriter.print(" ");
402       srcWriter.print(getInstantiationMethodName(type));
403       srcWriter.println("(SerializationStreamReader streamReader) throws SerializationException {");
404       srcWriter.indent();
405
406       JArrayType array = type.isArray();
407       if (array != null) {
408         writeArrayInstantiationMethod(array);
409       } else {
410         srcWriter.print("return new ");
411         srcWriter.print(type.getQualifiedSourceName());
412         srcWriter.println("();");
413       }
414
415       srcWriter.outdent();
416       srcWriter.println("}");
417
418       srcWriter.println();
419     }
420   }
421
422   private void writeCreateSignatureMapMethod() {
423     srcWriter.println("private static native JavaScriptObject createSignatureMap() /*-" + '{');
424     {
425       srcWriter.indent();
426       srcWriter.println("return {");
427       JType[] types = getSerializableTypes();
428       boolean needComma = false;
429       for (int index = 0; index < types.length; ++index) {
430         JType type = types[index];
431         if (isAbstractType(type)) {
432           continue;
433         }
434         if (needComma) {
435           srcWriter.println(",");
436         } else {
437           needComma = true;
438         }
439
440         srcWriter.print("\"" + serializationOracle.getSerializedTypeName(type)
441             + "\":\"" + serializationOracle.getSerializationSignature(type)
442             + "\"");
443       }
444       srcWriter.println();
445       srcWriter.println("};");
446       srcWriter.outdent();
447     }
448     srcWriter.println("}-*/;");
449     srcWriter.println();
450   }
451
452   private void writeDeserializeMethod() {
453     srcWriter.print(DESERIALIZE_METHOD_SIGNATURE);
454     srcWriter.println(" /*-" + '{');
455     {
456       String JavaDoc serializerTypeName = serializationOracle.getTypeSerializerQualifiedName(getServiceInterface());
457       srcWriter.indent();
458       srcWriter.println("var methodTable = @" + serializerTypeName
459           + "::methodMap[typeSignature];");
460       srcWriter.println("if (!methodTable) {");
461       srcWriter.indentln("@" + serializerTypeName
462           + "::raiseSerializationException(Ljava/lang/String;)(typeSignature);");
463       srcWriter.println("}");
464       srcWriter.println("methodTable[1](streamReader, instance);");
465       srcWriter.outdent();
466     }
467     srcWriter.println("}-*/;");
468     srcWriter.println();
469   }
470
471   private void writeGetSerializationSignatureMethod() {
472     if (!shouldEnforceTypeVersioning()) {
473       srcWriter.println("public String getSerializationSignature(String typeName) {");
474       srcWriter.indentln("return null;");
475       srcWriter.println("};");
476     } else {
477       String JavaDoc serializerTypeName = serializationOracle.getTypeSerializerQualifiedName(getServiceInterface());
478       srcWriter.println("public native String getSerializationSignature(String typeName) /*-" + '{');
479       srcWriter.indent();
480       srcWriter.println("var signature = @" + serializerTypeName
481           + "::signatureMap[typeName];");
482       srcWriter.println("return (signature == null) ? typeName : signature;");
483       srcWriter.outdent();
484       srcWriter.println("}-*/;");
485     }
486     srcWriter.println();
487   }
488
489   private void writeInstantiateMethod() {
490     srcWriter.print(INSTANTIATE_METHOD_SIGNATURE);
491     srcWriter.println(" /*-" + '{');
492     {
493       String JavaDoc serializerTypeName = serializationOracle.getTypeSerializerQualifiedName(getServiceInterface());
494       srcWriter.indent();
495       srcWriter.println("var methodTable = @" + serializerTypeName
496           + "::methodMap[typeSignature];");
497       srcWriter.println("if (!methodTable) {");
498       srcWriter.indentln("@" + serializerTypeName
499           + "::raiseSerializationException(Ljava/lang/String;)(typeSignature);");
500       srcWriter.println("}");
501       srcWriter.println("return methodTable[0](streamReader);");
502       srcWriter.outdent();
503     }
504     srcWriter.println("}-*/;");
505     srcWriter.println();
506   }
507
508   private void writeRaiseSerializationException() {
509     srcWriter.println("private static void raiseSerializationException(String msg) throws SerializationException {");
510     srcWriter.indentln("throw new SerializationException(msg);");
511     srcWriter.println("}");
512     srcWriter.println();
513   }
514
515   private void writeSerializeMethod() {
516     srcWriter.print(SERIALIZE_METHOD_SIGNATURE);
517     srcWriter.println(" /*-" + '{');
518     {
519       String JavaDoc serializerTypeName = serializationOracle.getTypeSerializerQualifiedName(getServiceInterface());
520       srcWriter.indent();
521       srcWriter.println("var methodTable = @" + serializerTypeName
522           + "::methodMap[typeSignature];");
523       srcWriter.println("if (!methodTable) {");
524       srcWriter.indentln("@" + serializerTypeName
525           + "::raiseSerializationException(Ljava/lang/String;)(typeSignature);");
526       srcWriter.println("}");
527       srcWriter.println("methodTable[2](streamWriter, instance);");
528       srcWriter.outdent();
529     }
530     srcWriter.println("}-*/;");
531     srcWriter.println();
532   }
533
534   private void writeStaticFields() {
535     srcWriter.println("private static final JavaScriptObject methodMap = createMethodMap();");
536     if (shouldEnforceTypeVersioning()) {
537       srcWriter.println("private static final JavaScriptObject signatureMap = createSignatureMap();");
538     }
539     srcWriter.println();
540   }
541 }
Popular Tags