FELIX-3345 Apply patch FELIX-3345-2.diff by David Jencks (thanks alot) slightly reformatted and turned around checks (assuming the positive success of failure)

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1298266 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/Activator.java b/scr/src/main/java/org/apache/felix/scr/impl/Activator.java
index 267f7dc..aa2c2b2 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/Activator.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/Activator.java
@@ -352,15 +352,22 @@
             if ( activators[i] instanceof BundleComponentActivator )
             {
                 final BundleComponentActivator ga = ( BundleComponentActivator ) activators[i];
-                final Bundle bundle = ga.getBundleContext().getBundle();
                 try
                 {
-                    ga.dispose( ComponentConstants.DEACTIVATION_REASON_DISPOSED );
+                    final Bundle bundle = ga.getBundleContext().getBundle();
+                    try
+                    {
+                        ga.dispose( ComponentConstants.DEACTIVATION_REASON_DISPOSED );
+                    }
+                    catch ( Exception e )
+                    {
+                        log( LogService.LOG_ERROR, m_context.getBundle(), "Error while disposing components of bundle "
+                            + bundle.getSymbolicName() + "/" + bundle.getBundleId(), e );
+                    }
                 }
-                catch ( Exception e )
+                catch ( IllegalStateException e )
                 {
-                    log( LogService.LOG_ERROR, m_context.getBundle(), "Error while disposing components of bundle "
-                        + bundle.getSymbolicName() + "/" + bundle.getBundleId(), e );
+                    //bundle context was already shut down in another thread, bundle is not available.
                 }
             }
         }
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/BundleComponentActivator.java b/scr/src/main/java/org/apache/felix/scr/impl/BundleComponentActivator.java
index 86b9d9d..e3da405 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/BundleComponentActivator.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/BundleComponentActivator.java
@@ -465,7 +465,7 @@
 
 
     /**
-     * Returns an array of {@link ComponentManager} instances which match the
+     * Returns an array of {@link ComponentHolder} instances which match the
      * <code>name</code>. If the <code>name</code> is <code>null</code> an
      * array of all currently known component managers is returned. Otherwise
      * an array containing a single component manager matching the name is
@@ -611,14 +611,23 @@
                 message = "[" + metadata.getName() + "] " + message;
             }
 
-            Object logger = m_logService.getService();
-            if ( logger == null )
+            ServiceTracker logService = m_logService;
+            if ( logService != null )
             {
-                Activator.log( level, getBundleContext().getBundle(), message, ex );
+                Object logger = logService.getService();
+                if ( logger == null )
+                {
+                    Activator.log( level, getBundleContext().getBundle(), message, ex );
+                }
+                else
+                {
+                    ( ( LogService ) logger ).log( level, message, ex );
+                }
             }
             else
             {
-                ( ( LogService ) logger ).log( level, message, ex );
+                // BCA has been disposed off, bundle context is probably invalid. Try to log something.
+                Activator.log( level, null, message, ex );
             }
         }
     }
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java b/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java
index 7a1e137..3612d3e 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java
@@ -109,7 +109,14 @@
                     }
                     finally
                     {
-                        bundleContext.ungetService(caRef);
+                        try
+                        {
+                            bundleContext.ungetService( caRef );
+                        }
+                        catch ( IllegalStateException e )
+                        {
+                            // ignore, bundle context was shut down during the above.
+                        }
                     }
                 }
             }
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java
index f386cfa..3068384 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java
@@ -73,22 +73,22 @@
     private int m_size;
 
     // the object on which the bind/undind methods are to be called
-    private transient Object m_componentInstance;
+    private volatile Object m_componentInstance;
 
     // the bind method
-    private BindMethod m_bind;
+    private volatile BindMethod m_bind;
 
     // the updated method
-    private UpdatedMethod m_updated;
+    private volatile UpdatedMethod m_updated;
 
     // the unbind method
-    private UnbindMethod m_unbind;
+    private volatile UnbindMethod m_unbind;
 
     // the target service filter string
-    private String m_target;
+    private volatile String m_target;
 
     // the target service filter
-    private Filter m_targetFilter;
+    private volatile Filter m_targetFilter;
 
 
     /**
@@ -121,23 +121,23 @@
     /**
      * Initialize binding methods.
      */
-    private void initBindingMethods()
+    private void initBindingMethods(Class instanceClass)
     {
         m_bind = new BindMethod( m_componentManager,
                                  m_dependencyMetadata.getBind(),
-                                 m_componentInstance.getClass(),
+                                 instanceClass,
                                  m_dependencyMetadata.getName(),
                                  m_dependencyMetadata.getInterface()
         );
         m_updated = new UpdatedMethod( m_componentManager,
                 m_dependencyMetadata.getUpdated(),
-                m_componentInstance.getClass(),
+                instanceClass,
                 m_dependencyMetadata.getName(),
                 m_dependencyMetadata.getInterface()
         );
         m_unbind = new UnbindMethod( m_componentManager,
             m_dependencyMetadata.getUnbind(),
-            m_componentInstance.getClass(),
+            instanceClass,
             m_dependencyMetadata.getName(),
             m_dependencyMetadata.getInterface()
         );
@@ -816,7 +816,18 @@
         Object service = m_bound.remove( serviceReference );
         if ( service != null && service != BOUND_SERVICE_SENTINEL )
         {
-            m_componentManager.getActivator().getBundleContext().ungetService( serviceReference );
+            try
+            {
+                m_componentManager.getActivator().getBundleContext().ungetService( serviceReference );
+            }
+            catch ( IllegalStateException e )
+            {
+                m_componentManager.log( LogService.LOG_INFO,
+                    "For dependency {0}, trying to unget ServiceReference {1} on invalid bundle context {2}",
+                    new Object[]
+                        { m_dependencyMetadata.getName(), serviceReference.getProperty( Constants.SERVICE_ID ),
+                            serviceReference }, null );
+            }
         }
     }
 
@@ -863,8 +874,8 @@
 
     boolean open( Object instance )
     {
+        initBindingMethods( instance.getClass() );
         m_componentInstance = instance;
-        initBindingMethods();
         return bind();
     }
 
@@ -1025,20 +1036,30 @@
         // null. This is valid for both immediate and delayed components
         if( m_componentInstance != null )
         {
-            return m_bind.invoke( m_componentInstance, new BindMethod.Service()
+            if ( m_bind != null )
             {
-                public ServiceReference getReference()
+                return m_bind.invoke( m_componentInstance, new BindMethod.Service()
                 {
-                    bindService( ref );
-                    return ref;
-                }
+                    public ServiceReference getReference()
+                    {
+                        bindService( ref );
+                        return ref;
+                    }
 
 
-                public Object getInstance()
-                {
-                    return getService( ref );
-                }
-            }, true );
+                    public Object getInstance()
+                    {
+                        return getService( ref );
+                    }
+                }, true );
+            }
+
+            // Concurrency Issue: The component instance still exists but
+            // but the defined bind method field is null, fail binding
+            m_componentManager.log( LogService.LOG_INFO,
+                "DependencyManager : Component instance present, but DependencyManager shut down (no bind method)",
+                null );
+            return false;
         }
         else if ( !m_componentManager.getComponentMetadata().isImmediate() )
         {