You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by pa...@apache.org on 2009/10/20 23:28:10 UTC

svn commit: r827806 - in /felix/trunk/framework/src/main/java/org/apache/felix/framework: ExtensionManager.java ModuleImpl.java URLHandlers.java URLHandlersStreamHandlerProxy.java util/SecureAction.java

Author: pauls
Date: Tue Oct 20 21:28:10 2009
New Revision: 827806

URL: http://svn.apache.org/viewvc?rev=827806&view=rev
Log:
Fix various error during start-up on gnu/classpath based VMs (jamvm, kaffe, cacao) and mika (FELIX-1782). Mainly, catch throwable instead of exceptions when we look for dalvik specific classes and add a couple of workarounds to URLHandlers.

Modified:
    felix/trunk/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlers.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java?rev=827806&r1=827805&r2=827806&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java Tue Oct 20 21:28:10 2009
@@ -88,9 +88,19 @@
 
     static
     {
+        // pre-init the url sub-system as otherwise we don't work on gnu/classpath
+        ExtensionManager extensionManager = new ExtensionManager();
+        try 
+        {
+            (new URL("http://felix.extensions:9/")).openConnection();
+        }
+        catch (Throwable t)
+        {
+            // This doesn't matter much - we only need the above to init the url subsystem
+        }
+        
         // We use the secure action of Felix to add a new instance to the parent
         // classloader.
-        ExtensionManager extensionManager = new ExtensionManager();
         try
         {
             Felix.m_secureAction.addURLToURLClassLoader(Felix.m_secureAction.createURL(
@@ -98,7 +108,7 @@
                 "http://felix.extensions:9/", extensionManager),
                 Felix.class.getClassLoader());
         }
-        catch (Exception ex)
+        catch (Throwable ex)
         {
             // extension bundles will not be supported.
             extensionManager = null;
@@ -375,7 +385,6 @@
             }
             catch (Throwable ex)
             {
-                ex.printStackTrace();
                 m_logger.log(Logger.LOG_WARNING,
                     "Unable to start Felix Extension Activator", ex);
             }

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java?rev=827806&r1=827805&r2=827806&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java Tue Oct 20 21:28:10 2009
@@ -112,7 +112,7 @@
             m_secureAction.setAccesssible(ctor);
             cl = (ClassLoader) m_secureAction.invoke(ctor, new Object[] { null });
         }
-        catch (Exception ex)
+        catch (Throwable ex)
         {
             // On Android we get an exception if we set the parent class loader
             // to null, so we will work around that case by setting the parent
@@ -1602,7 +1602,7 @@
             dexFileClassLoadClass = dexFileClass.getMethod("loadClass",
                 new Class[] { String.class, ClassLoader.class });
         }
-        catch (Exception ex)
+        catch (Throwable ex)
         {
            dexFileClassConstructor = null;
            dexFileClassLoadDex = null;

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlers.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlers.java?rev=827806&r1=827805&r2=827806&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlers.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlers.java Tue Oct 20 21:28:10 2009
@@ -125,7 +125,6 @@
         }
         catch (Throwable ex)
         {
-            ex.printStackTrace();
             // Ignore, this is a best effort (maybe log it or something).
         }
     }
@@ -150,7 +149,6 @@
         }
         catch (Throwable ex)
         {
-            ex.printStackTrace();
             // Ignore, this is a best effort (maybe log it or something)
         }
         m_sm = new SecurityManagerEx();
@@ -161,6 +159,15 @@
                 URL.setURLStreamHandlerFactory(this);
                 m_streamHandlerFactory = this;
                 m_rootURLHandlers = this;
