FELIX-3456 use Registered status to create component if missing

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1371287 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/BaseMethod.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/BaseMethod.java
index cc2c912..622ee32 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/helper/BaseMethod.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/BaseMethod.java
@@ -184,8 +184,8 @@
             {
                 // log and return null
                 getComponentManager().log( LogService.LOG_ERROR,
-                    "findMethod: Suitable but non-accessible method found in class {0}", new Object[]
-                        { targetClass.getName() }, null );
+                    "findMethod: Suitable but non-accessible method {0} found in class {1}, subclass of {2}", new Object[]
+                        { getMethodName(), theClass.getName(), targetClass.getName() }, null );
                 break;
             }
 
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/BindMethod.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/BindMethod.java
index a542ba3..4d22578 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/helper/BindMethod.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/BindMethod.java
@@ -38,15 +38,13 @@
 
     private static final Class OBJECT_CLASS = Object.class;
 
-    private final String m_referenceName;
     private final String m_referenceClassName;
 
 
     public BindMethod( final AbstractComponentManager componentManager, final String methodName,
-        final Class componentClass, final String referenceName, final String referenceClassName )
+            final Class componentClass, final String referenceClassName )
     {
         super( componentManager, methodName, componentClass );
-        m_referenceName = referenceName;
         m_referenceClassName = referenceClassName;
     }
 
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/UnbindMethod.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/UnbindMethod.java
index 4c4150b..b0db1e4 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/helper/UnbindMethod.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/UnbindMethod.java
@@ -31,7 +31,7 @@
     public UnbindMethod( final AbstractComponentManager componentManager, final String methodName,
         final Class componentClass, final String referenceName, final String referenceClassName )
     {
-        super( componentManager, methodName, componentClass, referenceName, referenceClassName );
+        super( componentManager, methodName, componentClass, referenceClassName );
     }
 
 
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/UpdatedMethod.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/UpdatedMethod.java
index 2283888..2f68714 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/helper/UpdatedMethod.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/UpdatedMethod.java
@@ -31,7 +31,7 @@
     public UpdatedMethod( final AbstractComponentManager componentManager, final String methodName,
         final Class componentClass, final String referenceName, final String referenceClassName )
     {
-        super( componentManager, methodName, componentClass, referenceName, referenceClassName );
+        super( componentManager, methodName, componentClass, referenceClassName );
     }
 
 
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
index a1c3d02..97b5265 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
@@ -31,6 +31,7 @@
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
+import EDU.oswego.cs.dl.util.concurrent.ReaderPreferenceReadWriteLock;
 import org.apache.felix.scr.Component;
 import org.apache.felix.scr.Reference;
 import org.apache.felix.scr.impl.BundleComponentActivator;
@@ -90,7 +91,7 @@
     private BundleComponentActivator m_activator;
 
     // The ServiceRegistration
-    private final AtomicReferenceWrapper m_serviceRegistration = new AtomicReferenceWrapper(  );
+    private final AtomicReferenceWrapper m_serviceRegistration;
 
     private final LockWrapper m_stateLock;
 
@@ -114,10 +115,12 @@
         if (JUC_AVAILABLE)
         {
             m_stateLock = new JLock();
+            m_serviceRegistration = new JAtomicReferenceWrapper();
         }
         else
         {
             m_stateLock = new EDULock();
+            m_serviceRegistration = new EDUAtomicReferenceWrapper();
         }
 
         // dump component details
