Added xml storage adapter bundle fragments for config persister. 70/3670/1
authorMaros Marsalek <mmarsale@cisco.com>
Thu, 12 Dec 2013 10:12:11 +0000 (11:12 +0100)
committerMaros Marsalek <mmarsale@cisco.com>
Thu, 12 Dec 2013 10:26:12 +0000 (11:26 +0100)
File and Directory based xml adapters are now available.
Only File xml adapter is used so far to persist current configuration.

Directory based persister is still using plain text to keep backwards compatibility.

Change-Id: If1a83701ce23d36313c943e9fe49bd4e704afe27
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
27 files changed:
opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryPersister.java
opendaylight/config/config-persister-directory-xml-adapter/pom.xml [new file with mode: 0644]
opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryPersister.java [new file with mode: 0644]
opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryStorageAdapter.java [new file with mode: 0644]
opendaylight/config/config-persister-directory-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/xml/DirectoryStorageAdapterTest.java [new file with mode: 0644]
opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/oneFile/controller.config.xml [new file with mode: 0644]
opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config1.xml [new file with mode: 0644]
opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config2.xml [new file with mode: 0644]
opendaylight/config/config-persister-file-xml-adapter/pom.xml [new file with mode: 0644]
opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/XmlFileStorageAdapter.java [new file with mode: 0644]
opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/CapabilityHandler.java [new file with mode: 0644]
opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/Config.java [new file with mode: 0644]
opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/ConfigSnapshot.java [new file with mode: 0644]
opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/PersistException.java [new file with mode: 0644]
opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/SnapshotHandler.java [new file with mode: 0644]
opendaylight/config/config-persister-file-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/file/xml/FileStorageAdapterTest.java [new file with mode: 0644]
opendaylight/config/pom.xml
opendaylight/distribution/opendaylight/pom.xml
opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributesConstants.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java
opendaylight/netconf/config-persister-impl/pom.xml
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregator.java
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregatorTest.java
opendaylight/netconf/config-persister-impl/src/test/resources/test2.properties
opendaylight/netconf/config-persister-impl/src/test/resources/test3.properties

