package org.eclipse.osgi.internal.url;
import java.lang.reflect.Method;
import java.net.*;
import java.security.AccessController;
import java.util.*;
import org.eclipse.osgi.framework.log.FrameworkLogEntry;
import org.eclipse.osgi.framework.util.SecureAction;
import org.eclipse.osgi.internal.framework.EquinoxContainer;
import org.eclipse.osgi.internal.location.EquinoxLocations;
import org.eclipse.osgi.internal.messages.Msg;
import org.eclipse.osgi.storage.url.BundleResourceHandler;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.url.URLConstants;
import org.osgi.service.url.URLStreamHandlerService;
import org.osgi.util.tracker.ServiceTracker;
public class URLStreamHandlerFactoryImpl extends MultiplexingFactory implements URLStreamHandlerFactory {
protected static final String URLSTREAMHANDLERCLASS = "org.osgi.service.url.URLStreamHandlerService";
protected static final String PROTOCOL_HANDLER_PKGS = "java.protocol.handler.pkgs";
public static final String PROTOCOL_REFERENCE = "reference";
static final SecureAction secureAction = AccessController.doPrivileged(SecureAction.createSecureAction());
private ServiceTracker<URLStreamHandlerService, URLStreamHandlerService> handlerTracker;
private static final List<Class<?>> ignoredClasses = Arrays.asList(new Class<?>[] {MultiplexingURLStreamHandler.class, URLStreamHandlerFactoryImpl.class, URL.class});
private Map<String, URLStreamHandler> proxies;
private URLStreamHandlerFactory parentFactory;
private ThreadLocal<List<String>> creatingProtocols = new ThreadLocal<>();
public URLStreamHandlerFactoryImpl(BundleContext context, EquinoxContainer container) {
super(context, container);
proxies = new Hashtable<>(15);
handlerTracker = new ServiceTracker<>(context, URLSTREAMHANDLERCLASS, null);
handlerTracker.open();
}
private Class<?> getBuiltIn(String protocol, String builtInHandlers) {
if (builtInHandlers == null)
return null;
Class<?> clazz;
StringTokenizer tok = new StringTokenizer(builtInHandlers, "|");
while (tok.hasMoreElements()) {
StringBuilder name = new StringBuilder();
name.append(tok.nextToken());
name.append(".");
name.append(protocol);
name.append(".Handler");
try {
clazz = secureAction.loadSystemClass(name.toString());
if (clazz != null)
return clazz;
} catch (ClassNotFoundException ex) {
}
}
return null;
}
@Override
public URLStreamHandler createURLStreamHandler(String protocol) {
if (isRecursive(protocol))
return null;
try {
String builtInHandlers = secureAction.getProperty(PROTOCOL_HANDLER_PKGS);
Class<?> clazz = getBuiltIn(protocol, builtInHandlers);
if (clazz != null)
return null;
URLStreamHandler result = null;
if (isMultiplexing()) {
URLStreamHandler authorized = findAuthorizedURLStreamHandler(protocol);
if (authorized != null)
result = new MultiplexingURLStreamHandler(protocol, this, authorized);
} else {
result = createInternalURLStreamHandler(protocol);
}
if (result == null && parentFactory != null)
result = parentFactory.createURLStreamHandler(protocol);
return result;
} catch (Throwable t) {
container.getLogServices().log(URLStreamHandlerFactoryImpl.class.getName(), FrameworkLogEntry.ERROR, "Unexpected error in factory.", t);
return null;
} finally {
releaseRecursive(protocol);
}
}
private boolean isRecursive(String protocol) {
List<String> protocols = 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<String> protocols = creatingProtocols.get();
protocols.remove(protocol);
}
private URLStreamHandler getFrameworkHandler(String protocol) {
if (BundleResourceHandler.OSGI_ENTRY_URL_PROTOCOL.equals(protocol)) {
return new org.eclipse.osgi.storage.url.bundleentry.Handler(container.getStorage().getModuleContainer(), null);
} else if (BundleResourceHandler.OSGI_RESOURCE_URL_PROTOCOL.equals(protocol)) {
return new org.eclipse.osgi.storage.url.bundleresource.Handler(container.getStorage().getModuleContainer(), null);
} else if (PROTOCOL_REFERENCE.equals(protocol)) {
return new org.eclipse.osgi.storage.url.reference.Handler(container.getConfiguration().getConfiguration(EquinoxLocations.PROP_INSTALL_AREA));
}
return null;
}
public URLStreamHandler createInternalURLStreamHandler(String protocol) {
URLStreamHandler frameworkHandler = getFrameworkHandler(protocol);
if (frameworkHandler != null) {
return frameworkHandler;
}
URLStreamHandlerProxy handler = (URLStreamHandlerProxy) proxies.get(protocol);
if (handler != null)
return (handler);
ServiceReference<URLStreamHandlerService>[] serviceReferences = handlerTracker.getServiceReferences();
if (serviceReferences == null)
return null;
for (ServiceReference<URLStreamHandlerService> serviceReference : serviceReferences) {
Object prop = serviceReference.getProperty(URLConstants.URL_HANDLER_PROTOCOL);
if (prop instanceof String)
prop = new String[] {(String) prop};
if (!(prop instanceof String[])) {
String message = NLS.bind(Msg.URL_HANDLER_INCORRECT_TYPE, new Object[]{URLConstants.URL_HANDLER_PROTOCOL, URLSTREAMHANDLERCLASS, serviceReference.getBundle()});
container.getLogServices().log(EquinoxContainer.NAME, FrameworkLogEntry.WARNING, message, null);
continue;
}
String[] protocols = (String[]) prop;
for (String candidateProtocol : protocols) {
if (candidateProtocol.equals(protocol)) {
handler = new URLStreamHandlerProxy(protocol, serviceReference, context);
proxies.put(protocol, handler);
return (handler);
}
}
}
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});
return (URLStreamHandler) createInternalURLStreamHandlerMethod.invoke(factory, new Object[] {protocol});
} catch (Exception e) {
container.getLogServices().log(URLStreamHandlerFactoryImpl.class.getName(), FrameworkLogEntry.ERROR, "findAuthorizedURLStreamHandler-loop", e);
throw new RuntimeException(e.getMessage(), e);
}
}
@Override
public Object getParentFactory() {
return parentFactory;
}
@Override
public void setParentFactory(Object parentFactory) {
if (this.parentFactory == null)
this.parentFactory = (URLStreamHandlerFactory) parentFactory;
}
}