X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fconfig%2Fconfig-manager%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fconfig%2Fmanager%2Fimpl%2Fosgi%2FExtensibleBundleTracker.java;h=61c050506e4130e0937b898ea26003e721ce40ef;hp=c1ebba78817fb36c1a34f256ee81bdcb8c86d85f;hb=493c4f70a0a315d77927e4c0d90a90acbbcb2897;hpb=c05e8241fcef668a8d2fe00776839df56187a401 diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ExtensibleBundleTracker.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ExtensibleBundleTracker.java index c1ebba7881..61c050506e 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ExtensibleBundleTracker.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ExtensibleBundleTracker.java @@ -7,6 +7,11 @@ */ package org.opendaylight.controller.config.manager.impl.osgi; +import com.google.common.util.concurrent.MoreExecutors; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; @@ -15,74 +20,111 @@ import org.osgi.util.tracker.BundleTrackerCustomizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + /** * - * Extensible bundle tracker. Takes several BundleTrackerCustomizers and propagates bundle events to all of them. - * Primary customizer + * Extensible bundle tracker. Takes several BundleTrackerCustomizers and + * propagates bundle events to all of them. + * + * Primary customizer may return tracking object, + * which will be passed to it during invocation of + * {@link BundleTrackerCustomizer#removedBundle(Bundle, BundleEvent, Future)} + * + * + * This extender modifies behaviour to not leak platform thread + * in {@link BundleTrackerCustomizer#addingBundle(Bundle, BundleEvent)} + * but deliver this event from its own single threaded executor. + * + * If bundle is removed before event for adding bundle was executed, + * that event is cancelled. If addingBundle event is currently in progress + * or was already executed, platform thread is block untill addingBundle + * finishes so bundle could be removed correctly in platform thread. + * + * + * Method {@link BundleTrackerCustomizer#removedBundle(Bundle, BundleEvent, Object)} + * is never invoked on registered trackers. * * @param */ -public final class ExtensibleBundleTracker extends BundleTracker { +public final class ExtensibleBundleTracker extends BundleTracker> { + private final ExecutorService eventExecutor; private final BundleTrackerCustomizer primaryTracker; private final BundleTrackerCustomizer[] additionalTrackers; - private static final Logger logger = LoggerFactory.getLogger(ExtensibleBundleTracker.class); + private static final Logger LOG = LoggerFactory.getLogger(ExtensibleBundleTracker.class); - public ExtensibleBundleTracker(BundleContext context, BundleTrackerCustomizer primaryBundleTrackerCustomizer, - BundleTrackerCustomizer... additionalBundleTrackerCustomizers) { + public ExtensibleBundleTracker(final BundleContext context, final BundleTrackerCustomizer primaryBundleTrackerCustomizer, + final BundleTrackerCustomizer... additionalBundleTrackerCustomizers) { this(context, Bundle.ACTIVE, primaryBundleTrackerCustomizer, additionalBundleTrackerCustomizers); } - public ExtensibleBundleTracker(BundleContext context, int bundleState, - BundleTrackerCustomizer primaryBundleTrackerCustomizer, - BundleTrackerCustomizer... additionalBundleTrackerCustomizers) { + public ExtensibleBundleTracker(final BundleContext context, final int bundleState, + final BundleTrackerCustomizer primaryBundleTrackerCustomizer, + final BundleTrackerCustomizer... additionalBundleTrackerCustomizers) { super(context, bundleState, null); this.primaryTracker = primaryBundleTrackerCustomizer; this.additionalTrackers = additionalBundleTrackerCustomizers; - logger.trace("Registered as extender with context {} and bundle state {}", context, bundleState); + eventExecutor = MoreExecutors.newDirectExecutorService(); + LOG.trace("Registered as extender with context {} and bundle state {}", context, bundleState); } @Override - public T addingBundle(final Bundle bundle, final BundleEvent event) { - T primaryTrackerRetVal = primaryTracker.addingBundle(bundle, event); - - forEachAdditionalBundle(new BundleStrategy() { + public Future addingBundle(final Bundle bundle, final BundleEvent event) { + LOG.trace("Submiting AddingBundle for bundle {} and event {} to be processed asynchronously",bundle,event); + Future future = eventExecutor.submit(new Callable() { @Override - public void execute(BundleTrackerCustomizer tracker) { - tracker.addingBundle(bundle, event); + public T call() throws Exception { + try { + T primaryTrackerRetVal = primaryTracker.addingBundle(bundle, event); + + forEachAdditionalBundle(new BundleStrategy() { + @Override + public void execute(final BundleTrackerCustomizer tracker) { + tracker.addingBundle(bundle, event); + } + }); + LOG.trace("AddingBundle for {} and event {} finished successfully",bundle,event); + return primaryTrackerRetVal; + } catch (Exception e) { + LOG.error("Failed to add bundle ",e); + throw e; + } } }); - - return primaryTrackerRetVal; + return future; } @Override - public void modifiedBundle(final Bundle bundle, final BundleEvent event, final T object) { - primaryTracker.modifiedBundle(bundle, event, object); - - forEachAdditionalBundle(new BundleStrategy() { - @Override - public void execute(BundleTrackerCustomizer tracker) { - tracker.modifiedBundle(bundle, event, null); - } - }); + public void modifiedBundle(final Bundle bundle, final BundleEvent event, final Future object) { + // Intentionally NOOP } @Override - public void removedBundle(final Bundle bundle, final BundleEvent event, final T object) { - primaryTracker.removedBundle(bundle, event, object); - - forEachAdditionalBundle(new BundleStrategy() { - @Override - public void execute(BundleTrackerCustomizer tracker) { - tracker.removedBundle(bundle, event, null); - } - }); + public void removedBundle(final Bundle bundle, final BundleEvent event, final Future object) { + if(!object.isDone() && object.cancel(false)) { + // We canceled adding event before it was processed + // so it is safe to return + LOG.trace("Adding Bundle event for {} was cancelled. No additional work required.",bundle); + return; + } + try { + LOG.trace("Invoking removedBundle event for {}",bundle); + primaryTracker.removedBundle(bundle, event, object.get()); + forEachAdditionalBundle(new BundleStrategy() { + @Override + public void execute(final BundleTrackerCustomizer tracker) { + tracker.removedBundle(bundle, event, null); + } + }); + LOG.trace("Removed bundle event for {} finished successfully.",bundle); + } catch (InterruptedException | ExecutionException e) { + LOG.error("Addition of bundle failed, ", e); + } } - private void forEachAdditionalBundle(BundleStrategy lambda) { + private void forEachAdditionalBundle(final BundleStrategy lambda) { for (BundleTrackerCustomizer trac : additionalTrackers) { lambda.execute(trac); }