HONEYCOMB-61: Restore configuration and context from persisted files
authorMaros Marsalek <[email protected]>
Wed, 18 May 2016 13:05:51 +0000 (15:05 +0200)
committerMaros Marsalek <[email protected]>
Tue, 24 May 2016 08:36:34 +0000 (08:36 +0000)
Change-Id: I6edce127f8895f5d65998b4be71a0a111ca2e8bb
Signed-off-by: Maros Marsalek <[email protected]>
31 files changed:
v3po/data-api/src/main/yang/data-api.yang
v3po/data-impl/pom.xml
v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java
v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java
v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/InMemoryDataTreeModule.java
v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/PersistingDataTreeAdapterModule.java
v3po/data-impl/src/main/yang/data-impl.yang
v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapterTest.java
v3po/data-impl/src/test/resources/expected-persisted-output.txt [deleted file]
v3po/features/pom.xml
v3po/features/src/main/features/features.xml
v3po/impl/pom.xml
v3po/impl/src/main/config/default-config.xml
v3po/impl/src/main/config/initializer-config.xml [new file with mode: 0644]
v3po/translate-utils/pom.xml
v3po/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/JsonUtils.java [new file with mode: 0644]
v3po/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/JsonUtilsTest.java [new file with mode: 0644]
v3po/translate-utils/src/test/resources/expected-persisted-output.txt [new file with mode: 0644]
v3po/translate-utils/src/test/resources/test-persistence.yang [moved from v3po/data-impl/src/test/resources/test-persistence.yang with 76% similarity]
v3po/vpp-cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/DataTreeInitializer.java
v3po/vpp-cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/InterfacesInitializer.java
v3po/vpp-cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/RestoringInitializer.java [new file with mode: 0644]
v3po/vpp-cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/VppInitializer.java
v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModule.java [new file with mode: 0644]
v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModuleFactory.java [new file with mode: 0644]
v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/InterfacesConfigurationInitializerModule.java [new file with mode: 0644]
v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/InterfacesConfigurationInitializerModuleFactory.java [new file with mode: 0644]
v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModule.java [new file with mode: 0644]
v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModuleFactory.java [new file with mode: 0644]
v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/VppConfigurationInitializerModule.java
v3po/vpp-cfg-init/src/main/yang/vpp-cfg-init.yang

index 11d963e..693a73a 100644 (file)
@@ -29,4 +29,10 @@ module data-api {
         config:java-class io.fd.honeycomb.v3po.data.ModifiableDataManager;
     }
 
+    typedef datatree-type {
+        type enumeration {
+             enum config;
+             enum oper;
+         }
+    }
 }
\ No newline at end of file
index 46faab7..1d716a6 100644 (file)
             <groupId>org.opendaylight.mdsal</groupId>
             <artifactId>mdsal-binding-dom-codec</artifactId>
         </dependency>
-        <dependency>
-            <groupId>org.opendaylight.yangtools</groupId>
-            <artifactId>yang-data-codec-gson</artifactId>
-        </dependency>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>sal-core-api</artifactId>
index a54b7f1..df5bbee 100644 (file)
@@ -18,33 +18,22 @@ package io.fd.honeycomb.v3po.data.impl;
 
 import static com.google.common.base.Preconditions.checkArgument;
 
-import com.google.common.base.Charsets;
 import com.google.common.base.Optional;
-import com.google.gson.stream.JsonWriter;
+import io.fd.honeycomb.v3po.translate.util.JsonUtils;
 import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.StandardOpenOption;
 import javax.annotation.Nonnull;
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
-import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
-import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactory;
-import org.opendaylight.yangtools.yang.data.codec.gson.JSONNormalizedNodeStreamWriter;
-import org.opendaylight.yangtools.yang.data.codec.gson.JsonWriterFactory;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -82,17 +71,16 @@ public class PersistingDataTreeAdapter implements org.opendaylight.yangtools.yan
     private Path testPersistPath(final Path persistPath) {
         try {
             checkArgument(!Files.isDirectory(persistPath), "Path %s points to a directory", persistPath);
+            if(Files.exists(persistPath)) {
+                checkArgument(Files.isReadable(persistPath),
+                    "Provided path %s points to existing, but non-readable file", persistPath);
+                return persistPath;
+            }
             Files.createDirectories(persistPath.getParent());
             Files.write(persistPath, new byte[]{}, StandardOpenOption.CREATE);
         } catch (IOException | UnsupportedOperationException e) {
             LOG.warn("Provided path for persistence: {} is not usable", persistPath, e);
             throw new IllegalArgumentException("Path " + persistPath + " cannot be used as ");
-        } finally {
-            try {
-                Files.delete(persistPath);
-            } catch (IOException e) {
-                LOG.warn("Unable to delete file at {}", persistPath, e);
-            }
         }
 
         return persistPath;
@@ -131,17 +119,8 @@ public class PersistingDataTreeAdapter implements org.opendaylight.yangtools.yan
                 if(Files.exists(path)) {
                     Files.delete(path);
                 }
-                // TODO once we are in static environment, do the writer, streamWriter and NNWriter initialization only once
-                final JsonWriter
-                    jsonWriter = createJsonWriter(Files.newOutputStream(path, StandardOpenOption.CREATE), true);
-                final NormalizedNodeStreamWriter streamWriter = JSONNormalizedNodeStreamWriter
-                    .createNestedWriter(JSONCodecFactory.create(schemaServiceDependency.getGlobalContext()), SchemaPath.ROOT, null, jsonWriter);
-                final NormalizedNodeWriter normalizedNodeWriter =
-                    NormalizedNodeWriter.forStreamWriter(streamWriter, true);
-                jsonWriter.beginObject();
-                writeChildren(normalizedNodeWriter,(ContainerNode) currentRoot.get());
-                jsonWriter.endObject();
-                jsonWriter.flush();
+                JsonUtils.writeJsonRoot(currentRoot.get(), schemaServiceDependency.getGlobalContext(),
+                    Files.newOutputStream(path, StandardOpenOption.CREATE));
                 LOG.trace("Data persisted successfully in {}", path);
             } catch (IOException e) {
                 throw new IllegalStateException("Unable to persist current data", e);
@@ -151,20 +130,6 @@ public class PersistingDataTreeAdapter implements org.opendaylight.yangtools.yan
         }
     }
 
