Skip to content

Commit

Permalink
Fix serialization with ApplicationRunnerServlet
Browse files Browse the repository at this point in the history
Make the InvocationHandler used by the DeploymentConfiguration proxying
feature serializable. Also make findDeploymentConfiguration static to
avoid serializing an ApplicatinRunnerServlet instance.

Change-Id: I360276ae42a875e9227df34e8aabf8ce2a697bc2
  • Loading branch information
Legioth authored and Vaadin Code Review committed Jan 7, 2015
1 parent 0c9625d commit c0b90c7
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 30 deletions.
61 changes: 40 additions & 21 deletions uitest/src/com/vaadin/launcher/ApplicationRunnerServlet.java
Expand Up @@ -17,6 +17,7 @@


import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
Expand Down Expand Up @@ -48,7 +49,10 @@
import com.vaadin.server.UIClassSelectionEvent; import com.vaadin.server.UIClassSelectionEvent;
import com.vaadin.server.UIProvider; import com.vaadin.server.UIProvider;
import com.vaadin.server.VaadinRequest; import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinService;
import com.vaadin.server.VaadinServlet;
import com.vaadin.server.VaadinServletRequest; import com.vaadin.server.VaadinServletRequest;
import com.vaadin.server.VaadinServletService;
import com.vaadin.server.VaadinSession; import com.vaadin.server.VaadinSession;
import com.vaadin.tests.components.TestBase; import com.vaadin.tests.components.TestBase;
import com.vaadin.ui.UI; import com.vaadin.ui.UI;
Expand Down Expand Up @@ -184,6 +188,29 @@ private String getApplicationRunnerApplicationClassName(
return getApplicationRunnerURIs(request).applicationClassname; return getApplicationRunnerURIs(request).applicationClassname;
} }


private final static class ProxyDeploymentConfiguration implements
InvocationHandler, Serializable {
private final DeploymentConfiguration originalConfiguration;

private ProxyDeploymentConfiguration(
DeploymentConfiguration originalConfiguration) {
this.originalConfiguration = originalConfiguration;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if (method.getDeclaringClass() == DeploymentConfiguration.class) {
// Find the configuration instance to delegate to
DeploymentConfiguration configuration = findDeploymentConfiguration(originalConfiguration);

return method.invoke(configuration, args);
} else {
return method.invoke(proxy, args);
}
}
}

private static final class ApplicationRunnerUIProvider extends UIProvider { private static final class ApplicationRunnerUIProvider extends UIProvider {
private final Class<?> classToRun; private final Class<?> classToRun;


Expand Down Expand Up @@ -309,23 +336,10 @@ protected DeploymentConfiguration createDeploymentConfiguration(
return (DeploymentConfiguration) Proxy.newProxyInstance( return (DeploymentConfiguration) Proxy.newProxyInstance(
DeploymentConfiguration.class.getClassLoader(), DeploymentConfiguration.class.getClassLoader(),
new Class[] { DeploymentConfiguration.class }, new Class[] { DeploymentConfiguration.class },
new InvocationHandler() { new ProxyDeploymentConfiguration(originalConfiguration));
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
if (method.getDeclaringClass() == DeploymentConfiguration.class) {
// Find the configuration instance to delegate to
DeploymentConfiguration configuration = findDeploymentConfiguration(originalConfiguration);

return method.invoke(configuration, args);
} else {
return method.invoke(proxy, args);
}
}
});
} }


