You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by pd...@apache.org on 2015/07/09 00:10:16 UTC

svn commit: r1689973 [17/25] - in /felix/sandbox/pderop/dependencymanager.ds: cnf/ext/ cnf/localrepo/ cnf/localrepo/org.apache.felix.framework/ cnf/releaserepo/ org.apache.felix.dependencymanager.ds.itest/ org.apache.felix.dependencymanager.ds.itest/.s...

Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/EdgeInfo.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/EdgeInfo.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/EdgeInfo.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/EdgeInfo.java Wed Jul  8 22:10:14 2015
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.scr.impl.manager;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.osgi.service.log.LogService;
+
+/**
+ * EdgeInfo holds information about the service event tracking counts for creating (open) and disposing (close) 
+ * implementation object instances per dependency manager.  These need to be maintained for each implementation object instance
+ * because each instance (for a service factory) will have different sets of service references available.  These need to be 
+ * maintained for each dependency manager because the open/close tracking counts are obtained when the set of current
+ * service references is obtained, using a lock internal to the service tracker.
+ * 
+ *
+ * The information in the open/close counts is used in the outOfRange method which determines if a service event tracking count 
+ * occurred before the "open" event (in which case it is reflected in the open set already and does not need to be processed separately)
+ * or after the "close" event (in which case it is reflected in the close set already).
+ * 
+ * The open latch is used to make sure that elements in the open set are completely processed before updated or unbind events
+ *  are processed
+ * The close latch is used to make sure that unbind events that are out of range wait for the close to complete before returning; 
+ * in this case the unbind is happening in the "close" thread rather than the service event thread, so we wait for the close to complete 
+ * so that when the service event returns the unbind will actually have been completed.
+ * 
+ * Related to this functionality is the missing tracking in AbstractComponentManager.  This is used on close of an instance to make 
+ * sure all service events occuring before close starts complete processing before the close takes action.
+ *
+ */
+
+class EdgeInfo
+{
+    private int open = -1;
+    private int close = -1;
+    private final CountDownLatch openLatch = new CountDownLatch(1);
+    private final CountDownLatch closeLatch = new CountDownLatch(1);
+
+    public void setClose( int close )
+    {
+        this.close = close;
+    }
+
+    public CountDownLatch getOpenLatch()
+    {
+        return openLatch;
+    }
+    
+    public void waitForOpen(AbstractComponentManager<?> m_componentManager, String componentName, String methodName)
+    {
+        
+        CountDownLatch latch = getOpenLatch();
+        String latchName = "open";
+        waitForLatch( m_componentManager, latch, componentName, methodName, latchName );
+    }
+
+    public void waitForClose(AbstractComponentManager<?> m_componentManager, String componentName, String methodName)
+    {
+        
+        CountDownLatch latch = getCloseLatch();
+        String latchName = "close";
+        waitForLatch( m_componentManager, latch, componentName, methodName, latchName );
+    }
+
+    private void waitForLatch(AbstractComponentManager<?> m_componentManager, CountDownLatch latch, String componentName,
+            String methodName, String latchName)
+    {
+        try
+        {
+            if (!latch.await( m_componentManager.getLockTimeout(), TimeUnit.MILLISECONDS ))
+            {
+                m_componentManager.log( LogService.LOG_ERROR,
+                        "DependencyManager : {0} : timeout on {1} latch {2}",  new Object[] {methodName, latchName, componentName}, null );
+                m_componentManager.dumpThreads();
+            }
+        }
+        catch ( InterruptedException e )
+        {
+            try
+            {
+                if (!latch.await( m_componentManager.getLockTimeout(), TimeUnit.MILLISECONDS ))
+                {
+                    m_componentManager.log( LogService.LOG_ERROR,
+                            "DependencyManager : {0} : timeout on {1} latch {2}",  new Object[] {methodName, latchName, componentName}, null );
+                    m_componentManager.dumpThreads();
+                }
+            }
+            catch ( InterruptedException e1 )
+            {
+                m_componentManager.log( LogService.LOG_ERROR,
+                        "DependencyManager : {0} : Interrupted twice on {1} latch {2}",  new Object[] {methodName, latchName, componentName}, null );
+                Thread.currentThread().interrupt();
+            }
+            Thread.currentThread().interrupt();
+        }
+    }
+
+    public CountDownLatch getCloseLatch()
+    {
+        return closeLatch;
+    }
+
+    public void setOpen( int open )
+    {
+        this.open = open;
+    }
+    
+    public void ignore()
+    {
+        open = Integer.MAX_VALUE;
+        close = Integer.MAX_VALUE - 1;
+        openLatch.countDown();
+        closeLatch.countDown();
+    }
+
+    /**
+     * Returns whether the tracking count is before the open count or after the close count (if set)
+     * This must be called from within a block synchronized on m_tracker.tracked().
+     * Setting open occurs in a synchronized block as well, to the tracker's current tracking count.
+     * Therefore if this outOfRange call finds open == -1 then open will be set to a tracking count 
+     * at least as high as the argument tracking count.
+     * @param trackingCount tracking count from tracker to compare with range
+     * @return true if open not set, tracking count before open, or close set and tracking count after close.
+     */
+    public boolean outOfRange( int trackingCount )
+    {
+        return open == -1 
+                || trackingCount < open
+                || (close != -1 && trackingCount > close);
+    }
+    
+    public boolean beforeRange( int trackingCount )
+    {
+        return open == -1 || trackingCount < open;
+    }
+    
+    public boolean afterRange( int trackingCount )
+    {
+        return close != -1 && trackingCount > close;
+    }
+}
\ No newline at end of file

Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/MultiplePrototypeRefPair.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/MultiplePrototypeRefPair.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/MultiplePrototypeRefPair.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/MultiplePrototypeRefPair.java Wed Jul  8 22:10:14 2015
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package org.apache.felix.scr.impl.manager;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.felix.scr.impl.helper.SimpleLogger;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceObjects;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogService;
+
+/**
+ * @version $Rev: 1689302 $ $Date: 2015-07-06 03:31:39 +0200 (Mon, 06 Jul 2015) $
+ */
+public class MultiplePrototypeRefPair<S, T> extends RefPair<S, T>
+{
+    private final ServiceObjects<T> serviceObjects;
+    private final ConcurrentMap<ComponentContextImpl<S>, T> instances = new ConcurrentHashMap<ComponentContextImpl<S>, T>();
+
+    public MultiplePrototypeRefPair( BundleContext context, ServiceReference<T> ref )
+    {
+        super(ref);
+        this.serviceObjects = context.getServiceObjects(ref);
+    }
+
+    @Override
+    public ServiceObjects<T> getServiceObjects()
+    {
+        return serviceObjects;
+    }
+
+    @Override
+    public T getServiceObject(ComponentContextImpl<S> key)
+    {
+        return instances.get( key );
+    }
+
+    @Override
+    public boolean setServiceObject(ComponentContextImpl<S> key, T serviceObject)
+    {
+        return instances.putIfAbsent(key, serviceObject) == null;
+    }
+
+    @Override
+    public T unsetServiceObject(ComponentContextImpl<S> key)
+    {
+        return instances.get(key);
+    }
+
+    @Override
+    public String toString()
+    {
+        return "[MultiplePrototypeRefPair: ref: [" + getRef() + "] has service: [" + !instances.isEmpty() + "]]";
+    }
+
+    @Override
+    public boolean getServiceObject(ComponentContextImpl<S> key, BundleContext context,
+        SimpleLogger logger)
+    {
+    	final T service = key.getComponentServiceObjectsHelper().getPrototypeRefInstance(this.getRef(), serviceObjects);
+        if ( service == null )
+        {
+            setFailed();
+            logger.log(
+                 LogService.LOG_WARNING,
+                 "Could not get service from serviceobjects for ref {0}", new Object[] {getRef()}, null );
+            return false;
+        }
+        if (!setServiceObject(key, service))
+        {
+            // Another thread got the service before, so unget our
+            serviceObjects.ungetService( service );
+        }
+        return true;
+    }
+}

Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/PrototypeServiceFactoryComponentManager.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/PrototypeServiceFactoryComponentManager.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/PrototypeServiceFactoryComponentManager.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/PrototypeServiceFactoryComponentManager.java Wed Jul  8 22:10:14 2015
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.scr.impl.manager;
+
+import org.apache.felix.scr.impl.config.ComponentContainer;
+import org.apache.felix.scr.impl.helper.ComponentMethods;
+import org.osgi.framework.PrototypeServiceFactory;
+
+public class PrototypeServiceFactoryComponentManager<S> extends ServiceFactoryComponentManager<S> implements PrototypeServiceFactory<S>
+{
+
+    public PrototypeServiceFactoryComponentManager(ComponentContainer<S> container, ComponentMethods componentMethods)
+    {
+        super(container, componentMethods);
+    }
+
+}

Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/RefPair.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/RefPair.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/RefPair.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/RefPair.java Wed Jul  8 22:10:14 2015
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package org.apache.felix.scr.impl.manager;
+
+import org.apache.felix.scr.impl.helper.SimpleLogger;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceObjects;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * @version $Rev: 1689302 $ $Date: 2015-07-06 03:31:39 +0200 (Mon, 06 Jul 2015) $
+ */
+public abstract class RefPair<S, T>
+{
+    private final ServiceReference<T> ref;
+
+    boolean failed;
+    volatile boolean deleted;
+
+    public RefPair( ServiceReference<T> ref )
+    {
+        this.ref = ref;
+    }
+
+    public ServiceReference<T> getRef()
+    {
+        return ref;
+    }
+
+    public ServiceObjects<T> getServiceObjects()
+    {
+        return null;
+    }
+
+    public abstract boolean getServiceObject( ComponentContextImpl<S> key, BundleContext context, SimpleLogger logger );
+ 
+    public abstract T getServiceObject(ComponentContextImpl<S> key);
+
+    public abstract boolean setServiceObject( ComponentContextImpl<S> key, T serviceObject );
+    
+    public abstract T unsetServiceObject(ComponentContextImpl<S> key);
+
+    public void setFailed( )
+    {
+        this.failed = true;
+    }
+
+    public boolean isFailed()
+    {
+        return failed;
+    }
+
+    public boolean isDeleted()
+    {
+        return deleted;
+    }
+
+    public void setDeleted(boolean deleted)
+    {
+        this.deleted = deleted;
+    }
+
+
+}

Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/RegistrationManager.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/RegistrationManager.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/RegistrationManager.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/RegistrationManager.java Wed Jul  8 22:10:14 2015
@@ -0,0 +1,216 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.scr.impl.manager;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.osgi.service.log.LogService;
+
+abstract class RegistrationManager<T>
+{
+    enum RegState {unregistered, registered};
+    private static class RegStateWrapper 
+    {
+        private final CountDownLatch latch = new CountDownLatch(1);
+        private final RegState regState;
+        
+        RegStateWrapper( RegState regState )
+        {
+            this.regState = regState;
+        }
+        
+        public RegState getRegState()
+        {
+            return regState;
+        }
+        
+        public CountDownLatch getLatch()
+        {
+            return latch;
+        }
+        
+        @Override
+        public int hashCode()
+        {
+            return regState.hashCode();
+        }
+        
+        @Override
+        public boolean equals(Object other)
+        {
+            return other instanceof RegStateWrapper && regState == ((RegStateWrapper)other).getRegState();
+        }
+
+        @Override
+        public String toString()
+        {
+            return regState.toString();
+        }
+        
+        
+        
+    }
+    private final Lock registrationLock = new ReentrantLock();
+    //Deque, ArrayDeque if we had java 6
+    private final List<RegStateWrapper> opqueue = new ArrayList<RegStateWrapper>();
+
+    private volatile T m_serviceRegistration;
+    /**
+     * 
+     * @param desired desired registration state
+     * @param services services to register this under
+     * @return true if this request results in a state change, false if we are already in the desired state or some other thread 
+     * will deal with the consequences of the state change.
+     */
+    boolean changeRegistration( RegState desired, String[] services )
+    {
+        RegStateWrapper rsw = null;
+        registrationLock.lock();
+        try
+        {
+            if (opqueue.isEmpty())
+            {
+                if ((desired == RegState.unregistered) == (m_serviceRegistration == null))
+                {
+                    log( LogService.LOG_DEBUG, "Already in desired state {0}", new Object[]
+                            {desired}, null );
+                    return false; 
+                }
+            }
+            else if (opqueue.get( opqueue.size() - 1 ).getRegState() == desired)
+            {
+                log( LogService.LOG_DEBUG, "Duplicate request on other thread: registration change queue {0}", new Object[]
+                        {opqueue}, null );
+                rsw = opqueue.get( opqueue.size() - 1 );
+                return false; //another thread will do our work and owns the state change
+            }
+            rsw = new RegStateWrapper( desired );
+            opqueue.add( rsw );
+            if (opqueue.size() > 1)
+            {
+                log( LogService.LOG_DEBUG, "Allowing other thread to process request: registration change queue {0}", new Object[]
+                        {opqueue}, null );
+                return true; //some other thread will do it later but this thread owns the state change.
+            }
+            //we're next
+            do
+            {
+                log( LogService.LOG_DEBUG, "registration change queue {0}", new Object[]
+                        {opqueue}, null );
+                RegStateWrapper next = opqueue.get( 0 );
+                T serviceRegistration = m_serviceRegistration;
+                if ( next.getRegState() == RegState.unregistered)
+                {
+                    m_serviceRegistration = null;
+                }
+                    
+                registrationLock.unlock();
+                try
+                {
+                    if (next.getRegState() == RegState.registered)
+                    {
+                        serviceRegistration = register(services );
+
+                    }
+                    else 
+                    {
+                        if ( serviceRegistration != null )
+                        {
+                            unregister( serviceRegistration );
+                        }
+                        else
+                        {
+                            log( LogService.LOG_ERROR, "Unexpected unregistration request with no registration present", new Object[]
+                                    {}, new Exception("Stack trace") );
+                           
+                        }
+                    }
+                }
+                finally
+                {
+                    registrationLock.lock();
+                    opqueue.remove(0);
+                    if ( next.getRegState() == RegState.registered)
+                    {
+                        m_serviceRegistration = serviceRegistration;
+                    }
+                    next.getLatch().countDown();
+                }
+            }
+            while (!opqueue.isEmpty());
+            return true;
+        }
+        finally
+        {
+            registrationLock.unlock();
+            if (rsw != null)
+            {
+                try
+                {
+                    if ( !rsw.getLatch().await( getTimeout(), TimeUnit.MILLISECONDS ))
+                    {
+                        log( LogService.LOG_ERROR, "Timeout waiting for reg change to complete {0}", new Object[]
+                                {rsw.getRegState()}, null);
+                        reportTimeout();
+                    }
+                }
+                catch ( InterruptedException e )
+                {
+                    try
+                    {
+                        if ( !rsw.getLatch().await( getTimeout(), TimeUnit.MILLISECONDS ))
+                        {
+                            log( LogService.LOG_ERROR, "Timeout waiting for reg change to complete {0}", new Object[]
+                                    {rsw.getRegState()}, null);
+                            reportTimeout();
+                        }
+                    }
+                    catch ( InterruptedException e1 )
+                    {
+                        log( LogService.LOG_ERROR, "Interrupted twice waiting for reg change to complete {0}", new Object[]
+                                {rsw.getRegState()}, null);
+                    }
+                    Thread.currentThread().interrupt();
+                }
+            }
+        }
+
+    }
+    
+    abstract T register(String[] services);
+
+    abstract void unregister(T serviceRegistration);
+    
+    abstract void log( int level, String message, Object[] arguments, Throwable ex );
+    
+    abstract long getTimeout();
+    
+    abstract void reportTimeout();
+    
+    T getServiceRegistration()
+    {
+        return m_serviceRegistration;
+    }
+    
+}

Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/ServiceFactoryComponentManager.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/ServiceFactoryComponentManager.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/ServiceFactoryComponentManager.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/ServiceFactoryComponentManager.java Wed Jul  8 22:10:14 2015
@@ -0,0 +1,224 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.scr.impl.manager;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.IdentityHashMap;
+
+import org.apache.felix.scr.impl.config.ComponentContainer;
+import org.apache.felix.scr.impl.helper.ActivatorParameter;
+import org.apache.felix.scr.impl.helper.ComponentMethods;
+import org.apache.felix.scr.impl.helper.MethodResult;
+import org.apache.felix.scr.impl.helper.ModifiedMethod;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.component.ComponentConstants;
+import org.osgi.service.component.ComponentInstance;
+import org.osgi.service.log.LogService;
+
+
+/**
+ * The <code>ServiceFactoryComponentManager</code> for components specified with &lt;service serviceFactory='true'/&gt;
+ * in the xml metadata. The component must be delayed, not immediate or factory.
+ */
+public class ServiceFactoryComponentManager<S> extends SingleComponentManager<S>
+{
+
+    // maintain the map of ComponentContext objects created for the
+    // service instances
+    private IdentityHashMap<S, ComponentContextImpl<S>> serviceContexts = new IdentityHashMap<S, ComponentContextImpl<S>>();
+
+    /**
+     * @param container ComponentHolder for configuration management
+     * @param componentMethods
+     */
+    public ServiceFactoryComponentManager( ComponentContainer<S> container, ComponentMethods componentMethods )
+    {
+        super( container, componentMethods );
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.felix.scr.AbstractComponentManager#deleteComponent()
+     */
+    protected void deleteComponent( int reason )
+    {
+        if ( !isStateLocked() )
+        {
+            throw new IllegalStateException( "need write lock (deleteComponent)" );
+        }
+        for (ComponentContextImpl<S> componentContext: getComponentContexts() )
+        {
+            disposeImplementationObject( componentContext, reason );
+            log( LogService.LOG_DEBUG, "Unset implementation object for component {0} in deleteComponent for reason {1}", new Object[] { getName(), REASONS[ reason ] },  null );
+        }
+        serviceContexts.clear();
+        clearServiceProperties();
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.ServiceFactory#getService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration)
+     */
+    public S getService( Bundle bundle, ServiceRegistration<S> registration )
+    {
+        log( LogService.LOG_DEBUG, "ServiceFactory.getService()", null );
+
+        // When the getServiceMethod is called, the implementation object must be created
+
+        ComponentContextImpl<S> componentContext = new ComponentContextImpl<S>(this, bundle);
+        if (collectDependencies(componentContext) )
+        {
+            log( LogService.LOG_DEBUG,
+                "getService (ServiceFactory) dependencies collected.",
+                null );
+
+        }
+        else
+        {
+            //cannot obtain service from a required reference
+            return null;
+        }
+        // private ComponentContext and implementation instances
+        S service = createImplementationObject( bundle, new SetImplementationObject<S>()
+        {
+            public void presetComponentContext( ComponentContextImpl<S> componentContext )
+            {
+                synchronized ( serviceContexts )
+                {
+                    serviceContexts.put( componentContext.getImplementationObject( false ), componentContext );
+                }
+            }
+
+            public void resetImplementationObject( S implementationObject )
+            {
+                synchronized ( serviceContexts )
+                {
+                    serviceContexts.remove( implementationObject );
+                }
+            }
+
+        }, componentContext );
+
+        // register the components component context if successful
+        if ( service == null )
+        {
+            // log that the service factory component cannot be created (we don't
+            // know why at this moment; this should already have been logged)
+            log( LogService.LOG_ERROR, "Failed creating the component instance; see log for reason", null );
+        } 
+        else 
+        {
+            m_activated = true;
+        }
+
+        return service;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.ServiceFactory#ungetService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration, java.lang.Object)
+     */
+    public void ungetService( Bundle bundle, ServiceRegistration<S> registration, S service )
+    {
+        log( LogService.LOG_DEBUG, "ServiceFactory.ungetService()", null );
+
+        // When the ungetServiceMethod is called, the implementation object must be deactivated
+        // private ComponentContext and implementation instances
+        final ComponentContextImpl<S> serviceContext;
+        synchronized ( serviceContexts )
+        {
+            serviceContext = serviceContexts.get( service );
+        }
+        disposeImplementationObject( serviceContext, ComponentConstants.DEACTIVATION_REASON_DISPOSED );
+        synchronized ( serviceContexts )
+        {
+            serviceContexts.remove( service );
+            // if this was the last use of the component, go back to REGISTERED state
+            if ( serviceContexts.isEmpty() && getState() == STATE_ACTIVE )
+            {
+                m_activated = false;
+            }
+        }
+    }
+
+    private Collection<ComponentContextImpl<S>> getComponentContexts()
+    {
+        synchronized ( serviceContexts )
+        {
+            return new ArrayList<ComponentContextImpl<S>>( serviceContexts.values() );
+        }
+    }
+
+    <T> void invokeBindMethod( DependencyManager<S, T> dependencyManager, RefPair<S, T> refPair, int trackingCount )
+    {
+        for ( ComponentContextImpl<S> cc : getComponentContexts() )
+        {
+            dependencyManager.invokeBindMethod( cc, refPair, trackingCount, cc.getEdgeInfo( dependencyManager ) );
+        }
+    }
+
+    <T> void invokeUpdatedMethod( DependencyManager<S, T> dependencyManager, RefPair<S, T> refPair, int trackingCount )
+    {
+        for ( ComponentContextImpl<S> cc : getComponentContexts() )
+        {
+            dependencyManager.invokeUpdatedMethod( cc, refPair, trackingCount, cc.getEdgeInfo( dependencyManager ) );
+        }
+    }
+
+    <T> void invokeUnbindMethod( DependencyManager<S, T> dependencyManager, RefPair<S, T> oldRefPair, int trackingCount )
+    {
+        for ( ComponentContextImpl<S> cc : getComponentContexts() )
+        {
+            dependencyManager.invokeUnbindMethod( cc, oldRefPair, trackingCount, cc.getEdgeInfo( dependencyManager ) );
+        }
+    }
+
+    protected MethodResult invokeModifiedMethod()
+    {
+        ModifiedMethod modifiedMethod = getComponentMethods().getModifiedMethod();
+        MethodResult result = MethodResult.VOID;
+        for ( ComponentContextImpl<S> componentContext : getComponentContexts() )
+        {
+            S instance = componentContext.getImplementationObject(true);
+            result = modifiedMethod.invoke( instance,
+                    new ActivatorParameter( componentContext, -1 ), MethodResult.VOID, this );
+
+        }
+        return result;
+    }
+    
+    @Override
+    boolean hasInstance()
+    {
+        return !serviceContexts.isEmpty();
+    }
+
+    //---------- Component interface
+
+    public ComponentInstance getComponentInstance()
+    {
+        // TODO: should return the component instance corresponding to the
+        // bundle owning ScrService
+        return super.getComponentInstance();
+    }
+
+}