diff options
author | Leif Åstrand <leif@vaadin.com> | 2012-08-17 18:11:54 +0300 |
---|---|---|
committer | Leif Åstrand <leif@vaadin.com> | 2012-08-22 19:25:30 +0300 |
commit | 1a7d126e358d92850a41060b06d53309f2ac58f0 (patch) | |
tree | 3ceca4be0eeeffcc59a0f19dd28d298f9238c9d2 /client-compiler | |
parent | 88776600733901f3f9891aa90a11a5aeb2b97ef4 (diff) | |
download | vaadin-framework-1a7d126e358d92850a41060b06d53309f2ac58f0.tar.gz vaadin-framework-1a7d126e358d92850a41060b06d53309f2ac58f0.zip |
Initial ConnectorBundle implementation (#9371)
Diffstat (limited to 'client-compiler')
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); +} |