This implementation is based on infrastructure provided by the framework artifact
and contains server as well as client side code.
Netconf subsystem structure:
Netconf-api:
Api definition for client and server.
Netconf-impl:
Netconf server implementation. Server handles basic communication
and delegates handling of rpcs to an implementation of netconf-mapping-api.
Netconf-mapping-api:
Api definition for pluggable rpcs handler. Implementations of this api
are plugged dynamically into netconf-impl using OSGi apis.
Config-netconf-connector:
Implementation of netconf-mapping-api that handles netconf rpcs and delegates
requests to configuration subsystem
Netconf-util:
Utility classes used by client and server code.
Netconf-client:
Netconf client implementation.
Netconf-it:
Integration tests for netconf. These tests verify correct cooperation of netconf server,
config-netconf-connector, config subsystem and netconf client.
Config-persister-api:
Api definition for config persister. Config persister is a component that is responsible
for storing configuration snapshots after every change to the configuration via netconf rpcs.
(Pushed to config-subsystem)
Config-persister-impl:
Implementation of config persister that receives notifications from netconf-impl about changes
to the configuration and uses pluggable adapters to store received snapshots.
Config-persister-file-adapter:
Implementation of config persister adapter that stores and restores config snapshots from a file.
(Pushed to config-subsystem)
In order to run netconf in OSGi, some configuration issues had to be resolved
in config-subsystem bundles.
Change-Id: I8e0421c924b0714a4d49962c4bb5ca01ef68ac78
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
<geminiweb.version>2.2.0.RELEASE</geminiweb.version>
<checkstyle.version>2.10</checkstyle.version>
<testvm.argLine>-Xmx1024m -XX:MaxPermSize=256m</testvm.argLine>
- <yang.version>0.5.8</yang.version>
+ <yang.version>0.5.9-SNAPSHOT</yang.version>
<guava.version>14.0.1</guava.version>
<osgi.core.version>5.0.0</osgi.core.version>
<ietf-inet-types.version>2010.09.24.1</ietf-inet-types.version>
<bundle.plugin.version>2.3.7</bundle.plugin.version>
<junit.version>4.8.1</junit.version>
<bgpcep.version>0.2.0-SNAPSHOT</bgpcep.version>
- <yangtools.version>0.5.8</yangtools.version>
+ <yangtools.version>0.5.9-SNAPSHOT</yangtools.version>
+ <yangtools.binding.version>0.6.0-SNAPSHOT</yangtools.binding.version>
<!--versions for bits of the controller -->
<controller.version>0.4.1-SNAPSHOT</controller.version>
<config.version>0.2.1-SNAPSHOT</config.version>
<version>${bgpcep.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>framework</artifactId>
+ <version>${bgpcep.version}</version>
+ </dependency>
+
+ <!--Netty-->
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-handler</artifactId>
+ <version>4.0.9.Final</version>
+ </dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-codec</artifactId>
+ <version>4.0.9.Final</version>
+ </dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-buffer</artifactId>
+ <version>4.0.9.Final</version>
+ </dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-transport</artifactId>
+ <version>4.0.9.Final</version>
+ </dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-common</artifactId>
+ <version>4.0.9.Final</version>
+ </dependency>
+
<!-- yangtools dependencies -->
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-binding</artifactId>
- <version>${yangtools.version}</version>
+ <version>${yangtools.binding.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>concepts</artifactId>
<version>0.2.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </dependency>
</dependencies>
<build>
<instructions>
<Import-Package>
javax.management,
- org.opendaylight.protocol.concepts
+ org.opendaylight.protocol.concepts,
+ org.osgi.framework,
</Import-Package>
<Export-Package>
org.opendaylight.controller.config.api,
org.opendaylight.controller.config.api.jmx,
org.opendaylight.controller.config.api.jmx.constants,
org.opendaylight.controller.config.api.runtime,
+ org.opendaylight.controller.config.stat,
</Export-Package>
</instructions>
</configuration>
--- /dev/null
+/*
+ * 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.stat;
+
+import org.osgi.framework.BundleContext;
+
+/**
+ * Subset of {@link org.osgi.framework.BundleContext}
+ */
+public interface ConfigProvider {
+ /**
+ * Returns the value of the specified property. If the key is not found in
+ * the Framework properties, the system properties are then searched. The
+ * method returns {@code null} if the property is not found.
+ *
+ * <p>
+ * All bundles must have permission to read properties whose names start
+ * with "org.osgi.".
+ *
+ * @param key
+ * The name of the requested property.
+ * @return The value of the requested property, or {@code null} if the
+ * property is undefined.
+ * @throws SecurityException
+ * If the caller does not have the appropriate
+ * {@code PropertyPermission} to read the property, and the Java
+ * Runtime Environment supports permissions.
+ */
+ String getProperty(String key);
+
+ public static class ConfigProviderImpl implements ConfigProvider {
+ private final BundleContext context;
+
+ public ConfigProviderImpl(BundleContext context) {
+ this.context = context;
+ }
+
+ @Override
+ public String getProperty(String key) {
+ return context.getProperty(key);
+ }
+
+ @Override
+ public String toString() {
+ return "ConfigProviderImpl{" + "context=" + context + '}';
+ }
+ }
+
+}
--- /dev/null
+<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.1-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+ <artifactId>config-persister-api</artifactId>
+ <name>${project.artifactId}</name>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>config-util</artifactId>
+ <version>0.2.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Import-Package>
+ com.google.common.base,
+ org.w3c.dom,
+ org.osgi.framework,
+ org.opendaylight.controller.config.stat
+ </Import-Package>
+ <Export-Package>
+ org.opendaylight.controller.config.persist.api,
+ org.opendaylight.controller.config.persist.api.storage,
+ </Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
--- /dev/null
+/*
+ * 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.api;
+
+import com.google.common.base.Optional;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.Set;
+
+/**
+ * Base interface for persister implementation.
+ */
+public interface Persister extends Closeable {
+
+ void persistConfig(ConfigSnapshotHolder configSnapshotHolder) throws IOException;
+
+ Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException;
+
+ public static interface ConfigSnapshotHolder {
+
+ String getConfigSnapshot();
+
+ Set<String> getCapabilities();
+ }
+}
--- /dev/null
+/*
+ * 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.api.storage;
+
+import org.opendaylight.controller.config.persist.api.Persister;
+import org.opendaylight.controller.config.stat.ConfigProvider;
+
+/**
+ * Plugins for {@link org.opendaylight.controller.config.persist.api.Persister}
+ * must implement this interface.
+ */
+public interface StorageAdapter extends Persister {
+
+ void setProperties(ConfigProvider configProvider);
+
+}
--- /dev/null
+<?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.1-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+ <artifactId>config-persister-file-adapter</artifactId>
+ <name>${project.artifactId}</name>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <!-- compile dependencies -->
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>config-persister-api</artifactId>
+ <version>${project.version}</version>
+ </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>
+
+ <!-- test dependencies -->
+ <dependency>
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>mockito-configuration</artifactId>
+ <version>0.2.0-SNAPSHOT</version>
+ <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>
+ org.osgi.framework,
+ com.google.common.base,
+ com.google.common.collect,
+ com.google.common.io,
+ javax.xml.parsers,
+ javax.xml.transform,
+ javax.xml.transform.dom,
+ javax.xml.transform.stream,
+ org.apache.commons.lang3,
+ org.opendaylight.controller.config.persist.api,
+ org.opendaylight.controller.config.stat,
+ org.opendaylight.controller.config.persist.api.storage,
+ org.slf4j,
+ org.w3c.dom,
+ org.xml.sax,
+ </Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
--- /dev/null
+/*
+ * 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;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Sets;
+import com.google.common.io.Files;
+import org.apache.commons.lang3.StringUtils;
+import org.opendaylight.controller.config.persist.api.storage.StorageAdapter;
+import org.opendaylight.controller.config.stat.ConfigProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.Set;
+
+/**
+ * StorageAdapter that stores configuration in a plan file.
+ */
+public class FileStorageAdapter implements StorageAdapter {
+ private static final Logger logger = LoggerFactory.getLogger(FileStorageAdapter.class);
+
+ // TODO prefix properties
+
+ private static final Charset ENCODING = Charsets.UTF_8;
+
+ public static final String FILE_STORAGE_PROP = "fileStorage";
+ public static final String NUMBER_OF_BACKUPS = "numberOfBackups";
+
+ private static final String SEPARATOR_E_PURE = "//END OF CONFIG";
+ private static final String SEPARATOR_E = newLine(SEPARATOR_E_PURE);
+
+ private static final String SEPARATOR_M_PURE = "//END OF SNAPSHOT";
+ private static final String SEPARATOR_M = newLine(SEPARATOR_M_PURE);
+
+ private static final String SEPARATOR_S = newLine("//START OF CONFIG");
+
+ private static final String SEPARATOR_SL_PURE = "//START OF CONFIG-LAST";
+ private static final String SEPARATOR_SL = newLine(SEPARATOR_SL_PURE);
+
+ private static Integer numberOfStoredBackups;
+ private File storage;
+
+ @Override
+ public void setProperties(ConfigProvider configProvider) {
+ File storage = extractStorageFileFromProperties(configProvider);
+ 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);
+
+ }
+
+ @VisibleForTesting
+ void setFileStorage(File storage) {
+ this.storage = storage;
+ }
+
+ @VisibleForTesting
+ void setNumberOfBackups(Integer numberOfBackups) {
+ numberOfStoredBackups = numberOfBackups;
+ }
+
+ private static File extractStorageFileFromProperties(ConfigProvider configProvider) {
+ String fileStorageProperty = configProvider.getProperty(FILE_STORAGE_PROP);
+ Preconditions.checkNotNull(fileStorageProperty, "Unable to find " + FILE_STORAGE_PROP
+ + " in received properties :" + configProvider);
+ File result = new File(fileStorageProperty);
+ String numberOfBAckupsAsString = configProvider.getProperty(NUMBER_OF_BACKUPS);
+ if (numberOfBAckupsAsString != null) {
+ numberOfStoredBackups = Integer.valueOf(numberOfBAckupsAsString);
+ } else {
+ numberOfStoredBackups = Integer.MAX_VALUE;
+ }
+
+ return result;
+ }
+
+ private static String newLine(String string) {
+ return string + "\n";
+ }
+
+ @Override
+ public void persistConfig(ConfigSnapshotHolder holder) throws IOException {
+ Preconditions.checkNotNull(storage, "Storage file is null");
+
+ String content = Files.toString(storage, ENCODING);
+ if (numberOfStoredBackups == Integer.MAX_VALUE) {
+ resetLastConfig(content);
+ persistLastConfig(holder);
+ } else {
+ if (numberOfStoredBackups == 1) {
+ Files.write("", storage, ENCODING);
+ persistLastConfig(holder);
+ } else {
+ int count = StringUtils.countMatches(content, SEPARATOR_S);
+ if ((count + 1) < numberOfStoredBackups) {
+ resetLastConfig(content);
+ persistLastConfig(holder);
+ } else {
+ String contentSubString = StringUtils.substringBefore(content, SEPARATOR_E);
+ contentSubString = contentSubString.concat(SEPARATOR_E_PURE);
+ content = StringUtils.substringAfter(content, contentSubString);
+ resetLastConfig(content);
+ persistLastConfig(holder);
+ }
+ }
+ }
+ }
+
+ private void resetLastConfig(String content) throws IOException {
+ content = content.replaceFirst(SEPARATOR_SL, SEPARATOR_S);
+ Files.write(content, storage, ENCODING);
+ }
+
+ private void persistLastConfig(ConfigSnapshotHolder holder) throws IOException {
+ Files.append(SEPARATOR_SL, storage, ENCODING);
+ String snapshotAsString = holder.getConfigSnapshot();
+ Files.append(newLine(snapshotAsString), storage, ENCODING);
+ Files.append(SEPARATOR_M, storage, ENCODING);
+ Files.append(toStringCaps(holder.getCapabilities()), storage, ENCODING);
+ Files.append(SEPARATOR_E, storage, ENCODING);
+ }
+
+ private CharSequence toStringCaps(Set<String> capabilities) {
+ StringBuilder b = new StringBuilder();
+ for (String capability : capabilities) {
+ b.append(newLine(capability));
+ }
+ return b.toString();
+ }
+
+ @Override
+ public Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException {
+ Preconditions.checkNotNull(storage, "Storage file is null");
+
+ if (!storage.exists()) {
+ return Optional.absent();
+ }
+
+ final LineProcessor lineProcessor = new LineProcessor();
+ String result = Files.readLines(storage, ENCODING, lineProcessor);
+
+ try {
+ if (lineProcessor.getConfigSnapshot().isPresent() == false) {
+ return Optional.absent();
+ } else {
+ return Optional.<ConfigSnapshotHolder> of(new PersistedConfigImpl(lineProcessor.getConfigSnapshot(),
+ lineProcessor.getCapabilities()));
+ }
+
+ } catch (ParserConfigurationException | SAXException e) {
+ throw new IOException("Unable to load last config ", e);
+ }
+ }
+
+ private static final class LineProcessor implements com.google.common.io.LineProcessor<String> {
+
+ private boolean inLastConfig, inLastSnapshot;
+ private final StringBuffer snapshotBuffer = new StringBuffer();
+ private final Set<String> caps = Sets.newHashSet();
+
+ @Override
+ public String getResult() {
+ return null;
+ }
+
+ @Override
+ public boolean processLine(String line) throws IOException {
+ if (inLastConfig && line.equals(SEPARATOR_E_PURE)) {
+ inLastConfig = false;
+ return false;
+ }
+
+ if (inLastConfig && line.equals(SEPARATOR_M_PURE)) {
+ inLastSnapshot = false;
+ return true;
+ }
+
+ if (inLastConfig) {
+ if (inLastSnapshot) {
+ snapshotBuffer.append(line);
+ snapshotBuffer.append(System.lineSeparator());
+ } else {
+ caps.add(line);
+ }
+ }
+
+ if (line.equals(SEPARATOR_SL_PURE)) {
+ inLastConfig = true;
+ inLastSnapshot = true;
+ }
+
+ return true;
+ }
+
+ Optional<String> getConfigSnapshot() throws IOException, SAXException, ParserConfigurationException {
+ final String xmlContent = snapshotBuffer.toString();
+ if (xmlContent == null || xmlContent.equals("")) {
+ return Optional.absent();
+ } else
+ return Optional.of(xmlContent);
+ }
+
+ Set<String> getCapabilities() throws IOException, SAXException, ParserConfigurationException {
+ return caps;
+ }
+
+ }
+
+ @Override
+ public void close() throws IOException {
+
+ }
+
+ @Override
+ public String toString() {
+ return "FileStorageAdapter [storage=" + storage + "]";
+ }
+
+ private class PersistedConfigImpl implements ConfigSnapshotHolder {
+
+ private final String snapshot;
+ private final Set<String> caps;
+
+ public PersistedConfigImpl(Optional<String> configSnapshot, Set<String> capabilities) {
+ this.snapshot = configSnapshot.get();
+ this.caps = capabilities;
+ }
+
+ @Override
+ public String getConfigSnapshot() {
+ return snapshot;
+ }
+
+ @Override
+ public Set<String> getCapabilities() {
+ return caps;
+ }
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Sets;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.controller.config.persist.api.Persister;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.*;
+
+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 {
+ FileStorageAdapter storage = new FileStorageAdapter();
+ storage.setFileStorage(file);
+ storage.setNumberOfBackups(Integer.MAX_VALUE);
+ final Persister.ConfigSnapshotHolder holder = new Persister.ConfigSnapshotHolder() {
+ @Override
+ public String getConfigSnapshot() {
+ return createConfig();
+ }
+
+ @Override
+ public Set<String> getCapabilities() {
+ return createCaps();
+ }
+ };
+ storage.persistConfig(holder);
+
+ storage.persistConfig(holder);
+
+ Collection<String> readLines = Collections2.filter(com.google.common.io.Files.readLines(file, Charsets.UTF_8),
+ new Predicate<String>() {
+
+ @Override
+ public boolean apply(String input) {
+ if (input.equals(""))
+ return false;
+ return true;
+ }
+ });
+ assertEquals(14, readLines.size());
+
+ Optional<Persister.ConfigSnapshotHolder> lastConf = storage.loadLastConfig();
+ assertTrue(lastConf.isPresent());
+ assertEquals("<config>2</config>",
+ lastConf.get().getConfigSnapshot().replaceAll("\\s", ""));
+ assertEquals(createCaps(), lastConf.get().getCapabilities());
+ }
+
+ private Set<String> createCaps() {
+ Set<String> caps = Sets.newHashSet();
+
+ caps.add("cap1");
+ caps.add("cap2");
+ caps.add("capaaaa as dasfasdf s2");
+ return caps;
+ }
+
+ @Test
+ public void testFileAdapterOneBackup() throws Exception {
+ FileStorageAdapter storage = new FileStorageAdapter();
+ storage.setFileStorage(file);
+ storage.setNumberOfBackups(1);
+ final Persister.ConfigSnapshotHolder holder = new Persister.ConfigSnapshotHolder() {
+ @Override
+ public String getConfigSnapshot() {
+ return createConfig();
+ }
+
+ @Override
+ public Set<String> getCapabilities() {
+ return createCaps();
+ }
+ };
+ storage.persistConfig(holder);
+
+ storage.persistConfig(holder);
+
+ Collection<String> readLines = Collections2.filter(com.google.common.io.Files.readLines(file, Charsets.UTF_8),
+ new Predicate<String>() {
+
+ @Override
+ public boolean apply(String input) {
+ if (input.equals(""))
+ return false;
+ return true;
+ }
+ });
+ assertEquals(7, readLines.size());
+
+ Optional<Persister.ConfigSnapshotHolder> lastConf = storage.loadLastConfig();
+ assertTrue(lastConf.isPresent());
+ assertEquals("<config>2</config>",
+ lastConf.get().getConfigSnapshot().replaceAll("\\s", ""));
+ }
+
+ @Test
+ public void testFileAdapterOnlyTwoBackups() throws Exception {
+ FileStorageAdapter storage = new FileStorageAdapter();
+ storage.setFileStorage(file);
+ storage.setNumberOfBackups(2);
+ final Persister.ConfigSnapshotHolder holder = new Persister.ConfigSnapshotHolder() {
+ @Override
+ public String getConfigSnapshot() {
+ return createConfig();
+ }
+
+ @Override
+ public Set<String> getCapabilities() {
+ return createCaps();
+ }
+ };
+ storage.persistConfig(holder);
+
+ storage.persistConfig(holder);
+ storage.persistConfig(holder);
+
+ Collection<String> readLines = Collections2.filter(com.google.common.io.Files.readLines(file, Charsets.UTF_8),
+ new Predicate<String>() {
+
+ @Override
+ public boolean apply(String input) {
+ if (input.equals(""))
+ return false;
+ return true;
+ }
+ });
+
+ assertEquals(14, readLines.size());
+
+ Optional<Persister.ConfigSnapshotHolder> lastConf = storage.loadLastConfig();
+ assertTrue(lastConf.isPresent());
+ assertEquals("<config>3</config>",
+ lastConf.get().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;
+ FileStorageAdapter storage = new FileStorageAdapter();
+ storage.setFileStorage(file);
+
+ Optional<Persister.ConfigSnapshotHolder> elementOptional = storage.loadLastConfig();
+ assertThat(elementOptional.isPresent(), is(false));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testNoProperties() throws Exception {
+ FileStorageAdapter storage = new FileStorageAdapter();
+ storage.loadLastConfig();
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testNoProperties2() throws Exception {
+ FileStorageAdapter storage = new FileStorageAdapter();
+ storage.persistConfig(new Persister.ConfigSnapshotHolder() {
+ @Override
+ public String getConfigSnapshot() {
+ return Mockito.mock(String.class);
+ }
+
+ @Override
+ public Set<String> getCapabilities() {
+ return Collections.<String> emptySet();
+ }
+ } );
+ }
+
+ static String createConfig() {
+ return "<config>" + i++ + "</config>";
+ }
+
+}
<module>config-api</module>
<module>config-manager</module>
<module>config-util</module>
+ <module>config-persister-api</module>
+ <module>config-persister-file-adapter</module>
<module>yang-jmx-generator</module>
<module>yang-jmx-generator-plugin</module>
<module>yang-jmx-generator-it</module>
<jacoco.version>0.6.2.201302030002</jacoco.version>
<slf4j.version>1.7.2</slf4j.version>
<jolokia.version>1.1.1</jolokia.version>
- <osgi.core.version>5.0.0</osgi.core.version>
<opendaylight.yang.version>0.5.9-SNAPSHOT</opendaylight.yang.version>
<opendaylight.binding.version>0.6.0-SNAPSHOT</opendaylight.binding.version>
<jmxGeneratorPath>${project.build.directory}/generated-sources/config</jmxGeneratorPath>
<artifactId>gmaven-plugin</artifactId>
<version>1.0</version>
</plugin>
+ <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
+ <plugin>
+ <groupId>org.eclipse.m2e</groupId>
+ <artifactId>lifecycle-mapping</artifactId>
+ <version>1.0.0</version>
+ <configuration>
+ <lifecycleMappingMetadata>
+ <pluginExecutions>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>
+ org.opendaylight.yangtools
+ </groupId>
+ <artifactId>
+ yang-maven-plugin
+ </artifactId>
+ <versionRange>
+ [0.5.7-SNAPSHOT,)
+ </versionRange>
+ <goals>
+ <goal>
+ generate-sources
+ </goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <ignore></ignore>
+ </action>
+ </pluginExecution>
+ </pluginExecutions>
+ </lifecycleMappingMetadata>
+ </configuration>
+ </plugin>
</plugins>
</pluginManagement>
</build>
<pluginRepositories>
<pluginRepository>
<id>nexus.opendaylight.org</id>
- <url>http://nexus.opendaylight.org/content/repositories/opendaylight.snapshot</url>
+ <url>http://nexus.opendaylight.org/content/repositories/opendaylight.release</url>
<releases>
<enabled>true</enabled>
</releases>
</parent>
<artifactId>yang-jmx-generator-plugin</artifactId>
<dependencies>
+
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
+
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>yang-jmx-generator</artifactId>
<version>0.2.1-SNAPSHOT</version>
</dependency>
+
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-maven-plugin-spi</artifactId>
<version>${opendaylight.yang.version}</version>
</dependency>
+
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
- <artifactId>binding-generator-impl</artifactId>
+ <artifactId>binding-type-provider</artifactId>
<version>${opendaylight.binding.version}</version>
</dependency>
+
<dependency>
<groupId>org.eclipse.jdt</groupId>
<artifactId>core</artifactId>
<version>3.3.0-v_771</version>
<scope>test</scope>
</dependency>
+
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.20</version>
</dependency>
+
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>config-api</artifactId>
<version>0.2.1-SNAPSHOT</version>
</dependency>
+
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
+
<dependency>
<!--FIXME two implementations of slf4j on classpath, logback classic from parent-->
<groupId>com.googlecode.slf4j-maven-plugin-log</groupId>
<artifactId>slf4j-maven-plugin-log</artifactId>
<version>1.0.0</version>
</dependency>
+
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<scope>test</scope>
<type>test-jar</type>
</dependency>
+
<dependency>
<groupId>org.eclipse</groupId>
<artifactId>jdt</artifactId>
<version>3.3.0-v20070607-1300</version>
<scope>test</scope>
</dependency>
+
<dependency>
<groupId>org.opendaylight.bgpcep</groupId>
<artifactId>mockito-configuration</artifactId>
<version>0.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
+
<dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-lang3</artifactId>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
</dependency>
</dependencies>
*/
package org.opendaylight.controller.config.yangjmxgenerator.plugin;
-import java.io.File;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
+import com.google.common.annotations.VisibleForTesting;
+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.io.FileUtils;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.slf4j.LoggerFactory;
import org.slf4j.impl.StaticLoggerBinder;
-import com.google.common.annotations.VisibleForTesting;
-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 java.io.File;
+import java.io.IOException;
+import java.util.*;
+import java.util.Map.Entry;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* This class interfaces with yang-maven-plugin. Gets parsed yang modules in
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
+
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
- <artifactId>binding-generator-util</artifactId>
+ <artifactId>binding-generator-spi</artifactId>
<version>${opendaylight.binding.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
- <artifactId>binding-generator-spi</artifactId>
+ <artifactId>binding-generator-util</artifactId>
<version>${opendaylight.binding.version}</version>
</dependency>
+
+
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
*/
package org.opendaylight.controller.config.yangjmxgenerator;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.FullyQualifiedNameHelper;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.NameConflictException;
import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
-import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
-import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
-import org.opendaylight.yangtools.yang.model.api.SchemaNode;
-import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.UsesNode;
+import org.opendaylight.yangtools.yang.model.api.*;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Optional;
-import com.google.common.collect.Lists;
+import java.util.*;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
/**
* Holds information about runtime bean to be generated. There are two kinds of
+ "Error occured in " + rpcDefinition);
}
List<JavaAttribute> parameters = new ArrayList<>();
- for (DataSchemaNode childNode : rpcDefinition.getInput()
- .getChildNodes()) {
+ for (DataSchemaNode childNode : sortAttributes(rpcDefinition.getInput()
+ .getChildNodes())) {
if (childNode.isAddedByUses() == false) { // skip
// refined
// context-instance
attributes, rpcs);
}
+ private static Collection<DataSchemaNode> sortAttributes(Set<DataSchemaNode> childNodes) {
+ final TreeSet<DataSchemaNode> dataSchemaNodes = new TreeSet<>(new Comparator<DataSchemaNode>() {
+ @Override
+ public int compare(DataSchemaNode o1, DataSchemaNode o2) {
+ return o1.getQName().getLocalName().compareTo(o2.getQName().getLocalName());
+ }
+ });
+ dataSchemaNodes.addAll(childNodes);
+ return dataSchemaNodes;
+ }
+
private static boolean isInnerStateBean(DataSchemaNode child) {
for (UnknownSchemaNode unknownSchemaNode : child
.getUnknownSchemaNodes()) {
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
- <artifactId>binding-generator-impl</artifactId>
+ <artifactId>binding-type-provider</artifactId>
<version>${opendaylight.binding.version}</version>
</dependency>
<dependency>
--- /dev/null
+
+#24
+<rpc message-id="101" xm
+#28
+lns="urn:ietf:params:xml:ns:
+#2
+ne
+#33
+tconf:base:1.0">
+ <my-own-method
+#3
+ xm
+#13
+lns="http://e
+#34
+xample.net/me/my-own/1.0">
+ <my
+#8
+-first-p
+#21
+arameter>14</my-first
+#26
+-parameter>
+ <another-p
+#23
+arameter>fred</another-
+#31
+parameter>
+ </my-own-method>
+ <
+#2
+/r
+#3
+pc>
+##
--- /dev/null
+
+#22
+<rpc message-id="101"
+#24
+xmlns="urn:ietf:params:x
+#15
+ml:ns:netconf:b
+#54
+ase:1.0">
+ <get-config>
+ <source>
+ <r
+#2
+un
+#9
+ning/>
+
+#18
+ </source> <fi
+#33
+lter type="subtree">
+ <top x
+#4
+mlns
+#31
+="http://example.com/schema/1.2
+#15
+/config">
+
+#19
+ <users>
+
+#8
+ <us
+#3
+er/
+#5
+>
+
+#77
+ </users>
+ </top>
+ </filter>
+ </g
+#17
+et-config>
+</rpc>
+##
--- /dev/null
+
+#43
+<rpc message-id="101" xmlns="urn:ietf:param
+#14
+s:xml:ns:netco
+#14
+nf:base:1.0">
+
+#26
+<get-config>
+ <source>
+
+#35
+ <running/>
+ </source>
+
+#39
+ <filter type="subtree">
+ <
+#40
+top xmlns="http://example.com/schema/1.2
+#26
+/config">
+ <users>
+
+#36
+ <user>
+ <name>f
+#56
+red</name>
+ </user>
+ </users>
+
+#28
+ </top>
+ </fil
+#1
+t
+#28
+er>
+ </get-config>
+ </rpc>
+##
--- /dev/null
+
+#17
+<rpc message-id="
+#25
+101" xmlns="urn:ietf:para
+#19
+ms:xml:ns:netconf:b
+#3
+ase
+#19
+:1.0">
+ <get-confi
+#61
+g>
+ <source>
+ <running/>
+ </source>
+
+#43
+ <filter type="subtree">
+ <!-- requ
+#13
+est a text ve
+#22
+rsion of the configura
+#9
+tion -->
+
+#16
+ <config-text
+#45
+xmlns="http://example.com/text/1.2/config"/>
+
+#22
+ </filter>
+ </
+#18
+get-config>
+</rpc>
+##
--- /dev/null
+
+#43
+<rpc message-id="101" xmlns="urn:ietf:param
+#41
+s:xml:ns:netconf:base:1.0">
+ <edit-confi
+#29
+g>
+ <target>
+ <ru
+#13
+nning/>
+ <
+#4
+/tar
+#18
+get>
+ <config>
+
+#41
+ <top xmlns="http://example.com/schema/1
+#32
+.2/config">
+ <interface>
+
+#29
+ <name>Ethernet0/0</na
+#30
+me>
+ <mtu>1500</mtu>
+
+#61
+</interface>
+ </top>
+ </config>
+ </e
+#9
+dit-confi
+#9
+g>
+</rpc>
+##
--- /dev/null
+curl http://localhost:17777/jolokia/read/org.opendaylight.controller:instanceName=fixed1,type=ConfigBean,interfaceName=testing-threadpool | jsonpp
+{
+ "request": {
+ "mbean": "org.opendaylight.controller:instanceName=fixed1,interfaceName=testing-threadpool,type=ConfigBean",
+ "type": "read"
+ },
+ "status": 200,
+ "timestamp": 1362416252,
+ "value": {
+ "ExportedInterfaces": [
+ "testing-threadpool",
+ "modifiable-threadpool"
+ ],
+ "ImplementationName": "fixed",
+ "ThreadCount": 10,
+ "TriggerNewInstanceCreation": false
+ }
+}
\ No newline at end of file
--- /dev/null
+$ curl 'http://localhost:17777/jolokia/exec/org.opendaylight.controller:type=ConfigRegistry/lookupConfigBeans()' | jsonpp
+{
+ "request": {
+ "mbean": "org.opendaylight.controller:type=ConfigRegistry",
+ "operation": "lookupConfigBeans()",
+ "type": "exec"
+ },
+ "status": 200,
+ "timestamp": 1362417043,
+ "value": [
+ {
+ "objectName": "org.opendaylight.controller:instanceName=fixed1,interfaceName=modifiable-threadpool,type=ConfigBean"
+ },
+ {
+ "objectName": "org.opendaylight.controller:instanceName=fixed1,interfaceName=testing-threadpool,type=ConfigBean"
+ }
+ ]
+}
--- /dev/null
+<rpc message-id="104"
+ xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <commit/>
+</rpc>
\ No newline at end of file
--- /dev/null
+<rpc message-id="102"
+ xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <lock>
+ <target>
+ <candidate/>
+ </target>
+ </lock>
+</rpc>
\ No newline at end of file
--- /dev/null
+<rpc message-id="101"
+ xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <lock>
+ <target>
+ <running/>
+ </target>
+ </lock>
+</rpc>
\ No newline at end of file
--- /dev/null
+<rpc message-id="103"
+ xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <edit-config>
+ <target>
+ <candidate/>
+ </target>
+ <default-operation>none</default-operation>
+ <test-option>test-then-set</test-option>
+ <error-option>stop-on-error</error-option>
+ <nc:config
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
+ xmlns="uri-for-my-data-model-namespace">
+ <some-existing-node>
+ <my-new-node nc:operation="create">
+ <my-new-leaf>7</my-new-leaf>
+ </my-new-node>
+ </some-existing-node>
+ </nc:config>
+ </edit-config>
+</rpc>
\ No newline at end of file
--- /dev/null
+<rpc message-id="105"
+ xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <unlock>
+ <target>
+ <candidate/>
+ </target>
+ </unlock>
+</rpc>
\ No newline at end of file
--- /dev/null
+<rpc message-id="106"
+ xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <unlock>
+ <target>
+ <running/>
+ </target>
+ </unlock>
+</rpc>
\ No newline at end of file
--- /dev/null
+<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <rpc-error>
+ <error-type>rpc</error-type>
+ <error-tag>missing-attribute</error-tag>
+ <error-severity>error</error-severity>
+ <error-info>
+ <bad-attribute>message-id</bad-attribute>
+ <bad-element>rpc</bad-element>
+ </error-info>
+ </rpc-error>
+</rpc-reply>
<version>0.1.1-SNAPSHOT</version>
</dependency>
- <!-- config
+ <!-- config-->
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-api</artifactId>
<artifactId>logback-config</artifactId>
<version>${config.version}</version>
</dependency>
- -->
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-persister-api</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-persister-file-adapter</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+
+
+ <!-- Netconf -->
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-api</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-impl</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-util</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-client</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-mapping-api</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-netconf-connector</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-persister-impl</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+
+
</dependencies>
</profile>
</profiles>
<groupId>org.opendaylight.bgpcep</groupId>
<artifactId>util</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>framework</artifactId>
+ </dependency>
- <!-- testing dependencies I'm pretty sure we should trim -->
+ <!--Netty-->
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-handler</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-codec</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-buffer</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-transport</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-common</artifactId>
+ </dependency>
+
+
+ <!-- testing dependencies I'm pretty sure we should trim -->
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>clustering.test</artifactId>
<artifactId>yang-binding</artifactId>
<version>0.6.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-type-provider</artifactId>
+ <version>0.6.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-generator-util</artifactId>
+ <version>${yangtools.binding.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-model-api</artifactId>
+ <version>${yangtools.binding.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-generator-spi</artifactId>
+ <version>${yangtools.binding.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ <version>2.4</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.opendaylight.yangtools.thirdparty</groupId>
+ <artifactId>antlr-runtime-osgi</artifactId>
+ <version>4.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.thirdparty</groupId>
+ <artifactId>xtend-lib-osgi</artifactId>
+ <version>2.4.2-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-parser-api</artifactId>
+ <version>${yangtools.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-model-util</artifactId>
+ <version>${yangtools.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-parser-impl</artifactId>
+ <version>${yangtools.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-common</artifactId>
reference\:file\:../lib/jersey-json-1.17.jar@2:start,\
reference\:file\:../lib/jersey-server-1.17.jar@2:start
+# Netconf startup configuration
+netconf.tcp.address=127.0.0.1
+netconf.tcp.port=8383
+
+#netconf.tls.address=127.0.0.1
+#netconf.tls.port=8384
+#netconf.tls.keystore=
+#netconf.tls.keystore.password=
+
+netconf.config.persister.storageAdapterClass=org.opendaylight.controller.netconf.persist.impl.NoOpStorageAdapter
+
# Set Default start level for framework
osgi.bundles.defaultStartLevel=4
# Extra packages to import from the boot class loader
<!-- OSGi logging bridge -->
<logger name="org.opendaylight.controller.logging.bridge" level="WARN"/>
+ <!-- Netty -->
+ <logger name="io.netty" level="WARN"/>
+
<!-- Openflow Protocol Plugin -->
<logger name="org.opendaylight.controller.protocol_plugin.openflow" level="INFO"/>
<logger name="org.opendaylight.controller.protocol_plugin.openflow.internal.DiscoveryService" level="INFO"/>
--- /dev/null
+<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>netconf-subsystem</artifactId>
+ <groupId>org.opendaylight.controller</groupId>
+ <version>0.2.1-SNAPSHOT</version>
+ </parent>
+ <artifactId>config-netconf-connector</artifactId>
+ <name>${project.artifactId}</name>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <!-- compile dependencies -->
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>config-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+
+ <artifactId>yang-jmx-generator</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+
+ <artifactId>config-util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-util</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+
+ <artifactId>yang-store-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-mapping-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-util</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ <type>test-jar</type>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+
+ <artifactId>yang-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+
+ <artifactId>config-manager</artifactId>
+ <version>${config.version}</version>
+ <scope>test</scope>
+ <type>test-jar</type>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+
+ <artifactId>config-manager</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-impl</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+
+ <artifactId>yang-store-impl</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>mockito-configuration</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Bundle-Activator>org.opendaylight.controller.netconf.confignetconfconnector.osgi.Activator
+ </Bundle-Activator>
+ <Private-Package>
+ org.opendaylight.controller.netconf.confignetconfconnector.mapping.*,
+ org.opendaylight.controller.netconf.confignetconfconnector.operations.*,
+ org.opendaylight.controller.netconf.confignetconfconnector.transactions,
+ org.opendaylight.controller.netconf.confignetconfconnector.util,
+ org.opendaylight.controller.netconf.confignetconfconnector.osgi,
+ org.opendaylight.controller.config.util,
+ </Private-Package>
+ <Import-Package>
+ com.google.common.base,
+ com.google.common.collect,
+ javax.annotation,
+ javax.management,
+ javax.management.openmbean,
+ org.opendaylight.controller.config.api,
+ org.opendaylight.controller.config.api.jmx,
+ org.opendaylight.controller.config.yang.store.api,
+ org.opendaylight.controller.config.yangjmxgenerator,
+ org.opendaylight.controller.config.yangjmxgenerator.attribute,
+ org.opendaylight.controller.netconf.api,
+ org.opendaylight.controller.netconf.mapping.api,
+ org.opendaylight.controller.netconf.util.mapping,
+ org.opendaylight.controller.netconf.util.xml,
+ org.opendaylight.yangtools.yang.common,
+ org.opendaylight.yangtools.yang.model.api,
+ org.osgi.framework,
+ org.osgi.util.tracker,
+ org.slf4j,
+ org.w3c.dom
+ </Import-Package>
+ <Export-Package>
+ </Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes;
+
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.*;
+
+public abstract class AttributeIfcSwitchStatement<T> {
+
+ public T switchAttribute(AttributeIfc attributeIfc) {
+
+ if (attributeIfc instanceof JavaAttribute) {
+ return caseJavaAttribute((JavaAttribute) attributeIfc);
+ } else if (attributeIfc instanceof DependencyAttribute) {
+ return caseDependencyAttribute((DependencyAttribute) attributeIfc);
+ } else if (attributeIfc instanceof ListAttribute) {
+ return caseListAttribute((ListAttribute) attributeIfc);
+ } else if (attributeIfc instanceof TOAttribute) {
+ return caseTOAttribute((TOAttribute) attributeIfc);
+ }
+
+ throw new IllegalArgumentException("Unknown attribute type " + attributeIfc.getClass() + ", " + attributeIfc);
+ }
+
+ protected abstract T caseJavaAttribute(JavaAttribute attributeIfc);
+
+ protected abstract T caseDependencyAttribute(DependencyAttribute attributeIfc);
+
+ protected abstract T caseTOAttribute(TOAttribute attributeIfc);
+
+ protected abstract T caseListAttribute(ListAttribute attributeIfc);
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.fromxml;
+
+import java.util.List;
+
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+
+public abstract class AbstractAttributeReadingStrategy<A extends AttributeIfc> implements AttributeReadingStrategy {
+
+ private final A attributeIfc;
+
+ public AbstractAttributeReadingStrategy(A attributeIfc) {
+ this.attributeIfc = attributeIfc;
+ }
+
+ public A getAttributeIfc() {
+ return attributeIfc;
+ }
+
+ @Override
+ public AttributeConfigElement readElement(List<XmlElement> configNodes) {
+ if (configNodes.size() == 0)
+ return AttributeConfigElement.createNullValue(attributeIfc);
+
+ return readElementHook(configNodes);
+ }
+
+ abstract AttributeConfigElement readElementHook(List<XmlElement> configNodes);
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.fromxml;
+
+import com.google.common.collect.Lists;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+
+import java.util.List;
+
+public class ArrayAttributeReadingStrategy extends AbstractAttributeReadingStrategy<AttributeIfc> {
+
+ private final AttributeReadingStrategy innerStrategy;
+
+ /**
+ * @param attributeIfc
+ * @param innerStrategy
+ */
+ public ArrayAttributeReadingStrategy(AttributeIfc attributeIfc, AttributeReadingStrategy innerStrategy) {
+ super(attributeIfc);
+ this.innerStrategy = innerStrategy;
+ }
+
+ @Override
+ AttributeConfigElement readElementHook(List<XmlElement> configNodes) {
+ List<Object> innerList = Lists.newArrayList();
+ for (int i = 0; i < configNodes.size(); i++) {
+ innerList.add(innerStrategy.readElement(Lists.newArrayList(configNodes.get(i))).getValue());
+ }
+ return AttributeConfigElement.create(getAttributeIfc(), innerList);
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.fromxml;
+
+import javax.management.openmbean.OpenType;
+
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving.AttributeResolvingStrategy;
+
+import com.google.common.base.Optional;
+
+/**
+ * Parsed xml element containing configuration for one attribute of an instance
+ * of some module. Contains default value extracted from yang file.
+ */
+public class AttributeConfigElement {
+ private final Object dafaultValue;
+ private final Object value;
+
+ private Optional<?> resolvedValue;
+ private Object resolvedDefaultValue;
+ private String jmxName;
+
+ public AttributeConfigElement(Object dafaultValue, Object value) {
+ this.dafaultValue = dafaultValue;
+ this.value = value;
+ }
+
+ public void setJmxName(String jmxName) {
+ this.jmxName = jmxName;
+ }
+
+ public String getJmxName() {
+ return jmxName;
+ }
+
+ public void resolveValue(AttributeResolvingStrategy<?, ? extends OpenType<?>> attributeResolvingStrategy,
+ String attrName) {
+ resolvedValue = attributeResolvingStrategy.parseAttribute(attrName, value);
+ Optional<?> resolvedDefault = attributeResolvingStrategy.parseAttribute(attrName, dafaultValue);
+ resolvedDefaultValue = resolvedDefault.isPresent() ? resolvedDefault.get() : null;
+
+ }
+
+ public static AttributeConfigElement create(AttributeIfc attributeIfc, Object value) {
+ return new AttributeConfigElement(attributeIfc.getNullableDefault(), value);
+ }
+
+ public static AttributeConfigElement createNullValue(AttributeIfc attributeIfc) {
+ return new AttributeConfigElement(attributeIfc.getNullableDefault(), null);
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public Optional<?> getResolvedValue() {
+ return resolvedValue;
+ }
+
+ public Object getResolvedDefaultValue() {
+ return resolvedDefaultValue;
+ }
+
+ @Override
+ public String toString() {
+ return "AttributeConfigElement [dafaultValue=" + dafaultValue + ", value=" + value + "]";
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.fromxml;
+
+import java.util.List;
+
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+
+public interface AttributeReadingStrategy {
+
+ public abstract AttributeConfigElement readElement(List<XmlElement> element);
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.fromxml;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+public class CompositeAttributeReadingStrategy extends AbstractAttributeReadingStrategy<TOAttribute> {
+
+ private final Map<String, AttributeReadingStrategy> innerStrategies;
+
+ public CompositeAttributeReadingStrategy(TOAttribute attributeIfc,
+ Map<String, AttributeReadingStrategy> innerStrategies) {
+ super(attributeIfc);
+ this.innerStrategies = innerStrategies;
+ }
+
+ @Override
+ AttributeConfigElement readElementHook(List<XmlElement> configNodes) {
+
+ Preconditions.checkState(configNodes.size() == 1, "This element should be present only once %s", configNodes);
+
+ XmlElement complexElement = configNodes.get(0);
+
+ Map<String, Object> innerMap = Maps.newHashMap();
+
+ Map<String, AttributeIfc> inner = getAttributeIfc().getYangPropertiesToTypesMap();
+
+ List<XmlElement> recognisedChildren = Lists.newArrayList();
+ for (Entry<String, AttributeIfc> innerAttrEntry : inner.entrySet()) {
+ List<XmlElement> childItem = complexElement.getChildElementsWithSameNamespace(innerAttrEntry.getKey());
+ recognisedChildren.addAll(childItem);
+
+ AttributeConfigElement resolvedInner = innerStrategies.get(innerAttrEntry.getKey()).readElement(childItem);
+
+ innerMap.put(innerAttrEntry.getKey(), resolvedInner.getValue());
+ }
+
+ complexElement.checkUnrecognisedElements(recognisedChildren);
+
+ return AttributeConfigElement.create(getAttributeIfc(), innerMap);
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.fromxml;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.ObjectNameAttributeMappingStrategy;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+
+import java.util.List;
+
+public class ObjectNameAttributeReadingStrategy extends AbstractAttributeReadingStrategy<AttributeIfc> {
+
+ public ObjectNameAttributeReadingStrategy(DependencyAttribute attributeIfc) {
+ super(attributeIfc);
+ }
+
+ @Override
+ AttributeConfigElement readElementHook(List<XmlElement> configNodes) {
+
+ XmlElement firstChild = configNodes.get(0);
+ Preconditions.checkState(configNodes.size() == 1, "This element should be present only once " + firstChild
+ + " but was " + configNodes.size());
+
+ Preconditions.checkNotNull(firstChild, "Element %s should be present", firstChild);
+ return AttributeConfigElement.create(getAttributeIfc(), resolve(firstChild));
+ }
+
+ private ObjectNameAttributeMappingStrategy.MappedDependency resolve(XmlElement firstChild) {
+ XmlElement typeElement = firstChild.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.TYPE_KEY);
+ String serviceName = typeElement.getTextContent();
+ XmlElement nameElement = firstChild.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.NAME_KEY);
+ String dependencyName = nameElement.getTextContent();
+
+ return new ObjectNameAttributeMappingStrategy.MappedDependency(serviceName, dependencyName);
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.fromxml;
+
+import com.google.common.collect.Maps;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.*;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
+
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.SimpleType;
+import java.util.Map;
+import java.util.Map.Entry;
+
+public class ObjectXmlReader extends AttributeIfcSwitchStatement<AttributeReadingStrategy> {
+
+ private String key;
+
+ public Map<String, AttributeReadingStrategy> prepareReading(Map<String, AttributeIfc> yangToAttrConfig) {
+ Map<String, AttributeReadingStrategy> strategies = Maps.newHashMap();
+
+ for (Entry<String, AttributeIfc> attributeEntry : yangToAttrConfig.entrySet()) {
+ AttributeReadingStrategy strat = prepareReadingStrategy(attributeEntry.getKey(), attributeEntry.getValue());
+ strategies.put(attributeEntry.getKey(), strat);
+ }
+ return strategies;
+ }
+
+ private AttributeReadingStrategy prepareReadingStrategy(String key, AttributeIfc attributeIfc) {
+ this.key = key;
+ return switchAttribute(attributeIfc);
+ }
+
+ @Override
+ protected AttributeReadingStrategy caseJavaAttribute(JavaAttribute attributeIfc) {
+ if (attributeIfc.getOpenType() instanceof SimpleType<?>)
+ return new SimpleAttributeReadingStrategy(attributeIfc);
+ else if (attributeIfc.getOpenType() instanceof ArrayType<?>) {
+ SimpleAttributeReadingStrategy innerStrategy = new SimpleAttributeReadingStrategy(
+ ((ArrayType<?>) attributeIfc.getOpenType()).getElementOpenType());
+ return new ArrayAttributeReadingStrategy(attributeIfc, innerStrategy);
+ }
+ throw new IllegalStateException(JavaAttribute.class + " can only provide open type " + SimpleType.class
+ + " or " + ArrayType.class);
+ }
+
+ @Override
+ protected AttributeReadingStrategy caseDependencyAttribute(DependencyAttribute attributeIfc) {
+ return new ObjectNameAttributeReadingStrategy(attributeIfc);
+ }
+
+ @Override
+ protected AttributeReadingStrategy caseTOAttribute(TOAttribute attributeIfc) {
+ Map<String, AttributeIfc> inner = attributeIfc.getYangPropertiesToTypesMap();
+ Map<String, AttributeReadingStrategy> innerStrategies = Maps.newHashMap();
+
+ for (Entry<String, AttributeIfc> innerAttrEntry : inner.entrySet()) {
+ AttributeReadingStrategy innerStrat = prepareReadingStrategy(innerAttrEntry.getKey(),
+ innerAttrEntry.getValue());
+ innerStrategies.put(innerAttrEntry.getKey(), innerStrat);
+ }
+
+ return new CompositeAttributeReadingStrategy(attributeIfc, innerStrategies);
+ }
+
+ @Override
+ protected AttributeReadingStrategy caseListAttribute(ListAttribute attributeIfc) {
+ AttributeIfc innerAttr = attributeIfc.getInnerAttribute();
+ AttributeReadingStrategy innerStrategy = prepareReadingStrategy(key, innerAttr);
+ return new ArrayAttributeReadingStrategy(attributeIfc, innerStrategy);
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.fromxml;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+
+import javax.management.openmbean.OpenType;
+import java.util.List;
+
+public class SimpleAttributeReadingStrategy extends AbstractAttributeReadingStrategy<AttributeIfc> {
+
+ public SimpleAttributeReadingStrategy(AttributeIfc attributeIfc) {
+ super(attributeIfc);
+ }
+
+ /**
+ * @param elementOpenType
+ */
+ public SimpleAttributeReadingStrategy(OpenType<?> elementOpenType) {
+ super(new AttributeIfcWrapper(elementOpenType));
+ }
+
+ @Override
+ AttributeConfigElement readElementHook(List<XmlElement> configNodes) {
+ XmlElement xmlElement = configNodes.get(0);
+ Preconditions.checkState(configNodes.size() == 1, "This element should be present only once " + xmlElement
+ + " but was " + configNodes.size());
+
+ String textContent = xmlElement.getTextContent();
+
+ Preconditions.checkNotNull(textContent, "This element should contain text %s", xmlElement);
+ return AttributeConfigElement.create(getAttributeIfc(), textContent);
+ }
+
+ /**
+ * Wrapper for JavaAttribute inner element attributes (in case JavaAttribute
+ * is array)
+ */
+ static class AttributeIfcWrapper implements AttributeIfc {
+
+ private final OpenType<?> elementOpenType;
+
+ public AttributeIfcWrapper(OpenType<?> elementOpenType) {
+ this.elementOpenType = elementOpenType;
+ }
+
+ @Override
+ public String getAttributeYangName() {
+ return null;
+ }
+
+ @Override
+ public String getNullableDescription() {
+ return null;
+ }
+
+ @Override
+ public String getNullableDefault() {
+ return null;
+ }
+
+ @Override
+ public String getUpperCaseCammelCase() {
+ return null;
+ }
+
+ @Override
+ public String getLowerCaseCammelCase() {
+ return null;
+ }
+
+ @Override
+ public OpenType<?> getOpenType() {
+ return elementOpenType;
+ }
+
+ }
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.mapping;
+
+import javax.management.openmbean.OpenType;
+
+public abstract class AbstractAttributeMappingStrategy<T, O extends OpenType<?>> implements
+ AttributeMappingStrategy<T, O> {
+
+ private final O attrOpenType;
+
+ public AbstractAttributeMappingStrategy(O attributeIfc) {
+ this.attrOpenType = attributeIfc;
+ }
+
+ @Override
+ public O getOpenType() {
+ return attrOpenType;
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.mapping;
+
+import java.lang.reflect.Array;
+import java.util.List;
+
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.OpenType;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+
+public class ArrayAttributeMappingStrategy extends AbstractAttributeMappingStrategy<List<Object>, ArrayType<?>> {
+
+ private final AttributeMappingStrategy<?, ? extends OpenType<?>> innerElementStrategy;
+
+ public ArrayAttributeMappingStrategy(ArrayType<?> arrayType,
+ AttributeMappingStrategy<?, ? extends OpenType<?>> innerElementStrategy) {
+ super(arrayType);
+ this.innerElementStrategy = innerElementStrategy;
+ }
+
+ @Override
+ public Optional<List<Object>> mapAttribute(Object value) {
+ if (value == null)
+ return Optional.absent();
+
+ Preconditions.checkArgument(value.getClass().isArray(), "Value has to be instanceof Array ");
+
+ List<Object> retVal = Lists.newArrayList();
+
+ for (int i = 0; i < Array.getLength(value); i++) {
+ Object innerValue = Array.get(value, i);
+ // String expectedClassName =
+ // getOpenType().getElementOpenType().getClassName();
+ // String realClassName = value.getClass().getName();
+
+ // Preconditions.checkState(realClassName.contains(expectedClassName),
+ // "Element in collection/array should be of type " +
+ // expectedClassName + " but was "
+ // + realClassName + " for attribute: " + getOpenType());
+
+ Optional<?> mapAttribute = innerElementStrategy.mapAttribute(innerValue);
+
+ if (mapAttribute.isPresent())
+ retVal.add(mapAttribute.get());
+ }
+
+ return Optional.of(retVal);
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.mapping;
+
+import com.google.common.base.Optional;
+
+import javax.management.openmbean.OpenType;
+
+public interface AttributeMappingStrategy<T, O extends OpenType<?>> {
+
+ O getOpenType();
+
+ Optional<T> mapAttribute(Object o);
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.mapping;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
+
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import java.util.Map;
+import java.util.Set;
+
+public class CompositeAttributeMappingStrategy extends
+ AbstractAttributeMappingStrategy<Map<String, Object>, CompositeType> {
+
+ private final Map<String, AttributeMappingStrategy<?, ? extends OpenType<?>>> innerStrategies;
+ private final Map<String, String> jmxToJavaNameMapping;
+
+ public CompositeAttributeMappingStrategy(CompositeType compositeType,
+ Map<String, AttributeMappingStrategy<?, ? extends OpenType<?>>> innerStrategies,
+ Map<String, String> jmxToJavaNameMapping) {
+ super(compositeType);
+ this.innerStrategies = innerStrategies;
+ this.jmxToJavaNameMapping = jmxToJavaNameMapping;
+ }
+
+ @Override
+ public Optional<Map<String, Object>> mapAttribute(Object value) {
+ if (value == null)
+ return Optional.absent();
+
+ Util.checkType(value, CompositeDataSupport.class);
+
+ CompositeDataSupport compositeData = (CompositeDataSupport) value;
+ CompositeType currentType = compositeData.getCompositeType();
+ CompositeType expectedType = getOpenType();
+
+ Set<String> expectedCompositeTypeKeys = expectedType.keySet();
+ Set<String> currentCompositeTypeKeys = currentType.keySet();
+ Preconditions.checkArgument(expectedCompositeTypeKeys.equals(currentCompositeTypeKeys),
+ "Composite type mismatch, expected composite type with attributes " + expectedCompositeTypeKeys
+ + " but was " + currentCompositeTypeKeys);
+
+ Map<String, Object> retVal = Maps.newHashMap();
+
+ for (String jmxName : jmxToJavaNameMapping.keySet()) {
+ String innerAttrJmxName = jmxName;
+ Object innerValue = compositeData.get(innerAttrJmxName);
+
+ AttributeMappingStrategy<?, ? extends OpenType<?>> attributeMappingStrategy = innerStrategies
+ .get(innerAttrJmxName);
+ Optional<?> mapAttribute = attributeMappingStrategy.mapAttribute(innerValue);
+ if (mapAttribute.isPresent())
+ retVal.put(jmxToJavaNameMapping.get(innerAttrJmxName), mapAttribute.get());
+ }
+
+ return Optional.of(retVal);
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.mapping;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.*;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
+
+import com.google.common.collect.Maps;
+
+public class ObjectMapper extends AttributeIfcSwitchStatement<AttributeMappingStrategy<?, ? extends OpenType<?>>> {
+
+ private final Services dependencyTracker;
+
+ public ObjectMapper(Services depTracker) {
+ this.dependencyTracker = depTracker;
+ }
+
+ public Map<String, AttributeMappingStrategy<?, ? extends OpenType<?>>> prepareMapping(
+ Map<String, AttributeIfc> configDefinition) {
+ Map<String, AttributeMappingStrategy<?, ? extends OpenType<?>>> strategies = Maps.newHashMap();
+
+ for (Entry<String, AttributeIfc> attrEntry : configDefinition.entrySet()) {
+ strategies.put(attrEntry.getKey(), prepareStrategy(attrEntry.getValue()));
+ }
+
+ return strategies;
+ }
+
+ private AttributeMappingStrategy<?, ? extends OpenType<?>> prepareStrategy(AttributeIfc attributeIfc) {
+ return switchAttribute(attributeIfc);
+ }
+
+ private Map<String, String> createJmxToYangMapping(TOAttribute attributeIfc) {
+ Map<String, String> retVal = Maps.newHashMap();
+ for (Entry<String, AttributeIfc> entry : attributeIfc.getJmxPropertiesToTypesMap().entrySet()) {
+ retVal.put(entry.getKey(), (entry.getValue()).getAttributeYangName());
+ }
+ return retVal;
+ }
+
+ @Override
+ protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseJavaAttribute(JavaAttribute attributeIfc) {
+
+ if (attributeIfc.getOpenType() instanceof SimpleType<?>)
+ return new SimpleAttributeMappingStrategy((SimpleType<?>) attributeIfc.getOpenType());
+ else if (attributeIfc.getOpenType() instanceof ArrayType<?>) {
+ ArrayType<?> arrayType = (ArrayType<?>) attributeIfc.getOpenType();
+ AttributeMappingStrategy<?, ? extends OpenType<?>> innerStrategy = new SimpleAttributeMappingStrategy(
+ (SimpleType<?>) arrayType.getElementOpenType());
+ return new ArrayAttributeMappingStrategy(arrayType, innerStrategy);
+ }
+ throw new IllegalStateException(JavaAttribute.class + " can only provide open type " + SimpleType.class
+ + " or " + ArrayType.class);
+ }
+
+ @Override
+ protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseDependencyAttribute(
+ DependencyAttribute attributeIfc) {
+ String serviceName = attributeIfc.getDependency().getSie().getQName().getLocalName();
+ return new ObjectNameAttributeMappingStrategy((SimpleType<?>) attributeIfc.getOpenType(), dependencyTracker,
+ serviceName);
+ }
+
+ @Override
+ protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseTOAttribute(TOAttribute attributeIfc) {
+ Map<String, AttributeMappingStrategy<?, ? extends OpenType<?>>> innerStrategies = Maps.newHashMap();
+
+ for (Entry<String, AttributeIfc> innerAttrEntry : attributeIfc.getJmxPropertiesToTypesMap().entrySet()) {
+ innerStrategies.put(innerAttrEntry.getKey(), prepareStrategy(innerAttrEntry.getValue()));
+ }
+
+ return new CompositeAttributeMappingStrategy((CompositeType) attributeIfc.getOpenType(), innerStrategies,
+ createJmxToYangMapping(attributeIfc));
+ }
+
+ @Override
+ protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseListAttribute(ListAttribute attributeIfc) {
+ return new ArrayAttributeMappingStrategy(attributeIfc.getOpenType(),
+ prepareStrategy(attributeIfc.getInnerAttribute()));
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.mapping;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
+import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
+
+import javax.management.ObjectName;
+import javax.management.openmbean.SimpleType;
+
+public class ObjectNameAttributeMappingStrategy extends
+ AbstractAttributeMappingStrategy<ObjectNameAttributeMappingStrategy.MappedDependency, SimpleType<?>> {
+
+ private final Services tracker;
+ private final String serviceName;
+
+ public ObjectNameAttributeMappingStrategy(SimpleType<?> openType, Services dependencyTracker, String serviceName) {
+ super(openType);
+ this.tracker = dependencyTracker;
+ this.serviceName = serviceName;
+ }
+
+ @Override
+ public Optional<MappedDependency> mapAttribute(Object value) {
+ if (value == null)
+ return Optional.absent();
+
+ String expectedClass = getOpenType().getClassName();
+ String realClass = value.getClass().getName();
+ Preconditions.checkArgument(realClass.equals(expectedClass), "Type mismatch, expected " + expectedClass
+ + " but was " + realClass);
+ Util.checkType(value, ObjectName.class);
+
+ ObjectName on = (ObjectName) value;
+ String refName = tracker.addServiceEntry(serviceName, on);
+
+ return Optional.of(new MappedDependency(serviceName, refName));
+ }
+
+ public static class MappedDependency {
+ private final String serviceName, refName;
+
+ public MappedDependency(String serviceName, String refName) {
+ this.serviceName = serviceName;
+ this.refName = refName;
+ }
+
+ public String getServiceName() {
+ return serviceName;
+ }
+
+ public String getRefName() {
+ return refName;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuffer sb = new StringBuffer("MappedDependency{");
+ sb.append("serviceName='").append(serviceName).append('\'');
+ sb.append(", refName='").append(refName).append('\'');
+ sb.append('}');
+ return sb.toString();
+ }
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.mapping;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
+
+import javax.management.openmbean.SimpleType;
+import java.util.Date;
+import java.util.Map;
+
+public class SimpleAttributeMappingStrategy extends AbstractAttributeMappingStrategy<String, SimpleType<?>> {
+
+ public SimpleAttributeMappingStrategy(SimpleType<?> openType) {
+ super(openType);
+ }
+
+ @Override
+ public Optional<String> mapAttribute(Object value) {
+ if (value == null)
+ return Optional.absent();
+
+ String expectedClass = getOpenType().getClassName();
+ String realClass = value.getClass().getName();
+ Preconditions.checkArgument(realClass.equals(expectedClass), "Type mismatch, expected " + expectedClass
+ + " but was " + realClass);
+
+ WriterPlugin prefferedPlugin = writerPlugins.get(value.getClass().getCanonicalName());
+ prefferedPlugin = prefferedPlugin == null ? writerPlugins.get(DEFAULT_WRITER_PLUGIN) : prefferedPlugin;
+ return Optional.of(prefferedPlugin.writeObject(value));
+ }
+
+ private static final String DEFAULT_WRITER_PLUGIN = "default";
+ private static final Map<String, WriterPlugin> writerPlugins = Maps.newHashMap();
+ static {
+ writerPlugins.put(DEFAULT_WRITER_PLUGIN, new DefaultWriterPlugin());
+ writerPlugins.put(Date.class.getCanonicalName(), new DatePlugin());
+ }
+
+ /**
+ * Custom writer plugins must implement this interface.
+ */
+ static interface WriterPlugin {
+ String writeObject(Object value);
+ }
+
+ static class DefaultWriterPlugin implements WriterPlugin {
+
+ @Override
+ public String writeObject(Object value) {
+ return value.toString();
+ }
+ }
+
+ static class DatePlugin implements WriterPlugin {
+
+ @Override
+ public String writeObject(Object value) {
+ Preconditions.checkArgument(value instanceof Date, "Attribute must be Date");
+ return Util.writeDate((Date) value);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.resolving;
+
+import javax.management.openmbean.OpenType;
+
+abstract class AbstractAttributeResolvingStrategy<T, O extends OpenType<?>> implements AttributeResolvingStrategy<T, O> {
+ private final O openType;
+
+ public AbstractAttributeResolvingStrategy(O openType) {
+ this.openType = openType;
+ }
+
+ @Override
+ public O getOpenType() {
+ return openType;
+ }
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.resolving;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import java.lang.reflect.Array;
+import java.util.List;
+
+final class ArrayAttributeResolvingStrategy extends AbstractAttributeResolvingStrategy<Object, ArrayType<?>> {
+
+ private final AttributeResolvingStrategy<?, ? extends OpenType<?>> innerTypeResolvingStrategy;
+
+ private static final Logger logger = LoggerFactory.getLogger(ArrayAttributeResolvingStrategy.class);
+
+ public ArrayAttributeResolvingStrategy(AttributeResolvingStrategy<?, ? extends OpenType<?>> innerTypeResolved,
+ ArrayType<?> openType) {
+ super(openType);
+ this.innerTypeResolvingStrategy = innerTypeResolved;
+ }
+
+ @Override
+ public Optional<Object> parseAttribute(String attrName, Object value) {
+ if (value == null) {
+ return Optional.absent();
+ }
+
+ Util.checkType(value, List.class);
+ List<?> valueList = (List<?>) value;
+
+ Class<?> innerTypeClass = null;
+
+ if (innerTypeResolvingStrategy.getOpenType() instanceof CompositeType) {
+ innerTypeClass = CompositeDataSupport.class;
+ } else
+ try {
+ innerTypeClass = Class.forName(getOpenType().getElementOpenType().getClassName());
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException("Unable to locate class for "
+ + getOpenType().getElementOpenType().getClassName(), e);
+ }
+
+ Object parsedArray = null;
+
+ if (getOpenType().isPrimitiveArray()) {
+ Class<?> primitiveType = getPrimitiveType(innerTypeClass);
+ parsedArray = Array.newInstance(primitiveType, valueList.size());
+ } else
+ parsedArray = Array.newInstance(innerTypeClass, valueList.size());
+
+ int i = 0;
+ for (Object innerValue : valueList) {
+ Optional<?> parsedElement = innerTypeResolvingStrategy.parseAttribute(attrName + "_" + i, innerValue);
+
+ if (!parsedElement.isPresent())
+ continue;
+
+ Array.set(parsedArray, i, parsedElement.get());
+ // parsedArray[i] = parsedElement.get();
+ i++;
+ }
+
+ logger.debug("Attribute {} : {} parsed to type {} as {}", attrName, value, getOpenType(),
+ toStringArray(parsedArray));
+
+ return Optional.of(parsedArray);
+ }
+
+ private static String toStringArray(Object array) {
+ StringBuilder build = new StringBuilder(array.toString());
+ build.append(" [");
+ for (int i = 0; i < Array.getLength(array); i++) {
+ build.append(Array.get(array, i).toString());
+ build.append(",");
+ }
+ build.append("]]");
+ return build.toString();
+ }
+
+ private static Class<?> getPrimitiveType(Class<?> innerTypeClass) {
+ try {
+ return (Class<?>) innerTypeClass.getField("TYPE").get(null);
+ } catch (Exception e) {
+ throw new RuntimeException("Unable to determine primitive type to " + innerTypeClass);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "ResolvedArrayTypeAttributeType [innerTypeResolved=" + innerTypeResolvingStrategy + "]";
+ }
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.resolving;
+
+import com.google.common.base.Optional;
+
+import javax.management.openmbean.OpenType;
+
+/**
+ * Create real object from String or Map that corresponds to given opentype.
+ */
+public interface AttributeResolvingStrategy<T, O extends OpenType<?>> {
+ O getOpenType();
+
+ Optional<T> parseAttribute(String attrName, Object value);
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.resolving;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.OpenType;
+import java.util.Map;
+
+final class CompositeAttributeResolvingStrategy extends
+ AbstractAttributeResolvingStrategy<CompositeDataSupport, CompositeType> {
+ private final Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> innerTypes;
+ private final Map<String, String> yangToJavaAttrMapping;
+
+ private static final Logger logger = LoggerFactory.getLogger(CompositeAttributeResolvingStrategy.class);
+
+ CompositeAttributeResolvingStrategy(Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> innerTypes,
+ CompositeType openType, Map<String, String> yangToJavaAttrMapping) {
+ super(openType);
+ this.innerTypes = innerTypes;
+ this.yangToJavaAttrMapping = yangToJavaAttrMapping;
+ }
+
+ @Override
+ public String toString() {
+ return "ResolvedCompositeAttribute [" + innerTypes + "]";
+ }
+
+ @Override
+ public Optional<CompositeDataSupport> parseAttribute(String attrName, Object value) {
+
+ if (value == null) {
+ return Optional.absent();
+ }
+
+ Util.checkType(value, Map.class);
+ Map<?, ?> valueMap = (Map<?, ?>) value;
+
+ Map<String, Object> items = Maps.newHashMap();
+ Map<String, OpenType<?>> openTypes = Maps.newHashMap();
+
+ for (Object innerAttrName : innerTypes.keySet()) {
+ Preconditions.checkState(innerAttrName instanceof String, "Attribute name must be string");
+ String innerAttrNameStr = (String) innerAttrName;
+
+ AttributeResolvingStrategy<?, ? extends OpenType<?>> attributeResolvingStrategy = innerTypes
+ .get(innerAttrName);
+
+ Object valueToParse = valueMap.get(innerAttrName);
+
+ Optional<?> parsedInnerValue = attributeResolvingStrategy.parseAttribute(innerAttrNameStr, valueToParse);
+
+ openTypes.put(innerAttrNameStr, attributeResolvingStrategy.getOpenType());
+
+ items.put(yangToJavaAttrMapping.get(innerAttrNameStr),
+ parsedInnerValue.isPresent() ? parsedInnerValue.get() : null);
+ }
+
+ CompositeDataSupport parsedValue = null;
+ try {
+ parsedValue = new CompositeDataSupport(getOpenType(), items);
+ } catch (OpenDataException e) {
+ throw new RuntimeException("An error occured during restoration of composite type " + this
+ + " for attribute " + attrName + " from value " + value, e);
+ }
+
+ logger.debug("Attribute {} : {} parsed to type {} as {}", attrName, value, getOpenType(), parsedValue);
+
+ return Optional.of(parsedValue);
+ }
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.resolving;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.ObjectNameAttributeMappingStrategy;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services.ServiceInstance;
+import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.management.ObjectName;
+import javax.management.openmbean.SimpleType;
+
+public class ObjectNameAttributeResolvingStrategy extends AbstractAttributeResolvingStrategy<ObjectName, SimpleType<?>> {
+
+ private final Services serviceTracker;
+ private static final Logger logger = LoggerFactory.getLogger(ObjectNameAttributeResolvingStrategy.class);
+
+ ObjectNameAttributeResolvingStrategy(Services serviceTracker) {
+ super(SimpleType.OBJECTNAME);
+ this.serviceTracker = serviceTracker;
+ }
+
+ @Override
+ public Optional<ObjectName> parseAttribute(String attrName, Object value) {
+ if (value == null) {
+ return Optional.absent();
+ }
+
+ Util.checkType(value, ObjectNameAttributeMappingStrategy.MappedDependency.class);
+
+ ObjectNameAttributeMappingStrategy.MappedDependency mappedDep = (ObjectNameAttributeMappingStrategy.MappedDependency) value;
+ ServiceInstance byRefName = serviceTracker.getByServiceAndRefName(mappedDep.getServiceName(),
+ mappedDep.getRefName());
+ ObjectName on = ObjectNameUtil.createReadOnlyModuleON(byRefName.getModuleName(), byRefName.getInstanceName());
+ logger.debug("Attribute {} : {} parsed to type {}", attrName, value, getOpenType());
+ return Optional.of(on);
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.resolving;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.*;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+
+public class ObjectResolver extends AttributeIfcSwitchStatement<AttributeResolvingStrategy<?, ? extends OpenType<?>>> {
+
+ private final Services serviceTracker;
+ private OpenType<?> openType;
+
+ public ObjectResolver(Services serviceTracker) {
+ this.serviceTracker = serviceTracker;
+ }
+
+ public Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> prepareResolving(
+ Map<String, AttributeIfc> configDefinition) {
+ Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> strategies = Maps.newHashMap();
+
+ for (Entry<String, AttributeIfc> attrEntry : configDefinition.entrySet()) {
+ strategies.put(attrEntry.getKey(),
+ prepareStrategy(attrEntry.getValue(), attrEntry.getValue().getOpenType()));
+ }
+
+ return strategies;
+ }
+
+ private AttributeResolvingStrategy<?, ? extends OpenType<?>> prepareStrategy(AttributeIfc attributeIfc,
+ OpenType<?> openType) {
+
+ this.openType = openType;
+ return switchAttribute(attributeIfc);
+ }
+
+ private Map<String, String> createYangToJmxMapping(TOAttribute attributeIfc) {
+ Map<String, String> retVal = Maps.newHashMap();
+ for (Entry<String, AttributeIfc> entry : attributeIfc.getYangPropertiesToTypesMap().entrySet()) {
+ retVal.put(entry.getKey(), (entry.getValue()).getLowerCaseCammelCase());
+ }
+ return retVal;
+ }
+
+ @Override
+ protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseJavaAttribute(JavaAttribute attributeIfc) {
+ if (attributeIfc.getOpenType() instanceof SimpleType<?>)
+ return new SimpleAttributeResolvingStrategy((SimpleType<?>) openType);
+ else if (attributeIfc.getOpenType() instanceof ArrayType<?>) {
+ ArrayType<?> arrayType = (ArrayType<?>) openType;
+ SimpleType<?> innerType = (SimpleType<?>) arrayType.getElementOpenType();
+ AttributeResolvingStrategy<?, ? extends OpenType<?>> strat = new SimpleAttributeResolvingStrategy(innerType);
+ return new ArrayAttributeResolvingStrategy(strat, arrayType);
+ }
+ throw new IllegalStateException(JavaAttribute.class + " can only provide open type " + SimpleType.class
+ + " or " + ArrayType.class);
+ }
+
+ @Override
+ protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseDependencyAttribute(
+ DependencyAttribute attributeIfc) {
+ return new ObjectNameAttributeResolvingStrategy(serviceTracker);
+ }
+
+ @Override
+ protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseTOAttribute(TOAttribute attributeIfc) {
+ CompositeType compositeType = (CompositeType) openType;
+ Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> innerMap = Maps.newHashMap();
+ for (String innerName : compositeType.keySet()) {
+ Preconditions.checkState(attributeIfc instanceof TOAttribute, "Unexpected state, " + attributeIfc
+ + " should be instance of " + TOAttribute.class.getName());
+ AttributeIfc innerAttributeIfc = attributeIfc.getJmxPropertiesToTypesMap().get(innerName);
+ innerMap.put(innerAttributeIfc.getAttributeYangName(),
+ prepareStrategy(innerAttributeIfc, compositeType.getType(innerName)));
+ }
+ return new CompositeAttributeResolvingStrategy(innerMap, compositeType, createYangToJmxMapping(attributeIfc));
+ }
+
+ @Override
+ protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseListAttribute(ListAttribute attributeIfc) {
+ ArrayType<?> arrayType = (ArrayType<?>) openType;
+ OpenType<?> innerType = arrayType.getElementOpenType();
+ AttributeIfc inner = attributeIfc.getInnerAttribute();
+ return new ArrayAttributeResolvingStrategy(prepareStrategy(inner, innerType), arrayType);
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.resolving;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Maps;
+import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.management.openmbean.SimpleType;
+import java.lang.reflect.Method;
+import java.math.BigInteger;
+import java.util.Date;
+import java.util.Map;
+
+final class SimpleAttributeResolvingStrategy extends AbstractAttributeResolvingStrategy<Object, SimpleType<?>> {
+
+ private static final Logger logger = LoggerFactory.getLogger(SimpleAttributeResolvingStrategy.class);
+
+ SimpleAttributeResolvingStrategy(SimpleType<?> simpleType) {
+ super(simpleType);
+ }
+
+ @Override
+ public String toString() {
+ return "ResolvedSimpleAttribute [" + getOpenType().getClassName() + "]";
+ }
+
+ @Override
+ public Optional<Object> parseAttribute(String attrName, Object value) {
+ if (value == null) {
+ return Optional.absent();
+ }
+
+ Class<?> cls;
+ try {
+ cls = Class.forName(getOpenType().getClassName());
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException("Unable to locate class for " + getOpenType().getClassName(), e);
+ }
+
+ Util.checkType(value, String.class);
+
+ Resolver prefferedPlugin = resolverPlugins.get(cls.getCanonicalName());
+ prefferedPlugin = prefferedPlugin == null ? resolverPlugins.get(DEFAULT_RESOLVERS) : prefferedPlugin;
+
+ Object parsedValue = prefferedPlugin.resolveObject(cls, attrName, (String) value);
+ logger.debug("Attribute {} : {} parsed to type {} with value {}", attrName, value, getOpenType(), parsedValue);
+ return Optional.of(parsedValue);
+ }
+
+ private static final String DEFAULT_RESOLVERS = "default";
+ private static final Map<String, Resolver> resolverPlugins = Maps.newHashMap();
+
+ static {
+ resolverPlugins.put(DEFAULT_RESOLVERS, new DefaultResolver());
+ resolverPlugins.put(String.class.getCanonicalName(), new StringResolver());
+ resolverPlugins.put(Date.class.getCanonicalName(), new DateResolver());
+ resolverPlugins.put(Character.class.getCanonicalName(), new CharResolver());
+ resolverPlugins.put(BigInteger.class.getCanonicalName(), new BigIntegerResolver());
+ }
+
+ static interface Resolver {
+ Object resolveObject(Class<?> type, String attrName, String value);
+ }
+
+ static class DefaultResolver implements Resolver {
+
+ @Override
+ public Object resolveObject(Class<?> type, String attrName, String value) {
+ try {
+ Object parsedValue = parseObject(type, value);
+ return parsedValue;
+ } catch (Exception e) {
+ throw new RuntimeException("Unable to resolve attribute " + attrName + " from " + value, e);
+ }
+ }
+
+ protected Object parseObject(Class<?> type, String value) throws Exception {
+ Method method = type.getMethod("valueOf", String.class);
+ Object parsedValue = method.invoke(null, value);
+ return parsedValue;
+ }
+ }
+
+ static class StringResolver extends DefaultResolver {
+
+ @Override
+ protected Object parseObject(Class<?> type, String value) throws Exception {
+ return value;
+ }
+ }
+
+ static class BigIntegerResolver extends DefaultResolver {
+
+ @Override
+ protected Object parseObject(Class<?> type, String value) throws Exception {
+ return new BigInteger(value);
+ }
+ }
+
+ static class CharResolver extends DefaultResolver {
+
+ @Override
+ protected Object parseObject(Class<?> type, String value) throws Exception {
+ return new Character(value.charAt(0));
+ }
+ }
+
+ static class DateResolver extends DefaultResolver {
+
+ @Override
+ protected Object parseObject(Class<?> type, String value) throws Exception {
+ return Util.readDate(value);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.toxml;
+
+import java.util.List;
+
+import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
+import org.w3c.dom.Element;
+
+public class ArrayAttributeWritingStrategy implements AttributeWritingStrategy {
+
+ private final AttributeWritingStrategy innnerStrategy;
+
+ public ArrayAttributeWritingStrategy(AttributeWritingStrategy innerStrategy) {
+ this.innnerStrategy = innerStrategy;
+ }
+
+ @Override
+ public void writeElement(Element parentElement, String namespace, Object value) {
+ Util.checkType(value, List.class);
+
+ for (Object innerObject : ((List<?>) value)) {
+ innnerStrategy.writeElement(parentElement, namespace, innerObject);
+ }
+
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.toxml;
+
+import org.w3c.dom.Element;
+
+public interface AttributeWritingStrategy {
+
+ void writeElement(Element parentElement, String namespace, Object value);
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.toxml;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class CompositeAttributeWritingStrategy implements AttributeWritingStrategy {
+
+ protected final String key;
+ protected final Document document;
+ protected final Map<String, AttributeWritingStrategy> innerStrats;
+
+ public CompositeAttributeWritingStrategy(Document document, String key,
+ Map<String, AttributeWritingStrategy> innerStrats) {
+ this.document = document;
+ this.key = key;
+ this.innerStrats = innerStrats;
+ }
+
+ @Override
+ public void writeElement(Element parentElement, String namespace, Object value) {
+ Util.checkType(value, Map.class);
+
+ Element innerNode = document.createElement(key);
+ XmlUtil.addNamespaceAttr(innerNode, namespace);
+
+ Map<?, ?> map = (Map<?, ?>) value;
+
+ for (Entry<?, ?> innerObjectEntry : map.entrySet()) {
+ Util.checkType(innerObjectEntry.getKey(), String.class);
+
+ String innerKey = (String) innerObjectEntry.getKey();
+ Object innerValue = innerObjectEntry.getValue();
+
+ innerStrats.get(innerKey).writeElement(innerNode, namespace, innerValue);
+ }
+ parentElement.appendChild(innerNode);
+ }
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.toxml;
+
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.ObjectNameAttributeMappingStrategy;
+import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
+import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class ObjectNameAttributeWritingStrategy implements AttributeWritingStrategy {
+
+ private final Document document;
+ private final String key;
+
+ /**
+ * @param document
+ * @param key
+ */
+ public ObjectNameAttributeWritingStrategy(Document document, String key) {
+ this.document = document;
+ this.key = key;
+ }
+
+ @Override
+ public void writeElement(Element parentElement, String namespace, Object value) {
+ Util.checkType(value, ObjectNameAttributeMappingStrategy.MappedDependency.class);
+ Element innerNode = document.createElement(key);
+ XmlUtil.addNamespaceAttr(innerNode, namespace);
+
+ String moduleName = ((ObjectNameAttributeMappingStrategy.MappedDependency) value).getServiceName();
+ String refName = ((ObjectNameAttributeMappingStrategy.MappedDependency) value).getRefName();
+
+ final Element typeElement = XmlUtil.createTextElement(document, XmlNetconfConstants.TYPE_KEY, moduleName);
+ innerNode.appendChild(typeElement);
+
+ final Element nameElement = XmlUtil.createTextElement(document, XmlNetconfConstants.NAME_KEY, refName);
+ innerNode.appendChild(nameElement);
+
+ parentElement.appendChild(innerNode);
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.toxml;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.*;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
+import org.w3c.dom.Document;
+
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.SimpleType;
+import java.util.Map;
+import java.util.Map.Entry;
+
+public class ObjectXmlWriter extends AttributeIfcSwitchStatement<AttributeWritingStrategy> {
+
+ private Document document;
+ private String key;
+
+ public Map<String, AttributeWritingStrategy> prepareWriting(Map<String, AttributeIfc> yangToAttrConfig,
+ Document document) {
+
+ Map<String, AttributeWritingStrategy> preparedWriting = Maps.newHashMap();
+
+ for (Entry<String, AttributeIfc> mappedAttributeEntry : yangToAttrConfig.entrySet()) {
+ String key = mappedAttributeEntry.getKey();
+ AttributeIfc value = mappedAttributeEntry.getValue();
+ AttributeWritingStrategy strat = prepareWritingStrategy(key, value, document);
+ preparedWriting.put(key, strat);
+ }
+
+ return preparedWriting;
+ }
+
+ private AttributeWritingStrategy prepareWritingStrategy(String key, AttributeIfc expectedAttr, Document document) {
+ Preconditions.checkNotNull(expectedAttr, "Mbean attributes mismatch, unable to find expected attribute for %s",
+ key);
+ this.document = document;
+ this.key = key;
+ return switchAttribute(expectedAttr);
+ }
+
+ @Override
+ protected AttributeWritingStrategy caseJavaAttribute(JavaAttribute attributeIfc) {
+
+ if (attributeIfc.getOpenType() instanceof SimpleType<?>)
+ return new SimpleAttributeWritingStrategy(document, key);
+ else if (attributeIfc.getOpenType() instanceof ArrayType<?>) {
+ AttributeWritingStrategy innerStrategy = new SimpleAttributeWritingStrategy(document, key);
+ return new ArrayAttributeWritingStrategy(innerStrategy);
+ }
+ throw new IllegalStateException(JavaAttribute.class + " can only provide open type " + SimpleType.class
+ + " or " + ArrayType.class);
+ }
+
+ @Override
+ protected AttributeWritingStrategy caseDependencyAttribute(DependencyAttribute attributeIfc) {
+ return new ObjectNameAttributeWritingStrategy(document, key);
+ }
+
+ @Override
+ protected AttributeWritingStrategy caseTOAttribute(TOAttribute attributeIfc) {
+ Map<String, AttributeWritingStrategy> innerStrats = Maps.newHashMap();
+ String currentKey = key;
+ for (Entry<String, AttributeIfc> innerAttrEntry : attributeIfc.getYangPropertiesToTypesMap().entrySet()) {
+
+ AttributeWritingStrategy innerStrategy = prepareWritingStrategy(innerAttrEntry.getKey(),
+ innerAttrEntry.getValue(), document);
+ innerStrats.put(innerAttrEntry.getKey(), innerStrategy);
+ }
+
+ return new CompositeAttributeWritingStrategy(document, currentKey, innerStrats);
+ }
+
+ @Override
+ protected AttributeWritingStrategy caseListAttribute(ListAttribute attributeIfc) {
+ AttributeIfc inner = attributeIfc.getInnerAttribute();
+ AttributeWritingStrategy innerStrategy = prepareWritingStrategy(key, inner, document);
+ return new ArrayAttributeWritingStrategy(innerStrategy);
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.toxml;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class RuntimeBeanEntryWritingStrategy extends CompositeAttributeWritingStrategy {
+
+ public RuntimeBeanEntryWritingStrategy(Document document, String key,
+ Map<String, AttributeWritingStrategy> innerStrats) {
+ super(document, key, innerStrats);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.opendaylight.controller.config.netconf.mapping.attributes.toxml.
+ * AttributeWritingStrategy#writeElement(org.w3c.dom.Element,
+ * java.lang.Object)
+ */
+ @Override
+ public void writeElement(Element parentElement, String namespace, Object value) {
+ Util.checkType(value, Map.class);
+
+ Element innerNode = document.createElement(key);
+
+ Map<?, ?> map = (Map<?, ?>) value;
+
+ for (Entry<?, ?> runtimeBeanInstanceMappingEntry : map.entrySet()) {
+
+ // wrap runtime attributes with number assigned to current runtime
+ // bean
+ Util.checkType(runtimeBeanInstanceMappingEntry.getValue(), Map.class);
+ Map<?, ?> innerMap = (Map<?, ?>) runtimeBeanInstanceMappingEntry.getValue();
+ Element runtimeInstanceNode = document.createElement("_"
+ + (String) runtimeBeanInstanceMappingEntry.getKey());
+ innerNode.appendChild(runtimeInstanceNode);
+
+ for (Entry<?, ?> innerObjectEntry : innerMap.entrySet()) {
+
+ Util.checkType(innerObjectEntry.getKey(), String.class);
+
+ String innerKey = (String) innerObjectEntry.getKey();
+ Object innerValue = innerObjectEntry.getValue();
+
+ innerStrats.get(innerKey).writeElement(runtimeInstanceNode, namespace, innerValue);
+ }
+ }
+ parentElement.appendChild(innerNode);
+
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.toxml;
+
+import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class SimpleAttributeWritingStrategy implements AttributeWritingStrategy {
+
+ private final Document document;
+ private final String key;
+
+ /**
+ * @param document
+ * @param key
+ */
+ public SimpleAttributeWritingStrategy(Document document, String key) {
+ this.document = document;
+ this.key = key;
+ }
+
+ @Override
+ public void writeElement(Element parentElement, String namespace, Object value) {
+ Util.checkType(value, String.class);
+ Element innerNode = XmlUtil.createTextElement(document, key, (String) value);
+ XmlUtil.addNamespaceAttr(innerNode, namespace);
+ parentElement.appendChild(innerNode);
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.config;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import javax.management.ObjectName;
+import java.util.*;
+import java.util.Map.Entry;
+
+import static com.google.common.base.Preconditions.checkState;
+import static java.lang.String.format;
+
+public class Config {
+
+ private final Map<String, Map<String, ModuleConfig>> moduleConfigs;
+
+ public Config(Map<String, Map<String, ModuleConfig>> moduleConfigs) {
+ this.moduleConfigs = moduleConfigs;
+ }
+
+ private Map<String, Map<String, Collection<ObjectName>>> getMappedInstances(Set<ObjectName> instancesToMap,
+ Services serviceTracker) {
+ Multimap<String, ObjectName> moduleToInstances = mapInstancesToModules(instancesToMap);
+
+ Map<String, Map<String, Collection<ObjectName>>> retVal = Maps.newLinkedHashMap();
+
+ for (String namespace : moduleConfigs.keySet()) {
+
+ Map<String, Collection<ObjectName>> innerRetVal = Maps.newHashMap();
+
+ for (Entry<String, ModuleConfig> mbeEntry : moduleConfigs.get(namespace).entrySet()) {
+
+ String moduleName = mbeEntry.getKey();
+ Collection<ObjectName> instances = moduleToInstances.get(moduleName);
+
+ if (instances == null)
+ continue;
+
+ innerRetVal.put(moduleName, instances);
+
+ // All found instances add to service tracker in advance
+ // This way all instances will be serialized as all available
+ // services when get-config is triggered
+ // (even if they are not used as services by other onstances)
+ // = more user friendly
+ addServices(serviceTracker, instances, mbeEntry.getValue().getProvidedServices());
+
+ }
+
+ retVal.put(namespace, innerRetVal);
+ }
+ return retVal;
+ }
+
+ private void addServices(Services serviceTracker, Collection<ObjectName> instances,
+ Collection<String> providedServices) {
+ for (ObjectName instanceOn : instances) {
+ for (String serviceName : providedServices) {
+ serviceTracker.addServiceEntry(serviceName, instanceOn);
+ }
+ }
+ }
+
+ private static Multimap<String, ObjectName> mapInstancesToModules(Set<ObjectName> instancesToMap) {
+ Multimap<String, ObjectName> retVal = HashMultimap.create();
+
+ for (ObjectName objectName : instancesToMap) {
+ String factoryName = ObjectNameUtil.getFactoryName(objectName);
+ retVal.put(factoryName, objectName);
+ }
+ return retVal;
+ }
+
+ // public Element toXml(Set<ObjectName> instancesToMap, String namespace,
+ // Document document) {
+ // return toXml(instancesToMap, Optional.of(namespace), document);
+ // }
+
+ public Element toXml(Set<ObjectName> instancesToMap, Optional<String> maybeNamespace, Document document,
+ Element dataElement) {
+ Services serviceTracker = new Services();
+
+ Map<String, Map<String, Collection<ObjectName>>> moduleToInstances = getMappedInstances(instancesToMap,
+ serviceTracker);
+
+ Element root = dataElement;
+ if (maybeNamespace.isPresent()) {
+ XmlUtil.addNamespaceAttr(root, maybeNamespace.get());
+ }
+
+ Element modulesElement = document.createElement(XmlNetconfConstants.MODULES_KEY);
+ XmlUtil.addNamespaceAttr(modulesElement,
+ XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
+ root.appendChild(modulesElement);
+ for (String moduleNamespace : moduleToInstances.keySet()) {
+ for (Entry<String, Collection<ObjectName>> moduleMappingEntry : moduleToInstances.get(moduleNamespace)
+ .entrySet()) {
+
+ ModuleConfig mapping = moduleConfigs.get(moduleNamespace).get(moduleMappingEntry.getKey());
+
+ if (moduleMappingEntry.getValue().isEmpty()) {
+ addEmptyModulesCommented(document, modulesElement, moduleNamespace, moduleMappingEntry);
+ } else {
+ for (ObjectName objectName : moduleMappingEntry.getValue()) {
+ modulesElement
+ .appendChild(mapping.toXml(objectName, serviceTracker, document, moduleNamespace));
+ }
+ }
+
+ }
+ }
+
+ root.appendChild(serviceTracker.toXml(serviceTracker.getMappedServices(), document));
+
+ return root;
+ }
+
+ private void addEmptyModulesCommented(Document document, Element root, String moduleNamespace,
+ Entry<String, Collection<ObjectName>> moduleMappingEntry) {
+ Element emptyModule = document.createElement(XmlNetconfConstants.MODULE_KEY);
+
+ Element typeElement = XmlUtil.createTextElement(document, XmlNetconfConstants.TYPE_KEY,
+ moduleMappingEntry.getKey());
+ emptyModule.appendChild(typeElement);
+
+ root.appendChild(document.createComment(XmlUtil.toString(emptyModule, false)));
+ }
+
+ // TODO refactor, replace string representing namespace with namespace class
+ // TODO refactor, replace Map->Multimap with e.g. ConfigElementResolved
+ // class
+ public Map<String, Multimap<String, ModuleElementResolved>> fromXml(XmlElement xml) {
+ Map<String, Multimap<String, ModuleElementResolved>> retVal = Maps.newHashMap();
+
+ List<XmlElement> recognisedChildren = Lists.newArrayList();
+
+ Services serviceTracker = fromXmlServices(xml, recognisedChildren);
+ List<XmlElement> moduleElements = fromXmlModules(xml, recognisedChildren);
+
+ xml.checkUnrecognisedElements(recognisedChildren);
+
+ for (XmlElement moduleElement : moduleElements) {
+ resolveModule(retVal, serviceTracker, moduleElement);
+ }
+
+ return retVal;
+ }
+
+ private List<XmlElement> fromXmlModules(XmlElement xml, List<XmlElement> recognisedChildren) {
+ Optional<XmlElement> modulesElement = xml.getOnlyChildElementOptionally(XmlNetconfConstants.MODULES_KEY,
+ XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
+ List<XmlElement> moduleElements;
+ if (modulesElement.isPresent()) {
+ moduleElements = modulesElement.get().getChildElementsWithSameNamespace(XmlNetconfConstants.MODULE_KEY);
+ recognisedChildren.add(modulesElement.get());
+ modulesElement.get().checkUnrecognisedElements(moduleElements);
+ } else {
+ moduleElements = Lists.newArrayList();
+ }
+ return moduleElements;
+ }
+
+ private void resolveModule(Map<String, Multimap<String, ModuleElementResolved>> retVal, Services serviceTracker,
+ XmlElement moduleElement) {
+ XmlElement typeElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.TYPE_KEY);
+ Entry<String, String> prefixToNamespace = typeElement.findNamespaceOfTextContent();
+ String moduleNamespace = prefixToNamespace.getValue();
+ XmlElement nameElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.NAME_KEY);
+ String instanceName = nameElement.getTextContent();
+ String factoryNameWithPrefix = typeElement.getTextContent();
+ String prefixOrEmptyString = prefixToNamespace.getKey();
+ String factoryName = getFactoryName(factoryNameWithPrefix, prefixOrEmptyString);
+
+ ModuleConfig moduleMapping = getModuleMapping(moduleNamespace, instanceName, factoryName);
+
+ Multimap<String, ModuleElementResolved> innerMap = retVal.get(moduleNamespace);
+ if (innerMap == null) {
+ innerMap = HashMultimap.create();
+ retVal.put(moduleNamespace, innerMap);
+ }
+
+ ModuleElementResolved moduleElementResolved = moduleMapping.fromXml(moduleElement, serviceTracker,
+ instanceName, moduleNamespace);
+
+ innerMap.put(factoryName, moduleElementResolved);
+ }
+
+ private Services fromXmlServices(XmlElement xml, List<XmlElement> recognisedChildren) {
+ Optional<XmlElement> servicesElement = xml.getOnlyChildElementOptionally(XmlNetconfConstants.SERVICES_KEY,
+ XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
+
+ Map<String, Map<String, String>> mappedServices;
+ if (servicesElement.isPresent()) {
+ mappedServices = Services.fromXml(servicesElement.get());
+ recognisedChildren.add(servicesElement.get());
+ } else {
+ mappedServices = new HashMap<>();
+ }
+
+ return Services.resolveServices(mappedServices);
+ }
+
+ private String getFactoryName(String factoryNameWithPrefix, String prefixOrEmptyString) {
+ checkState(
+ factoryNameWithPrefix.startsWith(prefixOrEmptyString),
+ format("Internal error: text " + "content '%s' of type node does not start with prefix '%s'",
+ factoryNameWithPrefix, prefixOrEmptyString));
+
+ int factoryNameAfterPrefixIndex;
+ if (prefixOrEmptyString.isEmpty()) {
+ factoryNameAfterPrefixIndex = 0;
+ } else {
+ factoryNameAfterPrefixIndex = prefixOrEmptyString.length() + 1;
+ }
+ return factoryNameWithPrefix.substring(factoryNameAfterPrefixIndex);
+ }
+
+ private ModuleConfig getModuleMapping(String moduleNamespace, String instanceName, String factoryName) {
+ Map<String, ModuleConfig> mappingsFromNamespace = moduleConfigs.get(moduleNamespace);
+
+ Preconditions.checkNotNull(mappingsFromNamespace,
+ "Namespace %s, defined in: module %s of type %s not found, available namespaces: %s", moduleNamespace,
+ instanceName, factoryName, moduleConfigs.keySet());
+
+ ModuleConfig moduleMapping = mappingsFromNamespace.get(factoryName);
+ checkState(moduleMapping != null, "Cannot find mapping for module type " + factoryName);
+ return moduleMapping;
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.config;
+
+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 org.opendaylight.controller.config.util.ConfigRegistryClient;
+import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeReadingStrategy;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.ObjectXmlReader;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.AttributeMappingStrategy;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.ObjectMapper;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving.AttributeResolvingStrategy;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving.ObjectResolver;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.toxml.AttributeWritingStrategy;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.toxml.ObjectXmlWriter;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import javax.management.ObjectName;
+import javax.management.openmbean.OpenType;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+public final class InstanceConfig {
+ private static final Logger logger = LoggerFactory.getLogger(InstanceConfig.class);
+
+ private final Map<String, AttributeIfc> yangToAttrConfig;
+ private final Map<String, AttributeIfc> jmxToAttrConfig;
+ private final ConfigRegistryClient configRegistryClient;
+
+ public InstanceConfig(ConfigRegistryClient configRegistryClient, Map<String, AttributeIfc> yangNamesToAttributes) {
+ this.yangToAttrConfig = yangNamesToAttributes;
+ this.jmxToAttrConfig = reverseMap(yangNamesToAttributes);
+ this.configRegistryClient = configRegistryClient;
+ }
+
+ private Map<String, Object> getMappedConfiguration(ObjectName on, Services depTracker) {
+
+ // TODO make field, mappingStrategies can be instantiated only once
+ Map<String, AttributeMappingStrategy<?, ? extends OpenType<?>>> mappingStrategies = new ObjectMapper(depTracker)
+ .prepareMapping(jmxToAttrConfig);
+
+ Map<String, Object> toXml = Maps.newHashMap();
+
+ for (Entry<String, AttributeIfc> configDefEntry : jmxToAttrConfig.entrySet()) {
+
+ // Skip children runtime beans as they are mapped by InstanceRuntime
+ if (configDefEntry.getValue() instanceof RuntimeBeanEntry)
+ continue;
+
+ Object value = configRegistryClient.getAttributeCurrentValue(on, configDefEntry.getKey());
+ try {
+ AttributeMappingStrategy<?, ? extends OpenType<?>> attributeMappingStrategy = mappingStrategies
+ .get(configDefEntry.getKey());
+ Optional<?> a = attributeMappingStrategy.mapAttribute(value);
+ if (a.isPresent() == false)
+ continue;
+
+ toXml.put(configDefEntry.getValue().getAttributeYangName(), a.get());
+ } catch (Exception e) {
+ throw new IllegalStateException("Unable to map value " + value + " to attribute "
+ + configDefEntry.getKey(), e);
+ }
+ }
+
+ return toXml;
+ }
+
+ public Element toXml(ObjectName on, Services depTracker, String namespace, Document document, Element rootElement) {
+
+ Element cfgElement = rootElement;
+
+ Map<String, AttributeWritingStrategy> strats = new ObjectXmlWriter().prepareWriting(yangToAttrConfig, document);
+
+ Map<String, Object> mappedConfig = getMappedConfiguration(on, depTracker);
+
+ for (Entry<String, ?> mappingEntry : mappedConfig.entrySet()) {
+ try {
+ strats.get(mappingEntry.getKey()).writeElement(cfgElement, namespace, mappingEntry.getValue());
+ } catch (Exception e) {
+ throw new IllegalStateException("Unable to write value " + mappingEntry.getValue() + " for attribute "
+ + mappingEntry.getValue(), e);
+ }
+ }
+
+ return cfgElement;
+ }
+
+ private void resolveConfiguration(InstanceConfigElementResolved mappedConfig, Services depTracker) {
+
+ // TODO make field, resolvingStrategies can be instantiated only once
+ Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> resolvingStrategies = new ObjectResolver(
+ depTracker).prepareResolving(yangToAttrConfig);
+
+ for (Entry<String, AttributeConfigElement> configDefEntry : mappedConfig.getConfiguration().entrySet()) {
+ try {
+
+ AttributeResolvingStrategy<?, ? extends OpenType<?>> attributeResolvingStrategy = resolvingStrategies
+ .get(configDefEntry.getKey());
+
+ configDefEntry.getValue().resolveValue(attributeResolvingStrategy, configDefEntry.getKey());
+ configDefEntry.getValue().setJmxName(
+ yangToAttrConfig.get(configDefEntry.getKey()).getUpperCaseCammelCase());
+ } catch (Exception e) {
+ throw new IllegalStateException("Unable to resolve value " + configDefEntry.getValue()
+ + " to attribute " + configDefEntry.getKey(), e);
+ }
+ }
+ }
+
+ public InstanceConfigElementResolved fromXml(XmlElement moduleElement, Services services, String moduleNamespace) {
+ Map<String, AttributeConfigElement> retVal = Maps.newHashMap();
+
+ Map<String, AttributeReadingStrategy> strats = new ObjectXmlReader().prepareReading(yangToAttrConfig);
+ List<XmlElement> recognisedChildren = Lists.newArrayList();
+
+ XmlElement type = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.TYPE_KEY);
+ XmlElement name = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.NAME_KEY);
+ List<XmlElement> typeAndName = Lists.newArrayList(type, name);
+
+ for (Entry<String, AttributeReadingStrategy> readStratEntry : strats.entrySet()) {
+ List<XmlElement> configNodes = getConfigNodes(moduleElement, moduleNamespace, readStratEntry.getKey(),
+ recognisedChildren, typeAndName);
+ AttributeConfigElement readElement = readStratEntry.getValue().readElement(configNodes);
+ retVal.put(readStratEntry.getKey(), readElement);
+ }
+
+ recognisedChildren.addAll(typeAndName);
+ moduleElement.checkUnrecognisedElements(recognisedChildren);
+
+ // TODO: add check for conflicts between global and local edit strategy
+ String perInstanceEditStrategy = moduleElement.getAttribute(XmlNetconfConstants.OPERATION_ATTR_KEY,
+ XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
+
+ InstanceConfigElementResolved instanceConfigElementResolved = perInstanceEditStrategy.equals("") ? new InstanceConfigElementResolved(
+ retVal) : new InstanceConfigElementResolved(perInstanceEditStrategy, retVal);
+
+ resolveConfiguration(instanceConfigElementResolved, services);
+ return instanceConfigElementResolved;
+ }
+
+ private List<XmlElement> getConfigNodes(XmlElement moduleElement, String moduleNamespace, String name,
+ List<XmlElement> recognisedChildren, List<XmlElement> typeAndName) {
+ List<XmlElement> foundConfigNodes = moduleElement.getChildElementsWithinNamespace(name, moduleNamespace);
+ if (foundConfigNodes.isEmpty()) {
+ logger.debug("No config nodes {}:{} found in {}", moduleNamespace, name, moduleElement);
+ logger.debug("Trying lookup of config nodes without specified namespace");
+ foundConfigNodes = moduleElement.getChildElementsWithinNamespace(name,
+ XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
+ // In case module type or name element is not present in config it
+ // would be matched with config type or name
+ // We need to remove config type and name from available module
+ // config elements
+ foundConfigNodes.removeAll(typeAndName);
+ logger.debug("Found {} config nodes {} without specified namespace in {}", foundConfigNodes.size(), name,
+ moduleElement);
+ } else {
+ List<XmlElement> foundWithoutNamespaceNodes = moduleElement.getChildElementsWithinNamespace(name,
+ XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
+ foundWithoutNamespaceNodes.removeAll(typeAndName);
+ Preconditions.checkState(foundWithoutNamespaceNodes.isEmpty(),
+ "Element %s present multiple times with different namespaces: %s, %s", name, foundConfigNodes,
+ foundWithoutNamespaceNodes);
+ }
+
+ recognisedChildren.addAll(foundConfigNodes);
+ return foundConfigNodes;
+ }
+
+ private static Map<String, AttributeIfc> reverseMap(Map<String, AttributeIfc> yangNameToAttr) {
+ Map<String, AttributeIfc> reversednameToAtr = Maps.newHashMap();
+
+ for (Entry<String, AttributeIfc> entry : yangNameToAttr.entrySet()) {
+ reversednameToAtr.put(entry.getValue().getUpperCaseCammelCase(), entry.getValue());
+ }
+
+ return reversednameToAtr;
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.config;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigStrategy;
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigXmlParser;
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
+
+import java.util.Map;
+
+/**
+ * Parsed xml element containing whole configuration for an instance of some
+ * module. Contains preferred edit strategy type.
+ */
+public class InstanceConfigElementResolved {
+
+ private final EditStrategyType editStrategy;
+ private final Map<String, AttributeConfigElement> configuration;
+
+ public InstanceConfigElementResolved(String strat, Map<String, AttributeConfigElement> configuration) {
+ EditStrategyType valueOf = checkStrategy(strat);
+ this.editStrategy = valueOf;
+ this.configuration = configuration;
+ }
+
+ EditStrategyType checkStrategy(String strat) {
+ EditStrategyType valueOf = EditStrategyType.valueOf(strat);
+ if (EditStrategyType.defaultStrategy().isEnforcing()) {
+ Preconditions
+ .checkArgument(
+ valueOf == EditStrategyType.defaultStrategy(),
+ "With "
+ + EditStrategyType.defaultStrategy()
+ + " as "
+ + EditConfigXmlParser.DEFAULT_OPERATION_KEY
+ + " operations on module elements are not permitted since the default option is restrictive");
+ }
+ return valueOf;
+ }
+
+ public InstanceConfigElementResolved(Map<String, AttributeConfigElement> configuration) {
+ editStrategy = EditStrategyType.defaultStrategy();
+ this.configuration = configuration;
+ }
+
+ public EditConfigStrategy getEditStrategy() {
+ return editStrategy.getFittingStrategy();
+ }
+
+ public Map<String, AttributeConfigElement> getConfiguration() {
+ return configuration;
+ }
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.config;
+
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import javax.management.ObjectName;
+import java.util.Collection;
+import java.util.Collections;
+
+public class ModuleConfig {
+
+ private final String moduleName;
+ private final InstanceConfig instanceConfig;
+ private final Collection<String> providedServices;
+
+ public ModuleConfig(String moduleName, InstanceConfig mbeanMapping, Collection<String> providedServices) {
+ this.moduleName = moduleName;
+ this.instanceConfig = mbeanMapping;
+ this.providedServices = providedServices;
+ }
+
+ public ModuleConfig(String key, InstanceConfig instanceConfig) {
+ this(key, instanceConfig, Collections.<String> emptyList());
+ }
+
+ public InstanceConfig getMbeanMapping() {
+ return instanceConfig;
+ }
+
+ public Collection<String> getProvidedServices() {
+ return providedServices;
+ }
+
+ public Element toXml(ObjectName instanceON, Services depTracker, Document document, String namespace) {
+ Element root = document.createElement(XmlNetconfConstants.MODULE_KEY);
+ // Xml.addNamespaceAttr(document, root, namespace);
+
+ final String prefix = getPrefix(namespace);
+ Element typeElement = XmlUtil.createPrefixedTextElement(document, XmlNetconfConstants.TYPE_KEY, prefix,
+ moduleName);
+ XmlUtil.addPrefixedNamespaceAttr(typeElement, prefix, namespace);
+ // Xml.addNamespaceAttr(document, typeElement,
+ // XMLUtil.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
+ root.appendChild(typeElement);
+
+ Element nameElement = XmlUtil.createTextElement(document, XmlNetconfConstants.NAME_KEY,
+ ObjectNameUtil.getInstanceName(instanceON));
+ // Xml.addNamespaceAttr(document, nameElement,
+ // XMLUtil.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
+ root.appendChild(nameElement);
+
+ root = instanceConfig.toXml(instanceON, depTracker, namespace, document, root);
+
+ return root;
+ }
+
+ private String getPrefix(String namespace) {
+ // if(namespace.contains(":")==false)
+ return "prefix";
+ // return namespace.substring(namespace.lastIndexOf(':') + 1,
+ // namespace.length());
+
+ }
+
+ public ModuleElementResolved fromXml(XmlElement moduleElement, Services depTracker, String instanceName,
+ String moduleNamespace) {
+
+ InstanceConfigElementResolved ice = instanceConfig.fromXml(moduleElement, depTracker, moduleNamespace);
+ return new ModuleElementResolved(instanceName, ice);
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.config;
+
+public class ModuleElementResolved {
+
+ private final String instanceName;
+ private final InstanceConfigElementResolved instanceConfigElementResolved;
+
+ public ModuleElementResolved(String instanceName, InstanceConfigElementResolved instanceConfigElementResolved) {
+ this.instanceName = instanceName;
+ this.instanceConfigElementResolved = instanceConfigElementResolved;
+ }
+
+ public String getInstanceName() {
+ return instanceName;
+ }
+
+ public InstanceConfigElementResolved getInstanceConfigElementResolved() {
+ return instanceConfigElementResolved;
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.config;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import javax.annotation.Nullable;
+import javax.management.ObjectName;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public final class Services {
+
+ private static final String PROVIDER_KEY = "provider";
+ private static final String NAME_KEY = "name";
+ public static final String TYPE_KEY = "type";
+ public static final String SERVICE_KEY = "service";
+
+ private long suffix = 1;
+
+ private final Map<ServiceInstance, String> instanceToRef = Maps.newHashMap();
+ private final Map<String/* ServiceName */, Map<String/* refName */, ServiceInstance>> serviceNameToRefNameToInstance = Maps
+ .newHashMap();
+
+ public String addServiceEntry(String serviceName, ObjectName on) {
+
+ String moduleName = on.getKeyProperty("moduleFactoryName");
+ String instanceName = on.getKeyProperty("instanceName");
+
+ return addServiceEntry(serviceName, moduleName, instanceName);
+ }
+
+ public String addServiceEntry(String serviceName, String moduleName, String instanceName) {
+ ServiceInstance serviceInstance = new ServiceInstance(moduleName, instanceName);
+ serviceInstance.setServiceName(serviceName);
+
+ String refName = instanceToRef.get(serviceInstance);
+
+ Map<String, ServiceInstance> refNameToInstance = serviceNameToRefNameToInstance.get(serviceName);
+ if (refNameToInstance == null) {
+ refNameToInstance = Maps.newHashMap();
+ serviceNameToRefNameToInstance.put(serviceName, refNameToInstance);
+ }
+
+ if (refName != null) {
+ if (serviceNameToRefNameToInstance.get(serviceName).containsKey(moduleName) == false) {
+ refNameToInstance.put(refName, serviceInstance);
+ }
+ return refName;
+ } else {
+ refName = "ref_" + instanceName;
+
+ final Set<String> refNamesAsSet = toSet(instanceToRef.values());
+ if (refNamesAsSet.contains(refName)) {
+ refName = findAvailableRefName(refName, refNamesAsSet);
+ }
+
+ instanceToRef.put(serviceInstance, refName);
+ refNameToInstance.put(refName, serviceInstance);
+
+ return refName;
+ }
+ }
+
+ private Set<String> toSet(Collection<String> values) {
+ Set<String> refNamesAsSet = Sets.newHashSet();
+
+ for (String refName : values) {
+ boolean resultAdd = refNamesAsSet.add(refName);
+ Preconditions.checkState(resultAdd,
+ "Error occurred building services element, reference name {} was present twice", refName);
+ }
+
+ return refNamesAsSet;
+ }
+
+ public ServiceInstance getByServiceAndRefName(String serviceName, String refName) {
+ Map<String, ServiceInstance> refNameToInstance = serviceNameToRefNameToInstance.get(serviceName);
+ Preconditions.checkArgument(refNameToInstance != null, "No serviceInstances mapped to " + serviceName + " , "
+ + serviceNameToRefNameToInstance.keySet());
+
+ ServiceInstance serviceInstance = refNameToInstance.get(refName);
+ Preconditions.checkArgument(serviceInstance != null, "No serviceInstance mapped to " + refName
+ + " under service name " + serviceName + " , " + refNameToInstance.keySet());
+ return serviceInstance;
+ }
+
+ // TODO hide getMappedServices, call it explicitly in toXml
+
+ public Map<String, Map<String, String>> getMappedServices() {
+ Map<String, Map<String, String>> retVal = Maps.newHashMap();
+
+ for (String serviceName : serviceNameToRefNameToInstance.keySet()) {
+
+ Map<String, String> innerRetVal = Maps.transformValues(serviceNameToRefNameToInstance.get(serviceName),
+ new Function<ServiceInstance, String>() {
+ @Nullable
+ @Override
+ public String apply(@Nullable ServiceInstance serviceInstance) {
+ return serviceInstance.toString();
+ }
+ });
+ retVal.put(serviceName, innerRetVal);
+ }
+
+ return retVal;
+ }
+
+ // TODO hide resolveServices, call it explicitly in fromXml
+
+ public static Services resolveServices(Map<String, Map<String, String>> mappedServices) {
+ Services tracker = new Services();
+
+ for (Entry<String, Map<String, String>> serviceEntry : mappedServices.entrySet()) {
+
+ String serviceName = serviceEntry.getKey();
+ for (Entry<String, String> refEntry : serviceEntry.getValue().entrySet()) {
+
+ Map<String, ServiceInstance> refNameToInstance = tracker.serviceNameToRefNameToInstance
+ .get(serviceName);
+ if (refNameToInstance == null) {
+ refNameToInstance = Maps.newHashMap();
+ tracker.serviceNameToRefNameToInstance.put(serviceName, refNameToInstance);
+ }
+
+ String refName = refEntry.getKey();
+ Preconditions.checkState(false == refNameToInstance.containsKey(refName),
+ "Duplicate reference name to service " + refName + " under service " + serviceName);
+ ServiceInstance serviceInstance = ServiceInstance.fromString(refEntry.getValue());
+ refNameToInstance.put(refName, serviceInstance);
+
+ tracker.instanceToRef.put(serviceInstance, refEntry.getKey());
+ }
+ }
+ return tracker;
+ }
+
+ public static Map<String, Map<String, String>> fromXml(XmlElement xml) {
+ Map<String, Map<String, String>> retVal = Maps.newHashMap();
+
+ List<XmlElement> services = xml.getChildElements(SERVICE_KEY);
+ xml.checkUnrecognisedElements(services);
+
+ for (XmlElement service : services) {
+
+ XmlElement typeElement = service.getOnlyChildElement(TYPE_KEY);
+ String serviceName = typeElement.getTextContent();
+
+ Map<String, String> innerMap = Maps.newHashMap();
+ retVal.put(serviceName, innerMap);
+
+ List<XmlElement> instances = service.getChildElements(XmlNetconfConstants.INSTANCE_KEY);
+ service.checkUnrecognisedElements(instances, typeElement);
+
+ for (XmlElement instance : instances) {
+ XmlElement nameElement = instance.getOnlyChildElement(NAME_KEY);
+ String refName = nameElement.getTextContent();
+
+ XmlElement providerElement = instance.getOnlyChildElement(PROVIDER_KEY);
+ String providerName = providerElement.getTextContent();
+
+ instance.checkUnrecognisedElements(nameElement, providerElement);
+
+ innerMap.put(refName, providerName);
+ }
+ }
+
+ return retVal;
+ }
+
+ private String findAvailableRefName(String refName, Set<String> refNamesAsSet) {
+ String intitialRefName = refName;
+
+ while (true) {
+ refName = intitialRefName + "_" + suffix++;
+ if (refNamesAsSet.contains(refName) == false)
+ return refName;
+ }
+ }
+
+ public Element toXml(Map<String, Map<String, String>> mappedServices, Document document) {
+ Element root = document.createElement(XmlNetconfConstants.SERVICES_KEY);
+ XmlUtil.addNamespaceAttr(root, XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
+
+ for (Entry<String, Map<String, String>> serviceEntry : mappedServices.entrySet()) {
+ Element serviceElement = document.createElement(SERVICE_KEY);
+ root.appendChild(serviceElement);
+
+ Element typeElement = XmlUtil.createTextElement(document, TYPE_KEY, serviceEntry.getKey());
+ serviceElement.appendChild(typeElement);
+
+ for (Entry<String, String> instanceEntry : serviceEntry.getValue().entrySet()) {
+ Element instanceElement = document.createElement(XmlNetconfConstants.INSTANCE_KEY);
+ serviceElement.appendChild(instanceElement);
+
+ Element nameElement = XmlUtil.createTextElement(document, NAME_KEY, instanceEntry.getKey());
+ instanceElement.appendChild(nameElement);
+
+ Element providerElement = XmlUtil.createTextElement(document, PROVIDER_KEY, instanceEntry.getValue());
+ instanceElement.appendChild(providerElement);
+ }
+ }
+
+ return root;
+ }
+
+ public static final class ServiceInstance {
+ public ServiceInstance(String moduleName, String instanceName) {
+ this.moduleName = moduleName;
+ this.instanceName = instanceName;
+ }
+
+ public static ServiceInstance fromString(String instanceId) {
+ instanceId = instanceId.trim();
+ Matcher matcher = p.matcher(instanceId);
+ Preconditions.checkArgument(matcher.matches(), "Unexpected format for provider, expected " + p.toString()
+ + " but was " + instanceId);
+ String factoryName = matcher.group(1);
+ String instanceName = matcher.group(2);
+ return new ServiceInstance(factoryName, instanceName);
+ }
+
+ private final String moduleName, instanceName;
+ private String serviceName;
+
+ public String getServiceName() {
+ return serviceName;
+ }
+
+ public void setServiceName(String serviceName) {
+ this.serviceName = serviceName;
+ }
+
+ public String getModuleName() {
+ return moduleName;
+ }
+
+ public String getInstanceName() {
+ return instanceName;
+ }
+
+ private static final String blueprint = "/" + XmlNetconfConstants.CONFIG_KEY + "/"
+ + XmlNetconfConstants.MODULES_KEY + "/" + XmlNetconfConstants.MODULE_KEY + "["
+ + XmlNetconfConstants.NAME_KEY + "='%s']/" + XmlNetconfConstants.INSTANCE_KEY + "["
+ + XmlNetconfConstants.NAME_KEY + "='%s']";
+
+ private static final String blueprintR = "/" + XmlNetconfConstants.CONFIG_KEY + "/"
+ + XmlNetconfConstants.MODULES_KEY + "/" + XmlNetconfConstants.MODULE_KEY + "\\["
+ + XmlNetconfConstants.NAME_KEY + "='%s'\\]/" + XmlNetconfConstants.INSTANCE_KEY + "\\["
+ + XmlNetconfConstants.NAME_KEY + "='%s'\\]";
+
+ private static final Pattern p = Pattern.compile(String.format(blueprintR, "(.+)", "(.+)"));
+
+ @Override
+ public String toString() {
+ return String.format(blueprint, moduleName, instanceName);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((instanceName == null) ? 0 : instanceName.hashCode());
+ result = prime * result + ((moduleName == null) ? 0 : moduleName.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ServiceInstance other = (ServiceInstance) obj;
+ if (instanceName == null) {
+ if (other.instanceName != null)
+ return false;
+ } else if (!instanceName.equals(other.instanceName))
+ return false;
+ if (moduleName == null) {
+ if (other.moduleName != null)
+ return false;
+ } else if (!moduleName.equals(other.moduleName))
+ return false;
+ return true;
+ }
+
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.rpc;
+
+import com.google.common.collect.Maps;
+import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry.Rpc;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeReadingStrategy;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.ObjectXmlReader;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving.AttributeResolvingStrategy;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving.ObjectResolver;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+
+import javax.management.openmbean.OpenType;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+public final class InstanceRuntimeRpc {
+
+ private final Map<String, AttributeIfc> yangToAttrConfig;
+ private final Rpc rpc;
+
+ public InstanceRuntimeRpc(Rpc rpc) {
+ this.yangToAttrConfig = map(rpc.getParameters());
+ this.rpc = rpc;
+ }
+
+ private Map<String, AttributeIfc> map(List<JavaAttribute> parameters) {
+ Map<String, AttributeIfc> mapped = Maps.newHashMap();
+ for (JavaAttribute javaAttribute : parameters) {
+ mapped.put(javaAttribute.getAttributeYangName(), javaAttribute);
+ }
+ return mapped;
+ }
+
+ private void resolveConfiguration(Map<String, AttributeConfigElement> mappedConfig) {
+
+ // TODO make field, resolvingStrategies can be instantiated only once
+ Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> resolvingStrategies = new ObjectResolver(null)
+ .prepareResolving(yangToAttrConfig);
+ // TODO make constructor for object resolver without service tracker
+ for (Entry<String, AttributeConfigElement> configDefEntry : mappedConfig.entrySet()) {
+ try {
+
+ AttributeResolvingStrategy<?, ? extends OpenType<?>> attributeResolvingStrategy = resolvingStrategies
+ .get(configDefEntry.getKey());
+
+ configDefEntry.getValue().resolveValue(attributeResolvingStrategy, configDefEntry.getKey());
+ configDefEntry.getValue().setJmxName(
+ yangToAttrConfig.get(configDefEntry.getKey()).getUpperCaseCammelCase());
+ } catch (Exception e) {
+ throw new IllegalStateException("Unable to resolve value " + configDefEntry.getValue()
+ + " to attribute " + configDefEntry.getKey(), e);
+ }
+ }
+ }
+
+ public Map<String, AttributeConfigElement> fromXml(XmlElement configRootNode) {
+ Map<String, AttributeConfigElement> retVal = Maps.newHashMap();
+
+ Map<String, AttributeReadingStrategy> strats = new ObjectXmlReader().prepareReading(yangToAttrConfig);
+
+ for (Entry<String, AttributeReadingStrategy> readStratEntry : strats.entrySet()) {
+ List<XmlElement> configNodes = configRootNode.getChildElements(readStratEntry.getKey());
+ AttributeConfigElement readElement = readStratEntry.getValue().readElement(configNodes);
+ retVal.put(readStratEntry.getKey(), readElement);
+ }
+
+ resolveConfiguration(retVal);
+ return retVal;
+ }
+
+ public String getName() {
+ return rpc.getName();
+ }
+
+ public String getReturnType() {
+ return rpc.getReturnType();
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.rpc;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
+import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry.Rpc;
+
+import java.util.Map;
+
+public final class ModuleRpcs {
+
+ Map<String, String> yangToJavaNames = Maps.newHashMap();
+ Map<String, Map<String, InstanceRuntimeRpc>> rpcMapping = Maps.newHashMap();
+
+ public void addNameMapping(RuntimeBeanEntry runtimeEntry) {
+ String yangName = runtimeEntry.getYangName();
+ Preconditions.checkState(yangToJavaNames.containsKey(yangName) == false,
+ "RuntimeBean %s found twice in same namespace", yangName);
+ yangToJavaNames.put(yangName, runtimeEntry.getJavaNamePrefix());
+ }
+
+ public void addRpc(RuntimeBeanEntry runtimeEntry, Rpc rpc) {
+ String yangName = runtimeEntry.getYangName();
+ Map<String, InstanceRuntimeRpc> map = rpcMapping.get(yangName);
+ if (map == null) {
+ map = Maps.newHashMap();
+ rpcMapping.put(yangName, map);
+ }
+
+ Preconditions.checkState(map.containsKey(rpc.getYangName()) == false, "Rpc %s for runtime bean %s added twice",
+ rpc.getYangName(), yangName);
+ map.put(rpc.getYangName(), new InstanceRuntimeRpc(rpc));
+ }
+
+ public String getRbeJavaName(String yangName) {
+ String javaName = yangToJavaNames.get(yangName);
+ Preconditions.checkState(javaName != null,
+ "No runtime bean entry found under yang name %s, available yang names %s", yangName,
+ yangToJavaNames.keySet());
+ return javaName;
+ }
+
+ public InstanceRuntimeRpc getRpc(String rbeName, String rpcName) {
+ Map<String, InstanceRuntimeRpc> rpcs = rpcMapping.get(rbeName);
+ Preconditions.checkState(rpcs != null, "No rpcs found for runtime bean %s", rbeName);
+ InstanceRuntimeRpc rpc = rpcs.get(rpcName);
+ Preconditions.checkState(rpc != null, "No rpc found for runtime bean %s with name %s", rbeName, rpcName);
+ return rpc;
+ }
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.rpc;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.runtimerpc.RuntimeRpcElementResolved;
+
+import java.util.Map;
+
+public class Rpcs {
+ private final Map<String, Map<String, ModuleRpcs>> mappedRpcs;
+
+ public Rpcs(Map<String, Map<String, ModuleRpcs>> mappedRpcs) {
+ super();
+ this.mappedRpcs = mappedRpcs;
+ }
+
+ public ModuleRpcs getRpcMapping(RuntimeRpcElementResolved id) {
+ Map<String, ModuleRpcs> modules = mappedRpcs.get(id.getNamespace());
+ Preconditions.checkState(modules != null, "No modules found for namespace %s", id.getNamespace());
+ ModuleRpcs rpcMapping = modules.get(id.getModuleName());
+ Preconditions.checkState(modules != null, "No module %s found for namespace %s", id.getModuleName(),
+ id.getNamespace());
+
+ return rpcMapping;
+ }
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.runtime;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Sets;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfig;
+import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import javax.management.ObjectName;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+public class InstanceRuntime {
+
+ /**
+ *
+ */
+ private static final String KEY_ATTRIBUTE_KEY = "key";
+
+ private final InstanceConfig instanceMapping;
+ private final Map<String, InstanceRuntime> childrenMappings;
+ private final Map<String, String> jmxToYangChildRbeMapping;
+
+ public InstanceRuntime(InstanceConfig instanceMapping, Map<String, InstanceRuntime> childrenMappings,
+ Map<String, String> jmxToYangChildRbeMapping) {
+ this.instanceMapping = instanceMapping;
+ this.childrenMappings = childrenMappings;
+ this.jmxToYangChildRbeMapping = jmxToYangChildRbeMapping;
+ }
+
+ /**
+ * Finds all children runtime beans, same properties and values as current
+ * root + any number of additional properties
+ */
+ private Set<ObjectName> findChildren(ObjectName innerRootBean, Set<ObjectName> childRbeOns) {
+ final Hashtable<String, String> wantedProperties = innerRootBean.getKeyPropertyList();
+
+ return Sets.newHashSet(Collections2.filter(childRbeOns, new Predicate<ObjectName>() {
+
+ @Override
+ public boolean apply(ObjectName on) {
+ Hashtable<String, String> localProperties = on.getKeyPropertyList();
+ for (Entry<String, String> propertyEntry : wantedProperties.entrySet()) {
+ if (!localProperties.containsKey(propertyEntry.getKey()))
+ return false;
+ if (!localProperties.get(propertyEntry.getKey()).equals(propertyEntry.getValue()))
+ return false;
+ if (localProperties.size() <= wantedProperties.size())
+ return false;
+ }
+ return true;
+ }
+ }));
+ }
+
+ /**
+ * Finds next level root runtime beans, beans that have the same properties
+ * as current root + one additional
+ */
+ private Set<ObjectName> getRootBeans(Set<ObjectName> childRbeOns, final String string, final int keyListSize) {
+ return Sets.newHashSet(Collections2.filter(childRbeOns, new Predicate<ObjectName>() {
+
+ @Override
+ public boolean apply(ObjectName on) {
+ if (on.getKeyPropertyList().size() != keyListSize + 1)
+ return false;
+ if (!on.getKeyPropertyList().containsKey(string))
+ return false;
+ return true;
+ }
+ }));
+ }
+
+ public Element toXml(ObjectName rootOn, Set<ObjectName> childRbeOns, Document document) {
+ return toXml(rootOn, childRbeOns, document, null, null);
+ }
+
+ public Element toXml(ObjectName rootOn, Set<ObjectName> childRbeOns, Document document, String instanceIndex,
+ String keyName) {
+ Element xml = document.createElement(keyName == null ? XmlNetconfConstants.DATA_KEY : keyName);
+ // TODO namespace
+ xml = instanceMapping.toXml(rootOn, null, "namespace", document, xml);
+
+ if (instanceIndex != null) {
+ xml.setAttribute(KEY_ATTRIBUTE_KEY, instanceIndex);
+ }
+
+ for (Entry<String, InstanceRuntime> childMappingEntry : childrenMappings.entrySet()) {
+ Set<ObjectName> innerRootBeans = getRootBeans(childRbeOns, childMappingEntry.getKey(), rootOn
+ .getKeyPropertyList().size());
+
+ for (ObjectName objectName : innerRootBeans) {
+ Set<ObjectName> innerChildRbeOns = findChildren(objectName, childRbeOns);
+ String runtimeInstanceIndex = objectName.getKeyProperty(childMappingEntry.getKey());
+
+ String elementName = jmxToYangChildRbeMapping.get(childMappingEntry.getKey());
+ xml.appendChild(childMappingEntry.getValue().toXml(objectName, innerChildRbeOns, document,
+ runtimeInstanceIndex, elementName));
+ }
+ }
+
+ return xml;
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.runtime;
+
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
+import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import javax.management.ObjectName;
+import java.util.Collection;
+import java.util.Set;
+
+public class ModuleRuntime {
+
+ private final String moduleName;
+ private final InstanceRuntime instanceRuntime;
+
+ public ModuleRuntime(String moduleName, InstanceRuntime instanceRuntime) {
+ this.moduleName = moduleName;
+ this.instanceRuntime = instanceRuntime;
+ }
+
+ public InstanceRuntime getMbeanMapping() {
+ return instanceRuntime;
+ }
+
+ private ObjectName findRoot(Collection<ObjectName> runtimeBeanOns) {
+ for (ObjectName objectName : runtimeBeanOns) {
+ if (objectName.getKeyPropertyList().size() == 3)
+ return objectName;
+ }
+ throw new IllegalStateException("Root runtime bean not found among " + runtimeBeanOns);
+ }
+
+ public Element toXml(String namespace, Multimap<String, ObjectName> instances, Document document) {
+ Element root = document.createElement(XmlNetconfConstants.MODULE_KEY);
+ XmlUtil.addNamespaceAttr(root, namespace);
+
+ Element nameElement = XmlUtil.createTextElement(document, XmlNetconfConstants.NAME_KEY, moduleName);
+ root.appendChild(nameElement);
+
+ for (String instanceName : instances.keySet()) {
+ Element instance = document.createElement(XmlNetconfConstants.INSTANCE_KEY);
+
+ Element innerNameElement = XmlUtil.createTextElement(document, XmlNetconfConstants.NAME_KEY, instanceName);
+ instance.appendChild(innerNameElement);
+
+ Collection<ObjectName> runtimeBeanOns = instances.get(instanceName);
+ ObjectName rootName = findRoot(runtimeBeanOns);
+
+ Set<ObjectName> childrenRuntimeBeans = Sets.newHashSet(runtimeBeanOns);
+ childrenRuntimeBeans.remove(rootName);
+
+ instance.appendChild(instanceRuntime.toXml(rootName, childrenRuntimeBeans, document));
+
+ root.appendChild(instance);
+ }
+
+ return root;
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.mapping.runtime;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import javax.management.ObjectName;
+import java.util.Map;
+import java.util.Set;
+
+public class Runtime {
+
+ private final Map<String, Map<String, ModuleRuntime>> moduleRuntimes;
+
+ public Runtime(Map<String, Map<String, ModuleRuntime>> moduleRuntimes) {
+ this.moduleRuntimes = moduleRuntimes;
+ }
+
+ private Map<String, Multimap<String, ObjectName>> mapInstancesToModules(Set<ObjectName> instancesToMap) {
+ Map<String, Multimap<String, ObjectName>> retVal = Maps.newHashMap();
+
+ for (ObjectName objectName : instancesToMap) {
+ String moduleName = ObjectNameUtil.getFactoryName(objectName);
+
+ Multimap<String, ObjectName> multimap = retVal.get(moduleName);
+ if (multimap == null) {
+ multimap = HashMultimap.create();
+ retVal.put(moduleName, multimap);
+ }
+
+ String instanceName = ObjectNameUtil.getInstanceName(objectName);
+
+ multimap.put(instanceName, objectName);
+ }
+
+ return retVal;
+ }
+
+ public Element toXml(Set<ObjectName> instancesToMap, Document document) {
+ Element root = document.createElement(XmlNetconfConstants.DATA_KEY);
+
+ Element modulesElement = document.createElement(XmlNetconfConstants.MODULES_KEY);
+ XmlUtil.addNamespaceAttr(modulesElement,
+ XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
+ root.appendChild(modulesElement);
+
+ Map<String, Multimap<String, ObjectName>> moduleToInstances = mapInstancesToModules(instancesToMap);
+
+ for (String localNamespace : moduleRuntimes.keySet()) {
+ for (String moduleName : moduleRuntimes.get(localNamespace).keySet()) {
+ Multimap<String, ObjectName> instanceToRbe = moduleToInstances.get(moduleName);
+
+ if (instanceToRbe == null)
+ continue;
+
+ ModuleRuntime moduleRuntime = moduleRuntimes.get(localNamespace).get(moduleName);
+ Element innerXml = moduleRuntime.toXml(localNamespace, instanceToRbe, document);
+ modulesElement.appendChild(innerXml);
+ }
+ }
+
+ return root;
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.operations;
+
+import org.opendaylight.controller.config.util.ConfigRegistryClient;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
+import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
+import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public abstract class AbstractConfigNetconfOperation extends AbstractNetconfOperation {
+
+ protected final ConfigRegistryClient configRegistryClient;
+
+ protected AbstractConfigNetconfOperation(ConfigRegistryClient configRegistryClient,
+ String netconfSessionIdForReporting) {
+ super(netconfSessionIdForReporting);
+ this.configRegistryClient = configRegistryClient;
+ }
+
+ @Override
+ protected HandlingPriority canHandle(String operationName, String operationNamespace) {
+ // TODO check namespace
+ return operationName.equals(getOperationName()) ? HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY
+ : HandlingPriority.CANNOT_HANDLE;
+ }
+
+ protected abstract String getOperationName();
+
+ @Override
+ protected Element handle(Document document, XmlElement operationElement, NetconfOperationRouter opRouter)
+ throws NetconfDocumentedException {
+ return handle(document, operationElement);
+ }
+
+ protected abstract Element handle(Document document, XmlElement operationElement) throws NetconfDocumentedException;
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.operations;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.opendaylight.controller.config.api.jmx.CommitStatus;
+import org.opendaylight.controller.config.util.ConfigRegistryClient;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
+import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class Commit extends AbstractConfigNetconfOperation {
+
+ private static final Logger logger = LoggerFactory.getLogger(Commit.class);
+
+ private final TransactionProvider transactionProvider;
+
+ public Commit(TransactionProvider transactionProvider, ConfigRegistryClient configRegistryClient,
+ String netconfSessionIdForReporting) {
+ super(configRegistryClient, netconfSessionIdForReporting);
+ this.transactionProvider = transactionProvider;
+ }
+
+ private static void checkXml(XmlElement xml) {
+ xml.checkName(XmlNetconfConstants.COMMIT);
+ xml.checkNamespace(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
+ }
+
+ @Override
+ protected String getOperationName() {
+ return XmlNetconfConstants.COMMIT;
+ }
+
+ @Override
+ protected Element handle(Document document, XmlElement xml) throws NetconfDocumentedException {
+ checkXml(xml);
+
+ CommitStatus status;
+ try {
+ status = this.transactionProvider.commitTransaction();
+ } catch (final IllegalStateException e) {
+ logger.warn("Commit failed: ", e);
+ final Map<String, String> errorInfo = new HashMap<>();
+ errorInfo.put(ErrorTag.operation_failed.name(),
+ "Operation failed. Use 'get-config' or 'edit-config' before triggering 'commit' operation");
+ throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed,
+ ErrorSeverity.error, errorInfo);
+ } catch (final NetconfDocumentedException e) {
+ throw new NetconfDocumentedException(
+ "Unable to retrieve config snapshot after commit for persister, details: " + e.getMessage(),
+ ErrorType.application, ErrorTag.operation_failed, ErrorSeverity.error, e.getErrorInfo());
+ }
+ logger.info("Datastore {} committed successfully: {}", Datastore.candidate, status);
+
+ return document.createElement(XmlNetconfConstants.OK);
+ }
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.operations;
+
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.getconfig.CandidateDatastoreQueryStrategy;
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.getconfig.DatastoreQueryStrategy;
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.getconfig.RunningDatastoreQueryStrategy;
+import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
+
+public enum Datastore {
+
+ running, candidate;
+
+ /**
+ * @param source
+ * @param transactionProvider
+ * @return
+ */
+ public static DatastoreQueryStrategy getInstanceQueryStrategy(Datastore source,
+ TransactionProvider transactionProvider) {
+ switch (source) {
+ case running:
+ return new RunningDatastoreQueryStrategy();
+ case candidate:
+ return new CandidateDatastoreQueryStrategy(transactionProvider);
+ default:
+ throw new UnsupportedOperationException("Unimplemented datastore query strategy for " + source);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.operations;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.opendaylight.controller.config.util.ConfigRegistryClient;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
+import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class DiscardChanges extends AbstractConfigNetconfOperation {
+
+ public static final String DISCARD = "discard-changes";
+
+ private static final Logger logger = LoggerFactory.getLogger(DiscardChanges.class);
+
+ private final TransactionProvider transactionProvider;
+
+ public DiscardChanges(final TransactionProvider transactionProvider, ConfigRegistryClient configRegistryClient,
+ String netconfSessionIdForReporting) {
+ super(configRegistryClient, netconfSessionIdForReporting);
+ this.transactionProvider = transactionProvider;
+ }
+
+ private static void fromXml(XmlElement xml) {
+ xml.checkName(DISCARD);
+ xml.checkNamespace(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
+ }
+
+ @Override
+ protected String getOperationName() {
+ return DISCARD;
+ }
+
+ @Override
+ protected Element handle(Document document, XmlElement xml) throws NetconfDocumentedException {
+ try {
+ fromXml(xml);
+ } catch (final IllegalArgumentException e) {
+ logger.warn("Rpc error: {}", ErrorTag.bad_attribute, e);
+ final Map<String, String> errorInfo = new HashMap<>();
+ errorInfo.put(ErrorTag.bad_attribute.name(), e.getMessage());
+ throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.rpc, ErrorTag.bad_attribute,
+ ErrorSeverity.error, errorInfo);
+ }
+
+ try {
+ this.transactionProvider.abortTransaction();
+ } catch (final IllegalStateException e) {
+ logger.warn("Abort failed: ", e);
+ final Map<String, String> errorInfo = new HashMap<>();
+ errorInfo
+ .put(ErrorTag.operation_failed.name(),
+ "Operation failed. Use 'get-config' or 'edit-config' before triggering 'discard-changes' operation");
+ throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed,
+ ErrorSeverity.error, errorInfo);
+ }
+ logger.info("Changes discarded successfully from datastore {}", Datastore.candidate);
+
+ return document.createElement(XmlNetconfConstants.OK);
+ }
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.operations;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.config.api.ValidationException;
+import org.opendaylight.controller.config.util.ConfigRegistryClient;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
+import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Validate extends AbstractConfigNetconfOperation {
+
+ public static final String VALIDATE = "validate";
+
+ private static final Logger logger = LoggerFactory.getLogger(Validate.class);
+
+ private final TransactionProvider transactionProvider;
+
+ public Validate(final TransactionProvider transactionProvider, ConfigRegistryClient configRegistryClient,
+ String netconfSessionIdForReporting) {
+ super(configRegistryClient, netconfSessionIdForReporting);
+ this.transactionProvider = transactionProvider;
+ }
+
+ private void checkXml(XmlElement xml) {
+ xml.checkName(VALIDATE);
+ xml.checkNamespace(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
+
+ XmlElement sourceElement = xml.getOnlyChildElement(XmlNetconfConstants.SOURCE_KEY,
+ XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
+ XmlElement sourceChildNode = sourceElement.getOnlyChildElement();
+
+ sourceChildNode.checkNamespace(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
+ String datastoreValue = sourceChildNode.getName();
+ Datastore sourceDatastore = Datastore.valueOf(datastoreValue);
+
+ Preconditions.checkState(sourceDatastore == Datastore.candidate, "Only " + Datastore.candidate
+ + " is supported as source for " + VALIDATE + " but was " + datastoreValue);
+ }
+
+ @Override
+ protected String getOperationName() {
+ return VALIDATE;
+ }
+
+ @Override
+ protected Element handle(Document document, XmlElement xml) throws NetconfDocumentedException {
+ try {
+ checkXml(xml);
+ } catch (IllegalStateException e) {
+ logger.warn("Rpc error: {}", ErrorTag.missing_attribute, e);
+ final Map<String, String> errorInfo = new HashMap<>();
+ errorInfo.put(ErrorTag.missing_attribute.name(), "Missing value of datastore attribute");
+ throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.rpc, ErrorTag.missing_attribute,
+ ErrorSeverity.error, errorInfo);
+ } catch (final IllegalArgumentException e) {
+ logger.warn("Rpc error: {}", ErrorTag.bad_attribute, e);
+ final Map<String, String> errorInfo = new HashMap<>();
+ errorInfo.put(ErrorTag.bad_attribute.name(), e.getMessage());
+ throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.rpc, ErrorTag.bad_attribute,
+ ErrorSeverity.error, errorInfo);
+ }
+
+ try {
+ transactionProvider.validateTransaction();
+ } catch (ValidationException e) {
+ logger.warn("Validation failed", e);
+ final Map<String, String> errorInfo = new HashMap<>();
+ errorInfo.put(ErrorTag.operation_failed.name(), "Validation failed");
+ throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed,
+ ErrorSeverity.error, errorInfo);
+ } catch (IllegalStateException e) {
+ logger.warn("Validation failed", e);
+ final Map<String, String> errorInfo = new HashMap<>();
+ errorInfo
+ .put(ErrorTag.operation_failed.name(),
+ "Datastore is not present. Use 'get-config' or 'edit-config' before triggering 'operations' operation");
+ throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed,
+ ErrorSeverity.error, errorInfo);
+
+ }
+
+ logger.info("Datastore {} validated successfully", Datastore.candidate);
+
+ return document.createElement(XmlNetconfConstants.OK);
+ }
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.operations.editconfig;
+
+import java.util.Map;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+
+import org.opendaylight.controller.config.util.ConfigTransactionClient;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractEditConfigStrategy implements EditConfigStrategy {
+
+ private static final Logger logger = LoggerFactory.getLogger(AbstractEditConfigStrategy.class);
+
+ @Override
+ public void executeConfiguration(String module, String instance, Map<String, AttributeConfigElement> configuration,
+ ConfigTransactionClient ta) {
+
+ try {
+ ObjectName on = ta.lookupConfigBean(module, instance);
+ logger.debug("ServiceInstance for {} {} located successfully under {}", module, instance, on);
+ executeStrategy(configuration, ta, on);
+ } catch (InstanceNotFoundException e) {
+ handleMissingInstance(configuration, ta, module, instance);
+ }
+
+ }
+
+ abstract void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
+ String module, String instance);
+
+ abstract void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
+ ObjectName objectName);
+
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.operations.editconfig;
+
+import java.util.Map;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+
+import org.opendaylight.controller.config.util.ConfigTransactionClient;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DeleteEditConfigStrategy extends AbstractEditConfigStrategy {
+
+ private static final Logger logger = LoggerFactory.getLogger(DeleteEditConfigStrategy.class);
+
+ @Override
+ void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
+ String module, String instance) {
+ throw new IllegalStateException("Unable to delete " + module + ":" + instance + " , ServiceInstance not found");
+ }
+
+ @Override
+ void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on) {
+ try {
+ ta.destroyModule(on);
+ logger.debug("ServiceInstance {} deleted successfully", on);
+ } catch (InstanceNotFoundException e) {
+ throw new IllegalStateException("Unable to delete " + on, e);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.netconf.confignetconfconnector.operations.editconfig;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import org.opendaylight.controller.config.api.JmxAttributeValidationException;
+import org.opendaylight.controller.config.api.ValidationException;
+import org.opendaylight.controller.config.util.ConfigRegistryClient;
+import org.opendaylight.controller.config.util.ConfigTransactionClient;
+import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
+import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.*;
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
+import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import javax.management.ObjectName;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+public class EditConfig extends AbstractConfigNetconfOperation {
+
+ private static final Logger logger = LoggerFactory.getLogger(EditConfig.class);
+
+ private final YangStoreSnapshot yangStoreSnapshot;
+
+ private final TransactionProvider transactionProvider;
+ private EditConfigXmlParser editConfigXmlParser;
+
+ public EditConfig(YangStoreSnapshot yangStoreSnapshot, TransactionProvider transactionProvider,
+ ConfigRegistryClient configRegistryClient, String netconfSessionIdForReporting) {
+ super(configRegistryClient, netconfSessionIdForReporting);
+ this.yangStoreSnapshot = yangStoreSnapshot;
+ this.transactionProvider = transactionProvider;
+ this.editConfigXmlParser = new EditConfigXmlParser();
+ }
+
+ @VisibleForTesting
+ Element getResponseInternal(final Document document,
+ final EditConfigXmlParser.EditConfigExecution editConfigExecution) throws NetconfDocumentedException {
+ if (editConfigExecution.shouldTest()) {
+ executeTests(configRegistryClient, editConfigExecution);
+ }
+
+ if (editConfigExecution.shouldSet()) {
+ executeSet(configRegistryClient, editConfigExecution);
+ }
+
+ logger.info("Operation {} successful", EditConfigXmlParser.EDIT_CONFIG);
+
+ return document.createElement(XmlNetconfConstants.OK);
+ }
+
+ private void executeSet(ConfigRegistryClient configRegistryClient,
+ EditConfigXmlParser.EditConfigExecution editConfigExecution) throws NetconfDocumentedException {
+ try {
+ set(configRegistryClient, editConfigExecution);
+ } catch (IllegalStateException | JmxAttributeValidationException | ValidationException e) {
+ logger.warn("Set phase for {} failed", EditConfigXmlParser.EDIT_CONFIG, e);
+ final Map<String, String> errorInfo = new HashMap<>();
+ errorInfo.put(ErrorTag.operation_failed.name(), e.getMessage());
+ throw new NetconfDocumentedException("Test phase: " + e.getMessage(), e, ErrorType.application,
+ ErrorTag.operation_failed, ErrorSeverity.error, errorInfo);
+ }
+ logger.debug("Set phase for {} operation successful", EditConfigXmlParser.EDIT_CONFIG);
+ }
+
+ private void executeTests(ConfigRegistryClient configRegistryClient,
+ EditConfigXmlParser.EditConfigExecution editConfigExecution) throws NetconfDocumentedException {
+ try {
+ test(configRegistryClient, editConfigExecution.resolvedXmlElements);
+ } catch (IllegalStateException | JmxAttributeValidationException | ValidationException e) {
+ logger.warn("Test phase for {} failed", EditConfigXmlParser.EDIT_CONFIG, e);
+ final Map<String, String> errorInfo = new HashMap<>();
+ errorInfo.put(ErrorTag.operation_failed.name(), e.getMessage());
+ throw new NetconfDocumentedException("Test phase: " + e.getMessage(), e, ErrorType.application,
+ ErrorTag.operation_failed, ErrorSeverity.error, errorInfo);
+ }
+ logger.debug("Test phase for {} operation successful", EditConfigXmlParser.EDIT_CONFIG);
+ }
+
+ private void test(ConfigRegistryClient configRegistryClient,
+ Map<String, Multimap<String, ModuleElementResolved>> resolvedModules) {
+ ObjectName taON = transactionProvider.getTestTransaction();
+ try {
+
+ // default strategy = replace wipes config
+ if (EditStrategyType.defaultStrategy() == EditStrategyType.replace) {
+ transactionProvider.wipeTestTransaction(taON);
+ }
+ setOnTransaction(configRegistryClient, resolvedModules, taON);
+ transactionProvider.validateTestTransaction(taON);
+ } finally {
+ transactionProvider.abortTestTransaction(taON);
+ }
+ }
+
+ private void set(ConfigRegistryClient configRegistryClient,
+ EditConfigXmlParser.EditConfigExecution editConfigExecution) {
+ ObjectName taON = transactionProvider.getOrCreateTransaction();
+
+ // default strategy = replace wipes config
+ if (EditStrategyType.defaultStrategy() == EditStrategyType.replace) {
+ transactionProvider.wipeTransaction();
+ }
+ setOnTransaction(configRegistryClient, editConfigExecution.resolvedXmlElements, taON);
+ }
+
+ private void setOnTransaction(ConfigRegistryClient configRegistryClient,
+ Map<String, Multimap<String, ModuleElementResolved>> resolvedXmlElements, ObjectName taON) {
+ ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(taON);
+
+ for (Multimap<String, ModuleElementResolved> modulesToResolved : resolvedXmlElements.values()) {
+ for (Entry<String, ModuleElementResolved> moduleToResolved : modulesToResolved.entries()) {
+ String moduleName = moduleToResolved.getKey();
+
+ ModuleElementResolved moduleElementResolved = moduleToResolved.getValue();
+ String instanceName = moduleElementResolved.getInstanceName();
+
+ InstanceConfigElementResolved ice = moduleElementResolved.getInstanceConfigElementResolved();
+ EditConfigStrategy strategy = ice.getEditStrategy();
+ strategy.executeConfiguration(moduleName, instanceName, ice.getConfiguration(), ta);
+ }
+ }
+ }
+
+ public static Config getConfigMapping(ConfigRegistryClient configRegistryClient,
+ Map<String, Map<String, ModuleMXBeanEntry>> mBeanEntries) {
+ Map<String, Map<String, ModuleConfig>> factories = transform(configRegistryClient, mBeanEntries);
+ return new Config(factories);
+ }
+
+ // TODO refactor
+ private static Map<String, Map<String, ModuleConfig>> transform(final ConfigRegistryClient configRegistryClient,
+ Map<String, Map<String, ModuleMXBeanEntry>> mBeanEntries) {
+ return Maps.transformEntries(mBeanEntries,
+ new Maps.EntryTransformer<String, Map<String, ModuleMXBeanEntry>, Map<String, ModuleConfig>>() {
+
+ @Override
+ public Map<String, ModuleConfig> transformEntry(String arg0, Map<String, ModuleMXBeanEntry> arg1) {
+ return Maps.transformEntries(arg1,
+ new Maps.EntryTransformer<String, ModuleMXBeanEntry, ModuleConfig>() {
+
+ @Override
+ public ModuleConfig transformEntry(String key, ModuleMXBeanEntry value) {
+ return new ModuleConfig(key, new InstanceConfig(configRegistryClient, value
+ .getAttributes()));
+ }
+ });
+ }
+ });
+ }
+
+ @Override
+ protected String getOperationName() {
+ return EditConfigXmlParser.EDIT_CONFIG;
+ }
+
+ @Override
+ protected Element handle(Document document, XmlElement xml) throws NetconfDocumentedException {
+
+ EditConfigXmlParser.EditConfigExecution editConfigExecution;
+ Config cfg = getConfigMapping(configRegistryClient, yangStoreSnapshot.getModuleMXBeanEntryMap());
+ try {
+ editConfigExecution = editConfigXmlParser.fromXml(xml, cfg);
+ } catch (IllegalStateException e) {
+ logger.warn("Error parsing xml", e);
+ final Map<String, String> errorInfo = new HashMap<>();
+ errorInfo.put(ErrorTag.missing_attribute.name(), "Missing value for 'target' attribute");
+ throw new Ne