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 2014/07/02 14:21:54 UTC
svn commit: r1607341 -
/felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ComponentImpl.java
Author: pderop
Date: Wed Jul 2 12:21:53 2014
New Revision: 1607341
URL: http://svn.apache.org/r1607341
Log:
FELIX-4002: Using the reentrant serial executor in order to fix the FELIX-4002 issue.
Modified:
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ComponentImpl.java
Modified: felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ComponentImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ComponentImpl.java?rev=1607341&r1=1607340&r2=1607341&view=diff
==============================================================================
--- felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ComponentImpl.java (original)
+++ felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ComponentImpl.java Wed Jul 2 12:21:53 2014
@@ -90,7 +90,7 @@ public class ComponentImpl implements Co
private final List m_stateListeners = new ArrayList();
// work queue
- private final SerialExecutor m_executor = new SerialExecutor();
+ private final SerialExecutor m_executor;
// instance factory
private volatile Object m_instanceFactory;
@@ -108,8 +108,27 @@ public class ComponentImpl implements Co
private final Map m_autoConfigInstance = new HashMap();
private boolean m_isStarted = false;
+
+ // Used to track what state listener callback we have already called
+ private int m_stateListener = LISTENER_IDLE;
+
+ // We have not yet called any state listener callbacks
+ private final static int LISTENER_IDLE = 0;
+
+ // We have already called the "starting" state listener callback.
+ private final static int LISTENER_STARTING = 1;
+
+ // We have already called the "started" state listener callback.
+ private final static int LISTENER_STARTED = 2;
+
+ // We have already called the "stopping" state listener callback.
+ private final static int LISTENER_STOPPING = 3;
+
+ // We have already called the "stopped" state listener callback.
+ private final static int LISTENER_STOPPED = 4;
public ComponentImpl(BundleContext context, DependencyManager manager, Logger logger) {
+ m_executor = new SerialExecutor(logger);
synchronized (VOID) {
m_id = HIGHEST_ID++;
}
@@ -530,27 +549,63 @@ public class ComponentImpl implements Co
}
// service state listener methods
- public void addStateListener(ComponentStateListener listener) {
- synchronized (m_stateListeners) {
- m_stateListeners.add(listener);
- }
- // when we register as a listener and the service is already started
- // make sure we invoke the right callbacks so the listener knows
- State state;
- synchronized (m_dependencies) {
- state = m_state;
- }
- if (state.isBound()) {
- listener.starting(this);
- listener.started(this);
- }
+ public void addStateListener(final ComponentStateListener listener) {
+ m_executor.execute(new Runnable() {
+ public void run() { // executed immediately if we are already being executed from the executor
+ synchronized (m_stateListeners) {
+ m_stateListeners.add(listener);
+ }
+ switch (m_stateListener) {
+ case LISTENER_STARTING:
+ // this new listener missed the starting cb
+ listener.starting(ComponentImpl.this);
+ break;
+ case LISTENER_STARTED:
+ // this new listener missed the starting/started cb
+ listener.starting(ComponentImpl.this);
+ listener.started(ComponentImpl.this);
+ break;
+ case LISTENER_STOPPING:
+ // this new listener missed the starting/started/stopping cb
+ listener.starting(ComponentImpl.this);
+ listener.started(ComponentImpl.this);
+ listener.stopping(ComponentImpl.this);
+ break;
+ case LISTENER_STOPPED:
+ // this new listener missed the starting/started/stopping/stopped cb
+ listener.starting(ComponentImpl.this);
+ listener.started(ComponentImpl.this);
+ listener.stopping(ComponentImpl.this);
+ listener.stopped(ComponentImpl.this);
+ break;
+ }
+ }
+ });
}
- public void removeStateListener(ComponentStateListener listener) {
- synchronized (m_stateListeners) {
- m_stateListeners.remove(listener);
- }
- }
+ public void removeStateListener(final ComponentStateListener listener) {
+ m_executor.execute(new Runnable() {
+ public void run() { // executed immediately if we are already being executed from the executor
+ switch (m_stateListener) {
+ case LISTENER_STARTING:
+ // The listener has been previously called in starting cb;
+ // so we should call the listener started cb, before unregistering it.
+ listener.started(ComponentImpl.this);
+ break;
+
+ case LISTENER_STOPPING:
+ // The listener has been previously called in stopping cb;
+ // so we should call the listener stopped cb, before unregistering it.
+ listener.stopped(ComponentImpl.this);
+ break;
+ }
+ synchronized (m_stateListeners) {
+ m_stateListeners.remove(listener);
+ }
+ }
+ });
+ m_executor.execute();
+ }
public void removeStateListeners() {
synchronized (m_stateListeners) {
@@ -558,7 +613,9 @@ public class ComponentImpl implements Co
}
}
- private void stateListenersStarting() {
+ private void stateListenersStarting() {
+ // called from our serial executor
+ m_stateListener = LISTENER_STARTING;
ComponentStateListener[] list = getListeners();
for (int i = 0; i < list.length; i++) {
try {
@@ -571,7 +628,9 @@ public class ComponentImpl implements Co
}
private void stateListenersStarted() {
- ComponentStateListener[] list = getListeners();
+ // called from our serial executor
+ m_stateListener = LISTENER_STARTED;
+ ComponentStateListener[] list = getListeners();
for (int i = 0; i < list.length; i++) {
try {
list[i].started(this);
@@ -583,6 +642,8 @@ public class ComponentImpl implements Co
}
private void stateListenersStopping() {
+ // called from our serial executor
+ m_stateListener = LISTENER_STOPPING;
ComponentStateListener[] list = getListeners();
for (int i = 0; i < list.length; i++) {
try {
@@ -595,6 +656,8 @@ public class ComponentImpl implements Co
}
private void stateListenersStopped() {
+ // called from our serial executor
+ m_stateListener = LISTENER_STOPPED;
ComponentStateListener[] list = getListeners();
for (int i = 0; i < list.length; i++) {
try {