index 39595ed..a123eb9 100644 (file)
@@ -139,7 +139,7 @@ class MyLineProcessor implements com.google.common.io.LineProcessor<String> {
     }
 
     private void checkFileConsistency(){
-        checkState(inCapabilities, "File {} is missing delimiters in this order: {}", fileNameForReporting,
+        checkState(inCapabilities, "File %s is missing delimiters in this order: %s", fileNameForReporting,
                 Arrays.asList(DirectoryPersister.MODULES_START,
                         DirectoryPersister.SERVICES_START,
                         DirectoryPersister.CAPABILITIES_START));
diff --git a/opendaylight/config/config-persister-directory-xml-adapter/pom.xml b/opendaylight/config/config-persister-directory-xml-adapter/pom.xml
new file mode 100644 (file)
index 0000000..b2ea632
--- /dev/null
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>config-subsystem</artifactId>
+        <groupId>org.opendaylight.controller</groupId>
+        <version>0.2.3-SNAPSHOT</version>
+        <relativePath>..</relativePath>
+    </parent>
+    <artifactId>config-persister-directory-xml-adapter</artifactId>
+    <name>${project.artifactId}</name>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <!-- compile dependencies -->
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>config-persister-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>config-persister-file-xml-adapter</artifactId>
+            <version>${config.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.eclipse.persistence</groupId>
+            <artifactId>org.eclipse.persistence.moxy</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.persistence</groupId>
+            <artifactId>org.eclipse.persistence.core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+        </dependency>
+
+        <!-- test dependencies -->
+        <dependency>
+            <groupId>org.opendaylight.bgpcep</groupId>
+            <artifactId>mockito-configuration</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <!-- workaround for creating version according to OSGi specification (major.minor.micro[.qualifier] -->
+            <plugin>
+                <groupId>org.codehaus.groovy.maven</groupId>
+                <artifactId>gmaven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>execute</goal>
+                        </goals>
+                        <configuration>
+                            <source>
+                                System.setProperty("osgiversion", "${project.version}".replace('-', '.'))
+                            </source>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Fragment-Host>${project.groupId}.config-persister-impl;bundle-version=${osgiversion}
+                        </Fragment-Host>
+                        <Provide-Capability>org.opendaylight.controller.config.persister.storage.adapter
+                        </Provide-Capability>
+                        <Import-Package>
+                            com.google.common.base,
+                            com.google.common.io,
+                            org.apache.commons.io,
+                            org.opendaylight.controller.config.persist.api,
+                            org.slf4j,
+                            com.google.common.collect,
+                            javax.xml.bind,
+                            javax.xml.bind.annotation,
+                            javax.xml.transform,
+                            javax.xml.transform.stream,
+                            org.eclipse.persistence.jaxb,
+                            org.apache.commons.lang3
+                        </Import-Package>
+                        <Private-Package>
+                            org.opendaylight.controller.config.persist.storage.file.xml.model,
+                        </Private-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryPersister.java b/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryPersister.java
new file mode 100644 (file)
index 0000000..f6f6de9
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.persist.storage.directory.xml;
+
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+import org.opendaylight.controller.config.persist.api.Persister;
+import org.opendaylight.controller.config.persist.storage.file.xml.model.ConfigSnapshot;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.SortedSet;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+public class XmlDirectoryPersister implements Persister {
+    private static final Logger logger = LoggerFactory.getLogger(XmlDirectoryPersister.class);
+
+    private final File storage;
+
+    public XmlDirectoryPersister(File storage) {
+        checkArgument(storage.exists() && storage.isDirectory(), "Storage directory does not exist: " + storage);
+        this.storage = storage;
+    }
+
+    @Override
+    public void persistConfig(ConfigSnapshotHolder holder) throws IOException {
+        throw new UnsupportedOperationException("This adapter is read only. Please set readonly=true on " + getClass());
+    }
+
+    @Override
+    public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
+        File[] filesArray = storage.listFiles();
+        if (filesArray == null || filesArray.length == 0) {
+            return Collections.emptyList();
+        }
+        List<File> sortedFiles = new ArrayList<>(Arrays.asList(filesArray));
+        Collections.sort(sortedFiles);
+        // combine all found files
+        logger.debug("Reading files in following order: {}", sortedFiles);
+
+        List<ConfigSnapshotHolder> result = new ArrayList<>();
+        for (File file : sortedFiles) {
+            logger.trace("Adding file '{}' to combined result", file);
+            ConfigSnapshotHolder h = fromXmlSnapshot(file);
+            result.add(h);
+        }
+        return result;
+    }
+
+    private ConfigSnapshotHolder fromXmlSnapshot(File file) {
+        try {
+            JAXBContext jaxbContext = JAXBContext.newInstance(ConfigSnapshot.class);
+            Unmarshaller um = jaxbContext.createUnmarshaller();
+
+            return asHolder((ConfigSnapshot) um.unmarshal(file));
+        } catch (JAXBException e) {
+            logger.warn("Unable to restore configuration snapshot from {}", file, e);
+            throw new IllegalStateException("Unable to restore configuration snapshot from " + file, e);
+        }
+    }
+
+    private ConfigSnapshotHolder asHolder(final ConfigSnapshot unmarshalled) {
+        return new ConfigSnapshotHolder() {
+            @Override
+            public String getConfigSnapshot() {
+                return unmarshalled.getConfigSnapshot();
+            }
+
+            @Override
+            public SortedSet<String> getCapabilities() {
+                return unmarshalled.getCapabilities();
+            }
+
+            @Override
+            public String toString() {
+                return unmarshalled.toString();
+            }
+        };
+    }
+
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String toString() {
+        final StringBuffer sb = new StringBuffer("XmlDirectoryPersister{");
+        sb.append("storage=").append(storage);
+        sb.append('}');
+        return sb.toString();
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryStorageAdapter.java b/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryStorageAdapter.java
new file mode 100644 (file)
index 0000000..ab6fb15
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.config.persist.storage.directory.xml;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.config.persist.api.Persister;
+import org.opendaylight.controller.config.persist.api.PropertiesProvider;
+import org.opendaylight.controller.config.persist.api.StorageAdapter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+
+/**
+ * StorageAdapter that retrieves initial configuration from a directory. If multiple files are present, snapshot and
+ * required capabilities will be merged together. Writing to this persister is not supported.
+ */
+public class XmlDirectoryStorageAdapter implements StorageAdapter {
+    private static final Logger logger = LoggerFactory.getLogger(XmlDirectoryStorageAdapter.class);
+
+    public static final String DIRECTORY_STORAGE_PROP = "directoryStorage";
+
+
+    @Override
+    public Persister instantiate(PropertiesProvider propertiesProvider) {
+        String fileStorageProperty = propertiesProvider.getProperty(DIRECTORY_STORAGE_PROP);
+        Preconditions.checkNotNull(fileStorageProperty, "Unable to find " + propertiesProvider.getFullKeyForReporting(DIRECTORY_STORAGE_PROP));
+        File storage  = new File(fileStorageProperty);
+        logger.debug("Using {}", storage);
+        return new XmlDirectoryPersister(storage);
+    }
+
+}
diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/xml/DirectoryStorageAdapterTest.java b/opendaylight/config/config-persister-directory-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/xml/DirectoryStorageAdapterTest.java
new file mode 100644 (file)
index 0000000..73061f8
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.config.persist.storage.directory.xml;
+
+import org.junit.Test;
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.List;
+import java.util.SortedSet;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class DirectoryStorageAdapterTest {
+    XmlDirectoryPersister tested;
+
+    @Test
+    public void testEmptyDirectory() throws Exception {
+        File folder = new File("target/emptyFolder");
+        folder.mkdir();
+        tested = new XmlDirectoryPersister((folder));
+        assertEquals(Collections.<ConfigSnapshotHolder>emptyList(), tested.loadLastConfigs());
+
+        try {
+            tested.persistConfig(new ConfigSnapshotHolder() {
+                @Override
+                public String getConfigSnapshot() {
+                    throw new RuntimeException();
+                }
+
+                @Override
+                public SortedSet<String> getCapabilities() {
+                    throw new RuntimeException();
+                }
+            });
+            fail();
+        } catch (UnsupportedOperationException e) {
+
+        }
+    }
+
+    private File getFolder(String folderName) {
+        File result = new File(("src/test/resources/" +
+                folderName).replace("/", File.separator));
+        assertTrue(result + " is not a directory", result.isDirectory());
+        return result;
+    }
+
+    @Test
+    public void testOneFile() throws Exception {
+        File folder = getFolder("oneFile");
+        tested = new XmlDirectoryPersister((folder));
+        List<ConfigSnapshotHolder> results = tested.loadLastConfigs();
+        assertEquals(1, results.size());
+        ConfigSnapshotHolder result = results.get(0);
+        assertResult(result, "<config>1</config>", "cap1&rev", "cap2", "capa a");
+    }
+
+    private void assertResult(ConfigSnapshotHolder result, String s, String... caps) {
+        assertEquals(s, result.getConfigSnapshot().replaceAll("\\s", ""));
+        int i = 0;
+        for (String capFromSnapshot : result.getCapabilities()) {
+            assertEquals(capFromSnapshot, caps[i++]);
+        }
+    }
+
+    @Test
+    public void testTwoFiles() throws Exception {
+        File folder = getFolder("twoFiles");
+        tested = new XmlDirectoryPersister((folder));
+        List<ConfigSnapshotHolder> results = tested.loadLastConfigs();
+        assertEquals(2, results.size());
+
+        assertResult(results.get(0), "<config>1</config>", "cap1-a", "cap2-a", "capa a-a");
+        assertResult(results.get(1), "<config>2</config>", "cap1-b", "cap2-b", "capa a-b");
+
+    }
+
+}
diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/oneFile/controller.config.xml b/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/oneFile/controller.config.xml
new file mode 100644 (file)
index 0000000..aa8b14c
--- /dev/null
@@ -0,0 +1,10 @@
+<snapshot>
+    <required-capabilities>
+        <capability>cap1&amp;rev</capability>
+        <capability>cap2</capability>
+        <capability>capa a</capability>
+    </required-capabilities>
+    <configuration>
+        <config>1</config>
+    </configuration>
+</snapshot>
\ No newline at end of file
diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config1.xml b/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config1.xml
new file mode 100644 (file)
index 0000000..28f112e
--- /dev/null
@@ -0,0 +1,10 @@
+<snapshot>
+    <required-capabilities>
+        <capability>cap1-a</capability>
+        <capability>cap2-a</capability>
+        <capability>capa a-a</capability>
+    </required-capabilities>
+    <configuration>
+        <config>1</config>
+    </configuration>
+</snapshot>
\ No newline at end of file
diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config2.xml b/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config2.xml
new file mode 100644 (file)
index 0000000..8fed29d
--- /dev/null
@@ -0,0 +1,10 @@
+<snapshot>
+    <required-capabilities>
+        <capability>cap1-b</capability>
+        <capability>cap2-b</capability>
+        <capability>capa a-b</capability>
+    </required-capabilities>
+    <configuration>
+        <config>2</config>
+    </configuration>
+</snapshot>
\ No newline at end of file
diff --git a/opendaylight/config/config-persister-file-xml-adapter/pom.xml b/opendaylight/config/config-persister-file-xml-adapter/pom.xml
new file mode 100644 (file)
index 0000000..abbec38
--- /dev/null
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>config-subsystem</artifactId>
+        <groupId>org.opendaylight.controller</groupId>
+        <version>0.2.3-SNAPSHOT</version>
+        <relativePath>..</relativePath>
+    </parent>
+    <artifactId>config-persister-file-xml-adapter</artifactId>
+    <name>${project.artifactId}</name>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <!-- compile dependencies -->
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>config-persister-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.eclipse.persistence</groupId>
+            <artifactId>org.eclipse.persistence.moxy</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.persistence</groupId>
+            <artifactId>org.eclipse.persistence.core</artifactId>
+        </dependency>
+
+        <!-- test dependencies -->
+        <dependency>
+            <groupId>org.opendaylight.bgpcep</groupId>
+            <artifactId>mockito-configuration</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <!-- workaround for creating version according to OSGi specification (major.minor.micro[.qualifier] -->
+            <plugin>
+                <groupId>org.codehaus.groovy.maven</groupId>
+                <artifactId>gmaven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>execute</goal>
+                        </goals>
+                        <configuration>
+                            <source>
+                                System.setProperty("osgiversion", "${project.version}".replace('-', '.'))
+                            </source>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Fragment-Host>${project.groupId}.config-persister-impl;bundle-version=${osgiversion}
+                        </Fragment-Host>
+                        <Provide-Capability>org.opendaylight.controller.config.persister.storage.adapter
+                        </Provide-Capability>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/XmlFileStorageAdapter.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/XmlFileStorageAdapter.java
new file mode 100644 (file)
index 0000000..e75c62b
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.config.persist.storage.file.xml;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+import org.opendaylight.controller.config.persist.api.Persister;
+import org.opendaylight.controller.config.persist.api.PropertiesProvider;
+import org.opendaylight.controller.config.persist.api.StorageAdapter;
+import org.opendaylight.controller.config.persist.storage.file.xml.model.Config;
+import org.opendaylight.controller.config.persist.storage.file.xml.model.ConfigSnapshot;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.SortedSet;
+
+/**
+ * StorageAdapter that stores configuration in an xml file.
+ */
+public class XmlFileStorageAdapter implements StorageAdapter, Persister {
+    private static final Logger logger = LoggerFactory.getLogger(XmlFileStorageAdapter.class);
+
+    public static final String FILE_STORAGE_PROP = "fileStorage";
+    public static final String NUMBER_OF_BACKUPS = "numberOfBackups";
+
+    private static Integer numberOfStoredBackups;
+    private File storage;
+
+    @Override
+    public Persister instantiate(PropertiesProvider propertiesProvider) {
+        File storage = extractStorageFileFromProperties(propertiesProvider);
+        logger.debug("Using file {}", storage.getAbsolutePath());
+        // Create file if it does not exist
+        File parentFile = storage.getAbsoluteFile().getParentFile();
+        if (parentFile.exists() == false) {
+            logger.debug("Creating parent folders {}", parentFile);
+            parentFile.mkdirs();
+        }
+        if (storage.exists() == false) {
+            logger.debug("Storage file does not exist, creating empty file");
+            try {
+                boolean result = storage.createNewFile();
+                if (result == false)
+                    throw new RuntimeException("Unable to create storage file " + storage);
+            } catch (IOException e) {
+                throw new RuntimeException("Unable to create storage file " + storage, e);
+            }
+        }
+        if (numberOfStoredBackups == 0) {
+            throw new RuntimeException(NUMBER_OF_BACKUPS
+                    + " property should be either set to positive value, or ommited. Can not be set to 0.");
+        }
+        setFileStorage(storage);
+        return this;
+    }
+
+    @VisibleForTesting
+    public void setFileStorage(File storage) {
+        this.storage = storage;
+    }
+
+    @VisibleForTesting
+    public void setNumberOfBackups(Integer numberOfBackups) {
+        numberOfStoredBackups = numberOfBackups;
+    }
+
+    private static File extractStorageFileFromProperties(PropertiesProvider propertiesProvider) {
+        String fileStorageProperty = propertiesProvider.getProperty(FILE_STORAGE_PROP);
+        Preconditions.checkNotNull(fileStorageProperty, "Unable to find " + propertiesProvider.getFullKeyForReporting(FILE_STORAGE_PROP));
+        File result = new File(fileStorageProperty);
+        String numberOfBackupsAsString = propertiesProvider.getProperty(NUMBER_OF_BACKUPS);
+        if (numberOfBackupsAsString != null) {
+            numberOfStoredBackups = Integer.valueOf(numberOfBackupsAsString);
+        } else {
+            numberOfStoredBackups = Integer.MAX_VALUE;
+        }
+        logger.trace("Property {} set to {}", NUMBER_OF_BACKUPS, numberOfStoredBackups);
+        return result;
+    }
+
+    @Override
+    public void persistConfig(ConfigSnapshotHolder holder) throws IOException {
+        Preconditions.checkNotNull(storage, "Storage file is null");
+
+        Config cfg = Config.fromXml(storage);
+        cfg.addConfigSnapshot(ConfigSnapshot.fromConfigSnapshot(holder), numberOfStoredBackups);
+        cfg.toXml(storage);
+    }
+
+    @Override
+    public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
+        Preconditions.checkNotNull(storage, "Storage file is null");
+
+        if (!storage.exists()) {
+            return Collections.emptyList();
+        }
+
+        Optional<ConfigSnapshot> lastSnapshot = Config.fromXml(storage).getLastSnapshot();
+
+        if (lastSnapshot.isPresent())
+            return Lists.newArrayList(toConfigSnapshot(lastSnapshot.get()));
+        else
+            return Collections.emptyList();
+    }
+
+
+    public ConfigSnapshotHolder toConfigSnapshot(final ConfigSnapshot configSnapshot) {
+        return new ConfigSnapshotHolder() {
+            @Override
+            public String getConfigSnapshot() {
+                return configSnapshot.getConfigSnapshot();
+            }
+
+            @Override
+            public SortedSet<String> getCapabilities() {
+                return configSnapshot.getCapabilities();
+            }
+
+            @Override
+            public String toString() {
+                return configSnapshot.toString();
+            }
+        };
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String toString() {
+        return "XmlFileStorageAdapter [storage=" + storage + "]";
+    }
+
+}
diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/CapabilityHandler.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/CapabilityHandler.java
new file mode 100644 (file)
index 0000000..d384df6
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.persist.storage.file.xml.model;
+
+import javax.xml.bind.ValidationEventHandler;
+import javax.xml.bind.annotation.DomHandler;
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+class CapabilityHandler implements DomHandler<String, StreamResult> {
+
+    private static final String START_TAG = "<capability>";
+    private static final String END_TAG = "</capability>";
+
+    private StringWriter xmlWriter = new StringWriter();
+
+    public StreamResult createUnmarshaller(ValidationEventHandler errorHandler) {
+        xmlWriter.getBuffer().setLength(0);
+        return new StreamResult(xmlWriter);
+    }
+
+    public String getElement(StreamResult rt) {
+        String xml = rt.getWriter().toString();
+        int beginIndex = xml.indexOf(START_TAG) + START_TAG.length();
+        int endIndex = xml.indexOf(END_TAG);
+        return xml.substring(beginIndex, endIndex);
+    }
+
+    public Source marshal(String n, ValidationEventHandler errorHandler) {
+        try {
+            String xml = START_TAG + n.trim() + END_TAG;
+            StringReader xmlReader = new StringReader(xml);
+            return new StreamSource(xmlReader);
+        } catch(Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+}
diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/Config.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/Config.java
new file mode 100644 (file)
index 0000000..fb84651
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.persist.storage.file.xml.model;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.io.Files;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+@XmlRootElement(name = "persisted-snapshots")
+public final class Config {
+
+    private List<ConfigSnapshot> snapshots;
+
+    Config(List<ConfigSnapshot> snapshots) {
+        this.snapshots = snapshots;
+    }
+
+    public Config() {
+        this.snapshots = Lists.newArrayList();
+    }
+
+    @XmlElement(name = "snapshot")
+    @XmlElementWrapper(name = "snapshots")
+    public List<ConfigSnapshot> getSnapshots() {
+        return snapshots;
+    }
+
+    public void setSnapshots(List<ConfigSnapshot> snapshots) {
+        this.snapshots = snapshots;
+    }
+
+    public void toXml(File to) {
+        try {
+
+            // TODO Moxy has to be used instead of default jaxb impl due to a bug
+            // default implementation has a bug that prevents from serializing xml in a string
+            JAXBContext jaxbContext = org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(new Class[]{Config.class}, null);
+
+            Marshaller marshaller = jaxbContext.createMarshaller();
+
+            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+
+            marshaller.marshal(this, to);
+        } catch (JAXBException e) {
+            throw new PersistException("Unable to persist configuration", e);
+        }
+    }
+
+    public static Config fromXml(File from) {
+        if(isEmpty(from))
+            return new Config();
+
+        try {
+            JAXBContext jaxbContext = JAXBContext.newInstance(Config.class);
+            Unmarshaller um = jaxbContext.createUnmarshaller();
+
+            return (Config) um.unmarshal(from);
+        } catch (JAXBException e) {
+            throw new PersistException("Unable to restore configuration", e);
+        }
+    }
+
+    private static boolean isEmpty(File from) {
+        return from.length() == 0 || isBlank(from);
+    }
+
+    private static boolean isBlank(File from) {
+        try {
+            return StringUtils.isBlank(Files.toString(from, Charsets.UTF_8));
+        } catch (IOException e) {
+            throw new IllegalStateException("Unexpected error reading file" + from, e);
+        }
+    }
+
+    public Optional<ConfigSnapshot> getLastSnapshot() {
+        ConfigSnapshot last = Iterables.getLast(snapshots, null);
+        return last == null ? Optional.<ConfigSnapshot>absent() : Optional.of(last);
+    }
+
+    public void addConfigSnapshot(ConfigSnapshot snap, int numberOfStoredBackups) {
+        if(shouldReplaceLast(numberOfStoredBackups) && snapshots.isEmpty() == false) {
+            snapshots.remove(0);
+        }
+        snapshots.add(snap);
+    }
+
+    private boolean shouldReplaceLast(int numberOfStoredBackups) {
+        return numberOfStoredBackups == snapshots.size();
+    }
+}
diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/ConfigSnapshot.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/ConfigSnapshot.java
new file mode 100644 (file)
index 0000000..4197600
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.persist.storage.file.xml.model;
+
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+
+import javax.xml.bind.annotation.XmlAnyElement;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.SortedSet;
+
+@XmlRootElement(name = "snapshot")
+public class ConfigSnapshot {
+
+    private String configSnapshot;
+    private SortedSet<String> capabilities;
+
+    ConfigSnapshot(String configXml, SortedSet<String> capabilities) {
+        this.configSnapshot = configXml;
+        this.capabilities = capabilities;
+    }
+
+    public ConfigSnapshot() {
+    }
+
+    public static ConfigSnapshot fromConfigSnapshot(ConfigSnapshotHolder cfg) {
+        return new ConfigSnapshot(cfg.getConfigSnapshot(), cfg.getCapabilities());
+    }
+
+    @XmlAnyElement(SnapshotHandler.class)
+    public String getConfigSnapshot() {
+        return configSnapshot;
+    }
+
+    public void setConfigSnapshot(String configSnapshot) {
+        this.configSnapshot = configSnapshot;
+    }
+
+    @XmlElement(name = "capability")
+    @XmlElementWrapper(name = "required-capabilities")
+    public SortedSet<String> getCapabilities() {
+        return capabilities;
+    }
+
+    public void setCapabilities(SortedSet<String> capabilities) {
+        this.capabilities = capabilities;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuffer sb = new StringBuffer("ConfigSnapshot{");
+        sb.append("configSnapshot='").append(configSnapshot).append('\'');
+        sb.append(", capabilities=").append(capabilities);
+        sb.append('}');
+        return sb.toString();
+    }
+}
diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/PersistException.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/PersistException.java
new file mode 100644 (file)
index 0000000..29d6232
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.persist.storage.file.xml.model;
+
+final class PersistException extends RuntimeException {
+
+    public PersistException(String s, Exception e) {
+        super(s, e);
+    }
+}
diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/SnapshotHandler.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/SnapshotHandler.java
new file mode 100644 (file)
index 0000000..dd39410
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.persist.storage.file.xml.model;
+
+import javax.xml.bind.ValidationEventHandler;
+import javax.xml.bind.annotation.DomHandler;
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+class SnapshotHandler implements DomHandler<String, StreamResult> {
+
+    private static final String START_TAG = "<configuration>";
+    private static final String END_TAG = "</configuration>";
+
+    private StringWriter xmlWriter = new StringWriter();
+
+    public StreamResult createUnmarshaller(ValidationEventHandler errorHandler) {
+        xmlWriter.getBuffer().setLength(0);
+        return new StreamResult(xmlWriter);
+    }
+
+    public String getElement(StreamResult rt) {
+        String xml = rt.getWriter().toString();
+        int beginIndex = xml.indexOf(START_TAG) + START_TAG.length();
+        int endIndex = xml.indexOf(END_TAG);
+        return xml.substring(beginIndex, endIndex);
+    }
+
+    public Source marshal(String n, ValidationEventHandler errorHandler) {
+        try {
+            String xml = START_TAG + n.trim() + END_TAG;
+            StringReader xmlReader = new StringReader(xml);
+            return new StreamSource(xmlReader);
+        } catch(Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+}
diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/file/xml/FileStorageAdapterTest.java b/opendaylight/config/config-persister-file-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/file/xml/FileStorageAdapterTest.java
new file mode 100644 (file)
index 0000000..d6bbeb3
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.config.persist.storage.file.xml;
+
+import com.google.common.base.Charsets;
+import junit.framework.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import static junit.framework.Assert.assertFalse;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+public class FileStorageAdapterTest {
+
+    private static int i;
+    private File file;
+
+    @Before
+    public void setUp() throws Exception {
+        file = Files.createTempFile("testFilePersist", ".txt").toFile();
+        if (!file.exists())
+            return;
+        com.google.common.io.Files.write("", file, Charsets.UTF_8);
+        i = 1;
+    }
+
+    @Test
+    public void testFileAdapter() throws Exception {
+        XmlFileStorageAdapter storage = new XmlFileStorageAdapter();
+        storage.setFileStorage(file);
+        storage.setNumberOfBackups(Integer.MAX_VALUE);
+        final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() {
+            @Override
+            public String getConfigSnapshot() {
+                return createConfig();
+            }
+
+            @Override
+            public SortedSet<String> getCapabilities() {
+                return createCaps();
+            }
+        };
+        storage.persistConfig(holder);
+
+        storage.persistConfig(holder);
+
+        assertEquals(27, com.google.common.io.Files.readLines(file, Charsets.UTF_8).size());
+        List<ConfigSnapshotHolder> lastConf = storage.loadLastConfigs();
+        assertEquals(1, lastConf.size());
+        ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0);
+        assertEquals("<config>2</config>",
+                configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", ""));
+        assertEquals(createCaps(), configSnapshotHolder.getCapabilities());
+
+        storage = new XmlFileStorageAdapter();
+        storage.setFileStorage(file);
+        storage.setNumberOfBackups(Integer.MAX_VALUE);
+
+        List<ConfigSnapshotHolder> last = storage.loadLastConfigs();
+        Assert.assertEquals(createCaps(), last.get(0).getCapabilities());
+    }
+
+    private SortedSet<String> createCaps() {
+        SortedSet<String> caps = new TreeSet<>();
+
+        caps.add("cap1" + i);
+        caps.add("cap2" + i);
+        caps.add("urn:opendaylight:params:xml:ns:yang:controller:netty?module=netty&revision=2013-11-19" + i);
+        caps.add("capaaaa as dasfasdf s2" + i);
+        return caps;
+    }
+
+    @Test
+    public void testFileAdapterOneBackup() throws Exception {
+        XmlFileStorageAdapter storage = new XmlFileStorageAdapter();
+        storage.setFileStorage(file);
+        storage.setNumberOfBackups(1);
+        final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() {
+            @Override
+            public String getConfigSnapshot() {
+                return createConfig();
+            }
+
+            @Override
+            public SortedSet<String> getCapabilities() {
+                return createCaps();
+            }
+        };
+        storage.persistConfig(holder);
+
+        storage.persistConfig(holder);
+
+        assertEquals(16, com.google.common.io.Files.readLines(file, Charsets.UTF_8).size());
+
+        List<ConfigSnapshotHolder> lastConf = storage.loadLastConfigs();
+        assertEquals(1, lastConf.size());
+        ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0);
+        assertEquals("<config>2</config>",
+                configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", ""));
+    }
+
+    @Test
+    public void testFileAdapterOnlyTwoBackups() throws Exception {
+        XmlFileStorageAdapter storage = new XmlFileStorageAdapter();
+        storage.setFileStorage(file);
+        storage.setNumberOfBackups(2);
+        final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() {
+            @Override
+            public String getConfigSnapshot() {
+                return createConfig();
+            }
+
+            @Override
+            public SortedSet<String> getCapabilities() {
+                return createCaps();
+            }
+        };
+        storage.persistConfig(holder);
+
+        storage.persistConfig(holder);
+        storage.persistConfig(holder);
+
+        List<String> readLines = com.google.common.io.Files.readLines(file, Charsets.UTF_8);
+        assertEquals(27, readLines.size());
+
+        List<ConfigSnapshotHolder> lastConf = storage.loadLastConfigs();
+        assertEquals(1, lastConf.size());
+        ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0);
+        assertEquals("<config>3</config>",
+                configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", ""));
+        assertFalse(readLines.contains(holder.getConfigSnapshot()));
+    }
+
+    @Test
+    public void testNoLastConfig() throws Exception {
+        File file = Files.createTempFile("testFilePersist", ".txt").toFile();
+        if (!file.exists())
+            return;
+        XmlFileStorageAdapter storage = new XmlFileStorageAdapter();
+        storage.setFileStorage(file);
+
+        List<ConfigSnapshotHolder> elementOptional = storage.loadLastConfigs();
+        assertThat(elementOptional.size(), is(0));
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testNoProperties() throws Exception {
+        XmlFileStorageAdapter storage = new XmlFileStorageAdapter();
+        storage.loadLastConfigs();
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testNoProperties2() throws Exception {
+        XmlFileStorageAdapter storage = new XmlFileStorageAdapter();
+        storage.persistConfig(new ConfigSnapshotHolder() {
+            @Override
+            public String getConfigSnapshot() {
+                return Mockito.mock(String.class);
+            }
+
+            @Override
+            public SortedSet<String> getCapabilities() {
+                return new TreeSet<>();
+            }
+        } );
+    }
+
+    static String createConfig() {
+        return "<config>" + i++ + "</config>";
+    }
+
+}
index 9f0145f..eba5e07 100644 (file)
@@ -26,6 +26,7 @@
         <module>config-util</module>
         <module>config-persister-api</module>
         <module>config-persister-file-adapter</module>
+        <module>config-persister-file-xml-adapter</module>
         <module>yang-jmx-generator</module>
         <module>yang-jmx-generator-plugin</module>
         <module>yang-store-api</module>
@@ -39,6 +40,7 @@
         <module>netty-event-executor-config</module>
         <module>netty-timer-config</module>
         <module>config-persister-directory-adapter</module>
+        <module>config-persister-directory-xml-adapter</module>
         <module>yang-test-plugin</module>
     </modules>
 
index 033d057..b7a4638 100644 (file)
           <artifactId>config-persister-file-adapter</artifactId>
           <version>${config.version}</version>
         </dependency>
-          <dependency>
-              <groupId>org.opendaylight.controller</groupId>
-              <artifactId>config-persister-directory-adapter</artifactId>
-              <version>${config.version}</version>
-          </dependency>
+        <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>config-persister-file-xml-adapter</artifactId>
+          <version>${config.version}</version>
+        </dependency>
+        <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>config-persister-directory-adapter</artifactId>
+          <version>${config.version}</version>
+        </dependency>
+        <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>config-persister-directory-xml-adapter</artifactId>
+          <version>${config.version}</version>
+        </dependency>
 
        <!-- Netconf -->
         <dependency>
index 7d57e60..ba5d862 100644 (file)
@@ -29,8 +29,16 @@ netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.confi
 netconf.config.persister.1.properties.directoryStorage=configuration/initial/
 netconf.config.persister.1.readonly=true
 
-netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
-netconf.config.persister.2.properties.fileStorage=configuration/current/controller.currentconfig.txt
+#netconf.config.persister.3.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter
+#netconf.config.persister.3.properties.directoryStorage=configuration/initialXml/
+#netconf.config.persister.3.readonly=true
+
+#netconf.config.persister.4.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
+#netconf.config.persister.4.properties.fileStorage=configuration/current/controller.currentconfig.txt
+#netconf.config.persister.4.properties.numberOfBackups=1
+
+netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter
+netconf.config.persister.2.properties.fileStorage=configuration/current/controller.currentconfig.xml
 netconf.config.persister.2.properties.numberOfBackups=1
 
 
index 4f9e1fe..23cdabf 100644 (file)
@@ -1,10 +1,9 @@
-/**
- * @author Maros Marsalek
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
- * 12 2013
- *
- * Copyright (c) 2012 by Cisco Systems, Inc.
- * All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes;
 
index a4f5e49..77f3cf2 100644 (file)
@@ -97,7 +97,11 @@ public final class Services {
         Preconditions.checkArgument(refNameToInstance != null, "No serviceInstances mapped to " + serviceName + " , "
                 + serviceNameToRefNameToInstance.keySet());
 
-        ServiceInstance serviceInstance = ServiceInstance.fromString(refNameToInstance.get(refName));
+        String instanceId = refNameToInstance.get(refName);
+        Preconditions.checkArgument(instanceId != null, "No serviceInstances mapped to " + serviceName + ":"
+                + refName + ", " + serviceNameToRefNameToInstance.keySet());
+
+        ServiceInstance serviceInstance = ServiceInstance.fromString(instanceId);
         Preconditions.checkArgument(serviceInstance != null, "No serviceInstance mapped to " + refName
                 + " under service name " + serviceName + " , " + refNameToInstance.keySet());
         return serviceInstance;
index ccb7931..b248342 100644 (file)
@@ -12,6 +12,7 @@ import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 import org.apache.commons.lang3.StringUtils;
 import org.junit.Before;
 import org.junit.Ignore;
@@ -75,9 +76,11 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
@@ -497,17 +500,20 @@ public class NetconfMappingTest extends AbstractConfigTest {
         XmlElement modulesElement = XmlElement.fromDomElement(response).getOnlyChildElement("data")
                 .getOnlyChildElement("modules");
 
-        XmlElement configAttributeType = null;
+        List<String> expectedValues = Lists.newArrayList("default-string", "configAttributeType");
+        Set<String> configAttributeType = Sets.newHashSet();
+
         for (XmlElement moduleElement : modulesElement.getChildElements("module")) {
             for (XmlElement type : moduleElement.getChildElements("type")) {
                 if (type.getAttribute(XmlUtil.XMLNS_ATTRIBUTE_KEY).equals("") == false) {
-                    configAttributeType = type;
+                    configAttributeType.add(type.getTextContent());
                 }
             }
         }
 
-        // TODO verify if should be default value
-        assertEquals("default-string", configAttributeType.getTextContent());
+        for (String expectedValue : expectedValues) {
+            assertTrue(configAttributeType.contains(expectedValue));
+        }
     }
 
     private Map<String, Map<String, ModuleMXBeanEntry>> getMbes() throws Exception {
index c6caf41..7fc2b58 100644 (file)
@@ -43,7 +43,9 @@
         </dependency>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
-            <artifactId>config-persister-file-adapter</artifactId>
+            <artifactId>config-persister-file-xml-adapter</artifactId>
+            <scope>test</scope>
+            <version>${config.version}</version>
         </dependency>
 
         <!-- test dependencies -->
@@ -60,8 +62,8 @@
         </dependency>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
-            <artifactId>config-persister-directory-adapter</artifactId>
-            <version>${parent.version}</version>
+            <artifactId>config-persister-directory-xml-adapter</artifactId>
+            <version>${config.version}</version>
             <scope>test</scope>
         </dependency>
     </dependencies>
index 7e9dce6..f168bb3 100644 (file)
@@ -34,7 +34,7 @@ import java.util.ListIterator;
  * Example configuration:<pre>
  netconf.config.persister.active=2,3
  # read startup configuration
- netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.DirectoryStorageAdapter
+ netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter
  netconf.config.persister.1.properties.fileStorage=configuration/initial/
 
  netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
index 227018b..acea75a 100644 (file)
@@ -11,7 +11,7 @@ package org.opendaylight.controller.netconf.persist.impl;
 import org.junit.Test;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.config.persist.api.Persister;
-import org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter;
+import org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter;
 import org.opendaylight.controller.netconf.persist.impl.osgi.ConfigPersisterActivator;
 import org.opendaylight.controller.netconf.persist.impl.osgi.PropertiesProviderBaseImpl;
 
@@ -93,7 +93,7 @@ public class PersisterAggregatorTest {
         List<PersisterWithConfiguration> persisters = persisterAggregator.getPersisterWithConfigurations();
         assertEquals(1, persisters.size());
         PersisterWithConfiguration persister = persisters.get(0);
-        assertEquals(FileStorageAdapter.class.getName() ,persister.getStorage().getClass().getName());
+        assertEquals(XmlFileStorageAdapter.class.getName() ,persister.getStorage().getClass().getName());
         assertFalse(persister.isReadOnly());
     }
 
index 222e7ce..729c67d 100644 (file)
@@ -1,9 +1,9 @@
 netconf.config.persister.active=2
 # read startup configuration
-netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.DirectoryStorageAdapter
+netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter
 netconf.config.persister.1.properties.directoryStorage=target/configuration/initial/
 netconf.config.persister.1.readonly=true
 
-netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
+netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter
 netconf.config.persister.2.properties.fileStorage=target/configuration/current/controller.config.2.txt
 netconf.config.persister.2.properties.numberOfBackups=3
index a1645ad..90ba772 100644 (file)
@@ -1,4 +1,4 @@
 netconf.config.persister.active=3
-netconf.config.persister.3.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
+netconf.config.persister.3.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter
 netconf.config.persister.3.properties.fileStorage=target/configuration/current/controller.config.2.txt
 netconf.config.persister.3.properties.numberOfBackups=0