Author: markt Date: Mon Nov 25 22:58:04 2013 New Revision: 1545438 URL: http://svn.apache.org/r1545438 Log: Backport automatic deployment changes part 10 Complete tests for modification
Modified: tomcat/tc7.0.x/trunk/ (props changed) tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/ContextConfig.java tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/HostConfig.java tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/LocalStrings.properties tomcat/tc7.0.x/trunk/test/org/apache/catalina/startup/TestHostConfigAutomaticDeployment.java Propchange: tomcat/tc7.0.x/trunk/ ------------------------------------------------------------------------------ Merged /tomcat/trunk:r1483360-1483361,1483390,1483552,1483554,1483679,1483743 Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/ContextConfig.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/ContextConfig.java?rev=1545438&r1=1545437&r2=1545438&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/ContextConfig.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/ContextConfig.java Mon Nov 25 22:58:04 2013 @@ -838,14 +838,6 @@ public class ContextConfig implements Li createWebXmlDigester(context.getXmlNamespaceAware(), context.getXmlValidation()); - - try { - fixDocBase(); - } catch (IOException e) { - log.error(sm.getString( - "contextConfig.fixDocBase", context.getName()), e); - } - } @@ -854,8 +846,14 @@ public class ContextConfig implements Li */ protected synchronized void beforeStart() { - antiLocking(); + try { + fixDocBase(); + } catch (IOException e) { + log.error(sm.getString( + "contextConfig.fixDocBase", context.getName()), e); + } + antiLocking(); } Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/HostConfig.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/HostConfig.java?rev=1545438&r1=1545437&r2=1545438&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/HostConfig.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/HostConfig.java Mon Nov 25 22:58:04 2013 @@ -603,7 +603,8 @@ public class HostConfig */ protected void deployDescriptor(ContextName cn, File contextXml) { - DeployedApplication deployedApp = new DeployedApplication(cn.getName()); + DeployedApplication deployedApp = + new DeployedApplication(cn.getName(), true); // Assume this is a configuration descriptor and deploy it if(log.isInfoEnabled()) { @@ -753,11 +754,35 @@ public class HostConfig if (files[i].equalsIgnoreCase("WEB-INF")) continue; File war = new File(appBase, files[i]); - if (files[i].toLowerCase(Locale.ENGLISH).endsWith(".war") && war.isFile() - && !invalidWars.contains(files[i]) ) { + if (files[i].toLowerCase(Locale.ENGLISH).endsWith(".war") && + war.isFile() && !invalidWars.contains(files[i]) ) { ContextName cn = new ContextName(files[i]); + if (isServiced(cn.getName())) { + continue; + } + if (deploymentExists(cn.getName())) { + DeployedApplication app = deployed.get(cn.getName()); + if (!unpackWARs && app != null) { + // Need to check for a directory that should not be + // there + File dir = new File(appBase, cn.getBaseName()); + if (dir.exists()) { + if (!app.loggedDirWarning) { + log.warn(sm.getString( + "hostConfig.deployWar.hiddenDir", + dir.getAbsoluteFile(), + war.getAbsoluteFile())); + app.loggedDirWarning = true; + } + } else { + app.loggedDirWarning = false; + } + } + continue; + } + // Check for WARs with /../ /./ or similar sequences in the name if (!validateContextPath(appBase, cn.getBaseName())) { log.error(sm.getString( @@ -902,7 +927,8 @@ public class HostConfig } } - DeployedApplication deployedApp = new DeployedApplication(cn.getName()); + DeployedApplication deployedApp = new DeployedApplication(cn.getName(), + xml.exists() && deployXML && copyXML); // Deploy the application in this WAR file if(log.isInfoEnabled()) @@ -1061,7 +1087,6 @@ public class HostConfig */ protected void deployDirectory(ContextName cn, File dir) { - DeployedApplication deployedApp = new DeployedApplication(cn.getName()); // Deploy the application in this directory if( log.isInfoEnabled() ) @@ -1071,6 +1096,10 @@ public class HostConfig Context context = null; File xml = new File(dir, Constants.ApplicationContextXml); File xmlCopy = null; + + DeployedApplication deployedApp = new DeployedApplication(cn.getName(), + xml.exists() && deployXML && copyXML); + try { if (deployXML && xml.exists()) { synchronized (digesterLock) { @@ -1236,11 +1265,41 @@ public class HostConfig if (resource.exists()) { long lastModified = app.redeployResources.get(resources[i]).longValue(); - if ((!resource.isDirectory()) && - resource.lastModified() > lastModified) { - // Undeploy application - deleteRedeployResources(app, resources, i, false); - return; + if (resource.lastModified() > lastModified) { + if (resource.isDirectory()) { + // No action required for modified directory + app.redeployResources.put(resources[i], + Long.valueOf(resource.lastModified())); + } else if (app.hasDescriptor && + resource.getName().toLowerCase( + Locale.ENGLISH).endsWith(".war")) { + // Modified WAR triggers a reload if there is an XML + // file present + // The only resource that should be deleted is the + // expanded WAR (if any) + Context context = (Context) host.findChild(app.name); + String docBase = context.getDocBase(); + docBase = docBase.toLowerCase(Locale.ENGLISH); + if (!docBase.endsWith(".war")) { + // This is an expanded directory + File docBaseFile = new File(docBase); + if (!docBaseFile.isAbsolute()) { + docBaseFile = new File(appBase(), docBase); + } + ExpandWar.delete(docBaseFile); + // Reset the docBase to trigger re-expansion of the + // WAR + context.setDocBase(resource.getAbsolutePath()); + } + reload(app); + return; + } else { + // Everything else triggers a redeploy + // (just need to undeploy here, deploy will follow) + deleteRedeployResources(app, resources, i, false); + undeploy(app); + return; + } } } else { // There is a chance the the resource was only missing @@ -1260,6 +1319,7 @@ public class HostConfig continue; } // Undeploy application + undeploy(app); deleteRedeployResources(app, resources, i, true); return; } @@ -1275,22 +1335,7 @@ public class HostConfig if ((!resource.exists() && lastModified != 0L) || (resource.lastModified() != lastModified)) { // Reload application - if(log.isInfoEnabled()) - log.info(sm.getString("hostConfig.reload", app.name)); - Context context = (Context) host.findChild(app.name); - if (context.getState().isAvailable()) { - // Reload catches and logs exceptions - context.reload(); - } else { - // If the context was not started (for example an error - // in web.xml) we'll still get to try to start - try { - context.start(); - } catch (Exception e) { - log.warn(sm.getString - ("hostConfig.context.restart", app.name), e); - } - } + reload(app); // Update times app.reloadResources.put(resources[i], Long.valueOf(resource.lastModified())); @@ -1301,10 +1346,27 @@ public class HostConfig } - private void deleteRedeployResources(DeployedApplication app, - String[] resources, int i, boolean deleteReloadResources) { + private void reload(DeployedApplication app) { + if(log.isInfoEnabled()) + log.info(sm.getString("hostConfig.reload", app.name)); + Context context = (Context) host.findChild(app.name); + if (context.getState().isAvailable()) { + // Reload catches and logs exceptions + context.reload(); + } else { + // If the context was not started (for example an error + // in web.xml) we'll still get to try to start + try { + context.start(); + } catch (Exception e) { + log.warn(sm.getString + ("hostConfig.context.restart", app.name), e); + } + } + } + - // Delete redeploy resources + private void undeploy(DeployedApplication app) { if (log.isInfoEnabled()) log.info(sm.getString("hostConfig.undeploy", app.name)); Container context = host.findChild(app.name); @@ -1315,6 +1377,13 @@ public class HostConfig log.warn(sm.getString ("hostConfig.context.remove", app.name), t); } + deployed.remove(app.name); + } + + + private void deleteRedeployResources(DeployedApplication app, + String[] resources, int i, boolean deleteReloadResources) { + // Delete other redeploy resources for (int j = i + 1; j < resources.length; j++) { try { @@ -1327,11 +1396,7 @@ public class HostConfig } // Only delete resources in the appBase or the // host's configBase - if ((current.getAbsolutePath().startsWith( - appBase().getAbsolutePath() + - File.separator)) - || (current.getAbsolutePath().startsWith( - configBase().getAbsolutePath()))) { + if (isDeletableResource(current)) { if (log.isDebugEnabled()) log.debug("Delete " + current); ExpandWar.delete(current); @@ -1357,11 +1422,7 @@ public class HostConfig } // Only delete resources in the appBase or the host's // configBase - if ((current.getAbsolutePath().startsWith( - appBase().getAbsolutePath() + File.separator)) - || ((current.getAbsolutePath().startsWith( - configBase().getAbsolutePath()) - && (current.getAbsolutePath().endsWith(".xml"))))) { + if (isDeletableResource(current)) { if (log.isDebugEnabled()) log.debug("Delete " + current); ExpandWar.delete(current); @@ -1373,9 +1434,21 @@ public class HostConfig } } - deployed.remove(app.name); } + + private boolean isDeletableResource(File resource) { + if ((resource.getAbsolutePath().startsWith( + appBase().getAbsolutePath() + File.separator)) + || ((resource.getAbsolutePath().startsWith( + configBase().getAbsolutePath()) + && (resource.getAbsolutePath().endsWith(".xml"))))) { + return true; + } + return false; + } + + /** * Process a "start" event for this Host. */ @@ -1525,6 +1598,7 @@ public class HostConfig // Version is unused - undeploy it completely // The -1 is a 'trick' to ensure all redeploy // resources are removed + undeploy(app); deleteRedeployResources(app, resources, -1, true); } @@ -1546,7 +1620,8 @@ public class HostConfig if (deployed.containsKey(contextName)) return; - DeployedApplication deployedApp = new DeployedApplication(contextName); + DeployedApplication deployedApp = + new DeployedApplication(contextName, false); // Add the associated docBase to the redeployed list if it's a WAR boolean isWar = false; @@ -1594,8 +1669,9 @@ public class HostConfig * the monitored resources. */ protected static class DeployedApplication { - public DeployedApplication(String name) { + public DeployedApplication(String name, boolean hasDescriptor) { this.name = name; + this.hasDescriptor = hasDescriptor; } /** @@ -1605,6 +1681,12 @@ public class HostConfig public String name; /** + * Does this application have a context.xml descriptor file on the + * host's configBase? + */ + public final boolean hasDescriptor; + + /** * Any modification of the specified (static) resources will cause a * redeployment of the application. If any of the specified resources is * removed, the application will be undeployed. Typically, this will @@ -1628,6 +1710,14 @@ public class HostConfig * Instant where the application was last put in service. */ public long timestamp = System.currentTimeMillis(); + + /** + * In some circumstances, such as when unpackWARs is true, a directory + * may be added to the appBase that is ignored. This flag indicates that + * the user has been warned so that the warning is not logged on every + * run of the auto deployer. + */ + public boolean loggedDirWarning = false; } private static class DeployDescriptor implements Runnable { Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/LocalStrings.properties URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/LocalStrings.properties?rev=1545438&r1=1545437&r2=1545438&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/LocalStrings.properties (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/LocalStrings.properties Mon Nov 25 22:58:04 2013 @@ -96,6 +96,7 @@ hostConfig.deployDir.error=Error deployi hostConfig.deployDir.threaded.error=Error waiting for multi-thread deployment of directories to complete hostConfig.deployWar=Deploying web application archive {0} hostConfig.deployWar.error=Error deploying web application archive {0} +hostConfig.deployWar.hiddenDir=The directory [{0}] will be ignored because the WAR [{1}] takes priority and unpackWARs is false hostConfig.deployWar.threaded.error=Error waiting for multi-thread deployment of WAR files to complete hostConfig.deploy.error=Exception while deploying web application directory {0} hostConfig.deploying=Deploying discovered web applications Modified: tomcat/tc7.0.x/trunk/test/org/apache/catalina/startup/TestHostConfigAutomaticDeployment.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/test/org/apache/catalina/startup/TestHostConfigAutomaticDeployment.java?rev=1545438&r1=1545437&r2=1545438&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/test/org/apache/catalina/startup/TestHostConfigAutomaticDeployment.java (original) +++ tomcat/tc7.0.x/trunk/test/org/apache/catalina/startup/TestHostConfigAutomaticDeployment.java Mon Nov 25 22:58:04 2013 @@ -69,6 +69,7 @@ public class TestHostConfigAutomaticDepl private static final String XML_COOKIE_NAME = "XML_CONTEXT"; private static final String WAR_COOKIE_NAME = "WAR_CONTEXT"; private static final String DIR_COOKIE_NAME = "DIR_CONTEXT"; + // private static final String DEFAULT_COOKIE_NAME = "JSESSIONID"; private File external; @@ -688,29 +689,31 @@ public class TestHostConfigAutomaticDepl /* - * Expected behaviour for deletion of files. + * Expected behaviour for the deletion of files. * - * Artifacts present(6) Artifact Artifacts remaining + * Artifacts present Artifact Artifacts remaining * XML WAR EXT DIR Removed XML WAR EXT DIR Notes * N N N Y DIR - - - N * N Y N N WAR - N - - - * N Y N Y DIR - Y - R 8 + * N Y N Y DIR - Y - R 1 * N Y N Y WAR - N - N * Y N N N XML N - - - - * Y N N Y DIR Y - - N 2 - * Y N N Y XML N - - N - * Y N Y N EXT Y - N - 2 - * Y N Y N XML N - Y - 9 - * Y N Y Y DIR Y - Y R 10,8 - * Y N Y Y EXT Y - N N 2 + * Y N N Y DIR N - - N + * Y N N Y XML R - - Y 2 + * Y N Y N EXT Y - N - + * Y N Y N XML N - Y - + * Y N Y Y DIR R - Y R 1,2 + * Y N Y Y EXT Y - N N * Y N Y Y XML N - Y N - * Y Y N N WAR Y N - - 2 + * Y Y N N WAR N N - - * Y Y N N XML N N - - - * Y Y N Y DIR Y Y - R 8 - * Y Y N Y WAR Y N - - 2 - * Y Y N Y XML N N - N + * Y Y N Y DIR R Y - R 1,2 + * Y Y N Y WAR N N - - + * Y Y N Y XML R Y - Y * - * Notes: + * Notes: 1. The DIR will be re-created since unpackWARs is true. + * 2. The XML will be extracted from the WAR/DIR if deployXML and + * copyXML are true. */ @Test public void testDeleteDirRemoveDir() throws Exception { @@ -742,22 +745,26 @@ public class TestHostConfigAutomaticDepl null); } - //@Test - // TODO + @Test public void testDeleteXmlDirRemoveDir() throws Exception { - doTestDelete(true, false, false, false, true, DIR, true, false, false, - XML_COOKIE_NAME); + doTestDelete(true, false, false, false, true, DIR, false, false, false, + null); } - //@Test - // TODO + @Test public void testDeleteXmlDirRemoveXml() throws Exception { - doTestDelete(true, false, false, false, true, XML, false, false, false, - null); + doTestDelete(true, false, false, false, true, XML, false, false, true, + DIR_COOKIE_NAME); } - //@Test - // TODO + @Test + public void testDeleteXmlDirRemoveXmlCopyXml() throws Exception { + ((StandardHost) getTomcatInstance().getHost()).setCopyXML(true); + doTestDelete(true, false, false, false, true, XML, true, false, true, + DIR_COOKIE_NAME); + } + + @Test public void testDeleteXmlExtwarRemoveExt() throws Exception { doTestDelete(true, true, false, false, false, EXT, true, false, false, XML_COOKIE_NAME); @@ -799,41 +806,64 @@ public class TestHostConfigAutomaticDepl null); } - //@Test - // TODO + @Test public void testDeleteXmlWarRemoveWar() throws Exception { - doTestDelete(true, false, false, true, false, WAR, true, false, false, - XML_COOKIE_NAME); + doTestDelete(true, false, false, true, false, WAR, false, false, false, + null); } - //@Test - // TODO + @Test public void testDeleteXmlWarRemoveXml() throws Exception { - doTestDelete(true, false, false, true, false, XML, false, false, false, - null); + doTestDelete(true, false, false, true, false, XML, false, true, false, + WAR_COOKIE_NAME); } - //@Test - // TODO + @Test + public void testDeleteXmlWarRemoveXmlCopyXml() throws Exception { + ((StandardHost) getTomcatInstance().getHost()).setCopyXML(true); + doTestDelete(true, false, false, true, false, XML, true, true, false, + WAR_COOKIE_NAME); + } + + @Test public void testDeleteXmlWarDirRemoveDir() throws Exception { + doTestDelete(true, false, false, true, true, DIR, false, true, true, + WAR_COOKIE_NAME); + } + + @Test + public void testDeleteXmlWarDirRemoveDirCopyXml() throws Exception { + ((StandardHost) getTomcatInstance().getHost()).setCopyXML(true); doTestDelete(true, false, false, true, true, DIR, true, true, true, - XML_COOKIE_NAME); + WAR_COOKIE_NAME); } - //@Test - // TODO + @Test public void testDeleteXmlWarDirRemoveWar() throws Exception { - doTestDelete(true, false, false, true, true, WAR, true, false, false, - XML_COOKIE_NAME); + doTestDelete(true, false, false, true, true, WAR, false, false, false, + null); } - //@Test - // TODO - public void testDeleteXmlWarDirRemoveXml() throws Exception { - doTestDelete(true, false, false, true, true, XML, false, false, false, + @Test + public void testDeleteXmlWarDirRemoveWarCopyXml() throws Exception { + ((StandardHost) getTomcatInstance().getHost()).setCopyXML(true); + doTestDelete(true, false, false, true, true, WAR, false, false, false, null); } + @Test + public void testDeleteXmlWarDirRemoveXml() throws Exception { + doTestDelete(true, false, false, true, true, XML, false, true, true, + DIR_COOKIE_NAME); + } + + @Test + public void testDeleteXmlWarDirRemoveXmlCopyXml() throws Exception { + ((StandardHost) getTomcatInstance().getHost()).setCopyXML(true); + doTestDelete(true, false, false, true, true, XML, true, true, true, + WAR_COOKIE_NAME); + } + private void doTestDelete(boolean startXml, boolean startExternalWar, boolean startExternalDir, boolean startWar, boolean startDir, int toDelete, boolean resultXml, boolean resultWar, @@ -1023,9 +1053,9 @@ public class TestHostConfigAutomaticDepl * Artifacts present Artifact Artifacts remaining * XML WAR EXT DIR Modified XML WAR EXT DIR Action * N N N Y DIR - - - M None - * N Y N N WAR - M - - Reload + * N Y N N WAR - M - - Redeploy * N Y N Y DIR - Y - M None - * N Y N Y WAR - M - R Reload + * N Y N Y WAR - M - R Redeploy * Y N N N XML M - - - Redeploy * Y N N Y DIR Y - - M None * Y N N Y XML M - - Y Redeploy @@ -1038,7 +1068,7 @@ public class TestHostConfigAutomaticDepl * Y Y N N XML M Y - - Redeploy * Y Y N Y DIR Y Y - M None * Y Y N Y WAR Y M - - Reload - * Y Y N Y XML M Y - Y Reload + * Y Y N Y XML M Y - Y Redeploy */ @Test public void testModifyDirUpdateDir() throws Exception { @@ -1077,6 +1107,84 @@ public class TestHostConfigAutomaticDepl true, false, true, XML_COOKIE_NAME, NONE); } + @Test + public void testModifyXmlDirUpdateXml() throws Exception { + doTestModify(true, false, false, false, true, XML, + true, false, true, XML_COOKIE_NAME, REDEPLOY); + } + + @Test + public void testModifyXmlExtwarUpdateExtwar() throws Exception { + doTestModify(true, true, false, false, false, EXT, + true, false, false, XML_COOKIE_NAME, RELOAD); + } + + @Test + public void testModifyXmlExtdirUpdateExtdir() throws Exception { + doTestModify(true, false, true, false, false, EXT, + true, false, false, XML_COOKIE_NAME, NONE); + } + + @Test + public void testModifyXmlExtwarUpdateXml() throws Exception { + doTestModify(true, true, false, false, false, XML, + true, false, false, XML_COOKIE_NAME, REDEPLOY); + } + + @Test + public void testModifyXmlExtdirUpdateXml() throws Exception { + doTestModify(true, false, true, false, false, XML, + true, false, false, XML_COOKIE_NAME, REDEPLOY); + } + + @Test + public void testModifyXmlExtwarDirUpdateDir() throws Exception { + doTestModify(true, true, false, false, true, DIR, + true, false, false, XML_COOKIE_NAME, NONE); + } + + @Test + public void testModifyXmlExtwarDirUpdateExt() throws Exception { + doTestModify(true, true, false, false, true, EXT, + true, false, true, XML_COOKIE_NAME, RELOAD); + } + + @Test + public void testModifyXmlExtwarDirUpdateXml() throws Exception { + doTestModify(true, true, false, false, true, XML, + true, false, false, XML_COOKIE_NAME, REDEPLOY); + } + + @Test + public void testModifyXmlWarUpdateWar() throws Exception { + doTestModify(true, false, false, true, false, WAR, + true, true, false, XML_COOKIE_NAME, RELOAD); + } + + @Test + public void testModifyXmlWarUpdateXml() throws Exception { + doTestModify(true, false, false, true, false, XML, + true, true, false, XML_COOKIE_NAME, REDEPLOY); + } + + @Test + public void testModifyXmlWarDirUpdateDir() throws Exception { + doTestModify(true, false, false, true, true, DIR, + true, true, true, XML_COOKIE_NAME, NONE); + } + + @Test + public void testModifyXmlWarDirUpdateWar() throws Exception { + doTestModify(true, false, false, true, true, WAR, + true, true, true, XML_COOKIE_NAME, RELOAD); + } + + @Test + public void testModifyXmlWarDirUpdateXml() throws Exception { + doTestModify(true, false, false, true, true, XML, + true, true, true, XML_COOKIE_NAME, REDEPLOY); + } + private void doTestModify(boolean startXml, boolean startExternalWar, boolean startExternalDir, boolean startWar, boolean startDir, int toModify, boolean resultXml, boolean resultWar, @@ -1170,7 +1278,7 @@ public class TestHostConfigAutomaticDepl tomcat.start(); host.backgroundProcess(); - // Remove the specified file + // Change the specified file switch (toModify) { case XML: if (xml == null) { @@ -1240,15 +1348,22 @@ public class TestHostConfigAutomaticDepl Assert.assertNull(newContext); } if (!resultWar && !resultDir) { - if (resultXml && !startExternalWar && !startExternalDir) { - Assert.assertEquals(LifecycleState.FAILED, newContext.getState()); + if (resultXml) { + if (!startExternalWar && !startExternalDir) { + Assert.assertEquals(LifecycleState.FAILED, + newContext.getState()); + } else { + Assert.assertEquals(LifecycleState.STARTED, + newContext.getState()); + } } else { Assert.assertNull(newContext); } } if (newContext != null) { - Assert.assertEquals(resultCookieName, newContext.getSessionCookieName()); + Assert.assertEquals(resultCookieName, + newContext.getSessionCookieName()); } if (resultAction == NONE) { @@ -1294,7 +1409,7 @@ public class TestHostConfigAutomaticDepl } - private static class AntiResourceLockingContext extends StandardContext { + public static class AntiResourceLockingContext extends StandardContext { @Override public boolean getAntiResourceLocking() { --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org