+                // try to flush the cache (gnu/classpath doesn't do it itself)
+                try
+                {
+                    m_secureAction.flush(URL.class, URL.class);
+                }
+                catch (Throwable t)
+                {
+                    // Not much we can do
+                }
             }
             catch (Error err)
             {
@@ -208,6 +215,15 @@
             {
                 URLConnection.setContentHandlerFactory(this);
                 m_contentHandlerFactory = this;
+                // try to flush the cache (gnu/classpath doesn't do it itself)
+                try
+                {
+                    m_secureAction.flush(URLConnection.class, URLConnection.class);
+                }
+                catch (Throwable t)
+                {
+                    // Not much we can do
+                }
             }
             catch (Error err)
             {
@@ -341,7 +357,7 @@
                         (URLStreamHandler) handler.newInstance());
                 }
             }
-            catch (Exception ex)
+            catch (Throwable ex)
             {
                 // This could be a class not found exception or an
                 // instantiation exception, not much we can do in either

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java?rev=827806&r1=827805&r2=827806&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java Tue Oct 20 21:28:10 2009
@@ -28,8 +28,6 @@
 import java.net.URL;
 import java.net.URLConnection;
 import java.net.URLStreamHandler;
-import java.util.Collections;
-import java.util.Arrays;
 
 import org.apache.felix.framework.util.SecureAction;
 import org.osgi.service.url.URLStreamHandlerService;
@@ -360,6 +358,10 @@
         }
     }
 
