FELIX-836 Some fixes in asynchronicity of deactivation:
- deactivate() is always asynchronous
- reactivation() is always asynchronous
- add a helper class supporting better loging of asynchronouse tasks
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@741567 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/AbstractComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/AbstractComponentManager.java
index 214f474..6ae1073 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/AbstractComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/AbstractComponentManager.java
@@ -92,7 +92,7 @@
*/
public final void enable()
{
- getActivator().schedule( new Runnable()
+ getActivator().schedule( new ComponentActivatorTask("Enable", this)
{
public void run()
{
@@ -135,7 +135,7 @@
*/
public final void activate()
{
- getActivator().schedule( new Runnable()
+ getActivator().schedule( new ComponentActivatorTask("Activate", this)
{
public void run()
{
@@ -153,43 +153,20 @@
public final void reconfigure()
{
log( LogService.LOG_DEBUG, "Deactivating and Activating to reconfigure", m_componentMetadata, null );
- reactivateAsynchronous();
+ reactivate();
}
/**
* Cycles this component by deactivating it and - if still satisfied -
- * activating it again.
- * <p>
- * This method immediately deactivates the component to prevent action
- * with old configuration/references and schedules the reactivation for
- * asynchronous execution.
- */
- public final void reactivate()
- {
- // synchronously deactivate and schedule activation asynchronously
- deactivate();
-
- getActivator().schedule( new Runnable()
- {
- public void run()
- {
- activateInternal();
- }
- } );
- }
-
-
- /**
- * Cycles this component by deactivating it and - if still satisfied -
* activating it again asynchronously.
* <p>
* This method schedules the deactivation and reactivation for asynchronous
* execution.
*/
- public final void reactivateAsynchronous()
+ public final void reactivate()
{
- getActivator().schedule( new Runnable()
+ getActivator().schedule( new ComponentActivatorTask( "Reactivate", this )
{
public void run()
{
@@ -203,40 +180,30 @@
/**
* Deactivates the component.
* <p>
- * This method unlike other state change methods immediately takes
- * action and deactivates the component. The reason for this is, that this
- * method is called when a required service is not available any more and
- * hence the component cannot work. The exception to this is, that the
- * deactivation is scheduled for asynchronous execution if the component
- * is currently activating.
+ * Deactivation of the component happens when a service is unregistered
+ * (or modified). Since such a service change may take place while a bundle
+ * is being stopped and the bundle lock is held, we have to be careful and
+ * schedule the deactivation for asynchronous execution.
* <p>
- * We must not immediately deactivate while the component is activating
- * because we might create a deadlock: If this method is called from the
- * framework service event thread some locks may be held. If at the same
- * time the activation tries to access referenced services the framework
- * lock will be tried to be obtained. On the other hand the activation
- * holds a lock on this instance and the deactivation tries to get that
- * lock.
+ * The drawback is, that the user of the removed (or modified) service is
+ * still bound to the old service for a small amount of time and thus may
+ * run into issues. But weighing this against the deadlock possibility, it
+ * is more important to be deadlock save.
+ * <p>
+ * If services have a problem with this delayed deactivation, they should
+ * consider marking the reference as optional and dynamic and be prepared
+ * to the service not being present, since service bind and unbind will
+ * always be synchronous.
*/
public final void deactivate()
{
- if ( getState() == STATE_ACTIVATING )
+ getActivator().schedule( new ComponentActivatorTask( "Deactivate", this )
{
- log( LogService.LOG_INFO,
- "Asynchronously deactivating the component to prevent a deadlock while it is being activated",
- m_componentMetadata, null );
- getActivator().schedule( new Runnable()
+ public void run()
{
- public void run()
- {
- deactivateInternal();
- }
- } );
- }
- else
- {
- deactivateInternal();
- }
+ deactivateInternal();
+ }
+ } );
}
@@ -248,7 +215,7 @@
*/
public final void disable()
{
- getActivator().schedule( new Runnable()
+ getActivator().schedule( new ComponentActivatorTask("Disable", this)
{
public void run()
{
@@ -831,6 +798,12 @@
}
+ public String toString()
+ {
+ return "Component: " + getName() + " (" + getId() + ")";
+ }
+
+
/**
* Returns <code>true</code> if this instance has not been disposed off
* yet and the BundleComponentActivator is still active. If the Bundle
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 e5612a9..0a95731 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
@@ -447,7 +447,7 @@
*
* @param task The component task to execute
*/
- void schedule( Runnable task )
+ void schedule( ComponentActivatorTask task )
{
if ( isActive() )
{
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/ComponentActivatorTask.java b/scr/src/main/java/org/apache/felix/scr/impl/ComponentActivatorTask.java
new file mode 100644
index 0000000..f501a6a
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/impl/ComponentActivatorTask.java
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+
+/**
+ * The <code>ComponentActivatorTask</code> extends the <code>Runnable</code>
+ * interface with the functionality to have a meaningful {@link #toString()}
+ * implementation. This is mainly used when logging something around the task
+ * being run or scheduled.
+ */
+abstract class ComponentActivatorTask implements Runnable
+{
+
+ private final String taskName;
+ private final ComponentManager component;
+
+
+ protected ComponentActivatorTask( String taskName, ComponentManager component )
+ {
+ this.taskName = taskName;
+ this.component = component;
+ }
+
+
+ public String toString()
+ {
+ return taskName + " " + component;
+ }
+}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/ImmediateComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/ImmediateComponentManager.java
index 87583f4..649f8c9 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/ImmediateComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/ImmediateComponentManager.java
@@ -389,7 +389,7 @@
{
log( LogService.LOG_DEBUG, "Deactivating and Activating to reconfigure from configuration",
getComponentMetadata(), null );
- reactivateAsynchronous();
+ reactivate();
}
}
}