Browse Source

Initial ConnectorBundle implementation (#9371)

tags/7.0.0.beta1
Leif Åstrand 11 years ago
parent
commit
1a7d126e35
27 changed files with 1028 additions and 124 deletions
  1. 280
    0
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/ConnectorBundleLoaderFactory.java
  2. 1
    1
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/GeneratedRpcMethodProviderGenerator.java
  3. 1
    1
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java
  4. 1
    1
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java
  5. 116
    0
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorBundle.java
  6. 32
    0
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorInitVisitor.java
  7. 15
    0
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/TypeVisitor.java
  8. 4
    5
      client/src/com/vaadin/Vaadin.gwt.xml
  9. 40
    92
      client/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java
  10. 1
    1
      client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
  11. 25
    23
      client/src/com/vaadin/terminal/gwt/client/WidgetSet.java
  12. 1
    0
      client/src/com/vaadin/terminal/gwt/client/communication/DiffJSONSerializer.java
  13. 1
    0
      client/src/com/vaadin/terminal/gwt/client/communication/JSONSerializer.java
  14. 1
    0
      client/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java
  15. 1
    0
      client/src/com/vaadin/terminal/gwt/client/communication/RpcManager.java
  16. 1
    0
      client/src/com/vaadin/terminal/gwt/client/communication/RpcMethod.java
  17. 1
    0
      client/src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java
  18. 86
    0
      client/src/com/vaadin/terminal/gwt/client/metadata/AsyncBundleLoader.java
  19. 11
    0
      client/src/com/vaadin/terminal/gwt/client/metadata/BundleLoadCallback.java
  20. 97
    0
      client/src/com/vaadin/terminal/gwt/client/metadata/ConnectorBundleLoader.java
  21. 9
    0
      client/src/com/vaadin/terminal/gwt/client/metadata/Invoker.java
  22. 54
    0
      client/src/com/vaadin/terminal/gwt/client/metadata/Method.java
  23. 53
    0
      client/src/com/vaadin/terminal/gwt/client/metadata/Property.java
  24. 79
    0
      client/src/com/vaadin/terminal/gwt/client/metadata/Type.java
  25. 20
    0
      client/src/com/vaadin/terminal/gwt/client/metadata/TypeData.java
  26. 33
    0
      client/src/com/vaadin/terminal/gwt/client/metadata/TypeDataBundle.java
  27. 64
    0
      client/src/com/vaadin/terminal/gwt/client/metadata/TypeDataStore.java

+ 280
- 0
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/ConnectorBundleLoaderFactory.java View File

@@ -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();
}

}

+ 1
- 1
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/GeneratedRpcMethodProviderGenerator.java View File

@@ -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());

+ 1
- 1
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java View File

@@ -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());

+ 1
- 1
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java View File

@@ -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()) };

+ 116
- 0
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorBundle.java View File

@@ -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);
}
}

+ 32
- 0
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorInitVisitor.java View File

@@ -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);
}
}

}

+ 15
- 0
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/TypeVisitor.java View File

@@ -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);
}

+ 4
- 5
client/src/com/vaadin/Vaadin.gwt.xml View File

@@ -35,11 +35,6 @@
<when-type-is class="com.vaadin.terminal.gwt.client.Console" />
</replace-with>

<generate-with
class="com.vaadin.terminal.gwt.widgetsetutils.EagerWidgetMapGenerator">
<when-type-is class="com.vaadin.terminal.gwt.client.WidgetMap" />
</generate-with>

<generate-with
class="com.vaadin.terminal.gwt.widgetsetutils.AcceptCriteriaFactoryGenerator">
<when-type-is
@@ -78,6 +73,10 @@
<when-type-assignable
class="com.vaadin.terminal.gwt.client.ui.ConnectorStateFactory" />
</generate-with>
<generate-with class="com.vaadin.terminal.gwt.widgetsetutils.ConnectorBundleLoaderFactory">
<when-type-assignable class="com.vaadin.terminal.gwt.client.metadata.ConnectorBundleLoader" />
</generate-with>

<!-- Use the new cross site linker to get a nocache.js without document.write -->
<add-linker name="xsiframe" />

+ 40
- 92
client/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java View File

