blob: 10c5d0372f0f200837e628d0914a573dc2a917aa [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.osgi.framework.internal.protocol;
import java.lang.reflect.Method;
import java.net.*;
import java.security.AccessController;
import java.util.*;
import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor;
import org.eclipse.osgi.framework.internal.core.Constants;
import org.eclipse.osgi.framework.internal.core.Msg;
import org.eclipse.osgi.framework.log.FrameworkLogEntry;
import org.eclipse.osgi.framework.util.SecureAction;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.BundleContext;
import org.osgi.service.url.URLConstants;
import org.osgi.util.tracker.ServiceTracker;
/**
* This class contains the URL stream handler factory for the OSGi framework.
*/
public class StreamHandlerFactory extends MultiplexingFactory implements URLStreamHandlerFactory {
static final SecureAction secureAction = (SecureAction) AccessController.doPrivileged(SecureAction.createSecureAction());
private ServiceTracker handlerTracker;
protected static final String URLSTREAMHANDLERCLASS = "org.osgi.service.url.URLStreamHandlerService"; //$NON-NLS-1$
protected static final String PROTOCOL_HANDLER_PKGS = "java.protocol.handler.pkgs"; //$NON-NLS-1$
protected static final String INTERNAL_PROTOCOL_HANDLER_PKG = "org.eclipse.osgi.framework.internal.protocol"; //$NON-NLS-1$
private static final List ignoredClasses = Arrays.asList(new Class[] {MultiplexingURLStreamHandler.class, StreamHandlerFactory.class, URL.class});
private static final boolean useNetProxy;
static {
Class clazz = null;
try {
clazz = Class.forName("java.net.Proxy"); //$NON-NLS-1$
} catch (ClassNotFoundException e) {
// expected on JRE < 1.5
}
useNetProxy = clazz != null;
}
private Hashtable proxies;
private URLStreamHandlerFactory parentFactory;
private ThreadLocal creatingProtocols = new ThreadLocal();
/**
* Create the factory.
*
* @param context BundleContext for the system bundle
*/
public StreamHandlerFactory(BundleContext context, FrameworkAdaptor adaptor) {
super(context, adaptor);
proxies = new Hashtable(15);
handlerTracker = new ServiceTracker(context, URLSTREAMHANDLERCLASS, null);
handlerTracker.open();
}
private Class getBuiltIn(String protocol, String builtInHandlers, boolean fromFramework) {
if (builtInHandlers == null)
return null;
Class clazz;
StringTokenizer tok = new StringTokenizer(builtInHandlers, "|"); //$NON-NLS-1$
while (tok.hasMoreElements()) {
StringBuffer name = new StringBuffer();
name.append(tok.nextToken());
name.append("."); //$NON-NLS-1$
name.append(protocol);
name.append(".Handler"); //$NON-NLS-1$
try {
if (fromFramework)
clazz = secureAction.forName(name.toString());
else
clazz = secureAction.loadSystemClass(name.toString());
if (clazz != null)
return clazz; //this class exists, it is a built in handler
} catch (ClassNotFoundException ex) {
// keep looking
}
}
return null;
}
/**
* Creates a new URLStreamHandler instance for the specified
* protocol.
*
* @param protocol The desired protocol
* @return a URLStreamHandler for the specific protocol.
*/
public URLStreamHandler createURLStreamHandler(String protocol) {
// Check if we are recursing
if (isRecursive(protocol))
return null;
try {
//first check for built in handlers
String builtInHandlers = secureAction.getProperty(PROTOCOL_HANDLER_PKGS);
Class clazz = getBuiltIn(protocol, builtInHandlers, false);
if (clazz != null)
return null; // let the VM handle it
URLStreamHandler result = null;
if (isMultiplexing()) {
if (findAuthorizedURLStreamHandler(protocol) != null)
result = new MultiplexingURLStreamHandler(protocol, this);
} else {
result = createInternalURLStreamHandler(protocol);
}
// if parent is present do parent lookup
if (result == null && parentFactory != null)
result = parentFactory.createURLStreamHandler(protocol);
return result; //result may be null; let the VM handle it (consider sun.net.protocol.www.*)
} finally {
releaseRecursive(protocol);
}
}
private boolean isRecursive(String protocol) {
List protocols = (List) creatingProtocols.get();
if (protocols == null) {
protocols = new ArrayList(1);
creatingProtocols.set(protocols);
}
if (protocols.contains(protocol))
return true;
protocols.add(protocol);
return false;
}
private void releaseRecursive(String protocol) {
List protocols = (List) creatingProtocols.get();
protocols.remove(protocol);
}
public URLStreamHandler createInternalURLStreamHandler(String protocol) {
//internal protocol handlers
String internalHandlerPkgs = secureAction.getProperty(Constants.INTERNAL_HANDLER_PKGS);
internalHandlerPkgs = internalHandlerPkgs == null ? INTERNAL_PROTOCOL_HANDLER_PKG : internalHandlerPkgs + '|' + INTERNAL_PROTOCOL_HANDLER_PKG;
Class clazz = getBuiltIn(protocol, internalHandlerPkgs, true);
if (clazz == null) {
//Now we check the service registry
//first check to see if the handler is in the cache
URLStreamHandlerProxy handler = (URLStreamHandlerProxy) proxies.get(protocol);
if (handler != null)
return (handler);
//look through the service registry for a URLStramHandler registered for this protocol
org.osgi.framework.ServiceReference[] serviceReferences = handlerTracker.getServiceReferences();
if (serviceReferences == null)
return null;
for (int i = 0; i < serviceReferences.length; i++) {
Object prop = serviceReferences[i].getProperty(URLConstants.URL_HANDLER_PROTOCOL);
if (prop instanceof String)
prop = new String[] {(String) prop}; // TODO should this be a warning?
if (!(prop instanceof String[])) {
String message = NLS.bind(Msg.URL_HANDLER_INCORRECT_TYPE, new Object[] {URLConstants.URL_HANDLER_PROTOCOL, URLSTREAMHANDLERCLASS, serviceReferences[i].getBundle()});
adaptor.getFrameworkLog().log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.WARNING, 0, message, 0, null, null));
continue;
}
String[] protocols = (String[]) prop;
for (int j = 0; j < protocols.length; j++)
if (protocols[j].equals(protocol)) {
handler = useNetProxy ? new URLStreamHandlerFactoryProxyFor15(protocol, serviceReferences[i], context) : new URLStreamHandlerProxy(protocol, serviceReferences[i], context);
proxies.put(protocol, handler);
return (handler);
}
}
return null;
}
// must be a built-in handler
try {
URLStreamHandler handler = (URLStreamHandler) clazz.newInstance();
if (handler instanceof ProtocolActivator) {
((ProtocolActivator) handler).start(context, adaptor);
}
return handler;
} catch (Exception e) {
return null;
}
}
protected URLStreamHandler findAuthorizedURLStreamHandler(String protocol) {
Object factory = findAuthorizedFactory(ignoredClasses);
if (factory == null)
return null;
if (factory == this)
return createInternalURLStreamHandler(protocol);
try {
Method createInternalURLStreamHandlerMethod = factory.getClass().getMethod("createInternalURLStreamHandler", new Class[] {String.class}); //$NON-NLS-1$
return (URLStreamHandler) createInternalURLStreamHandlerMethod.invoke(factory, new Object[] {protocol});
} catch (Exception e) {
adaptor.getFrameworkLog().log(new FrameworkLogEntry(StreamHandlerFactory.class.getName(), "findAuthorizedURLStreamHandler-loop", FrameworkLogEntry.ERROR, e, null)); //$NON-NLS-1$
throw new RuntimeException(e.getMessage(), e);
}
}
public Object getParentFactory() {
return parentFactory;
}
public void setParentFactory(Object parentFactory) {
if (this.parentFactory == null) // only allow it to be set once
this.parentFactory = (URLStreamHandlerFactory) parentFactory;
}
}