package net.sourceforge.javautil.common;
import java.net.URL;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Logger;
import net.sourceforge.javautil.common.classloader.ClassLoaderResource;
import net.sourceforge.javautil.common.classloader.ClassLoaderScanner;
import net.sourceforge.javautil.common.exception.ThrowableManagerRegistry;
import net.sourceforge.javautil.common.io.VirtualArtifactSystem;
import net.sourceforge.javautil.common.io.VirtualArtifactURLStreamHandler;
import net.sourceforge.javautil.common.io.VirtualArtifactSystem.*;
/**
* A handler factory composite allowing registry of many handlers at runtime. This will automatically
* register the {@link VirtualArtifactSystem#VAS_PROTOCOL} protocol.<br/><br/>
*
* This will detect the {@value #SUN_PROTOCOL_PACKAGE} if it exists.
*
* @author elponderador
* @author $Author$
* @version $Id$
*/
public class URLStreamHandlerFactoryComposite implements URLStreamHandlerFactory {
public static void main(String[] args) {
ClassLoaderResource rsc = ClassLoaderScanner.getClassResource(SUN_DETECT_CLASS);
System.out.println(rsc);
}
protected static final String SUN_PROTOCOL_PACKAGE = "sun.net.www.protocol.";
protected static final String SUN_DETECT_CLASS = SUN_PROTOCOL_PACKAGE + "file.Handler";
protected static final Logger log = Logger.getLogger(URLStreamHandlerFactoryComposite.class.getName());
protected static final List<String> prefixes = new CopyOnWriteArrayList<String>();
static {
if (ReflectionUtil.classExists(SUN_DETECT_CLASS)) {
prefixes.add(SUN_PROTOCOL_PACKAGE);
}
}
/**
* sun.net.www.protocol. Will have the first shot at protocol resolution. If you must override
* this you should register this {@link URLStreamHandlerFactory} via {@link URL#setURLStreamHandlerFactory(URLStreamHandlerFactory)}.
*
* @param prefix The package prefix (including the ending '.')
*/
public static void registerPrefix (String prefix) { prefixes.add(prefix); }
public final Map<String,URLStreamHandler> handlers = Collections.synchronizedMap( new LinkedHashMap<String, URLStreamHandler>() );
public final List<URLStreamHandlerFactory> factories = Collections.synchronizedList( new ArrayList<URLStreamHandlerFactory>() );
public URLStreamHandlerFactoryComposite () {
this.handlers.put(VirtualArtifactSystem.VAS_PROTOCOL, new VirtualArtifactURLStreamHandler());
}
public URLStreamHandler createURLStreamHandler(String protocol) {
if (this.handlers.containsKey(protocol))
return this.handlers.get(protocol);
for (URLStreamHandlerFactory factory : new ArrayList<URLStreamHandlerFactory>(this.factories)) {
URLStreamHandler handler = factory.createURLStreamHandler(protocol);
if (handler != null) return handler;
}
try {
for (String prefix : new ArrayList<String>(prefixes)) {
Class clazz = Class.forName(prefix + protocol + ".Handler");
handlers.put(protocol, (URLStreamHandler) clazz.newInstance());
return handlers.get(protocol);
}
} catch (ClassNotFoundException e) {
// Ignore this, just means the protocol is not available or we are not in the sun JVM
} catch (Exception e) {
throw ThrowableManagerRegistry.caught(e);
}
log.warning("Could not find protocol handler for: " + protocol);
return null;
}
}