]> source.dussan.org Git - vaadin-framework.git/commitdiff
Change the way classloader for VaadinService is selected (fixes #11295)
authorMaciej Przepióra <matthew@vaadin.com>
Wed, 22 Oct 2014 12:28:15 +0000 (15:28 +0300)
committerSauli Tähkäpää <sauli@vaadin.com>
Mon, 10 Nov 2014 11:14:28 +0000 (13:14 +0200)
Change-Id: I2a25b4149f927ee7940edf596e8cebaaa48dcd0d

server/src/com/vaadin/server/Constants.java
server/src/com/vaadin/server/VaadinPortletService.java
server/src/com/vaadin/server/VaadinService.java
server/src/com/vaadin/server/VaadinServiceClassLoaderUtil.java [new file with mode: 0644]
server/src/com/vaadin/server/VaadinServletService.java
server/tests/src/com/vaadin/tests/server/CsrfTokenMissingTestServer.java
server/tests/src/com/vaadin/tests/server/TestClassesSerializable.java
server/tests/src/com/vaadin/tests/server/TestStreamVariableMapping.java

index 14113fda3c44114b00008d0c95886c2055734e23..5841bfac4de9e29743b6786b21bd01f4d5b81c17 100644 (file)
@@ -115,6 +115,15 @@ public interface Constants {
             + Constants.SERVLET_PARAMETER_LEGACY_PROPERTY_TOSTRING
             + ". Supported values are 'false','warning','true'";
 
+    static final String CANNOT_ACQUIRE_CLASSLOADER_SEVERE = "\n"
+            + "=================================================================\n"
+            + "Vaadin was unable to acquire class loader from servlet container\n"
+            + "to load your application classes. Setup appropriate security\n"
+            + "policy to allow invoking Thread.getContextClassLoader() from\n"
+            + "VaadinService if you're not using custom class loader.\n"
+            + "NullPointerExceptions will be thrown later."
+            + "=================================================================";
+
     static final String URL_PARAMETER_THEME = "theme";
 
     static final String SERVLET_PARAMETER_PRODUCTION_MODE = "productionMode";
@@ -164,4 +173,5 @@ public interface Constants {
     static final String PORTAL_PARAMETER_VAADIN_THEME = "vaadin.theme";
 
     static final String PORTLET_CONTEXT = "PORTLET_CONTEXT";
+
 }
index c6d9b8e46afaba21dd11850aa2b5fc11961f7cde..9f467401f47d183042068ffcb907335cd90125c3 100644 (file)
@@ -46,16 +46,6 @@ public class VaadinPortletService extends VaadinService {
             throws ServiceException {
         super(deploymentConfiguration);
         this.portlet = portlet;
-
-        // Set default class loader if not already set
-        if (getClassLoader() == null) {
-            /*
-             * The portlet is most likely to be loaded with a class loader
-             * specific to the application instead of some generic system class
-             * loader that loads the Vaadin classes.
-             */
-            setClassLoader(portlet.getClass().getClassLoader());
-        }
     }
 
     @Override
@@ -164,7 +154,7 @@ public class VaadinPortletService extends VaadinService {
 
         if (Constants.PORTLET_CONTEXT.equals(staticFileLocation)) {
             return request.getContextPath();
-        } else{
+        } else {
             return trimTrailingSlashes(staticFileLocation);
         }
     }
index 0f2daa424203bf6662167e94db12d31b2a2b3953..b74e8c44ffb885bb8d684b73fac42ad14a07e6ef 100644 (file)
@@ -168,6 +168,10 @@ public abstract class VaadinService implements Serializable {
                                 + classLoaderName, e);
             }
         }
+
+        if (getClassLoader() == null) {
+            setDefaultClassLoader();
+        }
     }
 
     /**
@@ -1855,4 +1859,25 @@ public abstract class VaadinService implements Serializable {
         eventRouter.fireEvent(new ServiceDestroyEvent(this));
     }
 
+    /**
+     * Tries to acquire default class loader and sets it as a class loader for
+     * this {@link VaadinService} if found. If current security policy disallows
+     * acquiring class loader instance it will log a message and re-throw
+     * {@link SecurityException}
+     * 
+     * @throws SecurityException
+     *             If current security policy forbids acquiring class loader
+     * 
+     * @since
+     */
+    protected void setDefaultClassLoader() {
+        try {
+            setClassLoader(VaadinServiceClassLoaderUtil
+                    .findDefaultClassLoader());
+        } catch (SecurityException e) {
+            getLogger().log(Level.SEVERE,
+                    Constants.CANNOT_ACQUIRE_CLASSLOADER_SEVERE, e);
+            throw e;
+        }
+    }
 }
