com.digitalreasoning.herman.ResourceFinder Maven / Gradle / Ivy
/**
* Copyright 2013 Digital Reasoning Systems, Inc.
*
* Licensed 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 com.digitalreasoning.herman;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.net.JarURLConnection;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*
* This class returns nested jars under the URL protocol jarjar. JarJarUrlStreamHandler will have to be registered inorder to access these resources.
*/
class ResourceFinder
{
private static final Logger logger = LoggerFactory.getLogger(ResourceFinder.class);
static
{
HermanUrlStreamHandler.register();
}
private final ClassLoader classLoader;
public ResourceFinder()
{
this.classLoader = Thread.currentThread().getContextClassLoader();
}
public ResourceFinder(ClassLoader classLoader)
{
this.classLoader = classLoader;
}
public Map> getNestedJars(String uri) throws IOException
{
Map> resources = new HashMap>();
if (!uri.endsWith("/"))
{
uri += "/";
}
Enumeration urls = classLoader.getResources(uri);
Pattern uriEnding = Pattern.compile("/?" + Pattern.quote(uri) + "$");
while (urls.hasMoreElements())
{
URL location = urls.nextElement();
try
{
if (location.getProtocol().equals("jar"))
{
List jarUrls = readJarEntries(location, uri);
if(!jarUrls.isEmpty())
{
resources.put(location, jarUrls);
}
}
else if (location.getProtocol().equals("file"))
{
File root;
try {
root = new File(location.toURI());
} catch(URISyntaxException e) {
root = new File(location.getPath());
}
final File[] jarFiles = root.listFiles(new FilenameFilter()
{
@Override
public boolean accept(final File dir, final String name)
{
return name.endsWith(".jar");
}
});
if(jarFiles != null)
{
List jarUrls = new ArrayList();
for(File file: jarFiles)
{
jarUrls.add(file.toURI().toURL());
}
resources.put(location, jarUrls);
}
}
else
{
final String spec = uriEnding.matcher(location.toString()).replaceAll("");
URL jarUrl = new URL(spec);
List jarUrls = null;
try
{
jarUrls = readJarEntriesForArbitraryUrl(jarUrl, uri);
}
catch (RuntimeException e)
{
logger.warn("Got exception trying to read from " + jarUrl, e);
throw e;
}
catch (Error e)
{
logger.warn("Got error trying to read from " + jarUrl, e);
throw e;
}
if(!jarUrls.isEmpty())
{
resources.put(location, jarUrls);
}
}
}
catch (Exception e)
{
throw new RuntimeException("Failed to read jar entries from : " + location, e);
}
}
return resources;
}
private List readJarEntriesForArbitraryUrl(final URL jarUrl, final String basePath) throws IOException
{
logger.debug("Unrecognized procotol, so we are going to try searching the jar at " + jarUrl);
final InputStream in = jarUrl.openStream();
final JarInputStream jarInputStream;
if(in instanceof JarInputStream)
{
logger.debug("Url provided a JarInputStream, so we're going to use it.");
jarInputStream = (JarInputStream) in;
}
else
{
logger.debug("Url provided something other than a JarInputStream, we will wrap it with a JarInputStream.");
jarInputStream = new JarInputStream(in);
}
List entryUrls = new ArrayList();
for(JarEntry entry = jarInputStream.getNextJarEntry(); entry != null; entry = jarInputStream.getNextJarEntry())
{
String entryName = entry.getName();
logger.debug("Trying entry " + entryName);
if (entry.isDirectory() || !entryName.startsWith(basePath) || entryName.length() == basePath.length())
{
continue;
}
String jarName = entryName.substring(basePath.length());
if (jarName.contains("/"))
{
continue;
}
final URL resource;
if(!jarUrl.toString().contains(HermanUrlStreamHandler.JAR_SEPARATOR))
{
resource = new URL(jarUrl.toString() + "/" + entryName);
}
else
{
resource = new URL(null, "herman:" + jarUrl.toString() + "/" + entryName + HermanUrlStreamHandler.HERMAN_SEPARATOR, HermanUrlStreamHandler.INSTANCE);
}
logger.debug("Found embedded jar " + resource + " inside jar " + jarUrl);
entryUrls.add(resource);
}
logger.info("Found " + entryUrls.size() + " embedded jars in " + jarUrl);
return entryUrls;
}
static List readJarEntries(URL location, String basePath) throws IOException {
JarURLConnection conn = (JarURLConnection) location.openConnection();
JarFile jarfile = null;
jarfile = conn.getJarFile();
Enumeration entries = jarfile.entries();
List entryUrls = new ArrayList();
while (entries != null && entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
String name = entry.getName();
if (entry.isDirectory() || !name.startsWith(basePath) || name.length() == basePath.length()) {
continue;
}
name = name.substring(basePath.length());
if (name.contains("/")) {
continue;
}
URL resource = new URL(HermanUrlStreamHandler.PROTOCOL + ":" + location.toString() + name + HermanUrlStreamHandler.HERMAN_SEPARATOR);
entryUrls.add(resource);
}
return entryUrls;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy