You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

WidgetMapGenerator.java 8.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. package com.vaadin.terminal.gwt.widgetsetutils;
  2. import java.io.PrintWriter;
  3. import java.util.Collection;
  4. import java.util.Date;
  5. import java.util.Iterator;
  6. import com.google.gwt.core.ext.Generator;
  7. import com.google.gwt.core.ext.GeneratorContext;
  8. import com.google.gwt.core.ext.TreeLogger;
  9. import com.google.gwt.core.ext.UnableToCompleteException;
  10. import com.google.gwt.core.ext.TreeLogger.Type;
  11. import com.google.gwt.core.ext.typeinfo.JClassType;
  12. import com.google.gwt.core.ext.typeinfo.TypeOracle;
  13. import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
  14. import com.google.gwt.user.rebind.SourceWriter;
  15. import com.vaadin.terminal.Paintable;
  16. import com.vaadin.terminal.gwt.client.ui.VView;
  17. import com.vaadin.ui.ClientWidget;
  18. /**
  19. * GWT generator to build WidgetMapImpl dynamically based on
  20. * {@link ClientWidget} annotations available in workspace.
  21. *
  22. */
  23. public class WidgetMapGenerator extends Generator {
  24. private String packageName;
  25. private String className;
  26. @Override
  27. public String generate(TreeLogger logger, GeneratorContext context,
  28. String typeName) throws UnableToCompleteException {
  29. try {
  30. TypeOracle typeOracle = context.getTypeOracle();
  31. // get classType and save instance variables
  32. JClassType classType = typeOracle.getType(typeName);
  33. packageName = classType.getPackage().getName();
  34. className = classType.getSimpleSourceName() + "Impl";
  35. // Generate class source code
  36. generateClass(logger, context);
  37. } catch (Exception e) {
  38. logger.log(TreeLogger.ERROR, "WidgetMap creation failed", e);
  39. }
  40. // return the fully qualifed name of the class generated
  41. return packageName + "." + className;
  42. }
  43. /**
  44. * Generate source code for WidgetMapImpl
  45. *
  46. * @param logger
  47. * Logger object
  48. * @param context
  49. * Generator context
  50. */
  51. private void generateClass(TreeLogger logger, GeneratorContext context) {
  52. // get print writer that receives the source code
  53. PrintWriter printWriter = null;
  54. printWriter = context.tryCreate(logger, packageName, className);
  55. // print writer if null, source code has ALREADY been generated,
  56. // return (WidgetMap is equal to all permutations atm)
  57. if (printWriter == null) {
  58. return;
  59. }
  60. logger
  61. .log(Type.INFO,
  62. "Detecting vaading components in classpath to generate WidgetMapImpl.java ...");
  63. Date date = new Date();
  64. // init composer, set class properties, create source writer
  65. ClassSourceFileComposerFactory composer = null;
  66. composer = new ClassSourceFileComposerFactory(packageName, className);
  67. composer.addImport("com.google.gwt.core.client.GWT");
  68. composer.setSuperclass("com.vaadin.terminal.gwt.client.WidgetMap");
  69. SourceWriter sourceWriter = composer.createSourceWriter(context,
  70. printWriter);
  71. Collection<Class<? extends Paintable>> paintablesHavingWidgetAnnotation = getUsedPaintables();
  72. validatePaintables(logger, context, paintablesHavingWidgetAnnotation);
  73. // generator constructor source code
  74. generateImplementationDetector(sourceWriter,
  75. paintablesHavingWidgetAnnotation);
  76. generateInstantiatorMethod(sourceWriter,
  77. paintablesHavingWidgetAnnotation);
  78. // close generated class
  79. sourceWriter.outdent();
  80. sourceWriter.println("}");
  81. // commit generated class
  82. context.commit(logger, printWriter);
  83. logger.log(Type.INFO, "Done. ("
  84. + (new Date().getTime() - date.getTime()) / 1000 + "seconds)");
  85. }
  86. /**
  87. * Verifies that all client side components are available for client side
  88. * GWT module.
  89. *
  90. * @param logger
  91. * @param context
  92. * @param paintablesHavingWidgetAnnotation
  93. */
  94. private void validatePaintables(
  95. TreeLogger logger,
  96. GeneratorContext context,
  97. Collection<Class<? extends Paintable>> paintablesHavingWidgetAnnotation) {
  98. TypeOracle typeOracle = context.getTypeOracle();
  99. for (Iterator<Class<? extends Paintable>> iterator = paintablesHavingWidgetAnnotation
  100. .iterator(); iterator.hasNext();) {
  101. Class<? extends Paintable> class1 = iterator.next();
  102. ClientWidget annotation = class1.getAnnotation(ClientWidget.class);
  103. if (typeOracle.findType(annotation.value().getName()) == null) {
  104. // GWT widget not inherited
  105. logger
  106. .log(
  107. Type.WARN,
  108. "Widget implementation for "
  109. + class1.getName()
  110. + " not available for GWT compiler (but mapped "
  111. + "for component found in classpath). If this is not "
  112. + "intentional, check your gwt module definition file.");
  113. iterator.remove();
  114. }
  115. }
  116. logger.log(Type.INFO,
  117. "Widget set will contain implementations for following components: "
  118. + paintablesHavingWidgetAnnotation.toString());
  119. }
  120. /**
  121. * This method is protected to allow easy creation of optimized widgetsets.
  122. * <p>
  123. * TODO we need some sort of mechanism to easily exclude/include components
  124. * from widgetset. Properties in gwt.xml is one option. Now only possible by
  125. * extending this class, overriding getUsedPaintables() method and
  126. * redefining deferred binding rule.
  127. *
  128. * @return a collections of Vaadin components that will be added to
  129. * widgetset
  130. */
  131. protected Collection<Class<? extends Paintable>> getUsedPaintables() {
  132. return ClassPathExplorer.getPaintablesHavingWidgetAnnotation();
  133. }
  134. private void generateInstantiatorMethod(
  135. SourceWriter sourceWriter,
  136. Collection<Class<? extends Paintable>> paintablesHavingWidgetAnnotation) {
  137. sourceWriter
  138. .println("public Paintable instantiate(Class<? extends Paintable> classType) {");
  139. sourceWriter.indent();
  140. sourceWriter
  141. .println("Paintable p = super.instantiate(classType); if(p!= null) return p;");
  142. for (Class<? extends Paintable> class1 : paintablesHavingWidgetAnnotation) {
  143. ClientWidget annotation = class1.getAnnotation(ClientWidget.class);
  144. Class<? extends com.vaadin.terminal.gwt.client.Paintable> clientClass = annotation
  145. .value();
  146. if (clientClass == VView.class) {
  147. // VView's are not instantiated by widgetset
  148. continue;
  149. }
  150. sourceWriter.print("if (");
  151. sourceWriter.print(clientClass.getName());
  152. sourceWriter.print(".class == classType) return GWT.create(");
  153. sourceWriter.print(clientClass.getName());
  154. sourceWriter.println(".class );");
  155. sourceWriter.print("else ");
  156. }
  157. sourceWriter
  158. .println("return GWT.create( com.vaadin.terminal.gwt.client.ui.VUnknownComponent.class );");
  159. sourceWriter.outdent();
  160. sourceWriter.println("}");
  161. }
  162. /**
  163. *
  164. * @param sourceWriter
  165. * Source writer to output source code
  166. * @param paintablesHavingWidgetAnnotation
  167. */
  168. private void generateImplementationDetector(
  169. SourceWriter sourceWriter,
  170. Collection<Class<? extends Paintable>> paintablesHavingWidgetAnnotation) {
  171. sourceWriter
  172. .println("public Class<? extends Paintable> "
  173. + "getImplementationByServerSideClassName(String fullyQualifiedName) {");
  174. sourceWriter.indent();
  175. sourceWriter
  176. .println("fullyQualifiedName = fullyQualifiedName.intern();");
  177. for (Class<? extends Paintable> class1 : paintablesHavingWidgetAnnotation) {
  178. ClientWidget annotation = class1.getAnnotation(ClientWidget.class);
  179. Class<? extends com.vaadin.terminal.gwt.client.Paintable> clientClass = annotation
  180. .value();
  181. sourceWriter.print("if ( fullyQualifiedName == \"");
  182. sourceWriter.print(class1.getName());
  183. sourceWriter.print("\" ) return ");
  184. sourceWriter.print(clientClass.getName());
  185. sourceWriter.println(".class;");
  186. sourceWriter.print("else ");
  187. }
  188. sourceWriter
  189. .println("return com.vaadin.terminal.gwt.client.ui.VUnknownComponent.class;");
  190. sourceWriter.outdent();
  191. sourceWriter.println("}");
  192. }
  193. }