com.digitalreasoning.herman.HermanUrlStreamHandler 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.FileOutputStream;
import java.io.IOError;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Pattern;
import org.kohsuke.MetaInfServices;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@MetaInfServices(URLStreamHandler.class)
public class HermanUrlStreamHandler extends URLStreamHandler
{
private static final Logger logger = LoggerFactory.getLogger(HermanUrlStreamHandler.class);
public static final String PROTOCOL = "herman";
public static final String HERMAN_SEPARATOR = "^/";
static final String JAR_SEPARATOR = "!/";
public static final HermanUrlStreamHandler INSTANCE = new HermanUrlStreamHandler();
private static File EXTRACT_DIR;
static {
doRegister();
EXTRACT_DIR = new File(System.getProperty("java.io.tmpdir"), "herman-" + UUID.randomUUID());
EXTRACT_DIR.mkdirs();
}
static void doRegister()
{
try
{
URL.setURLStreamHandlerFactory(new HermanUrlStreamHandler.HermanURLStreamHandlerFactory());
}
catch(Error e)
{
// suppress error - let's hope something picks up via service loader
}
// hack for jboss support
try
{
logger.debug("Trying jboss url stream handler hack...");
Class> moduleClass = getJBossModuleClass();
Method moduleForClassMethod = moduleClass.getMethod("forClass", Class.class);
Object module = moduleForClassMethod.invoke(null, HermanUrlStreamHandler.class);
if(module == null)
{
throw new IllegalStateException("Herman apparently was not loaded by a module?");
}
Method registerUrlHandlerMethod = moduleClass.getMethod("registerURLStreamHandlerFactoryModule", moduleClass);
registerUrlHandlerMethod.invoke(null, module);
logger.debug("Jboss url stream handler hack complete...");
}
catch (ClassNotFoundException e)
{
logger.debug("Could not find jboss Module class, not doing hacky jboss registration strategy.", e);
}
catch (NoSuchMethodException e)
{
logger.debug("Could not find jboss Module class, not doing hacky jboss registration strategy.", e);
throw new IllegalStateException("Could not locate necessary method for jboss hack.", e);
}
catch (InvocationTargetException e)
{
logger.debug("Could not find jboss Module class, not doing hacky jboss registration strategy.", e);
throw new IllegalStateException("Could not load herman as a url module.", e);
}
catch (IllegalAccessException e)
{
logger.debug("Could not find jboss Module class, not doing hacky jboss registration strategy.", e);
throw new IllegalStateException("Could not load herman as a url module.", e);
}
}
private static Class> getJBossModuleClass() throws ClassNotFoundException
{
final String moduleClassName = "org.jboss.modules.Module";
try
{
return HermanUrlStreamHandler.class.getClassLoader().loadClass(moduleClassName);
}
catch (ClassNotFoundException e)
{
try
{
return Thread.currentThread().getContextClassLoader().loadClass(moduleClassName);
}
catch (ClassNotFoundException e1)
{
return ClassLoader.getSystemClassLoader().loadClass(moduleClassName);
}
}
}
public static void register()
{
// do nothing! - this still registers due to static block if this is the first time that this is called
}
public static class HermanURLStreamHandlerFactory implements URLStreamHandlerFactory
{
public URLStreamHandler createURLStreamHandler(String protocol)
{
if (protocol.equals(PROTOCOL))
{
return INSTANCE;
}
return null;
}
}
private final Map jarFileCache = new HashMap();
private File getJarFile(String jarUrl) throws IOException
{
if (!jarFileCache.containsKey(jarUrl))
{
URL url = new URL(jarUrl);
URLConnection embededJarCon = url.openConnection();
InputStream input = embededJarCon.getInputStream();
File tempJar = File.createTempFile(PROTOCOL + "-", ".jar", EXTRACT_DIR);
tempJar.deleteOnExit();
OutputStream output = new FileOutputStream(tempJar);
try
{
byte[] buffer = new byte[4096];
int n = 0;
while (-1 != (n = input.read(buffer)))
{
output.write(buffer, 0, n);
}
}
catch (Exception e)
{
throw new IOError(e);
}
finally
{
try
{
if (input != null)
{
input.close();
}
}
catch (IOException ioe)
{
throw new IOError(ioe);
}
try
{
if (output != null)
{
output.close();
}
}
catch (IOException ioe)
{
throw new IOError(ioe);
}
}
jarFileCache.put(jarUrl, tempJar);
}
return jarFileCache.get(jarUrl);
}
final Pattern hermanUrlSplitter = Pattern.compile(HERMAN_SEPARATOR, Pattern.LITERAL);
@Override
protected URLConnection openConnection(final URL url) throws IOException
{
File jarFile = null;
String resource;
try
{
String urlFile = URLDecoder.decode(url.getFile(), "UTF-8");
if (!urlFile.contains(HERMAN_SEPARATOR))
{
URI uri = new URI(urlFile);
if(uri.getScheme() == null)
{
throw new MalformedURLException("Url " + url + " does not have a sub-protocol. Herman protocols are required to have a sub-protocol.");
}
return uri.toURL().openConnection();
}
String[] parts = hermanUrlSplitter.split(urlFile);
if (parts.length > 2)
{
throw new IllegalArgumentException("Url " + url + " contains multiple '^' separators. We cannot handle that.");
}
String jarUrl = parts[0];
resource = parts.length < 2 ? "" : parts[1];
jarFile = getJarFile(jarUrl);
}
catch (MalformedURLException e)
{
throw e;
}
catch (Exception e)
{
final IOError ioError = new IOError(e);
throw ioError;
}
return new URL("jar:" + jarFile.toURI().toURL() + HermanUrlStreamHandler.JAR_SEPARATOR + resource).openConnection();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy