You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@felix.apache.org by "Tom Rutchik (Jira)" <ji...@apache.org> on 2020/12/22 00:47:00 UTC

[jira] [Created] (FELIX-6372) URLStreamHandlers don't work for Android

Tom Rutchik created FELIX-6372:
----------------------------------

             Summary: URLStreamHandlers don't work for Android
                 Key: FELIX-6372
                 URL: https://issues.apache.org/jira/browse/FELIX-6372
             Project: Felix
          Issue Type: Bug
          Components: Framework
            Reporter: Tom Rutchik


I'm not sure if you guys ever formally released Felix with Android support for versions greater than 5.10.0.  But I collaborated, with Karl Pauls on a 6.0.1 version that actually works really well on Android.  I finally found a problem in using it with Android, but there's an easy workaround that can be externally applied.  I'll describe the problem and the fix just for documentation purposes.

The problem is with the method

private URLStreamHandler loadBuiltInStreamHandler(String protocol, ClassLoader classLoader)

located in the class: org.apache.felix.framework.URLHandlers

At the bottom of that method, are the adjustments made for it to work with Android.  The handler class names are no longer valid for Android.   For http and https the classes should be com.android.okhttp.HttpHandler and com.android.okhttp.HttpsHandler.  For the file, jar, and  ftp protocols, it uses sun.net.www.protocol.<protocol>.Handler.  I would have thought that those handlers for them would have resolved earlier in that method. but the call to newInstance() fails for the reason that it can't find a constructor which doesn't take no arguments.  When I use reflection to look at Consructors or DeclaredConstructors for those handler class I get a zero length array back. I don't understand why that's the case, but it not import because here's what I did to solve the problem.:

Before starting up Felix I created my own URLStreamHandlerFactory class and the constructor for that class calls URL.setURLStreamHandlerFactory.  Here's the code I used to do that:

 
{code:java}
private class InternalURLStreamFactory implements URLStreamHandlerFactory {

  URLStreamHandler fileHandler = null;
  URLStreamHandler jarHandler = null;
  URLStreamHandler ftpHandler = null;
  URLStreamHandler httpHandler = null;
  URLStreamHandler httpsHandler = null;

  private InternalURLStreamFactory () {
    boolean fail = false;
    fileHandler = getHandler("file://test");
    jarHandler = getHandler("jar:file:/home/duke/duke.jar!/");
    ftpHandler = getHandler("ftp://myname@host.dom/%2Fetc/motd");
    httpHandler = getHandler("http://headstone/service/MyPage.html");
    httpsHandler = getHandler("https://flintstone/service/MySecurePage.html");
    URL.setURLStreamHandlerFactory(this);
 }

  private URLStreamHandler getHandler (String exampleURL) {
    try {
      URL url = new URL (exampleURL);
      Field handlerField = url.getClass().getDeclaredField("handler");
      handlerField.setAccessible(true);
      return (URLStreamHandler) handlerField.get(url);

    } catch (Exception e) {
    }
    return null;
  }

  @Override
  public URLStreamHandler createURLStreamHandler(String protocol) {
    URLStreamHandler handler = null;
    switch (protocol.toLowerCase()) {
    case "file":
      handler = fileHandler;
      break;
    case "jar":
      handler = jarHandler;
      break;
    case "ftp":
      handler = ftpHandler;
      break;
    case "http":
      handler = httpHandler;
      break;
    case "https":
      handler = httpsHandler;
      break;
    }
    return handler;
  }
}
 
{code}
As you can see, I get all the handlers for the supported protocols by generating a dummy URL command for each protocol, extracting the hander from the dummy URL object, and caching handler for each supported protocol. This cached value is passed back when the createURLStream handler is called.  Again, this needs to be done before starting Felix.  Felix will first use the URLStreamFactory if one is available , before it begins its time consuming hunt for a handler.



--
This message was sent by Atlassian Jira
(v8.3.4#803005)