Work in progress on Features

Moved jar discovery to META-INF
This commit is contained in:
Greg Wilkins 2016-03-10 04:41:30 +11:00
parent d41bd264ad
commit 13d914aa7c
2 changed files with 252 additions and 242 deletions

View File

@ -24,21 +24,29 @@ import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
import org.eclipse.jetty.util.PatternMatcher;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.EmptyResource;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceCollection;
/**
* MetaInfConfiguration
@ -65,11 +73,19 @@ public class MetaInfConfiguration extends AbstractConfiguration
public static final boolean DEFAULT_USE_CONTAINER_METAINF_CACHE = true;
public static final String CACHED_CONTAINER_TLDS = "org.eclipse.jetty.tlds.cache";
public static final String CACHED_CONTAINER_FRAGMENTS = FragmentConfiguration.FRAGMENT_RESOURCES+".cache";
public static final String CACHED_CONTAINER_RESOURCES = WebInfConfiguration.RESOURCE_DIRS+".cache";
public static final String CACHED_CONTAINER_RESOURCES = "org.eclipse.jetty.resources.cache";
public static final String METAINF_TLDS = "org.eclipse.jetty.tlds";
public static final String METAINF_FRAGMENTS = FragmentConfiguration.FRAGMENT_RESOURCES;
public static final String METAINF_RESOURCES = WebInfConfiguration.RESOURCE_DIRS;
public static final String METAINF_RESOURCES = "org.eclipse.jetty.resources";
public static final String CONTAINER_JAR_PATTERN = "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern";
public static final String WEBINF_JAR_PATTERN = "org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern";
/**
* If set, to a list of URLs, these resources are added to the context
* resource base as a resource collection.
*/
public static final String RESOURCE_DIRS = "org.eclipse.jetty.resources";
/* ------------------------------------------------------------------------------- */
public MetaInfConfiguration()
{
@ -87,6 +103,53 @@ public class MetaInfConfiguration extends AbstractConfiguration
@Override
public void preConfigure(final WebAppContext context) throws Exception
{
// discover matching container jars
if (context.getClassLoader() != null)
{
ClassLoader loader = context.getClassLoader().getParent();
List<URI> uris = new ArrayList<>();
while (loader != null && (loader instanceof URLClassLoader))
{
URL[] urls = ((URLClassLoader)loader).getURLs();
if (urls != null)
for(URL url:urls)
uris.add(new URI(url.toString().replaceAll(" ","%20")));
loader = loader.getParent();
}
new PatternMatcher ()
{
public void matched(URI uri) throws Exception
{
context.getMetaData().addContainerResource(Resource.newResource(uri));
}
}.match((String)context.getAttribute(CONTAINER_JAR_PATTERN),
uris.toArray(new URI[uris.size()]),
false);
}
//Discover matching WEB-INF/lib jars
List<Resource> jars = findJars(context);
if (jars!=null)
{
List<URI> uris = jars.stream().map(Resource::getURI).collect(Collectors.toList());
new PatternMatcher ()
{
@Override
public void matched(URI uri) throws Exception
{
context.getMetaData().addWebInfJar(Resource.newResource(uri));
}
}.match((String)context.getAttribute(WEBINF_JAR_PATTERN),
uris.toArray(new URI[uris.size()]),
true);
}
//No pattern to appy to classes, just add to metadata
context.getMetaData().setWebInfClassesDirs(findClassDirs(context));
boolean useContainerCache = DEFAULT_USE_CONTAINER_METAINF_CACHE;
Boolean attr = (Boolean)context.getServer().getAttribute(USE_CONTAINER_METAINF_CACHE);
if (attr != null)
@ -107,6 +170,27 @@ public class MetaInfConfiguration extends AbstractConfiguration
scanJars(context, context.getMetaData().getContainerResources(), useContainerCache);
scanJars(context, context.getMetaData().getWebInfJars(), false);
}
@Override
public boolean configure(WebAppContext context) throws Exception
{
// Look for extra resource
@SuppressWarnings("unchecked")
Set<Resource> resources = (Set<Resource>)context.getAttribute(RESOURCE_DIRS);
if (resources!=null && !resources.isEmpty())
{
Resource[] collection=new Resource[resources.size()+1];
int i=0;
collection[i++]=context.getBaseResource();
for (Resource resource : resources)
collection[i++]=resource;
context.setBaseResource(new ResourceCollection(collection));
}
return true;
}
/**
* Look into the jars to discover info in META-INF. If useCaches == true, then we will
@ -434,4 +518,170 @@ public class MetaInfConfiguration extends AbstractConfiguration
jarFile.close();
return tlds;
}
protected List<Resource> findClassDirs (WebAppContext context)
throws Exception
{
if (context == null)
return null;
List<Resource> classDirs = new ArrayList<Resource>();
Resource webInfClasses = findWebInfClassesDir(context);
if (webInfClasses != null)
classDirs.add(webInfClasses);
List<Resource> extraClassDirs = findExtraClasspathDirs(context);
if (extraClassDirs != null)
classDirs.addAll(extraClassDirs);
return classDirs;
}
/**
* Look for jars that should be treated as if they are in WEB-INF/lib
*
* @param context the context to find the jars in
* @return the list of jar resources found within context
* @throws Exception if unable to find the jars
*/
protected List<Resource> findJars (WebAppContext context)
throws Exception
{
List<Resource> jarResources = new ArrayList<Resource>();
List<Resource> webInfLibJars = findWebInfLibJars(context);
if (webInfLibJars != null)
jarResources.addAll(webInfLibJars);
List<Resource> extraClasspathJars = findExtraClasspathJars(context);
if (extraClasspathJars != null)
jarResources.addAll(extraClasspathJars);
return jarResources;
}
/**
* Look for jars in <code>WEB-INF/lib</code>
*
* @param context the context to find the lib jars in
* @return the list of jars as {@link Resource}
* @throws Exception if unable to scan for lib jars
*/
protected List<Resource> findWebInfLibJars(WebAppContext context)
throws Exception
{
Resource web_inf = context.getWebInf();
if (web_inf==null || !web_inf.exists())
return null;
List<Resource> jarResources = new ArrayList<Resource>();
Resource web_inf_lib = web_inf.addPath("/lib");
if (web_inf_lib.exists() && web_inf_lib.isDirectory())
{
String[] files=web_inf_lib.list();
for (int f=0;files!=null && f<files.length;f++)
{
try
{
Resource file = web_inf_lib.addPath(files[f]);
String fnlc = file.getName().toLowerCase(Locale.ENGLISH);
int dot = fnlc.lastIndexOf('.');
String extension = (dot < 0 ? null : fnlc.substring(dot));
if (extension != null && (extension.equals(".jar") || extension.equals(".zip")))
{
jarResources.add(file);
}
}
catch (Exception ex)
{
LOG.warn(Log.EXCEPTION,ex);
}
}
}
return jarResources;
}
/**
* Get jars from WebAppContext.getExtraClasspath as resources
*
* @param context the context to find extra classpath jars in
* @return the list of Resources with the extra classpath, or null if not found
* @throws Exception if unable to find the extra classpath jars
*/
protected List<Resource> findExtraClasspathJars(WebAppContext context)
throws Exception
{
if (context == null || context.getExtraClasspath() == null)
return null;
List<Resource> jarResources = new ArrayList<Resource>();
StringTokenizer tokenizer = new StringTokenizer(context.getExtraClasspath(), ",;");
while (tokenizer.hasMoreTokens())
{
Resource resource = context.newResource(tokenizer.nextToken().trim());
String fnlc = resource.getName().toLowerCase(Locale.ENGLISH);
int dot = fnlc.lastIndexOf('.');
String extension = (dot < 0 ? null : fnlc.substring(dot));
if (extension != null && (extension.equals(".jar") || extension.equals(".zip")))
{
jarResources.add(resource);
}
}
return jarResources;
}
/**
* Get <code>WEB-INF/classes</code> dir
*
* @param context the context to look for the <code>WEB-INF/classes</code> directory
* @return the Resource for the <code>WEB-INF/classes</code> directory
* @throws Exception if unable to find the <code>WEB-INF/classes</code> directory
*/
protected Resource findWebInfClassesDir (WebAppContext context)
throws Exception
{
if (context == null)
return null;
Resource web_inf = context.getWebInf();
// Find WEB-INF/classes
if (web_inf != null && web_inf.isDirectory())
{
// Look for classes directory
Resource classes= web_inf.addPath("classes/");
if (classes.exists())
return classes;
}
return null;
}
/**
* Get class dirs from WebAppContext.getExtraClasspath as resources
*
* @param context the context to look for extra classpaths in
* @return the list of Resources to the extra classpath
* @throws Exception if unable to find the extra classpaths
*/
protected List<Resource> findExtraClasspathDirs(WebAppContext context)
throws Exception
{
if (context == null || context.getExtraClasspath() == null)
return null;
List<Resource> dirResources = new ArrayList<Resource>();
StringTokenizer tokenizer = new StringTokenizer(context.getExtraClasspath(), ",;");
while (tokenizer.hasMoreTokens())
{
Resource resource = context.newResource(tokenizer.nextToken().trim());
if (resource.exists() && resource.isDirectory())
dirResources.add(resource);
}
return dirResources;
}
}

