2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.config.manager.impl.osgi;
10 import com.google.common.util.concurrent.ThreadFactoryBuilder;
11 import java.util.concurrent.ExecutorService;
12 import java.util.concurrent.Executors;
13 import java.util.concurrent.Future;
14 import java.util.concurrent.ThreadFactory;
15 import org.osgi.framework.Bundle;
16 import org.osgi.framework.BundleContext;
17 import org.osgi.framework.BundleEvent;
18 import org.osgi.util.tracker.BundleTracker;
19 import org.osgi.util.tracker.BundleTrackerCustomizer;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
26 * Extensible bundle tracker. Takes several BundleTrackerCustomizers and
27 * propagates bundle events to all of them.
29 * Primary customizer may return tracking object,
30 * which will be passed to it during invocation of
31 * {@link BundleTrackerCustomizer#removedBundle(Bundle, BundleEvent, Object)}
34 * This extender modifies behaviour to not leak platform thread
35 * in {@link BundleTrackerCustomizer#addingBundle(Bundle, BundleEvent)}
36 * but deliver this event from its own single threaded executor.
38 * If bundle is removed before event for adding bundle was executed,
39 * that event is cancelled. If addingBundle event is currently in progress
40 * or was already executed, platform thread is block untill addingBundle
41 * finishes so bundle could be removed correctly in platform thread.
44 * Method {@link BundleTrackerCustomizer#removedBundle(Bundle, BundleEvent, Object)}
45 * is never invoked on registered trackers.
49 public final class ExtensibleBundleTracker<T> extends BundleTracker<Future<T>> {
50 private static final ThreadFactory THREAD_FACTORY = new ThreadFactoryBuilder()
51 .setNameFormat("config-bundle-tracker-%d").build();
52 private final ExecutorService eventExecutor;
53 private final BundleTrackerCustomizer<T> primaryTracker;
54 private final BundleTrackerCustomizer<?>[] additionalTrackers;
56 private static final Logger LOG = LoggerFactory.getLogger(ExtensibleBundleTracker.class);
58 public ExtensibleBundleTracker(final BundleContext context, final BundleTrackerCustomizer<T> primaryBundleTrackerCustomizer,
59 final BundleTrackerCustomizer<?>... additionalBundleTrackerCustomizers) {
60 this(context, Bundle.ACTIVE, primaryBundleTrackerCustomizer, additionalBundleTrackerCustomizers);
63 public ExtensibleBundleTracker(final BundleContext context, final int bundleState,
64 final BundleTrackerCustomizer<T> primaryBundleTrackerCustomizer,
65 final BundleTrackerCustomizer<?>... additionalBundleTrackerCustomizers) {
66 super(context, bundleState, null);
67 this.primaryTracker = primaryBundleTrackerCustomizer;
68 this.additionalTrackers = additionalBundleTrackerCustomizers;
69 eventExecutor = Executors.newSingleThreadExecutor(THREAD_FACTORY);
70 LOG.trace("Registered as extender with context {} and bundle state {}", context, bundleState);
74 public Future<T> addingBundle(final Bundle bundle, final BundleEvent event) {
75 LOG.trace("Submiting AddingBundle for bundle {} and event {} to be processed asynchronously",bundle,event);
76 return eventExecutor.submit(() -> {
78 T primaryTrackerRetVal = primaryTracker.addingBundle(bundle, event);
80 forEachAdditionalBundle(tracker -> tracker.addingBundle(bundle, event));
81 LOG.trace("AddingBundle for {} and event {} finished successfully",bundle,event);
82 return primaryTrackerRetVal;
83 } catch (final Exception e) {
84 LOG.error("Failed to add bundle {}", bundle, e);
91 public void modifiedBundle(final Bundle bundle, final BundleEvent event, final Future<T> object) {
97 public void removedBundle(final Bundle bundle, final BundleEvent event, final Future<T> object) {
98 if(!object.isDone() && object.cancel(false)) {
99 // We canceled adding event before it was processed
100 // so it is safe to return
101 LOG.trace("Adding Bundle event for {} was cancelled. No additional work required.",bundle);
105 LOG.trace("Invoking removedBundle event for {}",bundle);
106 primaryTracker.removedBundle(bundle, event, object.get());
107 forEachAdditionalBundle(tracker -> tracker.removedBundle(bundle, event, null));
108 LOG.trace("Removed bundle event for {} finished successfully.",bundle);
109 } catch (final Exception e) {
110 LOG.error("Failed to remove bundle {}", bundle, e);
114 private void forEachAdditionalBundle(final BundleStrategy lambda) {
115 for (BundleTrackerCustomizer<?> trac : additionalTrackers) {
116 lambda.execute(trac);
120 private interface BundleStrategy {
121 void execute(BundleTrackerCustomizer<?> tracker);