Make urlhandlers work when a handler factory is already set. Furthermore, it is now possible to have more then one framework running in more then one classloader. It is still possible to disable urlhandlers per framework. If no framework has urlhandlers enabled the factory will not be set. (FELIX-38).
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@634291 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/URLHandlers.java b/framework/src/main/java/org/apache/felix/framework/URLHandlers.java
index 8d69279..01c6925 100644
--- a/framework/src/main/java/org/apache/felix/framework/URLHandlers.java
+++ b/framework/src/main/java/org/apache/felix/framework/URLHandlers.java
@@ -18,12 +18,12 @@
*/
package org.apache.felix.framework;
+import java.io.IOException;
import java.net.*;
import java.util.*;
import org.apache.felix.framework.searchpolicy.ContentClassLoader;
import org.apache.felix.framework.util.*;
-import org.osgi.framework.BundleContext;
/**
* <p>
@@ -68,32 +68,183 @@
{
private static final String STREAM_HANDLER_PACKAGE_PROP = "java.protocol.handler.pkgs";
private static final String CONTENT_HANDLER_PACKAGE_PROP = "java.content.handler.pkgs";
- private static final String DEFAULT_STREAM_HANDLER_PACKAGE = "sun.net.www.protocol";
-
- private static final String DEFAULT_CONTENT_HANDLER_PACKAGE = "sun.net.www.content";
- private static String m_lock = new String("string-lock");
+ private static final String DEFAULT_STREAM_HANDLER_PACKAGE = "sun.net.www.protocol|com.ibm.oti.net.www.protocol|gnu.java.net.protocol|wonka.net|com.acunia.wonka.net|org.apache.harmony.luni.internal.net.www.protocol|weblogic.utils|weblogic.net|javax.net.ssl|COM.newmonics.www.protocols";
+ private static final String DEFAULT_CONTENT_HANDLER_PACKAGE = "sun.net.www.content|com.ibm.oti.net.www.content|gnu.java.net.content|org.apache.harmony.luni.internal.net.www.content|COM.newmonics.www.content";
+
+ private static final SecureAction m_secureAction = new SecureAction();
+
private static SecurityManagerEx m_sm = null;
private static URLHandlers m_handler = null;
- private static int m_frameworkCount = 0;
- private static List m_frameworkList = null;
- private static Map m_streamHandlerCache = null;
- private static Map m_contentHandlerCache = null;
- private final static SecureAction m_secureAction = new SecureAction();
+ // This maps classloaders of URLHandlers in other classloaders to lists of
+ // their frameworks.
+ private static Map m_classloaderToFrameworkLists = new HashMap();
+
+ // The list to hold all enabled frameworks registered with this handlers
+ private static final List m_frameworks = new ArrayList();
+
+ private static Map m_contentHandlerCache = null;
+ private static Map m_streamHandlerCache = null;
+ private static URLStreamHandlerFactory m_streamHandlerFactory;
+ private static ContentHandlerFactory m_contentHandlerFactory;
/**
* <p>
- * Only one instance of this class is created in a static initializer
+ * Only one instance of this class is created per classloader
* and that one instance is registered as the stream and content handler
- * factories for the JVM.
+ * factories for the JVM. Unless, we already register one from a different
+ * classloader. In this case we attach to this root.
* </p>
**/
private URLHandlers()
{
- // No one can create an instance, but we need an instance
- // so we can set this as the stream and content handler factory.
- URL.setURLStreamHandlerFactory(this);
- URLConnection.setContentHandlerFactory(this);
+ synchronized (URL.class)
+ {
+ try
+ {
+ URL.setURLStreamHandlerFactory(this);
+ m_streamHandlerFactory = this;
+ }
+ catch (Error err)
+ {
+ try
+ {
+ // there already is a factory set so try to swap it with ours.
+ m_streamHandlerFactory = (URLStreamHandlerFactory)
+ m_secureAction.swapStaticFieldIfNotClass(URL.class,
+ URLStreamHandlerFactory.class, URLHandlers.class, "streamHandlerLock");
+
+ if (m_streamHandlerFactory == null)
+ {
+ throw err;
+ }
+ if (!m_streamHandlerFactory.getClass().getName().equals(URLHandlers.class.getName()))
+ {
+ URL.setURLStreamHandlerFactory(this);
+ }
+ else if (URLHandlers.class != m_streamHandlerFactory.getClass())
+ {
+ try
+ {
+ m_secureAction.invoke(
+ m_secureAction.getDeclaredMethod(m_streamHandlerFactory.getClass(),
+ "registerFrameworkListsForContextSearch",
+ new Class[]{ClassLoader.class, List.class}),
+ m_streamHandlerFactory, new Object[]{ URLHandlers.class.getClassLoader(),
+ m_frameworks });
+ }
+ catch (Exception ex)
+ {
+ new RuntimeException(ex.getMessage());
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ throw err;
+ }
+ }
+
+ try
+ {
+ URLConnection.setContentHandlerFactory(this);
+ m_contentHandlerFactory = this;
+ }
+ catch (Error err)
+ {
+ // there already is a factory set so try to swap it with ours.
+ try
+ {
+ m_contentHandlerFactory = (ContentHandlerFactory)
+ m_secureAction.swapStaticFieldIfNotClass(
+ URLConnection.class, ContentHandlerFactory.class,
+ URLHandlers.class, null);
+ if (m_contentHandlerFactory == null)
+ {
+ throw err;
+ }
+ if (!m_contentHandlerFactory.getClass().getName().equals(
+ URLHandlers.class.getName()))
+ {
+ URLConnection.setContentHandlerFactory(this);
+ }
+ }
+ catch (Exception ex)
+ {
+ throw err;
+ }
+ }
+ }
+ // are we not the new root?
+ if ((m_streamHandlerFactory == this) || !URLHandlers.class.getName().equals(
+ m_streamHandlerFactory.getClass().getName()))
+ {
+ // we only need a security manager in the root
+ m_sm = new SecurityManagerEx();
+ }
+ }
+
+ static void registerFrameworkListsForContextSearch(ClassLoader index,
+ List frameworkLists)
+ {
+ synchronized (URL.class)
+ {
+ synchronized (m_classloaderToFrameworkLists)
+ {
+ m_classloaderToFrameworkLists.put(index, frameworkLists);
+ }
+ }
+ }
+
+ static void unregisterFrameworkListsForContextSearch(ClassLoader index)
+ {
+ synchronized (URL.class)
+ {
+ synchronized (m_classloaderToFrameworkLists)
+ {
+ m_classloaderToFrameworkLists.remove(index);
+ if (m_classloaderToFrameworkLists.isEmpty() )
+ {
+ synchronized (m_frameworks)
+ {
+ if (m_frameworks.isEmpty())
+ {
+ try
+ {
+ m_secureAction.swapStaticFieldIfNotClass(URL.class,
+ URLStreamHandlerFactory.class, null, "streamHandlerLock");
+ }
+ catch (Exception ex)
+ {
+ // TODO log this
+ ex.printStackTrace();
+ }
+
+ if (m_streamHandlerFactory.getClass() != URLHandlers.class)
+ {
+ URL.setURLStreamHandlerFactory(m_streamHandlerFactory);
+ }
+ try
+ {
+ m_secureAction.swapStaticFieldIfNotClass(
+ URLConnection.class, ContentHandlerFactory.class,
+ null, null);
+ }
+ catch (Exception ex)
+ {
+ // TODO log this
+ ex.printStackTrace();
+ }
+
+ if (m_contentHandlerFactory.getClass() != URLHandlers.class)
+ {
+ URLConnection.setContentHandlerFactory(m_contentHandlerFactory);
+ }
+ }
+ }
+ }
+ }
+ }
}
/**
@@ -116,24 +267,22 @@
// performed for code consistency between stream and content
// handlers and also because caching behavior may not be guaranteed
// across different JRE implementations.
- URLStreamHandler handler = (m_streamHandlerCache == null)
- ? null
- : (URLStreamHandler) m_streamHandlerCache.get(protocol);
-
+ URLStreamHandler handler = (URLStreamHandler)
+ ((m_streamHandlerCache != null) ? m_streamHandlerCache.get(protocol) : null);
+
+ if (handler != null)
+ {
+ return handler;
+ }
// If this is the framework's "bundle:" protocol, then return
// a handler for that immediately, since no one else can be
// allowed to deal with it.
if (protocol.equals(FelixConstants.BUNDLE_URL_PROTOCOL))
{
- handler = new URLHandlersBundleStreamHandler(null);
- if (m_streamHandlerCache == null)
- {
- m_streamHandlerCache = new HashMap();
- }
- m_streamHandlerCache.put(protocol, handler);
- return handler;
+ return addToStreamCache(protocol,
+ new URLHandlersBundleStreamHandler(m_secureAction));
}
-
+
// If this is the framework's "felix:" extension protocol, then
// return the ExtensionManager.m_extensionManager handler for
// that immediately - this is a workaround for certain jvms that
@@ -141,59 +290,72 @@
// URLClassloader.
if (protocol.equals("felix"))
{
- handler = ExtensionManager.m_extensionManager;
- if (m_streamHandlerCache == null)
+ return addToStreamCache(protocol, new URLStreamHandler()
{
- m_streamHandlerCache = new HashMap();
- }
- m_streamHandlerCache.put(protocol, handler);
- return handler;
- }
-
- // If there is not cached handler, then search for built-in
- // handler or create a new handler proxy.
- if (handler == null)
- {
- // Check for built-in handlers for the protocol.
- String pkgs = m_secureAction.getSystemProperty(STREAM_HANDLER_PACKAGE_PROP, "");
- pkgs = (pkgs.equals(""))
- ? DEFAULT_STREAM_HANDLER_PACKAGE
- : pkgs + "|" + DEFAULT_STREAM_HANDLER_PACKAGE;
-
- // Iterate over built-in packages.
- StringTokenizer pkgTok = new StringTokenizer(pkgs, "| ");
- while (pkgTok.hasMoreTokens())
- {
- String pkg = pkgTok.nextToken().trim();
- String className = pkg + "." + protocol + ".Handler";
- try
+ protected URLConnection openConnection(URL url)
+ throws IOException
{
- // If a built-in handler is found then let the
- // JRE handle it.
- if (m_secureAction.forName(className) != null)
+ Object framework = getFrameworkFromContext();
+
+ try
{
- return null;
+ Object handler = m_secureAction.getDeclaredField(
+ framework.getClass(),"m_extensionManager", framework);
+
+ return (URLConnection) m_secureAction.invoke(
+ m_secureAction.getMethod(handler.getClass(),
+ "openConnection", new Class[]{URL.class}), handler,
+ new Object[]{url});
+ }
+ catch (Exception ex)
+ {
+ throw new IOException(ex.getMessage());
}
}
- catch (Exception ex)
- {
- // This could be a class not found exception or an
- // instantiation exception, not much we can do in either
- // case other than ignore it.
- }
- }
-
- // If no cached or built-in content handler, then create a
- // proxy handler and cache it.
- handler = new URLHandlersStreamHandlerProxy(protocol);
- if (m_streamHandlerCache == null)
- {
- m_streamHandlerCache = new HashMap();
- }
- m_streamHandlerCache.put(protocol, handler);
+ });
}
- return handler;
+ // If there was a custom factory then try to get the handler form it
+ if (m_streamHandlerFactory != this)
+ {
+ handler =
+ addToStreamCache(protocol, m_streamHandlerFactory.createURLStreamHandler(protocol));
+
+ if (handler != null)
+ {
+ return handler;
+ }
+ }
+ // Check for built-in handlers for the protocol.
+ String pkgs = m_secureAction.getSystemProperty(STREAM_HANDLER_PACKAGE_PROP, "");
+ pkgs = (pkgs.equals(""))
+ ? DEFAULT_STREAM_HANDLER_PACKAGE
+ : pkgs + "|" + DEFAULT_STREAM_HANDLER_PACKAGE;
+
+ // Iterate over built-in packages.
+ StringTokenizer pkgTok = new StringTokenizer(pkgs, "| ");
+ while (pkgTok.hasMoreTokens())
+ {
+ String pkg = pkgTok.nextToken().trim();
+ String className = pkg + "." + protocol + ".Handler";
+ try
+ {
+ // If a built-in handler is found then let the
+ // JRE handle it.
+ if (m_secureAction.forName(className) != null)
+ {
+ return null;
+ }
+ }
+ catch (Exception ex)
+ {
+ // This could be a class not found exception or an
+ // instantiation exception, not much we can do in either
+ // case other than ignore it.
+ }
+ }
+ // If built-in content handler, then create a proxy handler.
+ return addToStreamCache(protocol, new URLHandlersStreamHandlerProxy(protocol, m_secureAction));
}
}
@@ -211,59 +373,123 @@
{
synchronized (this)
{
- // See if there is a cached content handler.
- ContentHandler handler = (m_contentHandlerCache == null)
- ? null
- : (ContentHandler) m_contentHandlerCache.get(mimeType);
-
- // If there is not cached handler, then search for built-in
- // handler or create a new handler proxy.
- if (handler == null)
+ // See if there is a cached stream handler.
+ // IMPLEMENTATION NOTE: Caching is not strictly necessary for
+ // stream handlers since the Java runtime caches them. Caching is
+ // performed for code consistency between stream and content
+ // handlers and also because caching behavior may not be guaranteed
+ // across different JRE implementations.
+ ContentHandler handler = (ContentHandler)
+ ((m_contentHandlerCache != null) ? m_contentHandlerCache.get(mimeType) : null);
+
+ if (handler != null)
{
- // Check for built-in handlers for the mime type.
- String pkgs = m_secureAction.getSystemProperty(CONTENT_HANDLER_PACKAGE_PROP, "");
- pkgs = (pkgs.equals(""))
- ? DEFAULT_CONTENT_HANDLER_PACKAGE
- : pkgs + "|" + DEFAULT_CONTENT_HANDLER_PACKAGE;
-
- // Remove periods, slashes, and dashes from mime type.
- String fixedType = mimeType.replace('.', '_').replace('/', '.').replace('-', '_');
-
- // Iterate over built-in packages.
- StringTokenizer pkgTok = new StringTokenizer(pkgs, "| ");
- while (pkgTok.hasMoreTokens())
+ return handler;
+ }
+ // If there was a custom factory then try to get the handler form it
+ if (m_contentHandlerFactory != this)
+ {
+ handler = addToContentCache(mimeType,
+ m_contentHandlerFactory.createContentHandler(mimeType));
+
+ if (handler != null)
{
- String pkg = pkgTok.nextToken().trim();
- String className = pkg + "." + fixedType;
- try
+ return handler;
+ }
+ }
+
+ // Check for built-in handlers for the mime type.
+ String pkgs = m_secureAction.getSystemProperty(CONTENT_HANDLER_PACKAGE_PROP, "");
+ pkgs = (pkgs.equals(""))
+ ? DEFAULT_CONTENT_HANDLER_PACKAGE
+ : pkgs + "|" + DEFAULT_CONTENT_HANDLER_PACKAGE;
+
+ // Remove periods, slashes, and dashes from mime type.
+ String fixedType = mimeType.replace('.', '_').replace('/', '.').replace('-', '_');
+
+ // Iterate over built-in packages.
+ StringTokenizer pkgTok = new StringTokenizer(pkgs, "| ");
+ while (pkgTok.hasMoreTokens())
+ {
+ String pkg = pkgTok.nextToken().trim();
+ String className = pkg + "." + fixedType;
+ try
+ {
+ // If a built-in handler is found then let the
+ // JRE handle it.
+ if (m_secureAction.forName(className) != null)
{
- // If a built-in handler is found then let the
- // JRE handle it.
- if (m_secureAction.forName(className) != null)
- {
- return null;
- }
- }
- catch (Exception ex)
- {
- // This could be a class not found exception or an
- // instantiation exception, not much we can do in either
- // case other than ignore it.
+ return null;
}
}
+ catch (Exception ex)
+ {
+ // This could be a class not found exception or an
+ // instantiation exception, not much we can do in either
+ // case other than ignore it.
+ }
+ }
+
+ return addToContentCache(mimeType,
+ new URLHandlersContentHandlerProxy(mimeType, m_secureAction));
+ }
+ }
- // If no cached or built-in content handler, then create a
- // proxy handler and cache it.
- handler = new URLHandlersContentHandlerProxy(mimeType);
- if (m_contentHandlerCache == null)
- {
- m_contentHandlerCache = new HashMap();
- }
+ private ContentHandler addToContentCache(String mimeType, ContentHandler handler)
+ {
+ if (handler == null)
+ {
+ return null;
+ }
+ if (m_contentHandlerCache == null)
+ {
+ m_contentHandlerCache = new HashMap();
+ m_contentHandlerCache.put(mimeType, handler);
+ }
+ else
+ {
+ ContentHandler result = (ContentHandler)
+ m_contentHandlerCache.get(mimeType);
+
+ if (result == null)
+ {
m_contentHandlerCache.put(mimeType, handler);
}
-
- return handler;
+ else
+ {
+ handler = result;
+ }
}
+ return handler;
+ }
+
+ private URLStreamHandler addToStreamCache(String protocol, URLStreamHandler handler)
+ {
+ if (handler == null)
+ {
+ return null;
+ }
+
+ if (m_streamHandlerCache == null)
+ {
+ m_streamHandlerCache = new HashMap();
+ m_streamHandlerCache.put(protocol, handler);
+ }
+ else
+ {
+ URLStreamHandler result = (URLStreamHandler)
+ m_streamHandlerCache.get(protocol);
+
+ if (result == null)
+ {
+ m_streamHandlerCache.put(protocol, handler);
+ }
+ else
+ {
+ handler = result;
+ }
+ }
+ return handler;
}
/**
@@ -273,19 +499,13 @@
* </p>
* @param framework the framework instance to be added to the instance
* registry.
- * @param context the system bundle context associated with the framework
- * instance.
* @param enable a flag indicating whether or not the framework wants to
* enable the URL Handlers service.
**/
- public static void registerInstance(
- Felix framework, BundleContext context, boolean enable)
+ public static void registerFrameworkInstance(Object framework, boolean enable)
{
- synchronized (m_lock)
+ synchronized (m_frameworks)
{
- // Increment framework instance count.
- m_frameworkCount++;
-
// If the URL Handlers service is not going to be enabled,
// then return immediately.
if (enable)
@@ -295,17 +515,9 @@
// factories.
if (m_handler == null)
{
- m_sm = new SecurityManagerEx();
m_handler = new URLHandlers();
}
-
- // Create the framework list, if necessary, and add the
- // new framework instance to it.
- if (m_frameworkList == null)
- {
- m_frameworkList = new ArrayList();
- }
- m_frameworkList.add(framework);
+ m_frameworks.add(framework);
}
}
}
@@ -318,14 +530,31 @@
* @param framework the framework instance to be removed from the instance
* registry.
**/
- public static void unregisterInstance(Felix framework)
+ public static void unregisterFrameworkInstance(Object framework)
{
- synchronized (m_lock)
+ synchronized (m_frameworks)
{
- m_frameworkCount--;
- if (m_frameworkList != null)
+ if (m_frameworks.remove(framework) && m_frameworks.isEmpty())
{
- m_frameworkList.remove(framework);
+ if (m_handler.m_streamHandlerFactory.getClass().getName().equals(
+ URLHandlers.class.getName()))
+ {
+ try
+ {
+ m_secureAction.invoke(m_secureAction.getDeclaredMethod(
+ m_handler.m_streamHandlerFactory.getClass(),
+ "unregisterFrameworkListsForContextSearch",
+ new Class[]{ ClassLoader.class}),
+ m_handler.m_streamHandlerFactory,
+ new Object[] {URLHandlers.class.getClassLoader()});
+ }
+ catch (Exception e)
+ {
+ // TODO this should not happen
+ e.printStackTrace();
+ }
+ }
+ m_handler = null;
}
}
}
@@ -341,50 +570,69 @@
* @return the system bundle context associated with the caller or
* <tt>null</tt> if no associated framework was found.
**/
- public static Felix getFrameworkFromContext()
+ public static Object getFrameworkFromContext()
{
- synchronized (m_lock)
+ // get the current class call stack.
+ Class[] stack = m_sm.getClassContext();
+ // Find the first class that is loaded from a bundle.
+ Class targetClass = null;
+ for (int i = 0; i < stack.length; i++)
{
- if (m_frameworkList != null)
+ if ((stack[i].getClassLoader() != null) &&
+ ContentClassLoader.class.getName().equals(
+ stack[i].getClassLoader().getClass().getName()))
{
- // First, perform a simple short cut, if there is only
- // one framework instance registered, assume that this
- // is the bundle context to be returned and just return
- // it immediately.
- if ((m_frameworkList.size() == 1) && (m_frameworkCount == 1))
+ targetClass = stack[i];
+ break;
+ }
+ }
+
+ // If we found a class loaded from a bundle, then iterate
+ // over the framework instances and see which framework owns
+ // the bundle that loaded the class.
+ if (targetClass != null)
+ {
+ synchronized (m_classloaderToFrameworkLists)
+ {
+ ClassLoader index = targetClass.getClassLoader().getClass().getClassLoader();
+
+ List frameworks = (List) m_classloaderToFrameworkLists.get(
+ index);
+
+ if ((frameworks == null) && (index == URLHandlers.class.getClassLoader()))
{
- return (Felix) m_frameworkList.get(0);
+ frameworks = m_frameworks;
}
-
- // If there is more than one registered framework instance,
- // then get the current class call stack.
- Class[] stack = m_sm.getClassContext();
- // Find the first class that is loaded from a bundle.
- Class targetClass = null;
- for (int i = 0; i < stack.length; i++)
+ if (frameworks != null)
{
- if (stack[i].getClassLoader() instanceof ContentClassLoader)
+ synchronized (frameworks)
{
- targetClass = stack[i];
- break;
- }
- }
- // If we found a class loaded from a bundle, then iterate
- // over the framework instances and see which framework owns
- // the bundle that loaded the class.
- if (targetClass != null)
- {
- // Check the registry of framework instances
- for (int i = 0; i < m_frameworkList.size(); i++)
- {
- if (((Felix) m_frameworkList.get(i)).getBundle(targetClass) != null)
+ // Check the registry of framework instances
+ for (int i = 0; i < frameworks.size(); i++)
{
- return (Felix) m_frameworkList.get(i);
+ Object framework = frameworks.get(i);
+ try
+ {
+ if (m_secureAction.invoke(
+ m_secureAction.getDeclaredMethod(framework.getClass(),
+ "getBundle", new Class[]{Class.class}),
+ framework, new Object[]{targetClass}) != null)
+ {
+ return framework;
+ }
+ }
+ catch (Exception ex)
+ {
+ // This should not happen but if it does there is
+ // not much we can do other then ignore it.
+ // Maybe log this or something.
+ ex.printStackTrace();
+ }
}
}
}
}
- return null;
}
+ return null;
}
}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/URLHandlersActivator.java b/framework/src/main/java/org/apache/felix/framework/URLHandlersActivator.java
index 8608185..3180aaf 100644
--- a/framework/src/main/java/org/apache/felix/framework/URLHandlersActivator.java
+++ b/framework/src/main/java/org/apache/felix/framework/URLHandlersActivator.java
@@ -36,7 +36,6 @@
{
private Map m_configMap = null;
private Felix m_framework = null;
- private BundleContext m_context = null;
public URLHandlersActivator(Map configMap, Felix framework)
{
@@ -50,18 +49,17 @@
public void start(BundleContext context)
{
- m_context = context;
// Only register the framework with the URL Handlers service
// if the service is enabled.
boolean enable = (m_configMap.get(
FelixConstants.SERVICE_URLHANDLERS_PROP) == null)
? true
: !m_configMap.get(FelixConstants.SERVICE_URLHANDLERS_PROP).equals("false");
- URLHandlers.registerInstance(m_framework, m_context, enable);
+ URLHandlers.registerFrameworkInstance(m_framework, enable);
}
public void stop(BundleContext context)
{
- URLHandlers.unregisterInstance(m_framework);
+ URLHandlers.unregisterFrameworkInstance(m_framework);
}
}
diff --git a/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleStreamHandler.java b/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleStreamHandler.java
index 818ed4c..8e81e05 100644
--- a/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleStreamHandler.java
+++ b/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleStreamHandler.java
@@ -21,17 +21,51 @@
import java.io.IOException;
import java.net.*;
+import org.apache.felix.framework.util.SecureAction;
+
class URLHandlersBundleStreamHandler extends URLStreamHandler
{
- private Felix m_framework = null;
+ private final Felix m_framework;
+ private final SecureAction m_action;
public URLHandlersBundleStreamHandler(Felix framework)
{
m_framework = framework;
+ m_action = null;
+ }
+
+ public URLHandlersBundleStreamHandler(SecureAction action)
+ {
+ m_framework = null;
+ m_action = action;
}
protected synchronized URLConnection openConnection(URL url) throws IOException
{
- return new URLHandlersBundleURLConnection(url, m_framework);
+ if (m_framework != null)
+ {
+ return new URLHandlersBundleURLConnection(url, m_framework);
+ }
+
+ Object framework = URLHandlers.getFrameworkFromContext();
+
+ if (framework != null)
+ {
+ // TODO: optimize this to not use reflection if not needed
+ try
+ {
+ Class targetClass = framework.getClass().getClassLoader().loadClass(
+ URLHandlersBundleURLConnection.class.getName());
+
+ return (URLConnection) m_action.invoke(m_action.getConstructor(targetClass,
+ new Class[]{URL.class, framework.getClass()}),
+ new Object[]{url, framework});
+ }
+ catch (Exception ex)
+ {
+ throw new IOException(ex.getMessage());
+ }
+ }
+ throw new IOException("No framework context found");
}
}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.java b/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.java
index ac8cc82..88e5ea8 100644
--- a/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.java
+++ b/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.java
@@ -52,7 +52,7 @@
// one from the call context.
if (m_framework == null)
{
- m_framework = URLHandlers.getFrameworkFromContext();
+ m_framework = (Felix) URLHandlers.getFrameworkFromContext();
}
// If there is still no framework, then error.
@@ -60,7 +60,7 @@
{
throw new IOException("Unable to find framework for URL: " + url);
}
- // Verify that the resource pointed to be the URL exists.
+ // Verify that the resource pointed to by the URL exists.
// The URL is constructed like this:
// bundle://<module-id>:<bundle-classpath-index>/<resource-path>
// Where <module-id> = <bundle-id>.<revision>
diff --git a/framework/src/main/java/org/apache/felix/framework/URLHandlersContentHandlerProxy.java b/framework/src/main/java/org/apache/felix/framework/URLHandlersContentHandlerProxy.java
index 0a1d2e7..a8f06b9 100644
--- a/framework/src/main/java/org/apache/felix/framework/URLHandlersContentHandlerProxy.java
+++ b/framework/src/main/java/org/apache/felix/framework/URLHandlersContentHandlerProxy.java
@@ -24,7 +24,7 @@
import java.util.HashMap;
import java.util.Map;
-import org.osgi.framework.BundleContext;
+import org.apache.felix.framework.util.SecureAction;
import org.osgi.service.url.URLConstants;
/**
@@ -51,12 +51,14 @@
**/
class URLHandlersContentHandlerProxy extends ContentHandler
{
- private Map m_trackerMap = new HashMap();
- private String m_mimeType = null;
+ private final Map m_trackerMap = new HashMap();
+ private final String m_mimeType;
+ private final SecureAction m_action;
- public URLHandlersContentHandlerProxy(String mimeType)
+ public URLHandlersContentHandlerProxy(String mimeType, SecureAction action)
{
m_mimeType = mimeType;
+ m_action = action;
}
//
@@ -87,7 +89,7 @@
private ContentHandler getContentHandlerService()
{
// Get the framework instance associated with call stack.
- Felix framework = URLHandlers.getFrameworkFromContext();
+ Object framework = URLHandlers.getFrameworkFromContext();
// If the framework has disabled the URL Handlers service,
// then it will not be found so just return null.
@@ -97,27 +99,38 @@
}
// Get the service tracker for the framework instance or create one.
- URLHandlersServiceTracker tracker =
- (URLHandlersServiceTracker) m_trackerMap.get(framework);
- if (tracker == null)
+ Object tracker = m_trackerMap.get(framework);
+ try
{
- // Get the framework's system bundle context.
- BundleContext context =
- ((FelixBundle) framework.getBundle(0)).getInfo().getBundleContext();
- // Create a filter for the mime type.
- String filter =
- "(&(objectClass="
- + ContentHandler.class.getName()
- + ")("
- + URLConstants.URL_CONTENT_MIMETYPE
- + "="
- + m_mimeType
- + "))";
- // Create a simple service tracker for the framework.
- tracker = new URLHandlersServiceTracker(context, filter);
- // Cache the simple service tracker.
- m_trackerMap.put(framework, tracker);
+ if (tracker == null)
+ {
+ // Create a filter for the mime type.
+ String filter =
+ "(&(objectClass="
+ + ContentHandler.class.getName()
+ + ")("
+ + URLConstants.URL_CONTENT_MIMETYPE
+ + "="
+ + m_mimeType
+ + "))";
+ // Create a simple service tracker for the framework.
+ tracker = m_action.invoke(m_action.getConstructor(
+ framework.getClass().getClassLoader().loadClass(
+ URLHandlersServiceTracker.class.getName()),
+ new Class[]{framework.getClass(), String.class}),
+ new Object[]{framework, filter});
+ // Cache the simple service tracker.
+ m_trackerMap.put(framework, tracker);
+ }
+ return (ContentHandler) m_action.invoke(
+ m_action.getMethod(tracker.getClass(), "getService", null),
+ tracker, null);
}
- return (ContentHandler) tracker.getService();
+ catch (Exception ex)
+ {
+ // TODO: log this or something
+ ex.printStackTrace();
+ return null;
+ }
}
}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/URLHandlersServiceTracker.java b/framework/src/main/java/org/apache/felix/framework/URLHandlersServiceTracker.java
index fcce722..302ef0d 100644
--- a/framework/src/main/java/org/apache/felix/framework/URLHandlersServiceTracker.java
+++ b/framework/src/main/java/org/apache/felix/framework/URLHandlersServiceTracker.java
@@ -47,9 +47,10 @@
* @param context the bundle context used for tracking services.
* @param filter the filter used for matching services.
**/
- public URLHandlersServiceTracker(BundleContext context, String filter)
+ public URLHandlersServiceTracker(Felix framework, String filter)
{
- m_context = context;
+ m_context = ((FelixBundle)
+ framework.getBundle(0)).getInfo().getBundleContext();
m_filter = filter;
synchronized (this)
diff --git a/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java b/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java
index 08a99ed..ec431e5 100644
--- a/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java
+++ b/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java
@@ -19,12 +19,17 @@
package org.apache.felix.framework;
import java.io.IOException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
import java.net.*;
import java.util.HashMap;
import java.util.Map;
-import org.osgi.framework.BundleContext;
-import org.osgi.service.url.*;
+import org.apache.felix.framework.util.SecureAction;
+import org.osgi.service.url.URLConstants;
+import org.osgi.service.url.URLStreamHandlerService;
+import org.osgi.service.url.URLStreamHandlerSetter;
/**
* <p>
@@ -49,14 +54,25 @@
* </p>
**/
public class URLHandlersStreamHandlerProxy extends URLStreamHandler
- implements URLStreamHandlerSetter
+ implements URLStreamHandlerSetter, InvocationHandler
{
- private Map m_trackerMap = new HashMap();
- private String m_protocol = null;
+ private final Map m_trackerMap = new HashMap();
+ private final String m_protocol;
+ private final Object m_service;
+ private final SecureAction m_action;
- public URLHandlersStreamHandlerProxy(String protocol)
+ public URLHandlersStreamHandlerProxy(String protocol, SecureAction action)
{
m_protocol = protocol;
+ m_service = null;
+ m_action = action;
+ }
+
+ private URLHandlersStreamHandlerProxy(Object service, SecureAction action)
+ {
+ m_protocol = null;
+ m_service = service;
+ m_action = action;
}
//
@@ -187,7 +203,7 @@
private URLStreamHandlerService getStreamHandlerService()
{
// Get the framework instance associated with call stack.
- Felix framework = URLHandlers.getFrameworkFromContext();
+ Object framework = URLHandlers.getFrameworkFromContext();
// If the framework has disabled the URL Handlers service,
// then it will not be found so just return null.
@@ -197,27 +213,73 @@
}
// Get the service tracker for the framework instance or create one.
- URLHandlersServiceTracker tracker =
- (URLHandlersServiceTracker) m_trackerMap.get(framework);
- if (tracker == null)
+ Object tracker = m_trackerMap.get(framework);
+ try
{
- // Get the framework's system bundle context.
- BundleContext context =
- ((FelixBundle) framework.getBundle(0)).getInfo().getBundleContext();
- // Create a filter for the protocol.
- String filter =
- "(&(objectClass="
- + URLStreamHandlerService.class.getName()
- + ")("
- + URLConstants.URL_HANDLER_PROTOCOL
- + "="
- + m_protocol
- + "))";
- // Create a simple service tracker for the framework.
- tracker = new URLHandlersServiceTracker(context, filter);
- // Cache the simple service tracker.
- m_trackerMap.put(framework, tracker);
+ if (tracker == null)
+ {
+ // Create a filter for the protocol.
+ String filter =
+ "(&(objectClass="
+ + URLStreamHandlerService.class.getName()
+ + ")("
+ + URLConstants.URL_HANDLER_PROTOCOL
+ + "="
+ + m_protocol
+ + "))";
+ // Create a simple service tracker for the framework.
+ tracker = m_action.invoke(m_action.getConstructor(
+ framework.getClass().getClassLoader().loadClass(
+ URLHandlersServiceTracker.class.getName()),
+ new Class[]{framework.getClass(), String.class}),
+ new Object[]{framework, filter});
+
+ // Cache the simple service tracker.
+ m_trackerMap.put(framework, tracker);
+ }
+ Object service = m_action.invoke(m_action.getMethod(
+ tracker.getClass(), "getService", null), tracker, null);
+ if (service == null)
+ {
+ return null;
+ }
+ if (service instanceof URLStreamHandlerService)
+ {
+ return (URLStreamHandlerService) service;
+ }
+ return (URLStreamHandlerService) Proxy.newProxyInstance(
+ URLStreamHandlerService.class.getClassLoader(),
+ new Class[]{URLStreamHandlerService.class},
+ new URLHandlersStreamHandlerProxy(service, m_action));
}
- return (URLStreamHandlerService) tracker.getService();
+ catch (Exception ex)
+ {
+ // TODO: log this or something
+ ex.printStackTrace();
+ return null;
+ }
+ }
+
+ public Object invoke(Object obj, Method method, Object[] params)
+ throws Throwable
+ {
+ try
+ {
+ Class[] types = method.getParameterTypes();
+ if ("parseURL".equals(method.getName()))
+ {
+ types[0] = m_service.getClass().getClassLoader().loadClass(
+ URLStreamHandlerSetter.class.getName());
+ params[0] = Proxy.newProxyInstance(
+ m_service.getClass().getClassLoader(), new Class[]{types[0]},
+ (URLHandlersStreamHandlerProxy) params[0]);
+ }
+ return m_action.invoke(m_action.getMethod(m_service.getClass(),
+ method.getName(), types), m_service, params);
+ }
+ catch (Exception ex)
+ {
+ throw ex;
+ }
}
}
\ No newline at end of file