org.opendaylight.controller.sal.schema.service.impl.GlobalBundleScanningSchemaServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.opendaylight.controller.sal.schema.service.impl.GlobalBundleScanningSchemaServiceImpl.java

Source

/*
 * 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.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 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);

    @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);
        instance.start();
        return instance;
    }

    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);
    }
}