@@ -151,17 +154,15 @@
     //ImmediateComponentHolder should be in this manager package and this should be default access.
     public final boolean obtainReadLock()
     {
-//        new Exception("Stack trace obtainReadLock").printStackTrace();
         if (m_stateLock.getReadHoldCount() >0)
         {
             return false;
-//            throw new IllegalStateException( "nested read locks" );
         }
         try
         {
             if (!m_stateLock.tryReadLock( m_timeout ) )
             {
-                throw new IllegalStateException( "Could not obtain lock" );
+                throw new IllegalStateException( "Could not obtain lock in " + m_timeout + " milliseconds for component " + m_componentMetadata.getName() );
             }
         }
         catch ( InterruptedException e )
@@ -175,13 +176,11 @@
 
     public final void releaseReadLock()
     {
-//        new Exception("Stack trace releaseReadLock").printStackTrace();
         m_stateLock.unlockReadLock();
     }
 
-    public final void escalateLock()
+    final void escalateLock()
     {
-//        new Exception("Stack trace escalateLock").printStackTrace();
         m_stateLock.unlockReadLock();
         try
         {
@@ -197,13 +196,12 @@
         }
     }
 
-    public final void deescalateLock()
+    final void deescalateLock()
     {
-//        new Exception("Stack trace deescalateLock").printStackTrace();
         m_stateLock.deescalate();
     }
 
-    public final void checkLocked()
+    final void checkLocked()
     {
         if ( m_stateLock.getReadHoldCount() == 0 && m_stateLock.getWriteHoldCount() == 0 )
         {
@@ -211,7 +209,7 @@
         }
     }
 
-    public final boolean isWriteLocked()
+    final boolean isWriteLocked()
     {
         return m_stateLock.getWriteHoldCount() > 0;
     }
@@ -924,7 +922,7 @@
      */
     public Dictionary getServiceProperties()
     {
-        return copyTo( null, getProperties(), false);
+        return copyTo( null, getProperties(), false );
     }
 
     /**
@@ -1304,6 +1302,10 @@
                 acm.escalateLock();
                 try
                 {
+                    if ( acm.isImmediate() )
+                    {
+                        acm.changeState( Active.getInstance() );
+                    }
                     if ( !acm.createComponent() )
                     {
                         // component creation failed, not active now
@@ -1629,45 +1631,62 @@
         }
     }
 
-    private static class EDULock implements LockWrapper
+    private static class EDULock extends EDU.oswego.cs.dl.util.concurrent.ReentrantWriterPreferenceReadWriteLock implements LockWrapper
     {
-        private final EDU.oswego.cs.dl.util.concurrent.ReentrantLock lock = new EDU.oswego.cs.dl.util.concurrent.ReentrantLock();
-
         public boolean tryReadLock( long milliseconds ) throws InterruptedException
         {
-            return lock.attempt( milliseconds );
+            return readLock().attempt( milliseconds );
         }
 
         public long getReadHoldCount()
         {
-            return lock.holds();
+            return readers_.size();
         }
 
         public void unlockReadLock()
         {
-            lock.release();
+            readLock().release();
         }
 
         public boolean tryWriteLock( long milliseconds ) throws InterruptedException
         {
-            return false;
+            return writeLock().attempt( milliseconds );
         }
 
         public long getWriteHoldCount()
         {
-            return 0;
+            return writeHolds_;
         }
 
         public void unlockWriteLock()
         {
+            writeLock().release();
         }
 
         public void deescalate()
         {
+            try
+            {
+                readLock().acquire();
+            }
+            catch ( InterruptedException e )
+            {
+                //should not happen, we have the write lock
+                throw ( IllegalStateException ) new IllegalStateException( "Unexpected InterruptedException while acquiring read lock and holding write lock" ).initCause( e );
+            }
+            writeLock().release();
         }
     }
 
-    static class AtomicReferenceWrapper
+    private interface AtomicReferenceWrapper
+    {
+        ServiceRegistration get();
+
+        boolean compareAndSet(ServiceRegistration expected, ServiceRegistration replacement);
+
+    }
+
+    private static class JAtomicReferenceWrapper implements AtomicReferenceWrapper
     {
         private final AtomicReference ref = new AtomicReference(  );
 
@@ -1681,4 +1700,20 @@
             return ref.compareAndSet( expected, replacement );
         }
     }
+
+    private static class EDUAtomicReferenceWrapper implements AtomicReferenceWrapper
+    {
+        private final EDU.oswego.cs.dl.util.concurrent.SynchronizedRef ref = new EDU.oswego.cs.dl.util.concurrent.SynchronizedRef( null );
+
+        public ServiceRegistration get()
+        {
+            return ( ServiceRegistration ) ref.get();
+        }
+
+        public boolean compareAndSet(ServiceRegistration expected, ServiceRegistration replacement)
+        {
+            return ref.commit( expected, replacement );
+        }
+    }
+
 }
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/ConfigurationComponentFactoryImpl.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/ConfigurationComponentFactoryImpl.java
index e698544..a6ac519 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/ConfigurationComponentFactoryImpl.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/ConfigurationComponentFactoryImpl.java
@@ -258,5 +258,9 @@
             super( activator, componentHolder, metadata );
         }
 
+        public boolean isImmediate()
+        {
+            return true;
+        }
     }
 }
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/DelayedComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/DelayedComponentManager.java
index b203505..1c94b8e 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/DelayedComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/DelayedComponentManager.java
@@ -32,10 +32,6 @@
 public class DelayedComponentManager extends ImmediateComponentManager
 {
 
-//    // keep the using bundles as reference "counters" for instance deactivation
-//    private int m_useCount;
-
-
     /**
      * @param activator
      * @param metadata
@@ -44,65 +40,12 @@
         ComponentMetadata metadata )
     {
         super( activator, componentHolder, metadata );
-//        this.m_useCount = 0;
     }
 
-//    protected void deleteComponent( int reason )
+
+//    State getSatisfiedState()
 //    {
-//        // only have to delete, if there is actually an instance
-//        if ( getInstance() != null )
-//        {
-//            super.deleteComponent( reason );
-//        }
-//
-//        // ensure the refence set is also clear
-////        m_useCount = 0;
+//        return Registered.getInstance();
 //    }
 
-    State getSatisfiedState()
-    {
-        return Registered.getInstance();
-    }
-
-    //---------- ServiceFactory interface -------------------------------------
-
-//    public Object getService( Bundle bundle, ServiceRegistration sr )
-//    {
-//        obtainReadLock();
-//        try
-//        {
-//            m_useCount++;
-//            return state().getService( this );
-//        }
-//        finally
-//        {
-//            releaseReadLock();
-//        }
-//    }
-//
-//    public void ungetService( Bundle bundle, ServiceRegistration sr, Object service )
-//    {
-//        obtainReadLock();
-//        try
-//        {
-//            // the framework should not call ungetService more than it calls
-//            // calls getService. Still, we want to be sure to not go below zero
-//            if ( m_useCount > 0 )
-//            {
-//                m_useCount--;
-//
-//                // unget the service instance if no bundle is using it
-//                // any longer unless delayed component instances have to
-//                // be kept (FELIX-3039)
-//                if ( m_useCount == 0 && !getActivator().getConfiguration().keepInstances() )
-//                {
-//                    state().ungetService( this );
-//                }
-//            }
-//        }
-//        finally
-//        {
-//            releaseReadLock();
-//        }
-//    }
 }
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 578ff1c..c292180 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
@@ -125,8 +125,7 @@
         m_bind = new BindMethod( m_componentManager,
                                  m_dependencyMetadata.getBind(),
                                  instanceClass,
-                                 m_dependencyMetadata.getName(),
-                                 m_dependencyMetadata.getInterface()
+                m_dependencyMetadata.getInterface()
         );
         m_updated = new UpdatedMethod( m_componentManager,
                 m_dependencyMetadata.getUpdated(),
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/ImmediateComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/ImmediateComponentManager.java
index 5e5b0f3..875749a 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/ImmediateComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/ImmediateComponentManager.java
@@ -150,6 +150,7 @@
         if ( m_implementationObject != null )
         {
             disposeImplementationObject( m_implementationObject, m_componentContext, reason );
+            m_useCount = 0;
             m_implementationObject = null;
             m_componentContext = null;
             m_properties = null;
@@ -310,7 +311,7 @@
 
     State getSatisfiedState()
     {
-        return Active.getInstance();
+        return Registered.getInstance();
     }
 
     protected void setFactoryProperties( Dictionary dictionary )
@@ -627,8 +628,13 @@
                 {
                     if ( m_useCount == 0 )
                     {
-                        m_useCount++;
-                        return state().getService( this );
+                        //state should be "Registered"
+                        Object result = state().getService( this );
+                        if ( result != null )
+                        {
+                            m_useCount++;
+                        }
+                        return result;
                     }
                 }
                 finally
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/helper/BindMethodTest.java b/scr/src/test/java/org/apache/felix/scr/impl/helper/BindMethodTest.java
index 4ad5c3f..595f61c 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/helper/BindMethodTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/helper/BindMethodTest.java
@@ -439,8 +439,8 @@
             }
         };
         ImmediateComponentManager icm = new ImmediateComponentManager( null, null, metadata );
-        BindMethod bm = new BindMethod( icm, methodName, component.getClass(), "reference",
-            FakeService.class.getName() );
+        BindMethod bm = new BindMethod( icm, methodName, component.getClass(),
+                FakeService.class.getName() );
         bm.invoke( component, m_service, null );
         assertEquals( expectCallPerformed, component.callPerformed );
     }