X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=dom%2Fmdsal-dom-broker%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fmdsal%2Fdom%2Fbroker%2Fosgi%2FOsgiBundleScanningSchemaService.java;h=87e5c4d23e4e770fef87883f68188b1526b5df0d;hb=14f04995729708e2ac192df2bdfce6fe6a5a9aaf;hp=1ff49c0186dea19f588aae21511d9025d2a1d885;hpb=5151f7479368ed5578ae8d42fb7cf1cf3e3d21fc;p=mdsal.git diff --git a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/osgi/OsgiBundleScanningSchemaService.java b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/osgi/OsgiBundleScanningSchemaService.java index 1ff49c0186..87e5c4d23e 100644 --- a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/osgi/OsgiBundleScanningSchemaService.java +++ b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/osgi/OsgiBundleScanningSchemaService.java @@ -13,20 +13,31 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; +import com.google.common.util.concurrent.CheckedFuture; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; +import javax.annotation.Nonnull; +import javax.annotation.concurrent.GuardedBy; import org.opendaylight.mdsal.dom.api.DOMSchemaService; +import org.opendaylight.mdsal.dom.api.DOMSchemaServiceExtension; +import org.opendaylight.mdsal.dom.api.DOMYangTextSourceProvider; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.Registration; import org.opendaylight.yangtools.util.ListenerRegistry; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider; -import org.opendaylight.yangtools.yang.parser.repo.URLSchemaContextResolver; +import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException; +import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; +import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource; +import org.opendaylight.yangtools.yang.parser.repo.YangTextSchemaContextResolver; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; @@ -38,41 +49,50 @@ import org.osgi.util.tracker.ServiceTrackerCustomizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class OsgiBundleScanningSchemaService implements SchemaContextProvider, DOMSchemaService, ServiceTrackerCustomizer, AutoCloseable { +public class OsgiBundleScanningSchemaService implements SchemaContextProvider, DOMSchemaService, + ServiceTrackerCustomizer, DOMYangTextSourceProvider, + AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(OsgiBundleScanningSchemaService.class); + private static final AtomicReference GLOBAL_INSTANCE = new AtomicReference<>(); + + private static final long FRAMEWORK_BUNDLE_ID = 0; + + @GuardedBy("lock") private final ListenerRegistry listeners = new ListenerRegistry<>(); - private final URLSchemaContextResolver contextResolver = URLSchemaContextResolver.create("global-bundle"); + private final YangTextSchemaContextResolver contextResolver = YangTextSchemaContextResolver.create("global-bundle"); private final BundleScanner scanner = new BundleScanner(); + private final Object lock = new Object(); private final BundleContext context; private ServiceTracker listenerTracker; private BundleTracker> bundleTracker; private boolean starting = true; - private static OsgiBundleScanningSchemaService instance; + + private volatile boolean stopping; private OsgiBundleScanningSchemaService(final BundleContext context) { this.context = Preconditions.checkNotNull(context); } - public synchronized static OsgiBundleScanningSchemaService createInstance(final BundleContext ctx) { - Preconditions.checkState(instance == null); - instance = new OsgiBundleScanningSchemaService(ctx); + public static @Nonnull OsgiBundleScanningSchemaService createInstance(final BundleContext ctx) { + OsgiBundleScanningSchemaService instance = new OsgiBundleScanningSchemaService(ctx); + Preconditions.checkState(GLOBAL_INSTANCE.compareAndSet(null, instance)); instance.start(); return instance; } - public synchronized static OsgiBundleScanningSchemaService getInstance() { + public static OsgiBundleScanningSchemaService getInstance() { + OsgiBundleScanningSchemaService instance = GLOBAL_INSTANCE.get(); Preconditions.checkState(instance != null, "Global Instance was not instantiated"); return instance; } @VisibleForTesting - public static synchronized void destroyInstance() { - try { + public static void destroyInstance() { + OsgiBundleScanningSchemaService instance = GLOBAL_INSTANCE.getAndSet(null); + if (instance != null) { instance.close(); - } finally { - instance = null; } } @@ -80,20 +100,26 @@ public class OsgiBundleScanningSchemaService implements SchemaContextProvider, D return context; } - public void start() { + private void start() { checkState(context != null); LOG.debug("start() starting"); - listenerTracker = new ServiceTracker<>(context, SchemaContextListener.class, OsgiBundleScanningSchemaService.this); - bundleTracker = new BundleTracker<>(context, Bundle.RESOLVED | Bundle.STARTING | - Bundle.STOPPING | Bundle.ACTIVE, scanner); - bundleTracker.open(); + listenerTracker = new ServiceTracker<>(context, SchemaContextListener.class, this); + bundleTracker = new BundleTracker<>(context, Bundle.RESOLVED | Bundle.STARTING + | Bundle.STOPPING | Bundle.ACTIVE, scanner); + + synchronized (lock) { + bundleTracker.open(); - LOG.debug("BundleTracker.open() complete"); + LOG.debug("BundleTracker.open() complete"); + + if (Iterables.size(listeners.getListeners()) > 0) { + tryToUpdateSchemaContext(); + } + } listenerTracker.open(); starting = false; - tryToUpdateSchemaContext(); LOG.debug("start() complete"); } @@ -114,29 +140,40 @@ public class OsgiBundleScanningSchemaService implements SchemaContextProvider, D } @Override - public synchronized ListenerRegistration registerSchemaContextListener(final SchemaContextListener listener) { - final Optional potentialCtx = contextResolver.getSchemaContext(); - if(potentialCtx.isPresent()) { - listener.onGlobalContextUpdated(potentialCtx.get()); + public ListenerRegistration registerSchemaContextListener( + final SchemaContextListener listener) { + synchronized (lock) { + final Optional potentialCtx = contextResolver.getSchemaContext(); + if (potentialCtx.isPresent()) { + listener.onGlobalContextUpdated(potentialCtx.get()); + } + return listeners.register(listener); } - return listeners.register(listener); } @Override public void close() { - if (bundleTracker != null) { - bundleTracker.close(); - } - if (listenerTracker != null) { - listenerTracker.close(); - } + synchronized (lock) { + stopping = true; + if (bundleTracker != null) { + bundleTracker.close(); + bundleTracker = null; + } + if (listenerTracker != null) { + listenerTracker.close(); + listenerTracker = null; + } - for (final ListenerRegistration l : listeners.getListeners()) { - l.close(); + for (final ListenerRegistration l : listeners.getListeners()) { + l.close(); + } } } - private synchronized void updateContext(final SchemaContext snapshot) { + @SuppressWarnings("checkstyle:IllegalCatch") + @VisibleForTesting + @GuardedBy("lock") + void notifyListeners(final SchemaContext snapshot) { final Object[] services = listenerTracker.getServices(); for (final ListenerRegistration listener : listeners) { try { @@ -157,11 +194,12 @@ public class OsgiBundleScanningSchemaService implements SchemaContextProvider, D } } + @SuppressWarnings("checkstyle:IllegalCatch") private class BundleScanner implements BundleTrackerCustomizer> { @Override public Iterable addingBundle(final Bundle bundle, final BundleEvent event) { - if (bundle.getBundleId() == 0) { + if (bundle.getBundleId() == FRAMEWORK_BUNDLE_ID) { return Collections.emptyList(); } @@ -192,6 +230,13 @@ public class OsgiBundleScanningSchemaService implements SchemaContextProvider, D @Override public void modifiedBundle(final Bundle bundle, final BundleEvent event, final Iterable object) { + if (bundle.getBundleId() == FRAMEWORK_BUNDLE_ID) { + LOG.debug("Framework bundle {} got event {}", bundle, event.getType()); + if ((event.getType() & BundleEvent.STOPPING) != 0) { + LOG.info("OSGi framework is being stopped, halting bundle scanning"); + stopping = true; + } + } } /** @@ -199,9 +244,9 @@ public class OsgiBundleScanningSchemaService implements SchemaContextProvider, D * {@link #getYangStoreSnapshot()} will throw exception. There is no * rollback. */ - + @SuppressWarnings("checkstyle:IllegalCatch") @Override - public synchronized void removedBundle(final Bundle bundle, final BundleEvent event, final Iterable urls) { + public void removedBundle(final Bundle bundle, final BundleEvent event, final Iterable urls) { for (final Registration url : urls) { try { url.close(); @@ -211,9 +256,10 @@ public class OsgiBundleScanningSchemaService implements SchemaContextProvider, D } final int numUrls = Iterables.size(urls); - if(numUrls > 0 ) { - if(LOG.isDebugEnabled()) { - LOG.debug("removedBundle: {}, state: {}, # urls: {}", bundle.getSymbolicName(), bundle.getState(), numUrls); + if (numUrls > 0 ) { + if (LOG.isDebugEnabled()) { + LOG.debug("removedBundle: {}, state: {}, # urls: {}", bundle.getSymbolicName(), + bundle.getState(), numUrls); } tryToUpdateSchemaContext(); @@ -222,7 +268,7 @@ public class OsgiBundleScanningSchemaService implements SchemaContextProvider, D } @Override - public synchronized SchemaContextListener addingService(final ServiceReference reference) { + public SchemaContextListener addingService(final ServiceReference reference) { final SchemaContextListener listener = context.getService(reference); final SchemaContext _ctxContext = getGlobalContext(); @@ -232,27 +278,43 @@ public class OsgiBundleScanningSchemaService implements SchemaContextProvider, D return listener; } - public synchronized void tryToUpdateSchemaContext() { - if (starting) { + public void tryToUpdateSchemaContext() { + if (starting || stopping) { return; } - final Optional schema = contextResolver.getSchemaContext(); - if(schema.isPresent()) { - if(LOG.isDebugEnabled()) { - LOG.debug("Got new SchemaContext: # of modules {}", schema.get().getAllModuleIdentifiers().size()); - } - updateContext(schema.get()); + synchronized (lock) { + final Optional schema = contextResolver.getSchemaContext(); + if (schema.isPresent()) { + if (LOG.isDebugEnabled()) { + LOG.debug("Got new SchemaContext: # of modules {}", schema.get().getAllModuleIdentifiers().size()); + } + + notifyListeners(schema.get()); + } } } @Override - public void modifiedService(final ServiceReference reference, final SchemaContextListener service) { + public void modifiedService(final ServiceReference reference, + final SchemaContextListener service) { // NOOP } @Override - public void removedService(final ServiceReference reference, final SchemaContextListener service) { + public void removedService(final ServiceReference reference, + final SchemaContextListener service) { context.ungetService(reference); } + + @Override + public Map, DOMSchemaServiceExtension> getSupportedExtensions() { + return ImmutableMap.of(DOMYangTextSourceProvider.class, this); + } + + @Override + public CheckedFuture getSource( + final SourceIdentifier sourceIdentifier) { + return contextResolver.getSource(sourceIdentifier); + } }