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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759
  1. /*
  2. @VaadinApache2LicenseForJavaFiles@
  3. */
  4. package com.vaadin.server.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.HashSet;
  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.JParameterizedType;
  24. import com.google.gwt.core.ext.typeinfo.JType;
  25. import com.google.gwt.core.ext.typeinfo.NotFoundException;
  26. import com.google.gwt.core.ext.typeinfo.TypeOracle;
  27. import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
  28. import com.google.gwt.user.rebind.SourceWriter;
  29. import com.vaadin.client.ServerConnector;
  30. import com.vaadin.client.metadata.ConnectorBundleLoader;
  31. import com.vaadin.client.metadata.InvokationHandler;
  32. import com.vaadin.client.metadata.ProxyHandler;
  33. import com.vaadin.client.metadata.TypeData;
  34. import com.vaadin.client.metadata.TypeDataBundle;
  35. import com.vaadin.client.metadata.TypeDataStore;
  36. import com.vaadin.client.ui.UnknownComponentConnector;
  37. import com.vaadin.server.widgetsetutils.metadata.ClientRpcVisitor;
  38. import com.vaadin.server.widgetsetutils.metadata.ConnectorBundle;
  39. import com.vaadin.server.widgetsetutils.metadata.ConnectorInitVisitor;
  40. import com.vaadin.server.widgetsetutils.metadata.GeneratedSerializer;
  41. import com.vaadin.server.widgetsetutils.metadata.Property;
  42. import com.vaadin.server.widgetsetutils.metadata.ServerRpcVisitor;
  43. import com.vaadin.server.widgetsetutils.metadata.StateInitVisitor;
  44. import com.vaadin.server.widgetsetutils.metadata.TypeVisitor;
  45. import com.vaadin.server.widgetsetutils.metadata.WidgetInitVisitor;
  46. import com.vaadin.shared.annotations.Delayed;
  47. import com.vaadin.shared.annotations.DelegateToWidget;
  48. import com.vaadin.shared.communication.ClientRpc;
  49. import com.vaadin.shared.communication.ServerRpc;
  50. import com.vaadin.shared.ui.Connect;
  51. import com.vaadin.shared.ui.Connect.LoadStyle;
  52. public class ConnectorBundleLoaderFactory extends Generator {
  53. @Override
  54. public String generate(TreeLogger logger, GeneratorContext context,
  55. String typeName) throws UnableToCompleteException {
  56. TypeOracle typeOracle = context.getTypeOracle();
  57. try {
  58. JClassType classType = typeOracle.getType(typeName);
  59. String packageName = classType.getPackage().getName();
  60. String className = classType.getSimpleSourceName() + "Impl";
  61. generateClass(logger, context, packageName, className, typeName);
  62. return packageName + "." + className;
  63. } catch (UnableToCompleteException e) {
  64. // Just rethrow
  65. throw e;
  66. } catch (Exception e) {
  67. logger.log(Type.ERROR, getClass() + " failed", e);
  68. throw new UnableToCompleteException();
  69. }
  70. }
  71. private void generateClass(TreeLogger logger, GeneratorContext context,
  72. String packageName, String className, String requestedType)
  73. throws Exception {
  74. PrintWriter printWriter = context.tryCreate(logger, packageName,
  75. className);
  76. if (printWriter == null) {
  77. return;
  78. }
  79. List<ConnectorBundle> bundles = buildBundles(logger,
  80. context.getTypeOracle());
  81. ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(
  82. packageName, className);
  83. composer.setSuperclass(requestedType);
  84. SourceWriter w = composer.createSourceWriter(context, printWriter);
  85. w.println("public void init() {");
  86. w.indent();
  87. for (ConnectorBundle bundle : bundles) {
  88. String name = bundle.getName();
  89. boolean isEager = name
  90. .equals(ConnectorBundleLoader.EAGER_BUNDLE_NAME);
  91. w.print("addAsyncBlockLoader(new AsyncBundleLoader(\"");
  92. w.print(escape(name));
  93. w.print("\", ");
  94. w.print("new String[] {");
  95. for (Entry<JClassType, Set<String>> entry : bundle.getIdentifiers()
  96. .entrySet()) {
  97. Set<String> identifiers = entry.getValue();
  98. for (String id : identifiers) {
  99. w.print("\"");
  100. w.print(escape(id));
  101. w.print("\",");
  102. }
  103. }
  104. w.println("}) {");
  105. w.indent();
  106. w.print("protected void load(final ");
  107. w.print(TypeDataStore.class.getName());
  108. w.println(" store) {");
  109. w.indent();
  110. if (!isEager) {
  111. w.print(GWT.class.getName());
  112. w.print(".runAsync(");
  113. }
  114. w.print("new ");
  115. w.print(TypeDataBundle.class.getName());
  116. w.println("(getName()) {");
  117. w.indent();
  118. w.println("public void load() {");
  119. w.indent();
  120. printBundleData(logger, w, bundle);
  121. // Close load method
  122. w.outdent();
  123. w.println("}");
  124. // Close new TypeDataBundle() {}
  125. w.outdent();
  126. w.print("}");
  127. if (isEager) {
  128. w.println(".onSuccess();");
  129. } else {
  130. w.println(");");
  131. }
  132. // Close load method
  133. w.outdent();
  134. w.println("}");
  135. // Close add(new ...
  136. w.outdent();
  137. w.println("});");
  138. }
  139. w.outdent();
  140. w.println("}");
  141. w.commit(logger);
  142. }
  143. private void printBundleData(TreeLogger logger, SourceWriter w,
  144. ConnectorBundle bundle) throws UnableToCompleteException {
  145. writeIdentifiers(w, bundle);
  146. writeGwtConstructors(w, bundle);
  147. writeReturnTypes(w, bundle);
  148. writeInvokers(w, bundle);
  149. writeParamTypes(w, bundle);
  150. writeProxys(w, bundle);
  151. wirteDelayedInfo(w, bundle);
  152. writeProperites(logger, w, bundle);
  153. writePropertyTypes(w, bundle);
  154. writeSetters(logger, w, bundle);
  155. writeGetters(logger, w, bundle);
  156. writeSerializers(logger, w, bundle);
  157. writeDelegateToWidget(logger, w, bundle);
  158. }
  159. private void writeDelegateToWidget(TreeLogger logger, SourceWriter w,
  160. ConnectorBundle bundle) {
  161. Set<Property> needsDelegateToWidget = bundle.getNeedsDelegateToWidget();
  162. for (Property property : needsDelegateToWidget) {
  163. w.println("store.setDelegateToWidget(%s, \"%s\", \"%s\");",
  164. getClassLiteralString(property.getBeanType()),
  165. property.getName(),
  166. property.getAnnotation(DelegateToWidget.class).value());
  167. }
  168. }
  169. private void writeSerializers(TreeLogger logger, SourceWriter w,
  170. ConnectorBundle bundle) throws UnableToCompleteException {
  171. Map<JType, GeneratedSerializer> serializers = bundle.getSerializers();
  172. for (Entry<JType, GeneratedSerializer> entry : serializers.entrySet()) {
  173. JType type = entry.getKey();
  174. GeneratedSerializer serializer = entry.getValue();
  175. w.print("store.setSerializerFactory(");
  176. writeClassLiteral(w, type);
  177. w.print(", ");
  178. w.println("new Invoker() {");
  179. w.indent();
  180. w.println("public Object invoke(Object target, Object[] params) {");
  181. w.indent();
  182. serializer.writeSerializerInstantiator(logger, w);
  183. w.outdent();
  184. w.println("}");
  185. w.outdent();
  186. w.print("}");
  187. w.println(");");
  188. }
  189. }
  190. private void writeGetters(TreeLogger logger, SourceWriter w,
  191. ConnectorBundle bundle) {
  192. Set<Property> properties = bundle.getNeedsSetter();
  193. for (Property property : properties) {
  194. w.print("store.setGetter(");
  195. writeClassLiteral(w, property.getBeanType());
  196. w.print(", \"");
  197. w.print(escape(property.getName()));
  198. w.println("\", new Invoker() {");
  199. w.indent();
  200. w.println("public Object invoke(Object bean, Object[] params) {");
  201. w.indent();
  202. property.writeGetterBody(logger, w, "bean");
  203. w.println();
  204. w.outdent();
  205. w.println("}");
  206. w.outdent();
  207. w.println("});");
  208. }
  209. }
  210. private void writeSetters(TreeLogger logger, SourceWriter w,
  211. ConnectorBundle bundle) {
  212. Set<Property> properties = bundle.getNeedsSetter();
  213. for (Property property : properties) {
  214. w.print("store.setSetter(");
  215. writeClassLiteral(w, property.getBeanType());
  216. w.print(", \"");
  217. w.print(escape(property.getName()));
  218. w.println("\", new Invoker() {");
  219. w.indent();
  220. w.println("public Object invoke(Object bean, Object[] params) {");
  221. w.indent();
  222. property.writeSetterBody(logger, w, "bean", "params[0]");
  223. w.println("return null;");
  224. w.outdent();
  225. w.println("}");
  226. w.outdent();
  227. w.println("});");
  228. }
  229. }
  230. private void writePropertyTypes(SourceWriter w, ConnectorBundle bundle) {
  231. Set<Property> properties = bundle.getNeedsType();
  232. for (Property property : properties) {
  233. w.print("store.setPropertyType(");
  234. writeClassLiteral(w, property.getBeanType());
  235. w.print(", \"");
  236. w.print(escape(property.getName()));
  237. w.print("\", ");
  238. writeTypeCreator(w, property.getPropertyType());
  239. w.println(");");
  240. }
  241. }
  242. private void writeProperites(TreeLogger logger, SourceWriter w,
  243. ConnectorBundle bundle) throws UnableToCompleteException {
  244. Set<JClassType> needsPropertyListing = bundle.getNeedsPropertyListing();
  245. for (JClassType type : needsPropertyListing) {
  246. w.print("store.setProperties(");
  247. writeClassLiteral(w, type);
  248. w.print(", new String[] {");
  249. Set<String> usedPropertyNames = new HashSet<String>();
  250. Collection<Property> properties = bundle.getProperties(type);
  251. for (Property property : properties) {
  252. String name = property.getName();
  253. if (!usedPropertyNames.add(name)) {
  254. logger.log(
  255. Type.ERROR,
  256. type.getQualifiedSourceName()
  257. + " has multiple properties with the name "
  258. + name
  259. + ". This can happen if there are multiple setters with identical names exect casing.");
  260. throw new UnableToCompleteException();
  261. }
  262. w.print("\"");
  263. w.print(name);
  264. w.print("\", ");
  265. }
  266. w.println("});");
  267. }
  268. }
  269. private void wirteDelayedInfo(SourceWriter w, ConnectorBundle bundle) {
  270. Map<JClassType, Set<JMethod>> needsDelayedInfo = bundle
  271. .getNeedsDelayedInfo();
  272. Set<Entry<JClassType, Set<JMethod>>> entrySet = needsDelayedInfo
  273. .entrySet();
  274. for (Entry<JClassType, Set<JMethod>> entry : entrySet) {
  275. JClassType type = entry.getKey();
  276. Set<JMethod> methods = entry.getValue();
  277. for (JMethod method : methods) {
  278. Delayed annotation = method.getAnnotation(Delayed.class);
  279. if (annotation != null) {
  280. w.print("store.setDelayed(");
  281. writeClassLiteral(w, type);
  282. w.print(", \"");
  283. w.print(escape(method.getName()));
  284. w.println("\");");
  285. if (annotation.lastonly()) {
  286. w.print("store.setLastonly(");
  287. writeClassLiteral(w, type);
  288. w.print(", \"");
  289. w.print(escape(method.getName()));
  290. w.println("\");");
  291. }
  292. }
  293. }
  294. }
  295. }
  296. private void writeProxys(SourceWriter w, ConnectorBundle bundle) {
  297. Set<JClassType> needsProxySupport = bundle.getNeedsProxySupport();
  298. for (JClassType type : needsProxySupport) {
  299. w.print("store.setProxyHandler(");
  300. writeClassLiteral(w, type);
  301. w.print(", new ");
  302. w.print(ProxyHandler.class.getCanonicalName());
  303. w.println("() {");
  304. w.indent();
  305. w.println("public Object createProxy(final "
  306. + InvokationHandler.class.getName() + " handler) {");
  307. w.indent();
  308. w.print("return new ");
  309. w.print(type.getQualifiedSourceName());
  310. w.println("() {");
  311. w.indent();
  312. JMethod[] methods = type.getOverridableMethods();
  313. for (JMethod method : methods) {
  314. if (method.isAbstract()) {
  315. w.print("public ");
  316. w.print(method.getReturnType().getQualifiedSourceName());
  317. w.print(" ");
  318. w.print(method.getName());
  319. w.print("(");
  320. JType[] types = method.getParameterTypes();
  321. for (int i = 0; i < types.length; i++) {
  322. if (i != 0) {
  323. w.print(", ");
  324. }
  325. w.print(types[i].getQualifiedSourceName());
  326. w.print(" p");
  327. w.print(Integer.toString(i));
  328. }
  329. w.println(") {");
  330. w.indent();
  331. if (!method.getReturnType().getQualifiedSourceName()
  332. .equals("void")) {
  333. w.print("return ");
  334. }
  335. w.print("handler.invoke(this, ");
  336. w.print(TypeData.class.getCanonicalName());
  337. w.print(".getType(");
  338. writeClassLiteral(w, type);
  339. w.print(").getMethod(\"");
  340. w.print(escape(method.getName()));
  341. w.print("\"), new Object [] {");
  342. for (int i = 0; i < types.length; i++) {
  343. w.print("p" + i + ", ");
  344. }
  345. w.println("});");
  346. w.outdent();
  347. w.println("}");
  348. }
  349. }
  350. w.outdent();
  351. w.println("};");
  352. w.outdent();
  353. w.println("}");
  354. w.outdent();
  355. w.println("});");
  356. }
  357. }
  358. private void writeParamTypes(SourceWriter w, ConnectorBundle bundle) {
  359. Map<JClassType, Set<JMethod>> needsParamTypes = bundle
  360. .getNeedsParamTypes();
  361. for (Entry<JClassType, Set<JMethod>> entry : needsParamTypes.entrySet()) {
  362. JClassType type = entry.getKey();
  363. Set<JMethod> methods = entry.getValue();
  364. for (JMethod method : methods) {
  365. w.print("store.setParamTypes(");
  366. writeClassLiteral(w, type);
  367. w.print(", \"");
  368. w.print(escape(method.getName()));
  369. w.print("\", new Type[] {");
  370. for (JType parameter : method.getParameterTypes()) {
  371. ConnectorBundleLoaderFactory.writeTypeCreator(w, parameter);
  372. w.print(", ");
  373. }
  374. w.println("});");
  375. }
  376. }
  377. }
  378. private void writeInvokers(SourceWriter w, ConnectorBundle bundle) {
  379. Map<JClassType, Set<JMethod>> needsInvoker = bundle.getNeedsInvoker();
  380. for (Entry<JClassType, Set<JMethod>> entry : needsInvoker.entrySet()) {
  381. JClassType type = entry.getKey();
  382. Set<JMethod> methods = entry.getValue();
  383. for (JMethod method : methods) {
  384. w.print("store.setInvoker(");
  385. writeClassLiteral(w, type);
  386. w.print(", \"");
  387. w.print(escape(method.getName()));
  388. w.println("\", new Invoker() {");
  389. w.indent();
  390. w.println("public Object invoke(Object target, Object[] params) {");
  391. w.indent();
  392. JType returnType = method.getReturnType();
  393. boolean hasReturnType = !"void".equals(returnType
  394. .getQualifiedSourceName());
  395. if (hasReturnType) {
  396. w.print("return ");
  397. }
  398. JType[] parameterTypes = method.getParameterTypes();
  399. w.print("((" + type.getQualifiedSourceName() + ") target)."
  400. + method.getName() + "(");
  401. for (int i = 0; i < parameterTypes.length; i++) {
  402. JType parameterType = parameterTypes[i];
  403. if (i != 0) {
  404. w.print(", ");
  405. }
  406. String parameterTypeName = getBoxedTypeName(parameterType);
  407. w.print("(" + parameterTypeName + ") params[" + i + "]");
  408. }
  409. w.println(");");
  410. if (!hasReturnType) {
  411. w.println("return null;");
  412. }
  413. w.outdent();
  414. w.println("}");
  415. w.outdent();
  416. w.println("});");
  417. }
  418. }
  419. }
  420. private void writeReturnTypes(SourceWriter w, ConnectorBundle bundle) {
  421. Map<JClassType, Set<JMethod>> methodReturnTypes = bundle
  422. .getMethodReturnTypes();
  423. for (Entry<JClassType, Set<JMethod>> entry : methodReturnTypes
  424. .entrySet()) {
  425. JClassType type = entry.getKey();
  426. Set<JMethod> methods = entry.getValue();
  427. for (JMethod method : methods) {
  428. // setReturnType(Class<?> type, String methodName, Type
  429. // returnType)
  430. w.print("store.setReturnType(");
  431. writeClassLiteral(w, type);
  432. w.print(", \"");
  433. w.print(escape(method.getName()));
  434. w.print("\", ");
  435. writeTypeCreator(w, method.getReturnType());
  436. w.println(");");
  437. }
  438. }
  439. }
  440. private void writeGwtConstructors(SourceWriter w, ConnectorBundle bundle) {
  441. Set<JClassType> constructors = bundle.getGwtConstructors();
  442. for (JClassType type : constructors) {
  443. w.print("store.setConstructor(");
  444. writeClassLiteral(w, type);
  445. w.println(", new Invoker() {");
  446. w.indent();
  447. w.println("public Object invoke(Object target, Object[] params) {");
  448. w.indent();
  449. w.print("return ");
  450. w.print(GWT.class.getName());
  451. w.print(".create(");
  452. writeClassLiteral(w, type);
  453. w.println(");");
  454. w.outdent();
  455. w.println("}");
  456. w.outdent();
  457. w.println("});");
  458. }
  459. }
  460. public static void writeClassLiteral(SourceWriter w, JType type) {
  461. w.print(getClassLiteralString(type));
  462. }
  463. public static String getClassLiteralString(JType type) {
  464. return type.getQualifiedSourceName() + ".class";
  465. }
  466. private void writeIdentifiers(SourceWriter w, ConnectorBundle bundle) {
  467. Map<JClassType, Set<String>> identifiers = bundle.getIdentifiers();
  468. for (Entry<JClassType, Set<String>> entry : identifiers.entrySet()) {
  469. Set<String> ids = entry.getValue();
  470. JClassType type = entry.getKey();
  471. for (String id : ids) {
  472. w.print("store.setClass(\"");
  473. w.print(escape(id));
  474. w.print("\", ");
  475. writeClassLiteral(w, type);
  476. w.println(");");
  477. }
  478. }
  479. }
  480. private List<ConnectorBundle> buildBundles(TreeLogger logger,
  481. TypeOracle typeOracle) throws NotFoundException,
  482. UnableToCompleteException {
  483. Map<LoadStyle, Collection<JClassType>> connectorsByLoadStyle = new HashMap<LoadStyle, Collection<JClassType>>();
  484. for (LoadStyle loadStyle : LoadStyle.values()) {
  485. connectorsByLoadStyle.put(loadStyle, new ArrayList<JClassType>());
  486. }
  487. JClassType connectorType = typeOracle.getType(ServerConnector.class
  488. .getName());
  489. JClassType[] subtypes = connectorType.getSubtypes();
  490. // Find all types with a valid mapping
  491. Collection<JClassType> selectedTypes = getMappedTypes(logger, subtypes);
  492. // Group by load style
  493. for (JClassType connectorSubtype : selectedTypes) {
  494. LoadStyle loadStyle = getLoadStyle(connectorSubtype);
  495. if (loadStyle != null) {
  496. connectorsByLoadStyle.get(loadStyle).add(connectorSubtype);
  497. }
  498. }
  499. List<ConnectorBundle> bundles = new ArrayList<ConnectorBundle>();
  500. Collection<TypeVisitor> visitors = getVisitors(typeOracle);
  501. ConnectorBundle eagerBundle = new ConnectorBundle(
  502. ConnectorBundleLoader.EAGER_BUNDLE_NAME, visitors, typeOracle);
  503. TreeLogger eagerLogger = logger.branch(Type.TRACE,
  504. "Populating eager bundle");
  505. // Eager connectors and all RPC interfaces are loaded by default
  506. eagerBundle.processTypes(eagerLogger,
  507. connectorsByLoadStyle.get(LoadStyle.EAGER));
  508. eagerBundle.processType(eagerLogger, typeOracle
  509. .findType(UnknownComponentConnector.class.getCanonicalName()));
  510. eagerBundle.processSubTypes(eagerLogger,
  511. typeOracle.getType(ClientRpc.class.getName()));
  512. eagerBundle.processSubTypes(eagerLogger,
  513. typeOracle.getType(ServerRpc.class.getName()));
  514. bundles.add(eagerBundle);
  515. ConnectorBundle deferredBundle = new ConnectorBundle(
  516. ConnectorBundleLoader.DEFERRED_BUNDLE_NAME, eagerBundle);
  517. TreeLogger deferredLogger = logger.branch(Type.TRACE,
  518. "Populating deferred bundle");
  519. deferredBundle.processTypes(deferredLogger,
  520. connectorsByLoadStyle.get(LoadStyle.DEFERRED));
  521. bundles.add(deferredBundle);
  522. Collection<JClassType> lazy = connectorsByLoadStyle.get(LoadStyle.LAZY);
  523. for (JClassType type : lazy) {
  524. ConnectorBundle bundle = new ConnectorBundle(type.getName(),
  525. eagerBundle);
  526. TreeLogger subLogger = logger.branch(Type.TRACE, "Populating "
  527. + type.getName() + " bundle");
  528. bundle.processType(subLogger, type);
  529. bundles.add(bundle);
  530. }
  531. return bundles;
  532. }
  533. private Collection<JClassType> getMappedTypes(TreeLogger logger,
  534. JClassType[] types) throws UnableToCompleteException {
  535. Map<String, JClassType> mappings = new HashMap<String, JClassType>();
  536. // Keep track of what has happened to avoid logging intermediate state
  537. Map<JClassType, List<JClassType>> replaced = new HashMap<JClassType, List<JClassType>>();
  538. for (JClassType type : types) {
  539. Connect connectAnnotation = type.getAnnotation(Connect.class);
  540. if (connectAnnotation == null) {
  541. continue;
  542. }
  543. String identifier = connectAnnotation.value().getCanonicalName();
  544. JClassType previousMapping = mappings.put(identifier, type);
  545. if (previousMapping != null) {
  546. // There are multiple mappings, pick the subclass
  547. JClassType subclass;
  548. JClassType superclass;
  549. if (previousMapping.isAssignableFrom(type)) {
  550. subclass = type;
  551. superclass = previousMapping;
  552. } else if (type.isAssignableFrom(previousMapping)) {
  553. subclass = previousMapping;
  554. superclass = type;
  555. } else {
  556. // Neither inherits from the other - this is a conflict
  557. logger.log(
  558. Type.ERROR,
  559. "Conflicting @Connect mappings detected for "
  560. + identifier
  561. + ": "
  562. + type.getQualifiedSourceName()
  563. + " and "
  564. + previousMapping.getQualifiedSourceName()
  565. + ". There can only be multiple @Connect mappings for the same server-side type if one is the subclass of the other.");
  566. throw new UnableToCompleteException();
  567. }
  568. mappings.put(identifier, subclass);
  569. // Inherit any previous replacements
  570. List<JClassType> previousReplacements = replaced
  571. .remove(superclass);
  572. if (previousReplacements == null) {
  573. previousReplacements = new ArrayList<JClassType>();
  574. }
  575. previousReplacements.add(superclass);
  576. replaced.put(subclass, previousReplacements);
  577. }
  578. }
  579. // Log the final set of replacements
  580. for (Entry<JClassType, List<JClassType>> entry : replaced.entrySet()) {
  581. String msg = entry.getKey().getQualifiedSourceName() + " replaces ";
  582. List<JClassType> list = entry.getValue();
  583. for (int i = 0; i < list.size(); i++) {
  584. if (i != 0) {
  585. msg += ", ";
  586. }
  587. msg += list.get(i).getQualifiedSourceName();
  588. }
  589. logger.log(Type.INFO, msg);
  590. }
  591. // Return the types of the final mapping
  592. return mappings.values();
  593. }
  594. private Collection<TypeVisitor> getVisitors(TypeOracle oracle)
  595. throws NotFoundException {
  596. List<TypeVisitor> visitors = Arrays.<TypeVisitor> asList(
  597. new ConnectorInitVisitor(), new StateInitVisitor(),
  598. new WidgetInitVisitor(), new ClientRpcVisitor(),
  599. new ServerRpcVisitor());
  600. for (TypeVisitor typeVisitor : visitors) {
  601. typeVisitor.init(oracle);
  602. }
  603. return visitors;
  604. }
  605. protected LoadStyle getLoadStyle(JClassType connectorType) {
  606. Connect annotation = connectorType.getAnnotation(Connect.class);
  607. return annotation.loadStyle();
  608. }
  609. public static String getBoxedTypeName(JType type) {
  610. if (type.isPrimitive() != null) {
  611. // Used boxed types for primitives
  612. return type.isPrimitive().getQualifiedBoxedSourceName();
  613. } else {
  614. return type.getErasedType().getQualifiedSourceName();
  615. }
  616. }
  617. public static void writeTypeCreator(SourceWriter sourceWriter, JType type) {
  618. String typeName = ConnectorBundleLoaderFactory.getBoxedTypeName(type);
  619. JParameterizedType parameterized = type.isParameterized();
  620. if (parameterized != null) {
  621. sourceWriter.print("new Type(\"" + typeName + "\", ");
  622. sourceWriter.print("new Type[] {");
  623. JClassType[] typeArgs = parameterized.getTypeArgs();
  624. for (JClassType jClassType : typeArgs) {
  625. writeTypeCreator(sourceWriter, jClassType);
  626. sourceWriter.print(", ");
  627. }
  628. sourceWriter.print("}");
  629. } else {
  630. sourceWriter.print("new Type(" + typeName + ".class");
  631. }
  632. sourceWriter.print(")");
  633. }
  634. }