-    private void writeChildren(final NormalizedNodeWriter nnWriter, final ContainerNode data) throws IOException {
-        for(final DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> child : data.getValue()) {
-            nnWriter.write(child);
-        }
-    }
-
-    private JsonWriter createJsonWriter(final OutputStream entityStream, boolean prettyPrint) {
-        if (prettyPrint) {
-            return JsonWriterFactory.createJsonWriter(new OutputStreamWriter(entityStream, Charsets.UTF_8), 2);
-        } else {
-            return JsonWriterFactory.createJsonWriter(new OutputStreamWriter(entityStream, Charsets.UTF_8));
-        }
-    }
-
     @Override
     public YangInstanceIdentifier getRootPath() {
         return delegateDependency.getRootPath();
index 3644a9f..ac4ba90 100644 (file)
@@ -77,11 +77,11 @@ final class WriteTransaction implements DOMDataWriteTransaction {
                                  final java.util.function.Consumer<DataModification> r) {
         switch (store) {
             case CONFIGURATION:
-                checkArgument(configModification != null, "Modification of {} is not supported", store);
+                checkArgument(configModification != null, "Modification of %s is not supported", store);
                 r.accept(configModification);
                 break;
             case OPERATIONAL:
-                checkArgument(operationalModification != null, "Modification of {} is not supported", store);
+                checkArgument(operationalModification != null, "Modification of %s is not supported", store);
                 r.accept(operationalModification);
                 break;
         }
index 54c830e..956aa90 100644 (file)
@@ -1,5 +1,6 @@
 package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411;
 
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.api.rev160411.DatatreeType;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.*;
 import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
index aa57f4d..145fc43 100644 (file)
@@ -1,6 +1,8 @@
 package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411;
 
+import java.nio.file.InvalidPathException;
 import java.nio.file.Paths;
+import org.opendaylight.controller.config.api.JmxAttributeValidationException;
 
 public class PersistingDataTreeAdapterModule extends
     org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411.AbstractPersistingDataTreeAdapterModule {
@@ -18,7 +20,11 @@ public class PersistingDataTreeAdapterModule extends
 
     @Override
     public void customValidation() {
-        // add custom validation form module attributes here.
+        try {
+            Paths.get(getPersistFilePath());
+        } catch (InvalidPathException e) {
+            throw new JmxAttributeValidationException("Invalid persist path", e, persistFilePathJmxAttribute);
+        }
     }
 
     @Override
index 3af9d8d..a6b217a 100644 (file)
@@ -24,13 +24,6 @@ module data-impl {
         config:java-name-prefix InMemoryDataTree;
     }
 
-    typedef datatree-type {
-        type enumeration {
-             enum config;
-             enum oper;
-         }
-    }
-
     augment "/config:modules/config:module/config:configuration" {
         case inmemory-data-tree {
             when "/config:modules/config:module/config:type = 'inmemory-data-tree'";
@@ -45,7 +38,7 @@ module data-impl {
             }
 
             leaf type {
-                type datatree-type;
+                type dapi:datatree-type;
             }
         }
     }
index 986d7cf..523d9dd 100644 (file)
 
 package io.fd.honeycomb.v3po.data.impl;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-import com.google.common.io.ByteStreams;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import org.junit.Before;
@@ -34,28 +29,12 @@ import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
-import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
-import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
-import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
-import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline;
-import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl;
-import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.EffectiveSchemaContext;
 
 public class PersistingDataTreeAdapterTest {
 
-    public static final String NAMESPACE = "urn:opendaylight:params:xml:ns:yang:test:persistence";
-
-    // The root QNAME can be anything, onyl its children are iterated
-    private static final QName ROOT_QNAME = QName.create("random",  "data");
-    private static final QName TOP_CONTAINER_NAME = QName.create(NAMESPACE, "2015-01-05", "top-container");
-    private static final QName STRING_LEAF_QNAME = QName.create(TOP_CONTAINER_NAME, "string");
-
     @Mock
     private DataTree delegatingDataTree;
     @Mock
@@ -71,46 +50,9 @@ public class PersistingDataTreeAdapterTest {
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         tmpPersistFile = Files.createTempFile("testing-hc-persistence", "json");
-
-        // Build test yang schemas
-        final CrossSourceStatementReactor.BuildAction buildAction = YangInferencePipeline.RFC6020_REACTOR.newBuild();
-        buildAction.addSource(new YangStatementSourceImpl(getClass().getResourceAsStream("/test-persistence.yang")));
-        final EffectiveSchemaContext effectiveSchemaContext = buildAction.buildEffective();
-        doReturn(effectiveSchemaContext).when(schemaService).getGlobalContext();
-
         persistingDataTreeAdapter = new PersistingDataTreeAdapter(delegatingDataTree, schemaService, tmpPersistFile);
     }
 
-    @Test
-    public void testPersist() throws Exception {
-        doReturn(snapshot).when(delegatingDataTree).takeSnapshot();
-
-        NormalizedNode<?, ?> data = getData("testing");
-        doReturn(com.google.common.base.Optional.of(data)).when(snapshot).readNode(YangInstanceIdentifier.EMPTY);
-        persistingDataTreeAdapter.commit(null);
-        assertTrue(Files.exists(tmpPersistFile));
-
-        String persisted = new String(Files.readAllBytes(tmpPersistFile));
-        String expected =
-            new String(ByteStreams.toByteArray(getClass().getResourceAsStream("/expected-persisted-output.txt")));
-
-        assertEquals(expected, persisted);
-
-        data = getData("testing2");
-        doReturn(com.google.common.base.Optional.of(data)).when(snapshot).readNode(YangInstanceIdentifier.EMPTY);
-        persistingDataTreeAdapter.commit(null);
-
-        verify(delegatingDataTree, times(2)).commit(null);
-
-        persisted = new String(Files.readAllBytes(tmpPersistFile));
-        assertEquals(expected.replace("testing", "testing2"), persisted);
-
-        persistingDataTreeAdapter.close();
-
-        // File has to stay even after close
-        assertTrue(Files.exists(tmpPersistFile));
-    }
-
     @Test
     public void testNoPersistOnFailure() throws Exception {
         doThrow(new IllegalStateException("testing errors")).when(delegatingDataTree).commit(any(DataTreeCandidate.class));
@@ -119,19 +61,9 @@ public class PersistingDataTreeAdapterTest {
             persistingDataTreeAdapter.commit(null);
             fail("Exception expected");
         } catch (IllegalStateException e) {
-            assertFalse(Files.exists(tmpPersistFile));
             verify(delegatingDataTree, times(0)).takeSnapshot();
             verify(delegatingDataTree).commit(any(DataTreeCandidate.class));
         }
     }
 
-    private NormalizedNode<?, ?> getData(final String stringValue) {
-        return Builders.containerBuilder()
-                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(ROOT_QNAME))
-                .withChild(Builders.containerBuilder()
-                    .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TOP_CONTAINER_NAME))
-                    .withChild(ImmutableNodes.leafNode(STRING_LEAF_QNAME, stringValue))
-                    .build())
-                .build();
-    }
 }
