diff --git a/java/org/apache/catalina/manager/LocalStrings.properties b/java/org/apache/catalina/manager/LocalStrings.properties
index 8ee69ac05899..b0b397263ed5 100644
--- a/java/org/apache/catalina/manager/LocalStrings.properties
+++ b/java/org/apache/catalina/manager/LocalStrings.properties
@@ -80,6 +80,7 @@ managerServlet.exception=FAIL - Encountered exception {0}
managerServlet.findleaksFail=FAIL - Find leaks failed: Host not instance of StandardHost
managerServlet.findleaksList=OK - Found potential memory leaks in the following applications:
managerServlet.findleaksNone=OK - No memory leaks found
+managerServlet.invalidCommand=FAIL - Invalid parameters supplied for command [{0}]
managerServlet.invalidPath=FAIL - Invalid context path {0} was specified
managerServlet.listed=OK - Listed applications for virtual host {0}
managerServlet.listitem={0}:{1}:{2}:{3}
diff --git a/java/org/apache/catalina/manager/ManagerServlet.java b/java/org/apache/catalina/manager/ManagerServlet.java
index b2aecea0e8f5..3e19bbbe5906 100644
--- a/java/org/apache/catalina/manager/ManagerServlet.java
+++ b/java/org/apache/catalina/manager/ManagerServlet.java
@@ -54,6 +54,7 @@
import org.apache.catalina.connector.Connector;
import org.apache.catalina.core.StandardHost;
import org.apache.catalina.core.StandardServer;
+import org.apache.catalina.startup.ExpandWar;
import org.apache.catalina.util.ContextName;
import org.apache.catalina.util.RequestUtil;
import org.apache.catalina.util.ServerInfo;
@@ -179,8 +180,7 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
/**
* File object representing the directory into which the deploy() command
- * will store the WAR and context configuration files that have been
- * uploaded.
+ * will deploy uploaded WAR files (normally the appBase).
*/
protected File deployed = null;
@@ -340,8 +340,11 @@ public void doGet(HttpServletRequest request,
} else if (command.equals("/deploy")) {
if (war != null || config != null) {
deploy(writer, config, cn, war, update, smClient);
- } else {
+ } else if (tag != null) {
deploy(writer, cn, tag, smClient);
+ } else {
+ writer.println(smClient.getString(
+ "managerServlet.invalidCommand", command));
}
} else if (command.equals("/list")) {
list(writer, smClient);
@@ -654,21 +657,16 @@ protected synchronized void save(PrintWriter writer, String path,
String baseName = cn.getBaseName();
String displayPath = cn.getDisplayName();
- // Check if app already exists, or undeploy it if updating
+ // If app exists deployment can only proceed if update is true
+ // Note existing WAR will be deleted and then replaced
Context context = (Context) host.findChild(name);
- if (update) {
- if (context != null) {
- undeploy(writer, cn, smClient);
- }
- context = (Context) host.findChild(name);
- }
- if (context != null) {
+ if (context != null && !update) {
writer.println(smClient.getString("managerServlet.alreadyContext",
displayPath));
return;
}
- // Calculate the base path
+ // Determine directory where WAR will be uploaded to
File deployedPath = deployed;
if (tag != null) {
deployedPath = new File(versioned, tag);
@@ -679,26 +677,30 @@ protected synchronized void save(PrintWriter writer, String path,
}
}
- // Upload the web application archive to a local WAR file
+ // Determine full path for uploaded WAR
File localWar = new File(deployedPath, baseName + ".war");
if (debug >= 2) {
log("Uploading WAR file to " + localWar);
}
- // Copy WAR to appBase
try {
if (!isServiced(name)) {
addServiced(name);
try {
+ if (update && tag == null && localWar.isFile()) {
+ if (!localWar.delete()) {
+ writer.println(smClient.getString("managerServlet.deleteFail",
+ localWar));
+ return;
+ }
+ }
// Upload WAR
uploadWar(writer, request, localWar, smClient);
- // Copy WAR and XML to the host app base if needed
if (tag != null) {
+ // Copy WAR to the host's appBase
deployedPath = deployed;
File localWarCopy = new File(deployedPath, baseName + ".war");
copy(localWar, localWarCopy);
- localWar = localWarCopy;
- copy(localWar, new File(host.getAppBaseFile(), baseName + ".war"));
}
// Perform new deployment
check(name);
@@ -722,7 +724,6 @@ protected synchronized void save(PrintWriter writer, String path,
writer.println(smClient.getString(
"managerServlet.deployFailed", displayPath));
}
-
}
@@ -738,6 +739,8 @@ protected synchronized void save(PrintWriter writer, String path,
protected void deploy(PrintWriter writer, ContextName cn, String tag,
StringManager smClient) {
+ // NOTE: It is assumed that update is always true in this method.
+
// Validate the requested context path
if (!validateContextName(cn, writer, smClient)) {
return;
@@ -747,26 +750,19 @@ protected void deploy(PrintWriter writer, ContextName cn, String tag,
String name = cn.getName();
String displayPath = cn.getDisplayName();
- // Calculate the base path
- File deployedPath = versioned;
- if (tag != null) {
- deployedPath = new File(deployedPath, tag);
- }
-
// Find the local WAR file
- File localWar = new File(deployedPath, baseName + ".war");
-
- // Check if app already exists, or undeploy it if updating
- Context context = (Context) host.findChild(name);
- if (context != null) {
- undeploy(writer, cn, smClient);
- }
+ File localWar = new File(versioned, baseName + ".war");
// Copy WAR to appBase
try {
if (!isServiced(name)) {
addServiced(name);
try {
+ if (!localWar.delete()) {
+ writer.println(smClient.getString("managerServlet.deleteFail",
+ localWar));
+ return;
+ }
copy(localWar, new File(host.getAppBaseFile(), baseName + ".war"));
// Perform new deployment
check(name);
@@ -842,15 +838,10 @@ protected void deploy(PrintWriter writer, String config, ContextName cn,
String baseName = cn.getBaseName();
String displayPath = cn.getDisplayName();
- // Check if app already exists, or undeploy it if updating
+ // If app exists deployment can only proceed if update is true
+ // Note existing files will be deleted and then replaced
Context context = (Context) host.findChild(name);
- if (update) {
- if (context != null) {
- undeploy(writer, cn, smClient);
- }
- context = (Context) host.findChild(name);
- }
- if (context != null) {
+ if (context != null && !update) {
writer.println(smClient.getString("managerServlet.alreadyContext",
displayPath));
return;
@@ -873,17 +864,27 @@ protected void deploy(PrintWriter writer, String config, ContextName cn,
"managerServlet.mkdirFail",configBase));
return;
}
- copy(new File(config),
- new File(configBase, baseName + ".xml"));
+ File localConfig = new File(configBase, baseName + ".xml");
+ if (localConfig.isFile() && !localConfig.delete()) {
+ writer.println(smClient.getString(
+ "managerServlet.deleteFail", localConfig));
+ return;
+ }
+ copy(new File(config), localConfig);
}
if (war != null) {
+ File localWar;
if (war.endsWith(".war")) {
- copy(new File(war),
- new File(host.getAppBaseFile(), baseName + ".war"));
+ localWar = new File(host.getAppBaseFile(), baseName + ".war");
} else {
- copy(new File(war),
- new File(host.getAppBaseFile(), baseName));
+ localWar = new File(host.getAppBaseFile(), baseName);
+ }
+ if (localWar.exists() && !ExpandWar.delete(localWar)) {
+ writer.println(smClient.getString(
+ "managerServlet.deleteFail", localWar));
+ return;
}
+ copy(new File(war), localWar);
}
// Perform new deployment
check(name);
diff --git a/java/org/apache/catalina/startup/HostConfig.java b/java/org/apache/catalina/startup/HostConfig.java
index 64c7af24be27..d785700eb854 100644
--- a/java/org/apache/catalina/startup/HostConfig.java
+++ b/java/org/apache/catalina/startup/HostConfig.java
@@ -445,7 +445,7 @@ protected void deployApps(String name) {
ContextName cn = new ContextName(name, false);
String baseName = cn.getBaseName();
- if (deploymentExists(baseName)) {
+ if (deploymentExists(cn.getName())) {
return;
}
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index ddde8a9e75e7..c69ebc817bbf 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -112,6 +112,14 @@
56246: Fix NullPointerException in MemoryRealm when
authenticating an unknown user. (markt)
+
+ 56248: Allow the deployer to update an existing WAR file
+ without undeploying the existing application if the update flag is set.
+ This allows any existing custom context.xml for the application to be
+ retained. To update an application and remove any existing context.xml
+ simply undeploy the old version of the application before deploying the
+ new version. (markt)
+
56253: When listing resources that are provided by a JAR, fix
possible StringIndexOutOfBoundsException
s. Add some unit