View File

@ -20,21 +20,12 @@ package org.eclipse.jetty.webapp;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.stream.Collectors;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.NetworkConnector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.PatternMatcher;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -47,15 +38,6 @@ public class WebInfConfiguration extends AbstractConfiguration
private static final Logger LOG = Log.getLogger(WebInfConfiguration.class);
public static final String TEMPDIR_CONFIGURED = "org.eclipse.jetty.tmpdirConfigured";
public static final String CONTAINER_JAR_PATTERN = "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern";
public static final String WEBINF_JAR_PATTERN = "org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern";
/**
* If set, to a list of URLs, these resources are added to the context
* resource base as a resource collection.
*/
public static final String RESOURCE_DIRS = "org.eclipse.jetty.resources";
protected Resource _preUnpackBaseResource;
@ -79,52 +61,6 @@ public class WebInfConfiguration extends AbstractConfiguration
//Extract webapp if necessary
unpack (context);
// discover matching container jars
if (context.getClassLoader() != null)
{
ClassLoader loader = context.getClassLoader().getParent();
List<URI> uris = new ArrayList<>();
while (loader != null && (loader instanceof URLClassLoader))
{
URL[] urls = ((URLClassLoader)loader).getURLs();
if (urls != null)
for(URL url:urls)
uris.add(new URI(url.toString().replaceAll(" ","%20")));
loader = loader.getParent();
}
new PatternMatcher ()
{
public void matched(URI uri) throws Exception
{
context.getMetaData().addContainerResource(Resource.newResource(uri));
}
}.match((String)context.getAttribute(CONTAINER_JAR_PATTERN),
uris.toArray(new URI[uris.size()]),
false);
}
//Discover matcghing WEB-INF/lib jars
List<Resource> jars = findJars(context);
if (jars!=null)
{
List<URI> uris = jars.stream().map(Resource::getURI).collect(Collectors.toList());
new PatternMatcher ()
{
@Override
public void matched(URI uri) throws Exception
{
context.getMetaData().addWebInfJar(Resource.newResource(uri));
}
}.match((String)context.getAttribute(WEBINF_JAR_PATTERN),
uris.toArray(new URI[uris.size()]),
true);
}
//No pattern to appy to classes, just add to metadata
context.getMetaData().setWebInfClassesDirs(findClassDirs(context));
}
@ -147,18 +83,6 @@ public class WebInfConfiguration extends AbstractConfiguration
((WebAppClassLoader)context.getClassLoader()).addJars(lib);
}
// Look for extra resource
@SuppressWarnings("unchecked")
Set<Resource> resources = (Set<Resource>)context.getAttribute(RESOURCE_DIRS);
if (resources!=null && !resources.isEmpty())
{
Resource[] collection=new Resource[resources.size()+1];
int i=0;
collection[i++]=context.getBaseResource();
for (Resource resource : resources)
collection[i++]=resource;
context.setBaseResource(new ResourceCollection(collection));
}
return true;
}
@ -634,169 +558,5 @@ public class WebInfConfiguration extends AbstractConfiguration
}
protected List<Resource> findClassDirs (WebAppContext context)
throws Exception
{
if (context == null)
return null;
List<Resource> classDirs = new ArrayList<Resource>();
Resource webInfClasses = findWebInfClassesDir(context);
if (webInfClasses != null)
classDirs.add(webInfClasses);
List<Resource> extraClassDirs = findExtraClasspathDirs(context);
if (extraClassDirs != null)
classDirs.addAll(extraClassDirs);
return classDirs;
}
/**
* Look for jars that should be treated as if they are in WEB-INF/lib
*
* @param context the context to find the jars in
* @return the list of jar resources found within context
* @throws Exception if unable to find the jars
*/
protected List<Resource> findJars (WebAppContext context)
throws Exception
{
List<Resource> jarResources = new ArrayList<Resource>();
List<Resource> webInfLibJars = findWebInfLibJars(context);
if (webInfLibJars != null)
jarResources.addAll(webInfLibJars);
List<Resource> extraClasspathJars = findExtraClasspathJars(context);
if (extraClasspathJars != null)
jarResources.addAll(extraClasspathJars);
return jarResources;
}
/**
* Look for jars in <code>WEB-INF/lib</code>
*
* @param context the context to find the lib jars in
* @return the list of jars as {@link Resource}
* @throws Exception if unable to scan for lib jars
*/
protected List<Resource> findWebInfLibJars(WebAppContext context)
throws Exception
{
Resource web_inf = context.getWebInf();
if (web_inf==null || !web_inf.exists())
return null;
List<Resource> jarResources = new ArrayList<Resource>();
Resource web_inf_lib = web_inf.addPath("/lib");
if (web_inf_lib.exists() && web_inf_lib.isDirectory())
{
String[] files=web_inf_lib.list();
for (int f=0;files!=null && f<files.length;f++)
{
try
{
Resource file = web_inf_lib.addPath(files[f]);
String fnlc = file.getName().toLowerCase(Locale.ENGLISH);
int dot = fnlc.lastIndexOf('.');
String extension = (dot < 0 ? null : fnlc.substring(dot));
if (extension != null && (extension.equals(".jar") || extension.equals(".zip")))
{
jarResources.add(file);
}
}
catch (Exception ex)
{
LOG.warn(Log.EXCEPTION,ex);
}
}
}
return jarResources;
}
/**
* Get jars from WebAppContext.getExtraClasspath as resources
*
* @param context the context to find extra classpath jars in
* @return the list of Resources with the extra classpath, or null if not found
* @throws Exception if unable to find the extra classpath jars
*/
protected List<Resource> findExtraClasspathJars(WebAppContext context)
throws Exception
{
if (context == null || context.getExtraClasspath() == null)
return null;
List<Resource> jarResources = new ArrayList<Resource>();
StringTokenizer tokenizer = new StringTokenizer(context.getExtraClasspath(), ",;");
while (tokenizer.hasMoreTokens())
{
Resource resource = context.newResource(tokenizer.nextToken().trim());
String fnlc = resource.getName().toLowerCase(Locale.ENGLISH);
int dot = fnlc.lastIndexOf('.');
String extension = (dot < 0 ? null : fnlc.substring(dot));
if (extension != null && (extension.equals(".jar") || extension.equals(".zip")))
{
jarResources.add(resource);
}
}
return jarResources;
}
/**
* Get <code>WEB-INF/classes</code> dir
*
* @param context the context to look for the <code>WEB-INF/classes</code> directory
* @return the Resource for the <code>WEB-INF/classes</code> directory
* @throws Exception if unable to find the <code>WEB-INF/classes</code> directory
*/
protected Resource findWebInfClassesDir (WebAppContext context)
throws Exception
{
if (context == null)
return null;
Resource web_inf = context.getWebInf();
// Find WEB-INF/classes
if (web_inf != null && web_inf.isDirectory())
{
// Look for classes directory
Resource classes= web_inf.addPath("classes/");
if (classes.exists())
return classes;
}
return null;
}
/**
* Get class dirs from WebAppContext.getExtraClasspath as resources
*
* @param context the context to look for extra classpaths in
* @return the list of Resources to the extra classpath
* @throws Exception if unable to find the extra classpaths
*/
protected List<Resource> findExtraClasspathDirs(WebAppContext context)
throws Exception
{
if (context == null || context.getExtraClasspath() == null)
return null;
List<Resource> dirResources = new ArrayList<Resource>();
StringTokenizer tokenizer = new StringTokenizer(context.getExtraClasspath(), ",;");
while (tokenizer.hasMoreTokens())
{
Resource resource = context.newResource(tokenizer.nextToken().trim());
if (resource.exists() && resource.isDirectory())
dirResources.add(resource);
}
return dirResources;
}
}