\ No newline at end of file
diff --git a/v3po/data-impl/src/test/resources/expected-persisted-output.txt b/v3po/data-impl/src/test/resources/expected-persisted-output.txt
deleted file mode 100644 (file)
index fb21d61..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  "test-persistence:top-container": {
-    "string": "testing"
-  }
-}
\ No newline at end of file
index 1233f7d..b79e62d 100644 (file)
       <type>xml</type>
       <classifier>netconf</classifier>
     </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>v3po-impl</artifactId>
+      <version>${project.version}</version>
+      <type>xml</type>
+      <classifier>init</classifier>
+    </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
       <artifactId>v3po-impl</artifactId>
index 66e57fc..1e5f28f 100644 (file)
@@ -49,6 +49,7 @@
     <configfile finalname="${configfile.directory}/vpp-jvpp.xml">mvn:io.fd.honeycomb.v3po/vpp-jvpp-cfg/${project.version}/xml/config</configfile>
     <configfile finalname="${configfile.directory}/v3po-context.xml">mvn:io.fd.honeycomb.v3po/v3po-impl/${project.version}/xml/context</configfile>
     <configfile finalname="${configfile.directory}/v3po.xml">mvn:io.fd.honeycomb.v3po/v3po-impl/${project.version}/xml/config</configfile>
+    <configfile finalname="${configfile.directory}/v3po-init.xml">mvn:io.fd.honeycomb.v3po/v3po-impl/${project.version}/xml/init</configfile>
     <configfile finalname="${configfile.directory}/v3po-netconf.xml">mvn:io.fd.honeycomb.v3po/v3po-impl/${project.version}/xml/netconf</configfile>
     <configfile finalname="${configfile.directory}/v3po-restconf.xml">mvn:io.fd.honeycomb.v3po/v3po-impl/${project.version}/xml/restconf</configfile>
     <configfile finalname="${configfile.directory}/v3po2vpp.xml">mvn:io.fd.honeycomb.v3po/v3po2vpp/${project.version}/xml/config</configfile>
index 6db420b..6f4f4e1 100644 (file)
                   <type>xml</type>
                   <classifier>netconf</classifier>
                 </artifact>
+                <artifact>
+                  <file>src/main/config/initializer-config.xml</file>
+                  <type>xml</type>
+                  <classifier>init</classifier>
+                </artifact>
                 <artifact>
                   <file>src/main/config/context-datatree-config.xml</file>
                   <type>xml</type>
index 7106c78..961ca72 100644 (file)
@@ -19,7 +19,6 @@
       <capability>urn:opendaylight:params:xml:ns:yang:v3po:impl?module=v3po-impl&amp;revision=2014-12-10</capability>
       <capability>urn:honeycomb:params:xml:ns:yang:translate:utils?module=translate-utils&amp;revision=2016-04-06</capability>
       <capability>urn:honeycomb:params:xml:ns:yang:vpp:jvpp:cfg?module=vpp-jvpp-cfg&amp;revision=2016-04-06</capability>
-      <capability>urn:honeycomb:params:xml:ns:yang:vpp:data:init?module=vpp-cfg-init&amp;revision=2016-04-07</capability>
       <capability>urn:honeycomb:params:xml:ns:yang:data:api?module=data-api&amp;revision=2016-04-11</capability>
       <capability>urn:honeycomb:params:xml:ns:yang:data:impl?module=data-impl&amp;revision=2016-04-11</capability>
       <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&amp;revision=2013-10-28</capability>
             <name>honeycomb-dom-data-broker</name>
           </honeycomb-dom-data-broker>
         </module>
-
-        <!-- Config initialization -->
-        <!-- Empty registry which does not pass data to VPP  -->
-        <module>
-          <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:utils">prefix:noop-writer-registry</type>
-          <name>noop-writer-registry</name>
-        </module>
-        <!-- Config data tree which does not pass data to translation layer (uses noop-write-registry)  -->
-        <module>
-          <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:impl">prefix:honeycomb-config-data-tree</type>
-          <name>cfg-init-config-data-tree</name>
-
-          <!--FIXME do we need/want persistence here ? Do initializers only merge the data ? -->
-          <!-- Without persistence -->
-          <!--<data-tree>-->
-            <!--<type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:impl">prefix:data-tree</type>-->
-            <!--<name>inmemory-config-data-tree</name>-->
-          <!--</data-tree>-->
-          <!-- With persistence -->
-          <data-tree>
-            <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:data-tree</type>
-            <name>inmemory-persisted-config-data-tree</name>
-          </data-tree>
-
-          <serializer>
-            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-dom-mapping-service</type>
-            <name>runtime-mapping-singleton</name>
-          </serializer>
-          <writer-registry>
-            <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:api">prefix:honeycomb-writer-registry</type>
-            <name>noop-writer-registry</name>
-          </writer-registry>
-          <context-binding-broker>
-            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
-            <name>honeycomb-context-binding-data-broker</name>
-          </context-binding-broker>
-        </module>
-        <!-- DOM data broker for config initialization -->
-        <module>
-          <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:v3po:impl">prefix:honeycomb-dom-data-broker</type>
-          <name>cfg-init-dom-data-broker</name>
-          <config-data-tree>
-            <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:honeycomb-modifiable-data-tree</type>
-            <name>cfg-init-config-data-tree</name>
-          </config-data-tree>
-          <operational-data-tree>
-            <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:honeycomb-readable-data-tree</type>
-            <name>operational-data-tree</name>
-          </operational-data-tree>
-        </module>
-        <!-- Binding data broker for config initialization -->
-        <module>
-          <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-forwarded-data-broker</type>
-          <name>cfg-init-binding-data-broker</name>
-          <binding-forwarded-data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
-            <dom-async-broker>
-              <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
-              <name>cfg-init-dom-data-broker</name>
-            </dom-async-broker>
-            <schema-service>
-              <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
-              <name>yang-schema-service</name>
-            </schema-service>
-            <binding-mapping-service>
-              <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
-              <name>runtime-mapping-singleton</name>
-            </binding-mapping-service>
-          </binding-forwarded-data-broker>
-        </module>
-        <!-- Config initializer -->
-        <module>
-          <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:vpp-cfg-initializer-impl</type>
-          <name>vpp-cfg-initializer</name>
-          <binding-data-broker>
-            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-async-data-broker</type>
-            <name>cfg-init-binding-data-broker</name>
-          </binding-data-broker>
-        </module>noop-writer-registry
-        <!-- END: Config initialization -->
       </modules>
 
       <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
           </instance>
         </service>
 
