summaryrefslogtreecommitdiffstats
path: root/client/src/com/vaadin
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/src/com/vaadin
parent88776600733901f3f9891aa90a11a5aeb2b97ef4 (diff)
downloadvaadin-framework-1a7d126e358d92850a41060b06d53309f2ac58f0.tar.gz
vaadin-framework-1a7d126e358d92850a41060b06d53309f2ac58f0.zip
Initial ConnectorBundle implementation (#9371)
Diffstat (limited to 'client/src/com/vaadin')
-rw-r--r--client/src/com/vaadin/Vaadin.gwt.xml9
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java132
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java2
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/WidgetSet.java48
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/communication/DiffJSONSerializer.java1
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/communication/JSONSerializer.java1
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java1
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/communication/RpcManager.java1
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/communication/RpcMethod.java1
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java1
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/metadata/AsyncBundleLoader.java86
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/metadata/BundleLoadCallback.java11
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/metadata/ConnectorBundleLoader.java97
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/metadata/Invoker.java9
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/metadata/Method.java54
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/metadata/Property.java53
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/metadata/Type.java79
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/metadata/TypeData.java20
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/metadata/TypeDataBundle.java33
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/metadata/TypeDataStore.java64
20 files changed, 582 insertions, 121 deletions
diff --git a/client/src/com/vaadin/Vaadin.gwt.xml b/client/src/com/vaadin/Vaadin.gwt.xml
index 07d7c941e6..5a9909a29c 100644
--- a/client/src/com/vaadin/Vaadin.gwt.xml
+++ b/client/src/com/vaadin/Vaadin.gwt.xml
@@ -36,11 +36,6 @@
</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
class="com.vaadin.terminal.gwt.client.ui.dd.VAcceptCriterionFactory" />
@@ -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" />
diff --git a/client/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java b/client/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java
index eea60b04ea..8f6697288c 100644
--- a/client/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java
+++ b/client/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java
@@ -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();
}
/**
diff --git a/client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
index 32b15d6d87..9a14e5434e 100644
--- a/client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
+++ b/client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
@@ -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;
diff --git a/client/src/com/vaadin/terminal/gwt/client/WidgetSet.java b/client/src/com/vaadin/terminal/gwt/client/WidgetSet.java
index fbcfbb68d9..776436f5f0 100644
--- a/client/src/com/vaadin/terminal/gwt/client/WidgetSet.java
+++ b/client/src/com/vaadin/terminal/gwt/client/WidgetSet.java
@@ -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();
+ }
+ });
+ }
}
}
diff --git a/client/src/com/vaadin/terminal/gwt/client/communication/DiffJSONSerializer.java b/client/src/com/vaadin/terminal/gwt/client/communication/DiffJSONSerializer.java
index a3b96a6cb2..1d5415263f 100644
--- a/client/src/com/vaadin/terminal/gwt/client/communication/DiffJSONSerializer.java
+++ b/client/src/com/vaadin/terminal/gwt/client/communication/DiffJSONSerializer.java
@@ -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> {
/**
diff --git a/client/src/com/vaadin/terminal/gwt/client/communication/JSONSerializer.java b/client/src/com/vaadin/terminal/gwt/client/communication/JSONSerializer.java
index a8fe2c7ccc..c6b814a5c1 100644
--- a/client/src/com/vaadin/terminal/gwt/client/communication/JSONSerializer.java
+++ b/client/src/com/vaadin/terminal/gwt/client/communication/JSONSerializer.java
@@ -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
diff --git a/client/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java b/client/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java
index 7d2046982c..ef5090ec18 100644
--- a/client/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java
+++ b/client/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java
@@ -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
diff --git a/client/src/com/vaadin/terminal/gwt/client/communication/RpcManager.java b/client/src/com/vaadin/terminal/gwt/client/communication/RpcManager.java
index 04d0e3f56f..537cc34185 100644
--- a/client/src/com/vaadin/terminal/gwt/client/communication/RpcManager.java
+++ b/client/src/com/vaadin/terminal/gwt/client/communication/RpcManager.java
@@ -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
diff --git a/client/src/com/vaadin/terminal/gwt/client/communication/RpcMethod.java b/client/src/com/vaadin/terminal/gwt/client/communication/RpcMethod.java
index a47fa5eab2..1759fbb97f 100644
--- a/client/src/com/vaadin/terminal/gwt/client/communication/RpcMethod.java
+++ b/client/src/com/vaadin/terminal/gwt/client/communication/RpcMethod.java
@@ -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;
diff --git a/client/src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java b/client/src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java
index f77553d3c0..3d2e4f3804 100644
--- a/client/src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java
+++ b/client/src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java
@@ -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> {
diff --git a/client/src/com/vaadin/terminal/gwt/client/metadata/AsyncBundleLoader.java b/client/src/com/vaadin/terminal/gwt/client/metadata/AsyncBundleLoader.java
new file mode 100644
index 0000000000..e92e51b40d
--- /dev/null
+++ b/client/src/com/vaadin/terminal/gwt/client/metadata/AsyncBundleLoader.java
@@ -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;
+ }
+
+}
diff --git a/client/src/com/vaadin/terminal/gwt/client/metadata/BundleLoadCallback.java b/client/src/com/vaadin/terminal/gwt/client/metadata/BundleLoadCallback.java
new file mode 100644
index 0000000000..c7fc735829
--- /dev/null
+++ b/client/src/com/vaadin/terminal/gwt/client/metadata/BundleLoadCallback.java
@@ -0,0 +1,11 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.metadata;
+
+public interface BundleLoadCallback {
+ public void loaded();
+
+ public void failed(Throwable reason);
+}
diff --git a/client/src/com/vaadin/terminal/gwt/client/metadata/ConnectorBundleLoader.java b/client/src/com/vaadin/terminal/gwt/client/metadata/ConnectorBundleLoader.java
new file mode 100644
index 0000000000..48a8430312
--- /dev/null
+++ b/client/src/com/vaadin/terminal/gwt/client/metadata/ConnectorBundleLoader.java
@@ -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();
+
+}
diff --git a/client/src/com/vaadin/terminal/gwt/client/metadata/Invoker.java b/client/src/com/vaadin/terminal/gwt/client/metadata/Invoker.java
new file mode 100644
index 0000000000..5f6a839da6
--- /dev/null
+++ b/client/src/com/vaadin/terminal/gwt/client/metadata/Invoker.java
@@ -0,0 +1,9 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.metadata;
+
+public interface Invoker {
+ public Object invoke(Object target, Object[] params);
+}
diff --git a/client/src/com/vaadin/terminal/gwt/client/metadata/Method.java b/client/src/com/vaadin/terminal/gwt/client/metadata/Method.java
new file mode 100644
index 0000000000..f164bc4bcf
--- /dev/null
+++ b/client/src/com/vaadin/terminal/gwt/client/metadata/Method.java
@@ -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();
+ }
+
+}
diff --git a/client/src/com/vaadin/terminal/gwt/client/metadata/Property.java b/client/src/com/vaadin/terminal/gwt/client/metadata/Property.java
new file mode 100644
index 0000000000..5f2b1ffb41
--- /dev/null
+++ b/client/src/com/vaadin/terminal/gwt/client/metadata/Property.java
@@ -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();
+ }
+
+}
diff --git a/client/src/com/vaadin/terminal/gwt/client/metadata/Type.java b/client/src/com/vaadin/terminal/gwt/client/metadata/Type.java
new file mode 100644
index 0000000000..4fab296441
--- /dev/null
+++ b/client/src/com/vaadin/terminal/gwt/client/metadata/Type.java
@@ -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();
+ }
+
+}
diff --git a/client/src/com/vaadin/terminal/gwt/client/metadata/TypeData.java b/client/src/com/vaadin/terminal/gwt/client/metadata/TypeData.java
new file mode 100644
index 0000000000..6ee0b4ede0
--- /dev/null
+++ b/client/src/com/vaadin/terminal/gwt/client/metadata/TypeData.java
@@ -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);
+ }
+}
diff --git a/client/src/com/vaadin/terminal/gwt/client/metadata/TypeDataBundle.java b/client/src/com/vaadin/terminal/gwt/client/metadata/TypeDataBundle.java
new file mode 100644
index 0000000000..cbde338ff2
--- /dev/null
+++ b/client/src/com/vaadin/terminal/gwt/client/metadata/TypeDataBundle.java
@@ -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;
+ }
+}
diff --git a/client/src/com/vaadin/terminal/gwt/client/metadata/TypeDataStore.java b/client/src/com/vaadin/terminal/gwt/client/metadata/TypeDataStore.java
new file mode 100644
index 0000000000..4b224721e6
--- /dev/null
+++ b/client/src/com/vaadin/terminal/gwt/client/metadata/TypeDataStore.java
@@ -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);
+ }
+}