Fix sonar warnings in blueprint bundle
[controller.git] / opendaylight / blueprint / src / main / java / org / opendaylight / controller / blueprint / ext / AbstractDependentComponentFactoryMetadata.java
index bdcc1ee86d261d6c05e9c4c2cc60f0875988ea68..81b374d9fa43420af3a4f2fa670e702d0280d314 100644 (file)
@@ -13,30 +13,41 @@ import java.util.Collections;
 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;
 import org.apache.aries.blueprint.ext.DependentComponentFactoryMetadata;
 import org.apache.aries.blueprint.services.ExtendedBlueprintContainer;
+import org.opendaylight.controller.blueprint.BlueprintContainerRestartService;
+import org.osgi.framework.ServiceReference;
 import org.osgi.service.blueprint.container.ComponentDefinitionException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
+ * Abstract base class for a DependentComponentFactoryMetadata implementation.
+ *
  * @author Thomas Pantelis
  */
 abstract class AbstractDependentComponentFactoryMetadata implements DependentComponentFactoryMetadata {
-    private final Logger log = LoggerFactory.getLogger(getClass());
+    final Logger log = LoggerFactory.getLogger(getClass());
     private final String id;
     private final AtomicBoolean started = new AtomicBoolean();
     private final AtomicBoolean satisfied = new AtomicBoolean();
+    private final AtomicBoolean restarting = new AtomicBoolean();
+    @GuardedBy("serviceRecipes")
     private final List<StaticServiceReferenceRecipe> serviceRecipes = new ArrayList<>();
     private volatile ExtendedBlueprintContainer container;
     private volatile SatisfactionCallback satisfactionCallback;
     private volatile String failureMessage;
-    private volatile String dependendencyDesc;
+    private volatile Throwable failureCause;
+    private volatile String dependencyDesc;
+    @GuardedBy("serviceRecipes")
+    private boolean stoppedServiceRecipes;
 
-    protected AbstractDependentComponentFactoryMetadata(String id) {
+    protected AbstractDependentComponentFactoryMetadata(final String id) {
         this.id = Preconditions.checkNotNull(id);
     }
 
@@ -57,7 +68,7 @@ abstract class AbstractDependentComponentFactoryMetadata implements DependentCom
 
     @Override
     public String getDependencyDescriptor() {
-        return dependendencyDesc;
+        return dependencyDesc;
     }
 
     @Override
@@ -65,14 +76,17 @@ abstract class AbstractDependentComponentFactoryMetadata implements DependentCom
         return satisfied.get();
     }
 
-    protected abstract void startTracking();
+    protected void setFailureMessage(final String failureMessage) {
+        setFailure(failureMessage, null);
+    }
 
-    protected void setFailureMessage(String failureMessage) {
+    protected void setFailure(final String failureMessage, final Throwable failureCause) {
         this.failureMessage = failureMessage;
+        this.failureCause = failureCause;
     }
 
-    protected void setDependendencyDesc(String dependendencyDesc) {
-        this.dependendencyDesc = dependendencyDesc;
+    protected void setDependencyDesc(final String dependencyDesc) {
+        this.dependencyDesc = dependencyDesc;
     }
 
     protected final ExtendedBlueprintContainer container() {
@@ -80,34 +94,46 @@ abstract class AbstractDependentComponentFactoryMetadata implements DependentCom
     }
 
     protected void setSatisfied() {
-        satisfied.set(true);
-        satisfactionCallback.notifyChanged();
+        if (satisfied.compareAndSet(false, true)) {
+            satisfactionCallback.notifyChanged();
+        }
     }
 
-    protected void retrieveService(String name, Class<?> interfaceClass, Consumer<Object> onServiceRetrieved) {
-        StaticServiceReferenceRecipe recipe = new StaticServiceReferenceRecipe(getId() + "-" + name,
-                container, interfaceClass.getName());
-        setDependendencyDesc(recipe.getOsgiFilter());
-        serviceRecipes.add(recipe);
+    protected void retrieveService(final String name, final Class<?> interfaceClass,
+            final Consumer<Object> onServiceRetrieved) {
+        retrieveService(name, interfaceClass.getName(), onServiceRetrieved);
+    }
 
-        recipe.startTracking(onServiceRetrieved);
+    protected void retrieveService(final String name, final String interfaceName,
+            final Consumer<Object> onServiceRetrieved) {
+        synchronized (serviceRecipes) {
+            if (stoppedServiceRecipes) {
+                return;
+            }
+
+            StaticServiceReferenceRecipe recipe = new StaticServiceReferenceRecipe(getId() + "-" + name,
+                    container, interfaceName);
+            setDependencyDesc(recipe.getOsgiFilter());
+            serviceRecipes.add(recipe);
+
+            recipe.startTracking(onServiceRetrieved);
+        }
     }
 
     protected final String logName() {
-        return (container != null ? container.getBundleContext().getBundle().getSymbolicName() : "") +
-                " (" + id + ")";
+        return (container != null ? container.getBundleContext().getBundle().getSymbolicName() : "") + " (" + id + ")";
     }
 
     @Override
-    public void init(ExtendedBlueprintContainer container) {
-        this.container = container;
+    public void init(final ExtendedBlueprintContainer newContainer) {
+        this.container = newContainer;
 
         log.debug("{}: In init", logName());
     }
 
     protected void onCreate() throws ComponentDefinitionException {
-        if(failureMessage != null) {
-            throw new ComponentDefinitionException(failureMessage);
+        if (failureMessage != null) {
+            throw new ComponentDefinitionException(failureMessage, failureCause);
         }
 
         // The following code is a bit odd so requires some explanation. A little background... If a bean
@@ -137,7 +163,7 @@ abstract class AbstractDependentComponentFactoryMetadata implements DependentCom
         executionContext.removePartialObject(id);
 
         Recipe myRecipe = executionContext.getRecipe(id);
-        if(myRecipe instanceof AbstractRecipe) {
+        if (myRecipe instanceof AbstractRecipe) {
             log.debug("{}: setPrototype to false", logName());
             ((AbstractRecipe)myRecipe).setPrototype(false);
         } else {
@@ -145,15 +171,17 @@ abstract class AbstractDependentComponentFactoryMetadata implements DependentCom
         }
     }
 
+    protected abstract void startTracking();
+
     @Override
-    public final void startTracking(final SatisfactionCallback satisfactionCallback) {
-        if(!started.compareAndSet(false, true)) {
+    public final void startTracking(final SatisfactionCallback newSatisfactionCallback) {
+        if (!started.compareAndSet(false, true)) {
             return;
         }
 
         log.debug("{}: In startTracking", logName());
 
-        this.satisfactionCallback = satisfactionCallback;
+        this.satisfactionCallback = newSatisfactionCallback;
 
         startTracking();
     }
@@ -166,17 +194,57 @@ abstract class AbstractDependentComponentFactoryMetadata implements DependentCom
     }
 
     @Override
-    public void destroy(Object instance) {
+    public void destroy(final Object instance) {
         log.debug("{}: In destroy", logName());
 
         stopServiceRecipes();
     }
 
     private void stopServiceRecipes() {
-        for(StaticServiceReferenceRecipe recipe: serviceRecipes) {
-            recipe.stop();
+        synchronized (serviceRecipes) {
+            stoppedServiceRecipes = true;
+            for (StaticServiceReferenceRecipe recipe: serviceRecipes) {
+                recipe.stop();
+            }
+
+            serviceRecipes.clear();
+        }
+    }
+
+    protected void restartContainer() {
+        if (restarting.compareAndSet(false, true)) {
+            BlueprintContainerRestartService restartService = getOSGiService(BlueprintContainerRestartService.class);
+            if (restartService != null) {
+                log.debug("{}: Restarting container", logName());
+                restartService.restartContainerAndDependents(container().getBundleContext().getBundle());
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Nullable
+    protected <T> T getOSGiService(final Class<T> serviceInterface) {
+        try {
+            ServiceReference<T> serviceReference =
+                    container().getBundleContext().getServiceReference(serviceInterface);
+            if (serviceReference == null) {
+                log.warn("{}: {} reference not found", logName(), serviceInterface.getSimpleName());
+                return null;
+            }
+
+            T service = (T)container().getService(serviceReference);
+            if (service == null) {
+                // This could happen on shutdown if the service was already unregistered so we log as debug.
+                log.debug("{}: {} was not found", logName(), serviceInterface.getSimpleName());
+            }
+
+            return service;
+        } catch (final IllegalStateException e) {
+            // This is thrown if the BundleContext is no longer valid which is possible on shutdown so we
+            // log as debug.
+            log.debug("{}: Error obtaining {}", logName(), serviceInterface.getSimpleName(), e);
         }
 
-        serviceRecipes.clear();
+        return null;
     }
 }