You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@apache.org on 2004/07/26 01:35:38 UTC
cvs commit: jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/startup HostConfig.java ContextConfig.java ExpandWar.java
remm 2004/07/25 16:35:37
Modified: catalina/src/share/org/apache/catalina/startup
HostConfig.java ContextConfig.java ExpandWar.java
Log:
- Implement a significant amount of reload/redeployment.
- Since I'm a happy (?) user of MickeyMouse(TM) OS (aka Windows), I can't really test stuff without the anti-locking code
which I haven't implemented yet. I'll do that tomorrow (this seems simple).
- I used some ideas from Peter, and managed to notice code I could remove. Thanks.
- Please don't file bugs on this until I've at least tested a bit :)
- I need to add one extra method and refactor a bit to allow usage through the manager webapp (the manager webapp
will want synced operation, I think, so the background thread won't do it in that case - although it would do the job
eventually).
- I'll also add the new extra configuration items tomorrow, such as the "watchedfile" feature (that's simple).
Revision Changes Path
1.35 +230 -159 jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/startup/HostConfig.java
Index: HostConfig.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/startup/HostConfig.java,v
retrieving revision 1.34
retrieving revision 1.35
diff -u -r1.34 -r1.35
--- HostConfig.java 23 Jul 2004 22:57:34 -0000 1.34
+++ HostConfig.java 25 Jul 2004 23:35:37 -0000 1.35
@@ -23,7 +23,6 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.jar.JarEntry;
@@ -36,6 +35,7 @@
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.core.ContainerBase;
import org.apache.catalina.core.StandardHost;
import org.apache.catalina.util.StringManager;
import org.apache.tomcat.util.digester.Digester;
@@ -422,14 +422,13 @@
File appBase = appBase();
File configBase = configBase();
- do {
- // Deploy XML descriptors from configBase
- deployDescriptors(configBase, configBase.list());
- // Deploy expanded folders
- deployDirectories(appBase, appBase.list());
- // Deploy WARs, and loop if additional descriptors are found
- } while (deployWARs(appBase, appBase.list()));
-
+ // Deploy XML descriptors from configBase
+ deployDescriptors(configBase, configBase.list());
+ // Deploy WARs, and loop if additional descriptors are found
+ deployWARs(appBase, appBase.list());
+ // Deploy expanded folders
+ deployDirectories(appBase, appBase.list());
+
}
@@ -460,6 +459,8 @@
if (deployed.containsKey(contextPath))
continue;
+ DeployedApplication deployedApp = new DeployedApplication(contextPath);
+
// Assume this is a configuration descriptor and deploy it
log.debug(sm.getString("hostConfig.deployDescriptor", files[i]));
try {
@@ -475,15 +476,45 @@
}
newContext.setConfigFile(contextXml.getAbsolutePath());
newContext.setPath(contextPath);
+ // Add the context XML to the list of watched files
+ deployedApp.reloadResources.put
+ (contextXml.getAbsolutePath(), new Long(contextXml.lastModified()));
+ // Add the associated docBase to the redeployed list if it's a WAR
+ boolean isWar = false;
+ if (newContext.getDocBase() != null) {
+ File docBase = new File(newContext.getDocBase());
+ if (!docBase.isAbsolute()) {
+ docBase = new File(new File(host.getAppBase()),
+ newContext.getDocBase());
+ }
+ deployedApp.redeployResources.put(docBase.getAbsolutePath(),
+ new Long(docBase.lastModified()));
+ if (docBase.getAbsolutePath().toLowerCase().endsWith(".war")) {
+ isWar = true;
+ }
+ }
host.addChild(newContext);
+ // Add the eventual unpacked WAR and all the resources which will be
+ // watched inside it
+ if (isWar && unpackWARs && (newContext.getDocBase() != null)) {
+ File docBase = new File(newContext.getDocBase());
+ if (!docBase.isAbsolute()) {
+ docBase = new File(new File(host.getAppBase()),
+ newContext.getDocBase());
+ }
+ deployedApp.redeployResources.put(docBase.getAbsolutePath(),
+ new Long(docBase.lastModified()));
+ // FIXME: Add the list of reload resources as given by the context
+ // This list would by default contain /WEB-INF/web.xml and
+ // /META-INF/context.xml
+ // Add new element in Context to configure this
+ }
} catch (Throwable t) {
log.error(sm.getString("hostConfig.deployDescriptor.error",
files[i]), t);
}
- deployed.put(contextPath, new DeployedApplication(contextPath));
- // FIXME: populate needed resources, such as the docBase (WAR, expanded)
- // FIXME: populate watched resources
+ deployed.put(contextPath, deployedApp);
}
@@ -495,22 +526,22 @@
/**
* Deploy WAR files.
*/
- protected boolean deployWARs(File appBase, String[] files) {
-
+ protected void deployWARs(File appBase, String[] files) {
+
if (files == null)
- return false;
+ return;
boolean checkAdditionalDeployments = false;
for (int i = 0; i < files.length; i++) {
-
+
if (files[i].equalsIgnoreCase("META-INF"))
continue;
if (files[i].equalsIgnoreCase("WEB-INF"))
continue;
File dir = new File(appBase, files[i]);
if (files[i].toLowerCase().endsWith(".war")) {
-
+
// Calculate the context path and make sure it is unique
String contextPath = "/" + files[i];
int period = contextPath.lastIndexOf(".");
@@ -518,137 +549,128 @@
contextPath = contextPath.substring(0, period);
if (contextPath.equals("/ROOT"))
contextPath = "";
-
+
if (deployed.containsKey(contextPath))
continue;
-
- if (isUnpackWARs()) {
-
- // Expand and deploy this application as a directory
- log.debug(sm.getString("hostConfig.expand", files[i]));
- URL url = null;
- String path = null;
+
+ // FIXME: Don't do that if disabled on Host (sort of "security" feature)
+ // Checking for a nested /META-INF/context.xml
+ JarFile jar = null;
+ JarEntry entry = null;
+ InputStream istream = null;
+ BufferedOutputStream ostream = null;
+ File xml = new File
+ (configBase, files[i].substring
+ (0, files[i].lastIndexOf(".")) + ".xml");
+ if (!xml.exists()) {
try {
- url = new URL("jar:file:" +
- dir.getCanonicalPath() + "!/");
- path = ExpandWar.expand(host, url);
- checkAdditionalDeployments = true;
- } catch (IOException e) {
- // JAR decompression failure
- log.warn(sm.getString
- ("hostConfig.expand.error", files[i]));
- } catch (Throwable t) {
- log.error(sm.getString
- ("hostConfig.expand.error", files[i]), t);
- }
-
- // The webapp will actually be deployed when checking the directories
-
- } else {
-
- // FIXME: Don't do that if disabled on Host (sort of "security" feature)
-
- // Checking for a nested /META-INF/context.xml
- JarFile jar = null;
- JarEntry entry = null;
- InputStream istream = null;
- BufferedOutputStream ostream = null;
- File xml = new File
- (configBase, files[i].substring
- (0, files[i].lastIndexOf(".")) + ".xml");
- if (!xml.exists()) {
- try {
- jar = new JarFile(dir);
- entry = jar.getJarEntry("META-INF/context.xml");
- if (entry != null) {
- istream = jar.getInputStream(entry);
-
- configBase.mkdirs();
-
- ostream =
- new BufferedOutputStream
- (new FileOutputStream(xml), 1024);
- byte buffer[] = new byte[1024];
- while (true) {
- int n = istream.read(buffer);
- if (n < 0) {
- break;
- }
- ostream.write(buffer, 0, n);
+ jar = new JarFile(dir);
+ entry = jar.getJarEntry("META-INF/context.xml");
+ if (entry != null) {
+ istream = jar.getInputStream(entry);
+
+ configBase.mkdirs();
+
+ ostream =
+ new BufferedOutputStream
+ (new FileOutputStream(xml), 1024);
+ byte buffer[] = new byte[1024];
+ while (true) {
+ int n = istream.read(buffer);
+ if (n < 0) {
+ break;
}
- ostream.flush();
- ostream.close();
- ostream = null;
- istream.close();
- istream = null;
- entry = null;
- jar.close();
- jar = null;
- //deployDescriptors(configBase(), configBase.list());
- checkAdditionalDeployments = true;
- continue;
+ ostream.write(buffer, 0, n);
}
- } catch (Exception e) {
- // Ignore and continue
- if (ostream != null) {
- try {
- ostream.close();
- } catch (Throwable t) {
- ;
- }
- ostream = null;
+ ostream.flush();
+ ostream.close();
+ ostream = null;
+ istream.close();
+ istream = null;
+ entry = null;
+ jar.close();
+ jar = null;
+ }
+ } catch (Exception e) {
+ // Ignore and continue
+ if (ostream != null) {
+ try {
+ ostream.close();
+ } catch (Throwable t) {
+ ;
}
- if (istream != null) {
- try {
- istream.close();
- } catch (Throwable t) {
- ;
- }
- istream = null;
+ ostream = null;
+ }
+ if (istream != null) {
+ try {
+ istream.close();
+ } catch (Throwable t) {
+ ;
}
- } finally {
- entry = null;
- if (jar != null) {
- try {
- jar.close();
- } catch (Throwable t) {
- ;
- }
- jar = null;
+ istream = null;
+ }
+ } finally {
+ entry = null;
+ if (jar != null) {
+ try {
+ jar.close();
+ } catch (Throwable t) {
+ ;
}
+ jar = null;
}
}
-
- // Deploy the application in this WAR file
- log.info(sm.getString("hostConfig.deployJar", files[i]));
- try {
- Context context = (Context) Class.forName(contextClass).newInstance();
- if (context instanceof Lifecycle) {
- Class clazz = Class.forName(host.getConfigClass());
- LifecycleListener listener =
- (LifecycleListener) clazz.newInstance();
- ((Lifecycle) context).addLifecycleListener(listener);
+ }
+
+ DeployedApplication deployedApp = new DeployedApplication(contextPath);
+
+ // Deploy the application in this WAR file
+ log.info(sm.getString("hostConfig.deployJar", files[i]));
+ try {
+ Context context = (Context) Class.forName(contextClass).newInstance();
+ if (context instanceof Lifecycle) {
+ Class clazz = Class.forName(host.getConfigClass());
+ LifecycleListener listener =
+ (LifecycleListener) clazz.newInstance();
+ ((Lifecycle) context).addLifecycleListener(listener);
+ }
+ context.setPath(contextPath);
+ context.setDocBase(files[i]);
+ if (xml.exists()) {
+ context.setConfigFile(xml.getAbsolutePath());
+ deployedApp.reloadResources.put
+ (xml.getAbsolutePath(), new Long(xml.lastModified()));
+ }
+ host.addChild(context);
+ // If we're unpacking WARs, the docBase will be mutated after
+ // starting the context
+ if (unpackWARs && (context.getDocBase() != null)) {
+ File docBase = new File(context.getDocBase());
+ if (!docBase.isAbsolute()) {
+ docBase = new File(new File(host.getAppBase()),
+ context.getDocBase());
}
- context.setPath(contextPath);
- context.setDocBase(files[i]);
- host.addChild(context);
- } catch (Throwable t) {
- log.error(sm.getString("hostConfig.deployJar.error",
- files[i]), t);
+ deployedApp.redeployResources.put(docBase.getAbsolutePath(),
+ new Long(docBase.lastModified()));
+ // FIXME: Add the list of reload resources as given by the context
+ // This list would by default contain /WEB-INF/web.xml and
+ // /META-INF/context.xml
+ // Add new element in Context to configure this
}
-
- deployed.put(contextPath, new DeployedApplication(contextPath));
- // FIXME: populate needed resources, such as the docBase (context file, WAR, expanded)
- // FIXME: populate watched resources
-
+ } catch (Throwable t) {
+ log.error(sm.getString("hostConfig.deployJar.error",
+ files[i]), t);
}
-
+
+ // Populate redeploy resources with the WAR file
+ deployedApp.redeployResources.put
+ (dir.getAbsolutePath(), new Long(dir.lastModified()));
+ deployed.put(contextPath, deployedApp);
+
}
-
+
}
- return checkAdditionalDeployments;
-
}
@@ -686,10 +708,11 @@
if (deployed.containsKey(contextPath))
continue;
+ DeployedApplication deployedApp = new DeployedApplication(contextPath);
+
// Deploy the application in this directory
if( log.isDebugEnabled() )
log.debug(sm.getString("hostConfig.deployDir", files[i]));
- long t1=System.currentTimeMillis();
try {
Context context = (Context) Class.forName(contextClass).newInstance();
if (context instanceof Lifecycle) {
@@ -703,17 +726,18 @@
// FIXME: Don't set that if disabled on Host (sort of "security" feature)
context.setConfigFile((new File(dir, "META-INF/context.xml")).getAbsolutePath());
host.addChild(context);
+ deployedApp.redeployResources.put(dir.getAbsolutePath(),
+ new Long(dir.lastModified()));
+ // FIXME: Add the list of reload resources as given by the context
+ // This list would by default contain /WEB-INF/web.xml and
+ // /META-INF/context.xml
+ // Add new element in Context to configure this
} catch (Throwable t) {
log.error(sm.getString("hostConfig.deployDir.error", files[i]),
t);
}
- long t2=System.currentTimeMillis();
- if( log.isDebugEnabled() && (t2-t1) > 200 )
- log.debug("Deployed " + files[i] + " " + (t2-t1));
-
- deployed.put(contextPath, new DeployedApplication(contextPath));
- // FIXME: populate needed resources, such as the docBase (context file, WAR, expanded)
- // FIXME: populate watched resources
+
+ deployed.put(contextPath, deployedApp);
}
@@ -726,32 +750,62 @@
* Check resources for redeployment and reloading.
*/
protected synchronized void checkResources(DeployedApplication app) {
- if (isServiced(app.name))
- return;
- String[] resources = (String[]) app.redeployResources.toArray(new String[0]);
+ String[] resources = (String[]) app.redeployResources.keySet().toArray(new String[0]);
for (int i = 0; i < resources.length; i++) {
File resource = new File(resources[i]);
- if (resource.exists()) {
- if (resource.lastModified() > app.timestamp) {
+ if (log.isDebugEnabled())
+ log.debug("Checking context[" + app.name + "] redeploy resource " + resource);
+ if (resource.exists()) {
+ long lastModified = ((Long) app.redeployResources.get(resources[i])).longValue();
+ if ((!resource.isDirectory()) && resource.lastModified() > lastModified) {
// Redeploy application
- host.removeChild(host.findChild(app.name));
- // FIXME: Remove other redeploy resources; need hack here to remove expanded
- // folder if updated resource is a WAR
- deployed.remove(app);
+ ContainerBase context = (ContainerBase) host.findChild(app.name);
+ host.removeChild(context);
+ try {
+ context.destroy();
+ } catch (Exception e) {
+ log.warn(sm.getString
+ ("hostConfig.context.destroy", app.name), e);
+ }
+ // Delete other redeploy resources
+ for (int j = 0; j < resources.length; j++) {
+ if (j != i) {
+ ExpandWar.delete(new File(resources[j]));
+ }
+ }
+ deployed.remove(app.name);
return;
}
} else {
// Undeploy application
- host.removeChild(host.findChild(app.name));
- // FIXME: Delete all redeploy resources
- deployed.remove(app);
+ ContainerBase context = (ContainerBase) host.findChild(app.name);
+ host.removeChild(context);
+ try {
+ context.destroy();
+ } catch (Exception e) {
+ log.warn(sm.getString
+ ("hostConfig.context.destroy", app.name), e);
+ }
+ // Delete all redeploy resources
+ for (int j = 0; j < resources.length; j++) {
+ ExpandWar.delete(new File(resources[j]));
+ }
+ // Delete reload resources as well (to remove any remaining .xml descriptor)
+ String[] resources2 = (String[]) app.reloadResources.keySet().toArray(new String[0]);
+ for (int j = 0; j < resources2.length; j++) {
+ ExpandWar.delete(new File(resources2[j]));
+ }
+ deployed.remove(app.name);
return;
}
}
- resources = (String[]) app.reloadResources.toArray(new String[0]);
+ resources = (String[]) app.reloadResources.keySet().toArray(new String[0]);
for (int i = 0; i < resources.length; i++) {
File resource = new File(resources[i]);
- if ((!resource.exists()) || (resource.lastModified() > app.timestamp)) {
+ if (log.isDebugEnabled())
+ log.debug("Checking context[" + app.name + "] reload resource " + resource);
+ long lastModified = ((Long) app.reloadResources.get(resources[i])).longValue();
+ if ((!resource.exists()) || (resource.lastModified() != lastModified)) {
// Reload application
Container context = host.findChild(app.name);
try {
@@ -825,7 +879,7 @@
/**
- * Deploy webapps.
+ * Check status of all webapps.
*/
protected void check() {
@@ -834,7 +888,8 @@
DeployedApplication[] apps =
(DeployedApplication[]) deployed.values().toArray(new DeployedApplication[0]);
for (int i = 0; i < apps.length; i++) {
- checkResources(apps[i]);
+ if (!isServiced(apps[i].name))
+ checkResources(apps[i]);
}
// Hotdeploy applications
deployApps();
@@ -843,6 +898,20 @@
}
+ /**
+ * Check status of a specific webapp, for use with stuff like management webapps.
+ */
+ protected void check(String name) {
+ DeployedApplication app = (DeployedApplication) deployed.get(name);
+ if (app != null) {
+ checkResources(app);
+ } else {
+ // FIXME: add a version of deployApps which would check only for
+ // deployment of a specified app.name
+ }
+ }
+
+
// ----------------------------------------------------- Instance Variables
@@ -866,16 +935,18 @@
* redeployment of the application. If any of the specified resources is
* removed, the application will be undeployed. Typically, this will
* contain resources like the context.xml file, a compressed WAR path.
+ * The value is the last modification time.
*/
- public ArrayList redeployResources = new ArrayList();
+ public HashMap redeployResources = new HashMap();
/**
* Any modification of the specified (static) resources will cause a
* reload of the application. This will typically contain resources
* such as the web.xml of a webapp, but can be configured to contain
* additional descriptors.
+ * The value is the last modification time.
*/
- public ArrayList reloadResources = new ArrayList();
+ public HashMap reloadResources = new HashMap();
/**
* Instant where the application was last put in service.
1.48 +3 -3 jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/startup/ContextConfig.java
Index: ContextConfig.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/startup/ContextConfig.java,v
retrieving revision 1.47
retrieving revision 1.48
diff -u -r1.47 -r1.48
--- ContextConfig.java 23 Jul 2004 22:57:34 -0000 1.47
+++ ContextConfig.java 25 Jul 2004 23:35:37 -0000 1.48
@@ -737,8 +737,8 @@
protected void antiLocking()
throws IOException {
// FIXME: Implement anti locking, if it is enabled, by copying the whole
- // contents of the docBase to a unique folder in temp, and setting the docBase
- // to point to that
+ // contents of the docBase to a unique folder in temp, and setting the resources
+ // to point to that. Note: Don't mutate the docBase here.
}
1.7 +18 -3 jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/startup/ExpandWar.java
Index: ExpandWar.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/startup/ExpandWar.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- ExpandWar.java 23 Jun 2004 13:51:37 -0000 1.6
+++ ExpandWar.java 25 Jul 2004 23:35:37 -0000 1.7
@@ -187,7 +187,22 @@
*
* @param dir File object representing the directory to be deleted
*/
- public static void deleteDir(File dir) {
+ public static boolean delete(File dir) {
+ if (dir.isDirectory()) {
+ return deleteDir(dir);
+ } else {
+ return dir.delete();
+ }
+ }
+
+
+ /**
+ * Delete the specified directory, including all of its contents and
+ * subdirectories recursively.
+ *
+ * @param dir File object representing the directory to be deleted
+ */
+ public static boolean deleteDir(File dir) {
String files[] = dir.list();
if (files == null) {
@@ -201,7 +216,7 @@
file.delete();
}
}
- dir.delete();
+ return dir.delete();
}
---------------------------------------------------------------------
To unsubscribe, e-mail: tomcat-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tomcat-dev-help@jakarta.apache.org