-        <!-- Config initialization -->
-        <service>
-          <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:api">prefix:honeycomb-writer-registry</type>
-          <instance>
-            <name>noop-writer-registry</name>
-            <provider>/modules/module[type='noop-writer-registry'][name='noop-writer-registry']</provider>
-          </instance>
-        </service>
-        <service>
-          <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:honeycomb-modifiable-data-tree</type>
-          <instance>
-            <name>cfg-init-config-data-tree</name>
-            <provider>/modules/module[type='honeycomb-config-data-tree'][name='cfg-init-config-data-tree']
-            </provider>
-          </instance>
-        </service>
-        <service>
-          <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
-          <instance>
-            <name>cfg-init-dom-data-broker</name>
-            <provider>/modules/module[type='honeycomb-dom-data-broker'][name='cfg-init-dom-data-broker']</provider>
-          </instance>
-        </service>
-        <service>
-          <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
-          <instance>
-            <name>cfg-init-binding-data-broker</name>
-            <provider>/modules/module[type='binding-forwarded-data-broker'][name='cfg-init-binding-data-broker']</provider>
-          </instance>
-        </service>
-        <service>
-          <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:vpp-cfg-initializer</type>
-          <instance>
-            <name>vpp-cfg-initializer</name>
-            <provider>/modules/module[type='vpp-cfg-initializer-impl'][name='vpp-cfg-initializer']
-            </provider>
-          </instance>
-        </service>
-        <!-- END: Config initialization -->
-
       </services>
     </data>
   </configuration>
diff --git a/v3po/impl/src/main/config/initializer-config.xml b/v3po/impl/src/main/config/initializer-config.xml
new file mode 100644 (file)
index 0000000..c5ee10f
--- /dev/null
@@ -0,0 +1,224 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright (c) 2016 Cisco and/or its affiliates.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at:
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+
+<snapshot>
+  <required-capabilities>
+      <capability>urn:opendaylight:params:xml:ns:yang:v3po:impl?module=v3po-impl&amp;revision=2014-12-10</capability>
+      <capability>urn:honeycomb:params:xml:ns:yang:translate:utils?module=translate-utils&amp;revision=2016-04-06</capability>
+      <capability>urn:honeycomb:params:xml:ns:yang:vpp:jvpp:cfg?module=vpp-jvpp-cfg&amp;revision=2016-04-06</capability>
+      <capability>urn:honeycomb:params:xml:ns:yang:vpp:data:init?module=vpp-cfg-init&amp;revision=2016-04-07</capability>
+      <capability>urn:honeycomb:params:xml:ns:yang:data:api?module=data-api&amp;revision=2016-04-11</capability>
+      <capability>urn:honeycomb:params:xml:ns:yang:data:impl?module=data-impl&amp;revision=2016-04-11</capability>
+      <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&amp;revision=2013-10-28</capability>
+  </required-capabilities>
+  <configuration>
+
+    <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+      <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+        <!-- Config initialization -->
+        <!-- Empty registry which does not pass data to VPP  -->
+        <module>
+          <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:utils">prefix:noop-writer-registry</type>
+          <name>noop-writer-registry</name>
+        </module>
+        <!-- Config data tree which does not pass data to translation layer (uses noop-write-registry)  -->
+        <module>
+          <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:impl">prefix:honeycomb-config-data-tree</type>
+          <name>cfg-init-config-data-tree</name>
+          <!-- Without persistence -->
+          <data-tree>
+            <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:data-tree</type>
+            <name>inmemory-config-data-tree</name>
+          </data-tree>
+          <serializer>
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-dom-mapping-service</type>
+            <name>runtime-mapping-singleton</name>
+          </serializer>
+          <writer-registry>
+            <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:api">prefix:honeycomb-writer-registry</type>
+            <name>noop-writer-registry</name>
+          </writer-registry>
+          <context-binding-broker>
+            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
+            <name>honeycomb-context-binding-data-broker</name>
+          </context-binding-broker>
+        </module>
+        <!-- DOM data broker for config initialization -->
+        <module>
+          <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:v3po:impl">prefix:honeycomb-dom-data-broker</type>
+          <name>cfg-init-dom-data-broker</name>
+          <config-data-tree>
+            <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:honeycomb-modifiable-data-tree</type>
+            <name>cfg-init-config-data-tree</name>
+          </config-data-tree>
+          <operational-data-tree>
+            <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:honeycomb-readable-data-tree</type>
+            <name>operational-data-tree</name>
+          </operational-data-tree>
+        </module>
+        <!-- Binding data broker for config initialization -->
+        <module>
+          <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-forwarded-data-broker</type>
+          <name>cfg-init-binding-data-broker</name>
+          <binding-forwarded-data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+            <dom-async-broker>
+              <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
+              <name>cfg-init-dom-data-broker</name>
+            </dom-async-broker>
+            <schema-service>
+              <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+              <name>yang-schema-service</name>
+            </schema-service>
+            <binding-mapping-service>
+              <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
+              <name>runtime-mapping-singleton</name>
+            </binding-mapping-service>
+          </binding-forwarded-data-broker>
+        </module>
+        <!-- Config initializer for VPP subtree-->
+        <module>
+          <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:vpp-cfg-initializer</type>
+          <name>vpp-cfg-initializer</name>
+          <binding-data-broker>
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-async-data-broker</type>
+            <name>cfg-init-binding-data-broker</name>
+          </binding-data-broker>
+        </module>
+        <!-- Config initializer for Interfaces subtree-->
+        <module>
+          <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:interfaces-cfg-initializer</type>
+          <name>interfaces-cfg-initializer</name>
+          <binding-data-broker>
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-async-data-broker</type>
+            <name>cfg-init-binding-data-broker</name>
+          </binding-data-broker>
+        </module>
+        <module>
+          <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:persisted-file-initializer</type>
+          <name>persisted-context-initializer</name>
+          <dom-data-broker>
+            <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
+            <name>honeycomb-context-data-broker</name>
+          </dom-data-broker>
+          <schema-service>
+            <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+            <name>yang-schema-service</name>
+          </schema-service>
+          <persist-file-path>etc/opendaylight/honeycomb/context.json</persist-file-path>
+          <restoration-type>merge</restoration-type>
+          <datastore-type>oper</datastore-type>
+        </module>
+        <module>
+          <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:persisted-file-initializer</type>
+          <name>persisted-config-initializer</name>
+          <dom-data-broker>
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-async-data-broker</type>
+            <name>honeycomb-dom-data-broker</name>
+          </dom-data-broker>
+          <schema-service>
+            <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+            <name>yang-schema-service</name>
+          </schema-service>
+          <persist-file-path>etc/opendaylight/honeycomb/config.json</persist-file-path>
+          <restoration-type>merge</restoration-type>
+          <datastore-type>config</datastore-type>
+        </module>
+
+        <module>
+          <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:cfg-initializer-registry</type>
+          <name>initializer-registry</name>
+          <persisted-context-initializer>
+            <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:cfg-initializer</type>
+            <name>persisted-context-initializer</name>
+          </persisted-context-initializer>
+          <initializers>
+            <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:cfg-initializer</type>
+            <name>vpp-cfg-initializer</name>
+          </initializers>
+          <initializers>
+            <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:cfg-initializer</type>
+            <name>interfaces-cfg-initializer</name>
+          </initializers>
+          <persisted-config-initializer>
+            <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:cfg-initializer</type>
+            <name>persisted-config-initializer</name>
+          </persisted-config-initializer>
+        </module>
+        <!-- END: Config initialization -->
+      </modules>
+
+      <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+        <!-- Config initialization -->
+        <service>
+          <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:api">prefix:honeycomb-writer-registry</type>
+          <instance>
+            <name>noop-writer-registry</name>
+            <provider>/modules/module[type='noop-writer-registry'][name='noop-writer-registry']</provider>
+          </instance>
+        </service>
+        <service>
+          <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:honeycomb-modifiable-data-tree</type>
+          <instance>
+            <name>cfg-init-config-data-tree</name>
+            <provider>/modules/module[type='honeycomb-config-data-tree'][name='cfg-init-config-data-tree']
+            </provider>
+          </instance>
+        </service>
+        <service>
+          <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
+          <instance>
+            <name>cfg-init-dom-data-broker</name>
+            <provider>/modules/module[type='honeycomb-dom-data-broker'][name='cfg-init-dom-data-broker']</provider>
+          </instance>
+        </service>
+        <service>
+          <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
+          <instance>
+            <name>cfg-init-binding-data-broker</name>
+            <provider>/modules/module[type='binding-forwarded-data-broker'][name='cfg-init-binding-data-broker']</provider>
+          </instance>
+        </service>
+
+        <service>
+          <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:cfg-initializer</type>
+          <instance>
+            <name>vpp-cfg-initializer</name>
+            <provider>/modules/module[type='vpp-cfg-initializer'][name='vpp-cfg-initializer']
+            </provider>
+          </instance>
+          <instance>
+            <name>interfaces-cfg-initializer</name>
+            <provider>/modules/module[type='interfaces-cfg-initializer'][name='interfaces-cfg-initializer']
+            </provider>
+          </instance>
+          <instance>
+            <name>persisted-context-initializer</name>
+            <provider>/modules/module[type='persisted-file-initializer'][name='persisted-context-initializer']
+            </provider>
+          </instance>
+          <instance>
+            <name>persisted-config-initializer</name>
+            <provider>/modules/module[type='persisted-file-initializer'][name='persisted-config-initializer']
+            </provider>
+          </instance>
+        </service>
+      </services>
+    </data>
+  </configuration>
+</snapshot>
index 346757c..9cb6590 100644 (file)
             <groupId>org.opendaylight.mdsal</groupId>
             <artifactId>mdsal-binding-dom-codec</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-data-codec-gson</artifactId>
