From f9b2551eae7b4410b6910a05f19413b9b83137d4 Mon Sep 17 00:00:00 2001 From: Maros Marsalek Date: Wed, 18 May 2016 15:05:51 +0200 Subject: HONEYCOMB-61: Restore configuration and context from persisted files Change-Id: I6edce127f8895f5d65998b4be71a0a111ca2e8bb Signed-off-by: Maros Marsalek --- v3po/data-impl/pom.xml | 4 -- .../v3po/data/impl/PersistingDataTreeAdapter.java | 51 +++------------- .../honeycomb/v3po/data/impl/WriteTransaction.java | 4 +- .../impl/rev160411/InMemoryDataTreeModule.java | 1 + .../rev160411/PersistingDataTreeAdapterModule.java | 8 ++- v3po/data-impl/src/main/yang/data-impl.yang | 9 +-- .../data/impl/PersistingDataTreeAdapterTest.java | 68 ---------------------- .../test/resources/expected-persisted-output.txt | 5 -- .../src/test/resources/test-persistence.yang | 16 ----- 9 files changed, 19 insertions(+), 147 deletions(-) delete mode 100644 v3po/data-impl/src/test/resources/expected-persisted-output.txt delete mode 100644 v3po/data-impl/src/test/resources/test-persistence.yang (limited to 'v3po/data-impl') diff --git a/v3po/data-impl/pom.xml b/v3po/data-impl/pom.xml index 46faab7a2..1d716a6d9 100644 --- a/v3po/data-impl/pom.xml +++ b/v3po/data-impl/pom.xml @@ -48,10 +48,6 @@ org.opendaylight.mdsal mdsal-binding-dom-codec - - org.opendaylight.yangtools - yang-data-codec-gson - org.opendaylight.controller sal-core-api diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java index a54b7f148..df5bbee4b 100644 --- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java +++ b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java @@ -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 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(); diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java index 3644a9fe7..ac4ba9049 100644 --- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java +++ b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java @@ -77,11 +77,11 @@ final class WriteTransaction implements DOMDataWriteTransaction { final java.util.function.Consumer 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; } diff --git a/v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/InMemoryDataTreeModule.java b/v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/InMemoryDataTreeModule.java index 54c830ec0..956aa90f4 100644 --- a/v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/InMemoryDataTreeModule.java +++ b/v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/InMemoryDataTreeModule.java @@ -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; diff --git a/v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/PersistingDataTreeAdapterModule.java b/v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/PersistingDataTreeAdapterModule.java index aa57f4d9b..145fc4345 100644 --- a/v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/PersistingDataTreeAdapterModule.java +++ b/v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/PersistingDataTreeAdapterModule.java @@ -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 diff --git a/v3po/data-impl/src/main/yang/data-impl.yang b/v3po/data-impl/src/main/yang/data-impl.yang index 3af9d8d3f..a6b217a84 100644 --- a/v3po/data-impl/src/main/yang/data-impl.yang +++ b/v3po/data-impl/src/main/yang/data-impl.yang @@ -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; } } } diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapterTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapterTest.java index 986d7cfb1..523d9dd70 100644 --- a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapterTest.java +++ b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapterTest.java @@ -16,17 +16,12 @@ 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 index fb21d61e8..000000000 --- a/v3po/data-impl/src/test/resources/expected-persisted-output.txt +++ /dev/null @@ -1,5 +0,0 @@ -{ - "test-persistence:top-container": { - "string": "testing" - } -} \ No newline at end of file diff --git a/v3po/data-impl/src/test/resources/test-persistence.yang b/v3po/data-impl/src/test/resources/test-persistence.yang deleted file mode 100644 index b7dbbb1bc..000000000 --- a/v3po/data-impl/src/test/resources/test-persistence.yang +++ /dev/null @@ -1,16 +0,0 @@ -module test-persistence { - yang-version 1; - namespace "urn:opendaylight:params:xml:ns:yang:test:persistence"; - prefix "tp"; - - revision "2015-01-05" { - description "Initial revision"; - } - - container top-container { - leaf string { - type string; - } - } - -} -- cgit 1.2.3-korg