Skip to content

Commit

Permalink
chore: add internal classes to access classloader and init context (#…
Browse files Browse the repository at this point in the history
…9618)

* chore: add internal classes to access classloader and init context

related to #9601 : needed to restore OSGi resource provider
  • Loading branch information
Denis authored Dec 9, 2020
1 parent 89190a5 commit f0a6e84
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 7 deletions.
3 changes: 1 addition & 2 deletions flow-server/bnd.bnd
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-License: http://www.apache.org/licenses/LICENSE-2.0
Import-Package: org.atmosphere*;resolution:=optional;version='${atmosphere.runtime.version}',\
org.apache.http*;resolution:=optional;,*
Export-Package: com.vaadin.flow.client,\
!com.vaadin.flow.push*, com.vaadin.flow*;-noimport:=true
Export-Package: !com.vaadin.flow.push*, com.vaadin.flow*;-noimport:=true
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2000-2020 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.flow.internal;

import com.vaadin.flow.server.VaadinContext;

/**
* Allows to access the web application classloader.
* <p>
* The functionality is intended to internal usage only. The implementation of
* this interface may be set as an attribute in {@link VaadinContext} so that
* the classloader may be used in other place where {@link VaadinContext} is
* available.
*
* @author Vaadin Ltd
* @since
*
*/
@FunctionalInterface
public interface ApplicationClassLoaderAccess {

/**
* Gets the web application classloader.
*
* @return the web application classloader.
*/
ClassLoader getClassloader();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright 2000-2020 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.flow.internal;

import javax.servlet.ServletContextListener;

import com.vaadin.flow.server.VaadinContext;
import com.vaadin.flow.server.VaadinServlet;

/**
* Allows to run initialization of {@link VaadinContext} which for some reasons
* may not be done via {@link ServletContextListener}.
* <p>
* The functionality is intended to internal usage only. The implementation of
* this interface may be available as an attribute in a {@link VaadinContext}.
* In the latter case {@link VaadinServlet#init()} method will run
* {@link #initialize(VaadinContext)} method.
*
* @author Vaadin Ltd
* @since
*
*/
@FunctionalInterface
public interface VaadinContextInitializer {

/**
* Initializes the Vaadin {@code context}.
*
* @param context
* the Vaadin context instance
*/
void initialize(VaadinContext context);

}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@
import com.vaadin.flow.component.UI;
import com.vaadin.flow.di.Lookup;
import com.vaadin.flow.function.DeploymentConfiguration;
import com.vaadin.flow.internal.ApplicationClassLoaderAccess;
import com.vaadin.flow.internal.CurrentInstance;
import com.vaadin.flow.internal.VaadinContextInitializer;
import com.vaadin.flow.server.HandlerHelper.RequestType;
import com.vaadin.flow.shared.JsonConstants;

Expand Down Expand Up @@ -84,8 +86,11 @@ public void init(ServletConfig servletConfig) throws ServletException {
* its "init" method is called from the {@code
* ServletContextListener} with the same ServletConfig instance.
*/
VaadinServletContext vaadinServletContext = null;
if (getServletConfig() == null) {
super.init(servletConfig);

vaadinServletContext = initializeContext();
}

if (getServletConfig() != servletConfig) {
Expand All @@ -94,11 +99,13 @@ public void init(ServletConfig servletConfig) throws ServletException {
+ "instance which has been used for the initial method call");
}

ServletContext servletContext = getServletConfig()
.getServletContext();
if (servletService != null
|| new VaadinServletContext(servletContext)
.getAttribute(Lookup.class) == null) {
if (vaadinServletContext == null) {
vaadinServletContext = new VaadinServletContext(
getServletConfig().getServletContext());
}

if (servletService != null || vaadinServletContext
.getAttribute(Lookup.class) == null) {
return;
}

Expand Down Expand Up @@ -513,4 +520,22 @@ public void destroy() {
getService().destroy();
}

private VaadinServletContext initializeContext() {
ServletContext servletContext = getServletConfig().getServletContext();
VaadinServletContext vaadinServletContext = new VaadinServletContext(
servletContext);
// ensure the web application classloader is available via context
ApplicationClassLoaderAccess access = () -> servletContext
.getClassLoader();
vaadinServletContext.getAttribute(ApplicationClassLoaderAccess.class,
() -> access);

VaadinContextInitializer initializer = vaadinServletContext
.getAttribute(VaadinContextInitializer.class);
if (initializer != null) {
initializer.initialize(vaadinServletContext);
}
return vaadinServletContext;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,14 @@
import net.jcip.annotations.NotThreadSafe;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;

import com.vaadin.flow.component.UI;
import com.vaadin.flow.di.Lookup;
import com.vaadin.flow.internal.ApplicationClassLoaderAccess;
import com.vaadin.flow.internal.CurrentInstance;
import com.vaadin.flow.internal.VaadinContextInitializer;

@NotThreadSafe
public class VaadinServletTest {
Expand Down Expand Up @@ -222,6 +225,48 @@ public void init() throws ServletException {
}
}

@Test
public void init_appClassLoaderIsSet() throws ServletException {
VaadinServlet servlet = new VaadinServlet();

ServletConfig config = mockConfig();
ServletContext servletContext = config.getServletContext();
ClassLoader loader = Mockito.mock(ClassLoader.class);
Mockito.when(servletContext.getClassLoader()).thenReturn(loader);
servlet.init(config);

ArgumentCaptor<ApplicationClassLoaderAccess> captor = ArgumentCaptor
.forClass(ApplicationClassLoaderAccess.class);
Mockito.verify(servletContext).setAttribute(
Mockito.eq(ApplicationClassLoaderAccess.class.getName()),
captor.capture());

ApplicationClassLoaderAccess access = captor.getValue();
Assert.assertSame(loader, access.getClassloader());
}

@Test
public void init_contextInitializationIsExecuted() throws ServletException {
VaadinServlet servlet = new VaadinServlet();

ServletConfig config = mockConfig();
ServletContext servletContext = config.getServletContext();
ClassLoader loader = Mockito.mock(ClassLoader.class);

VaadinContextInitializer initializer = Mockito
.mock(VaadinContextInitializer.class);

Mockito.when(servletContext
.getAttribute(VaadinContextInitializer.class.getName()))
.thenReturn(initializer);

Mockito.when(servletContext.getClassLoader()).thenReturn(loader);
servlet.init(config);

Mockito.verify(initializer)
.initialize(Mockito.any(VaadinContext.class));
}

private ServletConfig mockConfig() {
ServletConfig config = Mockito.mock(ServletConfig.class);
ServletContext context = Mockito.mock(ServletContext.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ protected Stream<String> getExcludedPatterns() {
"com\\.vaadin\\.flow\\.osgi\\.support\\..*",
"com\\.vaadin\\.flow\\.server\\.osgi\\..*",

"com\\.vaadin\\.flow\\.internal\\.VaadinContextInitializer",
"com\\.vaadin\\.flow\\.internal\\.ApplicationClassLoaderAccess",
"com\\.vaadin\\.flow\\.data\\.provider\\.InMemoryDataProviderHelpers",
"com\\.vaadin\\.flow\\.di\\.InstantiatorFactory",
"com\\.vaadin\\.flow\\.di\\.Lookup(\\$.*)?",
Expand Down

0 comments on commit f0a6e84

Please sign in to comment.