summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyGenerator.java7
-rw-r--r--client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java24
-rw-r--r--client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetMapGenerator.java30
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java123
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/JavaScriptConnectorHelper.java5
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/ServerConnector.java16
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/Util.java8
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/communication/StateChangeEvent.java41
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/extensions/javascriptmanager/JavaScriptManagerConnector.java2
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/ui/AbstractConnector.java31
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/ui/button/ButtonConnector.java84
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java50
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java20
-rw-r--r--server/src/com/vaadin/Application.java75
-rw-r--r--server/src/com/vaadin/terminal/AbstractClientConnector.java5
-rw-r--r--server/src/com/vaadin/terminal/DeploymentConfiguration.java21
-rw-r--r--server/src/com/vaadin/terminal/Page.java20
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java215
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java139
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java50
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/AbstractDeploymentConfiguration.java73
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/ClientConnector.java20
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/DragAndDropService.java5
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/JsonCodec.java40
-rw-r--r--server/src/com/vaadin/ui/AbsoluteLayout.java4
-rw-r--r--server/src/com/vaadin/ui/AbstractComponent.java8
-rw-r--r--server/src/com/vaadin/ui/AbstractField.java4
-rw-r--r--server/src/com/vaadin/ui/AbstractTextField.java4
-rw-r--r--server/src/com/vaadin/ui/Component.java12
-rw-r--r--server/src/com/vaadin/ui/ConnectorTracker.java60
-rw-r--r--server/src/com/vaadin/ui/CssLayout.java4
-rw-r--r--server/src/com/vaadin/ui/Root.java13
-rw-r--r--server/src/com/vaadin/ui/Window.java19
-rw-r--r--shared/src/com/vaadin/shared/annotations/Delayed.java54
-rw-r--r--shared/src/com/vaadin/shared/communication/LegacyChangeVariablesInvocation.java (renamed from server/src/com/vaadin/terminal/gwt/server/LegacyChangeVariablesInvocation.java)13
-rw-r--r--shared/src/com/vaadin/shared/communication/MethodInvocation.java14
-rw-r--r--shared/src/com/vaadin/shared/ui/root/RootConstants.java4
-rw-r--r--shared/src/com/vaadin/shared/ui/root/RootServerRpc.java5
-rw-r--r--shared/src/com/vaadin/shared/ui/root/RootState.java8
-rw-r--r--tests/sass/src/com/vaadin/sass/testcases/scss/Comments.java6
-rw-r--r--tests/server-side/com/vaadin/tests/server/TransactionListenersConcurrency.java24
-rw-r--r--tests/server-side/com/vaadin/tests/server/component/root/CustomRootClassLoader.java23
-rw-r--r--tests/testbench/com/vaadin/tests/serialization/SerializerNamespaceTest.java44
-rw-r--r--tests/testbench/com/vaadin/tests/serialization/SerializerTest.html40
-rw-r--r--tests/testbench/com/vaadin/tests/serialization/SerializerTest.java12
-rw-r--r--tests/testbench/com/vaadin/tests/widgetset/client/DummyLabelConnector.java50
-rw-r--r--tests/testbench/com/vaadin/tests/widgetset/client/LabelState.java41
-rw-r--r--tests/testbench/com/vaadin/tests/widgetset/client/SerializerTestConnector.java11
-rw-r--r--tests/testbench/com/vaadin/tests/widgetset/client/SerializerTestRpc.java3
-rw-r--r--tests/testbench/com/vaadin/tests/widgetset/server/DummyLabel.java38
50 files changed, 1119 insertions, 503 deletions
diff --git a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyGenerator.java b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyGenerator.java
index a54798e5d6..6d322c734e 100644
--- a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyGenerator.java
+++ b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyGenerator.java
@@ -29,6 +29,7 @@ import com.google.gwt.core.ext.typeinfo.JParameter;
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.annotations.Delayed;
import com.vaadin.shared.communication.MethodInvocation;
import com.vaadin.shared.communication.ServerRpc;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
@@ -129,6 +130,10 @@ public class RpcProxyGenerator extends Generator {
writer.println(" {");
writer.indent();
+ Delayed delayedAnnotation = m.getAnnotation(Delayed.class);
+ boolean delayed = delayedAnnotation != null;
+ boolean lastonly = delayed && delayedAnnotation.lastonly();
+
writer.print("this.connector.getConnection().addMethodInvocationToQueue(new MethodInvocation(this.connector.getConnectorId(), \""
+ requestedType.getQualifiedBinaryName() + "\", \"");
writer.print(m.getName());
@@ -145,7 +150,7 @@ public class RpcProxyGenerator extends Generator {
writer.print(p.getName());
}
- writer.println("}), true);");
+ writer.println("}), " + delayed + ", " + lastonly + ");");
writer.outdent();
writer.println("}");
diff --git a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java
index 2fc9645940..cc92551846 100644
--- a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java
+++ b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java
@@ -32,6 +32,7 @@ import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JEnumConstant;
import com.google.gwt.core.ext.typeinfo.JEnumType;
import com.google.gwt.core.ext.typeinfo.JMethod;
+import com.google.gwt.core.ext.typeinfo.JPackage;
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.TypeOracleException;
@@ -59,8 +60,6 @@ import com.vaadin.terminal.gwt.client.communication.SerializerMap;
public class SerializerGenerator extends Generator {
private static final String SUBTYPE_SEPARATOR = "___";
- private static String serializerPackageName = SerializerMap.class
- .getPackage().getName();
@Override
public String generate(TreeLogger logger, GeneratorContext context,
@@ -75,8 +74,8 @@ public class SerializerGenerator extends Generator {
String serializerClassName = getSerializerSimpleClassName(type);
try {
// Generate class source code
- generateClass(logger, context, type, serializerPackageName,
- serializerClassName);
+ generateClass(logger, context, type,
+ getSerializerPackageName(type), serializerClassName);
} catch (Exception e) {
logger.log(TreeLogger.ERROR, "SerializerGenerator failed for "
+ type.getQualifiedSourceName(), e);
@@ -465,6 +464,21 @@ public class SerializerGenerator extends Generator {
}
public static String getFullyQualifiedSerializerClassName(JClassType type) {
- return serializerPackageName + "." + getSerializerSimpleClassName(type);
+ return getSerializerPackageName(type) + "."
+ + getSerializerSimpleClassName(type);
+ }
+
+ private static String getSerializerPackageName(JClassType type) {
+ JPackage typePackage = type.getPackage();
+ if (typePackage == null) {
+ return SerializerMap.class.getPackage().getName();
+ } else {
+ String packageName = typePackage.getName();
+ // Dev mode classloader gets unhappy for some java packages
+ if (packageName.startsWith("java.")) {
+ packageName = "com.vaadin." + packageName;
+ }
+ return packageName;
+ }
}
}
diff --git a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetMapGenerator.java b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetMapGenerator.java
index dae6f2821e..1f5b301802 100644
--- a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetMapGenerator.java
+++ b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetMapGenerator.java
@@ -23,6 +23,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
+import java.util.Map;
import java.util.TreeSet;
import com.google.gwt.core.ext.Generator;
@@ -116,8 +117,10 @@ public class WidgetMapGenerator extends Generator {
* Logger object
* @param context
* Generator context
+ * @throws UnableToCompleteException
*/
- private void generateClass(TreeLogger logger, GeneratorContext context) {
+ private void generateClass(TreeLogger logger, GeneratorContext context)
+ throws UnableToCompleteException {
// get print writer that receives the source code
PrintWriter printWriter = null;
printWriter = context.tryCreate(logger, packageName, className);
@@ -147,7 +150,7 @@ public class WidgetMapGenerator extends Generator {
logConnectors(logger, context, connectors);
// generator constructor source code
- generateImplementationDetector(sourceWriter, connectors);
+ generateImplementationDetector(logger, sourceWriter, connectors);
generateInstantiatorMethod(sourceWriter, connectors);
// close generated class
sourceWriter.outdent();
@@ -369,13 +372,18 @@ public class WidgetMapGenerator extends Generator {
/**
*
+ * @param logger
+ * logger to print messages to
* @param sourceWriter
* Source writer to output source code
* @param paintablesHavingWidgetAnnotation
+ * @throws UnableToCompleteException
*/
private void generateImplementationDetector(
+ TreeLogger logger,
SourceWriter sourceWriter,
- Collection<Class<? extends ServerConnector>> paintablesHavingWidgetAnnotation) {
+ Collection<Class<? extends ServerConnector>> paintablesHavingWidgetAnnotation)
+ throws UnableToCompleteException {
sourceWriter
.println("public Class<? extends "
+ serverConnectorClassName
@@ -385,8 +393,24 @@ public class WidgetMapGenerator extends Generator {
sourceWriter
.println("fullyQualifiedName = fullyQualifiedName.intern();");
+ // Keep track of encountered mappings to detect conflicts
+ Map<Class<? extends ClientConnector>, Class<? extends ServerConnector>> mappings = new HashMap<Class<? extends ClientConnector>, Class<? extends ServerConnector>>();
+
for (Class<? extends ServerConnector> connectorClass : paintablesHavingWidgetAnnotation) {
Class<? extends ClientConnector> clientConnectorClass = getClientConnectorClass(connectorClass);
+
+ // Check for conflicts
+ Class<? extends ServerConnector> prevousMapping = mappings.put(
+ clientConnectorClass, connectorClass);
+ if (prevousMapping != null) {
+ logger.log(Type.ERROR,
+ "Both " + connectorClass.getName() + " and "
+ + prevousMapping.getName()
+ + " have @Connect referring to "
+ + clientConnectorClass.getName() + ".");
+ throw new UnableToCompleteException();
+ }
+
sourceWriter.print("if ( fullyQualifiedName == \"");
sourceWriter.print(clientConnectorClass.getName());
sourceWriter.print("\" ) { ensureInstantiator("
diff --git a/client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
index a8852fe9fa..32b15d6d87 100644
--- a/client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
+++ b/client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
@@ -22,6 +22,7 @@ import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -54,9 +55,9 @@ import com.google.gwt.user.client.ui.Widget;
import com.vaadin.shared.ApplicationConstants;
import com.vaadin.shared.ComponentState;
import com.vaadin.shared.Version;
+import com.vaadin.shared.communication.LegacyChangeVariablesInvocation;
import com.vaadin.shared.communication.MethodInvocation;
import com.vaadin.shared.communication.SharedState;
-import com.vaadin.shared.communication.UidlValue;
import com.vaadin.terminal.gwt.client.ApplicationConfiguration.ErrorMessage;
import com.vaadin.terminal.gwt.client.ResourceLoader.ResourceLoadEvent;
import com.vaadin.terminal.gwt.client.ResourceLoader.ResourceLoadListener;
@@ -132,7 +133,18 @@ public class ApplicationConnection {
private final HashMap<String, String> resourcesMap = new HashMap<String, String>();
- private ArrayList<MethodInvocation> pendingInvocations = new ArrayList<MethodInvocation>();
+ /**
+ * The pending method invocations that will be send to the server by
+ * {@link #sendPendingCommand}. The key is defined differently based on
+ * whether the method invocation is enqueued with lastonly. With lastonly
+ * enabled, the method signature ( {@link MethodInvocation#getLastonlyTag()}
+ * ) is used as the key to make enable removing a previously enqueued
+ * invocation. Without lastonly, an incremental id based on
+ * {@link #lastInvocationTag} is used to get unique values.
+ */
+ private LinkedHashMap<String, MethodInvocation> pendingInvocations = new LinkedHashMap<String, MethodInvocation>();
+
+ private int lastInvocationTag = 0;
private WidgetSet widgetSet;
@@ -155,7 +167,7 @@ public class ApplicationConnection {
private ApplicationConfiguration configuration;
/** List of pending variable change bursts that must be submitted in order */
- private final ArrayList<ArrayList<MethodInvocation>> pendingBursts = new ArrayList<ArrayList<MethodInvocation>>();
+ private final ArrayList<LinkedHashMap<String, MethodInvocation>> pendingBursts = new ArrayList<LinkedHashMap<String, MethodInvocation>>();
/** Timer for automatic refirect to SessionExpiredURL */
private Timer redirectTimer;
@@ -886,12 +898,11 @@ public class ApplicationConnection {
private void checkForPendingVariableBursts() {
cleanVariableBurst(pendingInvocations);
if (pendingBursts.size() > 0) {
- for (Iterator<ArrayList<MethodInvocation>> iterator = pendingBursts
- .iterator(); iterator.hasNext();) {
- cleanVariableBurst(iterator.next());
+ for (LinkedHashMap<String, MethodInvocation> pendingBurst : pendingBursts) {
+ cleanVariableBurst(pendingBurst);
}
- ArrayList<MethodInvocation> nextBurst = pendingBursts.get(0);
- pendingBursts.remove(0);
+ LinkedHashMap<String, MethodInvocation> nextBurst = pendingBursts
+ .remove(0);
buildAndSendVariableBurst(nextBurst, false);
}
}
@@ -902,13 +913,15 @@ public class ApplicationConnection {
*
* @param variableBurst
*/
- private void cleanVariableBurst(ArrayList<MethodInvocation> variableBurst) {
- for (int i = 1; i < variableBurst.size(); i++) {
- String id = variableBurst.get(i).getConnectorId();
+ private void cleanVariableBurst(
+ LinkedHashMap<String, MethodInvocation> variableBurst) {
+ Iterator<MethodInvocation> iterator = variableBurst.values().iterator();
+ while (iterator.hasNext()) {
+ String id = iterator.next().getConnectorId();
if (!getConnectorMap().hasConnector(id)
&& !getConnectorMap().isDragAndDropPaintable(id)) {
// variable owner does not exist anymore
- variableBurst.remove(i);
+ iterator.remove();
VConsole.log("Removed variable from removed component: " + id);
}
}
@@ -1460,9 +1473,12 @@ public class ApplicationConnection {
.getName(), null), stateJson, state,
ApplicationConnection.this);
- StateChangeEvent event = GWT
- .create(StateChangeEvent.class);
- event.setConnector(connector);
+ Set<String> changedProperties = new HashSet<String>();
+ addJsonFields(stateJson, changedProperties, "");
+
+ StateChangeEvent event = new StateChangeEvent(
+ connector, changedProperties);
+
events.add(event);
}
} catch (final Throwable e) {
@@ -1474,6 +1490,30 @@ public class ApplicationConnection {
}
/**
+ * Recursively adds the names of all fields in all objects in the
+ * provided json object.
+ *
+ * @param json
+ * the json object to process
+ * @param fields
+ * a set of all currently added fields
+ * @param context
+ * the base name of the current object
+ */
+ private void addJsonFields(JSONObject json, Set<String> fields,
+ String context) {
+ for (String key : json.keySet()) {
+ String fieldName = context + key;
+ fields.add(fieldName);
+
+ JSONObject object = json.get(key).isObject();
+ if (object != null) {
+ addJsonFields(object, fields, fieldName + ".");
+ }
+ }
+ }
+
+ /**
* Updates the connector hierarchy and returns a list of events that
* should be fired after update of the hierarchy and the state is
* done.
@@ -1693,12 +1733,10 @@ public class ApplicationConnection {
private void addVariableToQueue(String connectorId, String variableName,
Object value, boolean immediate) {
+ boolean lastOnly = !immediate;
// note that type is now deduced from value
- // TODO could eliminate invocations of same shared variable setter
- addMethodInvocationToQueue(new MethodInvocation(connectorId,
- ApplicationConstants.UPDATE_VARIABLE_INTERFACE,
- ApplicationConstants.UPDATE_VARIABLE_METHOD, new Object[] {
- variableName, new UidlValue(value) }), immediate);
+ addMethodInvocationToQueue(new LegacyChangeVariablesInvocation(
+ connectorId, variableName, value), lastOnly, lastOnly);
}
/**
@@ -1708,16 +1746,31 @@ public class ApplicationConnection {
*
* @param invocation
* RPC method invocation
- * @param immediate
- * true to trigger sending within a short time window (possibly
- * combining subsequent calls to a single request), false to let
- * the framework delay sending of RPC calls and variable changes
- * until the next immediate change
+ * @param delayed
+ * <code>false</code> to trigger sending within a short time
+ * window (possibly combining subsequent calls to a single
+ * request), <code>true</code> to let the framework delay sending
+ * of RPC calls and variable changes until the next non-delayed
+ * change
+ * @param lastonly
+ * <code>true</code> to remove all previously delayed invocations
+ * of the same method that were also enqueued with lastonly set
+ * to <code>true</code>. <code>false</code> to add invocation to
+ * the end of the queue without touching previously enqueued
+ * invocations.
*/
public void addMethodInvocationToQueue(MethodInvocation invocation,
- boolean immediate) {
- pendingInvocations.add(invocation);
- if (immediate) {
+ boolean delayed, boolean lastonly) {
+ String tag;
+ if (lastonly) {
+ tag = invocation.getLastonlyTag();
+ assert !tag.matches("\\d+") : "getLastonlyTag value must have at least one non-digit character";
+ pendingInvocations.remove(tag);
+ } else {
+ tag = Integer.toString(lastInvocationTag++);
+ }
+ pendingInvocations.put(tag, invocation);
+ if (!delayed) {
sendPendingVariableChanges();
}
}
@@ -1748,14 +1801,15 @@ public class ApplicationConnection {
};
private boolean deferedSendPending = false;
- @SuppressWarnings("unchecked")
private void doSendPendingVariableChanges() {
if (applicationRunning) {
if (hasActiveRequest()) {
// skip empty queues if there are pending bursts to be sent
if (pendingInvocations.size() > 0 || pendingBursts.size() == 0) {
pendingBursts.add(pendingInvocations);
- pendingInvocations = new ArrayList<MethodInvocation>();
+ pendingInvocations = new LinkedHashMap<String, MethodInvocation>();
+ // Keep tag string short
+ lastInvocationTag = 0;
}
} else {
buildAndSendVariableBurst(pendingInvocations, false);
@@ -1776,17 +1830,18 @@ public class ApplicationConnection {
* Should we use synchronous request?
*/
private void buildAndSendVariableBurst(
- ArrayList<MethodInvocation> pendingInvocations, boolean forceSync) {
+ LinkedHashMap<String, MethodInvocation> pendingInvocations,
+ boolean forceSync) {
final StringBuffer req = new StringBuffer();
while (!pendingInvocations.isEmpty()) {
if (ApplicationConfiguration.isDebugMode()) {
- Util.logVariableBurst(this, pendingInvocations);
+ Util.logVariableBurst(this, pendingInvocations.values());
}
JSONArray reqJson = new JSONArray();
- for (MethodInvocation invocation : pendingInvocations) {
+ for (MethodInvocation invocation : pendingInvocations.values()) {
JSONArray invocationJson = new JSONArray();
invocationJson.set(0,
new JSONString(invocation.getConnectorId()));
@@ -1810,6 +1865,8 @@ public class ApplicationConnection {
req.append(escapeBurstContents(reqJson.toString()));
pendingInvocations.clear();
+ // Keep tag string short
+ lastInvocationTag = 0;
// Append all the bursts to this synchronous request
if (forceSync && !pendingBursts.isEmpty()) {
pendingInvocations = pendingBursts.get(0);
diff --git a/client/src/com/vaadin/terminal/gwt/client/JavaScriptConnectorHelper.java b/client/src/com/vaadin/terminal/gwt/client/JavaScriptConnectorHelper.java
index 98c014b5ec..6494ae3480 100644
--- a/client/src/com/vaadin/terminal/gwt/client/JavaScriptConnectorHelper.java
+++ b/client/src/com/vaadin/terminal/gwt/client/JavaScriptConnectorHelper.java
@@ -267,7 +267,7 @@ public class JavaScriptConnectorHelper {
}
connector.getConnection().addMethodInvocationToQueue(
new MethodInvocation(connector.getConnectorId(), iface, method,
- parameters), true);
+ parameters), false, false);
}
private String findWildcardInterface(String method) {
@@ -298,7 +298,8 @@ public class JavaScriptConnectorHelper {
connector.getConnectorId(),
"com.vaadin.ui.JavaScript$JavaScriptCallbackRpc", "call",
new Object[] { name, new JSONArray(arguments) });
- connector.getConnection().addMethodInvocationToQueue(invocation, true);
+ connector.getConnection().addMethodInvocationToQueue(invocation, false,
+ false);
}
public void setNativeState(JavaScriptObject state) {
diff --git a/client/src/com/vaadin/terminal/gwt/client/ServerConnector.java b/client/src/com/vaadin/terminal/gwt/client/ServerConnector.java
index fa78f886a7..8788de74bf 100644
--- a/client/src/com/vaadin/terminal/gwt/client/ServerConnector.java
+++ b/client/src/com/vaadin/terminal/gwt/client/ServerConnector.java
@@ -75,7 +75,7 @@ public interface ServerConnector extends Connector {
String rpcInterfaceId);
/**
- * Adds a handler that is called whenever some part of the state has been
+ * Adds a handler that is called whenever any part of the state has been
* updated by the server.
*
* @param handler
@@ -86,13 +86,19 @@ public interface ServerConnector extends Connector {
public HandlerRegistration addStateChangeHandler(StateChangeHandler handler);
/**
- * Removes the specified StateChangeHandler from this connector. The handler
- * will no longer be notified of the state is updated by the server.
+ * Adds a handler that is called whenever the given part of the state has
+ * been updated by the server.
*
+ * @param propertyName
+ * the name of the property for which the handler should be
+ * called
* @param handler
- * The handler that should be removed.
+ * The handler that should be added.
+ * @return A handler registration reference that can be used to unregister
+ * the handler
*/
- public void removeStateChangeHandler(StateChangeHandler handler);
+ public HandlerRegistration addStateChangeHandler(String propertyName,
+ StateChangeHandler handler);
/**
* Sends the given event to all registered handlers.
diff --git a/client/src/com/vaadin/terminal/gwt/client/Util.java b/client/src/com/vaadin/terminal/gwt/client/Util.java
index 571258dbe3..96344f0792 100644
--- a/client/src/com/vaadin/terminal/gwt/client/Util.java
+++ b/client/src/com/vaadin/terminal/gwt/client/Util.java
@@ -874,13 +874,13 @@ public class Util {
}
static void logVariableBurst(ApplicationConnection c,
- ArrayList<MethodInvocation> loggedBurst) {
+ Collection<MethodInvocation> loggedBurst) {
try {
VConsole.log("Variable burst to be sent to server:");
String curId = null;
ArrayList<MethodInvocation> invocations = new ArrayList<MethodInvocation>();
- for (int i = 0; i < loggedBurst.size(); i++) {
- String id = loggedBurst.get(i).getConnectorId();
+ for (MethodInvocation methodInvocation : loggedBurst) {
+ String id = methodInvocation.getConnectorId();
if (curId == null) {
curId = id;
@@ -889,7 +889,7 @@ public class Util {
invocations.clear();
curId = id;
}
- invocations.add(loggedBurst.get(i));
+ invocations.add(methodInvocation);
}
if (!invocations.isEmpty()) {
printConnectorInvocations(invocations, curId, c);
diff --git a/client/src/com/vaadin/terminal/gwt/client/communication/StateChangeEvent.java b/client/src/com/vaadin/terminal/gwt/client/communication/StateChangeEvent.java
index e1847bdab7..8ed32bc94b 100644
--- a/client/src/com/vaadin/terminal/gwt/client/communication/StateChangeEvent.java
+++ b/client/src/com/vaadin/terminal/gwt/client/communication/StateChangeEvent.java
@@ -16,8 +16,11 @@
package com.vaadin.terminal.gwt.client.communication;
import java.io.Serializable;
+import java.util.Collections;
+import java.util.Set;
import com.google.gwt.event.shared.EventHandler;
+import com.vaadin.terminal.gwt.client.ServerConnector;
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent.StateChangeHandler;
public class StateChangeEvent extends
@@ -27,12 +30,25 @@ public class StateChangeEvent extends
*/
public static final Type<StateChangeHandler> TYPE = new Type<StateChangeHandler>();
+ private Set<String> changedProperties;
+
@Override
public Type<StateChangeHandler> getAssociatedType() {
return TYPE;
}
- public StateChangeEvent() {
+ /**
+ * Creates a new state change event.
+ *
+ * @param connector
+ * the event whose state has changed
+ * @param changedProperties
+ * a set of names of the changed properties
+ */
+ public StateChangeEvent(ServerConnector connector,
+ Set<String> changedProperties) {
+ setConnector(connector);
+ this.changedProperties = changedProperties;
}
@Override
@@ -40,7 +56,30 @@ public class StateChangeEvent extends
listener.onStateChanged(this);
}
+ /**
+ * Event handler that gets notified whenever any part of the state has been
+ * updated by the server.
+ *
+ * @author Vaadin Ltd
+ * @version @VERSION@
+ * @since 7.0.0
+ */
public interface StateChangeHandler extends Serializable, EventHandler {
+ /**
+ * Notifies the event handler that the state has changed.
+ *
+ * @param stateChangeEvent
+ * the state change event with details about the change
+ */
public void onStateChanged(StateChangeEvent stateChangeEvent);
}
+
+ /**
+ * Gets the properties that have changed.
+ *
+ * @return a set of names of the changed properties
+ */
+ public Set<String> getChangedProperties() {
+ return Collections.unmodifiableSet(changedProperties);
+ }
}
diff --git a/client/src/com/vaadin/terminal/gwt/client/extensions/javascriptmanager/JavaScriptManagerConnector.java b/client/src/com/vaadin/terminal/gwt/client/extensions/javascriptmanager/JavaScriptManagerConnector.java
index 5cc5911bb1..46578b0641 100644
--- a/client/src/com/vaadin/terminal/gwt/client/extensions/javascriptmanager/JavaScriptManagerConnector.java
+++ b/client/src/com/vaadin/terminal/gwt/client/extensions/javascriptmanager/JavaScriptManagerConnector.java
@@ -124,7 +124,7 @@ public class JavaScriptManagerConnector extends AbstractExtensionConnector {
getConnection().addMethodInvocationToQueue(
new MethodInvocation(getConnectorId(),
"com.vaadin.ui.JavaScript$JavaScriptCallbackRpc",
- "call", parameters), true);
+ "call", parameters), false, false);
}
@Override
diff --git a/client/src/com/vaadin/terminal/gwt/client/ui/AbstractConnector.java b/client/src/com/vaadin/terminal/gwt/client/ui/AbstractConnector.java
index 09b7556293..435fff8a5b 100644
--- a/client/src/com/vaadin/terminal/gwt/client/ui/AbstractConnector.java
+++ b/client/src/com/vaadin/terminal/gwt/client/ui/AbstractConnector.java
@@ -48,6 +48,7 @@ public abstract class AbstractConnector implements ServerConnector,
private String id;
private HandlerManager handlerManager;
+ private Map<String, HandlerManager> statePropertyHandlerManagers;
private Map<String, Collection<ClientRpc>> rpcImplementations;
private final boolean debugLogging = false;
@@ -168,6 +169,17 @@ public abstract class AbstractConnector implements ServerConnector,
if (handlerManager != null) {
handlerManager.fireEvent(event);
}
+ if (statePropertyHandlerManagers != null
+ && event instanceof StateChangeEvent) {
+ for (String property : ((StateChangeEvent) event)
+ .getChangedProperties()) {
+ HandlerManager manager = statePropertyHandlerManagers
+ .get(property);
+ if (manager != null) {
+ manager.fireEvent(event);
+ }
+ }
+ }
}
protected HandlerManager ensureHandlerManager() {
@@ -185,10 +197,25 @@ public abstract class AbstractConnector implements ServerConnector,
}
@Override
- public void removeStateChangeHandler(StateChangeHandler handler) {
- ensureHandlerManager().removeHandler(StateChangeEvent.TYPE, handler);
+ public HandlerRegistration addStateChangeHandler(String propertyName,
+ StateChangeHandler handler) {
+ return ensureHandlerManager(propertyName).addHandler(
+ StateChangeEvent.TYPE, handler);
+ }
+
+ private HandlerManager ensureHandlerManager(String propertyName) {
+ if (statePropertyHandlerManagers == null) {
+ statePropertyHandlerManagers = new HashMap<String, HandlerManager>();
+ }
+ HandlerManager manager = statePropertyHandlerManagers.get(propertyName);
+ if (manager == null) {
+ manager = new HandlerManager(this);
+ statePropertyHandlerManagers.put(propertyName, manager);
+ }
+ return manager;
}
+ @Override
public void onStateChanged(StateChangeEvent stateChangeEvent) {
if (debugLogging) {
VConsole.log("State change event for "
diff --git a/client/src/com/vaadin/terminal/gwt/client/ui/button/ButtonConnector.java b/client/src/com/vaadin/terminal/gwt/client/ui/button/ButtonConnector.java
index 59e187014c..59f90a9840 100644
--- a/client/src/com/vaadin/terminal/gwt/client/ui/button/ButtonConnector.java
+++ b/client/src/com/vaadin/terminal/gwt/client/ui/button/ButtonConnector.java
@@ -16,6 +16,8 @@
package com.vaadin.terminal.gwt.client.ui.button;
+import java.util.Set;
+
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickEvent;
@@ -34,6 +36,7 @@ import com.vaadin.terminal.gwt.client.EventHelper;
import com.vaadin.terminal.gwt.client.MouseEventDetailsBuilder;
import com.vaadin.terminal.gwt.client.communication.RpcProxy;
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
+import com.vaadin.terminal.gwt.client.communication.StateChangeEvent.StateChangeHandler;
import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector;
import com.vaadin.terminal.gwt.client.ui.Icon;
import com.vaadin.ui.Button;
@@ -59,6 +62,47 @@ public class ButtonConnector extends AbstractComponentConnector implements
super.init();
getWidget().addClickHandler(this);
getWidget().client = getConnection();
+ addStateChangeHandler("errorMessage", new StateChangeHandler() {
+ @Override
+ public void onStateChanged(StateChangeEvent stateChangeEvent) {
+ if (null != getState().getErrorMessage()) {
+ if (getWidget().errorIndicatorElement == null) {
+ getWidget().errorIndicatorElement = DOM.createSpan();
+ getWidget().errorIndicatorElement
+ .setClassName("v-errorindicator");
+ }
+ getWidget().wrapper.insertBefore(
+ getWidget().errorIndicatorElement,
+ getWidget().captionElement);
+
+ } else if (getWidget().errorIndicatorElement != null) {
+ getWidget().wrapper
+ .removeChild(getWidget().errorIndicatorElement);
+ getWidget().errorIndicatorElement = null;
+ }
+ }
+ });
+
+ addStateChangeHandler("icon", new StateChangeHandler() {
+ @Override
+ public void onStateChanged(StateChangeEvent stateChangeEvent) {
+ if (getState().getIcon() != null) {
+ if (getWidget().icon == null) {
+ getWidget().icon = new Icon(getConnection());
+ getWidget().wrapper.insertBefore(
+ getWidget().icon.getElement(),
+ getWidget().captionElement);
+ }
+ getWidget().icon.setUri(getState().getIcon().getURL());
+ } else {
+ if (getWidget().icon != null) {
+ getWidget().wrapper.removeChild(getWidget().icon
+ .getElement());
+ getWidget().icon = null;
+ }
+ }
+ }
+ });
}
@Override
@@ -68,39 +112,15 @@ public class ButtonConnector extends AbstractComponentConnector implements
focusHandlerRegistration);
blurHandlerRegistration = EventHelper.updateBlurHandler(this,
blurHandlerRegistration);
- // Set text
- if (getState().isHtmlContentAllowed()) {
- getWidget().setHtml(getState().getCaption());
- } else {
- getWidget().setText(getState().getCaption());
- }
- // handle error
- if (null != getState().getErrorMessage()) {
- if (getWidget().errorIndicatorElement == null) {
- getWidget().errorIndicatorElement = DOM.createSpan();
- getWidget().errorIndicatorElement
- .setClassName("v-errorindicator");
- }
- getWidget().wrapper.insertBefore(getWidget().errorIndicatorElement,
- getWidget().captionElement);
-
- } else if (getWidget().errorIndicatorElement != null) {
- getWidget().wrapper.removeChild(getWidget().errorIndicatorElement);
- getWidget().errorIndicatorElement = null;
- }
-
- if (getState().getIcon() != null) {
- if (getWidget().icon == null) {
- getWidget().icon = new Icon(getConnection());
- getWidget().wrapper.insertBefore(getWidget().icon.getElement(),
- getWidget().captionElement);
- }
- getWidget().icon.setUri(getState().getIcon().getURL());
- } else {
- if (getWidget().icon != null) {
- getWidget().wrapper.removeChild(getWidget().icon.getElement());
- getWidget().icon = null;
+ Set<String> changedProperties = stateChangeEvent.getChangedProperties();
+ if (changedProperties.contains("caption")
+ || changedProperties.contains("htmlContentAllowed")) {
+ // Set text
+ if (getState().isHtmlContentAllowed()) {
+ getWidget().setHtml(getState().getCaption());
+ } else {
+ getWidget().setText(getState().getCaption());
}
}
diff --git a/client/src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java b/client/src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java
index 7482748302..9b5c3cd767 100644
--- a/client/src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java
+++ b/client/src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java
@@ -23,10 +23,18 @@ import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Position;
+import com.google.gwt.event.logical.shared.ResizeEvent;
+import com.google.gwt.event.logical.shared.ResizeHandler;
+import com.google.gwt.http.client.Request;
+import com.google.gwt.http.client.RequestBuilder;
+import com.google.gwt.http.client.RequestCallback;
+import com.google.gwt.http.client.RequestException;
+import com.google.gwt.http.client.Response;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.History;
+import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
@@ -84,6 +92,24 @@ public class RootConnector extends AbstractComponentContainerConnector
com.google.gwt.user.client.Window.setTitle(title);
}
});
+ final int heartbeatInterval = getState().getHeartbeatInterval();
+ new Timer() {
+ @Override
+ public void run() {
+ sendHeartbeat();
+ schedule(heartbeatInterval);
+ }
+ }.schedule(heartbeatInterval);
+ getWidget().addResizeHandler(new ResizeHandler() {
+ @Override
+ public void onResize(ResizeEvent event) {
+ rpc.resize(event.getHeight(), event.getWidth(),
+ Window.getClientWidth(), Window.getClientHeight());
+ if (getState().isImmediate()) {
+ getConnection().sendPendingVariableChanges();
+ }
+ }
+ });
}
@Override
@@ -442,4 +468,28 @@ public class RootConnector extends AbstractComponentContainerConnector
});
}
+ private void sendHeartbeat() {
+ RequestBuilder rb = new RequestBuilder(RequestBuilder.POST, "url");
+
+ rb.setCallback(new RequestCallback() {
+
+ @Override
+ public void onResponseReceived(Request request, Response response) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void onError(Request request, Throwable exception) {
+ // TODO Auto-generated method stub
+
+ }
+ });
+
+ try {
+ rb.send();
+ } catch (RequestException re) {
+
+ }
+ }
}
diff --git a/client/src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java b/client/src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java
index a473bf4846..162e7c55a8 100644
--- a/client/src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java
+++ b/client/src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java
@@ -20,6 +20,7 @@ import java.util.ArrayList;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Element;
+import com.google.gwt.event.logical.shared.HasResizeHandlers;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
@@ -50,7 +51,8 @@ import com.vaadin.terminal.gwt.client.ui.textfield.VTextField;
*
*/
public class VRoot extends SimplePanel implements ResizeHandler,
- Window.ClosingHandler, ShortcutActionHandlerOwner, Focusable {
+ Window.ClosingHandler, ShortcutActionHandlerOwner, Focusable,
+ HasResizeHandlers {
private static final String CLASSNAME = "v-view";
@@ -401,16 +403,7 @@ public class VRoot extends SimplePanel implements ResizeHandler,
int viewHeight = parentElement.getClientHeight();
int viewWidth = parentElement.getClientWidth();
- connection.updateVariable(id, "height", viewHeight, false);
- connection.updateVariable(id, "width", viewWidth, false);
-
- int windowWidth = Window.getClientWidth();
- int windowHeight = Window.getClientHeight();
-
- connection.updateVariable(id, RootConstants.BROWSER_WIDTH_VAR,
- windowWidth, false);
- connection.updateVariable(id, RootConstants.BROWSER_HEIGHT_VAR,
- windowHeight, immediate);
+ ResizeEvent.fire(this, viewWidth, viewHeight);
}
public native static void goTo(String url)
@@ -458,4 +451,9 @@ public class VRoot extends SimplePanel implements ResizeHandler,
touchScrollHandler.addElement(getElement());
}
+ @Override
+ public HandlerRegistration addResizeHandler(ResizeHandler resizeHandler) {
+ return addHandler(resizeHandler, ResizeEvent.getType());
+ }
+
}
diff --git a/server/src/com/vaadin/Application.java b/server/src/com/vaadin/Application.java
index 1d716d60c5..b120c8455a 100644
--- a/server/src/com/vaadin/Application.java
+++ b/server/src/com/vaadin/Application.java
@@ -361,31 +361,24 @@ public class Application implements Terminal.ErrorListener, Serializable {
public static class ApplicationStartEvent implements Serializable {
private final URL applicationUrl;
- private final Properties applicationProperties;
+ private final DeploymentConfiguration configuration;
private final ApplicationContext context;
- private final boolean productionMode;
-
/**
* @param applicationUrl
* the URL the application should respond to.
- * @param applicationProperties
- * the Application properties as specified by the deployment
- * configuration.
+ * @param configuration
+ * the deployment configuration for the application.
* @param context
* the context application will be running in.
- * @param productionMode
- * flag indicating whether the application is running in
- * production mode.
*/
public ApplicationStartEvent(URL applicationUrl,
- Properties applicationProperties, ApplicationContext context,
- boolean productionMode) {
+ DeploymentConfiguration configuration,
+ ApplicationContext context) {
this.applicationUrl = applicationUrl;
- this.applicationProperties = applicationProperties;
+ this.configuration = configuration;
this.context = context;
- this.productionMode = productionMode;
}
/**
@@ -401,15 +394,12 @@ public class Application implements Terminal.ErrorListener, Serializable {
}
/**
- * Gets the Application properties as specified by the deployment
- * configuration.
- *
- * @return the properties configured for the applciation.
+ * Returns the deployment configuration used by this application.
*
- * @see Application#getProperty(String)
+ * @return the deployment configuration.
*/
- public Properties getApplicationProperties() {
- return applicationProperties;
+ public DeploymentConfiguration getConfiguration() {
+ return configuration;
}
/**
@@ -422,18 +412,6 @@ public class Application implements Terminal.ErrorListener, Serializable {
public ApplicationContext getContext() {
return context;
}
-
- /**
- * Checks whether the application is running in production mode.
- *
- * @return <code>true</code> if in production mode, else
- * <code>false</code>
- *
- * @see Application#isProductionMode()
- */
- public boolean isProductionMode() {
- return productionMode;
- }
}
private final static Logger logger = Logger.getLogger(Application.class
@@ -445,6 +423,11 @@ public class Application implements Terminal.ErrorListener, Serializable {
private ApplicationContext context;
/**
+ * Deployment configuration for the application.
+ */
+ private DeploymentConfiguration configuration;
+
+ /**
* The current user or <code>null</code> if no user has logged in.
*/
private Object user;
@@ -460,11 +443,6 @@ public class Application implements Terminal.ErrorListener, Serializable {
private volatile boolean applicationIsRunning = false;
/**
- * Application properties.
- */
- private Properties properties;
-
- /**
* Default locale of the application.
*/
private Locale locale;
@@ -512,8 +490,6 @@ public class Application implements Terminal.ErrorListener, Serializable {
private int nextRootId = 0;
private Map<Integer, Root> roots = new HashMap<Integer, Root>();
- private boolean productionMode = true;
-
private final Map<String, Integer> retainOnRefreshRoots = new HashMap<String, Integer>();
private final EventRouter eventRouter = new EventRouter();
@@ -638,8 +614,7 @@ public class Application implements Terminal.ErrorListener, Serializable {
*/
public void start(ApplicationStartEvent event) {
applicationUrl = event.getApplicationUrl();
- productionMode = event.isProductionMode();
- properties = event.getApplicationProperties();
+ configuration = event.getConfiguration();
context = event.getContext();
init();
applicationIsRunning = true;
@@ -673,6 +648,16 @@ public class Application implements Terminal.ErrorListener, Serializable {
}
/**
+ * Returns the properties of this application as specified in the deployment
+ * configuration.
+ *
+ * @return Application properties
+ */
+ protected Properties getProperties() {
+ return configuration.getInitParameters();
+ }
+
+ /**
* Returns an enumeration of all the names in this application.
*
* <p>
@@ -685,7 +670,7 @@ public class Application implements Terminal.ErrorListener, Serializable {
*
*/
public Enumeration<?> getPropertyNames() {
- return properties.propertyNames();
+ return getProperties().propertyNames();
}
/**
@@ -700,7 +685,7 @@ public class Application implements Terminal.ErrorListener, Serializable {
* @return the value in this property list with the specified key value.
*/
public String getProperty(String name) {
- return properties.getProperty(name);
+ return getProperties().getProperty(name);
}
/**
@@ -1930,7 +1915,7 @@ public class Application implements Terminal.ErrorListener, Serializable {
* @since 7.0
*/
protected String getRootClassName(WrappedRequest request) {
- Object rootClassNameObj = properties.get(ROOT_PARAMETER);
+ Object rootClassNameObj = getProperties().get(ROOT_PARAMETER);
if (rootClassNameObj instanceof String) {
return (String) rootClassNameObj;
} else {
@@ -2181,7 +2166,7 @@ public class Application implements Terminal.ErrorListener, Serializable {
* @since 7.0
*/
public boolean isProductionMode() {
- return productionMode;
+ return configuration.isProductionMode();
}
/**
diff --git a/server/src/com/vaadin/terminal/AbstractClientConnector.java b/server/src/com/vaadin/terminal/AbstractClientConnector.java
index 0eb38a3d13..bc1cd2af1a 100644
--- a/server/src/com/vaadin/terminal/AbstractClientConnector.java
+++ b/server/src/com/vaadin/terminal/AbstractClientConnector.java
@@ -518,4 +518,9 @@ public abstract class AbstractClientConnector implements ClientConnector {
return getParent().isConnectorEnabled();
}
}
+
+ @Override
+ public void beforeClientResponse(boolean initial) {
+ // Do nothing by default
+ }
}
diff --git a/server/src/com/vaadin/terminal/DeploymentConfiguration.java b/server/src/com/vaadin/terminal/DeploymentConfiguration.java
index 74d0320ff8..14a5a3724f 100644
--- a/server/src/com/vaadin/terminal/DeploymentConfiguration.java
+++ b/server/src/com/vaadin/terminal/DeploymentConfiguration.java
@@ -132,4 +132,25 @@ public interface DeploymentConfiguration extends Serializable {
public AddonContext getAddonContext();
public void setAddonContext(AddonContext vaadinContext);
+
+ /**
+ * Returns whether Vaadin is in production mode.
+ *
+ * @return true if in production mode, false otherwise.
+ */
+ public boolean isProductionMode();
+
+ /**
+ * Returns whether cross-site request forgery protection is enabled.
+ *
+ * @return true if XSRF protection is enabled, false otherwise.
+ */
+ public boolean isXsrfProtectionEnabled();
+
+ /**
+ * Returns the time resources can be cached in the browsers, in seconds.
+ *
+ * @return The resource cache time.
+ */
+ public int getResourceCacheTime();
}
diff --git a/server/src/com/vaadin/terminal/Page.java b/server/src/com/vaadin/terminal/Page.java
index d5d474e2e3..933f9b39e6 100644
--- a/server/src/com/vaadin/terminal/Page.java
+++ b/server/src/com/vaadin/terminal/Page.java
@@ -376,23 +376,17 @@ public class Page implements Serializable {
.getBrowser();
}
- public void setBrowserWindowSize(Integer width, Integer height) {
+ public void setBrowserWindowSize(int width, int height) {
boolean fireEvent = false;
- if (width != null) {
- int newWidth = width.intValue();
- if (newWidth != browserWindowWidth) {
- browserWindowWidth = newWidth;
- fireEvent = true;
- }
+ if (width != browserWindowWidth) {
+ browserWindowWidth = width;
+ fireEvent = true;
}
- if (height != null) {
- int newHeight = height.intValue();
- if (newHeight != browserWindowHeight) {
- browserWindowHeight = newHeight;
- fireEvent = true;
- }
+ if (height != browserWindowHeight) {
+ browserWindowHeight = height;
+ fireEvent = true;
}
if (fireEvent) {
diff --git a/server/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java b/server/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java
index 7892018218..bd39504237 100644
--- a/server/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java
+++ b/server/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java
@@ -217,99 +217,13 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
// TODO Can we close the application when the portlet is removed? Do we know
// when the portlet is removed?
- private boolean productionMode = false;
-
- private DeploymentConfiguration deploymentConfiguration = new AbstractDeploymentConfiguration(
- getClass()) {
- @Override
- public String getConfiguredWidgetset(WrappedRequest request) {
-
- String widgetset = getApplicationOrSystemProperty(
- PARAMETER_WIDGETSET, null);
-
- if (widgetset == null) {
- // If no widgetset defined for the application, check the
- // portal
- // property
- widgetset = WrappedPortletRequest.cast(request)
- .getPortalProperty(PORTAL_PARAMETER_VAADIN_WIDGETSET);
- }
-
- if (widgetset == null) {
- // If no widgetset defined for the portal, use the default
- widgetset = DEFAULT_WIDGETSET;
- }
-
- return widgetset;
- }
-
- @Override
- public String getConfiguredTheme(WrappedRequest request) {
-
- // is the default theme defined by the portal?
- String themeName = WrappedPortletRequest.cast(request)
- .getPortalProperty(Constants.PORTAL_PARAMETER_VAADIN_THEME);
-
- if (themeName == null) {
- // no, using the default theme defined by Vaadin
- themeName = DEFAULT_THEME_NAME;
- }
-
- return themeName;
- }
-
- @Override
- public boolean isStandalone(WrappedRequest request) {
- return false;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
- * com.vaadin.terminal.DeploymentConfiguration#getStaticFileLocation
- * (com.vaadin.terminal.WrappedRequest)
- *
- * Return the URL from where static files, e.g. the widgetset and the
- * theme, are served. In a standard configuration the VAADIN folder
- * inside the returned folder is what is used for widgetsets and themes.
- *
- * @return The location of static resources (inside which there should
- * be a VAADIN directory). Does not end with a slash (/).
- */
-
- @Override
- public String getStaticFileLocation(WrappedRequest request) {
- String staticFileLocation = WrappedPortletRequest.cast(request)
- .getPortalProperty(
- Constants.PORTAL_PARAMETER_VAADIN_RESOURCE_PATH);
- if (staticFileLocation != null) {
- // remove trailing slash if any
- while (staticFileLocation.endsWith(".")) {
- staticFileLocation = staticFileLocation.substring(0,
- staticFileLocation.length() - 1);
- }
- return staticFileLocation;
- } else {
- // default for Liferay
- return "/html";
- }
- }
-
- @Override
- public String getMimeType(String resourceName) {
- return getPortletContext().getMimeType(resourceName);
- }
- };
-
- private final AddonContext addonContext = new AddonContext(
- getDeploymentConfiguration());
+ private DeploymentConfiguration deploymentConfiguration;
+ private AddonContext addonContext;
@Override
public void init(PortletConfig config) throws PortletException {
super.init(config);
- Properties applicationProperties = getDeploymentConfiguration()
- .getInitParameters();
+ Properties applicationProperties = new Properties();
// Read default parameters from the context
final PortletContext context = config.getPortletContext();
@@ -328,45 +242,101 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
config.getInitParameter(name));
}
- checkProductionMode();
- checkCrossSiteProtection();
+ deploymentConfiguration = new AbstractDeploymentConfiguration(
+ getClass(), applicationProperties) {
+ @Override
+ public String getConfiguredWidgetset(WrappedRequest request) {
- addonContext.init();
- }
+ String widgetset = getApplicationOrSystemProperty(
+ PARAMETER_WIDGETSET, null);
- @Override
- public void destroy() {
- super.destroy();
+ if (widgetset == null) {
+ // If no widgetset defined for the application, check the
+ // portal property
+ widgetset = WrappedPortletRequest.cast(request)
+ .getPortalProperty(
+ PORTAL_PARAMETER_VAADIN_WIDGETSET);
+ }
- addonContext.destroy();
- }
+ if (widgetset == null) {
+ // If no widgetset defined for the portal, use the default
+ widgetset = DEFAULT_WIDGETSET;
+ }
+
+ return widgetset;
+ }
+
+ @Override
+ public String getConfiguredTheme(WrappedRequest request) {
+
+ // is the default theme defined by the portal?
+ String themeName = WrappedPortletRequest.cast(request)
+ .getPortalProperty(
+ Constants.PORTAL_PARAMETER_VAADIN_THEME);
+
+ if (themeName == null) {
+ // no, using the default theme defined by Vaadin
+ themeName = DEFAULT_THEME_NAME;
+ }
+
+ return themeName;
+ }
+
+ @Override
+ public boolean isStandalone(WrappedRequest request) {
+ return false;
+ }
- private void checkCrossSiteProtection() {
- if (getDeploymentConfiguration().getApplicationOrSystemProperty(
- SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION, "false").equals(
- "true")) {
/*
- * Print an information/warning message about running with xsrf
- * protection disabled
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.DeploymentConfiguration#getStaticFileLocation
+ * (com.vaadin.terminal.WrappedRequest)
+ *
+ * Return the URL from where static files, e.g. the widgetset and
+ * the theme, are served. In a standard configuration the VAADIN
+ * folder inside the returned folder is what is used for widgetsets
+ * and themes.
+ *
+ * @return The location of static resources (inside which there
+ * should be a VAADIN directory). Does not end with a slash (/).
*/
- getLogger().warning(WARNING_XSRF_PROTECTION_DISABLED);
- }
+
+ @Override
+ public String getStaticFileLocation(WrappedRequest request) {
+ String staticFileLocation = WrappedPortletRequest
+ .cast(request)
+ .getPortalProperty(
+ Constants.PORTAL_PARAMETER_VAADIN_RESOURCE_PATH);
+ if (staticFileLocation != null) {
+ // remove trailing slash if any
+ while (staticFileLocation.endsWith(".")) {
+ staticFileLocation = staticFileLocation.substring(0,
+ staticFileLocation.length() - 1);
+ }
+ return staticFileLocation;
+ } else {
+ // default for Liferay
+ return "/html";
+ }
+ }
+
+ @Override
+ public String getMimeType(String resourceName) {
+ return getPortletContext().getMimeType(resourceName);
+ }
+ };
+
+ addonContext = new AddonContext(deploymentConfiguration);
+ addonContext.init();
}
- private void checkProductionMode() {
- // TODO Identical code in AbstractApplicationServlet -> refactor
- // Check if the application is in production mode.
- // We are in production mode if productionMode=true
- if (getDeploymentConfiguration().getApplicationOrSystemProperty(
- SERVLET_PARAMETER_PRODUCTION_MODE, "false").equals("true")) {
- productionMode = true;
- }
+ @Override
+ public void destroy() {
+ super.destroy();
- if (!productionMode) {
- /* Print an information/warning message about running in debug mode */
- // TODO Maybe we need a different message for portlets?
- getLogger().warning(NOT_PRODUCTION_MODE_INFO);
- }
+ addonContext.destroy();
}
protected enum RequestType {
@@ -415,13 +385,13 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
}
/**
- * Returns true if the servlet is running in production mode. Production
+ * Returns true if the portlet is running in production mode. Production
* mode disables all debug facilities.
*
* @return true if in production mode, false if in debug mode
*/
public boolean isProductionMode() {
- return productionMode;
+ return deploymentConfiguration.isProductionMode();
}
protected void handleRequest(PortletRequest request,
@@ -811,8 +781,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
application.setLocale(locale);
// No application URL when running inside a portlet
application.start(new ApplicationStartEvent(null,
- getDeploymentConfiguration().getInitParameters(), context,
- isProductionMode()));
+ getDeploymentConfiguration(), context));
addonContext.fireApplicationStarted(application);
}
}
diff --git a/server/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java b/server/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
index dcab8b44f5..062ba6cdf7 100644
--- a/server/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
+++ b/server/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
@@ -97,49 +97,11 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
// TODO Move some (all?) of the constants to a separate interface (shared
// with portlet)
- private boolean productionMode = false;
-
private final String resourcePath = null;
- private int resourceCacheTime = 3600;
-
- private DeploymentConfiguration deploymentConfiguration = new AbstractDeploymentConfiguration(
- getClass()) {
-
- @Override
- public String getStaticFileLocation(WrappedRequest request) {
- HttpServletRequest servletRequest = WrappedHttpServletRequest
- .cast(request);
- return AbstractApplicationServlet.this
- .getStaticFilesLocation(servletRequest);
- }
-
- @Override
- public String getConfiguredWidgetset(WrappedRequest request) {
- return getApplicationOrSystemProperty(
- AbstractApplicationServlet.PARAMETER_WIDGETSET,
- AbstractApplicationServlet.DEFAULT_WIDGETSET);
- }
-
- @Override
- public String getConfiguredTheme(WrappedRequest request) {
- // Use the default
- return AbstractApplicationServlet.getDefaultTheme();
- }
-
- @Override
- public boolean isStandalone(WrappedRequest request) {
- return true;
- }
+ private DeploymentConfiguration deploymentConfiguration;
- @Override
- public String getMimeType(String resourceName) {
- return getServletContext().getMimeType(resourceName);
- }
- };
-
- private final AddonContext addonContext = new AddonContext(
- getDeploymentConfiguration());
+ private AddonContext addonContext;
/**
* Called by the servlet container to indicate to a servlet that the servlet
@@ -156,8 +118,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
public void init(javax.servlet.ServletConfig servletConfig)
throws javax.servlet.ServletException {
super.init(servletConfig);
- Properties applicationProperties = getDeploymentConfiguration()
- .getInitParameters();
+ Properties applicationProperties = new Properties();
// Read default parameters from server.xml
final ServletContext context = servletConfig.getServletContext();
@@ -176,10 +137,42 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
servletConfig.getInitParameter(name));
}
- checkProductionMode();
- checkCrossSiteProtection();
- checkResourceCacheTime();
+ deploymentConfiguration = new AbstractDeploymentConfiguration(
+ getClass(), applicationProperties) {
+
+ @Override
+ public String getStaticFileLocation(WrappedRequest request) {
+ HttpServletRequest servletRequest = WrappedHttpServletRequest
+ .cast(request);
+ return AbstractApplicationServlet.this
+ .getStaticFilesLocation(servletRequest);
+ }
+
+ @Override
+ public String getConfiguredWidgetset(WrappedRequest request) {
+ return getApplicationOrSystemProperty(
+ AbstractApplicationServlet.PARAMETER_WIDGETSET,
+ AbstractApplicationServlet.DEFAULT_WIDGETSET);
+ }
+
+ @Override
+ public String getConfiguredTheme(WrappedRequest request) {
+ // Use the default
+ return AbstractApplicationServlet.getDefaultTheme();
+ }
+
+ @Override
+ public boolean isStandalone(WrappedRequest request) {
+ return true;
+ }
+ @Override
+ public String getMimeType(String resourceName) {
+ return getServletContext().getMimeType(resourceName);
+ }
+ };
+
+ addonContext = new AddonContext(deploymentConfiguration);
addonContext.init();
}
@@ -190,47 +183,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
addonContext.destroy();
}
- private void checkCrossSiteProtection() {
- if (getDeploymentConfiguration().getApplicationOrSystemProperty(
- SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION, "false").equals(
- "true")) {
- /*
- * Print an information/warning message about running with xsrf
- * protection disabled
- */
- getLogger().warning(WARNING_XSRF_PROTECTION_DISABLED);
- }
- }
-
- private void checkProductionMode() {
- // Check if the application is in production mode.
- // We are in production mode if productionMode=true
- if (getDeploymentConfiguration().getApplicationOrSystemProperty(
- SERVLET_PARAMETER_PRODUCTION_MODE, "false").equals("true")) {
- productionMode = true;
- }
-
- if (!productionMode) {
- /* Print an information/warning message about running in debug mode */
- getLogger().warning(NOT_PRODUCTION_MODE_INFO);
- }
-
- }
-
- private void checkResourceCacheTime() {
- // Check if the browser caching time has been set in web.xml
- try {
- String rct = getDeploymentConfiguration()
- .getApplicationOrSystemProperty(
- SERVLET_PARAMETER_RESOURCE_CACHE_TIME, "3600");
- resourceCacheTime = Integer.parseInt(rct);
- } catch (NumberFormatException nfe) {
- // Default is 1h
- resourceCacheTime = 3600;
- getLogger().warning(WARNING_RESOURCE_CACHING_TIME_NOT_NUMERIC);
- }
- }
-
/**
* Returns true if the servlet is running in production mode. Production
* mode disables all debug facilities.
@@ -238,17 +190,17 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
* @return true if in production mode, false if in debug mode
*/
public boolean isProductionMode() {
- return productionMode;
+ return getDeploymentConfiguration().isProductionMode();
}
/**
- * Returns the amount of milliseconds the browser should cache a file.
- * Default is 1 hour (3600 ms).
+ * Returns the number of seconds the browser should cache a file. Default is
+ * 1 hour (3600 s).
*
- * @return The amount of milliseconds files are cached in the browser
+ * @return The number of seconds files are cached in the browser
*/
public int getResourceCacheTime() {
- return resourceCacheTime;
+ return getDeploymentConfiguration().getResourceCacheTime();
}
/**
@@ -909,8 +861,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
Locale locale = request.getLocale();
application.setLocale(locale);
application.start(new ApplicationStartEvent(applicationUrl,
- getDeploymentConfiguration().getInitParameters(),
- webApplicationContext, isProductionMode()));
+ getDeploymentConfiguration(), webApplicationContext));
addonContext.fireApplicationStarted(application);
}
}
@@ -1056,7 +1007,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
* parameter in web.xml
*/
response.setHeader("Cache-Control",
- "max-age= " + String.valueOf(resourceCacheTime));
+ "max-age= " + String.valueOf(getResourceCacheTime()));
}
// Write the resource to the client.
diff --git a/server/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java b/server/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
index 00e65382cd..99376ffd1f 100644
--- a/server/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
+++ b/server/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
@@ -68,7 +68,9 @@ import com.vaadin.external.json.JSONException;
import com.vaadin.external.json.JSONObject;
import com.vaadin.shared.ApplicationConstants;
import com.vaadin.shared.Connector;
+import com.vaadin.shared.JavaScriptConnectorState;
import com.vaadin.shared.Version;
+import com.vaadin.shared.communication.LegacyChangeVariablesInvocation;
import com.vaadin.shared.communication.MethodInvocation;
import com.vaadin.shared.communication.SharedState;
import com.vaadin.shared.communication.UidlValue;
@@ -818,6 +820,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
if (repaintAll) {
getClientCache(root).clear();
rootConnectorTracker.markAllConnectorsDirty();
+ rootConnectorTracker.markAllClientSidesUninitialized();
// Reset sent locales
locales = null;
@@ -832,9 +835,9 @@ public abstract class AbstractCommunicationManager implements Serializable {
"Found " + dirtyVisibleConnectors.size()
+ " dirty connectors to paint");
for (ClientConnector connector : dirtyVisibleConnectors) {
- if (connector instanceof Component) {
- ((Component) connector).updateState();
- }
+ boolean initialized = rootConnectorTracker
+ .isClientSideInitialized(connector);
+ connector.beforeClientResponse(!initialized);
}
rootConnectorTracker.markAllConnectorsClean();
@@ -883,23 +886,36 @@ public abstract class AbstractCommunicationManager implements Serializable {
try {
Class<? extends SharedState> stateType = connector
.getStateType();
- SharedState referenceState = null;
- if (repaintAll) {
+ Object diffState = rootConnectorTracker
+ .getDiffState(connector);
+ if (diffState == null) {
+ diffState = new JSONObject();
// Use an empty state object as reference for full
// repaints
- try {
- referenceState = stateType.newInstance();
- } catch (Exception e) {
- getLogger().log(
- Level.WARNING,
- "Error creating reference object for state of type "
- + stateType.getName());
+ boolean emptyInitialState = JavaScriptConnectorState.class
+ .isAssignableFrom(stateType);
+ if (!emptyInitialState) {
+ try {
+ SharedState referenceState = stateType
+ .newInstance();
+ diffState = JsonCodec.encode(referenceState,
+ null, stateType,
+ root.getConnectorTracker());
+ } catch (Exception e) {
+ getLogger().log(
+ Level.WARNING,
+ "Error creating reference object for state of type "
+ + stateType.getName());
+ }
}
+ rootConnectorTracker.setDiffState(connector, diffState);
}
- Object stateJson = JsonCodec.encode(state, referenceState,
- stateType, root.getConnectorTracker());
+ JSONObject stateJson = (JSONObject) JsonCodec.encode(state,
+ diffState, stateType, root.getConnectorTracker());
- sharedStates.put(connector.getConnectorId(), stateJson);
+ if (stateJson.length() != 0) {
+ sharedStates.put(connector.getConnectorId(), stateJson);
+ }
} catch (JSONException e) {
throw new PaintException(
"Failed to serialize shared state for connector "
@@ -1250,6 +1266,10 @@ public abstract class AbstractCommunicationManager implements Serializable {
dragAndDropService.printJSONResponse(outWriter);
}
+ for (ClientConnector connector : dirtyVisibleConnectors) {
+ rootConnectorTracker.markClientSideInitialized(connector);
+ }
+
writePerformanceData(outWriter);
}
diff --git a/server/src/com/vaadin/terminal/gwt/server/AbstractDeploymentConfiguration.java b/server/src/com/vaadin/terminal/gwt/server/AbstractDeploymentConfiguration.java
index 33e1c43b38..ad5acad5e9 100644
--- a/server/src/com/vaadin/terminal/gwt/server/AbstractDeploymentConfiguration.java
+++ b/server/src/com/vaadin/terminal/gwt/server/AbstractDeploymentConfiguration.java
@@ -20,6 +20,7 @@ import java.lang.reflect.Constructor;
import java.util.Iterator;
import java.util.Properties;
import java.util.ServiceLoader;
+import java.util.logging.Logger;
import com.vaadin.terminal.DeploymentConfiguration;
@@ -27,11 +28,20 @@ public abstract class AbstractDeploymentConfiguration implements
DeploymentConfiguration {
private final Class<?> systemPropertyBaseClass;
- private final Properties applicationProperties = new Properties();
+ private final Properties applicationProperties;
private AddonContext addonContext;
+ private boolean productionMode;
+ private boolean xsrfProtectionEnabled;
+ private int resourceCacheTime;
- public AbstractDeploymentConfiguration(Class<?> systemPropertyBaseClass) {
+ public AbstractDeploymentConfiguration(Class<?> systemPropertyBaseClass,
+ Properties applicationProperties) {
this.systemPropertyBaseClass = systemPropertyBaseClass;
+ this.applicationProperties = applicationProperties;
+
+ checkProductionMode();
+ checkXsrfProtection();
+ checkResourceCacheTime();
}
@Override
@@ -152,4 +162,63 @@ public abstract class AbstractDeploymentConfiguration implements
public AddonContext getAddonContext() {
return addonContext;
}
+
+ @Override
+ public boolean isProductionMode() {
+ return productionMode;
+ }
+
+ @Override
+ public boolean isXsrfProtectionEnabled() {
+ return xsrfProtectionEnabled;
+ }
+
+ @Override
+ public int getResourceCacheTime() {
+ return resourceCacheTime;
+ }
+
+ /**
+ * Log a warning if Vaadin is not running in production mode.
+ */
+ private void checkProductionMode() {
+ productionMode = getApplicationOrSystemProperty(
+ Constants.SERVLET_PARAMETER_PRODUCTION_MODE, "false").equals(
+ "true");
+ if (!productionMode) {
+ getLogger().warning(Constants.NOT_PRODUCTION_MODE_INFO);
+ }
+ }
+
+ /**
+ * Log a warning if cross-site request forgery protection is disabled.
+ */
+ private void checkXsrfProtection() {
+ xsrfProtectionEnabled = !getApplicationOrSystemProperty(
+ Constants.SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION, "false")
+ .equals("true");
+ if (!xsrfProtectionEnabled) {
+ getLogger().warning(Constants.WARNING_XSRF_PROTECTION_DISABLED);
+ }
+ }
+
+ /**
+ * Log a warning if resource cache time is set but is not an integer.
+ */
+ private void checkResourceCacheTime() {
+ try {
+ resourceCacheTime = Integer
+ .parseInt(getApplicationOrSystemProperty(
+ Constants.SERVLET_PARAMETER_RESOURCE_CACHE_TIME,
+ "3600"));
+ } catch (NumberFormatException e) {
+ getLogger().warning(
+ Constants.WARNING_RESOURCE_CACHING_TIME_NOT_NUMERIC);
+ resourceCacheTime = 3600;
+ }
+ }
+
+ private Logger getLogger() {
+ return Logger.getLogger(getClass().getName());
+ }
}
diff --git a/server/src/com/vaadin/terminal/gwt/server/ClientConnector.java b/server/src/com/vaadin/terminal/gwt/server/ClientConnector.java
index eef4e240ec..c9fe2563f9 100644
--- a/server/src/com/vaadin/terminal/gwt/server/ClientConnector.java
+++ b/server/src/com/vaadin/terminal/gwt/server/ClientConnector.java
@@ -157,4 +157,24 @@ public interface ClientConnector extends Connector, RpcTarget {
* attached to any Root
*/
public Root getRoot();
+
+ /**
+ * Called before the shared state and RPC invocations are sent to the
+ * client. Gives the connector an opportunity to set computed/dynamic state
+ * values or to invoke last minute RPC methods depending on other component
+ * features.
+ * <p>
+ * This method must not alter the component hierarchy in any way. Calling
+ * requestRepaint() from this method will have no effect.
+ * </p>
+ *
+ * @param initial
+ * <code>true</code> if the client-side connector will be created
+ * and initialized after this method has been invoked.
+ * <code>false</code> if there is already an initialized
+ * client-side connector.
+ *
+ * @since 7.0
+ */
+ public void beforeClientResponse(boolean initial);
}
diff --git a/server/src/com/vaadin/terminal/gwt/server/DragAndDropService.java b/server/src/com/vaadin/terminal/gwt/server/DragAndDropService.java
index bb96c6e53e..56d5ed1393 100644
--- a/server/src/com/vaadin/terminal/gwt/server/DragAndDropService.java
+++ b/server/src/com/vaadin/terminal/gwt/server/DragAndDropService.java
@@ -322,4 +322,9 @@ public class DragAndDropService implements VariableOwner, ClientConnector {
public Root getRoot() {
return null;
}
+
+ @Override
+ public void beforeClientResponse(boolean initial) {
+ // Nothing to do
+ }
}
diff --git a/server/src/com/vaadin/terminal/gwt/server/JsonCodec.java b/server/src/com/vaadin/terminal/gwt/server/JsonCodec.java
index 60197b0b3a..884e01f9a5 100644
--- a/server/src/com/vaadin/terminal/gwt/server/JsonCodec.java
+++ b/server/src/com/vaadin/terminal/gwt/server/JsonCodec.java
@@ -165,6 +165,10 @@ public class JsonCodec implements Serializable {
} else if (targetType == JSONObject.class
|| targetType == JSONArray.class) {
return value;
+ } else if (Enum.class.isAssignableFrom(getClassForType(targetType))) {
+ Class<?> classForType = getClassForType(targetType);
+ return decodeEnum(classForType.asSubclass(Enum.class),
+ (String) value);
} else {
return decodeObject(targetType, (JSONObject) value,
connectorTracker);
@@ -420,9 +424,8 @@ public class JsonCodec implements Serializable {
}
}
- private static Object decodeEnum(Class<? extends Enum> cls, JSONObject value) {
- String enumIdentifier = String.valueOf(value);
- return Enum.valueOf(cls, enumIdentifier);
+ private static Object decodeEnum(Class<? extends Enum> cls, String value) {
+ return Enum.valueOf(cls, value);
}
private static String[] decodeStringArray(JSONArray jsonArray)
@@ -491,10 +494,6 @@ public class JsonCodec implements Serializable {
throws JSONException {
Class<?> targetClass = getClassForType(targetType);
- if (Enum.class.isAssignableFrom(targetClass)) {
- return decodeEnum(targetClass.asSubclass(Enum.class),
- serializedObject);
- }
try {
Object decodedObject = targetClass.newInstance();
@@ -527,9 +526,8 @@ public class JsonCodec implements Serializable {
}
}
- public static Object encode(Object value, Object referenceValue,
- Type valueType, ConnectorTracker connectorTracker)
- throws JSONException {
+ public static Object encode(Object value, Object diffState, Type valueType,
+ ConnectorTracker connectorTracker) throws JSONException {
if (valueType == null) {
throw new IllegalArgumentException("type must be defined");
@@ -596,7 +594,7 @@ public class JsonCodec implements Serializable {
} else {
// Any object that we do not know how to encode we encode by looping
// through fields
- return encodeObject(value, referenceValue, connectorTracker);
+ return encodeObject(value, (JSONObject) diffState, connectorTracker);
}
}
@@ -604,7 +602,7 @@ public class JsonCodec implements Serializable {
return JSONObject.NULL;
}
- private static Object encodeObject(Object value, Object referenceValue,
+ private static Object encodeObject(Object value, JSONObject diffState,
ConnectorTracker connectorTracker) throws JSONException {
JSONObject jsonMap = new JSONObject();
@@ -621,10 +619,11 @@ public class JsonCodec implements Serializable {
Type fieldType = getterMethod.getGenericReturnType();
Object fieldValue = getterMethod.invoke(value, (Object[]) null);
boolean equals = false;
- Object referenceFieldValue = null;
- if (referenceValue != null) {
- referenceFieldValue = getterMethod.invoke(referenceValue,
- (Object[]) null);
+ Object diffStateValue = null;
+ if (diffState != null) {
+ diffStateValue = diffState.get(fieldName);
+ Object referenceFieldValue = decodeInternalOrCustomType(
+ fieldType, diffStateValue, connectorTracker);
equals = equals(fieldValue, referenceFieldValue);
}
if (!equals) {
@@ -638,8 +637,15 @@ public class JsonCodec implements Serializable {
}
jsonMap.put(
fieldName,
- encode(fieldValue, referenceFieldValue, fieldType,
+ encode(fieldValue, diffStateValue, fieldType,
connectorTracker));
+ if (diffState != null) {
+ diffState.put(
+ fieldName,
+ encode(fieldValue, null, fieldType,
+ connectorTracker));
+ }
+
// } else {
// System.out.println("Skipping field " + fieldName
// + " of type " + fieldType.getName()
diff --git a/server/src/com/vaadin/ui/AbsoluteLayout.java b/server/src/com/vaadin/ui/AbsoluteLayout.java
index 9851a79bcd..a3bc577fe3 100644
--- a/server/src/com/vaadin/ui/AbsoluteLayout.java
+++ b/server/src/com/vaadin/ui/AbsoluteLayout.java
@@ -169,8 +169,8 @@ public class AbsoluteLayout extends AbstractLayout implements
}
@Override
- public void updateState() {
- super.updateState();
+ public void beforeClientResponse(boolean initial) {
+ super.beforeClientResponse(initial);
// This could be in internalRemoveComponent and internalSetComponent if
// Map<Connector,String> was supported. We cannot get the child
diff --git a/server/src/com/vaadin/ui/AbstractComponent.java b/server/src/com/vaadin/ui/AbstractComponent.java
index fb3993d0cf..cde5217ca1 100644
--- a/server/src/com/vaadin/ui/AbstractComponent.java
+++ b/server/src/com/vaadin/ui/AbstractComponent.java
@@ -717,13 +717,9 @@ public abstract class AbstractComponent extends AbstractClientConnector
return (ComponentState) super.getState();
}
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.ui.Component#updateState()
- */
@Override
- public void updateState() {
+ public void beforeClientResponse(boolean initial) {
+ super.beforeClientResponse(initial);
// TODO This logic should be on the client side and the state should
// simply be a data object with "width" and "height".
if (getHeight() >= 0
diff --git a/server/src/com/vaadin/ui/AbstractField.java b/server/src/com/vaadin/ui/AbstractField.java
index 2d14acf442..67a1826100 100644
--- a/server/src/com/vaadin/ui/AbstractField.java
+++ b/server/src/com/vaadin/ui/AbstractField.java
@@ -1620,8 +1620,8 @@ public abstract class AbstractField<T> extends AbstractComponent implements
}
@Override
- public void updateState() {
- super.updateState();
+ public void beforeClientResponse(boolean initial) {
+ super.beforeClientResponse(initial);
// Hide the error indicator if needed
getState().setHideErrors(shouldHideErrors());
diff --git a/server/src/com/vaadin/ui/AbstractTextField.java b/server/src/com/vaadin/ui/AbstractTextField.java
index c8bbadd0ab..86315f801f 100644
--- a/server/src/com/vaadin/ui/AbstractTextField.java
+++ b/server/src/com/vaadin/ui/AbstractTextField.java
@@ -97,8 +97,8 @@ public abstract class AbstractTextField extends AbstractField<String> implements
}
@Override
- public void updateState() {
- super.updateState();
+ public void beforeClientResponse(boolean initial) {
+ super.beforeClientResponse(initial);
String value = getValue();
if (value == null) {
diff --git a/server/src/com/vaadin/ui/Component.java b/server/src/com/vaadin/ui/Component.java
index ac668168f2..ff7ed47930 100644
--- a/server/src/com/vaadin/ui/Component.java
+++ b/server/src/com/vaadin/ui/Component.java
@@ -637,18 +637,6 @@ public interface Component extends ClientConnector, Sizeable, Serializable {
public ComponentState getState();
/**
- * Called before the shared state is sent to the client. Gives the component
- * an opportunity to set computed/dynamic state values e.g. state values
- * that depend on other component features.
- * <p>
- * This method must not alter the component hierarchy in any way.
- * </p>
- *
- * @since 7.0
- */
- public void updateState();
-
- /**
* Adds an unique id for component that get's transferred to terminal for
* testing purposes. Keeping identifiers unique is the responsibility of the
* programmer.
diff --git a/server/src/com/vaadin/ui/ConnectorTracker.java b/server/src/com/vaadin/ui/ConnectorTracker.java
index 12ad377b62..2afe7f9025 100644
--- a/server/src/com/vaadin/ui/ConnectorTracker.java
+++ b/server/src/com/vaadin/ui/ConnectorTracker.java
@@ -20,6 +20,7 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -39,7 +40,8 @@ import com.vaadin.terminal.gwt.server.ClientConnector;
* Tracks which {@link ClientConnector}s are dirty so they can be updated to the
* client when the following response is sent. A connector is dirty when an
* operation has been performed on it on the server and as a result of this
- * operation new information needs to be sent to its {@link ServerConnector}.
+ * operation new information needs to be sent to its
+ * {@link com.vaadin.terminal.gwt.client.ServerConnector}.
* </p>
*
* @author Vaadin Ltd
@@ -50,8 +52,10 @@ public class ConnectorTracker implements Serializable {
private final HashMap<String, ClientConnector> connectorIdToConnector = new HashMap<String, ClientConnector>();
private Set<ClientConnector> dirtyConnectors = new HashSet<ClientConnector>();
+ private Set<ClientConnector> uninitializedConnectors = new HashSet<ClientConnector>();
private Root root;
+ private Map<ClientConnector, Object> diffStates = new HashMap<ClientConnector, Object>();
/**
* Gets a logger for this class
@@ -91,6 +95,7 @@ public class ConnectorTracker implements Serializable {
.get(connectorId);
if (previouslyRegistered == null) {
connectorIdToConnector.put(connectorId, connector);
+ uninitializedConnectors.add(connector);
getLogger().fine(
"Registered " + connector.getClass().getSimpleName() + " ("
+ connectorId + ")");
@@ -136,6 +141,49 @@ public class ConnectorTracker implements Serializable {
"Unregistered " + connector.getClass().getSimpleName() + " ("
+ connectorId + ")");
connectorIdToConnector.remove(connectorId);
+ uninitializedConnectors.remove(connector);
+ diffStates.remove(connector);
+ }
+
+ /**
+ * Checks whether the given connector has already been initialized in the
+ * browser. The given connector should be registered with this connector
+ * tracker.
+ *
+ * @param connector
+ * the client connector to check
+ * @return <code>true</code> if the initial state has previously been sent
+ * to the browser, <code>false</code> if the client-side doesn't
+ * already know anything about the connector.
+ */
+ public boolean isClientSideInitialized(ClientConnector connector) {
+ assert connectorIdToConnector.get(connector.getConnectorId()) == connector : "Connector should be registered with this ConnectorTracker";
+ return !uninitializedConnectors.contains(connector);
+ }
+
+ /**
+ * Marks the given connector as initialized, meaning that the client-side
+ * state has been initialized for the connector.
+ *
+ * @see #isClientSideInitialized(ClientConnector)
+ *
+ * @param connector
+ * the connector that should be marked as initialized
+ */
+ public void markClientSideInitialized(ClientConnector connector) {
+ uninitializedConnectors.remove(connector);
+ }
+
+ /**
+ * Marks all currently registered connectors as uninitialized. This should
+ * be done when the client-side has been reset but the server-side state is
+ * retained.
+ *
+ * @see #isClientSideInitialized(ClientConnector)
+ */
+ public void markAllClientSidesUninitialized() {
+ uninitializedConnectors.addAll(connectorIdToConnector.values());
+ diffStates.clear();
}
/**
@@ -175,6 +223,8 @@ public class ConnectorTracker implements Serializable {
"cleanConnectorMap unregistered connector "
+ getConnectorAndParentInfo(connector)
+ "). This should have been done when the connector was detached.");
+ uninitializedConnectors.remove(connector);
+ diffStates.remove(connector);
iterator.remove();
}
}
@@ -327,4 +377,12 @@ public class ConnectorTracker implements Serializable {
return dirtyConnectors;
}
+ public Object getDiffState(ClientConnector connector) {
+ return diffStates.get(connector);
+ }
+
+ public void setDiffState(ClientConnector connector, Object diffState) {
+ diffStates.put(connector, diffState);
+ }
+
}
diff --git a/server/src/com/vaadin/ui/CssLayout.java b/server/src/com/vaadin/ui/CssLayout.java
index c43f347e68..0192debc4a 100644
--- a/server/src/com/vaadin/ui/CssLayout.java
+++ b/server/src/com/vaadin/ui/CssLayout.java
@@ -197,8 +197,8 @@ public class CssLayout extends AbstractLayout implements LayoutClickNotifier {
}
@Override
- public void updateState() {
- super.updateState();
+ public void beforeClientResponse(boolean initial) {
+ super.beforeClientResponse(initial);
getState().getChildCss().clear();
for (Iterator<Component> ci = getComponentIterator(); ci.hasNext();) {
Component child = ci.next();
diff --git a/server/src/com/vaadin/ui/Root.java b/server/src/com/vaadin/ui/Root.java
index 685296c55a..b37005a16e 100644
--- a/server/src/com/vaadin/ui/Root.java
+++ b/server/src/com/vaadin/ui/Root.java
@@ -434,6 +434,13 @@ public abstract class Root extends AbstractComponentContainer implements
public void click(MouseEventDetails mouseDetails) {
fireEvent(new ClickEvent(Root.this, mouseDetails));
}
+
+ @Override
+ public void resize(int viewWidth, int viewHeight, int windowWidth,
+ int windowHeight) {
+ // TODO We're not doing anything with the view dimensions
+ getPage().setBrowserWindowSize(windowWidth, windowHeight);
+ }
};
/**
@@ -582,12 +589,6 @@ public abstract class Root extends AbstractComponentContainer implements
.get(RootConstants.FRAGMENT_VARIABLE);
getPage().setFragment(fragment, true);
}
-
- if (variables.containsKey("height") || variables.containsKey("width")) {
- getPage().setBrowserWindowSize((Integer) variables.get("width"),
- (Integer) variables.get("height"));
- }
-
}
/*
diff --git a/server/src/com/vaadin/ui/Window.java b/server/src/com/vaadin/ui/Window.java
index 13ef7e5784..d1d2c25d8b 100644
--- a/server/src/com/vaadin/ui/Window.java
+++ b/server/src/com/vaadin/ui/Window.java
@@ -32,7 +32,6 @@ import com.vaadin.event.ShortcutAction.KeyCode;
import com.vaadin.event.ShortcutAction.ModifierKey;
import com.vaadin.event.ShortcutListener;
import com.vaadin.shared.MouseEventDetails;
-import com.vaadin.shared.ui.root.RootConstants;
import com.vaadin.shared.ui.window.WindowServerRpc;
import com.vaadin.shared.ui.window.WindowState;
import com.vaadin.terminal.PaintException;
@@ -76,10 +75,6 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
}
};
- private int browserWindowWidth = -1;
-
- private int browserWindowHeight = -1;
-
/**
* Creates a new unnamed window with a default layout.
*/
@@ -170,20 +165,6 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
.get("width") != getWidth())) {
sizeHasChanged = true;
}
- Integer browserHeightVar = (Integer) variables
- .get(RootConstants.BROWSER_HEIGHT_VAR);
- if (browserHeightVar != null
- && browserHeightVar.intValue() != browserWindowHeight) {
- browserWindowHeight = browserHeightVar.intValue();
- sizeHasChanged = true;
- }
- Integer browserWidthVar = (Integer) variables
- .get(RootConstants.BROWSER_WIDTH_VAR);
- if (browserWidthVar != null
- && browserWidthVar.intValue() != browserWindowWidth) {
- browserWindowWidth = browserWidthVar.intValue();
- sizeHasChanged = true;
- }
super.changeVariables(source, variables);
diff --git a/shared/src/com/vaadin/shared/annotations/Delayed.java b/shared/src/com/vaadin/shared/annotations/Delayed.java
new file mode 100644
index 0000000000..706ffc1c53
--- /dev/null
+++ b/shared/src/com/vaadin/shared/annotations/Delayed.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2011 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.shared.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+import com.vaadin.shared.communication.ServerRpc;
+
+/**
+ * Invoking a method in a {@link ServerRpc} interface marked with this
+ * annotation will only add the invocation to a queue of outgoing RPC
+ * invocations, but it will not cause the queue to be purged and sent to the
+ * server. The queue will instead be sent when any RPC method not marked as @Delayed
+ * has been invoked.
+ *
+ * @author Vaadin Ltd
+ * @version @VERSION@
+ * @since 7.0.0
+ */
+@Target(ElementType.METHOD)
+@Documented
+public @interface Delayed {
+ /**
+ * By setting lastonly to <code>true</code>, any previous invocations of the
+ * same method will be removed from the queue when a new invocation is
+ * added. This can be used in cases where only the last value is of
+ * interest.
+ * <p>
+ * The default value is <code>false</code> which means that invoking the
+ * method multiple times will cause multiple invocations to be enqueued and
+ * eventually sent to the server.
+ *
+ * @return <code>true</code> if only the last invocation of the annotated
+ * method should be sent to the server, <code>false</code> if all
+ * enqueued invocations should be sent.
+ */
+ public boolean lastonly() default false;
+}
diff --git a/server/src/com/vaadin/terminal/gwt/server/LegacyChangeVariablesInvocation.java b/shared/src/com/vaadin/shared/communication/LegacyChangeVariablesInvocation.java
index fc3fbd6c00..2ffc56dd71 100644
--- a/server/src/com/vaadin/terminal/gwt/server/LegacyChangeVariablesInvocation.java
+++ b/shared/src/com/vaadin/shared/communication/LegacyChangeVariablesInvocation.java
@@ -13,13 +13,12 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.vaadin.terminal.gwt.server;
+package com.vaadin.shared.communication;
import java.util.HashMap;
import java.util.Map;
import com.vaadin.shared.ApplicationConstants;
-import com.vaadin.shared.communication.MethodInvocation;
public class LegacyChangeVariablesInvocation extends MethodInvocation {
private Map<String, Object> variableChanges = new HashMap<String, Object>();
@@ -27,7 +26,8 @@ public class LegacyChangeVariablesInvocation extends MethodInvocation {
public LegacyChangeVariablesInvocation(String connectorId,
String variableName, Object value) {
super(connectorId, ApplicationConstants.UPDATE_VARIABLE_INTERFACE,
- ApplicationConstants.UPDATE_VARIABLE_METHOD);
+ ApplicationConstants.UPDATE_VARIABLE_METHOD, new Object[] {
+ variableName, new UidlValue(value) });
setVariableChange(variableName, value);
}
@@ -47,4 +47,11 @@ public class LegacyChangeVariablesInvocation extends MethodInvocation {
return variableChanges;
}
+ @Override
+ public String getLastonlyTag() {
+ assert variableChanges.size() == 1;
+ return super.getLastonlyTag()
+ + variableChanges.keySet().iterator().next();
+ }
+
}
diff --git a/shared/src/com/vaadin/shared/communication/MethodInvocation.java b/shared/src/com/vaadin/shared/communication/MethodInvocation.java
index 720ce09fcb..c4da937c27 100644
--- a/shared/src/com/vaadin/shared/communication/MethodInvocation.java
+++ b/shared/src/com/vaadin/shared/communication/MethodInvocation.java
@@ -71,4 +71,18 @@ public class MethodInvocation implements Serializable {
+ Arrays.toString(parameters) + ")";
}
+ /**
+ * Gets a String tag that is used to uniquely identify previous method
+ * invocations that should be purged from the queue if
+ * <code>{@literal @}Delay(lastonly = true)</code> is used.
+ * <p>
+ * The returned string should contain at least one non-number char to ensure
+ * it doesn't collide with the keys used for invocations without lastonly.
+ *
+ * @return a string identifying this method invocation
+ */
+ public String getLastonlyTag() {
+ return connectorId + "-" + getInterfaceName() + "-" + getMethodName();
+ }
+
} \ No newline at end of file
diff --git a/shared/src/com/vaadin/shared/ui/root/RootConstants.java b/shared/src/com/vaadin/shared/ui/root/RootConstants.java
index bc4f6017f6..34c17ac71f 100644
--- a/shared/src/com/vaadin/shared/ui/root/RootConstants.java
+++ b/shared/src/com/vaadin/shared/ui/root/RootConstants.java
@@ -21,12 +21,8 @@ public class RootConstants {
*/
@Deprecated
public static final String RESIZE_LAZY = "rL";
- @Deprecated
- public static final String BROWSER_HEIGHT_VAR = "browserHeight";
@Deprecated
- public static final String BROWSER_WIDTH_VAR = "browserWidth";
- @Deprecated
public static final String NOTIFICATION_HTML_CONTENT_NOT_ALLOWED = "useplain";
@Deprecated
diff --git a/shared/src/com/vaadin/shared/ui/root/RootServerRpc.java b/shared/src/com/vaadin/shared/ui/root/RootServerRpc.java
index f074a8d3cc..df2031f7d5 100644
--- a/shared/src/com/vaadin/shared/ui/root/RootServerRpc.java
+++ b/shared/src/com/vaadin/shared/ui/root/RootServerRpc.java
@@ -15,9 +15,12 @@
*/
package com.vaadin.shared.ui.root;
+import com.vaadin.shared.annotations.Delayed;
import com.vaadin.shared.communication.ServerRpc;
import com.vaadin.shared.ui.ClickRpc;
public interface RootServerRpc extends ClickRpc, ServerRpc {
-
+ @Delayed(lastonly = true)
+ public void resize(int viewWidth, int viewHeight, int windowWidth,
+ int windowHeight);
} \ No newline at end of file
diff --git a/shared/src/com/vaadin/shared/ui/root/RootState.java b/shared/src/com/vaadin/shared/ui/root/RootState.java
index b7c2c88ce5..07c71c8167 100644
--- a/shared/src/com/vaadin/shared/ui/root/RootState.java
+++ b/shared/src/com/vaadin/shared/ui/root/RootState.java
@@ -20,6 +20,7 @@ import com.vaadin.shared.Connector;
public class RootState extends ComponentState {
private Connector content;
+ private int heartbeatInterval;
public Connector getContent() {
return content;
@@ -29,4 +30,11 @@ public class RootState extends ComponentState {
this.content = content;
}
+ public int getHeartbeatInterval() {
+ return heartbeatInterval;
+ }
+
+ public void setHeartbeatInterval(int heartbeatInterval) {
+ this.heartbeatInterval = heartbeatInterval;
+ }
} \ No newline at end of file
diff --git a/tests/sass/src/com/vaadin/sass/testcases/scss/Comments.java b/tests/sass/src/com/vaadin/sass/testcases/scss/Comments.java
index ea893f96e0..c76bbb8458 100644
--- a/tests/sass/src/com/vaadin/sass/testcases/scss/Comments.java
+++ b/tests/sass/src/com/vaadin/sass/testcases/scss/Comments.java
@@ -21,9 +21,6 @@ import java.net.URISyntaxException;
import junit.framework.Assert;
-import org.junit.Test;
-import org.w3c.css.sac.CSSException;
-
import com.vaadin.sass.AbstractTestBase;
import com.vaadin.sass.ScssStylesheet;
import com.vaadin.sass.handler.SCSSDocumentHandler;
@@ -31,6 +28,9 @@ import com.vaadin.sass.handler.SCSSDocumentHandlerImpl;
import com.vaadin.sass.parser.Parser;
import com.vaadin.sass.tree.CommentNode;
+import org.junit.Test;
+import org.w3c.css.sac.CSSException;
+
public class Comments extends AbstractTestBase {
String scss = "/scss/comments.scss";
String css = "/css/comments.css";
diff --git a/tests/server-side/com/vaadin/tests/server/TransactionListenersConcurrency.java b/tests/server-side/com/vaadin/tests/server/TransactionListenersConcurrency.java
index b567617fdd..f7ac55b6da 100644
--- a/tests/server-side/com/vaadin/tests/server/TransactionListenersConcurrency.java
+++ b/tests/server-side/com/vaadin/tests/server/TransactionListenersConcurrency.java
@@ -17,14 +17,15 @@ import javax.servlet.http.HttpSession;
import junit.framework.TestCase;
-import org.easymock.EasyMock;
-
import com.vaadin.Application;
import com.vaadin.Application.ApplicationStartEvent;
import com.vaadin.service.ApplicationContext.TransactionListener;
+import com.vaadin.terminal.DeploymentConfiguration;
import com.vaadin.terminal.gwt.server.AbstractWebApplicationContext;
import com.vaadin.terminal.gwt.server.WebApplicationContext;
+import org.easymock.EasyMock;
+
public class TransactionListenersConcurrency extends TestCase {
/**
@@ -71,10 +72,15 @@ public class TransactionListenersConcurrency extends TestCase {
// Start the application so the transaction listener is
// called later on.
try {
+ DeploymentConfiguration dc = EasyMock
+ .createMock(DeploymentConfiguration.class);
+ EasyMock.expect(dc.isProductionMode()).andReturn(true);
+ EasyMock.expect(dc.getInitParameters()).andReturn(
+ new Properties());
+ EasyMock.replay(dc);
app.start(new ApplicationStartEvent(new URL(
- "http://localhost/"), new Properties(),
- context, true));
+ "http://localhost/"), dc, context));
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
@@ -101,7 +107,9 @@ public class TransactionListenersConcurrency extends TestCase {
@Override
public void uncaughtException(Thread t, Throwable e) {
- e = e.getCause();
+ if (e.getCause() != null) {
+ e = e.getCause();
+ }
exceptions.add(e);
}
});
@@ -127,8 +135,10 @@ public class TransactionListenersConcurrency extends TestCase {
if (t instanceof InvocationTargetException) {
t = t.getCause();
}
- t.printStackTrace(System.err);
- fail(t.getClass().getName());
+ if (t != null) {
+ t.printStackTrace(System.err);
+ fail(t.getClass().getName());
+ }
}
System.out.println("Done, all ok");
diff --git a/tests/server-side/com/vaadin/tests/server/component/root/CustomRootClassLoader.java b/tests/server-side/com/vaadin/tests/server/component/root/CustomRootClassLoader.java
index aa9753ebcc..fa730515a2 100644
--- a/tests/server-side/com/vaadin/tests/server/component/root/CustomRootClassLoader.java
+++ b/tests/server-side/com/vaadin/tests/server/component/root/CustomRootClassLoader.java
@@ -6,8 +6,6 @@ import java.util.Properties;
import junit.framework.TestCase;
-import org.easymock.EasyMock;
-
import com.vaadin.Application;
import com.vaadin.Application.ApplicationStartEvent;
import com.vaadin.RootRequiresMoreInformationException;
@@ -15,6 +13,8 @@ import com.vaadin.terminal.DeploymentConfiguration;
import com.vaadin.terminal.WrappedRequest;
import com.vaadin.ui.Root;
+import org.easymock.EasyMock;
+
public class CustomRootClassLoader extends TestCase {
/**
@@ -52,13 +52,24 @@ public class CustomRootClassLoader extends TestCase {
*/
public void testWithNullClassLoader() throws Exception {
Application application = createStubApplication();
- application.start(new ApplicationStartEvent(null, new Properties(),
- null, false));
+ application.start(new ApplicationStartEvent(null,
+ createConfigurationMock(), null));
Root root = application.getRootForRequest(createRequestMock(null));
assertTrue(root instanceof MyRoot);
}
+ private static DeploymentConfiguration createConfigurationMock() {
+ DeploymentConfiguration configurationMock = EasyMock
+ .createMock(DeploymentConfiguration.class);
+ EasyMock.expect(configurationMock.isProductionMode()).andReturn(false);
+ EasyMock.expect(configurationMock.getInitParameters()).andReturn(
+ new Properties());
+
+ EasyMock.replay(configurationMock);
+ return configurationMock;
+ }
+
private static WrappedRequest createRequestMock(ClassLoader classloader) {
// Mock a DeploymentConfiguration to give the passed classloader
DeploymentConfiguration configurationMock = EasyMock
@@ -86,8 +97,8 @@ public class CustomRootClassLoader extends TestCase {
LoggingClassLoader loggingClassLoader = new LoggingClassLoader();
Application application = createStubApplication();
- application.start(new ApplicationStartEvent(null, new Properties(),
- null, false));
+ application.start(new ApplicationStartEvent(null,
+ createConfigurationMock(), null));
Root root = application
.getRootForRequest(createRequestMock(loggingClassLoader));
diff --git a/tests/testbench/com/vaadin/tests/serialization/SerializerNamespaceTest.java b/tests/testbench/com/vaadin/tests/serialization/SerializerNamespaceTest.java
new file mode 100644
index 0000000000..6a873a6be3
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/serialization/SerializerNamespaceTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2011 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.tests.serialization;
+
+import com.vaadin.annotations.Widgetset;
+import com.vaadin.terminal.WrappedRequest;
+import com.vaadin.tests.components.AbstractTestRoot;
+import com.vaadin.tests.widgetset.server.DummyLabel;
+import com.vaadin.ui.Label;
+
+@Widgetset("com.vaadin.tests.widgetset.TestingWidgetSet")
+public class SerializerNamespaceTest extends AbstractTestRoot {
+
+ @Override
+ protected void setup(WrappedRequest request) {
+ addComponent(new Label("The real label"));
+ addComponent(new DummyLabel("The dummy label"));
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Using connectors with different state classes having the same simple name should not cause any clietn-side exceptions";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return Integer.valueOf(8683);
+ }
+
+}
diff --git a/tests/testbench/com/vaadin/tests/serialization/SerializerTest.html b/tests/testbench/com/vaadin/tests/serialization/SerializerTest.html
index 3d52356cab..4417fabf14 100644
--- a/tests/testbench/com/vaadin/tests/serialization/SerializerTest.html
+++ b/tests/testbench/com/vaadin/tests/serialization/SerializerTest.html
@@ -18,90 +18,94 @@
</tr>
<tr>
<td>assertText</td>
- <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[16]</td>
+ <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[17]</td>
<td>1. sendBoolean: false, false, [false, false, true, false, true, true]</td>
</tr>
<tr>
<td>assertText</td>
- <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[15]</td>
+ <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[16]</td>
<td>2. sendByte: 5, -12, [3, 1, 2]</td>
</tr>
<tr>
<td>assertText</td>
- <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[14]</td>
+ <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[15]</td>
<td>3. sendChar: Å, ∫, [a, b, c, d]</td>
</tr>
<tr>
<td>assertText</td>
- <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[13]</td>
+ <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[14]</td>
<td>4. sendInt: 2, 5, [2147483647, 0]</td>
</tr>
<tr>
<td>assertText</td>
- <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[12]</td>
+ <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[13]</td>
<td>5. sendLong: -57841235865, 577431841358, [57, 0]</td>
</tr>
<tr>
<td>assertText</td>
- <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[11]</td>
+ <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[12]</td>
<td>6. sendFloat: 1.0000001, 3.14159, [-12.0, 0.0, 57.0]</td>
</tr>
<tr>
<td>assertText</td>
- <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[10]</td>
+ <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[11]</td>
<td>7. sendDouble: 0.423310825130748, 5.859874482048838, [2.0, 1.7976931348623157E308, 4.9E-324]</td>
</tr>
<tr>
<td>assertText</td>
- <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[9]</td>
+ <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[10]</td>
<td>8. sendString: Taegghiiiinnrsssstt‡</td>
</tr>
<tr>
<td>assertText</td>
- <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[8]</td>
+ <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[9]</td>
<td>9. sendConnector: com.vaadin.tests.widgetset.server.SerializerTestExtension</td>
</tr>
<tr>
<td>assertText</td>
- <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[7]</td>
+ <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[8]</td>
<td>10. sendBean: ComplexTestBean [innerBean1=SimpleTestBean(1), innerBean2=SimpleTestBean(3), innerBeanCollection=[SimpleTestBean(6), SimpleTestBean(0)], privimite=6], SimpleTestBean(0), [SimpleTestBean(7)]</td>
</tr>
<tr>
<td>assertText</td>
- <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[6]</td>
+ <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[7]</td>
<td>11. sendNull: null, Not null</td>
</tr>
<tr>
<td>assertText</td>
- <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[5]</td>
+ <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[6]</td>
<td>12. sendNestedArray: [[7, 5]], [[SimpleTestBean(2)], [SimpleTestBean(4)]]</td>
</tr>
<tr>
<td>assertText</td>
- <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[4]</td>
+ <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[5]</td>
<td>13. sendList: [-234, 5, 8], class com.vaadin.tests.widgetset.server.SerializerTestExtension, class com.vaadin.tests.serialization.SerializerTest, [SimpleTestBean(-568), SimpleTestBean(234)]</td>
</tr>
<tr>
<td>assertText</td>
- <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[3]</td>
+ <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[4]</td>
<td>14. sendArrayList: [[2], [2]], [[2, 1], [2, 3]], [[SimpleTestBean(7)]]</td>
</tr>
<tr>
<td>assertText</td>
- <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[2]</td>
+ <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[3]</td>
<td>15. sendSet: [-12, -7, -4], class com.vaadin.tests.serialization.SerializerTest, [SimpleTestBean(2), SimpleTestBean(3)]</td>
</tr>
<tr>
<td>assertText</td>
- <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[1]</td>
+ <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[2]</td>
<td>16. sendMap: {a=null}, [com.vaadin.tests.widgetset.server.SerializerTestExtension=false], [2=com.vaadin.tests.widgetset.server.SerializerTestExtension], {SimpleTestBean(4)=SimpleTestBean(-4), SimpleTestBean(-5)=SimpleTestBean(5)}</td>
</tr>
<tr>
<td>assertText</td>
- <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[0]</td>
+ <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[1]</td>
<td>17. sendWrappedGenerics: {[SimpleTestBean(1)]={1=[SimpleTestBean(42)]}}</td>
</tr>
-
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestsserializationSerializerTest::/VVerticalLayout[0]/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[0]</td>
+ <td>18. sendEnum: PREFORMATTED, [XHTML, RAW], [PREFORMATTED, XML]</td>
+</tr>
</tbody></table>
</body>
</html>
diff --git a/tests/testbench/com/vaadin/tests/serialization/SerializerTest.java b/tests/testbench/com/vaadin/tests/serialization/SerializerTest.java
index da4b5dd7d9..a301ecf828 100644
--- a/tests/testbench/com/vaadin/tests/serialization/SerializerTest.java
+++ b/tests/testbench/com/vaadin/tests/serialization/SerializerTest.java
@@ -28,6 +28,7 @@ import java.util.Set;
import com.vaadin.annotations.Widgetset;
import com.vaadin.shared.Connector;
+import com.vaadin.shared.ui.label.ContentMode;
import com.vaadin.terminal.WrappedRequest;
import com.vaadin.tests.components.AbstractTestRoot;
import com.vaadin.tests.util.Log;
@@ -122,6 +123,10 @@ public class SerializerTest extends AbstractTestRoot {
}
});
+ rpc.sendEnum(ContentMode.TEXT, new ContentMode[] {
+ ContentMode.PREFORMATTED, ContentMode.XML },
+ Arrays.asList(ContentMode.XHTML, ContentMode.RAW));
+
testExtension.registerRpc(new SerializerTestRpc() {
@Override
public void sendBoolean(boolean value, Boolean boxedValue,
@@ -288,6 +293,13 @@ public class SerializerTest extends AbstractTestRoot {
log.log("sendWrappedGenerics: " + generics.toString());
}
+ @Override
+ public void sendEnum(ContentMode contentMode, ContentMode[] array,
+ List<ContentMode> list) {
+ log.log("sendEnum: " + contentMode + ", "
+ + Arrays.toString(array) + ", " + list);
+ }
+
});
}
diff --git a/tests/testbench/com/vaadin/tests/widgetset/client/DummyLabelConnector.java b/tests/testbench/com/vaadin/tests/widgetset/client/DummyLabelConnector.java
new file mode 100644
index 0000000000..bf3a472b33
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/widgetset/client/DummyLabelConnector.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2011 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.tests.widgetset.client;
+
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
+import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector;
+import com.vaadin.terminal.gwt.client.ui.label.VLabel;
+import com.vaadin.tests.widgetset.server.DummyLabel;
+
+/**
+ * Dummy connector just to cause {@link LabelState} to be used to test #8683
+ *
+ * @author Vaadin Ltd
+ * @version @VERSION@
+ * @since 7.0.0
+ */
+@Connect(DummyLabel.class)
+public class DummyLabelConnector extends AbstractComponentConnector {
+ @Override
+ public LabelState getState() {
+ return (LabelState) super.getState();
+ }
+
+ @Override
+ public void onStateChanged(StateChangeEvent stateChangeEvent) {
+ super.onStateChanged(stateChangeEvent);
+
+ getWidget().setText(getState().getText());
+ }
+
+ @Override
+ public VLabel getWidget() {
+ return (VLabel) super.getWidget();
+ }
+}
diff --git a/tests/testbench/com/vaadin/tests/widgetset/client/LabelState.java b/tests/testbench/com/vaadin/tests/widgetset/client/LabelState.java
new file mode 100644
index 0000000000..91a269e33f
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/widgetset/client/LabelState.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2011 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.tests.widgetset.client;
+
+import com.vaadin.shared.ComponentState;
+
+/**
+ * State class with the same simple name as
+ * {@link com.vaadin.shared.ui.label.LabelState} to test #8683
+ *
+ * @author Vaadin Ltd
+ * @version @VERSION@
+ * @since 7.0.0
+ */
+public class LabelState extends ComponentState {
+
+ private String text;
+
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+}
diff --git a/tests/testbench/com/vaadin/tests/widgetset/client/SerializerTestConnector.java b/tests/testbench/com/vaadin/tests/widgetset/client/SerializerTestConnector.java
index 3977ff7f71..9fb6807bb7 100644
--- a/tests/testbench/com/vaadin/tests/widgetset/client/SerializerTestConnector.java
+++ b/tests/testbench/com/vaadin/tests/widgetset/client/SerializerTestConnector.java
@@ -28,6 +28,7 @@ import java.util.Set;
import com.vaadin.shared.Connector;
import com.vaadin.shared.ui.Connect;
+import com.vaadin.shared.ui.label.ContentMode;
import com.vaadin.terminal.gwt.client.communication.RpcProxy;
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
import com.vaadin.terminal.gwt.client.extensions.AbstractExtensionConnector;
@@ -231,6 +232,16 @@ public class SerializerTestConnector extends AbstractExtensionConnector {
objectListArray[0] }, new List[] { Collections
.singletonList(beanListArray[0].get(0)) });
}
+
+ @Override
+ public void sendEnum(ContentMode contentMode, ContentMode[] array,
+ List<ContentMode> list) {
+ ContentMode nextContentMode = ContentMode.values()[contentMode
+ .ordinal() + 1];
+ rpc.sendEnum(nextContentMode,
+ list.toArray(new ContentMode[list.size()]),
+ Arrays.asList(array));
+ }
});
}
diff --git a/tests/testbench/com/vaadin/tests/widgetset/client/SerializerTestRpc.java b/tests/testbench/com/vaadin/tests/widgetset/client/SerializerTestRpc.java
index 47a26b7408..eb3a20e90e 100644
--- a/tests/testbench/com/vaadin/tests/widgetset/client/SerializerTestRpc.java
+++ b/tests/testbench/com/vaadin/tests/widgetset/client/SerializerTestRpc.java
@@ -23,6 +23,7 @@ import java.util.Set;
import com.vaadin.shared.Connector;
import com.vaadin.shared.communication.ClientRpc;
import com.vaadin.shared.communication.ServerRpc;
+import com.vaadin.shared.ui.label.ContentMode;
@SuppressWarnings("javadoc")
public interface SerializerTestRpc extends ServerRpc, ClientRpc {
@@ -73,4 +74,6 @@ public interface SerializerTestRpc extends ServerRpc, ClientRpc {
public void sendWrappedGenerics(
Map<Set<SimpleTestBean>, Map<Integer, List<SimpleTestBean>>> generics);
+ public void sendEnum(ContentMode contentMode, ContentMode[] array, List<ContentMode> list);
+
}
diff --git a/tests/testbench/com/vaadin/tests/widgetset/server/DummyLabel.java b/tests/testbench/com/vaadin/tests/widgetset/server/DummyLabel.java
new file mode 100644
index 0000000000..bda36d64a8
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/widgetset/server/DummyLabel.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2011 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.tests.widgetset.server;
+
+import com.vaadin.tests.widgetset.client.LabelState;
+import com.vaadin.ui.AbstractComponent;
+
+/**
+ * Dummy component to cause {@link LabelState} to be used to test #8683
+ *
+ * @author Vaadin Ltd
+ * @version @VERSION@
+ * @since 7.0.0
+ */
+public class DummyLabel extends AbstractComponent {
+ public DummyLabel(String text) {
+ getState().setText(text);
+ }
+
+ @Override
+ public LabelState getState() {
+ return (LabelState) super.getState();
+ }
+}