Issue #11548 - Replication as jetty-ee10-webapp testcase (#11550)

* Issue #11548 - Replication as jetty-ee10-webapp testcase
* Correct order of WebAppContext.stop

---------

Co-authored-by: Jan Bartel <janb@webtide.com>
Co-authored-by: gregw <gregw@webtide.com>
This commit is contained in:
Joakim Erdfelt 2024-03-26 07:04:49 -05:00 committed by GitHub
parent 5ca620e0e6
commit 9defd5d416
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 119 additions and 2 deletions

View File

@ -771,14 +771,17 @@ public class ContextHandler extends Handler.Wrapper implements Attributes, Alias
protected void doStop() throws Exception
{
_context.call(super::doStop, null);
cleanupAfterStop();
_tempDirectoryCreated = false;
}
protected void cleanupAfterStop() throws Exception
{
File tempDirectory = getTempDirectory();
// if we're not persisting the temp dir contents delete it
if (tempDirectory != null && tempDirectory.exists() && !isTempDirectoryPersistent())
IO.delete(tempDirectory);
_tempDirectoryCreated = false;
}
public boolean checkVirtualHost(Request request)

View File

@ -50,6 +50,7 @@ import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Deployable;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.ExceptionUtil;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.StringUtil;
@ -1228,6 +1229,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
protected void stopContext() throws Exception
{
stopWebapp();
try
{
for (int i = _configurations.size(); i-- > 0; )
@ -1250,6 +1252,8 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
}
_unavailableException = null;
super.cleanupAfterStop();
}
}
@ -1271,6 +1275,16 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
super.stopContext();
}
/**
* Prevent the temp directory from being deleted during the normal stop sequence, and require that
* {@link ContextHandler#cleanupAfterStop()} is explicitly called after the webapp classloader is closed
*/
@Override
protected void cleanupAfterStop() throws Exception
{
//intentionally left blank
}
@Override
public Set<String> setServletSecurity(Dynamic registration, ServletSecurityElement servletSecurityElement)
{

View File

@ -14,12 +14,14 @@
package org.eclipse.jetty.ee10.webapp;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
@ -56,6 +58,7 @@ import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.resource.FileSystemPool;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.AfterEach;
@ -829,6 +832,99 @@ public class WebAppContextTest
assertThat("URL[0]", urls[0].toURI(), is(extLibs.toUri()));
}
@Test
public void testRestartWebApp(WorkDir workDir) throws Exception
{
Server server = newServer();
// Create war
Path tempDir = workDir.getEmptyPathDir();
Path testWebappDir = MavenPaths.projectBase().resolve("src/test/webapp");
assertTrue(Files.exists(testWebappDir));
Path warFile = tempDir.resolve("demo.war");
Map<String, String> env = new HashMap<>();
env.put("create", "true");
URI uri = URI.create("jar:" + warFile.toUri().toASCIIString());
// Use ZipFS so that we can create paths that are just "/"
try (FileSystem zipfs = FileSystems.newFileSystem(uri, env))
{
Path root = zipfs.getPath("/");
IO.copyDir(testWebappDir, root);
}
// Create WebAppContext
WebAppContext context = new WebAppContext();
ResourceFactory resourceFactory = context.getResourceFactory();
Resource warResource = resourceFactory.newResource(warFile);
context.setContextPath("/");
context.setWarResource(warResource);
context.setExtractWAR(true);
server.setHandler(context);
server.start();
// Should not have failed the start of the WebAppContext
assertTrue(context.isAvailable(), "WebAppContext should be available");
// Test WebAppClassLoader contents for expected directory reference
List<String> actualRefs = getWebAppClassLoaderUrlRefs(context);
String[] expectedRefs = new String[]{
"/webapp/WEB-INF/classes/",
"/webapp/WEB-INF/lib/acme.jar!/",
"/webapp/WEB-INF/lib/alpha.jar!/",
"/webapp/WEB-INF/lib/omega.jar!/"
};
assertThat("URLs (sub) refs", actualRefs, containsInAnyOrder(expectedRefs));
// Simulate a reload
LOG.info("Stopping Initial Context");
context.stop();
LOG.info("Stopped Initial Context - waiting 2 seconds");
Thread.sleep(2000);
LOG.info("Touch War File: {}", warFile);
touch(warFile);
LOG.info("ReStarting Context");
context.start();
actualRefs = getWebAppClassLoaderUrlRefs(context);
expectedRefs = new String[]{
"/webapp/WEB-INF/classes/",
"/webapp/WEB-INF/lib/acme.jar!/",
"/webapp/WEB-INF/lib/alpha.jar!/",
"/webapp/WEB-INF/lib/omega.jar!/"
};
assertThat("URLs (sub) refs", actualRefs, containsInAnyOrder(expectedRefs));
}
private void touch(Path path) throws IOException
{
FileTime now = FileTime.fromMillis(System.currentTimeMillis());
Files.setLastModifiedTime(path, now);
}
private List<String> getWebAppClassLoaderUrlRefs(WebAppContext context)
{
ClassLoader contextClassLoader = context.getClassLoader();
assertThat(contextClassLoader, instanceOf(WebAppClassLoader.class));
WebAppClassLoader webAppClassLoader = (WebAppClassLoader)contextClassLoader;
String webappTempDir = context.getTempDirectory().toString();
List<String> actualRefs = new ArrayList<>();
URL[] urls = webAppClassLoader.getURLs();
for (URL url: urls)
{
String ref = url.toExternalForm();
int idx = ref.indexOf(webappTempDir);
// strip temp directory from URL (to make test easier to write)
if (idx >= 0)
ref = ref.substring(idx + webappTempDir.length());
actualRefs.add(ref);
}
return actualRefs;
}
@Test
public void testSetServerPropagation()
{

View File

@ -1,4 +1,8 @@
#org.eclipse.jetty.LEVEL=DEBUG
#org.eclipse.jetty.webapp.LEVEL=DEBUG
#org.eclipse.jetty.util.LEVEL=DEBUG
#org.eclipse.jetty.util.resource.LEVEL=DEBUG
#org.eclipse.jetty.util.IO.LEVEL=DEBUG
#org.eclipse.jetty.ee10.webapp.MetaInfConfiguration.LEVEL=DEBUG
#org.eclipse.jetty.ee10.webapp.WebInfConfiguration.LEVEL=DEBUG
#org.eclipse.jetty.util.PathWatcher.Noisy.LEVEL=OFF