@@ -29,9 +29,11 @@ import com.google.gwt.core.client.JsArrayString;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.vaadin.shared.ApplicationConstants;
import com.vaadin.terminal.gwt.client.metadata.BundleLoadCallback;
import com.vaadin.terminal.gwt.client.metadata.ConnectorBundleLoader;
import com.vaadin.terminal.gwt.client.metadata.TypeData;
import com.vaadin.terminal.gwt.client.ui.UnknownComponentConnector;

public class ApplicationConfiguration implements EntryPoint {
@@ -207,7 +209,7 @@ public class ApplicationConfiguration implements EntryPoint {

private HashMap<Integer, String> unknownComponents;

private Class<? extends ServerConnector>[] classes = new Class[1024];
private Map<Integer, Class<? extends ServerConnector>> classes = new HashMap<Integer, Class<? extends ServerConnector>>();

private boolean browserDetailsSent = false;
private boolean widgetsetVersionSent = false;
@@ -390,12 +392,26 @@ public class ApplicationConfiguration implements EntryPoint {

public Class<? extends ServerConnector> getConnectorClassByEncodedTag(
int tag) {
try {
return classes[tag];
} catch (Exception e) {
// component was not present in mappings
return UnknownComponentConnector.class;
Class<? extends ServerConnector> type = classes.get(tag);
if (type == null && !classes.containsKey(tag)) {
// Initialize if not already loaded
Integer currentTag = Integer.valueOf(tag);
while (type == null && currentTag != null) {
String serverSideClassNameForTag = getServerSideClassNameForTag(currentTag);
type = (Class<? extends ServerConnector>) TypeData
.getClass(serverSideClassNameForTag);
currentTag = getParentTag(currentTag.intValue());
}
if (type == null) {
type = UnknownComponentConnector.class;
if (unknownComponents == null) {
unknownComponents = new HashMap<Integer, String>();
}
unknownComponents.put(tag, getServerSideClassNameForTag(tag));
}
classes.put(tag, type);
}
return type;
}

public void addComponentInheritanceInfo(ValueMap valueMap) {
@@ -418,13 +434,7 @@ public class ApplicationConfiguration implements EntryPoint {
for (int i = 0; i < keyArray.length(); i++) {
String key = keyArray.get(i).intern();
int value = valueMap.getInt(key);
classes[value] = widgetSet.getConnectorClassByTag(value, this);
if (classes[value] == UnknownComponentConnector.class) {
if (unknownComponents == null) {
unknownComponents = new HashMap<Integer, String>();
}
unknownComponents.put(value, key);
}
widgetSet.ensureConnectorLoaded(value, this);
}
}

@@ -466,86 +476,25 @@ public class ApplicationConfiguration implements EntryPoint {
cmd.execute();
}
callbacks.clear();
} else if (dependenciesLoading == 0 && deferredWidgetLoader != null) {
deferredWidgetLoader.trigger();
} else if (dependenciesLoading == 0
&& !ConnectorBundleLoader.get().isBundleLoaded(
ConnectorBundleLoader.DEFERRED_BUNDLE_NAME)) {
ConnectorBundleLoader.get().loadBundle(
ConnectorBundleLoader.DEFERRED_BUNDLE_NAME,
new BundleLoadCallback() {
@Override
public void loaded() {
// Nothing to do
}

@Override
public void failed(Throwable reason) {
VConsole.error(reason);
}
});
}

}

/*
* This loop loads widget implementation that should be loaded deferred.
*/
static class DeferredWidgetLoader extends Timer {
private static final int FREE_LIMIT = 4;
private static final int FREE_CHECK_TIMEOUT = 100;

int communicationFree = 0;
int nextWidgetIndex = 0;
private boolean pending;

public DeferredWidgetLoader() {
schedule(5000);
}

public void trigger() {
if (!pending) {
schedule(FREE_CHECK_TIMEOUT);
}
}

@Override
public void schedule(int delayMillis) {
super.schedule(delayMillis);
pending = true;
}

@Override
public void run() {
pending = false;
if (!isBusy()) {
Class<? extends ServerConnector> nextType = getNextType();
if (nextType == null) {
// ensured that all widgets are loaded
deferredWidgetLoader = null;
} else {
communicationFree = 0;
widgetSet.loadImplementation(nextType);
}
} else {
schedule(FREE_CHECK_TIMEOUT);
}
}

private Class<? extends ServerConnector> getNextType() {
Class<? extends ServerConnector>[] deferredLoadedConnectors = widgetSet
.getDeferredLoadedConnectors();
if (deferredLoadedConnectors.length <= nextWidgetIndex) {
return null;
} else {
return deferredLoadedConnectors[nextWidgetIndex++];
}
}

private boolean isBusy() {
if (dependenciesLoading > 0) {
communicationFree = 0;
return true;
}
for (ApplicationConnection app : runningApplications) {
if (app.hasActiveRequest()) {
// if an UIDL request or widget loading is active, mark as
// busy
communicationFree = 0;
return true;
}
}
communicationFree++;
return communicationFree < FREE_LIMIT;
}
}

private static DeferredWidgetLoader deferredWidgetLoader;

@Override
public void onModuleLoad() {

@@ -582,7 +531,6 @@ public class ApplicationConfiguration implements EntryPoint {
return;
}
registerCallback(GWT.getModuleName());
deferredWidgetLoader = new DeferredWidgetLoader();
}

/**

+ 1
- 1
client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java View File

@@ -67,8 +67,8 @@ import com.vaadin.terminal.gwt.client.communication.JsonEncoder;
import com.vaadin.terminal.gwt.client.communication.RpcManager;
import com.vaadin.terminal.gwt.client.communication.SerializerMap;
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
import com.vaadin.terminal.gwt.client.communication.Type;
import com.vaadin.terminal.gwt.client.extensions.AbstractExtensionConnector;
import com.vaadin.terminal.gwt.client.metadata.Type;
import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector;
import com.vaadin.terminal.gwt.client.ui.VContextMenu;
import com.vaadin.terminal.gwt.client.ui.dd.VDragAndDropManager;

+ 25
- 23
client/src/com/vaadin/terminal/gwt/client/WidgetSet.java View File

@@ -18,17 +18,12 @@ package com.vaadin.terminal.gwt.client;

import com.google.gwt.core.client.GWT;
import com.vaadin.terminal.gwt.client.communication.HasJavaScriptConnectorHelper;
import com.vaadin.terminal.gwt.client.metadata.BundleLoadCallback;
import com.vaadin.terminal.gwt.client.metadata.ConnectorBundleLoader;
import com.vaadin.terminal.gwt.client.metadata.TypeData;
import com.vaadin.terminal.gwt.client.ui.UnknownComponentConnector;

public class WidgetSet {

/**
* WidgetSet (and its extensions) delegate instantiation of widgets and
* client-server matching to WidgetMap. The actual implementations are
* generated with gwts generators/deferred binding.
*/
private WidgetMap widgetMap = GWT.create(WidgetMap.class);

/**
* Create an uninitialized connector that best matches given UIDL. The
* connector must implement {@link ServerConnector}.
@@ -65,7 +60,8 @@ public class WidgetSet {
/*
* let the auto generated code instantiate this type
*/
ServerConnector connector = widgetMap.instantiate(classType);
ServerConnector connector = (ServerConnector) TypeData.getType(
classType).createInstance();
if (connector instanceof HasJavaScriptConnectorHelper) {
((HasJavaScriptConnectorHelper) connector)
.getJavascriptConnectorHelper().setTag(tag);
@@ -102,26 +98,32 @@ public class WidgetSet {
* @param applicationConfiguration
* @return
*/
public Class<? extends ServerConnector> getConnectorClassByTag(int tag,
ApplicationConfiguration conf) {
Class<? extends ServerConnector> connectorClass = null;
public void ensureConnectorLoaded(int tag, ApplicationConfiguration conf) {
ConnectorBundleLoader loader = ConnectorBundleLoader.get();
String bundleName = null;
Integer t = tag;
do {
String serverSideClassName = conf.getServerSideClassNameForTag(t);
connectorClass = widgetMap
.getConnectorClassForServerSideClassName(serverSideClassName);
t = conf.getParentTag(t);
} while (connectorClass == UnknownComponentConnector.class && t != null);
bundleName = loader.getBundleForIdentifier(serverSideClassName);

return connectorClass;
}
t = conf.getParentTag(t);
} while (bundleName == null && t != null);

public Class<? extends ServerConnector>[] getDeferredLoadedConnectors() {
return widgetMap.getDeferredLoadedConnectors();
}
if (bundleName != null && !loader.isBundleLoaded(bundleName)) {
ApplicationConfiguration.startDependencyLoading();
loader.loadBundle(bundleName, new BundleLoadCallback() {
@Override
public void loaded() {
ApplicationConfiguration.endDependencyLoading();
}

public void loadImplementation(Class<? extends ServerConnector> nextType) {
widgetMap.ensureInstantiator(nextType);
@Override
public void failed(Throwable reason) {
VConsole.error(reason);
ApplicationConfiguration.endDependencyLoading();
}
});
}
}

}

+ 1
- 0
client/src/com/vaadin/terminal/gwt/client/communication/DiffJSONSerializer.java View File

@@ -17,6 +17,7 @@ package com.vaadin.terminal.gwt.client.communication;

import com.google.gwt.json.client.JSONValue;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.metadata.Type;

public interface DiffJSONSerializer<T> extends JSONSerializer<T> {
/**

+ 1
- 0
client/src/com/vaadin/terminal/gwt/client/communication/JSONSerializer.java View File

@@ -20,6 +20,7 @@ import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONValue;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.ConnectorMap;
import com.vaadin.terminal.gwt.client.metadata.Type;

/**
* Implementors of this interface knows how to serialize an Object of a given

+ 1
- 0
client/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java View File

@@ -31,6 +31,7 @@ import com.google.gwt.json.client.JSONValue;
import com.vaadin.shared.Connector;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.ConnectorMap;
import com.vaadin.terminal.gwt.client.metadata.Type;

/**
* Client side decoder for decodeing shared state and other values from JSON

+ 1
- 0
client/src/com/vaadin/terminal/gwt/client/communication/RpcManager.java View File

@@ -29,6 +29,7 @@ import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.ConnectorMap;
import com.vaadin.terminal.gwt.client.ServerConnector;
import com.vaadin.terminal.gwt.client.VConsole;
import com.vaadin.terminal.gwt.client.metadata.Type;

/**
* Client side RPC manager that can invoke methods based on RPC calls received

+ 1
- 0
client/src/com/vaadin/terminal/gwt/client/communication/RpcMethod.java View File

@@ -16,6 +16,7 @@
package com.vaadin.terminal.gwt.client.communication;

import com.vaadin.shared.communication.ClientRpc;
import com.vaadin.terminal.gwt.client.metadata.Type;

public abstract class RpcMethod {
private String interfaceName;

+ 1
- 0
client/src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java View File

@@ -20,6 +20,7 @@ import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONValue;
import com.vaadin.shared.communication.URLReference;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.metadata.Type;

public class URLReference_Serializer implements JSONSerializer<URLReference> {


+ 86
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/AsyncBundleLoader.java View File

@@ -0,0 +1,86 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.terminal.gwt.client.metadata;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public abstract class AsyncBundleLoader {
public enum State {
NOT_STARTED, LOADING, LOADED, ERROR;
}

private State state = State.NOT_STARTED;

private Throwable error = null;

private List<BundleLoadCallback> callbacks = new ArrayList<BundleLoadCallback>();

private final String packageName;

private final String[] indentifiers;

public AsyncBundleLoader(String packageName, String[] indentifiers) {
this.packageName = packageName;
this.indentifiers = indentifiers;
}

protected abstract void load(TypeDataStore store);

public List<BundleLoadCallback> setError(Throwable error) {
assert state == State.LOADING;
state = State.ERROR;
this.error = error;

return clearCallbacks();
}

public Throwable getError() {
return error;
}

public State getState() {
return state;
}

public List<BundleLoadCallback> getCallback() {
return Collections.unmodifiableList(callbacks);
}

public void load(BundleLoadCallback callback, TypeDataStore store) {
assert state == State.NOT_STARTED;
state = State.LOADING;
callbacks.add(callback);
load(store);
}

public void addCallback(BundleLoadCallback callback) {
assert state == State.LOADING;
callbacks.add(callback);
}

public List<BundleLoadCallback> setLoaded() {
assert state == State.LOADING;
state = State.LOADED;

return clearCallbacks();
}

private List<BundleLoadCallback> clearCallbacks() {
List<BundleLoadCallback> callbacks = this.callbacks;
this.callbacks = null;
return callbacks;
}

public String getName() {
return packageName;
}

public String[] getIndentifiers() {
return indentifiers;
}

}

+ 11
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/BundleLoadCallback.java View File

@@ -0,0 +1,11 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.terminal.gwt.client.metadata;

public interface BundleLoadCallback {
public void loaded();

public void failed(Throwable reason);
}

+ 97
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/ConnectorBundleLoader.java View File

@@ -0,0 +1,97 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.terminal.gwt.client.metadata;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.gwt.core.shared.GWT;
import com.vaadin.terminal.gwt.client.metadata.AsyncBundleLoader.State;

public abstract class ConnectorBundleLoader {
public static final String EAGER_BUNDLE_NAME = "__eager";
public static final String DEFERRED_BUNDLE_NAME = "__deferred";

private static ConnectorBundleLoader impl;

private Map<String, AsyncBundleLoader> asyncBlockLoaders = new HashMap<String, AsyncBundleLoader>();
private Map<String, String> identifierToBundle = new HashMap<String, String>();

private final TypeDataStore datStore = new TypeDataStore();

public ConnectorBundleLoader() {
init();
}

public TypeDataStore getTypeDataStore() {
return datStore;
}

public static ConnectorBundleLoader get() {
if (impl == null) {
impl = GWT.create(ConnectorBundleLoader.class);
}
return impl;
}

public void loadBundle(String packageName, BundleLoadCallback callback) {
AsyncBundleLoader loader = asyncBlockLoaders.get(packageName);
switch (loader.getState()) {
case NOT_STARTED:
loader.load(callback, getTypeDataStore());
break;
case LOADING:
loader.addCallback(callback);
break;
case LOADED:
callback.loaded();
break;
case ERROR:
callback.failed(loader.getError());
}
}

public boolean isBundleLoaded(String bundleName) {
AsyncBundleLoader loader = asyncBlockLoaders.get(bundleName);
if (loader == null) {
throw new IllegalArgumentException("Bundle " + bundleName
+ " not recognized");
}
return loader.getState() == State.LOADED;
}

public void setLoaded(String packageName) {
List<BundleLoadCallback> callbacks = asyncBlockLoaders.get(packageName)
.setLoaded();
for (BundleLoadCallback callback : callbacks) {
callback.loaded();
}
}

public void setLoadFailure(String bundleName, Throwable reason) {
List<BundleLoadCallback> callbacks = asyncBlockLoaders.get(bundleName)
.setError(reason);
for (BundleLoadCallback callback : callbacks) {
callback.failed(reason);
}
}

public String getBundleForIdentifier(String identifier) {
return identifierToBundle.get(identifier);
}

protected void addAsyncBlockLoader(AsyncBundleLoader loader) {
String name = loader.getName();
asyncBlockLoaders.put(name, loader);
String[] indentifiers = loader.getIndentifiers();
for (String identifier : indentifiers) {
identifierToBundle.put(identifier, name);
}
}

public abstract void init();

}

+ 9
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/Invoker.java View File

@@ -0,0 +1,9 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.terminal.gwt.client.metadata;

public interface Invoker {
public Object invoke(Object target, Object[] params);
}

+ 54
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/Method.java View File

@@ -0,0 +1,54 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.terminal.gwt.client.metadata;

public class Method {

private final Type type;
private final String name;

public Method(Type type, String name) {
this.type = type;
this.name = name;
}

public Type getType() {
return type;
}

public String getName() {
return name;
}

public Type getReturnType() {
return TypeDataStore.getReturnType(this);
}

public void invoke(Object target, Object... params) {
TypeDataStore.getInvoker(this).invoke(target, params);
}

public String getSignature() {
return type.toString() + "." + name;
}

@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
} else if (obj instanceof Method) {
Method other = (Method) obj;
return other.getSignature().equals(getSignature());
} else {
return false;
}
}

@Override
public int hashCode() {
return getSignature().hashCode();
}

}

+ 53
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/Property.java View File

@@ -0,0 +1,53 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.terminal.gwt.client.metadata;

public class Property {
private final Type type;
private final String name;

public Property(Type type, String name) {
this.type = type;
this.name = name;
}

public Object getValue(Object bean) {
return TypeDataStore.getGetter(this).invoke(bean, null);
}

public String getDelegateToWidgetMethod() {
String value = TypeDataStore.getDelegateToWidget(this);
if (value == null) {
return null;
} else if (value.isEmpty()) {
return "set" + Character.toUpperCase(value.charAt(0))
+ value.substring(1);
} else {
return value;
}
}

public String getSignature() {
return type.toString() + "." + name;
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else if (obj instanceof Property) {
Property other = (Property) obj;
return getSignature().equals(other.getSignature());
} else {
return false;
}
}

@Override
public int hashCode() {
return getSignature().hashCode();
}

}

+ 79
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/Type.java View File

@@ -0,0 +1,79 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/
package com.vaadin.terminal.gwt.client.metadata;

public class Type {
private final String name;
private final Type[] parameterTypes;

public Type(Class<?> clazz) {
name = clazz.getName();
parameterTypes = null;
}

public Type(String baseTypeName, Type[] parameterTypes) {
name = baseTypeName;
this.parameterTypes = parameterTypes;
}

public String getBaseTypeName() {
return name;
}

public Type[] getParameterTypes() {
return parameterTypes;
}

public Object createInstance() {
Invoker invoker = TypeDataStore.getConstructor(this);
return invoker.invoke(null, null);
}

public Method getMethod(String name) {
return new Method(this, name);
}

public Property getProperty(String propertyName) {
return new Property(this, propertyName);
}

public String getSignature() {
String string = name;
if (parameterTypes != null) {
string += '<';
for (int i = 0; i < parameterTypes.length; i++) {
if (i != 0) {
string += ',';
}
string += parameterTypes[i].toString();
}
string += '>';
}

return string;
}

@Override
public String toString() {
return getSignature();
}

@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
} else if (obj instanceof Type) {
Type other = (Type) obj;
return other.getSignature().equals(getSignature());
} else {
return false;
}
}

@Override
public int hashCode() {
return getSignature().hashCode();
}

}

+ 20
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/TypeData.java View File

@@ -0,0 +1,20 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.terminal.gwt.client.metadata;

public class TypeData {

public static Type getType(Class<?> type) {
return TypeDataStore.getType(type);
}

public static Type getType(String identifier) {
return TypeDataStore.getType(getClass(identifier));
}

public static Class<?> getClass(String identifier) {
return TypeDataStore.getClass(identifier);
}
}

+ 33
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/TypeDataBundle.java View File

@@ -0,0 +1,33 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.terminal.gwt.client.metadata;

import com.google.gwt.core.client.RunAsyncCallback;

public abstract class TypeDataBundle implements RunAsyncCallback {
private final String name;

public TypeDataBundle(String name) {
this.name = name;
}

@Override
public void onSuccess() {
ConnectorBundleLoader loader = ConnectorBundleLoader.get();
load();
loader.setLoaded(getName());
}

@Override
public void onFailure(Throwable reason) {
ConnectorBundleLoader.get().setLoadFailure(getName(), reason);
}

public abstract void load();

public String getName() {
return name;
}
}

+ 64
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/TypeDataStore.java View File

@@ -0,0 +1,64 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.terminal.gwt.client.metadata;

import java.util.HashMap;
import java.util.Map;

public class TypeDataStore {
private static final String CONSTRUCTOR_NAME = "!new";

private final Map<String, Class<?>> identifiers = new HashMap<String, Class<?>>();

private final Map<Method, Type> returnTypes = new HashMap<Method, Type>();
private final Map<Method, Invoker> invokers = new HashMap<Method, Invoker>();

private final Map<Property, Invoker> getters = new HashMap<Property, Invoker>();
private final Map<Property, String> delegateToWidget = new HashMap<Property, String>();

public static TypeDataStore get() {
return ConnectorBundleLoader.get().getTypeDataStore();
}

public void setClass(String identifier, Class<?> type) {
identifiers.put(identifier, type);
}

public static Class<?> getClass(String identifier) {
return get().identifiers.get(identifier);
}

public static Type getType(Class<?> clazz) {
return new Type(clazz);
}

public static Type getReturnType(Method method) {
return get().returnTypes.get(method);
}

public static Invoker getInvoker(Method method) {
return get().invokers.get(method);
}

public static Invoker getConstructor(Type type) {
return get().invokers.get(new Method(type, CONSTRUCTOR_NAME));
}

public static Invoker getGetter(Property property) {
return get().getters.get(property);
}

public static String getDelegateToWidget(Property property) {
return get().delegateToWidget.get(property);
}

public void setReturnType(Class<?> type, String methodName, Type returnType) {
returnTypes.put(new Method(getType(type), methodName), returnType);
}

public void setConstructor(Class<?> type, Invoker constructor) {
invokers.put(new Method(getType(type), CONSTRUCTOR_NAME), constructor);
}
}

Loading…
Cancel
Save