diff options
author | Henrik Paul <henrik@vaadin.com> | 2013-10-18 15:09:43 +0300 |
---|---|---|
committer | Henrik Paul <henrik@vaadin.com> | 2013-10-18 15:09:53 +0300 |
commit | 7cba636d8938c4491ae4c1995064ed0ef83ccdd7 (patch) | |
tree | da0f777665d1e0a56eb892d02d156b29c6c517b1 /server | |
parent | df3d643b3aaa3112d59e2ae0fb3649dd37e927a7 (diff) | |
parent | 6a99730d898f8e0663d69dbeba6682113c29ca52 (diff) | |
download | vaadin-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')
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; + } + +} |