KickJava   Java API By Example, From Geeks To Geeks.

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


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 package com.google.gwt.user.rebind.rpc;
17
18 import com.google.gwt.core.client.GWT;
19 import com.google.gwt.core.client.GWT.UncaughtExceptionHandler;
20 import com.google.gwt.core.ext.GeneratorContext;
21 import com.google.gwt.core.ext.TreeLogger;
22 import com.google.gwt.core.ext.UnableToCompleteException;
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.JParameter;
27 import com.google.gwt.core.ext.typeinfo.JParameterizedType;
28 import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
29 import com.google.gwt.core.ext.typeinfo.JType;
30 import com.google.gwt.dev.generator.NameFactory;
31 import com.google.gwt.user.client.ResponseTextHandler;
32 import com.google.gwt.user.client.rpc.AsyncCallback;
33 import com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException;
34 import com.google.gwt.user.client.rpc.InvocationException;
35 import com.google.gwt.user.client.rpc.SerializationException;
36 import com.google.gwt.user.client.rpc.ServiceDefTarget;
37 import com.google.gwt.user.client.rpc.ServiceDefTarget.NoServiceEntryPointSpecifiedException;
38 import com.google.gwt.user.client.rpc.impl.ClientSerializationStreamReader;
39 import com.google.gwt.user.client.rpc.impl.ClientSerializationStreamWriter;
40 import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
41 import com.google.gwt.user.rebind.SourceWriter;
42
43 import java.io.PrintWriter JavaDoc;
44
45 /**
46  * Creates a client-side proxy for a
47  * {@link com.google.gwt.user.client.rpc.RemoteService RemoteService} interface
48  * as well as the necessary type and field serializers.
49  */

