From c9db2c96200dda3b44e12325af6aa1c8ea0744a8 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Mon, 14 Jun 2010 22:19:08 +0000 Subject: [PATCH] 311550 The WebAppProvider should allow setTempDirectory git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@2000 7e9141cc-0065-0410-87d8-b60c137991c4 --- VERSION.txt | 3 +- .../deploy/providers/WebAppProvider.java | 68 ++++++++++-- .../deploy/providers/WebAppProviderTest.java | 76 +++++++++++++ .../jetty/deploy/test/XmlConfiguredJetty.java | 31 ++++-- .../src/test/resources/jetty-deploy-wars.xml | 29 +++++ .../eclipse/jetty/webapp/WebAppContext.java | 3 +- .../jetty/webapp/WebInfConfiguration.java | 102 ++++++++++-------- 7 files changed, 247 insertions(+), 65 deletions(-) create mode 100644 jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/WebAppProviderTest.java create mode 100644 jetty-deploy/src/test/resources/jetty-deploy-wars.xml diff --git a/VERSION.txt b/VERSION.txt index 838d8e8dff7..c80a6bbae89 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1,4 +1,5 @@ jetty-7.1.5-SNAPSHOT + + 311550 The WebAppProvider should allow setTempDirectory + 316449 Websocket disconnect fix jetty-7.1.4.v20100610 @@ -27,7 +28,7 @@ jetty-7.1.4.v20100610 + 316334 Breaking change on org.eclipse.jetty.client.HttpExchange + 316399 Debug output in MultiPartFilter + 316413 Restarting webapp for packed war fails - + 316557 OSGi HttpService is not available because context handlers files are not deployed + + 316557 OSGi HttpService failure due to undeployed context handlers + JETTY-547 Delay close after shutdown until request read + JETTY-1231 Support context request log handler diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java index 7a1d20404c0..417ff6cc33f 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java @@ -12,6 +12,7 @@ import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.webapp.WebAppContext; +import org.eclipse.jetty.webapp.WebInfConfiguration; /* ------------------------------------------------------------ */ @@ -27,6 +28,7 @@ public class WebAppProvider extends ScanningAppProvider private boolean _parentLoaderPriority = false; private String _defaultsDescriptor; private Filter _filter; + private File _tempDirectory; private String[] _configurationClasses; private static class Filter implements FilenameFilter @@ -36,13 +38,17 @@ public class WebAppProvider extends ScanningAppProvider public boolean accept(File dir, String name) { if (!dir.exists()) + { return false; + } String lowername = name.toLowerCase(); File file = new File(dir,name); // is it not a directory and not a war ? if (!file.isDirectory() && !lowername.endsWith(".war")) + { return false; + } // is it a directory for an existing war file? if (file.isDirectory() && @@ -57,7 +63,9 @@ public class WebAppProvider extends ScanningAppProvider { String context=name; if (!file.isDirectory()) + { context=context.substring(0,context.length()-4); + } if (new File(_contexts,context+".xml").exists() || new File(_contexts,context+".XML").exists() ) { @@ -112,7 +120,7 @@ public class WebAppProvider extends ScanningAppProvider { _parentLoaderPriority = parentLoaderPriority; } - + /* ------------------------------------------------------------ */ /** Get the defaultsDescriptor. * @return the defaultsDescriptor @@ -156,7 +164,7 @@ public class WebAppProvider extends ScanningAppProvider } catch (MalformedURLException e) { - e.printStackTrace(); + throw new RuntimeException(e); } catch (IOException e) { @@ -183,6 +191,27 @@ public class WebAppProvider extends ScanningAppProvider return _configurationClasses; } + /** + * Set the Work directory where unpacked WAR files are managed from. + *

+ * Default is the same as the java.io.tmpdir System Property. + * + * @param directory the new work directory + */ + public void setTempDir(File directory) + { + _tempDirectory = directory; + } + + /** + * Get the user supplied Work Directory. + * + * @return the user supplied work directory (null if user has not set Temp Directory yet) + */ + public File getTempDir() + { + return _tempDirectory; + } /* ------------------------------------------------------------ */ public ContextHandler createContextHandler(final App app) throws Exception @@ -203,31 +232,54 @@ public class WebAppProvider extends ScanningAppProvider // Context Path is the same as the archive. context = context.substring(0,context.length() - 4); } - else + else + { throw new IllegalStateException("unable to create ContextHandler for "+app); + } // special case of archive (or dir) named "root" is / context - if (context.equalsIgnoreCase("root") || context.equalsIgnoreCase("root/")) + if (context.equalsIgnoreCase("root") || context.equalsIgnoreCase("root/")) + { context = URIUtil.SLASH; + } // Ensure "/" is Prepended to all context paths. - if (context.charAt(0) != '/') + if (context.charAt(0) != '/') + { context = "/" + context; + } // Ensure "/" is Not Trailing in context paths. - if (context.endsWith("/") && context.length() > 0) + if (context.endsWith("/") && context.length() > 0) + { context = context.substring(0,context.length() - 1); + } WebAppContext wah = new WebAppContext(); wah.setContextPath(context); wah.setWar(file.getAbsolutePath()); - if (_defaultsDescriptor != null) + if (_defaultsDescriptor != null) + { wah.setDefaultsDescriptor(_defaultsDescriptor); + } wah.setExtractWAR(_extractWars); wah.setParentLoaderPriority(_parentLoaderPriority); - if (_configurationClasses != null) + if (_configurationClasses != null) + { wah.setConfigurationClasses(_configurationClasses); + } + if (_tempDirectory != null) + { + /* Since the Temp Dir is really a context base temp directory, + * Lets set the Temp Directory in a way similar to how WebInfConfiguration does it, + * instead of setting the + * WebAppContext.setTempDirectory(File). + * If we used .setTempDirectory(File) all webapps will wind up in the + * same temp / work directory, overwriting each others work. + */ + wah.setAttribute(WebAppContext.BASETEMPDIR,_tempDirectory); + } return wah; } diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/WebAppProviderTest.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/WebAppProviderTest.java new file mode 100644 index 00000000000..8fc7cb5930d --- /dev/null +++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/WebAppProviderTest.java @@ -0,0 +1,76 @@ +package org.eclipse.jetty.deploy.providers; + +import java.io.File; + +import org.eclipse.jetty.deploy.test.XmlConfiguredJetty; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class WebAppProviderTest +{ + private static XmlConfiguredJetty jetty; + + @BeforeClass + public static void setupEnvironment() throws Exception + { + jetty = new XmlConfiguredJetty(); + jetty.addConfiguration("jetty.xml"); + jetty.addConfiguration("jetty-deploy-wars.xml"); + + // Setup initial context + jetty.copyContext("foo.xml","foo.xml"); + jetty.copyWebapp("foo-webapp-1.war","foo.war"); + + // Should not throw an Exception + jetty.load(); + + // Start it + jetty.start(); + } + + @AfterClass + public static void teardownEnvironment() throws Exception + { + // Stop jetty. + jetty.stop(); + } + + @Test + public void testStartupContext() + { + // Check Server for Handlers + jetty.printHandlers(System.out); + jetty.assertWebAppContextsExists("/foo"); + + File workDir = jetty.getJettyDir("workish"); + + // Test for regressions + assertDirNotExists("root of work directory",workDir,"webinf"); + assertDirNotExists("root of work directory",workDir,"jsp"); + + // Test for correct behavior + Assert.assertTrue("Should have generated directory in work directory: " + workDir,hasJettyGeneratedPath(workDir,"foo.war")); + } + + private static boolean hasJettyGeneratedPath(File basedir, String expectedWarFilename) + { + for (File path : basedir.listFiles()) + { + if (path.exists() && path.isDirectory() && path.getName().startsWith("Jetty_") && path.getName().contains(expectedWarFilename)) + { + System.out.println("Found expected generated directory: " + path); + return true; + } + } + + return false; + } + + public static void assertDirNotExists(String msg, File workDir, String subdir) + { + File dir = new File(workDir,subdir); + Assert.assertFalse("Should not have " + subdir + " in " + msg + " - " + workDir,dir.exists()); + } +} diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/test/XmlConfiguredJetty.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/test/XmlConfiguredJetty.java index 954c776397e..6ff072728a5 100644 --- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/test/XmlConfiguredJetty.java +++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/test/XmlConfiguredJetty.java @@ -59,7 +59,7 @@ public class XmlConfiguredJetty { this(MavenTestingUtils.getTestID()); } - + public XmlConfiguredJetty(String testname) throws IOException { xmlConfigurations = new ArrayList(); @@ -69,9 +69,10 @@ public class XmlConfiguredJetty // Ensure we have a new (pristene) directory to work with. int idx = 0; jettyHome = new File(jettyHomeBase + "#" + idx); - while(jettyHome.exists()) { - idx++; - jettyHome = new File(jettyHomeBase + "#" + idx); + while (jettyHome.exists()) + { + idx++; + jettyHome = new File(jettyHomeBase + "#" + idx); } deleteContents(jettyHome); // Prepare Jetty.Home (Test) dir @@ -91,23 +92,37 @@ public class XmlConfiguredJetty deleteContents(contextsDir); } contextsDir.mkdirs(); + File webappsDir = new File(jettyHome,"webapps"); if (webappsDir.exists()) { deleteContents(webappsDir); } webappsDir.mkdirs(); + File tmpDir = new File(jettyHome,"tmp"); + if (tmpDir.exists()) + { + deleteContents(tmpDir); + } tmpDir.mkdirs(); + File workishDir = new File(jettyHome,"workish"); + if (workishDir.exists()) + { + deleteContents(workishDir); + } + workishDir.mkdirs(); + // Setup properties System.setProperty("java.io.tmpdir",tmpDir.getAbsolutePath()); properties.setProperty("jetty.home",jettyHome.getAbsolutePath()); System.setProperty("jetty.home",jettyHome.getAbsolutePath()); properties.setProperty("test.basedir",MavenTestingUtils.getBasedir().getAbsolutePath()); properties.setProperty("test.resourcesdir",MavenTestingUtils.getTestResourcesDir().getAbsolutePath()); - properties.setProperty("test.webapps",webappsDir.getAbsolutePath()); + properties.setProperty("test.webapps",workishDir.getAbsolutePath()); properties.setProperty("test.targetdir",MavenTestingUtils.getTargetDir().getAbsolutePath()); + properties.setProperty("test.workdir",workishDir.getAbsolutePath()); // Write out configuration for use by ConfigurationManager. File testConfig = MavenTestingUtils.getTargetFile("xml-configured-jetty.properties"); @@ -238,11 +253,11 @@ public class XmlConfiguredJetty private void deleteContents(File dir) { System.out.printf("Delete (dir) %s/%n",dir); - if(!dir.exists()) + if (!dir.exists()) { - return; + return; } - + for (File file : dir.listFiles()) { // Safety measure. only recursively delete within target directory. diff --git a/jetty-deploy/src/test/resources/jetty-deploy-wars.xml b/jetty-deploy/src/test/resources/jetty-deploy-wars.xml new file mode 100644 index 00000000000..f336584c667 --- /dev/null +++ b/jetty-deploy/src/test/resources/jetty-deploy-wars.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + /webapps + 1 + /workish + + + + + + + + + diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java index fb8ede6f401..e3abd2df9a7 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java @@ -20,9 +20,7 @@ import java.net.URL; import java.security.PermissionCollection; import java.util.EventListener; import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.jar.JarFile; import javax.servlet.http.HttpSessionActivationListener; import javax.servlet.http.HttpSessionAttributeListener; @@ -65,6 +63,7 @@ import org.eclipse.jetty.util.resource.ResourceCollection; public class WebAppContext extends ServletContextHandler { public static final String TEMPDIR = "javax.servlet.context.tempdir"; + public static final String BASETEMPDIR = "org.eclipse.jetty.webapp.basetempdir"; public final static String WEB_DEFAULTS_XML="org/eclipse/jetty/webapp/webdefault.xml"; public final static String ERROR_PAGE="org.eclipse.jetty.server.error_page"; public final static String SERVER_CONFIG = "org.eclipse.jetty.webapp.configuration"; diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java index 37c663715a6..cdf896c99dd 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java @@ -221,61 +221,47 @@ public class WebInfConfiguration implements Configuration { //If a tmp directory is already set, we're done File tmpDir = context.getTempDirectory(); - if (tmpDir!=null && tmpDir.isDirectory() && tmpDir.canWrite()) - return; //Already have a suitable tmp dir configured + if (tmpDir != null && tmpDir.isDirectory() && tmpDir.canWrite()) + { + return; // Already have a suitable tmp dir configured + } - //None configured, try and come up with one - //First ... see if one is configured in a context attribute - //either as a File or name of a file - Object t = context.getAttribute(WebAppContext.TEMPDIR); - if (t != null) + // No temp directory configured, try to establish one. + // First we check the context specific, javax.servlet specified, temp directory attribute + File servletTmpDir = asFile(context.getAttribute(WebAppContext.TEMPDIR)); + if (servletTmpDir != null && servletTmpDir.isDirectory() && servletTmpDir.canWrite()) { - //Is it a File? - if (t instanceof File) - { - tmpDir=(File)t; - if (tmpDir.isDirectory() && tmpDir.canWrite()) - { - context.setTempDirectory(tmpDir); - return; - } - } - // The context attribute specified a name not a File - if (t instanceof String) - { - try - { - tmpDir=new File((String)t); - - if (tmpDir.isDirectory() && tmpDir.canWrite()) - { - context.setAttribute(context.TEMPDIR,tmpDir); - context.setTempDirectory(tmpDir); - return; - } - } - catch(Exception e) - { - Log.warn(Log.EXCEPTION,e); - } - } + // Use as tmpDir + tmpDir = servletTmpDir; + // Ensure Attribute has File object + context.setAttribute(WebAppContext.TEMPDIR,tmpDir); + // Set as TempDir in context. + context.setTempDirectory(tmpDir); + return; } - // Second ... make a tmp directory, in a work directory if one exists - String temp = getCanonicalNameForWebAppTmpDir(context); - try { - //Put the tmp dir in the work directory if we had one + // Put the tmp dir in the work directory if we had one File work = new File(System.getProperty("jetty.home"),"work"); - if (!work.exists() || !work.canWrite() || !work.isDirectory()) - work = null; - - if (work!=null) + if (work.exists() && work.canWrite() && work.isDirectory()) + { makeTempDirectory(work, context, false); //make a tmp dir inside work, don't delete if it exists + } else - makeTempDirectory(new File(System.getProperty("java.io.tmpdir")), context, true); //make a tmpdir, delete if it already exists + { + File baseTemp = asFile(context.getAttribute(WebAppContext.BASETEMPDIR)); + if (baseTemp != null && baseTemp.isDirectory() && baseTemp.canWrite()) + { + // Use baseTemp directory (allow the funky Jetty_0_0_0_0.. subdirectory logic to kick in + makeTempDirectory(baseTemp,context,false); + } + else + { + makeTempDirectory(new File(System.getProperty("java.io.tmpdir")),context,true); //make a tmpdir, delete if it already exists + } + } } catch(Exception e) { @@ -304,7 +290,31 @@ public class WebInfConfiguration implements Configuration } } - + /** + * Given an Object, return File reference for object. + * Typically used to convert anonymous Object from getAttribute() calls to a File object. + * @param fileattr the file attribute to analyze and return from (supports type File and type String, all others return null) + * @return the File object, null if null, or null if not a File or String + */ + private File asFile(Object fileattr) + { + if (fileattr == null) + { + return null; + } + if (fileattr instanceof File) + { + return (File)fileattr; + } + if (fileattr instanceof String) + { + return new File((String)fileattr); + } + return null; + } + + + public void makeTempDirectory (File parent, WebAppContext context, boolean deleteExisting) throws IOException {