Skip to content

Commit

Permalink
Make the URLStreamHandler as lazy as possible
Browse files Browse the repository at this point in the history
URLStreamHandlerFactoryImpl currently opens a service tracker
unconditionally for URLStreamHandlerService to discover registered
handlers. This leads to any handler being fetched eagerly instead of
when it is required.

This changes the handling in a way where it is as lazy as possible by

- not open a tracker until a protocol is requested
- use a service tracker with a specific protocol filter in proxy
- only fetch the service when it is first used
  • Loading branch information
laeubi committed Jul 4, 2023
1 parent 513274d commit 786f008
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 168 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,22 @@
package org.eclipse.osgi.internal.url;

import java.lang.reflect.Method;
import java.net.*;
import java.net.URL;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
import java.security.AccessController;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
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;

/**
* This class contains the URL stream handler factory for the OSGi framework.
Expand All @@ -40,10 +41,8 @@ public class URLStreamHandlerFactoryImpl extends MultiplexingFactory implements
public static final String PROTOCOL_REFERENCE = "reference"; //$NON-NLS-1$
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 Map<String, URLStreamHandlerProxy> proxies;
private URLStreamHandlerFactory parentFactory;
private ThreadLocal<List<String>> creatingProtocols = new ThreadLocal<>();

Expand All @@ -54,10 +53,7 @@ public class URLStreamHandlerFactoryImpl extends MultiplexingFactory implements
*/
public URLStreamHandlerFactoryImpl(BundleContext context, EquinoxContainer container) {
super(context, container);

proxies = new Hashtable<>(15);
handlerTracker = new ServiceTracker<>(context, URLSTREAMHANDLERCLASS, null);
handlerTracker.open();
proxies = new ConcurrentHashMap<>();
}

private Class<?> getBuiltIn(String protocol, String builtInHandlers) {
Expand Down Expand Up @@ -154,35 +150,13 @@ public URLStreamHandler createInternalURLStreamHandler(String protocol) {
if (frameworkHandler != null) {
return frameworkHandler;
}

//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
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}; // 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, 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);
}
}
URLStreamHandlerProxy handler = proxies.computeIfAbsent(protocol, p -> new URLStreamHandlerProxy(p, context));
if (handler.isActive()) {
return handler;
}
return null;

}

protected URLStreamHandler findAuthorizedURLStreamHandler(String protocol) {
Expand Down
Loading

0 comments on commit 786f008

Please sign in to comment.