*/
package org.opendaylight.controller.sal.schema.service.impl;
-import static com.google.common.base.Preconditions.checkState;
-import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-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 com.google.common.util.concurrent.Futures;
+import java.util.HashSet;
+import java.util.Set;
import javax.annotation.concurrent.GuardedBy;
import org.opendaylight.controller.sal.core.api.model.SchemaService;
import org.opendaylight.controller.sal.core.api.model.YangTextSourceProvider;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.api.DOMYangTextSourceProvider;
+import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
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.Module;
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.model.repo.api.MissingSchemaSourceException;
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;
-import org.osgi.framework.ServiceReference;
-import org.osgi.util.tracker.BundleTracker;
-import org.osgi.util.tracker.BundleTrackerCustomizer;
-import org.osgi.util.tracker.ServiceTracker;
-import org.osgi.util.tracker.ServiceTrackerCustomizer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-public class GlobalBundleScanningSchemaServiceImpl implements SchemaContextProvider, SchemaService,
- ServiceTrackerCustomizer<SchemaContextListener, SchemaContextListener>, YangTextSourceProvider, AutoCloseable {
- private static final Logger LOG = LoggerFactory.getLogger(GlobalBundleScanningSchemaServiceImpl.class);
- private static final long FRAMEWORK_BUNDLE_ID = 0;
+public final class GlobalBundleScanningSchemaServiceImpl implements SchemaContextProvider, SchemaService,
+ YangTextSourceProvider, AutoCloseable {
- @GuardedBy(value = "lock")
- private final ListenerRegistry<SchemaContextListener> listeners = new ListenerRegistry<>();
- private final YangTextSchemaContextResolver contextResolver = YangTextSchemaContextResolver.create("global-bundle");
- private final BundleScanner scanner = new BundleScanner();
+ @GuardedBy("lock")
+ private final Set<ListenerRegistration<?>> listeners = new HashSet<>();
private final Object lock = new Object();
- private final BundleContext context;
-
- private ServiceTracker<SchemaContextListener, SchemaContextListener> listenerTracker;
- private BundleTracker<Iterable<Registration>> bundleTracker;
- private boolean starting = true;
-
- private volatile boolean stopping;
-
- private GlobalBundleScanningSchemaServiceImpl(final BundleContext context) {
- this.context = Preconditions.checkNotNull(context);
- }
+ private final DOMSchemaService schemaService;
+ private final DOMYangTextSourceProvider yangProvider;
- public static GlobalBundleScanningSchemaServiceImpl createInstance(final BundleContext ctx) {
- GlobalBundleScanningSchemaServiceImpl instance = new GlobalBundleScanningSchemaServiceImpl(ctx);
- instance.start();
- return instance;
+ private GlobalBundleScanningSchemaServiceImpl(final DOMSchemaService schemaService) {
+ this.schemaService = Preconditions.checkNotNull(schemaService);
+ this.yangProvider = (DOMYangTextSourceProvider) schemaService.getSupportedExtensions()
+ .get(DOMYangTextSourceProvider.class);
}
- public BundleContext getContext() {
- return context;
- }
-
- private void start() {
- checkState(context != null);
- LOG.debug("start() starting");
-
- 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");
- if (Iterables.size(listeners.getListeners()) > 0) {
- tryToUpdateSchemaContext();
- }
- }
-
- listenerTracker.open();
- starting = false;
-
- LOG.debug("start() complete");
+ public static GlobalBundleScanningSchemaServiceImpl createInstance(final DOMSchemaService schemaService) {
+ return new GlobalBundleScanningSchemaServiceImpl(schemaService);
}
@Override
public SchemaContext getSchemaContext() {
- return getGlobalContext();
+ return schemaService.getGlobalContext();
}
@Override
public SchemaContext getGlobalContext() {
- return contextResolver.getSchemaContext().orNull();
+ return schemaService.getGlobalContext();
}
@Override
public ListenerRegistration<SchemaContextListener> registerSchemaContextListener(
final SchemaContextListener listener) {
synchronized (lock) {
- Optional<SchemaContext> potentialCtx = contextResolver.getSchemaContext();
- if(potentialCtx.isPresent()) {
- listener.onGlobalContextUpdated(potentialCtx.get());
- }
- return listeners.register(listener);
+ final ListenerRegistration<SchemaContextListener> reg = schemaService.registerSchemaContextListener(
+ listener);
+
+ final ListenerRegistration<SchemaContextListener> ret =
+ new AbstractListenerRegistration<SchemaContextListener>(listener) {
+ @Override
+ protected void removeRegistration() {
+ synchronized (lock) {
+ listeners.remove(this);
+ }
+ reg.close();
+ }
+ };
+
+ listeners.add(ret);
+ return ret;
}
}
@Override
public void close() {
synchronized (lock) {
- stopping = true;
- if (bundleTracker != null) {
- bundleTracker.close();
- bundleTracker = null;
- }
- if (listenerTracker != null) {
- listenerTracker.close();
- listenerTracker = null;
- }
-
- for (ListenerRegistration<SchemaContextListener> l : listeners.getListeners()) {
+ for (ListenerRegistration<?> l : listeners) {
l.close();
}
+ listeners.clear();
}
}
- @GuardedBy("lock")
- private void notifyListeners(final SchemaContext snapshot) {
- Object[] services = listenerTracker.getServices();
- for (ListenerRegistration<SchemaContextListener> listener : listeners) {
- try {
- listener.getInstance().onGlobalContextUpdated(snapshot);
- } catch (Exception e) {
- LOG.error("Exception occured during invoking listener", e);
- }
- }
- if (services != null) {
- for (Object rawListener : services) {
- final SchemaContextListener listener = (SchemaContextListener) rawListener;
- try {
- listener.onGlobalContextUpdated(snapshot);
- } catch (Exception e) {
- LOG.error("Exception occured during invoking listener {}", listener, e);
- }
- }
- }
- }
-
+ @SuppressWarnings("unchecked")
@Override
public CheckedFuture<YangTextSchemaSource, SchemaSourceException> getSource(
final SourceIdentifier sourceIdentifier) {
- return contextResolver.getSource(sourceIdentifier);
- }
-
- private class BundleScanner implements BundleTrackerCustomizer<Iterable<Registration>> {
- @Override
- public Iterable<Registration> addingBundle(final Bundle bundle, final BundleEvent event) {
- if (bundle.getBundleId() == FRAMEWORK_BUNDLE_ID) {
- return Collections.emptyList();
- }
-
- final Enumeration<URL> enumeration = bundle.findEntries("META-INF/yang", "*.yang", false);
- if (enumeration == null) {
- return Collections.emptyList();
- }
-
- final List<Registration> urls = new ArrayList<>();
- while (enumeration.hasMoreElements()) {
- final URL u = enumeration.nextElement();
- try {
- urls.add(contextResolver.registerSource(u));
- LOG.debug("Registered {}", u);
- } catch (Exception e) {
- LOG.warn("Failed to register {}, ignoring it", e);
- }
- }
-
- if (!urls.isEmpty()) {
- LOG.debug("Loaded {} new URLs from bundle {}, attempting to rebuild schema context",
- urls.size(), bundle.getSymbolicName());
- tryToUpdateSchemaContext();
- }
-
- return ImmutableList.copyOf(urls);
- }
-
- @Override
- public void modifiedBundle(final Bundle bundle, final BundleEvent event, final Iterable<Registration> 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;
- }
- }
- }
-
- /**
- * If removing YANG files makes yang store inconsistent, method
- * {@link #getYangStoreSnapshot()} will throw exception. There is no
- * rollback.
- */
- @Override
- public void removedBundle(final Bundle bundle, final BundleEvent event, final Iterable<Registration> urls) {
- for (Registration url : urls) {
- try {
- url.close();
- } catch (Exception e) {
- LOG.warn("Failed do unregister URL {}, proceeding", url, e);
- }
- }
-
- int numUrls = Iterables.size(urls);
- if(numUrls > 0 ) {
- if(LOG.isDebugEnabled()) {
- LOG.debug("removedBundle: {}, state: {}, # urls: {}", bundle.getSymbolicName(), bundle.getState(),
- numUrls);
- }
-
- tryToUpdateSchemaContext();
- }
+ if (yangProvider == null) {
+ return Futures.immediateFailedCheckedFuture(new MissingSchemaSourceException(
+ "Source provider is not available", sourceIdentifier));
}
- }
- @Override
- public SchemaContextListener addingService(final ServiceReference<SchemaContextListener> reference) {
-
- SchemaContextListener listener = context.getService(reference);
- SchemaContext _ctxContext = getGlobalContext();
- if (getContext() != null && _ctxContext != null) {
- listener.onGlobalContextUpdated(_ctxContext);
- }
- return listener;
- }
-
- public void tryToUpdateSchemaContext() {
- if (starting || stopping) {
- return;
- }
-
- synchronized (lock) {
- Optional<SchemaContext> 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<SchemaContextListener> reference,
- final SchemaContextListener service) {
- // NOOP
- }
-
- @Override
- public void removedService(final ServiceReference<SchemaContextListener> reference,
- final SchemaContextListener service) {
- context.ungetService(reference);
+ return (CheckedFuture<YangTextSchemaSource, SchemaSourceException>) yangProvider.getSource(sourceIdentifier);
}
}