From 2875772469b2f8ed80f2dd6b539a8482d1f2e0b0 Mon Sep 17 00:00:00 2001 From: Tom Pantelis Date: Fri, 9 Dec 2016 10:35:51 -0500 Subject: [PATCH] Bug 7326: Fix ConcurrentModificationException in Blueprint in AbstractDependentComponentFactoryMetadata.stopServiceRecipes() tpantelis: "This is an edge case where the container is destroyed immediately after and while it's starting up. This isn't likely to happen in production but can happen during feature tests. I had assumed the container would provide the protection but apparently it doesn't." Change-Id: Id7532d30cb0a5f67fd907cb15372069d8769b247 Signed-off-by: Michael Vorburger Signed-off-by: Tom Pantelis --- ...ractDependentComponentFactoryMetadata.java | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/opendaylight/blueprint/src/main/java/org/opendaylight/controller/blueprint/ext/AbstractDependentComponentFactoryMetadata.java b/opendaylight/blueprint/src/main/java/org/opendaylight/controller/blueprint/ext/AbstractDependentComponentFactoryMetadata.java index c55fa0ce91..c15a7037e7 100644 --- a/opendaylight/blueprint/src/main/java/org/opendaylight/controller/blueprint/ext/AbstractDependentComponentFactoryMetadata.java +++ b/opendaylight/blueprint/src/main/java/org/opendaylight/controller/blueprint/ext/AbstractDependentComponentFactoryMetadata.java @@ -14,6 +14,7 @@ import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; import javax.annotation.Nullable; +import javax.annotation.concurrent.GuardedBy; import org.apache.aries.blueprint.di.AbstractRecipe; import org.apache.aries.blueprint.di.ExecutionContext; import org.apache.aries.blueprint.di.Recipe; @@ -36,12 +37,15 @@ abstract class AbstractDependentComponentFactoryMetadata implements DependentCom private final AtomicBoolean started = new AtomicBoolean(); private final AtomicBoolean satisfied = new AtomicBoolean(); private final AtomicBoolean restarting = new AtomicBoolean(); + @GuardedBy("serviceRecipes") private final List serviceRecipes = new ArrayList<>(); private volatile ExtendedBlueprintContainer container; private volatile SatisfactionCallback satisfactionCallback; private volatile String failureMessage; private volatile Throwable failureCause; private volatile String dependendencyDesc; + @GuardedBy("serviceRecipes") + private boolean stoppedServiceRecipes; protected AbstractDependentComponentFactoryMetadata(String id) { this.id = Preconditions.checkNotNull(id); @@ -100,12 +104,18 @@ abstract class AbstractDependentComponentFactoryMetadata implements DependentCom } protected void retrieveService(String name, String interfaceName, Consumer onServiceRetrieved) { - StaticServiceReferenceRecipe recipe = new StaticServiceReferenceRecipe(getId() + "-" + name, - container, interfaceName); - setDependendencyDesc(recipe.getOsgiFilter()); - serviceRecipes.add(recipe); + synchronized (serviceRecipes) { + if (stoppedServiceRecipes) { + return; + } + + StaticServiceReferenceRecipe recipe = new StaticServiceReferenceRecipe(getId() + "-" + name, + container, interfaceName); + setDependendencyDesc(recipe.getOsgiFilter()); + serviceRecipes.add(recipe); - recipe.startTracking(onServiceRetrieved); + recipe.startTracking(onServiceRetrieved); + } } protected final String logName() { @@ -189,11 +199,14 @@ abstract class AbstractDependentComponentFactoryMetadata implements DependentCom } private void stopServiceRecipes() { - for (StaticServiceReferenceRecipe recipe: serviceRecipes) { - recipe.stop(); - } + synchronized (serviceRecipes) { + stoppedServiceRecipes = true; + for (StaticServiceReferenceRecipe recipe: serviceRecipes) { + recipe.stop(); + } - serviceRecipes.clear(); + serviceRecipes.clear(); + } } protected void restartContainer() { -- 2.36.6