private DeploymentConfiguration findDeploymentConfiguration( private static DeploymentConfiguration findDeploymentConfiguration(
DeploymentConfiguration originalConfiguration) throws Exception { DeploymentConfiguration originalConfiguration) throws Exception {
// First level of cache // First level of cache
DeploymentConfiguration configuration = CurrentInstance DeploymentConfiguration configuration = CurrentInstance
Expand All @@ -344,16 +358,19 @@ private DeploymentConfiguration findDeploymentConfiguration(
* request. * request.
*/ */


HttpServletRequest currentRequest = request.get(); HttpServletRequest currentRequest = VaadinServletService
.getCurrentServletRequest();
if (currentRequest != null) { if (currentRequest != null) {
HttpSession httpSession = currentRequest.getSession(false); HttpSession httpSession = currentRequest.getSession(false);
if (httpSession != null) { if (httpSession != null) {
Map<Class<?>, CurrentInstance> oldCurrent = CurrentInstance Map<Class<?>, CurrentInstance> oldCurrent = CurrentInstance
.setCurrent((VaadinSession) null); .setCurrent((VaadinSession) null);
try { try {
session = getService().findVaadinSession( VaadinServletService service = (VaadinServletService) VaadinService
new VaadinServletRequest(currentRequest, .getCurrent();
getService())); session = service
.findVaadinSession(new VaadinServletRequest(
currentRequest, service));
} finally { } finally {
/* /*
* Clear some state set by findVaadinSession to * Clear some state set by findVaadinSession to
Expand All @@ -377,9 +394,11 @@ private DeploymentConfiguration findDeploymentConfiguration(
.getAttribute(name); .getAttribute(name);


if (configuration == null) { if (configuration == null) {
ApplicationRunnerServlet servlet = (ApplicationRunnerServlet) VaadinServlet
.getCurrent();
Class<?> classToRun; Class<?> classToRun;
try { try {
classToRun = getClassToRun(); classToRun = servlet.getClassToRun();
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
/* /*
* This happens e.g. if the UI class defined in the * This happens e.g. if the UI class defined in the
Expand All @@ -402,7 +421,7 @@ private DeploymentConfiguration findDeploymentConfiguration(
} }


configuration = new DefaultDeploymentConfiguration( configuration = new DefaultDeploymentConfiguration(
getClass(), initParameters); servlet.getClass(), initParameters);
} else { } else {
configuration = originalConfiguration; configuration = originalConfiguration;
} }
Expand Down
25 changes: 16 additions & 9 deletions uitest/src/com/vaadin/tests/components/ui/UISerializationTest.java
@@ -1,26 +1,33 @@
package com.vaadin.tests.components.ui; package com.vaadin.tests.components.ui;


import com.vaadin.testbench.elements.ButtonElement; import static org.hamcrest.Matchers.allOf;
import com.vaadin.tests.tb3.SingleBrowserTest; import static org.hamcrest.Matchers.containsString;
import org.junit.Ignore; import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertThat;

import org.junit.Test; import org.junit.Test;


import static org.hamcrest.Matchers.*; import com.vaadin.testbench.elements.ButtonElement;
import static org.junit.Assert.assertThat; import com.vaadin.tests.tb3.SingleBrowserTest;


public class UISerializationTest extends SingleBrowserTest { public class UISerializationTest extends SingleBrowserTest {


@Test @Test
@Ignore public void uiIsSerialized() throws Exception {
// Broken on all browsers since 9696e6c3e7e952b66ac3f5c9ddc3dfca4233451e
public void tb2test() throws Exception {
openTestURL(); openTestURL();
$(ButtonElement.class).first().click();
serialize();

assertThat(getLogRow(0), startsWith("3. Diff states match, size: ")); assertThat(getLogRow(0), startsWith("3. Diff states match, size: "));
assertThat(getLogRow(1), startsWith("2. Deserialized UI in ")); assertThat(getLogRow(1), startsWith("2. Deserialized UI in "));
assertThat( assertThat(
getLogRow(2), getLogRow(2),
allOf(startsWith("1. Serialized UI in"), allOf(startsWith("1. Serialized UI in"),
containsString(" into "), endsWith(" bytes"))); containsString(" into "), endsWith(" bytes")));
} }

private void serialize() {
$(ButtonElement.class).first().click();
}
} }

0 comments on commit c0b90c7

Please sign in to comment.