diff --git a/server/src/com/vaadin/server/VaadinServiceClassLoaderUtil.java b/server/src/com/vaadin/server/VaadinServiceClassLoaderUtil.java
new file mode 100644 (file)
index 0000000..c9e73e2
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2000-2014 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;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Utility class used by {@link VaadinService#setDefaultClassLoader()}.
+ * 
+ * @since
+ * @author Vaadin Ltd
+ */
+class VaadinServiceClassLoaderUtil {
+
+    private static class GetClassLoaderPrivilegedAction implements
+            PrivilegedAction<ClassLoader> {
+        @Override
+        public ClassLoader run() {
+            return Thread.currentThread().getContextClassLoader();
+        }
+    }
+
+    /**
+     * Called by {@link VaadinService#setDefaultClassLoader()} to acquire
+     * appropriate class loader to load application's classes (e.g. UI). Calls
+     * should be guarded by try/catch block to catch SecurityException and log
+     * appropriate message. The code for this method is modeled after
+     * recommendations laid out by JEE 5 specification sections EE.6.2.4.7 and
+     * EE.8.2.5
+     * 
+     * @return Instance of {@link ClassLoader} that should be used by this
+     *         instance of {@link VaadinService}
+     * @throws SecurityException
+     *             if current security policy doesn't allow acquiring current
+     *             thread's context class loader
+     */
+    static protected ClassLoader findDefaultClassLoader()
+            throws SecurityException {
+        return AccessController
+                .doPrivileged(new VaadinServiceClassLoaderUtil.GetClassLoaderPrivilegedAction());
+    }
+
+}
index a4ff3943c9491ecd3629a391fdba3a36a60e5dc6..0b431306e02aa081f0851fa4e1185765637b1dfc 100644 (file)
@@ -51,16 +51,6 @@ public class VaadinServletService extends VaadinService {
             throws ServiceException {
         super(deploymentConfiguration);
         this.servlet = servlet;
-
-        // Set default class loader if not already set
-        if (getClassLoader() == null) {
-            /*
-             * The servlet is most likely to be loaded with a class loader
-             * specific to the application instead of some generic system class
-             * loader that loads the Vaadin classes.
-             */
-            setClassLoader(servlet.getClass().getClassLoader());
-        }
     }
 
     private static boolean checkAtmosphereSupport() {
index 30f1c85fef0be3f7a02cde914ebcce34183a5f78..59bb71290785719581e282aa8d139e43d5c207be 100644 (file)
@@ -19,6 +19,7 @@ import java.util.UUID;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 
 import org.easymock.EasyMock;
@@ -27,6 +28,7 @@ import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
+import com.vaadin.server.MockServletConfig;
 import com.vaadin.server.ServiceException;
 import com.vaadin.server.VaadinService;
 import com.vaadin.server.VaadinServlet;
@@ -38,6 +40,7 @@ import com.vaadin.shared.ApplicationConstants;
 import com.vaadin.tests.util.AlwaysLockedVaadinSession;
 import com.vaadin.tests.util.MockDeploymentConfiguration;
 
+
 /**
  * Test the actual csrf token validation by the server.
  * 
@@ -62,10 +65,12 @@ public class CsrfTokenMissingTestServer {
 
     /**
      * Initialize the mock servlet and other stuff for our tests.
+     * 
      */
     @Before
-    public void initMockStuff() throws ServiceException {
+    public void initMockStuff() throws ServiceException, ServletException {
         mockServlet = new VaadinServlet();
+        mockServlet.init(new MockServletConfig());
         mockDeploymentConfiguration = new MockDeploymentConfiguration();
 
         mockService = new VaadinServletService(mockServlet,
index 63f79504ffb0a9aa657d8fcf2d6d2a361fe11264..10cc7634fdd85239195a13d62170fa6548545b10 100644 (file)
@@ -47,6 +47,8 @@ public class TestClassesSerializable extends TestCase {
             "com\\.vaadin\\.server\\.MockServletConfig", //
             "com\\.vaadin\\.server\\.MockServletContext", //
             "com\\.vaadin\\.server\\.Constants", //
+            "com\\.vaadin\\.server\\.VaadinServiceClassLoaderUtil", //
+            "com\\.vaadin\\.server\\.VaadinServiceClassLoaderUtil\\$GetClassLoaderPrivilegedAction", //
             "com\\.vaadin\\.server\\.communication\\.FileUploadHandler\\$SimpleMultiPartInputStream", //
             "com\\.vaadin\\.server\\.communication\\.PushRequestHandler.*",
             "com\\.vaadin\\.server\\.communication\\.PushHandler.*", // PushHandler
index fcc54a989da06b6ed88000542b256bd3856cd87a..b2faca1ed68e9b5c1722b6152f579631fa028525 100644 (file)
@@ -80,11 +80,11 @@ public class TestStreamVariableMapping extends TestCase {
     private LegacyCommunicationManager createCommunicationManager()
             throws Exception {
         VaadinServlet servlet = new VaadinServlet();
+        servlet.init(new MockServletConfig());
         VaadinServletService vss = new VaadinServletService(servlet,
                 new MockDeploymentConfiguration());
         servlet.init(new MockServletConfig());
         return new LegacyCommunicationManager(
                 new AlwaysLockedVaadinSession(vss));
     }
-
 }