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 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  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.HashMap;
  10. import java.util.List;
  11. import java.util.Map;
  12. import java.util.Map.Entry;
  13. import java.util.Set;
  14. import com.google.gwt.core.client.GWT;
  15. import com.google.gwt.core.ext.Generator;
  16. import com.google.gwt.core.ext.GeneratorContext;
  17. import com.google.gwt.core.ext.TreeLogger;
  18. import com.google.gwt.core.ext.TreeLogger.Type;
  19. import com.google.gwt.core.ext.UnableToCompleteException;
  20. import com.google.gwt.core.ext.typeinfo.JClassType;
  21. import com.google.gwt.core.ext.typeinfo.JMethod;
  22. import com.google.gwt.core.ext.typeinfo.JParameterizedType;
  23. import com.google.gwt.core.ext.typeinfo.JType;
  24. import com.google.gwt.core.ext.typeinfo.NotFoundException;
  25. import com.google.gwt.core.ext.typeinfo.TypeOracle;
  26. import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
  27. import com.google.gwt.user.rebind.SourceWriter;
  28. import com.vaadin.shared.annotations.Delayed;
  29. import com.vaadin.shared.communication.ClientRpc;
  30. import com.vaadin.shared.communication.ServerRpc;
  31. import com.vaadin.shared.ui.Connect;
  32. import com.vaadin.shared.ui.Connect.LoadStyle;
  33. import com.vaadin.terminal.gwt.client.ServerConnector;
  34. import com.vaadin.terminal.gwt.client.metadata.ConnectorBundleLoader;
  35. import com.vaadin.terminal.gwt.client.metadata.InvokationHandler;
  36. import com.vaadin.terminal.gwt.client.metadata.ProxyHandler;
  37. import com.vaadin.terminal.gwt.client.metadata.TypeData;
  38. import com.vaadin.terminal.gwt.client.metadata.TypeDataBundle;
  39. import com.vaadin.terminal.gwt.client.metadata.TypeDataStore;
  40. import com.vaadin.terminal.gwt.widgetsetutils.metadata.ClientRpcVisitor;
  41. import com.vaadin.terminal.gwt.widgetsetutils.metadata.ConnectorBundle;
  42. import com.vaadin.terminal.gwt.widgetsetutils.metadata.ConnectorInitVisitor;
  43. import com.vaadin.terminal.gwt.widgetsetutils.metadata.ServerRpcVisitor;
  44. import com.vaadin.terminal.gwt.widgetsetutils.metadata.StateInitVisitor;
  45. import com.vaadin.terminal.gwt.widgetsetutils.metadata.TypeVisitor;
  46. import com.vaadin.terminal.gwt.widgetsetutils.metadata.WidgetInitVisitor;
  47. public class ConnectorBundleLoaderFactory extends Generator {
  48. @Override
  49. public String generate(TreeLogger logger, GeneratorContext context,
  50. String typeName) throws UnableToCompleteException {
  51. TypeOracle typeOracle = context.getTypeOracle();
  52. try {
  53. JClassType classType = typeOracle.getType(typeName);
  54. String packageName = classType.getPackage().getName();
  55. String className = classType.getSimpleSourceName() + "Impl";
  56. generateClass(logger, context, packageName, className, typeName);
  57. return packageName + "." + className;
  58. } catch (UnableToCompleteException e) {
  59. // Just rethrow
  60. throw e;
  61. } catch (Exception e) {
  62. logger.log(Type.ERROR, getClass() + " failed", e);
  63. throw new UnableToCompleteException();
  64. }
  65. }
  66. private void generateClass(TreeLogger logger, GeneratorContext context,
  67. String packageName, String className, String requestedType)
  68. throws Exception {
  69. PrintWriter printWriter = context.tryCreate(logger, packageName,
  70. className);
  71. if (printWriter == null) {
  72. return;
  73. }
  74. List<ConnectorBundle> bundles = buildBundles(logger,
  75. context.getTypeOracle());
  76. ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(
  77. packageName, className);
  78. composer.setSuperclass(requestedType);
  79. SourceWriter w = composer.createSourceWriter(context, printWriter);
  80. w.println("public void init() {");
  81. w.indent();
  82. for (ConnectorBundle bundle : bundles) {
  83. String name = bundle.getName();
  84. boolean isEager = name
  85. .equals(ConnectorBundleLoader.EAGER_BUNDLE_NAME);
  86. w.print("addAsyncBlockLoader(new AsyncBundleLoader(\"");
  87. w.print(escape(name));
  88. w.print("\", ");
  89. w.print("new String[] {");
  90. for (Entry<JClassType, Set<String>> entry : bundle.getIdentifiers()
  91. .entrySet()) {
  92. Set<String> identifiers = entry.getValue();
  93. for (String id : identifiers) {
  94. w.print("\"");
  95. w.print(escape(id));
  96. w.print("\",");
  97. }
  98. }
  99. w.println("}) {");
  100. w.indent();
  101. w.print("protected void load(final ");
  102. w.print(TypeDataStore.class.getName());
  103. w.println(" store) {");
  104. w.indent();
  105. if (!isEager) {
  106. w.print(GWT.class.getName());
  107. w.print(".runAsync(");
  108. }
  109. w.print("new ");
  110. w.print(TypeDataBundle.class.getName());
  111. w.println("(getName()) {");
  112. w.indent();
  113. w.println("public void load() {");
  114. w.indent();
  115. printBundleData(w, bundle);
  116. // Close load method
  117. w.outdent();
  118. w.println("}");
  119. // Close new TypeDataBundle() {}
  120. w.outdent();
  121. w.print("}");
  122. if (isEager) {
  123. w.println(".onSuccess();");
  124. } else {
  125. w.println(");");
  126. }
  127. // Close load method
  128. w.outdent();
  129. w.println("}");
  130. // Close add(new ...
  131. w.outdent();
  132. w.println("});");
  133. }
  134. w.outdent();
  135. w.println("}");
  136. w.commit(logger);
  137. }
  138. private void printBundleData(SourceWriter w, ConnectorBundle bundle) {
  139. writeIdentifiers(w, bundle);
  140. writeGwtConstructors(w, bundle);
  141. writeReturnTypes(w, bundle);
  142. writeInvokers(w, bundle);
  143. writeParamTypes(w, bundle);
  144. writeProxys(w, bundle);
  145. wirteDelayedInfo(w, bundle);
  146. }
  147. private void wirteDelayedInfo(SourceWriter w, ConnectorBundle bundle) {
  148. Map<JClassType, Set<JMethod>> needsDelayedInfo = bundle
  149. .getNeedsDelayedInfo();
  150. Set<Entry<JClassType, Set<JMethod>>> entrySet = needsDelayedInfo
  151. .entrySet();
  152. for (Entry<JClassType, Set<JMethod>> entry : entrySet) {
  153. JClassType type = entry.getKey();
  154. Set<JMethod> methods = entry.getValue();
  155. for (JMethod method : methods) {
  156. Delayed annotation = method.getAnnotation(Delayed.class);
  157. if (annotation != null) {
  158. w.print("store.setDelayed(");
  159. printClassLiteral(w, type);
  160. w.print(", \"");
  161. w.print(escape(method.getName()));
  162. w.println("\");");
  163. if (annotation.lastonly()) {
  164. w.print("store.setLastonly(");
  165. printClassLiteral(w, type);
  166. w.print(", \"");
  167. w.print(escape(method.getName()));
  168. w.println("\");");
  169. }
  170. }
  171. }
  172. }
  173. }
  174. private void writeProxys(SourceWriter w, ConnectorBundle bundle) {
  175. Set<JClassType> needsProxySupport = bundle.getNeedsProxySupport();
  176. for (JClassType type : needsProxySupport) {
  177. w.print("store.setProxyHandler(");
  178. printClassLiteral(w, type);
  179. w.print(", new ");
  180. w.print(ProxyHandler.class.getCanonicalName());
  181. w.println("() {");
  182. w.indent();
  183. w.println("public Object createProxy(final "
  184. + InvokationHandler.class.getName() + " handler) {");
  185. w.indent();
  186. w.print("return new ");
  187. w.print(type.getQualifiedSourceName());
  188. w.println("() {");
  189. w.indent();
  190. JMethod[] methods = type.getOverridableMethods();
  191. for (JMethod method : methods) {
  192. if (method.isAbstract()) {
  193. w.print("public ");
  194. w.print(method.getReturnType().getQualifiedSourceName());
  195. w.print(" ");
  196. w.print(method.getName());
  197. w.print("(");
  198. JType[] types = method.getParameterTypes();
  199. for (int i = 0; i < types.length; i++) {
  200. if (i != 0) {
  201. w.print(", ");
  202. }
  203. w.print(types[i].getQualifiedSourceName());
  204. w.print(" p");
  205. w.print(Integer.toString(i));
  206. }
  207. w.println(") {");
  208. w.indent();
  209. if (!method.getReturnType().getQualifiedSourceName()
  210. .equals("void")) {
  211. w.print("return ");
  212. }
  213. w.print("handler.invoke(this, ");
  214. w.print(TypeData.class.getCanonicalName());
  215. w.print(".getType(");
  216. printClassLiteral(w, type);
  217. w.print(").getMethod(\"");
  218. w.print(escape(method.getName()));
  219. w.print("\"), new Object [] {");
  220. for (int i = 0; i < types.length; i++) {
  221. w.print("p" + i + ", ");
  222. }
  223. w.println("});");
  224. w.outdent();
  225. w.println("}");
  226. }
  227. }
  228. w.outdent();
  229. w.println("};");
  230. w.outdent();
  231. w.println("}");
  232. w.outdent();
  233. w.println("});");
  234. }
  235. }
  236. private void writeParamTypes(SourceWriter w, ConnectorBundle bundle) {
  237. Map<JClassType, Set<JMethod>> needsParamTypes = bundle
  238. .getNeedsParamTypes();
  239. for (Entry<JClassType, Set<JMethod>> entry : needsParamTypes.entrySet()) {
  240. JClassType type = entry.getKey();
  241. Set<JMethod> methods = entry.getValue();
  242. for (JMethod method : methods) {
  243. w.print("store.setParamTypes(");
  244. printClassLiteral(w, type);
  245. w.print(", \"");
  246. w.print(escape(method.getName()));
  247. w.print("\", new Type[] {");
  248. for (JType parameter : method.getParameterTypes()) {
  249. ConnectorBundleLoaderFactory.writeTypeCreator(w, parameter);
  250. w.print(", ");
  251. }
  252. w.println("});");
  253. }
  254. }
  255. }
  256. private void writeInvokers(SourceWriter w, ConnectorBundle bundle) {
  257. Map<JClassType, Set<JMethod>> needsInvoker = bundle.getNeedsInvoker();
  258. for (Entry<JClassType, Set<JMethod>> entry : needsInvoker.entrySet()) {
  259. JClassType type = entry.getKey();
  260. Set<JMethod> methods = entry.getValue();
  261. for (JMethod method : methods) {
  262. w.print("store.setInvoker(");
  263. printClassLiteral(w, type);
  264. w.print(", \"");
  265. w.print(escape(method.getName()));
  266. w.println("\", new Invoker() {");
  267. w.indent();
  268. w.println("public Object invoke(Object target, Object[] params) {");
  269. w.indent();
  270. JType returnType = method.getReturnType();
  271. boolean hasReturnType = !"void".equals(returnType
  272. .getQualifiedSourceName());
  273. if (hasReturnType) {
  274. w.print("return ");
  275. }
  276. JType[] parameterTypes = method.getParameterTypes();
  277. w.print("((" + type.getQualifiedSourceName() + ") target)."
  278. + method.getName() + "(");
  279. for (int i = 0; i < parameterTypes.length; i++) {
  280. JType parameterType = parameterTypes[i];
  281. if (i != 0) {
  282. w.print(", ");
  283. }
  284. String parameterTypeName = getBoxedTypeName(parameterType);
  285. w.print("(" + parameterTypeName + ") params[" + i + "]");
  286. }
  287. w.println(");");
  288. if (!hasReturnType) {
  289. w.println("return null;");
  290. }
  291. w.outdent();
  292. w.println("}");
  293. w.outdent();
  294. w.println("});");
  295. }
  296. }
  297. }
  298. private void writeReturnTypes(SourceWriter w, ConnectorBundle bundle) {
  299. Map<JClassType, Set<JMethod>> methodReturnTypes = bundle
  300. .getMethodReturnTypes();
  301. for (Entry<JClassType, Set<JMethod>> entry : methodReturnTypes
  302. .entrySet()) {
  303. JClassType type = entry.getKey();
  304. Set<JMethod> methods = entry.getValue();
  305. for (JMethod method : methods) {
  306. // setReturnType(Class<?> type, String methodName, Type
  307. // returnType)
  308. w.print("store.setReturnType(");
  309. printClassLiteral(w, type);
  310. w.print(", \"");
  311. w.print(escape(method.getName()));
  312. w.print("\", ");
  313. writeTypeCreator(w, method.getReturnType());
  314. w.println(");");
  315. }
  316. }
  317. }
  318. private void writeGwtConstructors(SourceWriter w, ConnectorBundle bundle) {
  319. Set<JClassType> constructors = bundle.getGwtConstructors();
  320. for (JClassType type : constructors) {
  321. w.print("store.setConstructor(");
  322. printClassLiteral(w, type);
  323. w.println(", new Invoker() {");
  324. w.indent();
  325. w.println("public Object invoke(Object target, Object[] params) {");
  326. w.indent();
  327. w.print("return ");
  328. w.print(GWT.class.getName());
  329. w.print(".create(");
  330. printClassLiteral(w, type);
  331. w.println(");");
  332. w.outdent();
  333. w.println("}");
  334. w.outdent();
  335. w.println("});");
  336. }
  337. }
  338. private void printClassLiteral(SourceWriter w, JClassType type) {
  339. w.print(type.getQualifiedSourceName());
  340. w.print(".class");
  341. }
  342. private void writeIdentifiers(SourceWriter w, ConnectorBundle bundle) {
  343. Map<JClassType, Set<String>> identifiers = bundle.getIdentifiers();
  344. for (Entry<JClassType, Set<String>> entry : identifiers.entrySet()) {
  345. Set<String> ids = entry.getValue();
  346. JClassType type = entry.getKey();
  347. for (String id : ids) {
  348. w.print("store.setClass(\"");
  349. w.print(escape(id));
  350. w.print("\", ");
  351. printClassLiteral(w, type);
  352. w.println(");");
  353. }
  354. }
  355. }
  356. private List<ConnectorBundle> buildBundles(TreeLogger logger,
  357. TypeOracle typeOracle) throws NotFoundException,
  358. UnableToCompleteException {
  359. Map<LoadStyle, Collection<JClassType>> connectorsByLoadStyle = new HashMap<LoadStyle, Collection<JClassType>>();
  360. for (LoadStyle loadStyle : LoadStyle.values()) {
  361. connectorsByLoadStyle.put(loadStyle, new ArrayList<JClassType>());
  362. }
  363. JClassType connectorType = typeOracle.getType(ServerConnector.class
  364. .getName());
  365. JClassType[] subtypes = connectorType.getSubtypes();
  366. for (JClassType connectorSubtype : subtypes) {
  367. if (!connectorSubtype.isAnnotationPresent(Connect.class)) {
  368. continue;
  369. }
  370. LoadStyle loadStyle = getLoadStyle(connectorSubtype);
  371. if (loadStyle != null) {
  372. connectorsByLoadStyle.get(loadStyle).add(connectorSubtype);
  373. }
  374. }
  375. List<ConnectorBundle> bundles = new ArrayList<ConnectorBundle>();
  376. Collection<TypeVisitor> visitors = getVisitors(typeOracle);
  377. ConnectorBundle eagerBundle = new ConnectorBundle(
  378. ConnectorBundleLoader.EAGER_BUNDLE_NAME, visitors);
  379. TreeLogger eagerLogger = logger.branch(Type.TRACE,
  380. "Populating eager bundle");
  381. // Eager connectors and all RPC interfaces are loaded by default
  382. eagerBundle.processTypes(eagerLogger,
  383. connectorsByLoadStyle.get(LoadStyle.EAGER));
  384. eagerBundle.processSubTypes(eagerLogger,
  385. typeOracle.getType(ClientRpc.class.getName()));
  386. eagerBundle.processSubTypes(eagerLogger,
  387. typeOracle.getType(ServerRpc.class.getName()));
  388. bundles.add(eagerBundle);
  389. ConnectorBundle deferredBundle = new ConnectorBundle(
  390. ConnectorBundleLoader.DEFERRED_BUNDLE_NAME, eagerBundle);
  391. TreeLogger deferredLogger = logger.branch(Type.TRACE,
  392. "Populating deferred bundle");
  393. deferredBundle.processTypes(deferredLogger,
  394. connectorsByLoadStyle.get(LoadStyle.DEFERRED));
  395. bundles.add(deferredBundle);
  396. Collection<JClassType> lazy = connectorsByLoadStyle.get(LoadStyle.LAZY);
  397. for (JClassType type : lazy) {
  398. ConnectorBundle bundle = new ConnectorBundle(type.getName(),
  399. eagerBundle);
  400. TreeLogger subLogger = logger.branch(Type.TRACE, "Populating "
  401. + type.getName() + " bundle");
  402. bundle.processType(subLogger, type);
  403. bundles.add(bundle);
  404. }
  405. return bundles;
  406. }
  407. private Collection<TypeVisitor> getVisitors(TypeOracle oracle)
  408. throws NotFoundException {
  409. List<TypeVisitor> visitors = Arrays.<TypeVisitor> asList(
  410. new ConnectorInitVisitor(), new StateInitVisitor(),
  411. new WidgetInitVisitor(), new ClientRpcVisitor(),
  412. new ServerRpcVisitor());
  413. for (TypeVisitor typeVisitor : visitors) {
  414. typeVisitor.init(oracle);
  415. }
  416. return visitors;
  417. }
  418. protected LoadStyle getLoadStyle(JClassType connectorType) {
  419. Connect annotation = connectorType.getAnnotation(Connect.class);
  420. return annotation.loadStyle();
  421. }
  422. public static String getBoxedTypeName(JType type) {
  423. if (type.isPrimitive() != null) {
  424. // Used boxed types for primitives
  425. return type.isPrimitive().getQualifiedBoxedSourceName();
  426. } else {
  427. return type.getErasedType().getQualifiedSourceName();
  428. }
  429. }
  430. public static void writeTypeCreator(SourceWriter sourceWriter, JType type) {
  431. String typeName = ConnectorBundleLoaderFactory.getBoxedTypeName(type);
  432. sourceWriter.print("new Type(\"" + typeName + "\", ");
  433. JParameterizedType parameterized = type.isParameterized();
  434. if (parameterized != null) {
  435. sourceWriter.print("new Type[] {");
  436. JClassType[] typeArgs = parameterized.getTypeArgs();
  437. for (JClassType jClassType : typeArgs) {
  438. writeTypeCreator(sourceWriter, jClassType);
  439. sourceWriter.print(", ");
  440. }
  441. sourceWriter.print("}");
  442. } else {
  443. sourceWriter.print("null");
  444. }
  445. sourceWriter.print(")");
  446. }
  447. }