From e83f012cf5f1388dcab9be427575a655769f75e9 Mon Sep 17 00:00:00 2001 From: Dos Moonen Date: Fri, 8 Sep 2017 15:05:14 +0200 Subject: [PATCH] Make Servlet related classes more welcoming to DI (#9658) VaadinCDIServlet can be made much cleaner when VaadinServletService can be proxied. This also enables specialization, interceptors and delegators. --- .../java/com/vaadin/server/VaadinService.java | 23 +++- .../java/com/vaadin/server/VaadinServlet.java | 113 ++++++++++++++---- .../vaadin/server/VaadinServletService.java | 23 +++- 3 files changed, 128 insertions(+), 31 deletions(-) diff --git a/server/src/main/java/com/vaadin/server/VaadinService.java b/server/src/main/java/com/vaadin/server/VaadinService.java index 27a6103211..ba54ad014f 100644 --- a/server/src/main/java/com/vaadin/server/VaadinService.java +++ b/server/src/main/java/com/vaadin/server/VaadinService.java @@ -114,6 +114,9 @@ public abstract class VaadinService implements Serializable { private static final String REQUEST_START_TIME_ATTRIBUTE = "requestStartTime"; + /** + * Should never be used directly, always use {@link #getDeploymentConfiguration()} + */ private final DeploymentConfiguration deploymentConfiguration; /* @@ -184,6 +187,20 @@ public abstract class VaadinService implements Serializable { } } + /** + * Creates a service. This method is for use by dependency injection + * frameworks etc. and must be followed by a call to + * {@link #setClassLoader(ClassLoader)} or {@link #setDefaultClassLoader()} + * before use. Furthermore {@link #getDeploymentConfiguration()} should be + * overridden (or otherwise intercepted) so it does not return + * null. + * + * @since + */ + protected VaadinService() { + this.deploymentConfiguration = null; + } + /** * Initializes this service. The service should be initialized before it is * used. @@ -357,7 +374,9 @@ public abstract class VaadinService implements Serializable { public abstract String getMimeType(String resourceName); /** - * Gets the deployment configuration. + * Gets the deployment configuration. Should be overridden (or otherwise + * intercepted) if the no-arg constructor is used in order to prevent + * NPEs. * * @return the deployment configuration */ @@ -1520,7 +1539,7 @@ public abstract class VaadinService implements Serializable { * Gets the filters which all resource dependencies are passed through * before being sent to the client for loading. * - * @see #initDependencyFilters() + * @see #initDependencyFilters(List) * * @since 8.1 * @return the dependency filters to pass resources dependencies through diff --git a/server/src/main/java/com/vaadin/server/VaadinServlet.java b/server/src/main/java/com/vaadin/server/VaadinServlet.java index b0ea6f87ec..0151d42b62 100644 --- a/server/src/main/java/com/vaadin/server/VaadinServlet.java +++ b/server/src/main/java/com/vaadin/server/VaadinServlet.java @@ -45,6 +45,7 @@ import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; +import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -200,32 +201,8 @@ public class VaadinServlet extends HttpServlet implements Constants { throws ServletException { CurrentInstance.clearAll(); super.init(servletConfig); - Properties initParameters = new Properties(); - - readUiFromEnclosingClass(initParameters); - - readConfigurationAnnotation(initParameters); - - // Read default parameters from server.xml - final ServletContext context = servletConfig.getServletContext(); - for (final Enumeration e = context.getInitParameterNames(); e - .hasMoreElements();) { - final String name = e.nextElement(); - initParameters.setProperty(name, context.getInitParameter(name)); - } - - // Override with application config from web.xml - for (final Enumeration e = servletConfig - .getInitParameterNames(); e.hasMoreElements();) { - final String name = e.nextElement(); - initParameters.setProperty(name, - servletConfig.getInitParameter(name)); - } - - DeploymentConfiguration deploymentConfiguration = createDeploymentConfiguration( - initParameters); try { - servletService = createServletService(deploymentConfiguration); + servletService = createServletService(); } catch (ServiceException e) { throw new ServletException("Could not initialize VaadinServlet", e); } @@ -321,11 +298,95 @@ public class VaadinServlet extends HttpServlet implements Constants { } } + /** + * Creates a deployment configuration to be used for the creation of a + * {@link VaadinService}. Intended to be used by dependency injection + * frameworks. + * + * @return the created deployment configuration + * + * @throws ServletException + * if construction of the {@link Properties} for + * {@link #createDeploymentConfiguration(Properties)} fails + * + * @since + */ + protected DeploymentConfiguration createDeploymentConfiguration() throws ServletException { + Properties initParameters = new Properties(); + + readUiFromEnclosingClass(initParameters); + + readConfigurationAnnotation(initParameters); + + // Read default parameters from server.xml + final ServletContext context = getServletConfig().getServletContext(); + for (final Enumeration e = context.getInitParameterNames(); e + .hasMoreElements();) { + final String name = e.nextElement(); + initParameters.setProperty(name, context.getInitParameter(name)); + } + + // Override with application config from web.xml + for (final Enumeration e = getServletConfig() + .getInitParameterNames(); e.hasMoreElements();) { + final String name = e.nextElement(); + initParameters.setProperty(name, + getServletConfig().getInitParameter(name)); + } + + return createDeploymentConfiguration(initParameters); + } + + /** + * Creates a deployment configuration to be used for the creation of a + * {@link VaadinService}. Override this if you want to override certain + * properties. + * + * @param initParameters + * the context-param and init-param values as properties + * @return the created deployment configuration + * + * @since 7.0.0 + */ protected DeploymentConfiguration createDeploymentConfiguration( Properties initParameters) { return new DefaultDeploymentConfiguration(getClass(), initParameters); } + /** + * Creates a vaadin servlet service. This method functions as a layer of + * indirection between {@link #init(ServletConfig)} and + * {@link #createServletService(DeploymentConfiguration)} so dependency + * injection frameworks can call {@link #createDeploymentConfiguration()} + * when creating a vaadin servlet service lazily. + * + * @return the created vaadin servlet service + * + * @throws ServletException + * if creating a deployment configuration fails + * @throws ServiceException + * if creating the vaadin servlet service fails + * + * @since + */ + protected VaadinServletService createServletService() + throws ServletException, ServiceException { + return createServletService(createDeploymentConfiguration()); + } + + /** + * Creates a vaadin servlet service. + * + * @param deploymentConfiguration + * the deployment configuration to be used + * + * @return the created vaadin servlet service + * + * @throws ServiceException + * if creating the vaadin servlet service fails + * + * @since 7.0.0 + */ protected VaadinServletService createServletService( DeploymentConfiguration deploymentConfiguration) throws ServiceException { @@ -471,7 +532,7 @@ public class VaadinServlet extends HttpServlet implements Constants { } /** - * Create a Vaadin request for a http servlet request. This method can be + * Creates a Vaadin request for a http servlet request. This method can be * overridden if the Vaadin request should have special properties. * * @param request diff --git a/server/src/main/java/com/vaadin/server/VaadinServletService.java b/server/src/main/java/com/vaadin/server/VaadinServletService.java index 4675f37340..42213f60d0 100644 --- a/server/src/main/java/com/vaadin/server/VaadinServletService.java +++ b/server/src/main/java/com/vaadin/server/VaadinServletService.java @@ -33,6 +33,10 @@ import com.vaadin.server.communication.ServletUIInitHandler; import com.vaadin.ui.UI; public class VaadinServletService extends VaadinService { + + /** + * Should never be used directly, always use {@link #getServlet()} + */ private final VaadinServlet servlet; public VaadinServletService(VaadinServlet servlet, @@ -42,6 +46,17 @@ public class VaadinServletService extends VaadinService { this.servlet = servlet; } + /** + * Creates a servlet service. This method is for use by dependency + * injection frameworks etc. {@link #getServlet()} should be overridden (or otherwise intercepted) + * so it does not return null. + * + * @since + */ + protected VaadinServletService() { + this.servlet = null; + } + @Override protected List createRequestHandlers() throws ServiceException { @@ -65,6 +80,8 @@ public class VaadinServletService extends VaadinService { /** * Retrieves a reference to the servlet associated with this service. + * Should be overridden (or otherwise intercepted) if the no-arg + * constructor is used to prevent NPEs. * * @return A reference to the VaadinServlet this service is using */ @@ -167,7 +184,7 @@ public class VaadinServletService extends VaadinService { @Override public File getBaseDirectory() { final String realPath = VaadinServlet - .getResourcePath(servlet.getServletContext(), "/"); + .getResourcePath(getServlet().getServletContext(), "/"); if (realPath == null) { return null; } @@ -226,12 +243,12 @@ public class VaadinServletService extends VaadinService { String resource) throws IOException { String filename = "/" + VaadinServlet.THEME_DIR_PATH + '/' + themeName + "/" + resource; - URL resourceUrl = servlet.findResourceURL(filename); + URL resourceUrl = getServlet().findResourceURL(filename); if (resourceUrl != null) { // security check: do not permit navigation out of the VAADIN // directory - if (!servlet.isAllowedVAADINResourceUrl(null, resourceUrl)) { + if (!getServlet().isAllowedVAADINResourceUrl(null, resourceUrl)) { throw new IOException(String.format( "Requested resource [{0}] not accessible in the VAADIN directory or access to it is forbidden.", filename)); -- 2.39.5