50 class ProxyCreator {
51   private static final String JavaDoc ENTRY_POINT_TAG = "gwt.defaultEntryPoint";
52   private static final String JavaDoc PROXY_SUFFIX = "_Proxy";
53
54   private static final String JavaDoc SERIALIZATION_STREAM_READER_INSTANTIATION = ClientSerializationStreamReader.class.getName()
55       + " streamReader = new "
56       + ClientSerializationStreamReader.class.getName() + "(SERIALIZER);";
57
58   private static final String JavaDoc SERIALIZATION_STREAM_WRITER_INSTANTIATION = ClientSerializationStreamWriter.class.getName()
59       + " streamWriter = new "
60       + ClientSerializationStreamWriter.class.getName() + "(SERIALIZER);";
61
62   /*
63    * This method returns the real type name. Currently, it only affects
64    * JParameterizedType since their names are not legal Java names.
65    */

66   private static String JavaDoc getJavaTypeName(JType type) {
67     JParameterizedType parameterizedType = type.isParameterized();
68     if (parameterizedType != null) {
69       return parameterizedType.getRawType().getQualifiedSourceName();
70     }
71
72     return type.getQualifiedSourceName();
73   }
74
75   private boolean enforceTypeVersioning;
76
77   private JClassType serviceIntf;
78
79   public ProxyCreator(JClassType serviceIntf) {
80     assert (serviceIntf.isInterface() != null);
81
82     this.serviceIntf = serviceIntf;
83   }
84
85   /**
86    * Creates the client-side proxy class.
87    *
88    * @throws UnableToCompleteException
89    */

90   public String JavaDoc create(TreeLogger logger, GeneratorContext context)
91       throws UnableToCompleteException {
92     SourceWriter srcWriter = getSourceWriter(logger, context);
93     if (srcWriter == null) {
94       return getProxyQualifiedName();
95     }
96
97     SerializableTypeOracleBuilder stob = new SerializableTypeOracleBuilder(
98         logger, context.getTypeOracle());
99     SerializableTypeOracle sto = stob.build(context.getPropertyOracle(),
100         serviceIntf);
101
102     TypeSerializerCreator tsc = new TypeSerializerCreator(logger, sto, context,
103         serviceIntf);
104     tsc.realize(logger);
105
106     enforceTypeVersioning = Shared.shouldEnforceTypeVersioning(logger,
107         context.getPropertyOracle());
108
109     generateProxyFields(srcWriter, sto);
110
111     generateServiceDefTargetImpl(srcWriter);
112
113     generateProxyMethods(srcWriter, sto);
114
115     srcWriter.commit(logger);
116
117     return getProxyQualifiedName();
118   }
119
120   /*
121    * Given a type emit an expression for calling the correct
122    * SerializationStreamReader method which reads the corresponding
123    * instance out of the stream.
124    */

125   protected final void generateDecodeCall(SourceWriter w, JType type) {
126     w.print("streamReader.");
127     w.print("read" + Shared.getCallSuffix(type) + "()");
128   }
129
130   /*
131    * Given a type emit an expression for calling the correct
132    * SerializationStreamWriter method which writes that type into the stream.
133    */

134   protected void generateEncodeCall(SourceWriter w, JParameter parameter) {
135     JType paramType = parameter.getType();
136     w.print("streamWriter.");
137     w.print("write" + Shared.getCallSuffix(paramType));
138     w.println("(" + parameter.getName() + ");");
139   }
140
141   /*
142    * Calls the __ version to encode.
143    */

144   private void generateAsynchronousProxyMethod(SourceWriter w, JMethod method) {
145
146     JType returnType = method.getReturnType();
147     JParameter[] params = method.getParameters();
148
149     NameFactory nameFactory = new NameFactory();
150
151     for (int i = 0; i < params.length; ++i) {
152       nameFactory.addName(params[i].getName());
153     }
154
155     w.println();
156     w.print("public void " + method.getName() + "(");
157     int i;
158     for (i = 0; i < params.length; i++) {
159       JParameter param = params[i];
160       w.print((i > 0 ? ", " : "") + getJavaTypeName(param.getType()) + " "
161           + param.getName());
162     }
163
164     w.println((i > 0 ? ", final " : "final ") + AsyncCallback.class.getName()
165         + " callback) {");
166     w.indent();
167     w.println("final " + SERIALIZATION_STREAM_READER_INSTANTIATION);
168     w.println("final " + SERIALIZATION_STREAM_WRITER_INSTANTIATION);
169     w.println("try {");
170     w.indent();
171     {
172       w.print("__" + method.getName() + "(streamWriter");
173       for (i = 0; i < params.length; i++) {
174         w.print(", " + params[i].getName());
175       }
176       w.println(");");
177     }
178     w.outdent();
179
180     String JavaDoc exceptionName = nameFactory.createName("e");
181     w.println("} catch (" + SerializationException.class.getName() + " "
182         + exceptionName + ") {");
183     w.indentln("callback.onFailure(" + exceptionName + ");");
184     w.indentln("return;");
185     w.println("}");
186
187     // Generate the async response handler.
188
//
189
w.println(ResponseTextHandler.class.getName() + " handler = new "
190         + ResponseTextHandler.class.getName() + "() {");
191     w.indent();
192     {
193       w.println("public final void onCompletion(String encodedResponse) {");
194       w.indent();
195       {
196         w.println("UncaughtExceptionHandler handler = GWT.getUncaughtExceptionHandler();");
197         w.println("if (handler != null)");
198         w.indent();
199         {
200           w.println("onCompletionAndCatch(encodedResponse, handler);");
201         }
202         w.outdent();
203         w.println("else");
204         w.indent();
205         {
206           w.println("onCompletionImpl(encodedResponse);");
207         }
208         w.outdent();
209       }
210       w.outdent();
211       w.println("}");
212
213       w.println("private void onCompletionAndCatch(String encodedResponse, UncaughtExceptionHandler handler) {");
214       w.indent();
215       {
216         w.println("try {");
217         w.indent();
218         {
219           w.println("onCompletionImpl(encodedResponse);");
220         }
221         w.outdent();
222         w.println("} catch (Throwable e) {");
223         w.indent();
224         {
225           w.println("handler.onUncaughtException(e);");
226         }
227         w.outdent();
228         w.println("}");
229       }
230       w.outdent();
231       w.println("}");
232
233       w.println("private void onCompletionImpl(String encodedResponse) {");
234       w.indent();
235       {
236         w.println("Object result = null;");
237         w.println("Throwable caught = null;");
238         w.println("try {");
239         w.indent();
240         {
241           w.println("if (encodedResponse.startsWith(\"//OK\")) {");
242           w.indent();
243           {
244             w.println("streamReader.prepareToRead(encodedResponse.substring(4));");
245             w.print("result = ");
246
247             JPrimitiveType primitive = returnType.isPrimitive();
248             if (primitive == JPrimitiveType.VOID) {
249               w.print("null");
250             } else {
251               if (primitive != null) {
252                 w.print("new ");
253                 w.print(getObjectWrapperName(primitive));
254                 w.print("(");
255                 generateDecodeCall(w, returnType);
256                 w.print(")");
257               } else {
258                 generateDecodeCall(w, returnType);
259               }
260             }
261             w.println(";");
262           }
263           w.outdent();
264           w.println("} else if (encodedResponse.startsWith(\"//EX\")) {");
265           w.indent();
266           {
267             w.println("streamReader.prepareToRead(encodedResponse.substring(4));");
268             w.println("caught = (Throwable) streamReader.readObject();");
269           }
270           w.outdent();
271           w.println("} else {");
272           w.indent();
273           {
274             w.println("caught = new " + InvocationException.class.getName()
275                 + "(encodedResponse);");
276           }
277           w.outdent();
278           w.println("}");
279         }
280         w.outdent();
281         w.println("} catch (" + SerializationException.class.getName() + " e) {");
282         w.indent();
283         {
284           w.println("caught = new " + IncompatibleRemoteServiceException.class.getName() + "();");
285         }
286         w.outdent();
287         w.println("} catch (Throwable e) {");
288         w.indent();
289         {
290           w.println("caught = e;");
291         }
292         w.outdent();
293         w.println("}");
294
295         w.println("if (caught == null)");
296         w.indent();
297         {
298           w.println("callback.onSuccess(result);");
299         }
300         w.outdent();
301         w.println("else");
302         w.indent();
303         {
304           w.println("callback.onFailure(caught);");
305         }
306         w.outdent();
307       }
308       w.outdent();
309       w.println("}");
310     }
311     w.outdent();
312     w.println("};");
313
314     // Make the asynchronous invocation.
315
//
316
w.println("if (!com.google.gwt.user.client.HTTPRequest.asyncPost(getServiceEntryPoint(), streamWriter.toString(), handler))");
317     w.indentln("callback.onFailure(new "
318         + InvocationException.class.getName()
319         + "(\"Unable to initiate the asynchronous service invocation -- check the network connection\"));");
320     w.outdent();
321
322     w.println("}");
323   }
324
325   /**
326    * Generate the code that addresses the service.
327    */

328   private void generateProxyEncode(SourceWriter w,
329       SerializableTypeOracle serializableTypeOracle, JMethod method) {
330     String JavaDoc methodName = method.getName();
331     JParameter[] params = method.getParameters();
332     w.println();
333     w.print("private void __" + methodName + "("
334         + ClientSerializationStreamWriter.class.getName() + " streamWriter");
335     for (int i = 0; i < params.length; i++) {
336       JParameter param = params[i];
337       w.print(", " + getJavaTypeName(param.getType()) + " " + param.getName());
338     }
339
340     w.println(") throws " + SerializationException.class.getName() + " {");
341     w.indent();
342
343     // Make sure that we have a service def class name specified.
344
//
345
w.println("if (getServiceEntryPoint() == null)");
346     String JavaDoc className = NoServiceEntryPointSpecifiedException.class.getName();
347     className = className.replace('$', '.');
348     w.indentln("throw new " + className + "();");
349
350     // Generate code to describe just enough meta data for the server to locate
351
// the service definition class and resolve the method overload.
352
//
353
w.println("streamWriter.prepareToWrite();");
354
355     if (!shouldEnforceTypeVersioning()) {
356       w.println("streamWriter.addFlags("
357           + ClientSerializationStreamReader.class.getName()
358           + ".SERIALIZATION_STREAM_FLAGS_NO_TYPE_VERSIONING);");
359     }
360     w.println("streamWriter.writeString(\""
361         + serializableTypeOracle.getSerializedTypeName(method.getEnclosingType())
362         + "\");");
363     w.println("streamWriter.writeString(\"" + methodName + "\");");
364     w.println("streamWriter.writeInt(" + params.length + ");");
365     for (int i = 0; i < params.length; ++i) {
366       JParameter param = params[i];
367       w.println("streamWriter.writeString(\""
368           + serializableTypeOracle.getSerializedTypeName(param.getType())
369           + "\");");
370     }
371
372     // Encode the arguments.
373
//
374
for (int i = 0; i < params.length; i++) {
375       JParameter param = params[i];
376       generateEncodeCall(w, param);
377     }
378
379     w.outdent();
380     w.println("}");
381   }
382
383   /**
384    * Generate any fields required by the proxy.
385    */

386   private void generateProxyFields(SourceWriter srcWriter,
387       SerializableTypeOracle serializableTypeOracle) {
388     String JavaDoc typeSerializerName = serializableTypeOracle.getTypeSerializerQualifiedName(serviceIntf);
389     srcWriter.println("private static final " + typeSerializerName
390         + " SERIALIZER = new " + typeSerializerName + "();");
391   }
392
393   private void generateProxyMethods(SourceWriter w,
394       SerializableTypeOracle serializableTypeOracle) {
395
396     JMethod[] methods = serviceIntf.getOverridableMethods();
397     for (int i = 0; i < methods.length; ++i) {
398       JMethod method = methods[i];
399       generateProxyEncode(w, serializableTypeOracle, method);
400       generateAsynchronousProxyMethod(w, method);
401     }
402   }
403
404   /**
405    * Implements the ServiceDefTarget interface to allow clients to switch which
406    * back-end service definition we send calls to.
407    */

408   private void generateServiceDefTargetImpl(SourceWriter w) {
409     String JavaDoc serverDefName = getDefaultServiceDefName();
410     if (serverDefName != null) {
411       serverDefName = "\"" + serverDefName + "\"";
412     } else {
413       serverDefName = "null";
414     }
415
416     w.println();
417     w.println("String fServiceEntryPoint = " + serverDefName + ";");
418     w.println();
419     w.println("public String getServiceEntryPoint() { return fServiceEntryPoint; }");
420     w.println();
421     w.println("public void setServiceEntryPoint(String s) { fServiceEntryPoint = s; }");
422   }
423
424   private String JavaDoc getAsyncIntfQualifiedName() {
425     String JavaDoc asyncIntf = serviceIntf.getQualifiedSourceName() + "Async";
426     return asyncIntf;
427   }
428
429   private String JavaDoc getDefaultServiceDefName() {
430     String JavaDoc[][] metaData = serviceIntf.getMetaData(ENTRY_POINT_TAG);
431     if (metaData.length == 0) {
432       return null;
433     }
434     return serviceIntf.getMetaData(ENTRY_POINT_TAG)[0][0];
435   }
436
437   /*
438    * Determine the name of the object wrapper class to instantiate based on the
439    * the type of the primitive.
440    */

441   private String JavaDoc getObjectWrapperName(JPrimitiveType primitive) {
442     if (primitive == JPrimitiveType.INT) {
443       return "Integer";
444     } else if (primitive == JPrimitiveType.CHAR) {
445       return "Character";
446     }
447
448     return Shared.capitalize(primitive.getSimpleSourceName());
449   }
450
451   private String JavaDoc getPackageName() {
452     JPackage pkg = serviceIntf.getPackage();
453     if (pkg != null) {
454       return pkg.getName();
455     }
456
457     return "";
458   }
459
460   private String JavaDoc getProxyQualifiedName() {
461     String JavaDoc[] name = Shared.synthesizeTopLevelClassName(serviceIntf,
462         PROXY_SUFFIX);
463     return name[0].length() == 0 ? name[1] : name[0] + "." + name[1];
464   }
465
466   private String JavaDoc getProxySimpleName() {
467     String JavaDoc[] name = Shared.synthesizeTopLevelClassName(serviceIntf,
468         PROXY_SUFFIX);
469     return name[1];
470   }
471
472   private SourceWriter getSourceWriter(TreeLogger logger, GeneratorContext ctx) {
473     PrintWriter JavaDoc printWriter = ctx.tryCreate(logger, getPackageName(),
474         getProxySimpleName());
475     if (printWriter == null) {
476       return null;
477     }
478
479     ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory(
480         getPackageName(), getProxySimpleName());
481
482     composerFactory.addImport(GWT.class.getName());
483     String JavaDoc className = UncaughtExceptionHandler.class.getName();
484     className = className.replace('$', '.');
485     composerFactory.addImport(className);
486
487     composerFactory.addImplementedInterface(ServiceDefTarget.class.getName());
488     composerFactory.addImplementedInterface(getAsyncIntfQualifiedName());
489
490     return composerFactory.createSourceWriter(ctx, printWriter);
491   }
492
493   private boolean shouldEnforceTypeVersioning() {
494     return enforceTypeVersioning;
495   }
496 }
497
Popular Tags