477895 Prevent leak of handles to deleted files after redeploy

This commit is contained in:
Jan Bartel 2015-09-28 09:46:55 +10:00
parent 6300480c0b
commit 697b0cccf2
7 changed files with 89 additions and 28 deletions

View File

@ -88,7 +88,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
protected CounterStatistic _webInfLibStats;
protected CounterStatistic _webInfClassesStats;
protected Pattern _sciExcludePattern;
protected ServiceLoader<ServletContainerInitializer> _loadedInitializers = null;
/**
* TimeStatistic
*
@ -413,6 +413,9 @@ public class AnnotationConfiguration extends AbstractConfiguration
context.removeBean(starter);
context.removeAttribute(CONTAINER_INITIALIZER_STARTER);
}
if (_loadedInitializers != null)
_loadedInitializers.reload();
}
/**
@ -735,7 +738,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
loadingJarName = loadingJarName.substring(0,i+4);
loadingJarName = (loadingJarName.startsWith("jar:")?loadingJarName.substring(4):loadingJarName);
return Resource.newResource(loadingJarName);
return Resource.newResource(loadingJarName, false);
}
/**
@ -823,22 +826,33 @@ public class AnnotationConfiguration extends AbstractConfiguration
return sci.getClass().getClassLoader()==context.getClassLoader().getParent();
}
/**
* Get SCIs that are not excluded from consideration
* @param context
* @return
* @throws Exception
*/
/**
* @param context
* @return
* @throws Exception
*/
public List<ServletContainerInitializer> getNonExcludedInitializers (WebAppContext context)
throws Exception
{
ArrayList<ServletContainerInitializer> nonExcludedInitializers = new ArrayList<ServletContainerInitializer>();
//We use the ServiceLoader mechanism to find the ServletContainerInitializer classes to inspect
long start = 0;
ClassLoader old = Thread.currentThread().getContextClassLoader();
ServiceLoader<ServletContainerInitializer> loadedInitializers = null;
try
{
if (LOG.isDebugEnabled())
start = System.nanoTime();
Thread.currentThread().setContextClassLoader(context.getClassLoader());
loadedInitializers = ServiceLoader.load(ServletContainerInitializer.class);
_loadedInitializers = ServiceLoader.load(ServletContainerInitializer.class);
}
finally
{
@ -847,21 +861,22 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (LOG.isDebugEnabled())
LOG.debug("Service loaders found in {}ms", (TimeUnit.MILLISECONDS.convert((System.nanoTime()-start), TimeUnit.NANOSECONDS)));
Map<ServletContainerInitializer,Resource> sciResourceMap = new HashMap<ServletContainerInitializer,Resource>();
ServletContainerInitializerOrdering initializerOrdering = getInitializerOrdering(context);
//Get initial set of SCIs that aren't from excluded jars or excluded by the containerExclusionPattern, or excluded
//because containerInitializerOrdering omits it
for (ServletContainerInitializer sci:loadedInitializers)
{
for (ServletContainerInitializer sci:_loadedInitializers)
{
if (matchesExclusionPattern(sci))
{
if (LOG.isDebugEnabled()) LOG.debug("{} excluded by pattern", sci);
continue;
}
Resource sciResource = getJarFor(sci);
if (isFromExcludedJar(context, sci, sciResource))
{
@ -921,7 +936,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
{
for (Map.Entry<ServletContainerInitializer, Resource> entry:sciResourceMap.entrySet())
{
if (webInfJar.equals(entry.getValue()))
if (webInfJar.equals(entry.getValue()))
nonExcludedInitializers.add(entry.getKey());
}
}
@ -933,7 +948,8 @@ public class AnnotationConfiguration extends AbstractConfiguration
int i=0;
for (ServletContainerInitializer sci:nonExcludedInitializers)
LOG.debug("ServletContainerInitializer: {} {} from {}",(++i), sci.getClass().getName(), sciResourceMap.get(sci));
}
}
return nonExcludedInitializers;
}

View File

@ -562,7 +562,10 @@ public class AnnotationParser
if (resource!= null)
{
Resource r = Resource.newResource(resource);
scanClass(handlers, null, r.getInputStream());
try (InputStream is = r.getInputStream())
{
scanClass(handlers, null, is);
}
}
}
}
@ -594,7 +597,10 @@ public class AnnotationParser
if (resource!= null)
{
Resource r = Resource.newResource(resource);
scanClass(handlers, null, r.getInputStream());
try (InputStream is = r.getInputStream())
{
scanClass(handlers, null, is);
}
}
}
}
@ -650,7 +656,10 @@ public class AnnotationParser
if (resource!= null)
{
Resource r = Resource.newResource(resource);
scanClass(handlers, null, r.getInputStream());
try (InputStream is = r.getInputStream())
{
scanClass(handlers, null, is);
}
}
}
}
@ -845,8 +854,11 @@ public class AnnotationParser
if (fullname.endsWith(".class"))
{
scanClass(handlers, null, r.getInputStream());
return;
try (InputStream is=r.getInputStream())
{
scanClass(handlers, null, is);
return;
}
}
if (LOG.isDebugEnabled()) LOG.warn("Resource not scannable for classes: {}", r);
@ -963,11 +975,14 @@ public class AnnotationParser
if ((resolver == null)
||
(!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName))))
(!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName))))
{
Resource clazz = Resource.newResource("jar:"+jar.getURI()+"!/"+name);
Resource clazz = Resource.newResource("jar:"+jar.getURI()+"!/"+name,false);
if (LOG.isDebugEnabled()) {LOG.debug("Scanning class from jar {}", clazz);};
scanClass(handlers, jar, clazz.getInputStream());
try (InputStream is = clazz.getInputStream())
{
scanClass(handlers, jar, is);
}
}
}
}

