Author: markt Date: Tue Nov 5 00:06:50 2013 New Revision: 1538836 URL: http://svn.apache.org/r1538836 Log: First cut at adding resource tracking
Added: tomcat/trunk/java/org/apache/catalina/WebResourceTraceWrapper.java tomcat/trunk/java/org/apache/catalina/webresources/TraceWrapperInputStream.java Modified: tomcat/trunk/java/org/apache/catalina/WebResourceRoot.java tomcat/trunk/java/org/apache/catalina/webresources/AbstractResource.java tomcat/trunk/java/org/apache/catalina/webresources/FileResource.java tomcat/trunk/java/org/apache/catalina/webresources/JarResource.java tomcat/trunk/java/org/apache/catalina/webresources/JarResourceRoot.java tomcat/trunk/java/org/apache/catalina/webresources/JarWarResource.java tomcat/trunk/java/org/apache/catalina/webresources/LocalStrings.properties tomcat/trunk/java/org/apache/catalina/webresources/StandardRoot.java Modified: tomcat/trunk/java/org/apache/catalina/WebResourceRoot.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/WebResourceRoot.java?rev=1538836&r1=1538835&r2=1538836&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/WebResourceRoot.java (original) +++ tomcat/trunk/java/org/apache/catalina/WebResourceRoot.java Tue Nov 5 00:06:50 2013 @@ -360,6 +360,33 @@ public interface WebResourceRoot extends long getCacheMaxObjectSize(); /** + * Controls whether the trace locked files feature is enabled. If enabled, + * all calls to methods that return objects that lock a file and need to be + * closed to release that lock (e.g. {@link WebResource#getInputStream()} + * will perform a number of additional tasks. + * <ul> + * <li>The stack trace at the point where the method was called will be + * recorded and associated with the returned object.</li> + * <li>The returned object will be wrapped so that the point where close() + * (or equivalent) is called to release the resources can be detected. + * Tracking of the object will cease once the resources have been + * released.</li> + * <li>All remaining locked resources on web application shutdown will be + * logged and then closed.</li> + * </ul> + * + * @param traceLockedFiles @true to enable it, @false to disable it + */ + void setTraceLockedFiles(boolean traceLockedFiles); + + /** + * Has the trace locked files feature been enabled? + * + * @return @true if it has been enabled, otherwise @false + */ + boolean getTraceLockedFiles(); + + /** * This method will be invoked by the context on a periodic basis and allows * the implementation a method that executes periodic tasks, such as purging * expired cache entries. @@ -372,4 +399,8 @@ public interface WebResourceRoot extends POST, CLASSES_JAR } + + void registerTracedResource(WebResourceTraceWrapper traceWrapper); + + void deregisterTracedResource(WebResourceTraceWrapper traceWrapperInputStream); } Added: tomcat/trunk/java/org/apache/catalina/WebResourceTraceWrapper.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/WebResourceTraceWrapper.java?rev=1538836&view=auto ============================================================================== --- tomcat/trunk/java/org/apache/catalina/WebResourceTraceWrapper.java (added) +++ tomcat/trunk/java/org/apache/catalina/WebResourceTraceWrapper.java Tue Nov 5 00:06:50 2013 @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina; + +import java.io.Closeable; + +public interface WebResourceTraceWrapper extends Closeable { + Exception getCreatedBy(); + String getName(); +} Modified: tomcat/trunk/java/org/apache/catalina/webresources/AbstractResource.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/webresources/AbstractResource.java?rev=1538836&r1=1538835&r2=1538836&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/webresources/AbstractResource.java (original) +++ tomcat/trunk/java/org/apache/catalina/webresources/AbstractResource.java Tue Nov 5 00:06:50 2013 @@ -128,5 +128,19 @@ public abstract class AbstractResource i } + @Override + public final InputStream getInputStream() { + InputStream is = doGetInputStream(); + + if (is == null || !root.getTraceLockedFiles()) { + return is; + } + + return new TraceWrapperInputStream(root, getName(), is); + } + + protected abstract InputStream doGetInputStream(); + + protected abstract Log getLog(); } Modified: tomcat/trunk/java/org/apache/catalina/webresources/FileResource.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/webresources/FileResource.java?rev=1538836&r1=1538835&r2=1538836&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/webresources/FileResource.java (original) +++ tomcat/trunk/java/org/apache/catalina/webresources/FileResource.java Tue Nov 5 00:06:50 2013 @@ -123,7 +123,7 @@ public class FileResource extends Abstra } @Override - public InputStream getInputStream() { + protected InputStream doGetInputStream() { if (resource.exists()) { try { return new FileInputStream(resource); Modified: tomcat/trunk/java/org/apache/catalina/webresources/JarResource.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/webresources/JarResource.java?rev=1538836&r1=1538835&r2=1538836&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/webresources/JarResource.java (original) +++ tomcat/trunk/java/org/apache/catalina/webresources/JarResource.java Tue Nov 5 00:06:50 2013 @@ -39,7 +39,7 @@ public class JarResource extends Abstrac } @Override - public InputStream getInputStream() { + protected InputStream doGetInputStream() { try { JarFile jarFile = new JarFile(getBase()); InputStream is = jarFile.getInputStream(getResource()); Modified: tomcat/trunk/java/org/apache/catalina/webresources/JarResourceRoot.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/webresources/JarResourceRoot.java?rev=1538836&r1=1538835&r2=1538836&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/webresources/JarResourceRoot.java (original) +++ tomcat/trunk/java/org/apache/catalina/webresources/JarResourceRoot.java Tue Nov 5 00:06:50 2013 @@ -104,7 +104,7 @@ public class JarResourceRoot extends Abs } @Override - public InputStream getInputStream() { + protected InputStream doGetInputStream() { return null; } Modified: tomcat/trunk/java/org/apache/catalina/webresources/JarWarResource.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/webresources/JarWarResource.java?rev=1538836&r1=1538835&r2=1538836&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/webresources/JarWarResource.java (original) +++ tomcat/trunk/java/org/apache/catalina/webresources/JarWarResource.java Tue Nov 5 00:06:50 2013 @@ -45,7 +45,7 @@ public class JarWarResource extends Abst } @Override - public InputStream getInputStream() { + protected InputStream doGetInputStream() { try { JarFile warFile = new JarFile(getBase()); JarEntry jarFileInWar = warFile.getJarEntry(archivePath); Modified: tomcat/trunk/java/org/apache/catalina/webresources/LocalStrings.properties URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/webresources/LocalStrings.properties?rev=1538836&r1=1538835&r2=1538836&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/webresources/LocalStrings.properties (original) +++ tomcat/trunk/java/org/apache/catalina/webresources/LocalStrings.properties Tue Nov 5 00:06:50 2013 @@ -33,6 +33,7 @@ standardRoot.checkStateNotStarted=The re standardRoot.createInvalidFile=Unable to create WebResourceSet from [{0}] standardRoot.createNoFileResourceSet=The FileResourceSet feature has not yet been implemented standardRoot.createUnknownType=Unable to create WebResourceSet of unknown type [{0}] +standardRoot.lockedFile=The web application [{0}] failed to close the file [{1}] opened via the following stack trace standardRoot.noContext=A Context has not been configured for this WebResourceRoot standardRoot.startInvalidMain=The main resource set specified [{0}] is not valid standardRoot.unsupportedProtocol=The URL protocol [{0}] is not supported by this web resources implementation \ No newline at end of file Modified: tomcat/trunk/java/org/apache/catalina/webresources/StandardRoot.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/webresources/StandardRoot.java?rev=1538836&r1=1538835&r2=1538836&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/webresources/StandardRoot.java (original) +++ tomcat/trunk/java/org/apache/catalina/webresources/StandardRoot.java Tue Nov 5 00:06:50 2013 @@ -17,6 +17,7 @@ package org.apache.catalina.webresources; import java.io.File; +import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URISyntaxException; @@ -33,7 +34,10 @@ import org.apache.catalina.LifecycleStat import org.apache.catalina.WebResource; import org.apache.catalina.WebResourceRoot; import org.apache.catalina.WebResourceSet; +import org.apache.catalina.WebResourceTraceWrapper; import org.apache.catalina.util.LifecycleMBeanBase; +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.res.StringManager; /** @@ -51,6 +55,7 @@ import org.apache.tomcat.util.res.String public class StandardRoot extends LifecycleMBeanBase implements WebResourceRoot { + private static final Log log = LogFactory.getLog(Cache.class); protected static final StringManager sm = StringManager.getManager(Constants.Package); @@ -65,6 +70,9 @@ public class StandardRoot extends Lifecy private Cache cache = new Cache(this); private boolean cachingAllowed = true; + private boolean traceLockedFiles = false; + private Set<WebResourceTraceWrapper> tracedResources = new HashSet<>(); + // Constructs to make iteration over all WebResourceSets simpler private ArrayList<WebResourceSet> mainResources = new ArrayList<>(); private ArrayList<ArrayList<WebResourceSet>> allResources = @@ -431,6 +439,16 @@ public class StandardRoot extends Lifecy } @Override + public void setTraceLockedFiles(boolean traceLockedFiles) { + this.traceLockedFiles = traceLockedFiles; + } + + @Override + public boolean getTraceLockedFiles() { + return traceLockedFiles; + } + + @Override public Context getContext() { return context; } @@ -483,6 +501,19 @@ public class StandardRoot extends Lifecy cache.backgroundProcess(); } + + @Override + public void registerTracedResource(WebResourceTraceWrapper traceResource) { + tracedResources.add(traceResource); + } + + + @Override + public void deregisterTracedResource(WebResourceTraceWrapper traceResource) { + tracedResources.remove(traceResource); + } + + // ----------------------------------------------------------- JMX Lifecycle @Override protected String getDomainInternal() { @@ -575,6 +606,17 @@ public class StandardRoot extends Lifecy } jarResources.clear(); + for (WebResourceTraceWrapper tracedResource : tracedResources) { + log.error(sm.getString("standardRoot.lockedFile", + context.getName(), + tracedResource.getName()), + tracedResource.getCreatedBy()); + try { + tracedResource.close(); + } catch (IOException e) { + // Ignore + } + } cache.clear(); setState(LifecycleState.STOPPING); Added: tomcat/trunk/java/org/apache/catalina/webresources/TraceWrapperInputStream.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/webresources/TraceWrapperInputStream.java?rev=1538836&view=auto ============================================================================== --- tomcat/trunk/java/org/apache/catalina/webresources/TraceWrapperInputStream.java (added) +++ tomcat/trunk/java/org/apache/catalina/webresources/TraceWrapperInputStream.java Tue Nov 5 00:06:50 2013 @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina.webresources; + +import java.io.IOException; +import java.io.InputStream; + +import org.apache.catalina.WebResourceRoot; +import org.apache.catalina.WebResourceTraceWrapper; + +class TraceWrapperInputStream extends InputStream implements WebResourceTraceWrapper { + + private final WebResourceRoot root; + private final String name; + private final InputStream is; + private final Exception creation; + + TraceWrapperInputStream(WebResourceRoot root, String name, InputStream is) { + this.root = root; + this.name = name; + this.is = is; + this.creation = new Exception(); + + root.registerTracedResource(this); + } + + @Override + public int read() throws IOException { + return is.read(); + } + + @Override + public int read(byte[] b) throws IOException { + return is.read(b); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + return is.read(b, off, len); + } + + @Override + public long skip(long n) throws IOException { + return is.skip(n); + } + + @Override + public int available() throws IOException { + return is.available(); + } + + @Override + public void close() throws IOException { + root.deregisterTracedResource(this); + is.close(); + } + + @Override + public synchronized void mark(int readlimit) { + is.mark(readlimit); + } + + @Override + public synchronized void reset() throws IOException { + is.reset(); + } + + @Override + public boolean markSupported() { + return is.markSupported(); + } + + @Override + public String getName() { + return name; + } + + @Override + public Exception getCreatedBy() { + return creation; + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org