X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-dom-broker%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fsal%2Fdom%2Fbroker%2FSchemaServiceImpl.java;h=428521b72f28bfbb719a3bd0fe4f214e5766b46f;hp=531f9e86c2dd76f55116a46a8d347d9b2daa1f6a;hb=3c6f666df68dfa61608dba4566afefb168fc7e7a;hpb=f20add00faf71465ad092144689450c105f9bde3 diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/SchemaServiceImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/SchemaServiceImpl.java index 531f9e86c2..428521b72f 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/SchemaServiceImpl.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/SchemaServiceImpl.java @@ -1,67 +1,60 @@ +/* + * 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 java.io.IOException; -import java.io.InputStream; +import static com.google.common.base.Preconditions.checkState; + import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; import java.util.Enumeration; -import java.util.List; -import java.util.Set; -import java.util.zip.Checksum; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -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.opendaylight.controller.sal.core.api.model.SchemaService; +import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener; +import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.concepts.Registration; +import org.opendaylight.yangtools.concepts.util.ListenerRegistry; import org.opendaylight.yangtools.yang.model.api.Module; -import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser; -import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.parser.impl.util.URLSchemaContextResolver; import org.osgi.framework.Bundle; -import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; import org.osgi.framework.ServiceReference; -import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.concepts.util.ListenerRegistry; -import org.opendaylight.controller.sal.core.api.model.SchemaService; -import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener; +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; -import com.google.common.base.Function; import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import com.google.common.collect.Collections2; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; - -import static com.google.common.base.Preconditions.*; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableSet.Builder; public class SchemaServiceImpl implements // -SchemaService, // -ServiceTrackerCustomizer, // -AutoCloseable { + SchemaContextProvider, // + SchemaService, // + ServiceTrackerCustomizer, // + AutoCloseable { private static final Logger logger = LoggerFactory.getLogger(SchemaServiceImpl.class); private ListenerRegistry listeners; - private YangModelParser parser; - + private BundleContext context; private BundleScanner scanner = new BundleScanner(); - /** - * Map of currently problematic yang files that should get fixed eventually - * after all events are received. - */ - private final Multimap inconsistentBundlesToYangURLs = HashMultimap.create(); - private final Multimap consistentBundlesToYangURLs = HashMultimap.create(); - private BundleTracker bundleTracker; - private final YangStoreCache cache = new YangStoreCache(); + private BundleTracker>> bundleTracker; + + private final URLSchemaContextResolver contextResolver = new URLSchemaContextResolver(); - private ServiceTracker listenerTracker; + private ServiceTracker listenerTracker; + + private boolean starting = true; public ListenerRegistry getListeners() { return listeners; @@ -71,14 +64,6 @@ AutoCloseable { this.listeners = listeners; } - public YangModelParser getParser() { - return parser; - } - - public void setParser(YangModelParser parser) { - this.parser = parser; - } - public BundleContext getContext() { return context; } @@ -88,123 +73,70 @@ AutoCloseable { } public void start() { - checkState(parser != null); checkState(context != null); if (listeners == null) { listeners = new ListenerRegistry<>(); } - - listenerTracker = new ServiceTracker<>(context, SchemaServiceListener.class, this); - bundleTracker = new BundleTracker(context, BundleEvent.RESOLVED | BundleEvent.UNRESOLVED, scanner); + + listenerTracker = new ServiceTracker<>(context, SchemaServiceListener.class, SchemaServiceImpl.this); + bundleTracker = new BundleTracker>>(context, BundleEvent.RESOLVED + | BundleEvent.UNRESOLVED, scanner); bundleTracker.open(); listenerTracker.open(); + starting = false; + tryToUpdateSchemaContext(); } - public SchemaContext getGlobalContext() { - return getSchemaContextSnapshot(); + @Override + public SchemaContext getSchemaContext() { + return getGlobalContext(); } - public synchronized SchemaContext getSchemaContextSnapshot() { - Optional yangStoreOpt = cache.getCachedSchemaContext(consistentBundlesToYangURLs); - if (yangStoreOpt.isPresent()) { - return yangStoreOpt.get(); - } - SchemaContext snapshot = createSnapshot(parser, consistentBundlesToYangURLs); - updateCache(snapshot); - return snapshot; + public SchemaContext getGlobalContext() { + return contextResolver.getSchemaContext().orNull(); } @Override public void addModule(Module module) { - // TODO Auto-generated method stub throw new UnsupportedOperationException(); } @Override public SchemaContext getSessionContext() { - // TODO Auto-generated method stub throw new UnsupportedOperationException(); } @Override public void removeModule(Module module) { - // TODO Auto-generated method stub throw new UnsupportedOperationException(); } - @Override public ListenerRegistration registerSchemaServiceListener(SchemaServiceListener listener) { return listeners.register(listener); } - + @Override public void close() throws Exception { - bundleTracker.close(); - // FIXME: Add listeners.close(); - - } - - private synchronized boolean tryToUpdateState(Collection changedURLs, Multimap proposedNewState, - boolean adding) { - Preconditions.checkArgument(changedURLs.size() > 0, "No change can occur when no URLs are changed"); - - try { - // consistent state - // merge into - SchemaContext snapshot = createSnapshot(parser, proposedNewState); - consistentBundlesToYangURLs.clear(); - consistentBundlesToYangURLs.putAll(proposedNewState); - inconsistentBundlesToYangURLs.clear(); - // update cache - updateCache(snapshot); - logger.info("SchemaService updated to new consistent state"); - logger.trace("SchemaService updated to new consistent state containing {}", consistentBundlesToYangURLs); - - // notifyListeners(changedURLs, adding); - return true; - } catch (Exception e) { - // inconsistent state - logger.debug( - "SchemaService is falling back on last consistent state containing {}, inconsistent yang files {}, reason {}", - consistentBundlesToYangURLs, inconsistentBundlesToYangURLs, e.toString()); - return false; + if (bundleTracker != null) { + bundleTracker.close(); } + if (listenerTracker != null) { + listenerTracker.close(); + } + // FIXME: Add listeners.close(); } - private static Collection fromUrlsToInputStreams(Multimap multimap) { - return Collections2.transform(multimap.values(), new Function() { - - @Override - public InputStream apply(URL url) { - try { - return url.openStream(); - } catch (IOException e) { - logger.warn("Unable to open stream from {}", url); - throw new IllegalStateException("Unable to open stream from " + url, e); - } - } - }); - } - - private static SchemaContext createSnapshot(YangModelParser parser, Multimap multimap) { - List models = new ArrayList<>(fromUrlsToInputStreams(multimap)); - Set modules = parser.parseYangModelsFromStreams(models); - SchemaContext yangStoreSnapshot = parser.resolveSchemaContext(modules); - return yangStoreSnapshot; - } - private void updateCache(SchemaContext snapshot) { - cache.cacheYangStore(consistentBundlesToYangURLs, snapshot); - + private void updateContext(SchemaContext snapshot) { Object[] services = listenerTracker.getServices(); - if(services != null) { - for(Object rawListener : services) { + if (services != null) { + for (Object rawListener : services) { SchemaServiceListener listener = (SchemaServiceListener) rawListener; try { listener.onGlobalContextUpdated(snapshot); } catch (Exception e) { - logger.error("Exception occured during invoking listener",e); + logger.error("Exception occured during invoking listener", e); } } } @@ -212,48 +144,35 @@ AutoCloseable { try { listener.getInstance().onGlobalContextUpdated(snapshot); } catch (Exception e) { - logger.error("Exception occured during invoking listener",e); + logger.error("Exception occured during invoking listener", e); } } } - private class BundleScanner implements BundleTrackerCustomizer { + private class BundleScanner implements BundleTrackerCustomizer>> { @Override - public Object addingBundle(Bundle bundle, BundleEvent event) { + public ImmutableSet> addingBundle(Bundle bundle, BundleEvent event) { - // Ignore system bundle: - // system bundle might have config-api on classpath && - // config-api contains yang files => - // system bundle might contain yang files from that bundle - if (bundle.getBundleId() == 0) - return bundle; + if (bundle.getBundleId() == 0) { + return ImmutableSet.of(); + } Enumeration enumeration = bundle.findEntries("META-INF/yang", "*.yang", false); - if (enumeration != null && enumeration.hasMoreElements()) { - synchronized (this) { - List addedURLs = new ArrayList<>(); - while (enumeration.hasMoreElements()) { - URL url = enumeration.nextElement(); - addedURLs.add(url); - } - logger.trace("Bundle {} has event {}, bundle state {}, URLs {}", bundle, event, bundle.getState(), - addedURLs); - // test that yang store is consistent - Multimap proposedNewState = HashMultimap.create(consistentBundlesToYangURLs); - proposedNewState.putAll(inconsistentBundlesToYangURLs); - proposedNewState.putAll(bundle, addedURLs); - boolean adding = true; - - if (tryToUpdateState(addedURLs, proposedNewState, adding) == false) { - inconsistentBundlesToYangURLs.putAll(bundle, addedURLs); - } - } + Builder> builder = ImmutableSet.> builder(); + while (enumeration != null && enumeration.hasMoreElements()) { + Registration reg = contextResolver.registerSource(enumeration.nextElement()); + builder.add(reg); + } + ImmutableSet> urls = builder.build(); + if(urls.isEmpty()) { + return urls; } - return bundle; + tryToUpdateSchemaContext(); + return urls; } @Override - public void modifiedBundle(Bundle bundle, BundleEvent event, Object object) { + public void modifiedBundle(Bundle bundle, BundleEvent event, ImmutableSet> object) { logger.debug("Modified bundle {} {} {}", bundle, event, object); } @@ -264,60 +183,44 @@ AutoCloseable { */ @Override - public synchronized void removedBundle(Bundle bundle, BundleEvent event, Object object) { - inconsistentBundlesToYangURLs.removeAll(bundle); - Collection consistentURLsToBeRemoved = consistentBundlesToYangURLs.removeAll(bundle); - - if (consistentURLsToBeRemoved.isEmpty()) { - return; // no change + public synchronized void removedBundle(Bundle bundle, BundleEvent event, ImmutableSet> urls) { + for (Registration url : urls) { + try { + url.close(); + } catch (Exception e) { + e.printStackTrace(); + } } - boolean adding = false; - // notifyListeners(consistentURLsToBeRemoved, adding); + tryToUpdateSchemaContext(); } } - private static final class YangStoreCache { - - Set cachedUrls; - SchemaContext cachedContextSnapshot; - - Optional getCachedSchemaContext(Multimap bundlesToYangURLs) { - Set urls = setFromMultimapValues(bundlesToYangURLs); - if (cachedUrls != null && cachedUrls.equals(urls)) { - Preconditions.checkState(cachedContextSnapshot != null); - return Optional.of(cachedContextSnapshot); - } - return Optional.absent(); - } - - private static Set setFromMultimapValues(Multimap bundlesToYangURLs) { - Set urls = Sets.newHashSet(bundlesToYangURLs.values()); - Preconditions.checkState(bundlesToYangURLs.size() == urls.size()); - return urls; - } - - void cacheYangStore(Multimap urls, SchemaContext ctx) { - this.cachedUrls = setFromMultimapValues(urls); - this.cachedContextSnapshot = ctx; - } - } - @Override public SchemaServiceListener addingService(ServiceReference reference) { - + SchemaServiceListener listener = context.getService(reference); SchemaContext _ctxContext = getGlobalContext(); - if(getContext() != null) { + if (getContext() != null) { listener.onGlobalContextUpdated(_ctxContext); } return listener; } - + + public synchronized void tryToUpdateSchemaContext() { + if(starting ) { + return; + } + Optional schema = contextResolver.tryToUpdateSchemaContext(); + if(schema.isPresent()) { + updateContext(schema.get()); + } + } + @Override public void modifiedService(ServiceReference reference, SchemaServiceListener service) { // NOOP } - + @Override public void removedService(ServiceReference reference, SchemaServiceListener service) { context.ungetService(reference);