From 6522afe3206c711ed61b4ab651930af2aed28640 Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Fri, 8 Nov 2013 01:29:42 +0100 Subject: [PATCH] Unified implementations of BrokerService Proxies which are provided to Consumers/Producers. - Added AbstractBrokerServiceProxy which is Autocloseable, and specific for each provider. This proxy is convenience wrapper, which keeps track of all object listeners retrieved from proxied service, so when proxy is closed (deregistered) all registrations are also removed. - Added concrete implementations of AbstractBrokerServiceProxy for Data*Services, Notification*Services and SchemaService - Updated implementation of SchemaService to provide notifications when new bundle with model is loaded. Change-Id: I92b67dcb7f376fcf05ea41213aac719c7a3e902e Signed-off-by: Tony Tkacik --- .../sal/core/api/model/SchemaService.java | 3 + .../core/api/model/SchemaServiceListener.java | 12 + opendaylight/md-sal/sal-dom-broker/pom.xml | 168 ++++++----- .../sal/dom/broker/BrokerActivator.java | 28 +- .../sal/dom/broker/BrokerImpl.xtend | 36 +-- .../sal/dom/broker/ConsumerContextImpl.xtend | 31 +- .../sal/dom/broker/DataBrokerImpl.xtend | 63 ++++ .../dom/broker/DataConsumerServiceImpl.xtend | 27 -- .../sal/dom/broker/SchemaServiceImpl.java | 281 ++++++++++++++++++ .../osgi/AbstractBrokerServiceProxy.java | 68 +++++ .../broker/osgi/DataBrokerServiceProxy.java | 35 +++ .../broker/osgi/DataProviderServiceProxy.java | 77 +++++ .../osgi/NotificationPublishServiceProxy.java | 29 ++ .../broker/osgi/NotificationServiceProxy.java | 20 ++ .../sal/dom/broker/osgi/ProxyFactory.xtend | 41 +++ .../dom/broker/osgi/SchemaServiceProxy.java | 45 +++ 16 files changed, 813 insertions(+), 151 deletions(-) create mode 100644 opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/model/SchemaServiceListener.java create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataBrokerImpl.xtend delete mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataConsumerServiceImpl.xtend create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/SchemaServiceImpl.java create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/AbstractBrokerServiceProxy.java create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DataBrokerServiceProxy.java create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DataProviderServiceProxy.java create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/NotificationPublishServiceProxy.java create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/NotificationServiceProxy.java create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/ProxyFactory.xtend create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/SchemaServiceProxy.java 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; + } + + + +} -- 2.36.6