aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorLeif Åstrand <legioth@gmail.com>2017-02-07 10:07:07 +0200
committerGitHub <noreply@github.com>2017-02-07 10:07:07 +0200
commit61938da3c22d62dc80c993a321ac2c6096510e08 (patch)
tree7ac0398eb68883985a0985f009d93748eb34494f /server
parent909c7e56d8d57be45210424850e904149546d738 (diff)
downloadvaadin-framework-61938da3c22d62dc80c993a321ac2c6096510e08.tar.gz
vaadin-framework-61938da3c22d62dc80c993a321ac2c6096510e08.zip
Use thread-safe collections for VaadinService listeners (#7037)
Fixes #7250
Diffstat (limited to 'server')
-rw-r--r--server/src/main/java/com/vaadin/server/VaadinService.java97
1 files changed, 57 insertions, 40 deletions
diff --git a/server/src/main/java/com/vaadin/server/VaadinService.java b/server/src/main/java/com/vaadin/server/VaadinService.java
index 3050e41f0e..6d0c442785 100644
--- a/server/src/main/java/com/vaadin/server/VaadinService.java
+++ b/server/src/main/java/com/vaadin/server/VaadinService.java
@@ -25,7 +25,6 @@ import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Serializable;
import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
@@ -37,6 +36,8 @@ import java.util.Locale;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
@@ -51,7 +52,6 @@ import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletResponse;
import com.vaadin.annotations.PreserveOnRefresh;
-import com.vaadin.event.EventRouter;
import com.vaadin.server.VaadinSession.FutureAccess;
import com.vaadin.server.VaadinSession.State;
import com.vaadin.server.communication.AtmospherePushConnection;
@@ -66,7 +66,6 @@ import com.vaadin.shared.Registration;
import com.vaadin.shared.ui.ui.UIConstants;
import com.vaadin.ui.UI;
import com.vaadin.util.CurrentInstance;
-import com.vaadin.util.ReflectTools;
import elemental.json.Json;
import elemental.json.JsonException;
@@ -101,17 +100,6 @@ public abstract class VaadinService implements Serializable {
@Deprecated
static final String REINITIALIZING_SESSION_MARKER = PRESERVE_UNBOUND_SESSION_ATTRIBUTE;
- private static final Method SESSION_INIT_METHOD = ReflectTools.findMethod(
- SessionInitListener.class, "sessionInit", SessionInitEvent.class);
-
- private static final Method SESSION_DESTROY_METHOD = ReflectTools
- .findMethod(SessionDestroyListener.class, "sessionDestroy",
- SessionDestroyEvent.class);
-
- private static final Method SERVICE_DESTROY_METHOD = ReflectTools
- .findMethod(ServiceDestroyListener.class, "serviceDestroy",
- ServiceDestroyEvent.class);
-
/**
* @deprecated As of 7.0. Only supported for {@link LegacyApplication}.
*/
@@ -128,7 +116,18 @@ public abstract class VaadinService implements Serializable {
private final DeploymentConfiguration deploymentConfiguration;
- private final EventRouter eventRouter = new EventRouter();
+ /*
+ * Can't use EventRouter for these listeners since it's not thread safe. One
+ * option would be to use an EventRouter instance guarded with a lock, but
+ * then we would needlessly hold a "global" lock while invoking potentially
+ * slow listener implementations.
+ */
+ private final Set<ServiceDestroyListener> serviceDestroyListeners = Collections
+ .newSetFromMap(new ConcurrentHashMap<>());
+
+ private final List<SessionInitListener> sessionInitListeners = new CopyOnWriteArrayList<>();
+
+ private final List<SessionDestroyListener> sessionDestroyListeners = new CopyOnWriteArrayList<>();
private SystemMessagesProvider systemMessagesProvider = DefaultSystemMessagesProvider
.get();
@@ -445,8 +444,8 @@ public abstract class VaadinService implements Serializable {
* @return a registration object for removing the listener
*/
public Registration addSessionInitListener(SessionInitListener listener) {
- return eventRouter.addListener(SessionInitEvent.class, listener,
- SESSION_INIT_METHOD);
+ sessionInitListeners.add(listener);
+ return () -> sessionInitListeners.remove(listener);
}
/**
@@ -463,8 +462,7 @@ public abstract class VaadinService implements Serializable {
*/
@Deprecated
public void removeSessionInitListener(SessionInitListener listener) {
- eventRouter.removeListener(SessionInitEvent.class, listener,
- SESSION_INIT_METHOD);
+ sessionInitListeners.remove(listener);
}
/**
@@ -482,8 +480,8 @@ public abstract class VaadinService implements Serializable {
*/
public Registration addSessionDestroyListener(
SessionDestroyListener listener) {
- return eventRouter.addListener(SessionDestroyEvent.class, listener,
- SESSION_DESTROY_METHOD);
+ sessionDestroyListeners.add(listener);
+ return () -> sessionDestroyListeners.remove(listener);
}
/**
@@ -517,12 +515,20 @@ public abstract class VaadinService implements Serializable {
session.removeUI(ui);
});
}
- // for now, use the session error handler; in the future, could
- // have an API for using some other handler for session init and
- // destroy listeners
- eventRouter.fireEvent(
- new SessionDestroyEvent(VaadinService.this, session),
- session.getErrorHandler());
+ SessionDestroyEvent event = new SessionDestroyEvent(
+ VaadinService.this, session);
+ for (SessionDestroyListener listener : sessionDestroyListeners) {
+ try {
+ listener.sessionDestroy(event);
+ } catch (Exception e) {
+ /*
+ * for now, use the session error handler; in the future,
+ * could have an API for using some other handler for
+ * session init and destroy listeners
+ */
+ session.getErrorHandler().error(new ErrorEvent(e));
+ }
+ }
session.setState(State.CLOSED);
});
}
@@ -540,8 +546,7 @@ public abstract class VaadinService implements Serializable {
*/
@Deprecated
public void removeSessionDestroyListener(SessionDestroyListener listener) {
- eventRouter.removeListener(SessionDestroyEvent.class, listener,
- SESSION_DESTROY_METHOD);
+ sessionDestroyListeners.remove(listener);
}
/**
@@ -851,12 +856,19 @@ public abstract class VaadinService implements Serializable {
private void onVaadinSessionStarted(VaadinRequest request,
VaadinSession session) throws ServiceException {
- // for now, use the session error handler; in the future, could have an
- // API for using some other handler for session init and destroy
- // listeners
-
- eventRouter.fireEvent(new SessionInitEvent(this, session, request),
- session.getErrorHandler());
+ SessionInitEvent event = new SessionInitEvent(this, session, request);
+ for (SessionInitListener listener : sessionInitListeners) {
+ try {
+ listener.sessionInit(event);
+ } catch (Exception e) {
+ /*
+ * for now, use the session error handler; in the future, could
+ * have an API for using some other handler for session init and
+ * destroy listeners
+ */
+ session.getErrorHandler().error(new ErrorEvent(e));
+ }
+ }
ServletPortletHelper.checkUiProviders(session, this);
}
@@ -1888,6 +1900,10 @@ public abstract class VaadinService implements Serializable {
/**
* Adds a service destroy listener that gets notified when this service is
* destroyed.
+ * <p>
+ * The listeners may be invoked in a non-deterministic order. In particular,
+ * it is not guaranteed that listeners will be invoked in the order they
+ * were added.
*
* @since 7.2
* @param listener
@@ -1900,8 +1916,8 @@ public abstract class VaadinService implements Serializable {
*/
public Registration addServiceDestroyListener(
ServiceDestroyListener listener) {
- return eventRouter.addListener(ServiceDestroyEvent.class, listener,
- SERVICE_DESTROY_METHOD);
+ serviceDestroyListeners.add(listener);
+ return () -> serviceDestroyListeners.remove(listener);
}
/**
@@ -1917,8 +1933,7 @@ public abstract class VaadinService implements Serializable {
*/
@Deprecated
public void removeServiceDestroyListener(ServiceDestroyListener listener) {
- eventRouter.removeListener(ServiceDestroyEvent.class, listener,
- SERVICE_DESTROY_METHOD);
+ serviceDestroyListeners.remove(serviceDestroyListeners);
}
/**
@@ -1933,7 +1948,9 @@ public abstract class VaadinService implements Serializable {
* @since 7.2
*/
public void destroy() {
- eventRouter.fireEvent(new ServiceDestroyEvent(this));
+ ServiceDestroyEvent event = new ServiceDestroyEvent(this);
+ serviceDestroyListeners
+ .forEach(listener -> listener.serviceDestroy(event));
}
/**