import java.util.LinkedList;
import java.util.List;
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArrayString;
import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.Timer;
import com.vaadin.terminal.gwt.client.ui.VUnknownComponent;
-public class ApplicationConfiguration {
+public class ApplicationConfiguration implements EntryPoint {
- // can only be inited once, to avoid multiple-entrypoint-problem
- private static WidgetSet initedWidgetSet;
+ private static WidgetSet widgetSet = GWT.create(WidgetSet.class);
private String id;
private String themeUri;
private String windowId;
- // TODO consider to make this hashmap per application
+ static// TODO consider to make this hashmap per application
LinkedList<Command> callbacks = new LinkedList<Command>();
- private int widgetsLoading;
+ private static int widgetsLoading;
private static ArrayList<ApplicationConnection> unstartedApplications = new ArrayList<ApplicationConnection>();
private static ArrayList<ApplicationConnection> runningApplications = new ArrayList<ApplicationConnection>();
* @param widgetset
* the widgetset that is running the apps
*/
- public static void initConfigurations(WidgetSet widgetset) {
-
- if (initedWidgetSet != null) {
- // Multiple widgetsets inited; can happen with custom WS + entry
- // point
- String msg = "Ignoring " + widgetset.getClass().getName()
- + ", because " + initedWidgetSet.getClass().getName()
- + " was already inited (if this is wrong, your entry point"
- + " is probably not first your .gwt.xml).";
- throw new IllegalStateException(msg);
- }
- initedWidgetSet = widgetset;
+ public static void initConfigurations() {
+
ArrayList<String> appIds = new ArrayList<String>();
loadAppIdListFromDOM(appIds);
for (Iterator<String> it = appIds.iterator(); it.hasNext();) {
String appId = it.next();
ApplicationConfiguration appConf = getConfigFromDOM(appId);
- ApplicationConnection a = new ApplicationConnection(widgetset,
+ ApplicationConnection a = new ApplicationConnection(widgetSet,
appConf);
unstartedApplications.add(a);
}
+
+ deferredWidgetLoadLoop.scheduleRepeating(100);
}
/**
for (int i = 0; i < keyArray.length(); i++) {
String key = keyArray.get(i).intern();
int value = valueMap.getInt(key);
- classes[value] = widgetSet.getImplementationByClassName(key, this);
+ classes[value] = widgetSet.getImplementationByClassName(key);
if (classes[value] == VUnknownComponent.class) {
if (unknownComponents == null) {
unknownComponents = new HashMap<String, String>();
*
* @param c
*/
- void runWhenWidgetsLoaded(Command c) {
+ static void runWhenWidgetsLoaded(Command c) {
if (widgetsLoading == 0) {
c.execute();
} else {
}
}
- void widgetLoadStart() {
+ static void startWidgetLoading() {
widgetsLoading++;
}
- void widgetLoaded() {
+ static void endWidgetLoading() {
widgetsLoading--;
if (widgetsLoading == 0 && !callbacks.isEmpty()) {
for (Command cmd : callbacks) {
}
}
+
+ /*
+ * This loop loads widget implementation that should be loaded deferred.
+ */
+ private static final Timer deferredWidgetLoadLoop = new Timer() {
+ private static final int FREE_LIMIT = 4;
+
+ int communicationFree = 0;
+ int nextWidgetIndex = 0;
+
+ @Override
+ public void run() {
+ if (!isBusy()) {
+ Class<? extends Paintable> nextType = getNextType();
+ if (nextType == null) {
+ // ensured that all widgets are loaded
+ cancel();
+ } else {
+ widgetSet.loadImplementation(nextType);
+ }
+ }
+ }
+
+ private Class<? extends Paintable> getNextType() {
+ Class<? extends Paintable>[] deferredLoadedWidgets = widgetSet
+ .getDeferredLoadedWidgets();
+ if (deferredLoadedWidgets.length <= nextWidgetIndex) {
+ return null;
+ } else {
+ return deferredLoadedWidgets[nextWidgetIndex++];
+ }
+ }
+
+ private boolean isBusy() {
+ if (widgetsLoading > 0) {
+ communicationFree = 0;
+ return false;
+ }
+ for (ApplicationConnection app : runningApplications) {
+ if (app.hasActiveRequest()) {
+ // if an UIDL request or widget loading is active, mark as
+ // busy
+ communicationFree = 0;
+ return false;
+ }
+ }
+ communicationFree++;
+ return communicationFree < FREE_LIMIT;
+ }
+ };
+
+ public void onModuleLoad() {
+ initConfigurations();
+ startNextApplication();
+ }
}
}
};
- configuration.runWhenWidgetsLoaded(c);
+ ApplicationConfiguration.runWhenWidgetsLoaded(c);
}
/**
+++ /dev/null
-/*
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client;
-
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ui.VButton;
-import com.vaadin.terminal.gwt.client.ui.VCheckBox;
-import com.vaadin.terminal.gwt.client.ui.VDateFieldCalendar;
-import com.vaadin.terminal.gwt.client.ui.VFilterSelect;
-import com.vaadin.terminal.gwt.client.ui.VListSelect;
-import com.vaadin.terminal.gwt.client.ui.VNativeSelect;
-import com.vaadin.terminal.gwt.client.ui.VOptionGroup;
-import com.vaadin.terminal.gwt.client.ui.VPasswordField;
-import com.vaadin.terminal.gwt.client.ui.VPopupCalendar;
-import com.vaadin.terminal.gwt.client.ui.VSplitPanelHorizontal;
-import com.vaadin.terminal.gwt.client.ui.VSplitPanelVertical;
-import com.vaadin.terminal.gwt.client.ui.VTextArea;
-import com.vaadin.terminal.gwt.client.ui.VTextField;
-import com.vaadin.terminal.gwt.client.ui.VTwinColSelect;
-import com.vaadin.terminal.gwt.client.ui.VUnknownComponent;
-import com.vaadin.terminal.gwt.client.ui.VView;
-import com.vaadin.terminal.gwt.client.ui.VWindow;
-
-public class DefaultWidgetSet implements WidgetSet {
-
- /**
- * DefaultWidgetSet (and its extensions) delegate instantiation of widgets
- * and client-server mathing to WidgetMap. The actual implementations are
- * generated with gwts deferred binding.
- */
- private WidgetMap map;
-
- /**
- * This is the entry point method. It will start the first
- */
- public void onModuleLoad() {
- try {
- ApplicationConfiguration.initConfigurations(this);
- } catch (Exception e) {
- // Log & don't continue;
- // custom WidgetSets w/ entry points will cause this
- ApplicationConnection.getConsole().log(e.getMessage());
- return;
- }
- ApplicationConfiguration.startNextApplication(); // start first app
- map = GWT.create(WidgetMap.class);
- }
-
- public Paintable createWidget(UIDL uidl, ApplicationConfiguration conf) {
- final Class<? extends Paintable> classType = resolveWidgetType(uidl,
- conf);
- if (classType == null || classType == VUnknownComponent.class) {
- String serverSideName = conf
- .getUnknownServerClassNameByEncodedTagName(uidl.getTag());
- return new VUnknownComponent(serverSideName);
- }
-
- return map.instantiate(classType);
- }
-
- protected Class<? extends Paintable> resolveWidgetType(UIDL uidl,
- ApplicationConfiguration conf) {
- final String tag = uidl.getTag();
-
- Class<? extends Paintable> widgetClass = conf
- .getWidgetClassByEncodedTag(tag);
-
- // add our historical quirks
-
- if (widgetClass == VButton.class && uidl.hasAttribute("type")) {
- return VCheckBox.class;
- } else if (widgetClass == VView.class && uidl.hasAttribute("sub")) {
- return VWindow.class;
- } else if (widgetClass == VFilterSelect.class) {
- if (uidl.hasAttribute("type")) {
- // TODO check if all type checks are really neede
- final String type = uidl.getStringAttribute("type").intern();
- if (type == "twincol") {
- return VTwinColSelect.class;
- } else if (type == "optiongroup") {
- return VOptionGroup.class;
- } else if (type == "native") {
- return VNativeSelect.class;
- } else if (type == "list") {
- return VListSelect.class;
- } else if (uidl.hasAttribute("selectmode")
- && uidl.getStringAttribute("selectmode")
- .equals("multi")) {
- return VListSelect.class;
- }
- }
- } else if (widgetClass == VTextField.class) {
- if (uidl.hasAttribute("multiline")) {
- return VTextArea.class;
- } else if (uidl.hasAttribute("secret")) {
- return VPasswordField.class;
- }
- } else if (widgetClass == VPopupCalendar.class) {
- if (uidl.hasAttribute("type")
- && uidl.getStringAttribute("type").equals("inline")) {
- return VDateFieldCalendar.class;
- }
- } else if (widgetClass == VSplitPanelHorizontal.class
- && uidl.hasAttribute("vertical")) {
- return VSplitPanelVertical.class;
- }
-
- return widgetClass;
-
- }
-
- public boolean isCorrectImplementation(Widget currentWidget, UIDL uidl,
- ApplicationConfiguration conf) {
- return currentWidget.getClass() == resolveWidgetType(uidl, conf);
- }
-
- public Class<? extends Paintable> getImplementationByClassName(
- String fullyqualifiedName,
- ApplicationConfiguration applicationConfiguration) {
- Class<? extends Paintable> implementationByServerSideClassName = map
- .getImplementationByServerSideClassName(fullyqualifiedName,
- applicationConfiguration);
- return implementationByServerSideClassName;
-
- }
-
-}
--- /dev/null
+package com.vaadin.terminal.gwt.client;
+
+/**
+ * A helper class used by WidgetMap implementation. Used by the generated code.
+ */
+interface WidgetInstantiator {
+ public Paintable get();
+}
--- /dev/null
+package com.vaadin.terminal.gwt.client;
+
+import com.google.gwt.core.client.RunAsyncCallback;
+
+/** A helper class used by WidgetMap implementation. Used by the generated code. */
+abstract class WidgetLoader implements RunAsyncCallback {
+
+ public void onFailure(Throwable reason) {
+ ApplicationConfiguration.endWidgetLoading();
+ }
+
+ public void onSuccess() {
+ addInstantiator();
+ ApplicationConfiguration.endWidgetLoading();
+ }
+
+ abstract void addInstantiator();
+}
*/
package com.vaadin.terminal.gwt.client;
-import com.vaadin.terminal.gwt.client.ui.VDateFieldCalendar;
-import com.vaadin.terminal.gwt.client.ui.VPasswordField;
-import com.vaadin.terminal.gwt.client.ui.VSplitPanelVertical;
-import com.vaadin.terminal.gwt.client.ui.VTextArea;
-import com.vaadin.terminal.gwt.client.ui.VWindow;
+import java.util.HashMap;
-public abstract class WidgetMap {
+abstract class WidgetMap {
- public Paintable instantiate(Class<? extends Paintable> classType) {
+ protected static HashMap<Class, WidgetInstantiator> instmap = new HashMap<Class, WidgetInstantiator>();
- /*
- * Yes, this (including the generated) may look very odd code, but due
- * the nature of GWT, we cannot do this with reflect. Luckily this is
- * mostly written by WidgetSetGenerator, here are just some hacks. Extra
- * instantiation code is needed if client side widget has no "native"
- * counterpart on client side.
- */
- if (VSplitPanelVertical.class == classType) {
- return new VSplitPanelVertical();
- } else if (VTextArea.class == classType) {
- return new VTextArea();
-
- } else if (VDateFieldCalendar.class == classType) {
- return new VDateFieldCalendar();
- } else if (VPasswordField.class == classType) {
- return new VPasswordField();
- } else if (VWindow.class == classType) {
- return new VWindow();
- } else {
- return null; // let generated type handle this
- }
+ public Paintable instantiate(Class<? extends Paintable> classType) {
+ return instmap.get(classType).get();
}
public abstract Class<? extends Paintable> getImplementationByServerSideClassName(
- String fullyqualifiedName,
- ApplicationConfiguration applicationConfiguration);
+ String fullyqualifiedName);
+
+ public abstract Class<? extends Paintable>[] getDeferredLoadedWidgets();
+
+ public abstract void ensureInstantiator(Class<? extends Paintable> classType);
}
package com.vaadin.terminal.gwt.client;
-import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ui.VButton;
+import com.vaadin.terminal.gwt.client.ui.VCheckBox;
+import com.vaadin.terminal.gwt.client.ui.VDateFieldCalendar;
+import com.vaadin.terminal.gwt.client.ui.VFilterSelect;
+import com.vaadin.terminal.gwt.client.ui.VListSelect;
+import com.vaadin.terminal.gwt.client.ui.VNativeSelect;
+import com.vaadin.terminal.gwt.client.ui.VOptionGroup;
+import com.vaadin.terminal.gwt.client.ui.VPasswordField;
+import com.vaadin.terminal.gwt.client.ui.VPopupCalendar;
+import com.vaadin.terminal.gwt.client.ui.VSplitPanelHorizontal;
+import com.vaadin.terminal.gwt.client.ui.VSplitPanelVertical;
+import com.vaadin.terminal.gwt.client.ui.VTextArea;
+import com.vaadin.terminal.gwt.client.ui.VTextField;
+import com.vaadin.terminal.gwt.client.ui.VTwinColSelect;
+import com.vaadin.terminal.gwt.client.ui.VUnknownComponent;
+import com.vaadin.terminal.gwt.client.ui.VView;
+import com.vaadin.terminal.gwt.client.ui.VWindow;
-public interface WidgetSet extends EntryPoint {
+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 component that best matches given UIDL. The
* @return New uninitialized and unregistered component that can paint given
* UIDL.
*/
- public Paintable createWidget(UIDL uidl, ApplicationConfiguration conf);
+ public Paintable createWidget(UIDL uidl, ApplicationConfiguration conf) {
+ /*
+ * Yes, this (including the generated code in WidgetMap) may look very
+ * odd code, but due the nature of GWT, we cannot do this any cleaner.
+ * Luckily this is mostly written by WidgetSetGenerator, here are just
+ * some hacks. Extra instantiation code is needed if client side widget
+ * has no "native" counterpart on client side.
+ *
+ * TODO should try to get rid of these exceptions here
+ */
+
+ final Class<? extends Paintable> classType = resolveWidgetType(uidl,
+ conf);
+ if (classType == null || classType == VUnknownComponent.class) {
+ String serverSideName = conf
+ .getUnknownServerClassNameByEncodedTagName(uidl.getTag());
+ return new VUnknownComponent(serverSideName);
+ } else if (VSplitPanelVertical.class == classType) {
+ return new VSplitPanelVertical();
+ } else if (VTextArea.class == classType) {
+ return new VTextArea();
+ } else if (VDateFieldCalendar.class == classType) {
+ return new VDateFieldCalendar();
+ } else if (VPasswordField.class == classType) {
+ return new VPasswordField();
+ } else if (VWindow.class == classType) {
+ return new VWindow();
+ } else {
+ /*
+ * let the auto generated code instantiate this type
+ */
+ return widgetMap.instantiate(classType);
+ }
+
+ }
+
+ protected Class<? extends Paintable> resolveWidgetType(UIDL uidl,
+ ApplicationConfiguration conf) {
+ final String tag = uidl.getTag();
+
+ Class<? extends Paintable> widgetClass = conf
+ .getWidgetClassByEncodedTag(tag);
+
+ // add our historical quirks
+
+ if (widgetClass == VButton.class && uidl.hasAttribute("type")) {
+ return VCheckBox.class;
+ } else if (widgetClass == VView.class && uidl.hasAttribute("sub")) {
+ return VWindow.class;
+ } else if (widgetClass == VFilterSelect.class) {
+ if (uidl.hasAttribute("type")) {
+ // TODO check if all type checks are really neede
+ final String type = uidl.getStringAttribute("type").intern();
+ if (type == "twincol") {
+ return VTwinColSelect.class;
+ } else if (type == "optiongroup") {
+ return VOptionGroup.class;
+ } else if (type == "native") {
+ return VNativeSelect.class;
+ } else if (type == "list") {
+ return VListSelect.class;
+ } else if (uidl.hasAttribute("selectmode")
+ && uidl.getStringAttribute("selectmode")
+ .equals("multi")) {
+ return VListSelect.class;
+ }
+ }
+ } else if (widgetClass == VTextField.class) {
+ if (uidl.hasAttribute("multiline")) {
+ return VTextArea.class;
+ } else if (uidl.hasAttribute("secret")) {
+ return VPasswordField.class;
+ }
+ } else if (widgetClass == VPopupCalendar.class) {
+ if (uidl.hasAttribute("type")
+ && uidl.getStringAttribute("type").equals("inline")) {
+ return VDateFieldCalendar.class;
+ }
+ } else if (widgetClass == VSplitPanelHorizontal.class
+ && uidl.hasAttribute("vertical")) {
+ return VSplitPanelVertical.class;
+ }
+
+ return widgetClass;
+
+ }
/**
* Test if the given component implementation conforms to UIDL.
* class than currentWidget
*/
public boolean isCorrectImplementation(Widget currentWidget, UIDL uidl,
- ApplicationConfiguration conf);
+ ApplicationConfiguration conf) {
+ return currentWidget.getClass() == resolveWidgetType(uidl, conf);
+ }
/**
* Due its nature, GWT does not support dynamic classloading. To bypass this
* @return
*/
public Class<? extends Paintable> getImplementationByClassName(
- String fullyQualifiedName,
- ApplicationConfiguration applicationConfiguration);
+ String fullyqualifiedName) {
+ Class<? extends Paintable> implementationByServerSideClassName = widgetMap
+ .getImplementationByServerSideClassName(fullyqualifiedName);
+ return implementationByServerSideClassName;
+
+ }
+
+ public Class<? extends Paintable>[] getDeferredLoadedWidgets() {
+ return widgetMap.getDeferredLoadedWidgets();
+ }
+
+ public void loadImplementation(Class<? extends Paintable> nextType) {
+ widgetMap.ensureInstantiator(nextType);
+ }
}
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
+import java.util.LinkedList;
import java.util.TreeSet;
import com.google.gwt.core.ext.Generator;
import com.vaadin.terminal.Paintable;
import com.vaadin.terminal.gwt.client.ui.VView;
import com.vaadin.ui.ClientWidget;
+import com.vaadin.ui.ClientWidget.LoadStyle;
/**
* GWT generator to build WidgetMapImpl dynamically based on
* @return true iff the widget for given component should be lazy loaded by
* the client side engine
*/
- protected boolean isLazyLoaded(Class<? extends Paintable> paintableType) {
+ protected LoadStyle getLoadStyle(Class<? extends Paintable> paintableType) {
ClientWidget annotation = paintableType
.getAnnotation(ClientWidget.class);
- return annotation.lazyLoad();
+ return annotation.loadStyle();
}
private void generateInstantiatorMethod(
SourceWriter sourceWriter,
Collection<Class<? extends Paintable>> paintablesHavingWidgetAnnotation) {
- sourceWriter
- .println("public interface Instantiator { public Paintable get();};");
+ Collection<Class<?>> deferredWidgets = new LinkedList<Class<?>>();
// TODO detect if it would be noticably faster to instantiate with a
// lookup with index than with the hashmap
sourceWriter
- .println("private HashMap<Class,Instantiator> instmap = new HashMap<Class,Instantiator>();");
-
- sourceWriter
- .println("public void ensureInstantiator(Class<? extends Paintable> classType, final ApplicationConfiguration c) {");
+ .println("public void ensureInstantiator(Class<? extends Paintable> classType) {");
sourceWriter.println("if(!instmap.containsKey(classType)){");
+ boolean first = true;
+
for (Class<? extends Paintable> class1 : paintablesHavingWidgetAnnotation) {
ClientWidget annotation = class1.getAnnotation(ClientWidget.class);
Class<? extends com.vaadin.terminal.gwt.client.Paintable> clientClass = annotation
// VView's are not instantiated by widgetset
continue;
}
+ if (!first) {
+ sourceWriter.print(" else ");
+ } else {
+ first = false;
+ }
sourceWriter.print("if( classType == " + clientClass.getName()
+ ".class) {");
- String instantiator = "new Instantiator() { public Paintable get(){ return GWT.create("
- + clientClass.getName() + ".class );}}";
+ String instantiator = "new WidgetInstantiator() {\n public Paintable get() {\n return GWT.create("
+ + clientClass.getName() + ".class );\n}\n}\n";
- if (isLazyLoaded(class1)) {
- sourceWriter
- .print("c.widgetLoadStart();GWT.runAsync(new RunAsyncCallback() {\n"
- + " public void onSuccess() {");
+ LoadStyle loadStyle = getLoadStyle(class1);
- sourceWriter.print("instmap.put(");
- sourceWriter.print(clientClass.getName());
- sourceWriter.print(".class, ");
- sourceWriter.print(instantiator);
- sourceWriter.println("); c.widgetLoaded();");
+ if (loadStyle != LoadStyle.EAGER) {
sourceWriter
- .print(" }\n"
- + "\n"
- + " public void onFailure(Throwable reason) {c.widgetLoaded();\n"
- + "\n" + " }\n" + " });\n");
+ .print("ApplicationConfiguration.startWidgetLoading();\n"
+ + "GWT.runAsync( \n"
+ + "new WidgetLoader() { void addInstantiator() {instmap.put("
+ + clientClass.getName()
+ + ".class,"
+ + instantiator + ");}});\n");
+
+ if (loadStyle == LoadStyle.DEFERRED) {
+ deferredWidgets.add(class1);
+ }
} else {
// widget implementation in initially loaded js script
sourceWriter.println("}");
sourceWriter
- .println("public Paintable instantiate(Class<? extends Paintable> classType) {");
- sourceWriter.indent();
- sourceWriter
- .println("Paintable p = super.instantiate(classType); if(p!= null) return p;");
- sourceWriter.println("return instmap.get(classType).get();");
+ .println("public Class<? extends Paintable>[] getDeferredLoadedWidgets() {");
- sourceWriter.outdent();
+ sourceWriter.println("return new Class[] {");
+ first = true;
+ for (Class<?> class2 : deferredWidgets) {
+ if (!first) {
+ sourceWriter.println(",");
+ }
+ first = false;
+ ClientWidget annotation = class2.getAnnotation(ClientWidget.class);
+ Class<? extends com.vaadin.terminal.gwt.client.Paintable> value = annotation
+ .value();
+ sourceWriter.print(value.getName() + ".class");
+ }
+
+ sourceWriter.println("};");
sourceWriter.println("}");
}
Collection<Class<? extends Paintable>> paintablesHavingWidgetAnnotation) {
sourceWriter
.println("public Class<? extends Paintable> "
- + "getImplementationByServerSideClassName(String fullyQualifiedName, ApplicationConfiguration c) {");
+ + "getImplementationByServerSideClassName(String fullyQualifiedName) {");
sourceWriter.indent();
sourceWriter
.println("fullyQualifiedName = fullyQualifiedName.intern();");
sourceWriter.print("if ( fullyQualifiedName == \"");
sourceWriter.print(class1.getName());
sourceWriter.print("\" ) { ensureInstantiator("
- + clientClass.getName() + ".class, c); return ");
+ + clientClass.getName() + ".class); return ");
sourceWriter.print(clientClass.getName());
sourceWriter.println(".class;}");
sourceWriter.print("else ");