summaryrefslogtreecommitdiffstats
path: root/client-compiler
diff options
context:
space:
mode:
authorLeif Åstrand <leif@vaadin.com>2012-08-17 18:11:54 +0300
committerLeif Åstrand <leif@vaadin.com>2012-08-22 19:25:30 +0300
commit1a7d126e358d92850a41060b06d53309f2ac58f0 (patch)
tree3ceca4be0eeeffcc59a0f19dd28d298f9238c9d2 /client-compiler
parent88776600733901f3f9891aa90a11a5aeb2b97ef4 (diff)
downloadvaadin-framework-1a7d126e358d92850a41060b06d53309f2ac58f0.tar.gz
vaadin-framework-1a7d126e358d92850a41060b06d53309f2ac58f0.zip
Initial ConnectorBundle implementation (#9371)
Diffstat (limited to 'client-compiler')
-rw-r--r--client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/ConnectorBundleLoaderFactory.java280
-rw-r--r--client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/GeneratedRpcMethodProviderGenerator.java2
-rw-r--r--client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java2
-rw-r--r--client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java2
-rw-r--r--client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorBundle.java116
-rw-r--r--client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorInitVisitor.java32
-rw-r--r--client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/TypeVisitor.java15
7 files changed, 446 insertions, 3 deletions
diff --git a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/ConnectorBundleLoaderFactory.java b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/ConnectorBundleLoaderFactory.java
new file mode 100644
index 0000000000..cb967dff86
--- /dev/null
+++ b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/ConnectorBundleLoaderFactory.java
@@ -0,0 +1,280 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.widgetsetutils;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.ext.Generator;
+import com.google.gwt.core.ext.GeneratorContext;
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.TreeLogger.Type;
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.NotFoundException;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
+import com.google.gwt.user.rebind.SourceWriter;
+import com.vaadin.shared.communication.ClientRpc;
+import com.vaadin.shared.communication.ServerRpc;
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.shared.ui.Connect.LoadStyle;
+import com.vaadin.terminal.gwt.client.ServerConnector;
+import com.vaadin.terminal.gwt.client.metadata.ConnectorBundleLoader;
+import com.vaadin.terminal.gwt.client.metadata.TypeDataBundle;
+import com.vaadin.terminal.gwt.client.metadata.TypeDataStore;
+import com.vaadin.terminal.gwt.widgetsetutils.metadata.ConnectorBundle;
+import com.vaadin.terminal.gwt.widgetsetutils.metadata.ConnectorInitVisitor;
+import com.vaadin.terminal.gwt.widgetsetutils.metadata.TypeVisitor;
+
+public class ConnectorBundleLoaderFactory extends Generator {
+
+ @Override
+ public String generate(TreeLogger logger, GeneratorContext context,
+ String typeName) throws UnableToCompleteException {
+ TypeOracle typeOracle = context.getTypeOracle();
+
+ try {
+ JClassType classType = typeOracle.getType(typeName);
+ String packageName = classType.getPackage().getName();
+ String className = classType.getSimpleSourceName() + "Impl";
+
+ generateClass(logger, context, packageName, className, typeName);
+
+ return packageName + "." + className;
+ } catch (UnableToCompleteException e) {
+ // Just rethrow
+ throw e;
+ } catch (Exception e) {
+ logger.log(Type.ERROR, getClass() + " failed", e);
+ throw new UnableToCompleteException();
+ }
+
+ }
+
+ private void generateClass(TreeLogger logger, GeneratorContext context,
+ String packageName, String className, String requestedType)
+ throws Exception {
+ PrintWriter printWriter = context.tryCreate(logger, packageName,
+ className);
+ if (printWriter == null) {
+ return;
+ }
+
+ List<ConnectorBundle> bundles = buildBundles(logger,
+ context.getTypeOracle());
+
+ ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(
+ packageName, className);
+ composer.setSuperclass(requestedType);
+
+ SourceWriter w = composer.createSourceWriter(context, printWriter);
+
+ w.println("public void init() {");
+ w.indent();
+
+ for (ConnectorBundle bundle : bundles) {
+ String name = bundle.getName();
+ boolean isEager = name
+ .equals(ConnectorBundleLoader.EAGER_BUNDLE_NAME);
+
+ w.print("addAsyncBlockLoader(new AsyncBundleLoader(\"");
+ w.print(escape(name));
+ w.print("\", ");
+
+ w.print("new String[] {");
+ for (Entry<JClassType, Set<String>> entry : bundle.getIdentifiers()
+ .entrySet()) {
+ Set<String> identifiers = entry.getValue();
+ for (String id : identifiers) {
+ w.print("\"");
+ w.print(escape(id));
+ w.print("\",");
+ }
+ }
+ w.println("}) {");
+ w.indent();
+
+ w.print("protected void load(final ");
+ w.print(TypeDataStore.class.getName());
+ w.println(" store) {");
+ w.indent();
+
+ if (!isEager) {
+ w.print(GWT.class.getName());
+ w.print(".runAsync(");
+ }
+
+ w.print("new ");
+ w.print(TypeDataBundle.class.getName());
+ w.println("(getName()) {");
+ w.indent();
+
+ w.println("public void load() {");
+ w.indent();
+
+ printBundleData(w, bundle);
+
+ // Close load method
+ w.outdent();
+ w.println("}");
+
+ // Close new TypeDataBundle() {}
+ w.outdent();
+ w.print("}");
+
+ if (isEager) {
+ w.println(".onSuccess();");
+ } else {
+ w.println(");");
+ }
+
+ // Close load method
+ w.outdent();
+ w.println("}");
+
+ // Close add(new ...
+ w.outdent();
+ w.println("});");
+ }
+
+ w.outdent();
+ w.println("}");
+
+ w.commit(logger);
+ }
+
+ private void printBundleData(SourceWriter w, ConnectorBundle bundle) {
+ writeIdentifiers(w, bundle);
+ writeGwtConstructors(w, bundle);
+ }
+
+ private void writeGwtConstructors(SourceWriter w, ConnectorBundle bundle) {
+ Set<JClassType> constructors = bundle.getGwtConstructors();
+ for (JClassType type : constructors) {
+ w.print("store.setConstructor(");
+ printClassLiteral(w, type);
+ w.print(", new Invoker() {");
+ w.indent();
+
+ w.println("public Object invoke(Object target, Object[] params) {");
+ w.indent();
+
+ w.print("return ");
+ w.print(GWT.class.getName());
+ w.print(".create(");
+ printClassLiteral(w, type);
+ w.println(");");
+
+ w.outdent();
+ w.println("}");
+
+ w.outdent();
+ w.println("});");
+ }
+ }
+
+ private void printClassLiteral(SourceWriter w, JClassType type) {
+ w.print(type.getQualifiedSourceName());
+ w.print(".class");
+ }
+
+ private void writeIdentifiers(SourceWriter w, ConnectorBundle bundle) {
+ Map<JClassType, Set<String>> identifiers = bundle.getIdentifiers();
+ for (Entry<JClassType, Set<String>> entry : identifiers.entrySet()) {
+ Set<String> ids = entry.getValue();
+ JClassType type = entry.getKey();
+ for (String id : ids) {
+ w.print("store.setClass(\"");
+ w.print(escape(id));
+ w.print("\", ");
+ printClassLiteral(w, type);
+ w.println(");");
+ }
+ }
+ }
+
+ private List<ConnectorBundle> buildBundles(TreeLogger logger,
+ TypeOracle typeOracle) throws NotFoundException {
+
+ Map<LoadStyle, Collection<JClassType>> connectorsByLoadStyle = new HashMap<LoadStyle, Collection<JClassType>>();
+ for (LoadStyle loadStyle : LoadStyle.values()) {
+ connectorsByLoadStyle.put(loadStyle, new ArrayList<JClassType>());
+ }
+
+ JClassType connectorType = typeOracle.getType(ServerConnector.class
+ .getName());
+ JClassType[] subtypes = connectorType.getSubtypes();
+ for (JClassType connectorSubtype : subtypes) {
+ if (!connectorSubtype.isAnnotationPresent(Connect.class)) {
+ continue;
+ }
+ LoadStyle loadStyle = getLoadStyle(connectorSubtype);
+ if (loadStyle != null) {
+ connectorsByLoadStyle.get(loadStyle).add(connectorSubtype);
+ }
+ }
+
+ List<ConnectorBundle> bundles = new ArrayList<ConnectorBundle>();
+
+ Collection<TypeVisitor> visitors = getVisitors(typeOracle);
+
+ ConnectorBundle eagerBundle = new ConnectorBundle(
+ ConnectorBundleLoader.EAGER_BUNDLE_NAME, null);
+
+ // Eager connectors and all RPC interfaces are loaded by default
+ eagerBundle.visitTypes(connectorsByLoadStyle.get(LoadStyle.EAGER),
+ visitors);
+ eagerBundle.visitSubTypes(
+ typeOracle.getType(ClientRpc.class.getName()), visitors);
+ eagerBundle.visitSubTypes(
+ typeOracle.getType(ServerRpc.class.getName()), visitors);
+
+ bundles.add(eagerBundle);
+
+ ConnectorBundle deferredBundle = new ConnectorBundle(
+ ConnectorBundleLoader.DEFERRED_BUNDLE_NAME, eagerBundle);
+ deferredBundle.visitTypes(
+ connectorsByLoadStyle.get(LoadStyle.DEFERRED), visitors);
+
+ bundles.add(deferredBundle);
+
+ Collection<JClassType> lazy = connectorsByLoadStyle.get(LoadStyle.LAZY);
+ for (JClassType type : lazy) {
+ ConnectorBundle bundle = new ConnectorBundle(type.getName(),
+ deferredBundle);
+ bundle.visitTypes(Collections.singleton(type), visitors);
+
+ bundles.add(bundle);
+ }
+
+ return bundles;
+ }
+
+ private Collection<TypeVisitor> getVisitors(TypeOracle oracle)
+ throws NotFoundException {
+ List<TypeVisitor> visitors = Arrays
+ .<TypeVisitor> asList(new ConnectorInitVisitor());
+ for (TypeVisitor typeVisitor : visitors) {
+ typeVisitor.init(oracle);
+ }
+ return visitors;
+ }
+
+ protected LoadStyle getLoadStyle(JClassType connectorType) {
+ Connect annotation = connectorType.getAnnotation(Connect.class);
+ return annotation.loadStyle();
+ }
+
+}
diff --git a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/GeneratedRpcMethodProviderGenerator.java b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/GeneratedRpcMethodProviderGenerator.java
index 47062d9abb..c6cf28db28 100644
--- a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/GeneratedRpcMethodProviderGenerator.java
+++ b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/GeneratedRpcMethodProviderGenerator.java
@@ -104,7 +104,7 @@ public class GeneratedRpcMethodProviderGenerator extends Generator {
composer.addImport("com.google.gwt.core.client.GWT");
composer.addImport(RpcMethod.class.getName());
composer.addImport(ClientRpc.class.getName());
- composer.addImport(com.vaadin.terminal.gwt.client.communication.Type.class
+ composer.addImport(com.vaadin.terminal.gwt.client.metadata.Type.class
.getName());
composer.addImplementedInterface(GeneratedRpcMethodProvider.class
.getName());
diff --git a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java
index cc92551846..c7cc7bf7cb 100644
--- a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java
+++ b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java
@@ -125,7 +125,7 @@ public class SerializerGenerator extends Generator {
serializerClassName);
composer.addImport(GWT.class.getName());
composer.addImport(JSONValue.class.getName());
- composer.addImport(com.vaadin.terminal.gwt.client.communication.Type.class
+ composer.addImport(com.vaadin.terminal.gwt.client.metadata.Type.class
.getName());
// composer.addImport(JSONObject.class.getName());
// composer.addImport(VPaintableMap.class.getName());
diff --git a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java
index 9e91763b9f..ac22aa2e8a 100644
--- a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java
+++ b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java
@@ -142,7 +142,7 @@ public class SerializerMapGenerator extends Generator {
.findType(JSONSerializer.class.getName());
JType[] deserializeParamTypes = new JType[] {
typeOracle
- .findType(com.vaadin.terminal.gwt.client.communication.Type.class
+ .findType(com.vaadin.terminal.gwt.client.metadata.Type.class
.getName()),
typeOracle.findType(JSONValue.class.getName()),
typeOracle.findType(ApplicationConnection.class.getName()) };
diff --git a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorBundle.java b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorBundle.java
new file mode 100644
index 0000000000..3155ab4474
--- /dev/null
+++ b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorBundle.java
@@ -0,0 +1,116 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.widgetsetutils.metadata;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import com.google.gwt.core.ext.typeinfo.JClassType;
+
+public class ConnectorBundle {
+ private final String name;
+ private final ConnectorBundle previousBundle;
+
+ private final Set<JClassType> needsGwtConstructor = new HashSet<JClassType>();
+ private final Map<JClassType, Set<String>> identifiers = new HashMap<JClassType, Set<String>>();
+ private final Set<JClassType> visitedTypes = new HashSet<JClassType>();
+ private final Set<JClassType> visitQueue = new HashSet<JClassType>();
+
+ public ConnectorBundle(String name, ConnectorBundle previousBundle) {
+ this.name = name;
+ this.previousBundle = previousBundle;
+ }
+
+ public void setNeedsGwtConstructor(JClassType type) {
+ if (!needsGwtConstructor(type)) {
+ needsGwtConstructor.add(type);
+ }
+ }
+
+ private boolean needsGwtConstructor(JClassType type) {
+ if (needsGwtConstructor.contains(type)) {
+ return true;
+ } else {
+ return previousBundle != null
+ && previousBundle.needsGwtConstructor(type);
+ }
+ }
+
+ public void setIdentifier(JClassType type, String identifier) {
+ if (!hasIdentifier(type, identifier)) {
+ Set<String> set = identifiers.get(type);
+ if (set == null) {
+ set = new HashSet<String>();
+ identifiers.put(type, set);
+ }
+ set.add(identifier);
+ }
+ }
+
+ private boolean hasIdentifier(JClassType type, String identifier) {
+ if (identifiers.containsKey(type)
+ && identifiers.get(type).contains(identifier)) {
+ return true;
+ } else {
+ return previousBundle != null
+ && previousBundle.hasIdentifier(type, identifier);
+ }
+ }
+
+ public ConnectorBundle getPreviousBundle() {
+ return previousBundle;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Map<JClassType, Set<String>> getIdentifiers() {
+ return Collections.unmodifiableMap(identifiers);
+ }
+
+ public Set<JClassType> getGwtConstructors() {
+ return Collections.unmodifiableSet(needsGwtConstructor);
+ }
+
+ public void visitTypes(Collection<JClassType> types,
+ Collection<TypeVisitor> visitors) {
+ for (JClassType type : types) {
+ if (!isTypeVisited(type)) {
+ visitQueue.add(type);
+ }
+ }
+ visitQueue(visitors);
+ }
+
+ private boolean isTypeVisited(JClassType type) {
+ if (visitedTypes.contains(type)) {
+ return true;
+ } else {
+ return previousBundle != null
+ && previousBundle.isTypeVisited(type);
+ }
+ }
+
+ private void visitQueue(Collection<TypeVisitor> visitors) {
+ while (!visitQueue.isEmpty()) {
+ JClassType type = visitQueue.iterator().next();
+ for (TypeVisitor typeVisitor : visitors) {
+ typeVisitor.visit(type, this);
+ }
+ visitQueue.remove(type);
+ visitedTypes.add(type);
+ }
+ }
+
+ public void visitSubTypes(JClassType type, Collection<TypeVisitor> visitors) {
+ visitTypes(Arrays.asList(type.getSubtypes()), visitors);
+ }
+} \ No newline at end of file
diff --git a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorInitVisitor.java b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorInitVisitor.java
new file mode 100644
index 0000000000..a6e71c70d9
--- /dev/null
+++ b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorInitVisitor.java
@@ -0,0 +1,32 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.widgetsetutils.metadata;
+
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.NotFoundException;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.terminal.gwt.client.ServerConnector;
+
+public class ConnectorInitVisitor implements TypeVisitor {
+
+ private JClassType serverConnector;
+
+ @Override
+ public void init(TypeOracle oracle) throws NotFoundException {
+ serverConnector = oracle.getType(ServerConnector.class.getName());
+ }
+
+ @Override
+ public void visit(JClassType type, ConnectorBundle bundle) {
+ Connect connectAnnotation = type.getAnnotation(Connect.class);
+ if (connectAnnotation != null && serverConnector.isAssignableFrom(type)) {
+ bundle.setIdentifier(type, connectAnnotation.value()
+ .getCanonicalName());
+ bundle.setNeedsGwtConstructor(type);
+ }
+ }
+
+}
diff --git a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/TypeVisitor.java b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/TypeVisitor.java
new file mode 100644
index 0000000000..6ed791fe86
--- /dev/null
+++ b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/TypeVisitor.java
@@ -0,0 +1,15 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.widgetsetutils.metadata;
+
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.NotFoundException;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
+
+public interface TypeVisitor {
+ public void init(TypeOracle oracle) throws NotFoundException;
+
+ public void visit(JClassType type, ConnectorBundle bundle);
+}