import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
+import javax.annotation.Nullable;
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 String id;
private final AtomicBoolean started = new AtomicBoolean();
private final AtomicBoolean satisfied = new AtomicBoolean();
+ private final AtomicBoolean restarting = new AtomicBoolean();
private final List<StaticServiceReferenceRecipe> serviceRecipes = new ArrayList<>();
private volatile ExtendedBlueprintContainer container;
private volatile SatisfactionCallback satisfactionCallback;
private volatile String failureMessage;
+ private volatile Throwable failureCause;
private volatile String dependendencyDesc;
protected AbstractDependentComponentFactoryMetadata(String id) {
return satisfied.get();
}
- protected abstract void startTracking();
-
protected void setFailureMessage(String failureMessage) {
+ setFailure(failureMessage, null);
+ }
+
+ protected void setFailure(String failureMessage, Throwable failureCause) {
this.failureMessage = failureMessage;
+ this.failureCause = failureCause;
}
protected void setDependendencyDesc(String dependendencyDesc) {
}
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) {
+ retrieveService(name, interfaceClass.getName(), onServiceRetrieved);
+ }
+
+ protected void retrieveService(String name, String interfaceName, Consumer<Object> onServiceRetrieved) {
StaticServiceReferenceRecipe recipe = new StaticServiceReferenceRecipe(getId() + "-" + name,
- container, interfaceClass.getName());
+ container, interfaceName);
setDependendencyDesc(recipe.getOsgiFilter());
serviceRecipes.add(recipe);
}
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(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
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 {
}
}
+ 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();
}
}
private void stopServiceRecipes() {
- for(StaticServiceReferenceRecipe recipe: serviceRecipes) {
+ 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(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 (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);
+ }
+
+ return null;
+ }
}