+        </dependency>
 
         <!-- Testing Dependencies -->
         <dependency>
diff --git a/v3po/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/JsonUtils.java b/v3po/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/JsonUtils.java
new file mode 100644 (file)
index 0000000..be6ffa2
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.translate.util;
+
+import com.google.common.base.Charsets;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactory;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.codec.gson.JsonParserStream;
+import org.opendaylight.yangtools.yang.data.codec.gson.JsonWriterFactory;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+public class JsonUtils {
+
+    private JsonUtils() {}
+
+    /**
+     * Serialize normalized node root structure into provided output stream
+     *
+     * @throws IOException if serialized data cannot be written into provided output stream
+     */
+    public static void writeJsonRoot(@Nonnull final NormalizedNode<?, ?> rootData,
+                                     @Nonnull final SchemaContext schemaContext,
+                                     @Nonnull final OutputStream outputStream) throws IOException {
+        final JsonWriter
+            jsonWriter = createJsonWriter(outputStream, true);
+        final NormalizedNodeStreamWriter streamWriter = JSONNormalizedNodeStreamWriter
+            .createNestedWriter(JSONCodecFactory.create(schemaContext), SchemaPath.ROOT, null, jsonWriter);
+        final NormalizedNodeWriter normalizedNodeWriter =
+            NormalizedNodeWriter.forStreamWriter(streamWriter, true);
+        jsonWriter.beginObject();
+        writeChildren(normalizedNodeWriter,(ContainerNode) rootData);
+        jsonWriter.endObject();
+        jsonWriter.flush();
+    }
+
+    /**
+     * Read json serialized normalized node root structure and parse them into normalized nodes
+     *
+     * @return artificial normalized node holding all the top level nodes from provided stream as children. In case
+     *         the stream is empty, empty artificial normalized node is returned
+     *
+     * @throws IllegalArgumentException if content in the provided input stream is not restore-able
+     */
+    public static ContainerNode readJsonRoot(@Nonnull final SchemaContext schemaContext,
+                                             @Nonnull final InputStream stream) {
+        final DataContainerNodeAttrBuilder<YangInstanceIdentifier.NodeIdentifier, ContainerNode> builder =
+            Builders.containerBuilder().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(schemaContext.getQName()));
+        final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(builder);
+
+        final JsonParserStream jsonParser = JsonParserStream.create(writer, schemaContext);
+        final JsonReader reader = new JsonReader(new InputStreamReader(stream));
+        jsonParser.parse(reader);
+
+        return builder.build();
+    }
+
+    private static void writeChildren(final NormalizedNodeWriter nnWriter, final ContainerNode data) throws IOException {
+        for(final DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> child : data.getValue()) {
+            nnWriter.write(child);
+        }
+    }
+
+    private static JsonWriter createJsonWriter(final OutputStream entityStream, boolean prettyPrint) {
+        if (prettyPrint) {
+            return JsonWriterFactory.createJsonWriter(new OutputStreamWriter(entityStream, Charsets.UTF_8), 2);
+        } else {
+            return JsonWriterFactory.createJsonWriter(new OutputStreamWriter(entityStream, Charsets.UTF_8));
+        }
+    }
+}
diff --git a/v3po/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/JsonUtilsTest.java b/v3po/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/JsonUtilsTest.java
new file mode 100644 (file)
index 0000000..bd48cb4
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.translate.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.io.ByteStreams;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.EffectiveSchemaContext;
+
+public class JsonUtilsTest {
+
+    public static final String NAMESPACE = "urn:opendaylight:params:xml:ns:yang:test:persistence";
+
+    private static final QName ROOT_QNAME = QName.create("urn:ietf:params:xml:ns:netconf:base:1.0",  "data");
+    private static final QName TOP_CONTAINER_NAME = QName.create(NAMESPACE, "2015-01-05", "top-container");
+    private static final QName TOP_CONTAINER2_NAME = QName.create(NAMESPACE, "2015-01-05", "top-container2");
+    private static final QName STRING_LEAF_QNAME = QName.create(TOP_CONTAINER_NAME, "string");
+
+    private Path tmpPersistFile;
+    private EffectiveSchemaContext effectiveSchemaContext;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        tmpPersistFile = Files.createTempFile("testing-hc-persistence", "json");
+
+        final CrossSourceStatementReactor.BuildAction buildAction = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+        buildAction.addSource(new YangStatementSourceImpl(getClass().getResourceAsStream("/test-persistence.yang")));
+        effectiveSchemaContext = buildAction.buildEffective();
+    }
+
+    @Test
+    public void testPersist() throws Exception {
+
+        NormalizedNode<?, ?> data = getData("testing");
+        JsonUtils.writeJsonRoot(data, effectiveSchemaContext, Files.newOutputStream(tmpPersistFile, StandardOpenOption.CREATE));
+        assertTrue(Files.exists(tmpPersistFile));
+
+        String persisted = new String(Files.readAllBytes(tmpPersistFile));
+        String expected =
+            new String(ByteStreams.toByteArray(getClass().getResourceAsStream("/expected-persisted-output.txt")));
+
+        assertEquals(expected, persisted);
+
+        data = getData("testing2");
+        JsonUtils.writeJsonRoot(data, effectiveSchemaContext, Files.newOutputStream(tmpPersistFile, StandardOpenOption.CREATE));
+        persisted = new String(Files.readAllBytes(tmpPersistFile));
+        assertEquals(expected.replace("testing", "testing2"), persisted);
+
+        // File has to stay even after close
+        assertTrue(Files.exists(tmpPersistFile));
+    }
+
+    @Test
+    public void testRestore() throws Exception {
+        final ContainerNode normalizedNodeOptional = JsonUtils
+            .readJsonRoot(effectiveSchemaContext, getClass().getResourceAsStream("/expected-persisted-output.txt"));
+        assertEquals(getData("testing"), normalizedNodeOptional);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testRestoreInvalidFile() throws Exception {
+        JsonUtils.readJsonRoot(effectiveSchemaContext, getClass().getResourceAsStream("/test-persistence.yang"));
+    }
+
+    private ContainerNode getData(final String stringValue) {
+        return Builders.containerBuilder()
+            .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(ROOT_QNAME))
+            .withChild(Builders.containerBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TOP_CONTAINER_NAME))
+                .withChild(ImmutableNodes.leafNode(STRING_LEAF_QNAME, stringValue))
+                .build())
+            .withChild(Builders.containerBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TOP_CONTAINER2_NAME))
+                .withChild(ImmutableNodes.leafNode(STRING_LEAF_QNAME, stringValue))
+                .build())
+            .build();
+    }
+}
\ No newline at end of file
diff --git a/v3po/translate-utils/src/test/resources/expected-persisted-output.txt b/v3po/translate-utils/src/test/resources/expected-persisted-output.txt
new file mode 100644 (file)
index 0000000..f0f5902
--- /dev/null
@@ -0,0 +1,8 @@
+{
+  "test-persistence:top-container": {
+    "string": "testing"
+  },
+  "test-persistence:top-container2": {
+    "string": "testing"
+  }
+}
\ No newline at end of file
@@ -13,4 +13,10 @@ module test-persistence {
         }
     }
 
