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.

ConnectorBundleLoaderFactory.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. /*
  2. @VaadinApache2LicenseForJavaFiles@
  3. */
  4. package com.vaadin.terminal.gwt.widgetsetutils;
  5. import java.io.PrintWriter;
  6. import java.util.ArrayList;
  7. import java.util.Arrays;
  8. import java.util.Collection;
  9. import java.util.Collections;
  10. import java.util.HashMap;
  11. import java.util.List;
  12. import java.util.Map;
  13. import java.util.Map.Entry;
  14. import java.util.Set;
  15. import com.google.gwt.core.client.GWT;
  16. import com.google.gwt.core.ext.Generator;
  17. import com.google.gwt.core.ext.GeneratorContext;
  18. import com.google.gwt.core.ext.TreeLogger;
  19. import com.google.gwt.core.ext.TreeLogger.Type;
  20. import com.google.gwt.core.ext.UnableToCompleteException;
  21. import com.google.gwt.core.ext.typeinfo.JClassType;
  22. import com.google.gwt.core.ext.typeinfo.JMethod;
  23. import com.google.gwt.core.ext.typeinfo.NotFoundException;
  24. import com.google.gwt.core.ext.typeinfo.TypeOracle;
  25. import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
  26. import com.google.gwt.user.rebind.SourceWriter;
  27. import com.vaadin.shared.communication.ClientRpc;
  28. import com.vaadin.shared.communication.ServerRpc;
  29. import com.vaadin.shared.ui.Connect;
  30. import com.vaadin.shared.ui.Connect.LoadStyle;
  31. import com.vaadin.terminal.gwt.client.ServerConnector;
  32. import com.vaadin.terminal.gwt.client.metadata.ConnectorBundleLoader;
  33. import com.vaadin.terminal.gwt.client.metadata.TypeDataBundle;
  34. import com.vaadin.terminal.gwt.client.metadata.TypeDataStore;
  35. import com.vaadin.terminal.gwt.widgetsetutils.metadata.ConnectorBundle;
  36. import com.vaadin.terminal.gwt.widgetsetutils.metadata.ConnectorInitVisitor;
  37. import com.vaadin.terminal.gwt.widgetsetutils.metadata.StateInitVisitor;
  38. import com.vaadin.terminal.gwt.widgetsetutils.metadata.TypeVisitor;
  39. import com.vaadin.terminal.gwt.widgetsetutils.metadata.WidgetInitVisitor;
  40. public class ConnectorBundleLoaderFactory extends Generator {
  41. @Override
  42. public String generate(TreeLogger logger, GeneratorContext context,
  43. String typeName) throws UnableToCompleteException {
  44. TypeOracle typeOracle = context.getTypeOracle();
  45. try {
  46. JClassType classType = typeOracle.getType(typeName);
  47. String packageName = classType.getPackage().getName();
  48. String className = classType.getSimpleSourceName() + "Impl";
  49. generateClass(logger, context, packageName, className, typeName);
  50. return packageName + "." + className;
  51. } catch (UnableToCompleteException e) {
  52. // Just rethrow
  53. throw e;
  54. } catch (Exception e) {
  55. logger.log(Type.ERROR, getClass() + " failed", e);
  56. throw new UnableToCompleteException();
  57. }
  58. }
  59. private void generateClass(TreeLogger logger, GeneratorContext context,
  60. String packageName, String className, String requestedType)
  61. throws Exception {
  62. PrintWriter printWriter = context.tryCreate(logger, packageName,
  63. className);
  64. if (printWriter == null) {
  65. return;
  66. }
  67. List<ConnectorBundle> bundles = buildBundles(logger,
  68. context.getTypeOracle());
  69. ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(
  70. packageName, className);
  71. composer.setSuperclass(requestedType);
  72. SourceWriter w = composer.createSourceWriter(context, printWriter);
  73. w.println("public void init() {");
  74. w.indent();
  75. for (ConnectorBundle bundle : bundles) {
  76. String name = bundle.getName();
  77. boolean isEager = name
  78. .equals(ConnectorBundleLoader.EAGER_BUNDLE_NAME);
  79. w.print("addAsyncBlockLoader(new AsyncBundleLoader(\"");
  80. w.print(escape(name));
  81. w.print("\", ");
  82. w.print("new String[] {");
  83. for (Entry<JClassType, Set<String>> entry : bundle.getIdentifiers()
  84. .entrySet()) {
  85. Set<String> identifiers = entry.getValue();
  86. for (String id : identifiers) {
  87. w.print("\"");
  88. w.print(escape(id));
  89. w.print("\",");
  90. }
  91. }
  92. w.println("}) {");
  93. w.indent();
  94. w.print("protected void load(final ");
  95. w.print(TypeDataStore.class.getName());
  96. w.println(" store) {");
  97. w.indent();
  98. if (!isEager) {
  99. w.print(GWT.class.getName());
  100. w.print(".runAsync(");
  101. }
  102. w.print("new ");
  103. w.print(TypeDataBundle.class.getName());
  104. w.println("(getName()) {");
  105. w.indent();
  106. w.println("public void load() {");
  107. w.indent();
  108. printBundleData(w, bundle);
  109. // Close load method
  110. w.outdent();
  111. w.println("}");
  112. // Close new TypeDataBundle() {}
  113. w.outdent();
  114. w.print("}");
  115. if (isEager) {
  116. w.println(".onSuccess();");
  117. } else {
  118. w.println(");");
  119. }
  120. // Close load method
  121. w.outdent();
  122. w.println("}");
  123. // Close add(new ...
  124. w.outdent();
  125. w.println("});");
  126. }
  127. w.outdent();
  128. w.println("}");
  129. w.commit(logger);
  130. }
  131. private void printBundleData(SourceWriter w, ConnectorBundle bundle) {
  132. writeIdentifiers(w, bundle);
  133. writeGwtConstructors(w, bundle);
  134. writeReturnTypes(w, bundle);
  135. }
  136. private void writeReturnTypes(SourceWriter w, ConnectorBundle bundle) {
  137. Map<JClassType, Set<JMethod>> methodReturnTypes = bundle
  138. .getMethodReturnTypes();
  139. for (Entry<JClassType, Set<JMethod>> entry : methodReturnTypes
  140. .entrySet()) {
  141. JClassType type = entry.getKey();
  142. Set<JMethod> methods = entry.getValue();
  143. for (JMethod method : methods) {
  144. // setReturnType(Class<?> type, String methodName, Type
  145. // returnType)
  146. w.print("store.setReturnType(");
  147. printClassLiteral(w, type);
  148. w.print(", \"");
  149. w.print(method.getName());
  150. w.print("\", ");
  151. GeneratedRpcMethodProviderGenerator.writeTypeCreator(w,
  152. method.getReturnType());
  153. w.println(");");
  154. }
  155. }
  156. }
  157. private void writeGwtConstructors(SourceWriter w, ConnectorBundle bundle) {
  158. Set<JClassType> constructors = bundle.getGwtConstructors();
  159. for (JClassType type : constructors) {
  160. w.print("store.setConstructor(");
  161. printClassLiteral(w, type);
  162. w.print(", new Invoker() {");
  163. w.indent();
  164. w.println("public Object invoke(Object target, Object[] params) {");
  165. w.indent();
  166. w.print("return ");
  167. w.print(GWT.class.getName());
  168. w.print(".create(");
  169. printClassLiteral(w, type);
  170. w.println(");");
  171. w.outdent();
  172. w.println("}");
  173. w.outdent();
  174. w.println("});");
  175. }
  176. }
  177. private void printClassLiteral(SourceWriter w, JClassType type) {
  178. w.print(type.getQualifiedSourceName());
  179. w.print(".class");
  180. }
  181. private void writeIdentifiers(SourceWriter w, ConnectorBundle bundle) {
  182. Map<JClassType, Set<String>> identifiers = bundle.getIdentifiers();
  183. for (Entry<JClassType, Set<String>> entry : identifiers.entrySet()) {
  184. Set<String> ids = entry.getValue();
  185. JClassType type = entry.getKey();
  186. for (String id : ids) {
  187. w.print("store.setClass(\"");
  188. w.print(escape(id));
  189. w.print("\", ");
  190. printClassLiteral(w, type);
  191. w.println(");");
  192. }
  193. }
  194. }
  195. private List<ConnectorBundle> buildBundles(TreeLogger logger,
  196. TypeOracle typeOracle) throws NotFoundException,
  197. UnableToCompleteException {
  198. Map<LoadStyle, Collection<JClassType>> connectorsByLoadStyle = new HashMap<LoadStyle, Collection<JClassType>>();
  199. for (LoadStyle loadStyle : LoadStyle.values()) {
  200. connectorsByLoadStyle.put(loadStyle, new ArrayList<JClassType>());
  201. }
  202. JClassType connectorType = typeOracle.getType(ServerConnector.class
  203. .getName());
  204. JClassType[] subtypes = connectorType.getSubtypes();
  205. for (JClassType connectorSubtype : subtypes) {
  206. if (!connectorSubtype.isAnnotationPresent(Connect.class)) {
  207. continue;
  208. }
  209. LoadStyle loadStyle = getLoadStyle(connectorSubtype);
  210. if (loadStyle != null) {
  211. connectorsByLoadStyle.get(loadStyle).add(connectorSubtype);
  212. }
  213. }
  214. List<ConnectorBundle> bundles = new ArrayList<ConnectorBundle>();
  215. Collection<TypeVisitor> visitors = getVisitors(typeOracle);
  216. ConnectorBundle eagerBundle = new ConnectorBundle(
  217. ConnectorBundleLoader.EAGER_BUNDLE_NAME, null);
  218. // Eager connectors and all RPC interfaces are loaded by default
  219. eagerBundle.visitTypes(logger,
  220. connectorsByLoadStyle.get(LoadStyle.EAGER), visitors);
  221. eagerBundle.visitSubTypes(logger,
  222. typeOracle.getType(ClientRpc.class.getName()), visitors);
  223. eagerBundle.visitSubTypes(logger,
  224. typeOracle.getType(ServerRpc.class.getName()), visitors);
  225. bundles.add(eagerBundle);
  226. ConnectorBundle deferredBundle = new ConnectorBundle(
  227. ConnectorBundleLoader.DEFERRED_BUNDLE_NAME, eagerBundle);
  228. deferredBundle.visitTypes(logger,
  229. connectorsByLoadStyle.get(LoadStyle.DEFERRED), visitors);
  230. bundles.add(deferredBundle);
  231. Collection<JClassType> lazy = connectorsByLoadStyle.get(LoadStyle.LAZY);
  232. for (JClassType type : lazy) {
  233. ConnectorBundle bundle = new ConnectorBundle(type.getName(),
  234. deferredBundle);
  235. bundle.visitTypes(logger, Collections.singleton(type), visitors);
  236. bundles.add(bundle);
  237. }
  238. return bundles;
  239. }
  240. private Collection<TypeVisitor> getVisitors(TypeOracle oracle)
  241. throws NotFoundException {
  242. List<TypeVisitor> visitors = Arrays.<TypeVisitor> asList(
  243. new ConnectorInitVisitor(), new StateInitVisitor(),
  244. new WidgetInitVisitor());
  245. for (TypeVisitor typeVisitor : visitors) {
  246. typeVisitor.init(oracle);
  247. }
  248. return visitors;
  249. }
  250. protected LoadStyle getLoadStyle(JClassType connectorType) {
  251. Connect annotation = connectorType.getAnnotation(Connect.class);
  252. return annotation.loadStyle();
  253. }
  254. }