+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.dom.broker;
-
-import static com.google.common.base.Preconditions.checkState;
-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.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.concurrent.atomic.AtomicReference;
-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.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.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 AtomicReference<GlobalBundleScanningSchemaServiceImpl> globalInstance = new AtomicReference<>();
-
- @GuardedBy(value = "lock")
- private final ListenerRegistry<SchemaContextListener> listeners = new ListenerRegistry<>();
- private final YangTextSchemaContextResolver contextResolver = YangTextSchemaContextResolver.create("global-bundle");
- private final BundleScanner scanner = new BundleScanner();
- private final BundleContext context;
-
- private ServiceTracker<SchemaContextListener, SchemaContextListener> listenerTracker;
- private BundleTracker<Iterable<Registration>> bundleTracker;
- private boolean starting = true;
- private volatile boolean stopping;
- private final Object lock = new Object();
-
- private GlobalBundleScanningSchemaServiceImpl(final BundleContext context) {
- this.context = Preconditions.checkNotNull(context);
- }
-
- public static GlobalBundleScanningSchemaServiceImpl createInstance(final BundleContext ctx) {
- GlobalBundleScanningSchemaServiceImpl instance = new GlobalBundleScanningSchemaServiceImpl(ctx);
- Preconditions.checkState(globalInstance.compareAndSet(null, instance));
- instance.start();
- return instance;
- }
-
- public static GlobalBundleScanningSchemaServiceImpl getInstance() {
- GlobalBundleScanningSchemaServiceImpl instance = globalInstance.get();
- Preconditions.checkState(instance != null, "Global Instance was not instantiated");
- return instance;
- }
-
- @VisibleForTesting
- public static void destroyInstance() {
- GlobalBundleScanningSchemaServiceImpl instance = globalInstance.getAndSet(null);
- if(instance != null) {
- instance.close();
- }
- }
-
- public BundleContext getContext() {
- return context;
- }
-
- public void start() {
- checkState(context != null);
- LOG.debug("start() starting");
-
- listenerTracker = new ServiceTracker<>(context, SchemaContextListener.class, GlobalBundleScanningSchemaServiceImpl.this);
- bundleTracker = new BundleTracker<>(context, Bundle.RESOLVED | Bundle.STARTING |
- Bundle.STOPPING | Bundle.ACTIVE, scanner);
-
- synchronized(lock) {
- bundleTracker.open();
-
- LOG.debug("BundleTracker.open() complete");
-
- boolean hasExistingListeners = Iterables.size(listeners.getListeners()) > 0;
- if(hasExistingListeners) {
- tryToUpdateSchemaContext();
- }
- }
-
- listenerTracker.open();
- starting = false;
-
- LOG.debug("start() complete");
- }
-
- @Override
- public SchemaContext getSchemaContext() {
- return getGlobalContext();
- }
-
- @Override
- public SchemaContext getGlobalContext() {
- return contextResolver.getSchemaContext().orNull();
- }
-
- @Override
- public void addModule(final Module module) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public SchemaContext getSessionContext() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void removeModule(final Module module) {
- throw new UnsupportedOperationException();
- }
-
- @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);
- }
- }
-
- @Override
- public void close() {
- stopping = true;
- if (bundleTracker != null) {
- bundleTracker.close();
- }
- if (listenerTracker != null) {
- listenerTracker.close();
- }
-
- for (ListenerRegistration<SchemaContextListener> l : listeners.getListeners()) {
- l.close();
- }
- }
-
- @GuardedBy(value = "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);
- }
- }
- }
- }
-
- @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() == 0) {
- 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 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();
- }
- }
- }
-
- @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);
- }
-}