All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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