+    container top-container2 {
+        leaf string {
+            type string;
+        }
+    }
+
 }
index 3cb6f14..d760401 100644 (file)
@@ -43,5 +43,9 @@ public interface DataTreeInitializer extends AutoCloseable {
         public InitializeException(final String message, final Throwable cause) {
             super(message, cause);
         }
+
+        public InitializeException(final String msg) {
+            super(msg);
+        }
     }
 }
index fde2a28..9ecbe0c 100644 (file)
@@ -43,6 +43,8 @@ public class InterfacesInitializer extends AbstractDataTreeConverter<InterfacesS
                 InstanceIdentifier.create(Interfaces.class));
     }
 
+    // TODO move to v3po2vpp
+
     @Override
     protected Interfaces convert(final InterfacesState operationalData) {
         LOG.debug("InterfacesInitializer.convert()");
diff --git a/v3po/vpp-cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/RestoringInitializer.java b/v3po/vpp-cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/RestoringInitializer.java
new file mode 100644 (file)
index 0000000..eed2231
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.vpp.data.init;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import io.fd.honeycomb.v3po.translate.util.JsonUtils;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.RestorationType;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+
+public class RestoringInitializer implements DataTreeInitializer {
+
+    private final SchemaService schemaService;
+    private final Path path;
+    private final DOMDataBroker dataTree;
+    private final RestorationType restorationType;
+    private final LogicalDatastoreType datastoreType;
+
+    public RestoringInitializer(@Nonnull final SchemaService schemaService,
+                                @Nonnull final Path path,
+                                @Nonnull final DOMDataBroker dataTree,
+                                @Nonnull final RestorationType restorationType,
+                                @Nonnull final LogicalDatastoreType datastoreType) {
+        this.schemaService = schemaService;
+        this.datastoreType = datastoreType;
+        this.path = checkStorage(path);
+        this.dataTree = dataTree;
+        this.restorationType = restorationType;
+    }
+
+    private Path checkStorage(final Path path) {
+        try {
+            if(Files.exists(path)) {
+                checkArgument(!Files.isDirectory(path), "File %s is a directory", path);
+                checkArgument(Files.isReadable(path), "File %s is not readable", path);
+            } else {
+                return checkStorage(Files.createFile(path));
+            }
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Cannot use " + path + " for restoring data", e);
+        }
+
+        return path;
+    }
+
+    @Override
+    public void initialize() throws InitializeException {
+        if(!Files.exists(path)) {
+            return;
+        }
+
+        try {
+            final ContainerNode containerNode = JsonUtils
+                .readJsonRoot(schemaService.getGlobalContext(), Files.newInputStream(path, StandardOpenOption.READ));
+
+            final DOMDataWriteTransaction domDataWriteTransaction = dataTree.newWriteOnlyTransaction();
+            for (DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> dataContainerChild : containerNode
+                .getValue()) {
+                final YangInstanceIdentifier iid = YangInstanceIdentifier.create(dataContainerChild.getIdentifier());
+                switch (restorationType) {
+                    case Merge:
+                        domDataWriteTransaction.merge(datastoreType, iid, dataContainerChild);
+                        break;
+                    case Put:
+                        domDataWriteTransaction.put(datastoreType, iid, dataContainerChild);
+                        break;
+                    default:
+                        throw new InitializeException(
+                            "Unable to initialize data using " + restorationType + " restoration strategy. Unsupported");
+                }
+            }
+
+            // Block here to prevent subsequent initializers processing before context is fully restored
+            domDataWriteTransaction.submit().checkedGet();
+
+        } catch (IOException | TransactionCommitFailedException e) {
+            throw new InitializeException("Unable to restore data from " + path, e);
+        }
+    }
+
+    @Override
+    public void close() {}
+}
index 77bb3a5..d7a6787 100644 (file)
@@ -42,6 +42,8 @@ public class VppInitializer extends AbstractDataTreeConverter<VppState, Vpp> {
         super(bindingDataBroker, InstanceIdentifier.create(VppState.class), InstanceIdentifier.create(Vpp.class));
     }
 
+    // TODO move to v3po2vpp
+
     @Override
     protected Vpp convert(final VppState operationalData) {
         LOG.debug("VppInitializer.convert()");
diff --git a/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModule.java b/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModule.java
new file mode 100644 (file)
index 0000000..d80b9ed
--- /dev/null
@@ -0,0 +1,55 @@
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407;
+
+import io.fd.honeycomb.v3po.vpp.data.init.InitializerRegistry;
+import io.fd.honeycomb.v3po.vpp.data.init.InitializerRegistryImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+* Initializer registry, delegating initialization to a list of initializers
+*/
+public class ConfigurationInitializerRegistryModule extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.AbstractConfigurationInitializerRegistryModule {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ConfigurationInitializerRegistryModule.class);
+
+    public ConfigurationInitializerRegistryModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public ConfigurationInitializerRegistryModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.ConfigurationInitializerRegistryModule oldModule, java.lang.AutoCloseable oldInstance) {
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    public void customValidation() {
+        // add custom validation form module attributes here.
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        LOG.info("VppConfigurationInitializerModule.createInstance(): initialization started");
+
+        final InitializerRegistry initializer = new InitializerRegistryImpl(getInitializersDependency());
+
+        try {
+            // Initialize contexts first so that other initializers can find any relevant mapping before initializing
+            // configuration to what is already in VPP
+            getPersistedContextInitializerDependency().initialize();
+            LOG.info("Persisted context restored successfully");
+            // Initialize all registered initializers
+            initializer.initialize();
+            LOG.info("VPP configuration initialized successfully from VPP");
+            // Initialize stored configuration on top
+            // FIXME uncomment and test
+//            getPersistedConfigInitializerDependency().initialize();
+            LOG.info("Persisted configuration restored successfully");
+        } catch (Exception e) {
+            LOG.warn("Failed to initialize config", e);
+        }
+
+        LOG.info("Honeycomb initialized");
+
+        return initializer;
+    }
+
+}
diff --git a/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModuleFactory.java b/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModuleFactory.java
new file mode 100644 (file)
index 0000000..f07be95
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: vpp-cfg-init yang module local name: cfg-initializer-registry
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed May 18 14:43:49 CEST 2016
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407;
+public class ConfigurationInitializerRegistryModuleFactory extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.AbstractConfigurationInitializerRegistryModuleFactory {
+
+}
diff --git a/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/InterfacesConfigurationInitializerModule.java b/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/InterfacesConfigurationInitializerModule.java
new file mode 100644 (file)
index 0000000..51a7c48
--- /dev/null
@@ -0,0 +1,24 @@
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407;
+
+import io.fd.honeycomb.v3po.vpp.data.init.InterfacesInitializer;
+
+public class InterfacesConfigurationInitializerModule extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.AbstractInterfacesConfigurationInitializerModule {
+    public InterfacesConfigurationInitializerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public InterfacesConfigurationInitializerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.InterfacesConfigurationInitializerModule oldModule, java.lang.AutoCloseable oldInstance) {
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    public void customValidation() {
+        // add custom validation form module attributes here.
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        return new InterfacesInitializer(getBindingDataBrokerDependency());
+    }
+
+}
diff --git a/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/InterfacesConfigurationInitializerModuleFactory.java b/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/InterfacesConfigurationInitializerModuleFactory.java
new file mode 100644 (file)
index 0000000..b749479
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: vpp-cfg-init yang module local name: interfaces-cfg-initializer
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed May 18 14:43:49 CEST 2016
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407;
+public class InterfacesConfigurationInitializerModuleFactory extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.AbstractInterfacesConfigurationInitializerModuleFactory {
+
+}
diff --git a/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModule.java b/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModule.java
new file mode 100644 (file)
index 0000000..188d164
--- /dev/null
@@ -0,0 +1,38 @@
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407;
+
+import io.fd.honeycomb.v3po.vpp.data.init.RestoringInitializer;
+import java.nio.file.InvalidPathException;
+import java.nio.file.Paths;
+import org.opendaylight.controller.config.api.JmxAttributeValidationException;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.api.rev160411.DatatreeType;
+
+/**
+* Initializer restoring data from a persisted file
+*/
+public class PersistedFileInitializerModule extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.AbstractPersistedFileInitializerModule {
+    public PersistedFileInitializerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public PersistedFileInitializerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.PersistedFileInitializerModule oldModule, java.lang.AutoCloseable oldInstance) {
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    public void customValidation() {
+        try {
+            Paths.get(getPersistFilePath());
+        } catch (InvalidPathException e) {
+            throw new JmxAttributeValidationException("Invalid persist path", e, persistFilePathJmxAttribute);
+        }
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        return new RestoringInitializer(getSchemaServiceDependency(), Paths.get(getPersistFilePath()),
+            getDomDataBrokerDependency(), getRestorationType(),
+            getDatastoreType() == DatatreeType.Config ? LogicalDatastoreType.CONFIGURATION : LogicalDatastoreType.OPERATIONAL);
+    }
+
+}
diff --git a/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModuleFactory.java b/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModuleFactory.java
new file mode 100644 (file)
index 0000000..1d7a3c9
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: vpp-cfg-init yang module local name: persisted-file-initializer
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed May 18 13:48:52 CEST 2016
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407;
+public class PersistedFileInitializerModuleFactory extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.AbstractPersistedFileInitializerModuleFactory {
+
+}
index ae83cb3..cc4f183 100644 (file)
@@ -1,12 +1,6 @@
 package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407;
 
-import io.fd.honeycomb.v3po.vpp.data.init.DataTreeInitializer;
-import io.fd.honeycomb.v3po.vpp.data.init.InitializerRegistry;
-import io.fd.honeycomb.v3po.vpp.data.init.InitializerRegistryImpl;
-import io.fd.honeycomb.v3po.vpp.data.init.InterfacesInitializer;
 import io.fd.honeycomb.v3po.vpp.data.init.VppInitializer;
-import java.util.Arrays;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -34,24 +28,7 @@ public class VppConfigurationInitializerModule extends
 
     @Override
     public java.lang.AutoCloseable createInstance() {
-        LOG.info("VppConfigurationInitializerModule.createInstance(): initialization started");
-        final DataBroker bindingDataBroker = getBindingDataBrokerDependency();
-
-        final VppInitializer vppInitializer = new VppInitializer(bindingDataBroker);
-        final InterfacesInitializer interfacesInitializer = new InterfacesInitializer(bindingDataBroker);
-
-        // TODO make configurable
-        final InitializerRegistry initializer =
-                new InitializerRegistryImpl(Arrays.<DataTreeInitializer>asList(vppInitializer, interfacesInitializer));
-
-        try {
-            initializer.initialize();
-        } catch (Exception e) {
-            LOG.warn("Failed to initialize config", e);
-        }
-        LOG.info("VppConfigurationInitializerModule.createInstance(): initialization completed");
-
-        return initializer;
+        return new VppInitializer(getBindingDataBrokerDependency());
     }
 
 }
