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 <service serviceFactory='true'/>
+ * 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();
+ }
+
+}