From: Ed Warnicke Date: Fri, 8 Nov 2013 10:46:25 +0000 (+0000) Subject: Merge "Unified implementations of BrokerService Proxies which are provided to Consume... X-Git-Tag: jenkins-controller-bulk-release-prepare-only-2-1~459 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=292bc87b66ab44f9d5d81587c25a5bd1d68dc766;hp=17c23f3c4f9726f268b481398ee0ca1df499b324;p=controller.git Merge "Unified implementations of BrokerService Proxies which are provided to Consumers/Producers." --- diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/model/SchemaService.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/model/SchemaService.java index 52f60b3cc2..b34c8d4c00 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/model/SchemaService.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/model/SchemaService.java @@ -8,6 +8,7 @@ package org.opendaylight.controller.sal.core.api.model; import org.opendaylight.controller.sal.core.api.BrokerService; +import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -39,4 +40,6 @@ public interface SchemaService extends BrokerService { * @return */ SchemaContext getGlobalContext(); + + ListenerRegistration registerSchemaServiceListener(SchemaServiceListener listener); } diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/model/SchemaServiceListener.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/model/SchemaServiceListener.java new file mode 100644 index 0000000000..d76fd4d726 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/model/SchemaServiceListener.java @@ -0,0 +1,12 @@ +package org.opendaylight.controller.sal.core.api.model; + +import java.util.EventListener; + +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +public interface SchemaServiceListener extends EventListener { + + + void onGlobalContextUpdated(SchemaContext context); + +} diff --git a/opendaylight/md-sal/sal-dom-broker/pom.xml b/opendaylight/md-sal/sal-dom-broker/pom.xml index 9383a9e2ff..74dd1a9901 100644 --- a/opendaylight/md-sal/sal-dom-broker/pom.xml +++ b/opendaylight/md-sal/sal-dom-broker/pom.xml @@ -1,79 +1,89 @@ - - 4.0.0 - - org.opendaylight.controller - sal-parent - 1.0-SNAPSHOT - - sal-broker-impl - bundle - - scm:git:ssh://git.opendaylight.org:29418/controller.git - scm:git:ssh://git.opendaylight.org:29418/controller.git - https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL - - - - - org.opendaylight.controller - sal-core-api - 1.0-SNAPSHOT - - - org.opendaylight.controller - sal-common-util - 1.0-SNAPSHOT - - - org.opendaylight.controller - sal-common-impl - 1.0-SNAPSHOT - - - org.opendaylight.controller - sal-common-impl - 1.0-SNAPSHOT - - - org.opendaylight.controller - sal-core-spi - 1.0-SNAPSHOT - - - org.slf4j - slf4j-api - - - com.google.guava - guava - - - org.eclipse.xtend - org.eclipse.xtend.lib - - - - - - - org.apache.felix - maven-bundle-plugin - true - - - ${project.groupId}.${project.artifactId} - org.opendaylight.controller.sal.dom.broker.BrokerActivator - - org.opendaylight.controller.sal.dom.broker.* - - - - - - org.eclipse.xtend - xtend-maven-plugin - - - - + + 4.0.0 + + org.opendaylight.controller + sal-parent + 1.0-SNAPSHOT + + sal-broker-impl + bundle + + scm:git:ssh://git.opendaylight.org:29418/controller.git + scm:git:ssh://git.opendaylight.org:29418/controller.git + https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL + + + + + org.opendaylight.controller + sal-core-api + 1.0-SNAPSHOT + + + org.opendaylight.controller + sal-common-util + 1.0-SNAPSHOT + + + org.opendaylight.controller + sal-common-impl + 1.0-SNAPSHOT + + + org.opendaylight.controller + sal-common-impl + 1.0-SNAPSHOT + + + org.opendaylight.controller + sal-core-spi + 1.0-SNAPSHOT + + + org.slf4j + slf4j-api + + + com.google.guava + guava + + + org.eclipse.xtend + org.eclipse.xtend.lib + + + org.opendaylight.controller + config-api + 0.2.2-SNAPSHOT + + + org.opendaylight.yangtools + yang-parser-impl + 0.5.9-SNAPSHOT + + + + + + + org.apache.felix + maven-bundle-plugin + true + + + ${project.groupId}.${project.artifactId} + org.opendaylight.controller.sal.dom.broker.BrokerActivator + + org.opendaylight.controller.sal.dom.broker.* + + + + + + org.eclipse.xtend + xtend-maven-plugin + + + + diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerActivator.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerActivator.java index e3f5e4b4cd..2bab4dbd26 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerActivator.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerActivator.java @@ -3,6 +3,10 @@ package org.opendaylight.controller.sal.dom.broker; import java.util.Hashtable; import org.opendaylight.controller.sal.core.api.Broker; +import org.opendaylight.controller.sal.core.api.data.DataBrokerService; +import org.opendaylight.controller.sal.core.api.data.DataProviderService; +import org.opendaylight.controller.sal.core.api.model.SchemaService; +import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; @@ -11,17 +15,35 @@ public class BrokerActivator implements BundleActivator { BrokerImpl broker; private ServiceRegistration brokerReg; - + private ServiceRegistration schemaReg; + private ServiceRegistration dataReg; + private ServiceRegistration dataProviderReg; + private SchemaServiceImpl schemaService; + private DataBrokerImpl dataService; + @Override public void start(BundleContext context) throws Exception { + Hashtable emptyProperties = new Hashtable(); broker = new BrokerImpl(); broker.setBundleContext(context); - brokerReg = context.registerService(Broker.class, broker, new Hashtable()); + brokerReg = context.registerService(Broker.class, broker, emptyProperties); + + schemaService = new SchemaServiceImpl(); + schemaService.setContext(context); + schemaService.setParser(new YangParserImpl()); + schemaService.start(); + schemaReg = context.registerService(SchemaService.class, schemaService, new Hashtable()); + + dataService = new DataBrokerImpl(); + dataReg = context.registerService(DataBrokerService.class, dataService, emptyProperties); + dataProviderReg = context.registerService(DataProviderService.class, dataService, emptyProperties); + + } @Override public void stop(BundleContext context) throws Exception { - if(brokerReg != null) { + if (brokerReg != null) { brokerReg.unregister(); } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend index 855ad9bd32..26fecef688 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend @@ -37,16 +37,13 @@ public class BrokerImpl implements Broker { private val Set sessions = Collections.synchronizedSet(new HashSet()); private val Set providerSessions = Collections.synchronizedSet( new HashSet()); - private val Set modules = Collections.synchronizedSet(new HashSet()); - private val Map, BrokerModule> serviceProviders = Collections. - synchronizedMap(new HashMap, BrokerModule>()); // Implementation specific @Property private var ExecutorService executor = Executors.newFixedThreadPool(5); @Property private var BundleContext bundleContext; - + @Property private var RpcRouter router; @@ -68,29 +65,6 @@ public class BrokerImpl implements Broker { return session; } - public def addModule(BrokerModule module) { - log.info("Registering broker module " + module); - if(modules.contains(module)) { - log.error("Module already registered"); - throw new IllegalArgumentException("Module already exists."); - } - - val provServices = module.getProvidedServices(); - for (Class serviceType : provServices) { - log.info(" Registering session service implementation: " + serviceType.getCanonicalName()); - serviceProviders.put(serviceType, module); - } - } - - public def T serviceFor(Class service, ConsumerContextImpl session) { - val prov = serviceProviders.get(service); - if(prov == null) { - log.warn("Service " + service.toString() + " is not supported"); - return null; - } - return prov.getServiceForSession(service, session); - } - protected def Future> invokeRpc(QName rpc, CompositeNode input) { val result = executor.submit([|router.invokeRpc(rpc, input)] as Callable>); return result; @@ -98,20 +72,20 @@ public class BrokerImpl implements Broker { // Validation private def void checkPredicates(Provider prov) { - if(prov == null) + if (prov == null) throw new IllegalArgumentException("Provider should not be null."); for (ProviderContextImpl session : providerSessions) { - if(prov.equals(session.getProvider())) + if (prov.equals(session.getProvider())) throw new IllegalStateException("Provider already registered"); } } private def void checkPredicates(Consumer cons) { - if(cons == null) + if (cons == null) throw new IllegalArgumentException("Consumer should not be null."); for (ConsumerContextImpl session : sessions) { - if(cons.equals(session.getConsumer())) + if (cons.equals(session.getConsumer())) throw new IllegalStateException("Consumer already registered"); } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/ConsumerContextImpl.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/ConsumerContextImpl.xtend index 6d57a4e224..9f21823e3e 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/ConsumerContextImpl.xtend +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/ConsumerContextImpl.xtend @@ -1,13 +1,15 @@ package org.opendaylight.controller.sal.dom.broker -import java.util.Collections import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession -import java.util.HashMap import org.opendaylight.controller.sal.core.api.BrokerService import org.opendaylight.controller.sal.core.api.Consumer import org.osgi.framework.BundleContext import org.opendaylight.yangtools.yang.common.QName import org.opendaylight.yangtools.yang.data.api.CompositeNode +import org.opendaylight.controller.sal.dom.broker.osgi.AbstractBrokerServiceProxy +import com.google.common.collect.ClassToInstanceMap +import com.google.common.collect.MutableClassToInstanceMap +import org.opendaylight.controller.sal.dom.broker.osgi.ProxyFactory class ConsumerContextImpl implements ConsumerSession { @@ -17,8 +19,7 @@ class ConsumerContextImpl implements ConsumerSession { @Property private var BrokerImpl broker; - private val instantiatedServices = Collections.synchronizedMap( - new HashMap, BrokerService>()); + private val ClassToInstanceMap instantiatedServices = MutableClassToInstanceMap.create(); private boolean closed = false; private BundleContext context; @@ -33,14 +34,20 @@ class ConsumerContextImpl implements ConsumerSession { } override T getService(Class service) { - val potential = instantiatedServices.get(service); - if(potential != null) { - val ret = potential as T; - return ret; + val localProxy = instantiatedServices.getInstance(service); + if(localProxy != null) { + return localProxy; } - val ret = broker.serviceFor(service, this); + val serviceRef = context.getServiceReference(service); + if(serviceRef == null) { + return null; + } + val serviceImpl = context.getService(serviceRef); + + + val ret = ProxyFactory.createProxy(serviceRef,serviceImpl); if(ret != null) { - instantiatedServices.put(service, ret); + instantiatedServices.putInstance(service, ret); } return ret; } @@ -49,7 +56,9 @@ class ConsumerContextImpl implements ConsumerSession { val toStop = instantiatedServices.values(); this.closed = true; for (BrokerService brokerService : toStop) { - //brokerService.closeSession(); + if(brokerService instanceof AbstractBrokerServiceProxy) { + (brokerService as AutoCloseable).close(); + } } broker.consumerSessionClosed(this); } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataBrokerImpl.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataBrokerImpl.xtend new file mode 100644 index 0000000000..8a17c83e6c --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataBrokerImpl.xtend @@ -0,0 +1,63 @@ +package org.opendaylight.controller.sal.dom.broker + +import org.opendaylight.controller.sal.core.api.data.DataProviderService +import org.opendaylight.controller.sal.common.DataStoreIdentifier +import org.opendaylight.controller.sal.core.api.data.DataProviderService.DataRefresher +import org.opendaylight.controller.sal.core.api.data.DataValidator +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier +import org.opendaylight.controller.sal.dom.broker.impl.DataReaderRouter +import org.opendaylight.controller.sal.core.api.data.DataChangeListener +import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler +import org.opendaylight.yangtools.yang.data.api.CompositeNode +import org.opendaylight.controller.md.sal.common.api.data.DataReader + +class DataBrokerImpl implements DataProviderService { + + val readRouter = new DataReaderRouter(); + + override addRefresher(DataStoreIdentifier store, DataRefresher refresher) { + // NOOP + } + + override addValidator(DataStoreIdentifier store, DataValidator validator) { + // NOOP + } + + override beginTransaction() { + // NOOP + } + + override readConfigurationData(InstanceIdentifier path) { + readRouter.readConfigurationData(path) + } + + override readOperationalData(InstanceIdentifier path) { + readRouter.readOperationalData(path) + } + + override registerConfigurationReader(InstanceIdentifier path, DataReader reader) { + readRouter.registerConfigurationReader(path, reader); + } + + override registerOperationalReader(InstanceIdentifier path, DataReader reader) { + readRouter.registerOperationalReader(path, reader); + } + + override removeRefresher(DataStoreIdentifier store, DataRefresher refresher) { + // NOOP + } + + override removeValidator(DataStoreIdentifier store, DataValidator validator) { + // NOOP + } + + override registerDataChangeListener(InstanceIdentifier path, DataChangeListener listener) { + // NOOP + } + + override registerCommitHandler(InstanceIdentifier path, + DataCommitHandler commitHandler) { + // NOOP + } + +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataConsumerServiceImpl.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataConsumerServiceImpl.xtend deleted file mode 100644 index 3bccc4e64b..0000000000 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataConsumerServiceImpl.xtend +++ /dev/null @@ -1,27 +0,0 @@ -package org.opendaylight.controller.sal.dom.broker - -import org.opendaylight.controller.sal.core.api.data.DataBrokerService -import org.opendaylight.controller.sal.common.DataStoreIdentifier -import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode -import org.opendaylight.yangtools.yang.data.api.CompositeNode -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier -import org.opendaylight.controller.sal.core.api.data.DataChangeListener - -class DataConsumerServiceImpl implements DataBrokerService { - - override beginTransaction() { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - } - - override readConfigurationData(InstanceIdentifier path) { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - } - - override readOperationalData(InstanceIdentifier path) { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - } - - override registerDataChangeListener(InstanceIdentifier path, DataChangeListener listener) { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - } -} \ No newline at end of file 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 new file mode 100644 index 0000000000..ba558c51fd --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/SchemaServiceImpl.java @@ -0,0 +1,281 @@ +package org.opendaylight.controller.sal.dom.broker; + +import java.io.IOException; +import java.io.InputStream; +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.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.osgi.framework.Bundle; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleEvent; +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.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.*; + +public class SchemaServiceImpl implements SchemaService, 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(); + + public ListenerRegistry getListeners() { + return listeners; + } + + public void setListeners(ListenerRegistry listeners) { + this.listeners = listeners; + } + + public YangModelParser getParser() { + return parser; + } + + public void setParser(YangModelParser parser) { + this.parser = parser; + } + + public BundleContext getContext() { + return context; + } + + public void setContext(BundleContext context) { + this.context = context; + } + + public void start() { + checkState(parser != null); + checkState(context != null); + if (listeners == null) { + listeners = new ListenerRegistry<>(); + } + + bundleTracker = new BundleTracker(context, BundleEvent.RESOLVED | BundleEvent.UNRESOLVED, scanner); + bundleTracker.open(); + } + + public SchemaContext getGlobalContext() { + return getSchemaContextSnapshot(); + } + + public synchronized SchemaContext getSchemaContextSnapshot() { + Optional yangStoreOpt = cache.getCachedSchemaContext(consistentBundlesToYangURLs); + if (yangStoreOpt.isPresent()) { + return yangStoreOpt.get(); + } + SchemaContext snapshot = createSnapshot(parser, consistentBundlesToYangURLs); + updateCache(snapshot); + return snapshot; + } + + @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; + } + } + + 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); + for (ListenerRegistration listener : listeners) { + try { + listener.getInstance().onGlobalContextUpdated(snapshot); + } catch (Exception e) { + logger.error("Exception occured during invoking listener",e); + } + } + } + + private class BundleScanner implements BundleTrackerCustomizer { + @Override + public Object 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; + + 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); + } + } + } + return bundle; + } + + @Override + public void modifiedBundle(Bundle bundle, BundleEvent event, Object object) { + logger.debug("Modified bundle {} {} {}", bundle, event, object); + } + + /** + * If removing YANG files makes yang store inconsistent, method + * {@link #getYangStoreSnapshot()} will throw exception. There is no + * rollback. + */ + + @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 + } + boolean adding = false; + // notifyListeners(consistentURLsToBeRemoved, adding); + } + } + + 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; + } + + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/AbstractBrokerServiceProxy.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/AbstractBrokerServiceProxy.java new file mode 100644 index 0000000000..7e3d9be59c --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/AbstractBrokerServiceProxy.java @@ -0,0 +1,68 @@ +package org.opendaylight.controller.sal.dom.broker.osgi; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.opendaylight.controller.sal.core.api.BrokerService; +import org.opendaylight.yangtools.concepts.Registration; +import org.osgi.framework.ServiceReference; +import static com.google.common.base.Preconditions.*; + +public abstract class AbstractBrokerServiceProxy implements AutoCloseable, BrokerService { + + private T delegate; + private final ServiceReference reference; + + public AbstractBrokerServiceProxy(ServiceReference ref, T delegate) { + this.delegate = checkNotNull(delegate, "Delegate should not be null."); + this.reference = checkNotNull(ref, "Reference should not be null."); + } + + protected final T getDelegate() { + checkState(delegate != null, "Proxy was closed and unregistered."); + return delegate; + } + + protected final ServiceReference getReference() { + return reference; + } + + private Set> registrations = Collections.synchronizedSet(new HashSet>()); + + protected > R addRegistration(R registration) { + if (registration != null) { + registrations.add(registration); + } + return registration; + } + + protected void closeBeforeUnregistrations() { + // NOOP + } + + protected void closeAfterUnregistrations() { + // NOOP + } + + @Override + public void close() { + if (delegate != null) { + delegate = null; + RuntimeException potentialException = new RuntimeException( + "Uncaught exceptions occured during unregistration"); + boolean hasSuppressed = false; + for (Registration registration : registrations) { + try { + registration.close(); + } catch (Exception e) { + potentialException.addSuppressed(e); + hasSuppressed = true; + } + } + if (hasSuppressed) { + throw potentialException; + } + } + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DataBrokerServiceProxy.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DataBrokerServiceProxy.java new file mode 100644 index 0000000000..3eb7e22bef --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DataBrokerServiceProxy.java @@ -0,0 +1,35 @@ +package org.opendaylight.controller.sal.dom.broker.osgi; + +import org.opendaylight.controller.sal.core.api.data.DataBrokerService; +import org.opendaylight.controller.sal.core.api.data.DataChangeListener; +import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +import org.osgi.framework.ServiceReference; + +public class DataBrokerServiceProxy extends AbstractBrokerServiceProxy implements DataBrokerService { + + public DataBrokerServiceProxy(ServiceReference ref, DataBrokerService delegate) { + super(ref, delegate); + } + + public ListenerRegistration registerDataChangeListener(InstanceIdentifier path, + DataChangeListener listener) { + return addRegistration(getDelegate().registerDataChangeListener(path, listener)); + } + + public CompositeNode readConfigurationData(InstanceIdentifier path) { + return getDelegate().readConfigurationData(path); + } + + public CompositeNode readOperationalData(InstanceIdentifier path) { + return getDelegate().readOperationalData(path); + } + + public DataModificationTransaction beginTransaction() { + return getDelegate().beginTransaction(); + } + + +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DataProviderServiceProxy.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DataProviderServiceProxy.java new file mode 100644 index 0000000000..2fded87981 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DataProviderServiceProxy.java @@ -0,0 +1,77 @@ +package org.opendaylight.controller.sal.dom.broker.osgi; + +import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler; +import org.opendaylight.controller.md.sal.common.api.data.DataReader; +import org.opendaylight.controller.sal.common.DataStoreIdentifier; +import org.opendaylight.controller.sal.core.api.data.DataChangeListener; +import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction; +import org.opendaylight.controller.sal.core.api.data.DataProviderService; +import org.opendaylight.controller.sal.core.api.data.DataValidator; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.concepts.Registration; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +import org.osgi.framework.ServiceReference; + +public class DataProviderServiceProxy extends AbstractBrokerServiceProxy implements + DataProviderService { + + public DataProviderServiceProxy(ServiceReference ref, DataProviderService delegate) { + super(ref, delegate); + } + + public ListenerRegistration registerDataChangeListener(InstanceIdentifier path, + DataChangeListener listener) { + return addRegistration(getDelegate().registerDataChangeListener(path, listener)); + } + + public CompositeNode readConfigurationData(InstanceIdentifier path) { + return getDelegate().readConfigurationData(path); + } + + public CompositeNode readOperationalData(InstanceIdentifier path) { + return getDelegate().readOperationalData(path); + } + + public DataModificationTransaction beginTransaction() { + return getDelegate().beginTransaction(); + } + + @Override + public void addRefresher(DataStoreIdentifier store, DataRefresher refresher) { + getDelegate().addRefresher(store, refresher); + } + + @Override + public void addValidator(DataStoreIdentifier store, DataValidator validator) { + getDelegate().addValidator(store, validator); + } + + @Override + public Registration> registerCommitHandler( + InstanceIdentifier path, DataCommitHandler commitHandler) { + return addRegistration(getDelegate().registerCommitHandler(path, commitHandler)); + } + + @Override + public Registration> registerConfigurationReader( + InstanceIdentifier path, DataReader reader) { + return addRegistration(getDelegate().registerConfigurationReader(path, reader)); + } + + @Override + public Registration> registerOperationalReader( + InstanceIdentifier path, DataReader reader) { + return addRegistration(getDelegate().registerOperationalReader(path, reader)); + } + + @Override + public void removeRefresher(DataStoreIdentifier store, DataRefresher refresher) { + getDelegate().removeRefresher(store, refresher); + } + + @Override + public void removeValidator(DataStoreIdentifier store, DataValidator validator) { + getDelegate().removeValidator(store, validator); + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/NotificationPublishServiceProxy.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/NotificationPublishServiceProxy.java new file mode 100644 index 0000000000..170517bb7a --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/NotificationPublishServiceProxy.java @@ -0,0 +1,29 @@ +package org.opendaylight.controller.sal.dom.broker.osgi; + +import org.opendaylight.controller.sal.core.api.notify.NotificationListener; +import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService; +import org.opendaylight.yangtools.concepts.Registration; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.osgi.framework.ServiceReference; + +public class NotificationPublishServiceProxy extends AbstractBrokerServiceProxy implements NotificationPublishService { + + public NotificationPublishServiceProxy(ServiceReference ref, + NotificationPublishService delegate) { + super(ref, delegate); + } + + public void sendNotification(CompositeNode notification) { + getDelegate().sendNotification(notification); + } + + public Registration addNotificationListener(QName notification, NotificationListener listener) { + return addRegistration(getDelegate().addNotificationListener(notification, listener)); + + } + + public void publish(CompositeNode notification) { + getDelegate().publish(notification); + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/NotificationServiceProxy.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/NotificationServiceProxy.java new file mode 100644 index 0000000000..d685370fea --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/NotificationServiceProxy.java @@ -0,0 +1,20 @@ +package org.opendaylight.controller.sal.dom.broker.osgi; + +import org.opendaylight.controller.sal.core.api.notify.NotificationListener; +import org.opendaylight.controller.sal.core.api.notify.NotificationService; +import org.opendaylight.yangtools.concepts.Registration; +import org.opendaylight.yangtools.yang.common.QName; +import org.osgi.framework.ServiceReference; + +public class NotificationServiceProxy extends AbstractBrokerServiceProxy implements + NotificationService { + + public NotificationServiceProxy(ServiceReference ref, NotificationService delegate) { + super(ref, delegate); + } + + @Override + public Registration addNotificationListener(QName notification, NotificationListener listener) { + return addRegistration(getDelegate().addNotificationListener(notification, listener)); + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/ProxyFactory.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/ProxyFactory.xtend new file mode 100644 index 0000000000..eb738673cb --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/ProxyFactory.xtend @@ -0,0 +1,41 @@ +package org.opendaylight.controller.sal.dom.broker.osgi + +import org.opendaylight.controller.sal.core.api.BrokerService +import org.osgi.framework.ServiceReference +import org.opendaylight.controller.sal.core.api.data.DataBrokerService +import org.opendaylight.controller.sal.core.api.data.DataProviderService +import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService +import org.opendaylight.controller.sal.core.api.notify.NotificationService +import org.opendaylight.controller.sal.core.api.model.SchemaService + +class ProxyFactory { + + static def T createProxy(ServiceReference serviceRef, T service) { + return createProxyImpl(serviceRef, service) as T; + } + + private static def dispatch createProxyImpl(ServiceReference ref, DataBrokerService service) { + new DataBrokerServiceProxy(ref as ServiceReference, service); + } + + private static def dispatch createProxyImpl(ServiceReference ref, DataProviderService service) { + new DataProviderServiceProxy(ref as ServiceReference, service); + } + + private static def dispatch createProxyImpl(ServiceReference ref, NotificationPublishService service) { + new NotificationPublishServiceProxy(ref as ServiceReference, service); + } + + private static def dispatch createProxyImpl(ServiceReference ref, NotificationService service) { + new NotificationServiceProxy(ref as ServiceReference, service); + } + + private static def dispatch createProxyImpl(ServiceReference ref, SchemaService service) { + new SchemaServiceProxy(ref as ServiceReference, service); + } + + private static def dispatch createProxyImpl(ServiceReference reference, BrokerService service) { + throw new IllegalArgumentException("Not supported class"); + } + +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/SchemaServiceProxy.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/SchemaServiceProxy.java new file mode 100644 index 0000000000..8938bf28e9 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/SchemaServiceProxy.java @@ -0,0 +1,45 @@ +package org.opendaylight.controller.sal.dom.broker.osgi; + +import org.opendaylight.controller.sal.core.api.model.SchemaService; +import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.osgi.framework.ServiceReference; + +public class SchemaServiceProxy extends AbstractBrokerServiceProxy implements SchemaService { + + public SchemaServiceProxy(ServiceReference ref, SchemaService delegate) { + super(ref, delegate); + } + + @Override + public void addModule(Module module) { + getDelegate().addModule(module); + } + + @Override + public void removeModule(Module module) { + getDelegate().removeModule(module); + } + + @Override + public SchemaContext getSessionContext() { + return null; + } + + @Override + public SchemaContext getGlobalContext() { + return getDelegate().getGlobalContext(); + } + + @Override + public ListenerRegistration registerSchemaServiceListener(SchemaServiceListener listener) { + ListenerRegistration registration = getDelegate().registerSchemaServiceListener(listener); + addRegistration(registration); + return registration; + } + + + +}