index e4ce95a..024c930 100644 (file)
@@ -5,6 +5,7 @@ module vpp-cfg-init {
 
     import config { prefix config; revision-date 2013-04-05; }
     import opendaylight-md-sal-binding { prefix md-sal-binding; revision-date 2013-10-28;}
+    import opendaylight-md-sal-dom {prefix dom;}
     import translate-api { prefix tapi; revision-date 2016-04-06; }
     import data-api { prefix dapi; revision-date 2016-04-11; }
 
@@ -16,20 +17,43 @@ module vpp-cfg-init {
             "Initial revision";
     }
 
-    identity vpp-cfg-initializer {
+    identity cfg-initializer {
         base "config:service-type";
-        config:java-class io.fd.honeycomb.v3po.vpp.data.init.InitializerRegistry;
+        config:java-class io.fd.honeycomb.v3po.vpp.data.init.DataTreeInitializer;
     }
 
-    identity vpp-cfg-initializer-impl {
+    // TODO move to v3po2vpp
+    identity vpp-cfg-initializer {
         base config:module-type;
-        config:provided-service vpp-cfg-initializer;
+        config:provided-service cfg-initializer;
         config:java-name-prefix VppConfigurationInitializer;
     }
 
     augment "/config:modules/config:module/config:configuration" {
-        case vpp-cfg-initializer-impl {
-            when "/config:modules/config:module/config:type = 'vpp-cfg-initializer-impl'";
+        case vpp-cfg-initializer {
+            when "/config:modules/config:module/config:type = 'vpp-cfg-initializer'";
+
+             container binding-data-broker {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity md-sal-binding:binding-async-data-broker;
+                    }
+                }
+             }
+        }
+    }
+
+    // TODO move to v3po2vpp
+    identity interfaces-cfg-initializer {
+        base config:module-type;
+        config:provided-service cfg-initializer;
+        config:java-name-prefix InterfacesConfigurationInitializer;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case interfaces-cfg-initializer {
+            when "/config:modules/config:module/config:type = 'interfaces-cfg-initializer'";
 
              container binding-data-broker {
                 uses config:service-ref {
@@ -42,4 +66,95 @@ module vpp-cfg-init {
         }
     }
 
+    identity cfg-initializer-registry {
+        base config:module-type;
+        config:provided-service cfg-initializer;
+        config:java-name-prefix ConfigurationInitializerRegistry;
+        description "Initializer registry, delegating initialization to a list of initializers";
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case cfg-initializer-registry {
+            when "/config:modules/config:module/config:type = 'cfg-initializer-registry'";
+
+             list initializers {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity cfg-initializer;
+                    }
+                }
+             }
+
+             container persisted-context-initializer {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity cfg-initializer;
+                    }
+                }
+             }
+
+             container persisted-config-initializer {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity cfg-initializer;
+                    }
+                }
+             }
+        }
+    }
+
+    identity persisted-file-initializer {
+        base config:module-type;
+        config:provided-service cfg-initializer;
+        description "Initializer restoring data from a persisted file";
+    }
+
+    typedef restoration-type {
+        type enumeration {
+             enum merge;
+             enum put;
+         }
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case persisted-file-initializer {
+            when "/config:modules/config:module/config:type = 'persisted-file-initializer'";
+
+            container dom-data-broker {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity dom:dom-async-data-broker;
+                    }
+                }
+            }
+
+            container schema-service {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity dom:schema-service;
+                    }
+                }
+            }
+
+            leaf persist-file-path {
+                type string;
+            }
+
+            leaf restoration-type {
+                type restoration-type;
+                default merge;
+            }
+
+
+            leaf datastore-type {
+                type dapi:datatree-type;
+            }
+        }
+    }
+
 }
\ No newline at end of file