summaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorHenrik Paul <henrik@vaadin.com>2013-10-18 15:09:43 +0300
committerHenrik Paul <henrik@vaadin.com>2013-10-18 15:09:53 +0300
commit7cba636d8938c4491ae4c1995064ed0ef83ccdd7 (patch)
treeda0f777665d1e0a56eb892d02d156b29c6c517b1 /server
parentdf3d643b3aaa3112d59e2ae0fb3649dd37e927a7 (diff)
parent6a99730d898f8e0663d69dbeba6682113c29ca52 (diff)
downloadvaadin-framework-7cba636d8938c4491ae4c1995064ed0ef83ccdd7.tar.gz
vaadin-framework-7cba636d8938c4491ae4c1995064ed0ef83ccdd7.zip
Merge changes from origin/7.1
377d49e Allow configuring deployment port for TB3 tests 6779857 Updatet servlet tests to follow the same *Test naming convention e1c38bf Avoid obsolete calendar panel renderings to avoid various NPEs. (#12504,#12667) 63f10ec Fixed compilation error in TB3 test 3e593b0 Focus selected row in Table #12540 3c842b7 added small pause to make test pass 1b7e40d Only fetch rows if there are some (#11189) f595d05 Make the various Writers member fields instead of local variables (#12446) 4cb304d Converted broken test to TB3 2aa2fdc Handle ClientMethodInvocation serialization with JSONArray as parameter (#12532) 1449425 Also hide shim iframe of VOverlay on setVisible(false) (#12731) 25fc2f2 Fix whitespace after including a mixin (#12715) c29ca5e Update to atmosphere javascript 2.0.3-vaadin1 (#12241, #12127) f75164f Disable unit cache to avoid compilation issues when switching between branches 6a99730 Allow skipping TB2/TB3 tests using tests.tb2/tb3.skip Change-Id: I5a92798e66575c2cfd1d3f761a5f00af7e83dc64
Diffstat (limited to 'server')
-rw-r--r--server/src/com/vaadin/server/ClientMethodInvocation.java54
-rw-r--r--server/src/com/vaadin/server/Constants.java4
-rw-r--r--server/src/com/vaadin/server/VaadinServletService.java4
-rw-r--r--server/src/com/vaadin/server/communication/UidlRequestHandler.java5
-rw-r--r--server/src/com/vaadin/server/communication/UidlWriter.java32
-rw-r--r--server/tests/src/com/vaadin/server/communication/UidlWriterTest.java125
-rw-r--r--server/tests/src/com/vaadin/tests/server/TestAtmosphereVersion.java2
-rw-r--r--server/tests/src/com/vaadin/tests/server/TestClientMethodSerialization.java111
8 files changed, 318 insertions, 19 deletions
diff --git a/server/src/com/vaadin/server/ClientMethodInvocation.java b/server/src/com/vaadin/server/ClientMethodInvocation.java
index 9c8318b064..3a6a87a53c 100644
--- a/server/src/com/vaadin/server/ClientMethodInvocation.java
+++ b/server/src/com/vaadin/server/ClientMethodInvocation.java
@@ -16,10 +16,16 @@
package com.vaadin.server;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
+import org.json.JSONArray;
+import org.json.JSONException;
+
/**
* Internal class for keeping track of pending server to client method
* invocations for a Connector.
@@ -80,4 +86,52 @@ public class ClientMethodInvocation implements Serializable,
}
return Long.signum(getSequenceNumber() - o.getSequenceNumber());
}
+
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ // Need to have custom serialization and deserialization because the
+ // constructor allows parameters of any type with Object[]. Thus, having
+ // parameters that are not Serializable will lead to
+ // NotSerializableException when trying to serialize this class.
+ // An example case of this is in #12532 (JavaScriptCallbackHelper ->
+ // JSONArray as parameter and not Serializable), for which this
+ // hac..workaround is implemented.
+
+ // Goes through the parameter types, and apply "custom serialization" to
+ // the ones that are not Serializable by changing them into something
+ // that is Serializable. On deserialization (readObject-method below)
+ // the process should be reversed.
+
+ // Easy way for implementing serialization & deserialization is by
+ // writing/parsing the object's content as string.
+ for (int i = 0; i < parameterTypes.length; i++) {
+ Type type = parameterTypes[i];
+ if (type instanceof Class<?>) {
+ Class<?> clazz = (Class<?>) type;
+ if (JSONArray.class.isAssignableFrom(clazz)) {
+ parameters[i] = ((JSONArray) parameters[i]).toString();
+ }
+ }
+ }
+ stream.defaultWriteObject();
+ }
+
+ private void readObject(ObjectInputStream stream) throws IOException,
+ ClassNotFoundException {
+ // Reverses the serialization done in writeObject. Basically just
+ // parsing the serialized type back to the non-serializable type.
+ stream.defaultReadObject();
+ for (int i = 0; i < parameterTypes.length; i++) {
+ Type type = parameterTypes[i];
+ if (type instanceof Class<?>) {
+ Class<?> clazz = (Class<?>) type;
+ if (JSONArray.class.isAssignableFrom(clazz)) {
+ try {
+ parameters[i] = new JSONArray(((String) parameters[i]));
+ } catch (JSONException e) {
+ throw new IOException(e);
+ }
+ }
+ }
+ }
+ }
} \ No newline at end of file
diff --git a/server/src/com/vaadin/server/Constants.java b/server/src/com/vaadin/server/Constants.java
index 8c379abe06..e910ba903b 100644
--- a/server/src/com/vaadin/server/Constants.java
+++ b/server/src/com/vaadin/server/Constants.java
@@ -67,7 +67,7 @@ public interface Constants {
// Keep the version number in sync with push/build.xml and other locations
// listed in that file
- static final String REQUIRED_ATMOSPHERE_VERSION = "1.0.14.vaadin4";
+ static final String REQUIRED_ATMOSPHERE_RUNTIME_VERSION = "1.0.14.vaadin4";
static final String INVALID_ATMOSPHERE_VERSION_WARNING = "\n"
+ "=================================================================\n"
@@ -82,7 +82,7 @@ public interface Constants {
+ "If using a dependency management system, please add a dependency\n"
+ "to vaadin-push.\n"
+ "If managing dependencies manually, please make sure Atmosphere\n"
- + REQUIRED_ATMOSPHERE_VERSION
+ + REQUIRED_ATMOSPHERE_RUNTIME_VERSION
+ " is included on the classpath.\n"
+ "Will fall back to using "
+ PushMode.class.getSimpleName()
diff --git a/server/src/com/vaadin/server/VaadinServletService.java b/server/src/com/vaadin/server/VaadinServletService.java
index 3b39f17849..818f2e87c6 100644
--- a/server/src/com/vaadin/server/VaadinServletService.java
+++ b/server/src/com/vaadin/server/VaadinServletService.java
@@ -66,11 +66,11 @@ public class VaadinServletService extends VaadinService {
private static boolean checkAtmosphereSupport() {
try {
String rawVersion = Version.getRawVersion();
- if (!Constants.REQUIRED_ATMOSPHERE_VERSION.equals(rawVersion)) {
+ if (!Constants.REQUIRED_ATMOSPHERE_RUNTIME_VERSION.equals(rawVersion)) {
getLogger().log(
Level.WARNING,
Constants.INVALID_ATMOSPHERE_VERSION_WARNING,
- new Object[] { Constants.REQUIRED_ATMOSPHERE_VERSION,
+ new Object[] { Constants.REQUIRED_ATMOSPHERE_RUNTIME_VERSION,
rawVersion });
}
return true;
diff --git a/server/src/com/vaadin/server/communication/UidlRequestHandler.java b/server/src/com/vaadin/server/communication/UidlRequestHandler.java
index cf25910fa4..2277e1c76f 100644
--- a/server/src/com/vaadin/server/communication/UidlRequestHandler.java
+++ b/server/src/com/vaadin/server/communication/UidlRequestHandler.java
@@ -56,8 +56,7 @@ public class UidlRequestHandler extends SynchronizedRequestHandler implements
private ServerRpcHandler rpcHandler = new ServerRpcHandler();
- public UidlRequestHandler() {
- }
+ private UidlWriter uidlWriter = new UidlWriter();
@Override
protected boolean canHandleRequest(VaadinRequest request) {
@@ -148,7 +147,7 @@ public class UidlRequestHandler extends SynchronizedRequestHandler implements
JSONException {
openJsonMessage(writer, response);
- new UidlWriter().write(ui, writer, repaintAll, false);
+ uidlWriter.write(ui, writer, repaintAll, false);
closeJsonMessage(writer);
}
diff --git a/server/src/com/vaadin/server/communication/UidlWriter.java b/server/src/com/vaadin/server/communication/UidlWriter.java
index b46fbbf58a..a290eb4846 100644
--- a/server/src/com/vaadin/server/communication/UidlWriter.java
+++ b/server/src/com/vaadin/server/communication/UidlWriter.java
@@ -52,6 +52,14 @@ import com.vaadin.ui.UI;
*/
public class UidlWriter implements Serializable {
+ private LegacyUidlWriter legacyUidlWriter = new LegacyUidlWriter();
+ private SharedStateWriter sharedStateWriter = new SharedStateWriter();
+ private ConnectorTypeWriter connectorTypeWriter = new ConnectorTypeWriter();
+ private ConnectorHierarchyWriter connectorHierarchyWriter = new ConnectorHierarchyWriter();
+ private ClientRpcWriter clientRpcWriter = new ClientRpcWriter();
+ private MetadataWriter metadataWriter = new MetadataWriter();
+ private ResourceWriter resourceWriter = new ResourceWriter();
+
/**
* Writes a JSON object containing all pending changes to the given UI.
*
@@ -80,13 +88,12 @@ public class UidlWriter implements Serializable {
// to write out
session.getService().runPendingAccessTasks(session);
- ArrayList<ClientConnector> dirtyVisibleConnectors = ui
- .getConnectorTracker().getDirtyVisibleConnectors();
- LegacyCommunicationManager manager = session.getCommunicationManager();
// Paints components
- ConnectorTracker uiConnectorTracker = ui.getConnectorTracker();
getLogger().log(Level.FINE, "* Creating response to client");
+ ConnectorTracker uiConnectorTracker = ui.getConnectorTracker();
+ ArrayList<ClientConnector> dirtyVisibleConnectors = uiConnectorTracker
+ .getDirtyVisibleConnectors();
getLogger().log(
Level.FINE,
"Found " + dirtyVisibleConnectors.size()
@@ -104,10 +111,13 @@ public class UidlWriter implements Serializable {
writer.write("\"changes\" : ");
+ LegacyCommunicationManager manager = session
+ .getCommunicationManager();
+
JsonPaintTarget paintTarget = new JsonPaintTarget(manager, writer,
!repaintAll);
- new LegacyUidlWriter().write(ui, writer, paintTarget);
+ legacyUidlWriter.write(ui, writer, paintTarget);
paintTarget.close();
writer.write(", "); // close changes
@@ -124,7 +134,7 @@ public class UidlWriter implements Serializable {
// processing.
writer.write("\"state\":");
- new SharedStateWriter().write(ui, writer);
+ sharedStateWriter.write(ui, writer);
writer.write(", "); // close states
// TODO This should be optimized. The type only needs to be
@@ -133,7 +143,7 @@ public class UidlWriter implements Serializable {
// widget mapping
writer.write("\"types\":");
- new ConnectorTypeWriter().write(ui, writer, paintTarget);
+ connectorTypeWriter.write(ui, writer, paintTarget);
writer.write(", "); // close states
// Send update hierarchy information to the client.
@@ -144,7 +154,7 @@ public class UidlWriter implements Serializable {
// child to 0 children)
writer.write("\"hierarchy\":");
- new ConnectorHierarchyWriter().write(ui, writer);
+ connectorHierarchyWriter.write(ui, writer);
writer.write(", "); // close hierarchy
// send server to client RPC calls for components in the UI, in call
@@ -154,7 +164,7 @@ public class UidlWriter implements Serializable {
// which they were performed, remove the calls from components
writer.write("\"rpc\" : ");
- new ClientRpcWriter().write(ui, writer);
+ clientRpcWriter.write(ui, writer);
writer.write(", "); // close rpc
uiConnectorTracker.markAllConnectorsClean();
@@ -164,11 +174,11 @@ public class UidlWriter implements Serializable {
SystemMessages messages = ui.getSession().getService()
.getSystemMessages(ui.getLocale(), null);
// TODO hilightedConnector
- new MetadataWriter().write(ui, writer, repaintAll, async, messages);
+ metadataWriter.write(ui, writer, repaintAll, async, messages);
writer.write(", ");
writer.write("\"resources\" : ");
- new ResourceWriter().write(ui, writer, paintTarget);
+ resourceWriter.write(ui, writer, paintTarget);
Collection<Class<? extends ClientConnector>> usedClientConnectors = paintTarget
.getUsedClientConnectors();
diff --git a/server/tests/src/com/vaadin/server/communication/UidlWriterTest.java b/server/tests/src/com/vaadin/server/communication/UidlWriterTest.java
new file mode 100644
index 0000000000..8dcd6cbdf4
--- /dev/null
+++ b/server/tests/src/com/vaadin/server/communication/UidlWriterTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2000-2013 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.server.communication;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Locale;
+
+import org.easymock.EasyMock;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.vaadin.server.ClientConnector;
+import com.vaadin.server.LegacyCommunicationManager;
+import com.vaadin.server.SystemMessages;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.VaadinService;
+import com.vaadin.server.VaadinSession;
+import com.vaadin.server.WrappedSession;
+import com.vaadin.ui.ConnectorTracker;
+import com.vaadin.ui.UI;
+
+/**
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+public class UidlWriterTest {
+
+ private UI ui;
+ private UidlWriter uidlWriter;
+
+ @Before
+ public void setUp() {
+ SystemMessages messages = EasyMock.createNiceMock(SystemMessages.class);
+ EasyMock.expect(messages.isSessionExpiredNotificationEnabled())
+ .andReturn(true).anyTimes();
+ EasyMock.replay(messages);
+
+ VaadinService service = EasyMock.createNiceMock(VaadinService.class);
+ EasyMock.expect(
+ service.getSystemMessages(EasyMock.anyObject(Locale.class),
+ EasyMock.anyObject(VaadinRequest.class)))
+ .andReturn(messages).anyTimes();
+ EasyMock.replay(service);
+
+ LegacyCommunicationManager manager = EasyMock
+ .createNiceMock(LegacyCommunicationManager.class);
+ EasyMock.replay(manager);
+
+ WrappedSession wrappedSession = EasyMock
+ .createNiceMock(WrappedSession.class);
+ EasyMock.expect(wrappedSession.getMaxInactiveInterval()).andReturn(100)
+ .times(3).andReturn(200);
+
+ EasyMock.replay(wrappedSession);
+
+ VaadinSession session = EasyMock.createNiceMock(VaadinSession.class);
+ EasyMock.expect(session.getService()).andReturn(service).anyTimes();
+ EasyMock.expect(session.getCommunicationManager()).andReturn(manager)
+ .anyTimes();
+ EasyMock.expect(session.getSession()).andReturn(wrappedSession)
+ .anyTimes();
+ EasyMock.replay(session);
+
+ ConnectorTracker tracker = EasyMock
+ .createNiceMock(ConnectorTracker.class);
+ EasyMock.expect(tracker.getDirtyVisibleConnectors())
+ .andReturn(new ArrayList<ClientConnector>()).anyTimes();
+ EasyMock.replay(tracker);
+
+ ui = EasyMock.createNiceMock(UI.class);
+ EasyMock.expect(ui.getSession()).andReturn(session).anyTimes();
+ EasyMock.expect(ui.getConnectorTracker()).andReturn(tracker).anyTimes();
+ EasyMock.replay(ui);
+
+ uidlWriter = new UidlWriter();
+ }
+
+ @Test
+ public void testMetadataWriterState() throws IOException, JSONException {
+
+ Assert.assertEquals(
+ "Metadata should contain redirect interval on first write",
+ 115, getRedirect(uidl(false, false)).optInt("interval"));
+ Assert.assertNull(
+ "Metadata should not contain redirect interval on second write",
+ getRedirect(uidl(false, false)));
+ Assert.assertEquals(
+ "Metadata should contain redirect interval on repaintAll", 115,
+ getRedirect(uidl(true, false)).optInt("interval"));
+ Assert.assertEquals(
+ "Metadata should contain redirect interval when changed in session",
+ 215, getRedirect(uidl(false, false)).optInt("interval"));
+ }
+
+ private JSONObject uidl(boolean repaintAll, boolean async)
+ throws IOException, JSONException {
+ StringWriter writer = new StringWriter();
+ uidlWriter.write(ui, writer, repaintAll, async);
+ return new JSONObject("{" + writer.toString() + "}");
+ }
+
+ private JSONObject getRedirect(JSONObject json) throws JSONException {
+ return json.getJSONObject("meta").optJSONObject("timedRedirect");
+
+ }
+}
diff --git a/server/tests/src/com/vaadin/tests/server/TestAtmosphereVersion.java b/server/tests/src/com/vaadin/tests/server/TestAtmosphereVersion.java
index 5c27ef0752..3d37022b81 100644
--- a/server/tests/src/com/vaadin/tests/server/TestAtmosphereVersion.java
+++ b/server/tests/src/com/vaadin/tests/server/TestAtmosphereVersion.java
@@ -12,7 +12,7 @@ public class TestAtmosphereVersion extends TestCase {
* classpath
*/
public void testAtmosphereVersion() {
- assertEquals(Constants.REQUIRED_ATMOSPHERE_VERSION,
+ assertEquals(Constants.REQUIRED_ATMOSPHERE_RUNTIME_VERSION,
Version.getRawVersion());
}
}
diff --git a/server/tests/src/com/vaadin/tests/server/TestClientMethodSerialization.java b/server/tests/src/com/vaadin/tests/server/TestClientMethodSerialization.java
new file mode 100644
index 0000000000..1e0210dc63
--- /dev/null
+++ b/server/tests/src/com/vaadin/tests/server/TestClientMethodSerialization.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2000-2013 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.server;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+import org.json.JSONArray;
+
+import com.vaadin.server.ClientMethodInvocation;
+import com.vaadin.server.JavaScriptCallbackHelper;
+import com.vaadin.ui.JavaScript.JavaScriptCallbackRpc;
+import com.vaadin.util.ReflectTools;
+
+public class TestClientMethodSerialization extends TestCase {
+
+ private static final Method JAVASCRIPT_CALLBACK_METHOD = ReflectTools
+ .findMethod(JavaScriptCallbackRpc.class, "call", String.class,
+ JSONArray.class);
+
+ private static final Method BASIC_PARAMS_CALL_METHOD = ReflectTools
+ .findMethod(TestClientMethodSerialization.class,
+ "basicParamsMethodForTesting", String.class, Integer.class);
+
+ private static final Method NO_PARAMS_CALL_METHOD = ReflectTools
+ .findMethod(TestClientMethodSerialization.class,
+ "noParamsMethodForTesting");
+
+ public void basicParamsMethodForTesting(String stringParam,
+ Integer integerParam) {
+ }
+
+ public void noParamsMethodForTesting() {
+ }
+
+ /**
+ * Tests the {@link ClientMethodInvocation} serialization when using
+ * {@link JavaScriptCallbackHelper#invokeCallback(String, Object...)}.
+ * #12532
+ */
+ public void testClientMethodSerialization_WithJSONArray_ContentStaysSame()
+ throws Exception {
+ JSONArray originalArray = new JSONArray(Arrays.asList(
+ "callbackParameter1", "callBackParameter2", "12345"));
+ ClientMethodInvocation original = new ClientMethodInvocation(null,
+ "interfaceName", JAVASCRIPT_CALLBACK_METHOD, new Object[] {
+ "callBackMethodName", originalArray });
+
+ ClientMethodInvocation copy = (ClientMethodInvocation) serializeAndDeserialize(original);
+ JSONArray copyArray = (JSONArray) copy.getParameters()[1];
+ assertEquals(originalArray.toString(), copyArray.toString());
+ }
+
+ public void testClientMethodSerialization_WithBasicParams_NoChanges()
+ throws Exception {
+ String stringParam = "a string 123";
+ Integer integerParam = 1234567890;
+ ClientMethodInvocation original = new ClientMethodInvocation(null,
+ "interfaceName", BASIC_PARAMS_CALL_METHOD, new Serializable[] {
+ stringParam, integerParam });
+ ClientMethodInvocation copy = (ClientMethodInvocation) serializeAndDeserialize(original);
+ String copyString = (String) copy.getParameters()[0];
+ Integer copyInteger = (Integer) copy.getParameters()[1];
+ assertEquals(copyString, stringParam);
+ assertEquals(copyInteger, integerParam);
+ }
+
+ public void testClientMethodSerialization_NoParams_NoExceptions() {
+ ClientMethodInvocation original = new ClientMethodInvocation(null,
+ "interfaceName", NO_PARAMS_CALL_METHOD, null);
+ ClientMethodInvocation copy = (ClientMethodInvocation) serializeAndDeserialize(original);
+ }
+
+ private static Serializable serializeAndDeserialize(Serializable input) {
+ Serializable output = null;
+ try {
+ ByteArrayOutputStream bs = new ByteArrayOutputStream();
+ ObjectOutputStream out = new ObjectOutputStream(bs);
+ out.writeObject(input);
+ byte[] data = bs.toByteArray();
+ ObjectInputStream in = new ObjectInputStream(
+ new ByteArrayInputStream(data));
+ output = (Serializable) in.readObject();
+ } catch (Exception e) {
+ fail("Exception during serialization/deserialization: "
+ + e.getMessage());
+ }
+ return output;
+ }
+
+}