remm 2004/07/26 03:56:55 Modified: catalina/src/share/org/apache/catalina/startup HostConfig.java ContextConfig.java ExpandWar.java catalina/src/share/org/apache/catalina/core StandardContext.java Log: - Add logic for avoiding locking on Windows. This takes a very heavy handed approach, but after trying many other methods, I think it's the only way to properly address the issue and allow real hot (re)deployment. - It's disabled by default, and there's a new antiResourceLocking attribute on Context. - I think I'll leave in the lighter anti JAR locking code in the CL, but disabled by default (and with another similar flag on Context). It could address different needs, and is less intrusive, as the webapp stays where it is. Revision Changes Path 1.37 +38 -17 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.36 retrieving revision 1.37 diff -u -r1.36 -r1.37 --- HostConfig.java 26 Jul 2004 08:09:19 -0000 1.36 +++ HostConfig.java 26 Jul 2004 10:56:53 -0000 1.37 @@ -496,15 +496,25 @@ host.addChild(context); // Add the eventual unpacked WAR and all the resources which will be // watched inside it - if (isWar && unpackWARs && (context.getDocBase() != null)) { - File docBase = new File(context.getDocBase()); + if (isWar && unpackWARs) { + String name = null; + String path = context.getPath(); + if (path.equals("")) { + name = "ROOT"; + } else { + if (path.startsWith("/")) { + name = path.substring(1); + } else { + name = path; + } + } + File docBase = new File(name); if (!docBase.isAbsolute()) { - docBase = new File(new File(host.getAppBase()), - context.getDocBase()); + docBase = new File(new File(host.getAppBase()), name); } deployedApp.redeployResources.put(docBase.getAbsolutePath(), new Long(docBase.lastModified())); - addWatchedResources(deployedApp, context); + addWatchedResources(deployedApp, docBase.getAbsolutePath(), context); } } catch (Throwable t) { log.error(sm.getString("hostConfig.deployDescriptor.error", @@ -642,14 +652,24 @@ // 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()); + String name = null; + String path = context.getPath(); + if (path.equals("")) { + name = "ROOT"; + } else { + if (path.startsWith("/")) { + name = path.substring(1); + } else { + name = path; + } + } + File docBase = new File(name); if (!docBase.isAbsolute()) { - docBase = new File(new File(host.getAppBase()), - context.getDocBase()); + docBase = new File(new File(host.getAppBase()), name); } deployedApp.redeployResources.put(docBase.getAbsolutePath(), new Long(docBase.lastModified())); - addWatchedResources(deployedApp, context); + addWatchedResources(deployedApp, docBase.getAbsolutePath(), context); } } catch (Throwable t) { log.error(sm.getString("hostConfig.deployJar.error", @@ -722,7 +742,7 @@ host.addChild(context); deployedApp.redeployResources.put(dir.getAbsolutePath(), new Long(dir.lastModified())); - addWatchedResources(deployedApp, context); + addWatchedResources(deployedApp, dir.getAbsolutePath(), context); } catch (Throwable t) { log.error(sm.getString("hostConfig.deployDir.error", files[i]), t); @@ -741,15 +761,16 @@ * Add watched resources to the specified Context. * @param app */ - protected void addWatchedResources(DeployedApplication app, Context context) { - File docBase = new File(context.getDocBase()); - if (!docBase.isAbsolute()) { - docBase = new File(new File(host.getAppBase()), - context.getDocBase()); + protected void addWatchedResources(DeployedApplication app, String docBase, Context context) { + // FIXME: Feature idea. Add support for patterns (ex: WEB-INF/*, WEB-INF/*.xml), where + // we would only check if at least one resource is newer than app.timestamp + File docBaseFile = new File(docBase); + if (!docBaseFile.isAbsolute()) { + docBaseFile = new File(new File(host.getAppBase()), docBase); } String[] watchedResources = context.findWatchedResources(); for (int i = 0; i < watchedResources.length; i++) { - File resource = new File(docBase, watchedResources[i]); + File resource = new File(docBaseFile, watchedResources[i]); app.reloadResources.put(resource.getAbsolutePath(), new Long(resource.lastModified())); } 1.49 +68 -5 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.48 retrieving revision 1.49 diff -u -r1.48 -r1.49 --- ContextConfig.java 25 Jul 2004 23:35:37 -0000 1.48 +++ ContextConfig.java 26 Jul 2004 10:56:54 -0000 1.49 @@ -141,7 +141,13 @@ */ protected static boolean xmlNamespaceAware = false; - + + /** + * Deployment count. + */ + protected static long deploymentCount = 0L; + + // ------------------------------------------------------------- Properties @@ -188,6 +194,8 @@ // Process the event that has occurred if (event.getType().equals(Lifecycle.START_EVENT)) { start(); + } else if (event.getType().equals(StandardContext.BEFORE_START_EVENT)) { + beforeStart(); } else if (event.getType().equals(Lifecycle.STOP_EVENT)) { stop(); } else if (event.getType().equals(Lifecycle.INIT_EVENT)) { @@ -736,9 +744,55 @@ 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 resources - // to point to that. Note: Don't mutate the docBase here. + + if ((context instanceof StandardContext) + && ((StandardContext) context).getAntiResourceLocking()) { + + Host host = (Host) context.getParent(); + String appBase = host.getAppBase(); + String docBase = context.getDocBase(); + if (docBase == null) + return; + File docBaseFile = new File(docBase); + if (!docBaseFile.isAbsolute()) { + docBaseFile = new File(appBase, docBase); + } + + String path = context.getPath(); + if (path == null) { + return; + } + if (path.equals("")) { + docBase = "ROOT"; + } else { + if (path.startsWith("/")) { + docBase = path.substring(1); + } else { + docBase = path; + } + } + + File file = null; + if (context.getDocBase().toLowerCase().endsWith(".war")) { + file = new File(System.getProperty("java.io.tmpdir"), + deploymentCount++ + "-" + docBase + ".war"); + } else { + file = new File(System.getProperty("java.io.tmpdir"), + deploymentCount++ + "-" + docBase); + } + + if (log.isDebugEnabled()) + log.debug("Anti locking context[" + context.getPath() + + "] setting docBase to " + file); + + // Cleanup just in case an old deployment is lying around + ExpandWar.delete(file); + if (ExpandWar.copy(docBaseFile, file)) { + context.setDocBase(file.getAbsolutePath()); + } + + } + } @@ -760,6 +814,15 @@ } catch (IOException e) { log.error(sm.getString("contextConfig.fixDocBase"), e); } + + } + + + /** + * Process a "before start" event for this Context. + */ + protected synchronized void beforeStart() { + try { antiLocking(); } catch (IOException e) { 1.8 +76 -1 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.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- ExpandWar.java 25 Jul 2004 23:35:37 -0000 1.7 +++ ExpandWar.java 26 Jul 2004 10:56:54 -0000 1.8 @@ -19,6 +19,7 @@ import java.io.BufferedOutputStream; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.IOException; @@ -181,6 +182,80 @@ } + /** + * Copy the specified file or directory to the destination. + * + * @param src File object representing the source + * @param dest File object representing the destination + */ + public static boolean copy(File src, File dest) { + return copyInternal(src, dest, new byte[4096]); + } + + + /** + * Copy the specified file or directory to the destination. + * + * @param src File object representing the source + * @param dest File object representing the destination + */ + public static boolean copyInternal(File src, File dest, byte[] buf) { + + boolean result = true; + + String files[] = null; + if (src.isDirectory()) { + files = src.list(); + result = dest.mkdir(); + } else { + files = new String[1]; + files[0] = src.getName(); + } + if (files == null) { + files = new String[0]; + } + for (int i = 0; (i < files.length) && result; i++) { + File fileSrc = new File(src, files[i]); + File fileDest = new File(dest, files[i]); + if (fileSrc.isDirectory()) { + result = copyInternal(fileSrc, fileDest, buf); + } else { + FileInputStream is = null; + FileOutputStream os = null; + try { + is = new FileInputStream(fileSrc); + os = new FileOutputStream(fileDest); + int len = 0; + while (true) { + len = is.read(buf); + if (len == -1) + break; + os.write(buf, 0, len); + } + } catch (IOException e) { + e.printStackTrace(); + result = false; + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException e) { + } + } + if (os != null) { + try { + os.close(); + } catch (IOException e) { + } + } + } + } + } + return result; + + } + + /** * Delete the specified directory, including all of its contents and * subdirectories recursively. 1.136 +33 -1 jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/core/StandardContext.java Index: StandardContext.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/core/StandardContext.java,v retrieving revision 1.135 retrieving revision 1.136 diff -u -r1.135 -r1.136 --- StandardContext.java 26 Jul 2004 08:09:20 -0000 1.135 +++ StandardContext.java 26 Jul 2004 10:56:54 -0000 1.136 @@ -166,6 +166,12 @@ /** + * The antiResourceLocking flag for this Context. + */ + private boolean antiResourceLocking = false; + + + /** * The set of application listener class names configured for this * application, in the order they were encountered in the web.xml file. */ @@ -815,6 +821,32 @@ */ public void setApplicationLifecycleListeners(Object listeners[]) { applicationLifecycleListenersObjects = listeners; + } + + + /** + * Return the antiResourceLocking flag for this Context. + */ + public boolean getAntiResourceLocking() { + + return (this.antiResourceLocking); + + } + + + /** + * Set the application available flag for this Context. + * + * @param available The new application available flag + */ + public void setAntiResourceLocking(boolean antiResourceLocking) { + + boolean oldAntiResourceLocking = this.antiResourceLocking; + this.antiResourceLocking = antiResourceLocking; + support.firePropertyChange("antiResourceLocking", + new Boolean(oldAntiResourceLocking), + new Boolean(this.antiResourceLocking)); + }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]