View File

@ -26,6 +26,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;
@ -156,9 +157,10 @@ public class JarResource extends URLResource
if (LOG.isDebugEnabled())
LOG.debug("Extracting entry = "+subEntryName+" from jar "+jarFileURL);
try (InputStream is = jarFileURL.openConnection().getInputStream();
JarInputStream jin = new JarInputStream(is))
URLConnection c = jarFileURL.openConnection();
c.setUseCaches(false);
try (InputStream is = c.getInputStream();
JarInputStream jin = new JarInputStream(is))
{
JarEntry entry;
boolean shouldExtract;

View File

@ -181,10 +181,14 @@ public class MetaInfConfiguration extends AbstractConfiguration
{
//Resource represents a packed jar
URI uri = target.getURI();
resourcesDir = Resource.newResource("jar:"+uri+"!/META-INF/resources");
resourcesDir = Resource.newResource("jar:"+uri+"!/META-INF/resources", false);
}
if (!resourcesDir.exists() || !resourcesDir.isDirectory())
{
resourcesDir.close();
resourcesDir = EmptyResource.INSTANCE;
}
if (cache != null)
{
@ -196,7 +200,9 @@ public class MetaInfConfiguration extends AbstractConfiguration
}
if (resourcesDir == EmptyResource.INSTANCE)
{
return;
}
}
//add it to the meta inf resources for this context
@ -207,6 +213,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
context.setAttribute(METAINF_RESOURCES, dirs);
}
if (LOG.isDebugEnabled()) LOG.debug(resourcesDir+" added to context");
dirs.add(resourcesDir);
}
@ -245,10 +252,13 @@ public class MetaInfConfiguration extends AbstractConfiguration
else
{
URI uri = jar.getURI();
webFrag = Resource.newResource("jar:"+uri+"!/META-INF/web-fragment.xml");
webFrag = Resource.newResource("jar:"+uri+"!/META-INF/web-fragment.xml", false);
}
if (!webFrag.exists() || webFrag.isDirectory())
{
webFrag.close();
webFrag = EmptyResource.INSTANCE;
}
if (cache != null)
{
@ -342,8 +352,10 @@ public class MetaInfConfiguration extends AbstractConfiguration
@Override
public void postConfigure(WebAppContext context) throws Exception
{
context.setAttribute(METAINF_FRAGMENTS, null);
context.setAttribute(METAINF_RESOURCES, null);
context.setAttribute(METAINF_FRAGMENTS, null);
context.setAttribute(METAINF_TLDS, null);
}
@ -392,7 +404,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
URL url = new URL("jar:"+uri+"!/");
JarURLConnection jarConn = (JarURLConnection) url.openConnection();
jarConn.setUseCaches(Resource.getDefaultUseCaches());
jarConn.setUseCaches(false);
JarFile jarFile = jarConn.getJarFile();
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements())

View File

@ -599,6 +599,13 @@ public class WebAppClassLoader extends URLClassLoader
return clazz;
}
@Override
public void close() throws IOException
{
super.close();
}
/* ------------------------------------------------------------ */
@Override
public String toString()

View File

@ -22,6 +22,7 @@ import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.PermissionCollection;
import java.util.ArrayList;
import java.util.Arrays;
@ -59,6 +60,7 @@ import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.util.AttributesMap;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.URIUtil;
@ -1354,7 +1356,12 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
finally
{
if (_ownClassLoader)
{
ClassLoader loader = getClassLoader();
if (loader != null && loader instanceof URLClassLoader)
((URLClassLoader)loader).close();
setClassLoader(null);
}
setAvailable(true);
_unavailableException=null;

View File

@ -192,15 +192,17 @@ public class WebInfConfiguration extends AbstractConfiguration
//if we're not persisting the temp dir contents delete it
if (!context.isPersistTempDirectory())
{
IO.delete(context.getTempDirectory());
IO.delete(context.getTempDirectory());
}
//if it wasn't explicitly configured by the user, then unset it
Boolean tmpdirConfigured = (Boolean)context.getAttribute(TEMPDIR_CONFIGURED);
Boolean tmpdirConfigured = (Boolean)context.getAttribute(TEMPDIR_CONFIGURED);
if (tmpdirConfigured != null && !tmpdirConfigured)
context.setTempDirectory(null);
//reset the base resource back to what it was before we did any unpacking of resources
if (context.getBaseResource() != null)
context.getBaseResource().close();
context.setBaseResource(_preUnpackBaseResource);
}