*/
package org.opendaylight.controller.blueprint;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
-import javax.annotation.Nullable;
import org.apache.aries.blueprint.NamespaceHandler;
import org.apache.aries.blueprint.services.BlueprintExtenderService;
import org.apache.aries.quiesce.participant.QuiesceParticipant;
import org.apache.aries.util.AriesFrameworkUtil;
+import org.eclipse.jdt.annotation.Nullable;
+import org.gaul.modernizer_maven_annotations.SuppressModernizer;
import org.opendaylight.controller.blueprint.ext.OpendaylightNamespaceHandler;
-import org.opendaylight.controller.config.api.ConfigSystemService;
+import org.opendaylight.yangtools.util.xml.UntrustedXML;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.SynchronousBundleListener;
import org.osgi.service.blueprint.container.BlueprintContainer;
-import org.osgi.service.blueprint.container.EventConstants;
-import org.osgi.service.event.Event;
-import org.osgi.service.event.EventHandler;
+import org.osgi.service.blueprint.container.BlueprintEvent;
+import org.osgi.service.blueprint.container.BlueprintListener;
import org.osgi.util.tracker.BundleTracker;
import org.osgi.util.tracker.BundleTrackerCustomizer;
import org.osgi.util.tracker.ServiceTracker;
*
* @author Thomas Pantelis
*/
-public class BlueprintBundleTracker implements BundleActivator, BundleTrackerCustomizer<Bundle>, EventHandler,
+public class BlueprintBundleTracker implements BundleActivator, BundleTrackerCustomizer<Bundle>, BlueprintListener,
SynchronousBundleListener {
private static final Logger LOG = LoggerFactory.getLogger(BlueprintBundleTracker.class);
- private static final String BLUEPRINT_FILE_PATH = "org/opendaylight/blueprint/";
+ private static final String ODL_CUSTOM_BLUEPRINT_FILE_PATH = "org/opendaylight/blueprint/";
+ private static final String STANDARD_BLUEPRINT_FILE_PATH = "OSGI-INF/blueprint/";
private static final String BLUEPRINT_FLE_PATTERN = "*.xml";
private static final long SYSTEM_BUNDLE_ID = 0;
public void start(final BundleContext context) {
LOG.info("Starting {}", getClass().getSimpleName());
+ // CONTROLLER-1867: force UntrustedXML initialization, so that it uses our TCCL to initialize
+ UntrustedXML.newDocumentBuilder();
+
restartService = new BlueprintContainerRestartServiceImpl();
bundleContext = context;
bundleTracker = new BundleTracker<>(context, Bundle.ACTIVE, this);
- blueprintExtenderServiceTracker = new ServiceTracker<>(context, BlueprintExtenderService.class.getName(),
+ blueprintExtenderServiceTracker = new ServiceTracker<>(context, BlueprintExtenderService.class,
new ServiceTrackerCustomizer<BlueprintExtenderService, BlueprintExtenderService>() {
@Override
public BlueprintExtenderService addingService(
});
blueprintExtenderServiceTracker.open();
- quiesceParticipantTracker = new ServiceTracker<>(context, QuiesceParticipant.class.getName(),
+ quiesceParticipantTracker = new ServiceTracker<>(context, QuiesceParticipant.class,
new ServiceTrackerCustomizer<QuiesceParticipant, QuiesceParticipant>() {
@Override
public QuiesceParticipant addingService(
quiesceParticipantTracker.open();
}
+ @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
+ justification = "https://github.com/spotbugs/spotbugs/issues/811")
private QuiesceParticipant onQuiesceParticipantAdded(final ServiceReference<QuiesceParticipant> reference) {
quiesceParticipant = reference.getBundle().getBundleContext().getService(reference);
return quiesceParticipant;
}
+ @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
+ justification = "https://github.com/spotbugs/spotbugs/issues/811")
private BlueprintExtenderService onBlueprintExtenderServiceAdded(
final ServiceReference<BlueprintExtenderService> reference) {
blueprintExtenderService = reference.getBundle().getBundleContext().getService(reference);
restartService.setBlueprintExtenderService(blueprintExtenderService);
- blueprintContainerRestartReg = bundleContext.registerService(
- BlueprintContainerRestartService.class.getName(), restartService, new Hashtable<>());
+ blueprintContainerRestartReg = bundleContext.registerService(BlueprintContainerRestartService.class,
+ restartService, null);
return blueprintExtenderService;
}
private void registerNamespaceHandler(final BundleContext context) {
- Dictionary<String, Object> props = new Hashtable<>();
+ Dictionary<String, Object> props = emptyDict();
props.put("osgi.service.blueprint.namespace", OpendaylightNamespaceHandler.NAMESPACE_1_0_0);
- namespaceReg = context.registerService(NamespaceHandler.class.getName(),
- new OpendaylightNamespaceHandler(), props);
+ namespaceReg = context.registerService(NamespaceHandler.class, new OpendaylightNamespaceHandler(), props);
}
private void registerBlueprintEventHandler(final BundleContext context) {
- Dictionary<String, Object> props = new Hashtable<>();
- props.put(org.osgi.service.event.EventConstants.EVENT_TOPIC,
- new String[]{EventConstants.TOPIC_CREATED, EventConstants.TOPIC_FAILURE});
- eventHandlerReg = context.registerService(EventHandler.class.getName(), this, props);
+ eventHandlerReg = context.registerService(BlueprintListener.class, this, null);
+ }
+
+ @SuppressModernizer
+ private static Dictionary<String, Object> emptyDict() {
+ return new Hashtable<>();
}
/**
}
if (bundle.getState() == Bundle.ACTIVE) {
- List<Object> paths = findBlueprintPaths(bundle);
+ List<Object> paths = findBlueprintPaths(bundle, ODL_CUSTOM_BLUEPRINT_FILE_PATH);
if (!paths.isEmpty()) {
LOG.info("Creating blueprint container for bundle {} with paths {}", bundle, paths);
}
/**
- * Implemented from EventHandler to listen for blueprint events.
+ * Implemented from BlueprintListener to listen for blueprint events.
*
* @param event the event to handle
*/
@Override
- public void handleEvent(final Event event) {
- if (EventConstants.TOPIC_CREATED.equals(event.getTopic())) {
- LOG.info("Blueprint container for bundle {} was successfully created",
- event.getProperty(EventConstants.BUNDLE));
+ public void blueprintEvent(final BlueprintEvent event) {
+ if (event.getType() == BlueprintEvent.CREATED) {
+ LOG.info("Blueprint container for bundle {} was successfully created", event.getBundle());
return;
}
// is indicated via a non-null DEPENDENCIES property containing the missing dependencies. The
// default timeout is 5 min and ideally we would set this to infinite but the timeout can only
// be set at the bundle level in the manifest - there's no way to set it globally.
- if (EventConstants.TOPIC_FAILURE.equals(event.getTopic())
- && event.getProperty(EventConstants.DEPENDENCIES) != null) {
- Bundle bundle = (Bundle) event.getProperty(EventConstants.BUNDLE);
+ if (event.getType() == BlueprintEvent.FAILURE && event.getDependencies() != null) {
+ Bundle bundle = event.getBundle();
List<Object> paths = findBlueprintPaths(bundle);
if (!paths.isEmpty()) {
LOG.warn("Blueprint container for bundle {} timed out waiting for dependencies - restarting it",
- event.getProperty(EventConstants.BUNDLE));
+ bundle);
restartService.restartContainer(bundle, paths);
}
}
}
- @SuppressWarnings({ "rawtypes", "unchecked" })
static List<Object> findBlueprintPaths(final Bundle bundle) {
- Enumeration<?> rntries = bundle.findEntries(BLUEPRINT_FILE_PATH, BLUEPRINT_FLE_PATTERN, false);
+ List<Object> paths = findBlueprintPaths(bundle, STANDARD_BLUEPRINT_FILE_PATH);
+ return !paths.isEmpty() ? paths : findBlueprintPaths(bundle, ODL_CUSTOM_BLUEPRINT_FILE_PATH);
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ private static List<Object> findBlueprintPaths(final Bundle bundle, final String path) {
+ Enumeration<?> rntries = bundle.findEntries(path, BLUEPRINT_FLE_PATTERN, false);
if (rntries == null) {
return Collections.emptyList();
} else {
restartService.close();
- // Close all CSS modules first.
- ConfigSystemService configSystem = getOSGiService(ConfigSystemService.class);
- if (configSystem != null) {
- configSystem.closeAllConfigModules();
- }
-
LOG.info("Shutting down all blueprint containers...");
Collection<Bundle> containerBundles = new HashSet<>(Arrays.asList(bundleContext.getBundles()));
}
if (!bundlesToDestroy.isEmpty()) {
- Collections.sort(bundlesToDestroy, (b1, b2) -> (int) (b2.getLastModified() - b1.getLastModified()));
+ bundlesToDestroy.sort((b1, b2) -> (int) (b2.getLastModified() - b1.getLastModified()));
LOG.debug("Selected bundles {} for destroy (no services in use)", bundlesToDestroy);
} else {
return bundlesToDestroy;
}
- @Nullable
- private Bundle findBundleWithHighestUsedServiceId(final Collection<Bundle> containerBundles) {
+ private @Nullable Bundle findBundleWithHighestUsedServiceId(final Collection<Bundle> containerBundles) {
ServiceReference<?> highestServiceRef = null;
for (Bundle bundle : containerBundles) {
ServiceReference<?>[] references = bundle.getRegisteredServices();
Bundle[] usingBundles = ref.getUsingBundles();
return usingBundles != null ? usingBundles.length : 0;
}
-
- private <T> T getOSGiService(final Class<T> serviceInterface) {
- try {
- ServiceReference<T> serviceReference = bundleContext.getServiceReference(serviceInterface);
- if (serviceReference == null) {
- LOG.warn("{} service reference not found", serviceInterface.getSimpleName());
- return null;
- }
-
- T service = bundleContext.getService(serviceReference);
- if (service == null) {
- // This could happen on shutdown if the service was already unregistered so we log as debug.
- LOG.debug("{} service instance was not found", 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 OSGi service {}", serviceInterface.getSimpleName(), e);
- }
-
- return null;
- }
}