<artifactId>mdsal-dom-broker</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-dom-schema-service-osgi</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.mdsal</groupId>
<artifactId>mdsal-dom-inmemory-datastore</artifactId>
<classifier>features</classifier>
<type>xml</type>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>odl-mdsal-dom-schema-service-osgi</artifactId>
+ <version>${project.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ </dependency>
<!-- BINDING2 -->
<dependency>
<classifier>features</classifier>
<type>xml</type>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>odl-mdsal-dom-schema-service-osgi</artifactId>
+ <classifier>features</classifier>
+ <type>xml</type>
+ </dependency>
<!-- EOS -->
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>mdsal-dom-broker</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>odl-mdsal-dom-schema-service-osgi</artifactId>
+ <type>xml</type>
+ <classifier>features</classifier>
+ </dependency>
</dependencies>
<!--
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright © 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+<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.odlparent</groupId>
+ <artifactId>single-feature-parent</artifactId>
+ <version>2.0.5</version>
+ <relativePath/>
+ </parent>
+
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>odl-mdsal-dom-schema-service-osgi</artifactId>
+ <version>2.4.0-SNAPSHOT</version>
+ <packaging>feature</packaging>
+
+ <name>OpenDaylight :: MD-SAL :: DOM Schema Service OSGi</name>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-artifacts</artifactId>
+ <version>${project.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mdsal-dom-schema-service-osgi</artifactId>
+ </dependency>
+ </dependencies>
+
+ <!--
+ Maven Site Configuration
+
+ The following configuration is necessary for maven-site-plugin to
+ correctly identify the correct deployment path for OpenDaylight Maven
+ sites.
+ -->
+ <url>${odl.site.url}/${project.groupId}/${stream}/${project.artifactId}/</url>
+
+ <distributionManagement>
+ <site>
+ <id>opendaylight-site</id>
+ <url>${nexus.site.url}/${project.artifactId}/</url>
+ </site>
+ </distributionManagement>
+
+</project>
</site>
</distributionManagement>
-</project>
\ No newline at end of file
+</project>
<module>odl-mdsal-dom</module>
<module>odl-mdsal-dom-api</module>
<module>odl-mdsal-dom-broker</module>
+ <module>odl-mdsal-dom-schema-service-osgi</module>
<!-- EOS -->
<module>odl-mdsal-eos-binding</module>
</dependencyManagement>
<dependencies>
- <dependency>
- <groupId>org.osgi</groupId>
- <artifactId>org.osgi.core</artifactId>
- </dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
</dependency>
+
<dependency>
<groupId>org.opendaylight.mdsal</groupId>
<artifactId>mdsal-dom-api</artifactId>
<groupId>org.opendaylight.mdsal</groupId>
<artifactId>mdsal-dom-inmemory-datastore</artifactId>
</dependency>
+
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>util</artifactId>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-parser-impl</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-model-api</artifactId>
+ </dependency>
<dependency>
<groupId>junit</groupId>
<build>
<plugins>
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <extensions>true</extensions>
- <configuration>
- <instructions>
- <Bundle-Activator>org.opendaylight.mdsal.dom.broker.osgi.SchemaServiceActivator</Bundle-Activator>
- </instructions>
- </configuration>
- </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.mdsal.dom.broker.osgi;
-
-import java.util.Hashtable;
-import org.opendaylight.mdsal.dom.api.DOMSchemaService;
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
-
-public class SchemaServiceActivator implements BundleActivator {
- private ServiceRegistration<DOMSchemaService> schemaServiceReg;
- private OsgiBundleScanningSchemaService schemaService;
-
- @Override
- public void start(final BundleContext context) {
- schemaService = OsgiBundleScanningSchemaService.createInstance(context);
- schemaServiceReg = context.registerService(DOMSchemaService.class,
- schemaService, new Hashtable<>());
- }
-
- @Override
- public void stop(final BundleContext context) {
- schemaServiceReg.unregister();
- schemaService.close();
- }
-}
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.dom.broker.schema;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import com.google.common.util.concurrent.CheckedFuture;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.concurrent.GuardedBy;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.api.DOMSchemaServiceExtension;
+import org.opendaylight.mdsal.dom.api.DOMYangTextSourceProvider;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.util.ListenerRegistry;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
+import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+import org.opendaylight.yangtools.yang.parser.repo.YangTextSchemaContextResolver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ScanningSchemaServiceProvider
+ implements DOMSchemaService, SchemaContextProvider, DOMYangTextSourceProvider, AutoCloseable {
+ private static final Logger LOG = LoggerFactory.getLogger(ScanningSchemaServiceProvider.class);
+
+ @GuardedBy("lock")
+ private final ListenerRegistry<SchemaContextListener> listeners = new ListenerRegistry<>();
+ private final Object lock = new Object();
+ private final YangTextSchemaContextResolver contextResolver = YangTextSchemaContextResolver.create("global-bundle");
+
+ public void tryToUpdateSchemaContext() {
+ synchronized (lock) {
+ final Optional<SchemaContext> schema = contextResolver.getSchemaContext();
+ if (schema.isPresent()) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Got new SchemaContext: # of modules {}", schema.get().getAllModuleIdentifiers().size());
+ }
+ notifyListeners(schema.get());
+ }
+ }
+ }
+
+ @VisibleForTesting
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ public void notifyListeners(final SchemaContext schemaContext) {
+ synchronized (lock) {
+ for (final ListenerRegistration<SchemaContextListener> registration : listeners) {
+ try {
+ registration.getInstance().onGlobalContextUpdated(schemaContext);
+ } catch (final Exception e) {
+ LOG.error("Exception occured during invoking listener", e);
+ }
+ }
+ }
+ }
+
+ public List<Registration> registerAvailableYangs(final List<URL> yangs) {
+ final List<Registration> sourceRegistrator = new ArrayList<>();
+ for (final URL url : yangs) {
+ try {
+ sourceRegistrator.add(contextResolver.registerSource(url));
+ } catch (SchemaSourceException | IOException | YangSyntaxErrorException e) {
+ LOG.warn("Failed to register {}, ignoring it", url, e);
+ }
+ }
+ return sourceRegistrator;
+ }
+
+ public void removeListener(final SchemaContextListener schemaContextListener) {
+ synchronized (lock) {
+ for (final ListenerRegistration<SchemaContextListener> listenerRegistration : listeners.getListeners()) {
+ if (listenerRegistration.getInstance().equals(schemaContextListener)) {
+ listenerRegistration.close();
+ break;
+ }
+ }
+ }
+ }
+
+ public boolean hasListeners() {
+ boolean hasListeners;
+ synchronized (lock) {
+ if (Iterables.size(listeners.getListeners()) > 0) {
+ hasListeners = true;
+ } else {
+ hasListeners = false;
+ }
+ }
+ return hasListeners;
+ }
+
+ @Override
+ public SchemaContext getSessionContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SchemaContext getGlobalContext() {
+ return contextResolver.getSchemaContext().orNull();
+ }
+
+ @Override
+ public ListenerRegistration<SchemaContextListener>
+ registerSchemaContextListener(final SchemaContextListener listener) {
+ synchronized (lock) {
+ final Optional<SchemaContext> potentialCtx = contextResolver.getSchemaContext();
+ if (potentialCtx.isPresent()) {
+ listener.onGlobalContextUpdated(potentialCtx.get());
+ }
+ return listeners.register(listener);
+ }
+ }
+
+ @Override
+ public SchemaContext getSchemaContext() {
+ return getGlobalContext();
+ }
+
+ @Override
+ public CheckedFuture<? extends YangTextSchemaSource, SchemaSourceException>
+ getSource(final SourceIdentifier sourceIdentifier) {
+ return contextResolver.getSource(sourceIdentifier);
+ }
+
+ @Override
+ public Map<Class<? extends DOMSchemaServiceExtension>, DOMSchemaServiceExtension> getSupportedExtensions() {
+ return ImmutableMap.of(DOMYangTextSourceProvider.class, this);
+ }
+
+ @Override
+ public void close() {
+ synchronized (lock) {
+ for (final ListenerRegistration<SchemaContextListener> registration : listeners) {
+ registration.close();
+ }
+ }
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.mdsal.dom.broker.osgi;
-
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.CALLS_REAL_METHODS;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-import java.lang.reflect.Field;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Filter;
-import org.osgi.framework.ServiceReference;
-import org.osgi.framework.ServiceRegistration;
-
-public class SchemaServiceActivatorTest {
-
- @Test
- public void basicTest() throws Exception {
- final BundleContext bundleContext = mock(BundleContext.class);
- doReturn(mock(Filter.class)).when(bundleContext).createFilter(any());
- doNothing().when(bundleContext).addBundleListener(any());
- doReturn(new Bundle[] {}).when(bundleContext).getBundles();
- doNothing().when(bundleContext).addServiceListener(any(), any());
- doReturn(new ServiceReference<?>[] {}).when(bundleContext).getServiceReferences(anyString(), any());
- doReturn(mock(ServiceRegistration.class)).when(bundleContext).registerService(any(Class.class), any(), any());
- doNothing().when(bundleContext).removeBundleListener(any());
- doNothing().when(bundleContext).removeServiceListener(any());
- final SchemaServiceActivator schemaServiceActivator = new SchemaServiceActivator();
- schemaServiceActivator.start(bundleContext);
-
- final ServiceRegistration<?> registration = mock(ServiceRegistration.class);
- final OsgiBundleScanningSchemaService osgiBundle =
- mock(OsgiBundleScanningSchemaService.class, CALLS_REAL_METHODS);
-
- final Field schemaServiceRegField = SchemaServiceActivator.class.getDeclaredField("schemaServiceReg");
- schemaServiceRegField.setAccessible(true);
- schemaServiceRegField.set(schemaServiceActivator, registration);
-
- final Field schemaServiceField = SchemaServiceActivator.class.getDeclaredField("schemaService");
- schemaServiceField.setAccessible(true);
- schemaServiceField.set(schemaServiceActivator, osgiBundle);
-
- doNothing().when(registration).unregister();
- doNothing().when(osgiBundle).close();
-
- schemaServiceActivator.stop(bundleContext);
- verify(registration).unregister();
- verify(osgiBundle).close();
- }
-
- @SuppressWarnings("checkstyle:IllegalCatch")
- @After
- @Before
- public void destroyInstance() throws Exception {
- try {
- OsgiBundleScanningSchemaService.getInstance();
- OsgiBundleScanningSchemaService.destroyInstance();
- } catch (Exception e) {
- assertTrue(e instanceof IllegalStateException);
- }
- }
-}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.dom.broker.schema;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.util.concurrent.CheckedFuture;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.internal.util.io.IOUtil;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
+import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+
+public class ScanningSchemaServiceProviderTest {
+
+ private ArrayList<URL> yangs;
+ private ScanningSchemaServiceProvider schemaService;
+
+ @Before
+ public void setup() {
+ yangs = new ArrayList<>();
+ addYang("/odl-datastore-test.yang");
+
+ schemaService = new ScanningSchemaServiceProvider();
+ assertNotNull(schemaService);
+ addYangs(schemaService);
+ }
+
+ @After
+ public void close() {
+ schemaService.close();
+ }
+
+ private void addYang(final String yang) {
+ yangs.add(ScanningSchemaServiceProvider.class.getResource(yang));
+ }
+
+ @Test
+ public void initJarScanningSchemaServiceTest() throws Exception {
+ assertNotNull(schemaService.getGlobalContext());
+ assertNotNull(schemaService.getSchemaContext());
+ assertEquals(schemaService.getGlobalContext(), schemaService.getSchemaContext());
+ }
+
+ @Test
+ public void listenersTests() {
+ assertFalse(schemaService.hasListeners());
+
+ final SchemaContextHolder actualSchemaCtx = new SchemaContextHolder();
+ final SchemaContextListener listener = prepareSchemaCtxListener(actualSchemaCtx);
+ final ListenerRegistration<SchemaContextListener> registerSchemaContextListener =
+ schemaService.registerSchemaContextListener(listener);
+ assertEquals(registerSchemaContextListener.getInstance(), listener);
+ assertEquals(schemaService.getSchemaContext(), actualSchemaCtx.getSchemaContext());
+ }
+
+ @Test
+ public void notifyListenersTest() {
+ final SchemaContext baseSchemaCtx = schemaService.getGlobalContext();
+ assertNotNull(baseSchemaCtx);
+ assertTrue(baseSchemaCtx.getModules().size() == 1);
+
+ final SchemaContextHolder actualSchemaCtx = new SchemaContextHolder();
+
+ final SchemaContextListener schemaCtxListener = prepareSchemaCtxListener(actualSchemaCtx);
+ final ListenerRegistration<SchemaContextListener> registerSchemaContextListener =
+ schemaService.registerSchemaContextListener(schemaCtxListener);
+ assertEquals(registerSchemaContextListener.getInstance(), schemaCtxListener);
+ assertNotNull(actualSchemaCtx.getSchemaContext());
+ assertEquals(baseSchemaCtx, actualSchemaCtx.getSchemaContext());
+
+ addYang("/empty-test1.yang");
+ addYangs(schemaService);
+
+ final SchemaContext nextSchemaCtx = schemaService.getGlobalContext();
+ assertNotNull(nextSchemaCtx);
+ assertTrue(nextSchemaCtx.getModules().size() == 2);
+
+ assertNotEquals(baseSchemaCtx, nextSchemaCtx);
+
+ schemaService.notifyListeners(nextSchemaCtx);
+ assertEquals(nextSchemaCtx, actualSchemaCtx.getSchemaContext());
+
+ addYang("/empty-test2.yang");
+ addYangs(schemaService);
+
+ final SchemaContext unregistredListenerSchemaCtx = schemaService.getGlobalContext();
+ assertNotNull(unregistredListenerSchemaCtx);
+ assertTrue(unregistredListenerSchemaCtx.getModules().size() == 3);
+
+ assertNotEquals(baseSchemaCtx, unregistredListenerSchemaCtx);
+ assertNotEquals(nextSchemaCtx, unregistredListenerSchemaCtx);
+
+ schemaService.removeListener(schemaCtxListener);
+ schemaService.notifyListeners(unregistredListenerSchemaCtx);
+
+ assertNotEquals(unregistredListenerSchemaCtx, actualSchemaCtx.getSchemaContext());
+ assertEquals(nextSchemaCtx, actualSchemaCtx.getSchemaContext());
+
+ schemaService.registerSchemaContextListener(schemaCtxListener);
+ assertEquals(unregistredListenerSchemaCtx, actualSchemaCtx.getSchemaContext());
+ }
+
+ @Test
+ public void tryToUpdateSchemaCtxTest() {
+ final SchemaContext baseSchemaContext = schemaService.getSchemaContext();
+ assertNotNull(baseSchemaContext);
+ assertTrue(baseSchemaContext.getModules().size() == 1);
+
+ final SchemaContextHolder actualSchemaCtx = new SchemaContextHolder();
+ final SchemaContextListener schemaCtxListener = prepareSchemaCtxListener(actualSchemaCtx);
+
+ schemaService.registerSchemaContextListener(schemaCtxListener);
+
+ assertEquals(baseSchemaContext, actualSchemaCtx.getSchemaContext());
+
+ addYang("/empty-test1.yang");
+ addYangs(schemaService);
+
+ final SchemaContext nextSchemaContext = schemaService.getSchemaContext();
+ assertNotNull(baseSchemaContext);
+ assertTrue(baseSchemaContext.getModules().size() == 1);
+
+ assertNotEquals(baseSchemaContext, nextSchemaContext);
+
+ schemaService.tryToUpdateSchemaContext();
+ assertEquals(nextSchemaContext, actualSchemaCtx.getSchemaContext());
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void getSourceTest() throws Exception {
+ final SourceIdentifier sourceIdentifier = RevisionSourceIdentifier.create("odl-datastore-test", "2014-03-13");
+ final CheckedFuture<? extends YangTextSchemaSource, SchemaSourceException> source =
+ schemaService.getSource(sourceIdentifier);
+ final YangTextSchemaSource yangTextSchemaSource = source.checkedGet();
+ final Collection<String> lines = IOUtil.readLines(yangTextSchemaSource.openStream());
+ assertEquals("module odl-datastore-test {", lines.iterator().next());
+ }
+
+ @Test
+ public void getSupportedExtensionsTest() {
+ assertEquals(schemaService.getSupportedExtensions().values().iterator().next(), schemaService);
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void getSessionContextTest() {
+ schemaService.getSessionContext();
+ }
+
+ private void addYangs(final ScanningSchemaServiceProvider schemaService) {
+ final List<Registration> registerAvailableYangs = schemaService.registerAvailableYangs(yangs);
+ assertTrue(!registerAvailableYangs.isEmpty());
+ }
+
+ private SchemaContextListener prepareSchemaCtxListener(final SchemaContextHolder actualSchemaCtx) {
+ return new SchemaContextListener() {
+
+ @Override
+ public void onGlobalContextUpdated(final SchemaContext context) {
+ actualSchemaCtx.setSchemaContext(context);
+ }
+ };
+ }
+
+ private class SchemaContextHolder {
+
+ private SchemaContext schemaCtx;
+
+ public void setSchemaContext(final SchemaContext ctx) {
+ schemaCtx = ctx;
+ }
+
+ public SchemaContext getSchemaContext() {
+ return schemaCtx;
+ }
+ }
+}
--- /dev/null
+module empty-test1 {
+ yang-version 1;
+ namespace "em:tst:1";
+ prefix "empty-test-1";
+
+ revision "2017-09-13" {
+ description "Initial revision.";
+ }
+}
--- /dev/null
+module empty-test2 {
+ yang-version 1;
+ namespace "em:tst:2";
+ prefix "empty-test-2";
+
+ revision "2017-09-13" {
+ description "Initial revision.";
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+<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.odlparent</groupId>
+ <artifactId>bundle-parent</artifactId>
+ <version>2.0.5</version>
+ <relativePath/>
+ </parent>
+
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-dom-schema-service-osgi</artifactId>
+ <version>2.4.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-artifacts</artifactId>
+ <version>2.4.0-SNAPSHOT</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yangtools-artifacts</artifactId>
+ <version>1.2.0-SNAPSHOT</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-dom-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-dom-broker</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-parser-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-test-util</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>mockito-configuration</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>osgiBundleScanningSchema</Bundle-Name>
+ <Import-Package>
+ *,
+ org.opendaylight.mdsal.dom.api
+ </Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <scm>
+ <connection>scm:git:http://git.opendaylight.org/gerrit/controller.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+ <tag>HEAD</tag>
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL:Architecture:Clustering</url>
+ </scm>
+
+
+ <!--
+ Maven Site Configuration
+
+ The following configuration is necessary for maven-site-plugin to
+ correctly identify the correct deployment path for OpenDaylight Maven
+ sites.
+ -->
+ <url>${odl.site.url}/${project.groupId}/${stream}/${project.artifactId}/</url>
+
+ <distributionManagement>
+ <site>
+ <id>opendaylight-site</id>
+ <url>${nexus.site.url}/${project.artifactId}/</url>
+ </site>
+ </distributionManagement>
+
+</project>
/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-package org.opendaylight.mdsal.dom.broker.osgi;
+package org.opendaylight.mdsal.dom.schema.service.osgi;
import static com.google.common.base.Preconditions.checkState;
-
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
-import com.google.common.util.concurrent.CheckedFuture;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
-import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.GuardedBy;
-import org.opendaylight.mdsal.dom.api.DOMSchemaService;
-import org.opendaylight.mdsal.dom.api.DOMSchemaServiceExtension;
-import org.opendaylight.mdsal.dom.api.DOMYangTextSourceProvider;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.mdsal.dom.broker.schema.ScanningSchemaServiceProvider;
import org.opendaylight.yangtools.concepts.Registration;
-import org.opendaylight.yangtools.util.ListenerRegistry;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
-import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
-import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
-import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
-import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
-import org.opendaylight.yangtools.yang.parser.repo.YangTextSchemaContextResolver;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public class OsgiBundleScanningSchemaService implements SchemaContextProvider, DOMSchemaService,
- ServiceTrackerCustomizer<SchemaContextListener, SchemaContextListener>, DOMYangTextSourceProvider,
- AutoCloseable {
- private static final Logger LOG = LoggerFactory.getLogger(OsgiBundleScanningSchemaService.class);
+public class OsgiBundleScanningSchemaService extends ScanningSchemaServiceProvider
+ implements ServiceTrackerCustomizer<SchemaContextListener, SchemaContextListener> {
+ private static final Logger LOG = LoggerFactory.getLogger(OsgiBundleScanningSchemaService.class);
private static final AtomicReference<OsgiBundleScanningSchemaService> GLOBAL_INSTANCE = new AtomicReference<>();
-
private static final long FRAMEWORK_BUNDLE_ID = 0;
- @GuardedBy("lock")
- private final ListenerRegistry<SchemaContextListener> listeners = new ListenerRegistry<>();
- private final YangTextSchemaContextResolver contextResolver = YangTextSchemaContextResolver.create("global-bundle");
private final BundleScanner scanner = new BundleScanner();
- private final Object lock = new Object();
private final BundleContext context;
- private ServiceTracker<SchemaContextListener, SchemaContextListener> listenerTracker;
+ @GuardedBy("lock")
private BundleTracker<Iterable<Registration>> bundleTracker;
+ private final Object lock = new Object();
+
+ private ServiceTracker<SchemaContextListener, SchemaContextListener> listenerTracker;
private boolean starting = true;
private volatile boolean stopping;
}
public static @Nonnull OsgiBundleScanningSchemaService createInstance(final BundleContext ctx) {
- OsgiBundleScanningSchemaService instance = new OsgiBundleScanningSchemaService(ctx);
+ final OsgiBundleScanningSchemaService instance = new OsgiBundleScanningSchemaService(ctx);
Preconditions.checkState(GLOBAL_INSTANCE.compareAndSet(null, instance));
instance.start();
return instance;
}
- public static OsgiBundleScanningSchemaService getInstance() {
- OsgiBundleScanningSchemaService instance = GLOBAL_INSTANCE.get();
- Preconditions.checkState(instance != null, "Global Instance was not instantiated");
- return instance;
- }
-
- @VisibleForTesting
- public static void destroyInstance() {
- OsgiBundleScanningSchemaService instance = GLOBAL_INSTANCE.getAndSet(null);
- if (instance != null) {
- instance.close();
- }
- }
-
- public BundleContext getContext() {
- return context;
- }
-
private void start() {
checkState(context != null);
LOG.debug("start() starting");
listenerTracker = new ServiceTracker<>(context, SchemaContextListener.class, this);
- bundleTracker = new BundleTracker<>(context, Bundle.RESOLVED | Bundle.STARTING
- | Bundle.STOPPING | Bundle.ACTIVE, scanner);
+ bundleTracker = new BundleTracker<>(context,
+ Bundle.RESOLVED | Bundle.STARTING | Bundle.STOPPING | Bundle.ACTIVE, scanner);
synchronized (lock) {
bundleTracker.open();
LOG.debug("BundleTracker.open() complete");
- if (Iterables.size(listeners.getListeners()) > 0) {
+ if (!hasListeners()) {
tryToUpdateSchemaContext();
}
}
LOG.debug("start() complete");
}
- @Override
- public SchemaContext getSchemaContext() {
- return getGlobalContext();
- }
-
- @Override
- public SchemaContext getGlobalContext() {
- return contextResolver.getSchemaContext().orNull();
+ public static OsgiBundleScanningSchemaService getInstance() {
+ final OsgiBundleScanningSchemaService instance = GLOBAL_INSTANCE.get();
+ Preconditions.checkState(instance != null, "Global Instance was not instantiated");
+ return instance;
}
- @Override
- public SchemaContext getSessionContext() {
- throw new UnsupportedOperationException();
- }
+ @VisibleForTesting
+ public static void destroyInstance() throws Exception {
+ final OsgiBundleScanningSchemaService instance = GLOBAL_INSTANCE.getAndSet(null);
+ if (instance != null) {
- @Override
- public ListenerRegistration<SchemaContextListener> registerSchemaContextListener(
- final SchemaContextListener listener) {
- synchronized (lock) {
- final Optional<SchemaContext> potentialCtx = contextResolver.getSchemaContext();
- if (potentialCtx.isPresent()) {
- listener.onGlobalContextUpdated(potentialCtx.get());
- }
- return listeners.register(listener);
+ instance.closeInstance();
}
}
- @Override
- public void close() {
- synchronized (lock) {
- stopping = true;
- if (bundleTracker != null) {
- bundleTracker.close();
- bundleTracker = null;
- }
- if (listenerTracker != null) {
- listenerTracker.close();
- listenerTracker = null;
- }
-
- for (final ListenerRegistration<SchemaContextListener> l : listeners.getListeners()) {
- l.close();
- }
+ private void closeInstance() {
+ stopping = true;
+ if (bundleTracker != null) {
+ bundleTracker.close();
+ bundleTracker = null;
+ }
+ if (listenerTracker != null) {
+ listenerTracker.close();
+ listenerTracker = null;
}
+ close();
}
- @SuppressWarnings("checkstyle:IllegalCatch")
- @VisibleForTesting
- @GuardedBy("lock")
- void notifyListeners(final SchemaContext snapshot) {
- final Object[] services = listenerTracker.getServices();
- for (final ListenerRegistration<SchemaContextListener> listener : listeners) {
- try {
- listener.getInstance().onGlobalContextUpdated(snapshot);
- } catch (final Exception e) {
- LOG.error("Exception occured during invoking listener", e);
- }
- }
- if (services != null) {
- for (final Object rawListener : services) {
- final SchemaContextListener listener = (SchemaContextListener) rawListener;
- try {
- listener.onGlobalContextUpdated(snapshot);
- } catch (final Exception e) {
- LOG.error("Exception occured during invoking listener {}", listener, e);
- }
- }
- }
+ public BundleContext getContext() {
+ return context;
}
@SuppressWarnings("checkstyle:IllegalCatch")
return Collections.emptyList();
}
- final List<Registration> urls = new ArrayList<>();
+ final List<URL> urls = new ArrayList<>();
while (enumeration.hasMoreElements()) {
final URL u = enumeration.nextElement();
try {
- urls.add(contextResolver.registerSource(u));
+ urls.add(u);
LOG.debug("Registered {}", u);
} catch (final Exception e) {
LOG.warn("Failed to register {}, ignoring it", e);
}
}
- if (!urls.isEmpty()) {
+ final List<Registration> registrations = registerAvailableYangs(urls);
+ if (!registrations.isEmpty()) {
LOG.debug("Loaded {} new URLs from bundle {}, attempting to rebuild schema context",
- urls.size(), bundle.getSymbolicName());
- tryToUpdateSchemaContext();
+ registrations.size(), bundle.getSymbolicName());
+ if (!starting && !stopping) {
+ tryToUpdateSchemaContext();
+ }
}
-
- return ImmutableList.copyOf(urls);
+ return ImmutableList.copyOf(registrations);
}
@Override
}
/**
- * If removing YANG files makes yang store inconsistent, method
- * {@link #getYangStoreSnapshot()} will throw exception. There is no
- * rollback.
+ * If removing YANG files makes yang store inconsistent, method {@link #getYangStoreSnapshot()} will
+ * throw exception. There is no rollback.
*/
@SuppressWarnings("checkstyle:IllegalCatch")
@Override
final int numUrls = Iterables.size(urls);
if (numUrls > 0) {
if (LOG.isDebugEnabled()) {
- LOG.debug("removedBundle: {}, state: {}, # urls: {}", bundle.getSymbolicName(),
- bundle.getState(), numUrls);
+ LOG.debug("removedBundle: {}, state: {}, # urls: {}", bundle.getSymbolicName(), bundle.getState(),
+ numUrls);
+ }
+ if (!starting && !stopping) {
+ tryToUpdateSchemaContext();
}
-
- tryToUpdateSchemaContext();
}
}
}
@Override
public SchemaContextListener addingService(final ServiceReference<SchemaContextListener> reference) {
-
final SchemaContextListener listener = context.getService(reference);
- final SchemaContext ctxContext = getGlobalContext();
- if (getContext() != null && ctxContext != null) {
- listener.onGlobalContextUpdated(ctxContext);
- }
+ registerSchemaContextListener(listener);
return listener;
}
- public void tryToUpdateSchemaContext() {
- if (starting || stopping) {
- return;
- }
-
- synchronized (lock) {
- final Optional<SchemaContext> schema = contextResolver.getSchemaContext();
- if (schema.isPresent()) {
- if (LOG.isDebugEnabled()) {
- LOG.debug("Got new SchemaContext: # of modules {}", schema.get().getAllModuleIdentifiers().size());
- }
-
- notifyListeners(schema.get());
- }
- }
- }
-
@Override
public void modifiedService(final ServiceReference<SchemaContextListener> reference,
final SchemaContextListener service) {
public void removedService(final ServiceReference<SchemaContextListener> reference,
final SchemaContextListener service) {
context.ungetService(reference);
- }
-
- @Override
- public Map<Class<? extends DOMSchemaServiceExtension>, DOMSchemaServiceExtension> getSupportedExtensions() {
- return ImmutableMap.of(DOMYangTextSourceProvider.class, this);
- }
-
- @Override
- public CheckedFuture<? extends YangTextSchemaSource, SchemaSourceException> getSource(
- final SourceIdentifier sourceIdentifier) {
- return contextResolver.getSource(sourceIdentifier);
+ removeListener(service);
}
}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+ xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0"
+ xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0">
+
+ <bean id="osgiBundleScanningSchema" class="org.opendaylight.mdsal.dom.schema.service.osgi.OsgiBundleScanningSchemaService" factory-method="createInstance" destroy-method="close">
+ <argument ref="blueprintBundleContext" />
+ </bean>
+
+ <service ref="osgiBundleScanningSchema" interface="org.opendaylight.mdsal.dom.api.DOMSchemaService" odl:type="default" />
+
+</blueprint>
/*
- * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-package org.opendaylight.mdsal.dom.broker.osgi;
+package org.opendaylight.mdsal.dom.schema.service.osgi;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import org.opendaylight.mdsal.dom.broker.util.TestModel;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.schema.service.osgi.util.TestModel;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
import org.osgi.framework.Bundle;
try {
OsgiBundleScanningSchemaService.getInstance();
OsgiBundleScanningSchemaService.destroyInstance();
- } catch (Exception e) {
+ } catch (final Exception e) {
assertTrue(e instanceof IllegalStateException);
}
}
@Test
public void basicTest() throws Exception {
+ assertTrue(osgiService instanceof DOMSchemaService);
+
final SchemaContext schemaContext = TestModel.createTestContext();
+
final SchemaContextListener schemaContextListener = mock(SchemaContextListener.class);
doNothing().when(schemaContextListener).onGlobalContextUpdated(schemaContext);
osgiService.registerSchemaContextListener(schemaContextListener);
public void sessionContextTest() throws Exception {
osgiService.getSessionContext();
}
-}
\ No newline at end of file
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.dom.schema.service.osgi.util;
+
+import java.io.InputStream;
+import java.util.Collections;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class TestModel {
+
+ public static final QName TEST_QNAME =
+ QName.create("urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test", "2014-03-13", "test");
+ public static final QName TEST2_QNAME =
+ QName.create("urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test", "2014-03-13", "test2");
+ public static final QName OUTER_LIST_QNAME = QName.create(TEST_QNAME, "outer-list");
+ public static final QName INNER_LIST_QNAME = QName.create(TEST_QNAME, "inner-list");
+ public static final QName OUTER_CHOICE_QNAME = QName.create(TEST_QNAME, "outer-choice");
+ public static final QName ID_QNAME = QName.create(TEST_QNAME, "id");
+ public static final QName NAME_QNAME = QName.create(TEST_QNAME, "name");
+ public static final QName VALUE_QNAME = QName.create(TEST_QNAME, "value");
+ public static final QName INNER_CONTAINER = QName.create(TEST_QNAME, "inner-container");
+ public static final QName ANOTHER_SHARD_CONTAINER = QName.create(TEST_QNAME, "another-shard");
+ public static final QName NEW_SHARD_LIST = QName.create(TEST_QNAME, "new-shard-list");
+ public static final QName SHARDED_VALUE_1 = QName.create(TEST_QNAME, "sharded-value-1");
+ public static final QName SHARDED_VALUE_2 = QName.create(TEST_QNAME, "sharded-value-2");
+ public static final QName ANOTHER_SHARD_VALUE = QName.create(TEST_QNAME, "another-shard-value");
+ public static final QName TWO_QNAME = QName.create(TEST_QNAME, "two");
+ public static final QName THREE_QNAME = QName.create(TEST_QNAME, "three");
+ public static final YangInstanceIdentifier TEST_PATH = YangInstanceIdentifier.of(TEST_QNAME);
+ public static final YangInstanceIdentifier TEST2_PATH = YangInstanceIdentifier.of(TEST2_QNAME);
+ public static final YangInstanceIdentifier OUTER_LIST_PATH =
+ YangInstanceIdentifier.builder(TEST_PATH).node(OUTER_LIST_QNAME).build();
+ public static final YangInstanceIdentifier INNER_LIST_PATH =
+ YangInstanceIdentifier.builder(OUTER_LIST_PATH).node(INNER_LIST_QNAME).build();
+ public static final YangInstanceIdentifier INNER_CONTAINER_PATH =
+ YangInstanceIdentifier.builder(TEST_PATH).node(INNER_CONTAINER).build();
+ public static final YangInstanceIdentifier ANOTHER_SHARD_PATH =
+ YangInstanceIdentifier.builder(INNER_CONTAINER_PATH).node(ANOTHER_SHARD_CONTAINER).build();
+ public static final YangInstanceIdentifier NEW_SHARD_LIST_PATH =
+ YangInstanceIdentifier.builder(ANOTHER_SHARD_PATH).node(NEW_SHARD_LIST).build();
+ private static final String DATASTORE_TEST_YANG = "/odl-datastore-test.yang";
+
+ public static SchemaContext createTestContext() throws ReactorException {
+ return YangParserTestUtils.parseYangStreams(Collections.singletonList(getInputStream()));
+ }
+
+ private static InputStream getInputStream() {
+ return TestModel.class.getResourceAsStream(DATASTORE_TEST_YANG);
+ }
+}
--- /dev/null
+module odl-datastore-test {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test";
+ prefix "store-test";
+
+ revision "2014-03-13" {
+ description "Initial revision.";
+ }
+
+ container test {
+ presence "presence container";
+ list outer-list {
+ key id;
+ leaf id {
+ type uint16;
+ }
+ choice outer-choice {
+ case one {
+ leaf one {
+ type string;
+ }
+ }
+ case two-three {
+ leaf two {
+ type string;
+ }
+ leaf three {
+ type string;
+ }
+ }
+ }
+ list inner-list {
+ key name;
+ leaf name {
+ type string;
+ }
+ leaf value {
+ type string;
+ }
+ }
+ }
+
+ container inner-container {
+
+ leaf sharded-value-1 {
+ type string;
+ }
+
+ leaf sharded-value-2 {
+ type string;
+ }
+
+ container another-shard {
+ list new-shard-list {
+ key name;
+ leaf name {
+ type string;
+ }
+ leaf value {
+ type string;
+ }
+ }
+
+ leaf another-shard-value {
+ type string;
+ }
+ }
+ }
+ }
+
+ container test2 {
+ }
+}
<module>mdsal-dom-spi</module>
<module>mdsal-dom-broker</module>
<module>mdsal-dom-inmemory-datastore</module>
+ <module>mdsal-dom-schema-service-osgi</module>
</modules>
<!--