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;
* @return
*/
SchemaContext getGlobalContext();
+
+ ListenerRegistration<SchemaServiceListener> registerSchemaServiceListener(SchemaServiceListener listener);
}
--- /dev/null
+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);
+
+}
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
- <modelVersion>4.0.0</modelVersion>\r
- <parent>\r
- <groupId>org.opendaylight.controller</groupId>\r
- <artifactId>sal-parent</artifactId>\r
- <version>1.0-SNAPSHOT</version>\r
- </parent>\r
- <artifactId>sal-broker-impl</artifactId>\r
- <packaging>bundle</packaging>\r
- <scm>\r
- <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>\r
- <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>\r
- <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>\r
- </scm>\r
-\r
- <dependencies>\r
- <dependency>\r
- <groupId>org.opendaylight.controller</groupId>\r
- <artifactId>sal-core-api</artifactId>\r
- <version>1.0-SNAPSHOT</version>\r
- </dependency>\r
- <dependency>\r
- <groupId>org.opendaylight.controller</groupId>\r
- <artifactId>sal-common-util</artifactId>\r
- <version>1.0-SNAPSHOT</version>\r
- </dependency>\r
- <dependency>\r
- <groupId>org.opendaylight.controller</groupId>\r
- <artifactId>sal-common-impl</artifactId>\r
- <version>1.0-SNAPSHOT</version>\r
- </dependency>\r
- <dependency>\r
- <groupId>org.opendaylight.controller</groupId>\r
- <artifactId>sal-common-impl</artifactId>\r
- <version>1.0-SNAPSHOT</version>\r
- </dependency>\r
- <dependency>\r
- <groupId>org.opendaylight.controller</groupId>\r
- <artifactId>sal-core-spi</artifactId>\r
- <version>1.0-SNAPSHOT</version>\r
- </dependency>\r
- <dependency>\r
- <groupId>org.slf4j</groupId>\r
- <artifactId>slf4j-api</artifactId>\r
- </dependency>\r
- <dependency>\r
- <groupId>com.google.guava</groupId>\r
- <artifactId>guava</artifactId>\r
- </dependency>\r
- <dependency>\r
- <groupId>org.eclipse.xtend</groupId>\r
- <artifactId>org.eclipse.xtend.lib</artifactId>\r
- </dependency>\r
- </dependencies>\r
-\r
- <build>\r
- <plugins>\r
- <plugin>\r
- <groupId>org.apache.felix</groupId>\r
- <artifactId>maven-bundle-plugin</artifactId>\r
- <extensions>true</extensions>\r
- <configuration>\r
- <instructions>\r
- <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>\r
- <Bundle-Activator>org.opendaylight.controller.sal.dom.broker.BrokerActivator</Bundle-Activator>\r
- <Private-Package>\r
- org.opendaylight.controller.sal.dom.broker.*\r
- </Private-Package>\r
- </instructions>\r
- </configuration>\r
- </plugin>\r
- <plugin>\r
- <groupId>org.eclipse.xtend</groupId>\r
- <artifactId>xtend-maven-plugin</artifactId>\r
- </plugin>\r
- </plugins>\r
- </build>\r
-</project>\r
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-parent</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>sal-broker-impl</artifactId>
+ <packaging>bundle</packaging>
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
+ </scm>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-core-api</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-common-util</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-common-impl</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-common-impl</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-core-spi</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.xtend</groupId>
+ <artifactId>org.eclipse.xtend.lib</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-api</artifactId>
+ <version>0.2.2-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-parser-impl</artifactId>
+ <version>0.5.9-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+ <Bundle-Activator>org.opendaylight.controller.sal.dom.broker.BrokerActivator</Bundle-Activator>
+ <Private-Package>
+ org.opendaylight.controller.sal.dom.broker.*
+ </Private-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.eclipse.xtend</groupId>
+ <artifactId>xtend-maven-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+</project>
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;
BrokerImpl broker;
private ServiceRegistration<Broker> brokerReg;
-
+ private ServiceRegistration<SchemaService> schemaReg;
+ private ServiceRegistration<DataBrokerService> dataReg;
+ private ServiceRegistration<DataProviderService> dataProviderReg;
+ private SchemaServiceImpl schemaService;
+ private DataBrokerImpl dataService;
+
@Override
public void start(BundleContext context) throws Exception {
+ Hashtable<String, String> emptyProperties = new Hashtable<String, String>();
broker = new BrokerImpl();
broker.setBundleContext(context);
- brokerReg = context.registerService(Broker.class, broker, new Hashtable<String,String>());
+ 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<String, String>());
+
+ 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();
}
}
private val Set<ConsumerContextImpl> sessions = Collections.synchronizedSet(new HashSet<ConsumerContextImpl>());
private val Set<ProviderContextImpl> providerSessions = Collections.synchronizedSet(
new HashSet<ProviderContextImpl>());
- private val Set<BrokerModule> modules = Collections.synchronizedSet(new HashSet<BrokerModule>());
- private val Map<Class<? extends BrokerService>, BrokerModule> serviceProviders = Collections.
- synchronizedMap(new HashMap<Class<? extends BrokerService>, BrokerModule>());
// Implementation specific
@Property
private var ExecutorService executor = Executors.newFixedThreadPool(5);
@Property
private var BundleContext bundleContext;
-
+
@Property
private var RpcRouter router;
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<? extends BrokerService> serviceType : provServices) {
- log.info(" Registering session service implementation: " + serviceType.getCanonicalName());
- serviceProviders.put(serviceType, module);
- }
- }
-
- public def <T extends BrokerService> T serviceFor(Class<T> 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<RpcResult<CompositeNode>> invokeRpc(QName rpc, CompositeNode input) {
val result = executor.submit([|router.invokeRpc(rpc, input)] as Callable<RpcResult<CompositeNode>>);
return result;
// 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");
}
}
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 {
@Property
private var BrokerImpl broker;
- private val instantiatedServices = Collections.synchronizedMap(
- new HashMap<Class<? extends BrokerService>, BrokerService>());
+ private val ClassToInstanceMap<BrokerService> instantiatedServices = MutableClassToInstanceMap.create();
private boolean closed = false;
private BundleContext context;
}
override <T extends BrokerService> T getService(Class<T> 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;
}
val toStop = instantiatedServices.values();
this.closed = true;
for (BrokerService brokerService : toStop) {
- //brokerService.closeSession();
+ if(brokerService instanceof AbstractBrokerServiceProxy<?>) {
+ (brokerService as AutoCloseable).close();
+ }
}
broker.consumerSessionClosed(this);
}
--- /dev/null
+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<InstanceIdentifier, CompositeNode> reader) {
+ readRouter.registerConfigurationReader(path, reader);
+ }
+
+ override registerOperationalReader(InstanceIdentifier path, DataReader<InstanceIdentifier, CompositeNode> 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<InstanceIdentifier, CompositeNode> commitHandler) {
+ // NOOP
+ }
+
+}
+++ /dev/null
-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
--- /dev/null
+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<SchemaServiceListener> 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<Bundle, URL> inconsistentBundlesToYangURLs = HashMultimap.create();
+ private final Multimap<Bundle, URL> consistentBundlesToYangURLs = HashMultimap.create();
+ private BundleTracker<Object> bundleTracker;
+ private final YangStoreCache cache = new YangStoreCache();
+
+ public ListenerRegistry<SchemaServiceListener> getListeners() {
+ return listeners;
+ }
+
+ public void setListeners(ListenerRegistry<SchemaServiceListener> 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<Object>(context, BundleEvent.RESOLVED | BundleEvent.UNRESOLVED, scanner);
+ bundleTracker.open();
+ }
+
+ public SchemaContext getGlobalContext() {
+ return getSchemaContextSnapshot();
+ }
+
+ public synchronized SchemaContext getSchemaContextSnapshot() {
+ Optional<SchemaContext> 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<SchemaServiceListener> registerSchemaServiceListener(SchemaServiceListener listener) {
+ return listeners.register(listener);
+ }
+
+ @Override
+ public void close() throws Exception {
+ bundleTracker.close();
+ // FIXME: Add listeners.close();
+
+ }
+
+ private synchronized boolean tryToUpdateState(Collection<URL> changedURLs, Multimap<Bundle, URL> 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<InputStream> fromUrlsToInputStreams(Multimap<Bundle, URL> multimap) {
+ return Collections2.transform(multimap.values(), new Function<URL, InputStream>() {
+
+ @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<Bundle, URL> multimap) {
+ List<InputStream> models = new ArrayList<>(fromUrlsToInputStreams(multimap));
+ Set<Module> modules = parser.parseYangModelsFromStreams(models);
+ SchemaContext yangStoreSnapshot = parser.resolveSchemaContext(modules);
+ return yangStoreSnapshot;
+ }
+
+ private void updateCache(SchemaContext snapshot) {
+ cache.cacheYangStore(consistentBundlesToYangURLs, snapshot);
+ for (ListenerRegistration<SchemaServiceListener> listener : listeners) {
+ try {
+ listener.getInstance().onGlobalContextUpdated(snapshot);
+ } catch (Exception e) {
+ logger.error("Exception occured during invoking listener",e);
+ }
+ }
+ }
+
+ private class BundleScanner implements BundleTrackerCustomizer<Object> {
+ @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<URL> enumeration = bundle.findEntries("META-INF/yang", "*.yang", false);
+ if (enumeration != null && enumeration.hasMoreElements()) {
+ synchronized (this) {
+ List<URL> 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<Bundle, URL> 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<URL> consistentURLsToBeRemoved = consistentBundlesToYangURLs.removeAll(bundle);
+
+ if (consistentURLsToBeRemoved.isEmpty()) {
+ return; // no change
+ }
+ boolean adding = false;
+ // notifyListeners(consistentURLsToBeRemoved, adding);
+ }
+ }
+
+ private static final class YangStoreCache {
+
+ Set<URL> cachedUrls;
+ SchemaContext cachedContextSnapshot;
+
+ Optional<SchemaContext> getCachedSchemaContext(Multimap<Bundle, URL> bundlesToYangURLs) {
+ Set<URL> urls = setFromMultimapValues(bundlesToYangURLs);
+ if (cachedUrls != null && cachedUrls.equals(urls)) {
+ Preconditions.checkState(cachedContextSnapshot != null);
+ return Optional.of(cachedContextSnapshot);
+ }
+ return Optional.absent();
+ }
+
+ private static Set<URL> setFromMultimapValues(Multimap<Bundle, URL> bundlesToYangURLs) {
+ Set<URL> urls = Sets.newHashSet(bundlesToYangURLs.values());
+ Preconditions.checkState(bundlesToYangURLs.size() == urls.size());
+ return urls;
+ }
+
+ void cacheYangStore(Multimap<Bundle, URL> urls, SchemaContext ctx) {
+ this.cachedUrls = setFromMultimapValues(urls);
+ this.cachedContextSnapshot = ctx;
+ }
+
+ }
+}
--- /dev/null
+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<T extends BrokerService> implements AutoCloseable, BrokerService {
+
+ private T delegate;
+ private final ServiceReference<T> reference;
+
+ public AbstractBrokerServiceProxy(ServiceReference<T> 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<T> getReference() {
+ return reference;
+ }
+
+ private Set<Registration<?>> registrations = Collections.synchronizedSet(new HashSet<Registration<?>>());
+
+ protected <R extends Registration<?>> 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;
+ }
+ }
+ }
+}
--- /dev/null
+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<DataBrokerService> implements DataBrokerService {
+
+ public DataBrokerServiceProxy(ServiceReference<DataBrokerService> ref, DataBrokerService delegate) {
+ super(ref, delegate);
+ }
+
+ public ListenerRegistration<DataChangeListener> 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();
+ }
+
+
+}
--- /dev/null
+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<DataProviderService> implements
+ DataProviderService {
+
+ public DataProviderServiceProxy(ServiceReference<DataProviderService> ref, DataProviderService delegate) {
+ super(ref, delegate);
+ }
+
+ public ListenerRegistration<DataChangeListener> 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<DataCommitHandler<InstanceIdentifier, CompositeNode>> registerCommitHandler(
+ InstanceIdentifier path, DataCommitHandler<InstanceIdentifier, CompositeNode> commitHandler) {
+ return addRegistration(getDelegate().registerCommitHandler(path, commitHandler));
+ }
+
+ @Override
+ public Registration<DataReader<InstanceIdentifier, CompositeNode>> registerConfigurationReader(
+ InstanceIdentifier path, DataReader<InstanceIdentifier, CompositeNode> reader) {
+ return addRegistration(getDelegate().registerConfigurationReader(path, reader));
+ }
+
+ @Override
+ public Registration<DataReader<InstanceIdentifier, CompositeNode>> registerOperationalReader(
+ InstanceIdentifier path, DataReader<InstanceIdentifier, CompositeNode> 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);
+ }
+}
--- /dev/null
+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<NotificationPublishService> implements NotificationPublishService {
+
+ public NotificationPublishServiceProxy(ServiceReference<NotificationPublishService> ref,
+ NotificationPublishService delegate) {
+ super(ref, delegate);
+ }
+
+ public void sendNotification(CompositeNode notification) {
+ getDelegate().sendNotification(notification);
+ }
+
+ public Registration<NotificationListener> addNotificationListener(QName notification, NotificationListener listener) {
+ return addRegistration(getDelegate().addNotificationListener(notification, listener));
+
+ }
+
+ public void publish(CompositeNode notification) {
+ getDelegate().publish(notification);
+ }
+}
--- /dev/null
+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<NotificationService> implements
+ NotificationService {
+
+ public NotificationServiceProxy(ServiceReference<NotificationService> ref, NotificationService delegate) {
+ super(ref, delegate);
+ }
+
+ @Override
+ public Registration<NotificationListener> addNotificationListener(QName notification, NotificationListener listener) {
+ return addRegistration(getDelegate().addNotificationListener(notification, listener));
+ }
+}
--- /dev/null
+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 extends BrokerService> T createProxy(ServiceReference<T> serviceRef, T service) {
+ return createProxyImpl(serviceRef, service) as T;
+ }
+
+ private static def dispatch createProxyImpl(ServiceReference<?> ref, DataBrokerService service) {
+ new DataBrokerServiceProxy(ref as ServiceReference<DataBrokerService>, service);
+ }
+
+ private static def dispatch createProxyImpl(ServiceReference<?> ref, DataProviderService service) {
+ new DataProviderServiceProxy(ref as ServiceReference<DataProviderService>, service);
+ }
+
+ private static def dispatch createProxyImpl(ServiceReference<?> ref, NotificationPublishService service) {
+ new NotificationPublishServiceProxy(ref as ServiceReference<NotificationPublishService>, service);
+ }
+
+ private static def dispatch createProxyImpl(ServiceReference<?> ref, NotificationService service) {
+ new NotificationServiceProxy(ref as ServiceReference<NotificationService>, service);
+ }
+
+ private static def dispatch createProxyImpl(ServiceReference<?> ref, SchemaService service) {
+ new SchemaServiceProxy(ref as ServiceReference<SchemaService>, service);
+ }
+
+ private static def dispatch createProxyImpl(ServiceReference<?> reference, BrokerService service) {
+ throw new IllegalArgumentException("Not supported class");
+ }
+
+}
--- /dev/null
+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<SchemaService> implements SchemaService {
+
+ public SchemaServiceProxy(ServiceReference<SchemaService> 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<SchemaServiceListener> registerSchemaServiceListener(SchemaServiceListener listener) {
+ ListenerRegistration<SchemaServiceListener> registration = getDelegate().registerSchemaServiceListener(listener);
+ addRegistration(registration);
+ return registration;
+ }
+
+
+
+}