+    // We use this thread local to detect whether we have a reentrant entry to the parseURL 
+    // method. This can happen do to some difference between gnu/classpath and sun jvms
+    // For more see inside the method.
+    private static final ThreadLocal m_loopCheck = new ThreadLocal();
     protected void parseURL(URL url, String spec, int start, int limit)
     {
         Object svc = getStreamHandlerService();
@@ -377,17 +379,50 @@
             try 
             {
                 URL test = null;
+                // In order to cater for built-in urls being over-writable we need to use a 
+                // somewhat strange hack. We use a hidden feature inside the jdk which passes
+                // the handler of the url given as a context to a new URL to that URL as its
+                // handler. This way, we can create a new URL which will use the given built-in
+                // handler to parse the url. Subsequently, we can use the information from that
+                // URL to call set with the correct values. 
                 if (m_builtInURL != null)
                 {
-                    test = new URL(new URL(m_builtInURL, url.toExternalForm()), spec);
+                    // However, if we are on gnu/classpath we have to pass the handler directly
+                    // because the hidden feature is not there. Funnily, the workaround to pass
+                    // pass the handler directly doesn't work on sun as their handler detects
+                    // that it is not the same as the one inside the url and throws an exception
+                    // Luckily it doesn't do that on gnu/classpath. We detect that we need to 
+                    // pass the handler directly by using the m_loopCheck thread local to detect
+                    // that we parseURL has been called inside a call to parseURL.
+                    if (m_loopCheck.get() != null)
+                    {
+                        test = new URL(new URL(m_builtInURL, url.toExternalForm()), spec, (URLStreamHandler) svc);
+                    }
+                    else
+                    {
+                        // Set-up the thread local as we don't expect to be called again until we are
+                        // done. Otherwise, we are on gnu/classpath
+                        m_loopCheck.set(Thread.currentThread());
+                        try
+                        {
+                            test = new URL(new URL(m_builtInURL, url.toExternalForm()), spec);
+                        }
+                        finally
+                        {
+                            m_loopCheck.set(null);
+                        }
+                    }
                 }
                 else
                 {
+                    // We don't have a url with a built-in handler for this but still want to create
+                    // the url with the buil-in handler as we could find one now. This might not 
+                    // work for all handlers on sun but it is better then doing nothing. 
                     test = m_action.createURL(url, spec, (URLStreamHandler) svc);
                 }
-                    
+
                 super.setURL(url, test.getProtocol(), test.getHost(), test.getPort(),test.getAuthority(), 
-                   test.getUserInfo(), test.getPath(), test.getQuery(), test.getRef());
+                    test.getUserInfo(), test.getPath(), test.getQuery(), test.getRef());
             } 
             catch (Exception ex)  
             {
@@ -452,8 +487,17 @@
         {
             try 
             {
-                return (String) TO_EXTERNAL_FORM.invoke( 
+                String result = (String) TO_EXTERNAL_FORM.invoke( 
                     svc, new Object[]{url});
+                
+                // mika does return an invalid format if we have a url with the 
+                // protocol only (<proto>://null) - we catch this case now
+                if ((result != null) && (result.equals(url.getProtocol() + "://null")))
+                {
+                    result = url.getProtocol() + ":";
+                }
+                
+                return result;
             }
             catch (InvocationTargetException ex)
             {
@@ -484,7 +528,7 @@
             answer.append(url.getProtocol());
             answer.append(':');
             String authority = url.getAuthority();
-            if (authority != null && authority.length() > 0) 
+            if ((authority != null) && (authority.length() > 0)) 
             {
                 answer.append("//"); //$NON-NLS-1$
                 answer.append(url.getAuthority());
@@ -563,6 +607,13 @@
         }
         catch (Throwable t)
         {
+            // In case that we are inside tomcat - the problem is that the webapp classloader
+            // creates a new url to load a class. This gets us to this method. Now, if we 
+            // trigger a classload while executing tomcat is creating a new url and we end-up with
+            // a loop which is cut short after two iterations (because of a circularclassload). 
+            // We catch this exception (and all others) and just return the built-in handler
+            // (if we have any) as this way we at least eventually get started (this just means 
+            // that we don't use the potentially provided built-in handler overwrite). 
             return m_builtIn;
         }
     }

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java?rev=827806&r1=827805&r2=827806&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java Tue Oct 20 21:28:10 2009
@@ -22,6 +22,7 @@
 import java.lang.reflect.*;
 import java.net.*;
 import java.security.*;
+import java.util.HashMap;
 import java.util.Hashtable;
 
 import org.osgi.framework.BundleActivator;
@@ -996,6 +997,60 @@
         return null;
     }
 
+    public void flush(Class targetClazz, Object lock) throws Exception
+    {
+        if (System.getSecurityManager() != null)
+        {
+            Actions actions = (Actions) m_actions.get();
+            actions.set(Actions.FLUSH_FIELD_ACTION, targetClazz, lock);
+            try
+            {
+                AccessController.doPrivileged(actions, m_acc);
+            }
+            catch (PrivilegedActionException e)
+            {
+                throw e.getException();
+            }
+        }
+        else
+        {
+            _flush(targetClazz, lock);
+        }
+    }
+
+    private static void _flush(Class targetClazz, Object lock) throws Exception
+    {
+        synchronized (lock) 
+        {
+            Field[] fields = targetClazz.getDeclaredFields();
+            // reset cache
+            for (int i = 0; i < fields.length; i++)
+            {
+                if (Modifier.isStatic(fields[i].getModifiers()) &&
+                    ((fields[i].getType() == Hashtable.class) || (fields[i].getType() == HashMap.class)))
+                {
+                    fields[i].setAccessible(true);
+                    if (fields[i].getType() == Hashtable.class)
+                    {
+                        Hashtable cache = (Hashtable) fields[i].get(null);
+                        if (cache != null)
+                        {
+                            cache.clear();
+                        }
+                    }
+                    else
+                    {
+                        HashMap cache = (HashMap) fields[i].get(null);
+                        if (cache != null)
+                        {
+                            cache.clear();
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     private static class Actions implements PrivilegedExceptionAction
     {
         public static final int INITIALIZE_CONTEXT = 0;
@@ -1038,6 +1093,7 @@
         public static final int STOP_ACTIVATOR_ACTION = 37;
         public static final int SWAP_FIELD_ACTION = 38;
         public static final int SYSTEM_EXIT_ACTION = 39;
+        public static final int FLUSH_FIELD_ACTION = 40;
 
         private int m_action = -1;
         private Object m_arg1 = null;
@@ -1280,6 +1336,10 @@
             {
                 ((AccessibleObject) arg1).setAccessible(true);
             }
+            else if (action == FLUSH_FIELD_ACTION)
+            {
+                _flush(((Class) arg1), arg2);
+            }
 
             return null;
         }