public interface ConfigSnapshotHolder {
- /**
- * Get part of get-config document that contains just
- */
- String getConfigSnapshot();
+ /**
+ * Get part of get-config document that contains just
+ */
+ String getConfigSnapshot();
- /**
- * Get only required capabilities referenced by the snapshot.
- */
- SortedSet<String> getCapabilities();
- }
+ /**
+ * Get only required capabilities referenced by the snapshot.
+ */
+ SortedSet<String> getCapabilities();
+
+}
--- /dev/null
+package org.opendaylight.controller.config.persist.api;
+
+import java.util.SortedSet;
+
+public class ConfigSnapshotHolderImpl implements ConfigSnapshotHolder {
+
+ private final String snapshot;
+ private final SortedSet<String> caps;
+ private final String fileName;
+
+ public ConfigSnapshotHolderImpl(String configSnapshot, SortedSet<String> capabilities, String fileName) {
+ this.snapshot = configSnapshot;
+ this.caps = capabilities;
+ this.fileName = fileName;
+ }
+
+ @Override
+ public String getConfigSnapshot() {
+ return snapshot;
+ }
+
+ @Override
+ public SortedSet<String> getCapabilities() {
+ return caps;
+ }
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ @Override
+ public String toString() {
+ return "ConfigSnapshotHolderImpl{" +
+ "snapshot='" + snapshot + '\'' +
+ ", caps=" + caps +
+ ", fileName='" + fileName + '\'' +
+ '}';
+ }
+}
package org.opendaylight.controller.config.persist.api;
-import com.google.common.base.Optional;
-
import java.io.IOException;
+import java.util.List;
/**
* Base interface for persister implementation.
void persistConfig(ConfigSnapshotHolder configSnapshotHolder) throws IOException;
- Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException;
+ List<ConfigSnapshotHolder> loadLastConfigs() throws IOException;
@Override
void close();
package org.opendaylight.controller.config.persist.storage.directory;
import com.google.common.base.Charsets;
-import com.google.common.base.Optional;
import com.google.common.io.Files;
import org.apache.commons.io.IOUtils;
import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolderImpl;
import org.opendaylight.controller.config.persist.api.Persister;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
}
@Override
- public Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException {
+ public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
File[] filesArray = storage.listFiles();
- if (filesArray.length == 0) {
- return Optional.absent();
+ if (filesArray == null || filesArray.length == 0) {
+ return Collections.emptyList();
}
List<File> sortedFiles = new ArrayList<>(Arrays.asList(filesArray));
Collections.sort(sortedFiles);
// combine all found files
+ logger.debug("Reading files in following order: {}", sortedFiles);
- SortedSet<String> combinedCapabilities = new TreeSet<>();
- StringBuilder modulesBuilder = new StringBuilder(), servicesBuilder = new StringBuilder();
+ List<ConfigSnapshotHolder> result = new ArrayList<>();
for (File file : sortedFiles) {
logger.trace("Adding file '{}' to combined result", file);
final MyLineProcessor lineProcessor = new MyLineProcessor(file.getAbsolutePath());
Files.readLines(file, ENCODING, lineProcessor);
-
- modulesBuilder.append(lineProcessor.getModules());
- servicesBuilder.append(lineProcessor.getServices());
- combinedCapabilities.addAll(lineProcessor.getCapabilities());
+ result.add(lineProcessor.getConfigSnapshotHolder(header, middle, footer));
}
- String combinedSnapshot = header + modulesBuilder.toString() + middle + servicesBuilder.toString() + footer;
- ConfigSnapshotHolder result = new ConfigSnapshotHolderImpl(combinedSnapshot, combinedCapabilities);
- return Optional.of(result);
+ return result;
}
return caps;
}
-}
-
-class ConfigSnapshotHolderImpl implements ConfigSnapshotHolder {
-
- private final String snapshot;
- private final SortedSet<String> caps;
-
- public ConfigSnapshotHolderImpl(String configSnapshot, SortedSet<String> capabilities) {
- this.snapshot = configSnapshot;
- this.caps = capabilities;
- }
-
- @Override
- public String getConfigSnapshot() {
- return snapshot;
+ ConfigSnapshotHolder getConfigSnapshotHolder(String header, String middle, String footer) {
+ String combinedSnapshot = header + getModules() + middle + getServices() + footer;
+ ConfigSnapshotHolder result = new ConfigSnapshotHolderImpl(combinedSnapshot, getCapabilities(), fileNameForReporting);
+ return result;
}
- @Override
- public SortedSet<String> getCapabilities() {
- return caps;
- }
}
+
package org.opendaylight.controller.config.persist.storage.directory;
-import com.google.common.base.Optional;
import org.apache.commons.io.IOUtils;
-import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
import java.io.File;
-import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
public class DirectoryStorageAdapterTest {
DirectoryPersister tested;
- SortedSet<String> expectedCapabilities;
- String expectedSnapshot;
-
- @Before
- public void setUp() throws Exception {
- expectedCapabilities = new TreeSet<>(IOUtils.readLines(getClass().getResourceAsStream("/expectedCapabilities.txt")));
- expectedSnapshot = IOUtils.toString(getClass().getResourceAsStream("/expectedSnapshot.xml"));
- }
@Test
public void testEmptyDirectory() throws Exception {
File folder = new File("target/emptyFolder");
folder.mkdir();
tested = new DirectoryPersister((folder));
- assertEquals(Optional.<ConfigSnapshotHolder>absent(), tested.loadLastConfig());
+ assertEquals(Collections.<ConfigSnapshotHolder>emptyList(), tested.loadLastConfigs());
try {
tested.persistConfig(new ConfigSnapshotHolder() {
public void testOneFile() throws Exception {
File folder = getFolder("oneFile");
tested = new DirectoryPersister((folder));
- assertExpected();
+ List<ConfigSnapshotHolder> results = tested.loadLastConfigs();
+ assertEquals(1, results.size());
+ ConfigSnapshotHolder result = results.get(0);
+ assertSnapshot(result, "oneFileExpected");
}
- private void assertExpected() throws IOException {
- Optional<ConfigSnapshotHolder> maybeResult = tested.loadLastConfig();
- assertTrue(maybeResult.isPresent());
- ConfigSnapshotHolder result = maybeResult.get();
- assertEquals(expectedCapabilities, result.getCapabilities());
- assertEquals(expectedSnapshot, result.getConfigSnapshot());
- }
@Test
public void testTwoFiles() throws Exception {
File folder = getFolder("twoFiles");
tested = new DirectoryPersister((folder));
- assertExpected();
+ List<ConfigSnapshotHolder> results = tested.loadLastConfigs();
+ assertEquals(2, results.size());
+ assertSnapshot(results.get(0), "twoFilesExpected1");
+ assertSnapshot(results.get(1), "twoFilesExpected2");
+ }
+
+ private void assertSnapshot(ConfigSnapshotHolder result, String directory) throws Exception {
+ SortedSet<String> expectedCapabilities = new TreeSet<>(IOUtils.readLines(getClass().getResourceAsStream("/" + directory + "/expectedCapabilities.txt")));
+ String expectedSnapshot = IOUtils.toString(getClass().getResourceAsStream("/" + directory + "/expectedSnapshot.xml"));
+ assertEquals(expectedCapabilities, result.getCapabilities());
+ assertEquals(expectedSnapshot, result.getConfigSnapshot());
}
}
--- /dev/null
+urn:opendaylight:l2:types?module=opendaylight-l2-types&revision=2013-08-27
--- /dev/null
+<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:schema-service-singleton</type>
+ <name>yang-schema-service</name>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:hash-map-data-store</type>
+ <name>hash-map-data-store</name>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-broker-impl</type>
+ <name>dom-broker</name>
+ <data-store xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
+ <name>ref_hash-map-data-store</name>
+ </data-store>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-broker-impl</type>
+ <name>binding-broker-impl</name>
+ <notification-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
+ <name>ref_binding-notification-broker</name>
+ </notification-service>
+ <data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
+ <name>ref_binding-data-broker</name>
+ </data-broker>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:runtime-generated-mapping</type>
+ <name>runtime-mapping-singleton</name>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-notification-broker</type>
+ <name>binding-notification-broker</name>
+ </module>
+ </modules>
+ <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <instance>
+ <name>ref_yang-schema-service</name>
+ <provider>/config/modules/module[name='schema-service-singleton']/instance[name='yang-schema-service']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
+ <instance>
+ <name>ref_binding-notification-broker</name>
+ <provider>/config/modules/module[name='binding-notification-broker']/instance[name='binding-notification-broker']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
+ <instance>
+ <name>ref_hash-map-data-store</name>
+ <provider>/config/modules/module[name='hash-map-data-store']/instance[name='hash-map-data-store']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
+ <instance>
+ <name>ref_binding-broker-impl</name>
+ <provider>/config/modules/module[name='binding-broker-impl']/instance[name='binding-broker-impl']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding-impl:binding-dom-mapping-service</type>
+ <instance>
+ <name>ref_runtime-mapping-singleton</name>
+ <provider>/config/modules/module[name='runtime-generated-mapping']/instance[name='runtime-mapping-singleton']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+ <instance>
+ <name>ref_dom-broker</name>
+ <provider>/config/modules/module[name='dom-broker-impl']/instance[name='dom-broker']</provider>
+ </instance>
+ </service>
+ </services>
+</data>
--- /dev/null
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28
+urn:opendaylight:params:xml:ns:yang:controller:threadpool?module=threadpool&revision=2013-04-09
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&revision=2013-10-28
+urn:opendaylight:params:xml:ns:yang:controller:config?module=config&revision=2013-04-05
+urn:ietf:params:netconf:capability:candidate:1.0
+urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04
+urn:opendaylight:params:xml:ns:yang:controller:netty:eventexecutor?module=netty-event-executor&revision=2013-11-12
+urn:ietf:params:xml:ns:yang:rpc-context?module=rpc-context&revision=2013-06-17
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&revision=2013-10-28
+urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&revision=2010-09-24
+urn:ietf:params:netconf:capability:rollback-on-error:1.0
+urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&revision=2010-09-24
+urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl?module=threadpool-impl&revision=2013-04-05
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&revision=2013-10-28
+urn:opendaylight:params:xml:ns:yang:controller:logback:config?module=config-logging&revision=2013-07-16
+urn:opendaylight:yang:extension:yang-ext?module=yang-ext&revision=2013-07-09
+urn:opendaylight:params:xml:ns:yang:iana?module=iana&revision=2013-08-16
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:common?module=opendaylight-md-sal-common&revision=2013-10-28
+urn:opendaylight:params:xml:ns:yang:ieee754?module=ieee754&revision=2013-08-19
--- /dev/null
+<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-data-broker</type>
+ <name>binding-data-broker</name>
+ <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+ <name>ref_dom-broker</name>
+ </dom-broker>
+ <mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
+ <name>ref_runtime-mapping-singleton</name>
+ </mapping-service>
+ </module>
+ </modules>
+ <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
+ <instance>
+ <name>ref_binding-data-broker</name>
+ <provider>/config/modules/module[name='binding-data-broker']/instance[name='binding-data-broker']</provider>
+ </instance>
+ </service>
+ </services>
+</data>
import com.google.common.io.Files;
import org.apache.commons.lang3.StringUtils;
import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolderImpl;
import org.opendaylight.controller.config.persist.api.Persister;
import org.opendaylight.controller.config.persist.api.PropertiesProvider;
import org.opendaylight.controller.config.persist.api.StorageAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import 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.Arrays;
+import java.util.Collections;
+import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
} else {
numberOfStoredBackups = Integer.MAX_VALUE;
}
-
+ logger.trace("Property {} set to {}", NUMBER_OF_BACKUPS, numberOfStoredBackups);
return result;
}
}
@Override
- public Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException {
+ public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
Preconditions.checkNotNull(storage, "Storage file is null");
if (!storage.exists()) {
- return Optional.absent();
+ return Collections.emptyList();
}
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()));
- }
+ Files.readLines(storage, ENCODING, lineProcessor);
- } catch (ParserConfigurationException | SAXException e) {
- throw new IOException("Unable to load last config ", e);
+ if (lineProcessor.getConfigSnapshot().isPresent() == false) {
+ return Collections.emptyList();
+ } else {
+ return Arrays.<ConfigSnapshotHolder>asList(new ConfigSnapshotHolderImpl(lineProcessor.getConfigSnapshot().get(),
+ lineProcessor.getCapabilities(), storage.getAbsolutePath()));
}
+
}
private static final class LineProcessor implements com.google.common.io.LineProcessor<String> {
return true;
}
- Optional<String> getConfigSnapshot() throws IOException, SAXException, ParserConfigurationException {
+ Optional<String> getConfigSnapshot() {
final String xmlContent = snapshotBuffer.toString();
- if (xmlContent == null || xmlContent.equals("")) {
+ if (xmlContent.equals("")) {
return Optional.absent();
- } else
+ } else {
return Optional.of(xmlContent);
+ }
}
- SortedSet<String> getCapabilities() throws IOException, SAXException, ParserConfigurationException {
+ SortedSet<String> getCapabilities() {
return caps;
}
return "FileStorageAdapter [storage=" + storage + "]";
}
- private class PersistedConfigImpl implements ConfigSnapshotHolder {
-
- private final String snapshot;
- private final SortedSet<String> caps;
-
- public PersistedConfigImpl(Optional<String> configSnapshot, SortedSet<String> capabilities) {
- this.snapshot = configSnapshot.get();
- this.caps = capabilities;
- }
-
- @Override
- public String getConfigSnapshot() {
- return snapshot;
- }
-
- @Override
- public SortedSet<String> getCapabilities() {
- return caps;
- }
- }
-
}
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 org.junit.Before;
import java.io.File;
import java.nio.file.Files;
import java.util.Collection;
+import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
});
assertEquals(14, readLines.size());
- Optional<ConfigSnapshotHolder> lastConf = storage.loadLastConfig();
- assertTrue(lastConf.isPresent());
+ List<ConfigSnapshotHolder> lastConf = storage.loadLastConfigs();
+ assertEquals(1, lastConf.size());
+ ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0);
assertEquals("<config>2</config>",
- lastConf.get().getConfigSnapshot().replaceAll("\\s", ""));
- assertEquals(createCaps(), lastConf.get().getCapabilities());
+ configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", ""));
+ assertEquals(createCaps(), configSnapshotHolder.getCapabilities());
}
private SortedSet<String> createCaps() {
});
assertEquals(7, readLines.size());
- Optional<ConfigSnapshotHolder> lastConf = storage.loadLastConfig();
- assertTrue(lastConf.isPresent());
+ List<ConfigSnapshotHolder> lastConf = storage.loadLastConfigs();
+ assertEquals(1, lastConf.size());
+ ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0);
assertEquals("<config>2</config>",
- lastConf.get().getConfigSnapshot().replaceAll("\\s", ""));
+ configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", ""));
}
@Test
assertEquals(14, readLines.size());
- Optional<ConfigSnapshotHolder> lastConf = storage.loadLastConfig();
- assertTrue(lastConf.isPresent());
+ List<ConfigSnapshotHolder> lastConf = storage.loadLastConfigs();
+ assertEquals(1, lastConf.size());
+ ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0);
assertEquals("<config>3</config>",
- lastConf.get().getConfigSnapshot().replaceAll("\\s", ""));
+ configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", ""));
assertFalse(readLines.contains(holder.getConfigSnapshot()));
}
FileStorageAdapter storage = new FileStorageAdapter();
storage.setFileStorage(file);
- Optional<ConfigSnapshotHolder> elementOptional = storage.loadLastConfig();
- assertThat(elementOptional.isPresent(), is(false));
+ List<ConfigSnapshotHolder> elementOptional = storage.loadLastConfigs();
+ assertThat(elementOptional.size(), is(0));
}
@Test(expected = NullPointerException.class)
public void testNoProperties() throws Exception {
FileStorageAdapter storage = new FileStorageAdapter();
- storage.loadLastConfig();
+ storage.loadLastConfigs();
}
@Test(expected = NullPointerException.class)
type string;
mandatory true;
}
+ key name;
config:java-name-prefix FileAppenderTO;
}
type string;
mandatory true;
}
+ key name;
leaf file-name-pattern {
type string;
leaf clean-history-on-start {
type boolean;
- default 0;
+ default false;
}
config:java-name-prefix RollingFileAppenderTO;
}
type string;
mandatory true;
}
+ key name;
+
config:java-name-prefix ConsoleAppenderTO;
}
type string;
mandatory true;
}
+ key logger-name;
leaf level {
type string;
*/
package org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.regex.Pattern;
-
+import com.google.common.annotations.VisibleForTesting;
+import freemarker.template.Configuration;
+import freemarker.template.Template;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.directives.AnnotationsDirective;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.directives.ConstructorsDirective;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.annotations.VisibleForTesting;
-
-import freemarker.template.Configuration;
-import freemarker.template.Template;
-import freemarker.template.TemplateException;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.regex.Pattern;
public class FtlFilePersister {
private static final Logger logger = LoggerFactory
ftlFile.getFtlTempleteLocation());
try {
template.process(ftlFile, writer);
- } catch (TemplateException e) {
+ } catch (Throwable e) {
throw new IllegalStateException(
"Template error while generating " + ftlFile, e);
}
import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry.Rpc;
import org.opendaylight.controller.config.yangjmxgenerator.ServiceInterfaceEntry;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute.Dependency;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.AbstractDependencyAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.Dependency;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.TypedAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.TypedAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.VoidAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Annotation;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Annotation.Parameter;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.ModuleField;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.FullyQualifiedNameHelper;
import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
+import org.opendaylight.yangtools.sal.binding.model.api.ParameterizedType;
import org.opendaylight.yangtools.sal.binding.model.api.Type;
import javax.management.openmbean.SimpleType;
// convert attributes to getters
for (AttributeIfc attributeIfc : entry.getAttributes()) {
- String returnType = null;
- returnType = getReturnType(entry, attributeIfc);
+ String returnType;
+ returnType = getReturnType(attributeIfc);
String getterName = "get"
+ attributeIfc.getUpperCaseCammelCase();
MethodDeclaration getter = new MethodDeclaration(returnType,
for (JavaAttribute ja : rpc.getParameters()) {
Field field = new Field(Collections.<String> emptyList(),
ja.getType().getFullyQualifiedName(),
- ja.getLowerCaseCammelCase());
+ ja.getLowerCaseCammelCase(), ja.getNullableDefaultWrappedForCode());
fields.add(field);
}
MethodDeclaration operation = new MethodDeclaration(
- getReturnType(entry, rpc.getReturnType()), rpc.getName(), fields);
+ getReturnType(rpc.getReturnType()), rpc.getName(), fields);
methods.add(operation);
}
return result;
}
- private static String getReturnType(RuntimeBeanEntry entry, AttributeIfc attributeIfc) {
+ // FIXME: put into Type.toString
+ static String serializeType(Type type) {
+ if (type instanceof ParameterizedType){
+ ParameterizedType parameterizedType = (ParameterizedType) type;
+ StringBuffer sb = new StringBuffer();
+ sb.append(parameterizedType.getRawType().getFullyQualifiedName());
+ sb.append("<");
+ boolean first = true;
+ for(Type parameter: parameterizedType.getActualTypeArguments()) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(",");
+ }
+ sb.append(serializeType(parameter));
+ }
+ sb.append(">");
+ return sb.toString();
+ } else {
+ return type.getFullyQualifiedName();
+ }
+ }
+
+
+ private static String getReturnType(AttributeIfc attributeIfc) {
String returnType;
if (attributeIfc instanceof TypedAttribute) {
- returnType = ((TypedAttribute) attributeIfc).getType()
- .getFullyQualifiedName();
- } else if (attributeIfc instanceof TOAttribute) {
- String fullyQualifiedName = FullyQualifiedNameHelper
- .getFullyQualifiedName(entry.getPackageName(),
- attributeIfc.getUpperCaseCammelCase());
-
- returnType = fullyQualifiedName;
- } else if (attributeIfc instanceof ListAttribute) {
- AttributeIfc innerAttr = ((ListAttribute) attributeIfc)
- .getInnerAttribute();
-
- String innerTpe = innerAttr instanceof TypedAttribute ? ((TypedAttribute) innerAttr)
- .getType().getFullyQualifiedName()
- : FullyQualifiedNameHelper.getFullyQualifiedName(
- entry.getPackageName(),
- attributeIfc.getUpperCaseCammelCase());
-
- returnType = "java.util.List<" + innerTpe + ">";
+ Type type = ((TypedAttribute) attributeIfc).getType();
+ returnType = serializeType(type);
} else if (attributeIfc == VoidAttribute.getInstance()) {
return "void";
} else {
public static GeneralInterfaceTemplate mXBeanInterfaceTemplateFromMbe(
ModuleMXBeanEntry mbe) {
MXBeanInterfaceAttributesProcessor attrProcessor = new MXBeanInterfaceAttributesProcessor();
- attrProcessor.processAttributes(mbe.getAttributes(),
- mbe.getPackageName());
+ attrProcessor.processAttributes(mbe.getAttributes());
GeneralInterfaceTemplate ifcTemplate = new GeneralInterfaceTemplate(
getHeaderFromEntry(mbe), mbe.getPackageName(),
mbe.getMXBeanInterfaceName(), Lists.<String> newArrayList(),
ModuleMXBeanEntry mbe) {
Map<String, GeneralClassTemplate> retVal = Maps.newHashMap();
TOAttributesProcessor processor = new TOAttributesProcessor();
- processor.processAttributes(mbe.getAttributes(), mbe.getPackageName());
+ processor.processAttributes(mbe.getAttributes());
for (org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.TemplateFactory.TOAttributesProcessor.TOInternal to : processor
.getTOs()) {
List<Constructor> constructors = Lists.newArrayList();
yangPropertiesToTypesMap.put(returnType.getAttributeYangName(), returnType);
}
- processor.processAttributes(yangPropertiesToTypesMap, rbe.getPackageName());
+ processor.processAttributes(yangPropertiesToTypesMap);
for (org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.TemplateFactory.TOAttributesProcessor.TOInternal to : processor
.getTOs()) {
List<Constructor> constructors = Lists.newArrayList();
private final List<TOInternal> tos = Lists.newArrayList();
- void processAttributes(Map<String, AttributeIfc> attributes,
- String packageName) {
+ void processAttributes(Map<String, AttributeIfc> attributes) {
for (Entry<String, AttributeIfc> attrEntry : attributes.entrySet()) {
AttributeIfc attributeIfc = attrEntry.getValue();
if (attributeIfc instanceof TOAttribute) {
- createTOInternal(packageName, attributeIfc);
+ createTOInternal((TOAttribute) attributeIfc);
}
if (attributeIfc instanceof ListAttribute) {
AttributeIfc innerAttr = ((ListAttribute) attributeIfc)
.getInnerAttribute();
if (innerAttr instanceof TOAttribute) {
- createTOInternal(packageName, innerAttr);
+ createTOInternal((TOAttribute) innerAttr);
}
}
}
}
- private void createTOInternal(String packageName,
- AttributeIfc attributeIfc) {
- String fullyQualifiedName = FullyQualifiedNameHelper
- .getFullyQualifiedName(packageName, attributeIfc.getUpperCaseCammelCase());
+ private void createTOInternal(TOAttribute toAttribute) {
- String type = fullyQualifiedName;
- String name = attributeIfc.getUpperCaseCammelCase();
- Map<String, AttributeIfc> attrs = ((TOAttribute) attributeIfc)
- .getCapitalizedPropertiesToTypesMap();
- // recursive processing
- processAttributes(attrs, packageName);
+ Map<String, AttributeIfc> attrs = toAttribute.getCapitalizedPropertiesToTypesMap();
+ // recursive processing of TO's attributes
+ processAttributes(attrs);
- tos.add(new TOInternal(type, name, attrs, packageName));
+ tos.add(new TOInternal(toAttribute.getType(), attrs));
}
List<TOInternal> getTOs() {
}
private static class TOInternal {
- private final String type, name;
+ private final String fullyQualifiedName, name;
private List<Field> fields;
private List<MethodDefinition> methods;
- public TOInternal(String type, String name,
+ public TOInternal(Type type, Map<String, AttributeIfc> attrs) {
+ this(type.getFullyQualifiedName(), type.getName(), attrs, type.getPackageName());
+ }
+
+ public TOInternal(String fullyQualifiedName, String name,
Map<String, AttributeIfc> attrs, String packageName) {
- super();
- this.type = type;
+ this.fullyQualifiedName = fullyQualifiedName;
this.name = name;
processAttrs(attrs, packageName);
}
- private void processAttrs(Map<String, AttributeIfc> attrs,
- String packageName) {
+ private void processAttrs(Map<String, AttributeIfc> attrs, String packageName) {
fields = Lists.newArrayList();
methods = Lists.newArrayList();
String varName = BindingGeneratorUtil
.parseToValidParamName(attrEntry.getKey());
- String fullyQualifiedName = null;
+ String fullyQualifiedName, nullableDefault = null;
if (attrEntry.getValue() instanceof TypedAttribute) {
- Type innerType = ((TypedAttribute) attrEntry.getValue())
- .getType();
- fullyQualifiedName = innerType.getFullyQualifiedName();
- } else if (attrEntry.getValue() instanceof ListAttribute) {
- AttributeIfc innerAttr = ((ListAttribute) attrEntry
- .getValue()).getInnerAttribute();
-
- String innerTpe = innerAttr instanceof TypedAttribute ? ((TypedAttribute) innerAttr)
- .getType().getFullyQualifiedName()
- : FullyQualifiedNameHelper
- .getFullyQualifiedName(packageName, attrEntry.getValue().getUpperCaseCammelCase());
-
- fullyQualifiedName = "java.util.List<" + innerTpe + ">";
- } else
+ Type type = ((TypedAttribute) attrEntry.getValue()).getType();
+ fullyQualifiedName = serializeType(type);
+ if(attrEntry.getValue() instanceof JavaAttribute) {
+ nullableDefault = ((JavaAttribute)attrEntry.getValue()).getNullableDefaultWrappedForCode();
+ }
+ } else {
fullyQualifiedName = FullyQualifiedNameHelper
.getFullyQualifiedName(packageName, attrEntry.getValue().getUpperCaseCammelCase());
-
- fields.add(new Field(fullyQualifiedName, varName));
+ }
+ fields.add(new Field(fullyQualifiedName, varName, nullableDefault));
String getterName = "get" + innerName;
MethodDefinition getter = new MethodDefinition(
}
String getType() {
- return type;
+ return fullyQualifiedName;
}
String getName() {
}
private static class MXBeanInterfaceAttributesProcessor {
- private static final String STRING_FULLY_QUALIFIED_NAME = "java.util.List";
private final List<MethodDeclaration> methods = Lists.newArrayList();
- void processAttributes(Map<String, AttributeIfc> attributes,
- String packageName) {
+ void processAttributes(Map<String, AttributeIfc> attributes) {
for (Entry<String, AttributeIfc> attrEntry : attributes.entrySet()) {
String returnType;
AttributeIfc attributeIfc = attrEntry.getValue();
if (attributeIfc instanceof TypedAttribute) {
- returnType = ((TypedAttribute) attributeIfc).getType()
- .getFullyQualifiedName();
- } else if (attributeIfc instanceof TOAttribute) {
- String fullyQualifiedName = FullyQualifiedNameHelper
- .getFullyQualifiedName(packageName, attributeIfc.getUpperCaseCammelCase());
-
- returnType = fullyQualifiedName;
- } else if (attributeIfc instanceof ListAttribute) {
- String fullyQualifiedName = null;
-
- AttributeIfc innerAttr = ((ListAttribute) attributeIfc)
- .getInnerAttribute();
- if (innerAttr instanceof JavaAttribute) {
- fullyQualifiedName = ((JavaAttribute) innerAttr)
- .getType().getFullyQualifiedName();
- } else if (innerAttr instanceof TOAttribute) {
- fullyQualifiedName = FullyQualifiedNameHelper
- .getFullyQualifiedName(packageName, innerAttr.getUpperCaseCammelCase());
- }
-
- returnType = STRING_FULLY_QUALIFIED_NAME.concat("<")
- .concat(fullyQualifiedName).concat(">");
+ TypedAttribute typedAttribute = (TypedAttribute) attributeIfc;
+ returnType = serializeType(typedAttribute.getType());
} else {
throw new UnsupportedOperationException(
"Attribute not supported: "
String packageName) {
for (Entry<String, AttributeIfc> attrEntry : attributes.entrySet()) {
String type;
+ String nullableDefaultWrapped = null;
AttributeIfc attributeIfc = attrEntry.getValue();
if (attributeIfc instanceof TypedAttribute) {
- type = ((TypedAttribute) attributeIfc).getType()
- .getFullyQualifiedName();
+ TypedAttribute typedAttribute = (TypedAttribute) attributeIfc;
+ type = serializeType(typedAttribute.getType());
} else if (attributeIfc instanceof TOAttribute) {
String fullyQualifiedName = FullyQualifiedNameHelper
.getFullyQualifiedName(packageName, attributeIfc.getUpperCaseCammelCase());
type = fullyQualifiedName;
- } else if (attributeIfc instanceof ListAttribute) {
+ } else if (attributeIfc instanceof ListAttribute) { //FIXME: listAttribute might extend TypedAttribute
String fullyQualifiedName = null;
AttributeIfc innerAttr = ((ListAttribute) attributeIfc)
.getInnerAttribute();
if (innerAttr instanceof JavaAttribute) {
fullyQualifiedName = ((JavaAttribute) innerAttr)
.getType().getFullyQualifiedName();
+ nullableDefaultWrapped = ((JavaAttribute) innerAttr).getNullableDefaultWrappedForCode();
} else if (innerAttr instanceof TOAttribute) {
fullyQualifiedName = FullyQualifiedNameHelper
.getFullyQualifiedName(packageName, innerAttr.getUpperCaseCammelCase());
}
fields.add(new Field(type, attributeIfc
- .getUpperCaseCammelCase()));
+ .getUpperCaseCammelCase(), nullableDefaultWrapped));
}
}
void processAttributes(Map<String, AttributeIfc> attributes,
String packageName) {
for (Entry<String, AttributeIfc> attrEntry : attributes.entrySet()) {
- String type;
+ String type, nullableDefaultWrapped = null;
AttributeIfc attributeIfc = attrEntry.getValue();
if (attributeIfc instanceof TypedAttribute) {
- type = ((TypedAttribute) attributeIfc).getType()
- .getFullyQualifiedName();
+ TypedAttribute typedAttribute = (TypedAttribute) attributeIfc;
+ type = serializeType(typedAttribute.getType());
+ if (attributeIfc instanceof JavaAttribute) {
+ nullableDefaultWrapped = ((JavaAttribute) attributeIfc).getNullableDefaultWrappedForCode();
+ }
+
} else if (attributeIfc instanceof TOAttribute) {
String fullyQualifiedName = FullyQualifiedNameHelper
.getFullyQualifiedName(packageName, attributeIfc.getUpperCaseCammelCase());
if (innerAttr instanceof JavaAttribute) {
fullyQualifiedName = ((JavaAttribute) innerAttr)
.getType().getFullyQualifiedName();
+ nullableDefaultWrapped = ((JavaAttribute) innerAttr).getNullableDefaultWrappedForCode();
} else if (innerAttr instanceof TOAttribute) {
fullyQualifiedName = FullyQualifiedNameHelper
.getFullyQualifiedName(packageName, innerAttr.getUpperCaseCammelCase());
List<Annotation> annotations = Lists
.newArrayList(overrideAnnotation);
- if (attributeIfc instanceof DependencyAttribute) {
+ if (attributeIfc instanceof AbstractDependencyAttribute) {
isDependency = true;
- dependency = ((DependencyAttribute) attributeIfc)
+ dependency = ((AbstractDependencyAttribute) attributeIfc)
.getDependency();
annotations.add(Annotation
.createRequireIfcAnnotation(dependency.getSie()));
String varName = BindingGeneratorUtil
.parseToValidParamName(attrEntry.getKey());
moduleFields.add(new ModuleField(type, varName, attributeIfc
- .getUpperCaseCammelCase(), attributeIfc
- .getNullableDefault(), isDependency, dependency));
+ .getUpperCaseCammelCase(), nullableDefaultWrapped, isDependency, dependency));
String getterName = "get"
+ attributeIfc.getUpperCaseCammelCase();
*/
package org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model;
-import java.util.List;
-
import com.google.common.collect.Lists;
+import java.util.List;
+
public class Field {
private final String type;
private final String name;
this(Lists.<String> newArrayList(), type, name, null);
}
+ public Field(String type, String name, String definition) {
+ this(Lists.<String> newArrayList(), type, name, definition);
+ }
+
public Field(List<String> modifiers, String type, String name) {
this(modifiers, type, name, null);
}
*/
package org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model;
+
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.Dependency;
+
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute.Dependency;
-
public class ModuleField extends Field {
private final String nullableDefault, attributeName;
String attributeName, String nullableDefault, boolean isDependency,
Dependency dependency) {
super(modifiers, type, name);
- this.nullableDefault = nullableDefault;
this.dependent = isDependency;
this.dependency = dependency;
this.attributeName = attributeName;
+ if (type.startsWith(List.class.getName()) && nullableDefault == null) {
+ String generics = type.substring(List.class.getName().length());
+ nullableDefault = "new " + ArrayList.class.getName() + generics + "()";
+ }
+ this.nullableDefault = nullableDefault;
}
public ModuleField(String type, String name, String attributeName,
public String getAttributeName() {
return attributeName;
}
+
}
public void validate(){
<#list moduleFields as field>
<#if field.dependent==true && field.dependency.mandatory==true>
+ <#if field.type?starts_with("java.util.List")>
+ for(javax.management.ObjectName dep : ${field.name}) {
+ dependencyResolver.validateDependency(${field.dependency.sie.fullyQualifiedName}.class, dep, ${field.name}JmxAttribute);
+ }
+ <#else>
dependencyResolver.validateDependency(${field.dependency.sie.fullyQualifiedName}.class, ${field.name}, ${field.name}JmxAttribute);
</#if>
+ </#if>
</#list>
customValidation();
}
// caches of resolved dependencies
<#list moduleFields as field>
<#if field.dependent==true>
+ <#if field.type?starts_with("java.util.List")>
+ private java.util.List<${field.dependency.sie.exportedOsgiClassName}> ${field.name}Dependency = new java.util.ArrayList<${field.dependency.sie.exportedOsgiClassName}>();
+ protected final java.util.List<${field.dependency.sie.exportedOsgiClassName}> get${field.attributeName}Dependency(){
+ return ${field.name}Dependency;
+ }
+ <#else>
private ${field.dependency.sie.exportedOsgiClassName} ${field.name}Dependency;
protected final ${field.dependency.sie.exportedOsgiClassName} get${field.attributeName}Dependency(){
return ${field.name}Dependency;
}
+ </#if>
</#if>
</#list>
<#list moduleFields as field>
<#if field.dependent==true>
-
<#if field.dependency.mandatory==false>
if(${field.name}!=null) {
</#if>
- ${field.name}Dependency = dependencyResolver.resolveInstance(${field.dependency.sie.exportedOsgiClassName}.class, ${field.name}, ${field.name}JmxAttribute);
+ <#if field.type?starts_with("java.util.List")>
+ ${field.name}Dependency = new java.util.ArrayList<${field.dependency.sie.exportedOsgiClassName}>();
+ for(javax.management.ObjectName dep : ${field.name}) {
+ ${field.name}Dependency.add(dependencyResolver.resolveInstance(${field.dependency.sie.exportedOsgiClassName}.class, dep, ${field.name}JmxAttribute));
+ }
+ <#else>
+ ${field.name}Dependency = dependencyResolver.resolveInstance(${field.dependency.sie.exportedOsgiClassName}.class, ${field.name}, ${field.name}JmxAttribute);
+ </#if>
<#if field.dependency.mandatory==false>
}
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+//TODO: refactor
public class JMXGeneratorTest extends AbstractGeneratorTest {
JMXGenerator jmxGenerator;
File generatedResourcesDir;
private static final List<String> expectedModuleFileNames = ServiceInterfaceEntryTest
- .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, " +
- "AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, " +
- "AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, " +
- "AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, " +
- "AsyncEventBusModule.java, AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, " +
- "AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, " +
- "AsyncEventBusRuntimeRegistrator.java, DynamicThreadPoolModule.java, " +
- "DynamicThreadPoolModuleFactory.java, DynamicThreadPoolModuleMXBean.java, " +
- "DynamicThreadPoolRuntimeMXBean.java, DynamicThreadPoolRuntimeRegistration.java, " +
- "DynamicThreadPoolRuntimeRegistrator.java, EventBusModule.java, EventBusModuleFactory.java, " +
- "EventBusModuleMXBean.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, " +
- "InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, " +
- "NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, Peer.java, StreamRuntimeMXBean.java, StreamRuntimeRegistration.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
+ .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, AbstractThreadPoolRegistryImplModule.java, AbstractThreadPoolRegistryImplModuleFactory.java, AsyncEventBusModule.java, AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, AsyncEventBusRuntimeRegistrator.java, DynamicThreadPoolModule.java, DynamicThreadPoolModuleFactory.java, DynamicThreadPoolModuleMXBean.java, DynamicThreadPoolRuntimeMXBean.java, DynamicThreadPoolRuntimeRegistration.java, DynamicThreadPoolRuntimeRegistrator.java, EventBusModule.java, EventBusModuleFactory.java, EventBusModuleMXBean.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, Peer.java, StreamRuntimeMXBean.java, StreamRuntimeRegistration.java, ThreadPoolRegistryImplModule.java, ThreadPoolRegistryImplModuleFactory.java, ThreadPoolRegistryImplModuleMXBean.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
private static final List<String> expectedBGPNames = ServiceInterfaceEntryTest
.toFileNames("[AbstractBgpListenerImplModule.java, " + "AbstractBgpListenerImplModuleFactory.java, " +
"NetconfTestFiles1ImplModuleMXBean.java, NetconfTestFiles1ImplRuntimeMXBean.java, " +
"NetconfTestFiles1ImplRuntimeRegistration.java, NetconfTestFiles1ImplRuntimeRegistrator.java, TestFileImplModule.java, TestFileImplModuleFactory.java, TestFileImplModuleMXBean.java, TestFileImplRuntimeMXBean.java, TestFileImplRuntimeRegistration.java, TestFileImplRuntimeRegistrator.java, TestFiles1ImplModule.java, TestFiles1ImplModuleFactory.java, TestFiles1ImplModuleMXBean.java, TestFiles1ImplRuntimeMXBean.java, TestFiles1ImplRuntimeRegistration.java, TestFiles1ImplRuntimeRegistrator.java]");
private static final List<String> expectedAllFileNames = ServiceInterfaceEntryTest
- .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, " +
- "AbstractBgpListenerImplModule.java, AbstractBgpListenerImplModuleFactory.java, " +
- "AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, " +
- "AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, " +
- "AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, " +
- "AbstractNetconfTestFileImplModule.java, AbstractNetconfTestFileImplModuleFactory.java, " +
- "AbstractNetconfTestFiles1ImplModule.java, AbstractNetconfTestFiles1ImplModuleFactory.java, " +
- "AbstractNetconfTestImplModule.java, AbstractNetconfTestImplModuleFactory.java, " +
- "AbstractTestFileImplModule.java, AbstractTestFileImplModuleFactory.java, " +
- "AbstractTestFiles1ImplModule.java, AbstractTestFiles1ImplModuleFactory.java, " +
- "AbstractTestImplModule.java, AbstractTestImplModuleFactory.java, AsyncEventBusModule.java, " +
- "AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, " +
- "AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, " +
- "AsyncEventBusRuntimeRegistrator.java, AutoCloseableServiceInterface.java, " +
- "BgpListenerImplModule.java, BgpListenerImplModuleFactory.java, BgpListenerImplModuleMXBean.java," +
- " BgpListenerImplRuntimeMXBean.java, BgpListenerImplRuntimeRegistration.java, " +
- "BgpListenerImplRuntimeRegistrator.java, ComplexDtoBInner.java, ComplexList.java, Deep.java, " +
- "DtoA.java, DtoA.java, DtoA.java, DtoA1.java, DtoAInner.java, DtoAInnerInner.java, DtoB.java, " +
- "DtoC.java, DynamicThreadPoolModule.java, DynamicThreadPoolModuleFactory.java, " +
- "DynamicThreadPoolModuleMXBean.java, DynamicThreadPoolRuntimeMXBean.java, " +
- "DynamicThreadPoolRuntimeRegistration.java, DynamicThreadPoolRuntimeRegistrator.java, " +
- "EventBusModule.java, EventBusModuleFactory.java, EventBusModuleMXBean.java, " +
- "EventBusServiceInterface.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, " +
- "InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, " +
- "NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, " +
- "NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, " +
- "NetconfTestFileImplModule.java, NetconfTestFileImplModuleFactory.java, " +
- "NetconfTestFileImplModuleMXBean.java, NetconfTestFileImplRuntimeMXBean.java, " +
- "NetconfTestFileImplRuntimeRegistration.java, NetconfTestFileImplRuntimeRegistrator.java, " +
- "NetconfTestFiles1ImplModule.java, NetconfTestFiles1ImplModuleFactory.java, " +
- "NetconfTestFiles1ImplModuleMXBean.java, NetconfTestFiles1ImplRuntimeMXBean.java, " +
- "NetconfTestFiles1ImplRuntimeRegistration.java, NetconfTestFiles1ImplRuntimeRegistrator.java, NetconfTestImplModule.java, NetconfTestImplModuleFactory.java, NetconfTestImplModuleMXBean.java, NetconfTestImplRuntimeMXBean.java, NetconfTestImplRuntimeRegistration.java, NetconfTestImplRuntimeRegistrator.java, Peer.java, Peer.java, PeersRuntimeMXBean.java, PeersRuntimeRegistration.java, ScheduledThreadPoolServiceInterface.java, SimpleList.java, StreamRuntimeMXBean.java, StreamRuntimeRegistration.java, TestFileImplModule.java, TestFileImplModuleFactory.java, TestFileImplModuleMXBean.java, TestFileImplRuntimeMXBean.java, TestFileImplRuntimeRegistration.java, TestFileImplRuntimeRegistrator.java, TestFiles1ImplModule.java, TestFiles1ImplModuleFactory.java, TestFiles1ImplModuleMXBean.java, TestFiles1ImplRuntimeMXBean.java, TestFiles1ImplRuntimeRegistration.java, TestFiles1ImplRuntimeRegistrator.java, TestImplModule.java, TestImplModuleFactory.java, TestImplModuleMXBean.java, TestImplRuntimeMXBean.java, TestImplRuntimeRegistration.java, TestImplRuntimeRegistrator.java, ThreadFactoryServiceInterface.java, ThreadPoolServiceInterface.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
+ .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, AbstractBgpListenerImplModule.java, AbstractBgpListenerImplModuleFactory.java, AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, AbstractNetconfTestFileImplModule.java, AbstractNetconfTestFileImplModuleFactory.java, AbstractNetconfTestFiles1ImplModule.java, AbstractNetconfTestFiles1ImplModuleFactory.java, AbstractNetconfTestImplModule.java, AbstractNetconfTestImplModuleFactory.java, AbstractTestFileImplModule.java, AbstractTestFileImplModuleFactory.java, AbstractTestFiles1ImplModule.java, AbstractTestFiles1ImplModuleFactory.java, AbstractTestImplModule.java, AbstractTestImplModuleFactory.java, AbstractThreadPoolRegistryImplModule.java, AbstractThreadPoolRegistryImplModuleFactory.java, AsyncEventBusModule.java, AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, AsyncEventBusRuntimeRegistrator.java, AutoCloseableServiceInterface.java, BgpListenerImplModule.java, BgpListenerImplModuleFactory.java, BgpListenerImplModuleMXBean.java, BgpListenerImplRuntimeMXBean.java, BgpListenerImplRuntimeRegistration.java, BgpListenerImplRuntimeRegistrator.java, ComplexDtoBInner.java, ComplexList.java, Deep.java, DtoA.java, DtoA.java, DtoA.java, DtoA1.java, DtoAInner.java, DtoAInnerInner.java, DtoB.java, DtoC.java, DynamicThreadPoolModule.java, DynamicThreadPoolModuleFactory.java, DynamicThreadPoolModuleMXBean.java, DynamicThreadPoolRuntimeMXBean.java, DynamicThreadPoolRuntimeRegistration.java, DynamicThreadPoolRuntimeRegistrator.java, EventBusModule.java, EventBusModuleFactory.java, EventBusModuleMXBean.java, EventBusServiceInterface.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, NetconfTestFileImplModule.java, NetconfTestFileImplModuleFactory.java, NetconfTestFileImplModuleMXBean.java, NetconfTestFileImplRuntimeMXBean.java, NetconfTestFileImplRuntimeRegistration.java, NetconfTestFileImplRuntimeRegistrator.java, NetconfTestFiles1ImplModule.java, NetconfTestFiles1ImplModuleFactory.java, NetconfTestFiles1ImplModuleMXBean.java, NetconfTestFiles1ImplRuntimeMXBean.java, NetconfTestFiles1ImplRuntimeRegistration.java, NetconfTestFiles1ImplRuntimeRegistrator.java, NetconfTestImplModule.java, NetconfTestImplModuleFactory.java, NetconfTestImplModuleMXBean.java, NetconfTestImplRuntimeMXBean.java, NetconfTestImplRuntimeRegistration.java, NetconfTestImplRuntimeRegistrator.java, Peer.java, Peer.java, PeersRuntimeMXBean.java, PeersRuntimeRegistration.java, ScheduledThreadPoolServiceInterface.java, SimpleList.java, StreamRuntimeMXBean.java, StreamRuntimeRegistration.java, TestFileImplModule.java, TestFileImplModuleFactory.java, TestFileImplModuleMXBean.java, TestFileImplRuntimeMXBean.java, TestFileImplRuntimeRegistration.java, TestFileImplRuntimeRegistrator.java, TestFiles1ImplModule.java, TestFiles1ImplModuleFactory.java, TestFiles1ImplModuleMXBean.java, TestFiles1ImplRuntimeMXBean.java, TestFiles1ImplRuntimeRegistration.java, TestFiles1ImplRuntimeRegistrator.java, TestImplModule.java, TestImplModuleFactory.java, TestImplModuleMXBean.java, TestImplRuntimeMXBean.java, TestImplRuntimeRegistration.java, TestImplRuntimeRegistrator.java, ThreadFactoryServiceInterface.java, ThreadPoolRegistryImplModule.java, ThreadPoolRegistryImplModuleFactory.java, ThreadPoolRegistryImplModuleMXBean.java, ThreadPoolServiceInterface.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
private static final List<String> expectedGenerateMBEsListNames = ServiceInterfaceEntryTest
.toFileNames("[AbstractBgpListenerImplModule.java, AbstractBgpListenerImplModuleFactory.java, BgpListenerImplModule.java, BgpListenerImplModuleFactory.java, BgpListenerImplModuleMXBean.java, BgpListenerImplRuntimeMXBean.java, BgpListenerImplRuntimeRegistration.java, BgpListenerImplRuntimeRegistrator.java, PeersRuntimeMXBean.java, PeersRuntimeRegistration.java]");
PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
+ ".threads.java.DynamicThreadPoolModuleFactory",//
PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
- + ".threads.java.NamingThreadFactoryModuleFactory");
+ + ".threads.java.NamingThreadFactoryModuleFactory", //
+ PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
+ + ".threads.java.ThreadPoolRegistryImplModuleFactory");
+
+
assertThat(lines, equalTo(expectedLines));
}
assertDeclaredField(fieldDeclarations,
"private java.util.concurrent.ThreadFactory threadfactoryDependency");
assertDeclaredField(fieldDeclarations,
- "private java.lang.Long keepAlive=10");
+ "private java.lang.Long keepAlive=new java.lang.Long(\"10\")");
assertDeclaredField(fieldDeclarations,
"private java.lang.Long coreSize");
assertDeclaredField(fieldDeclarations, "private byte[] binary");
*/
package org.opendaylight.controller.config.yangjmxgenerator.plugin;
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-
-import java.util.Collections;
-import java.util.Map;
-
+import com.google.common.collect.Maps;
import org.junit.Test;
import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.TemplateFactory;
import org.opendaylight.yangtools.sal.binding.model.api.Type;
-import com.google.common.collect.Maps;
+import java.util.Collections;
+import java.util.Map;
+
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
public class ModuleMXBeanEntryTemplatesTest {
doReturn("package.type").when(typeA).getFullyQualifiedName();
doReturn(typeA).when(attr).getType();
doReturn("Type").when(attr).getUpperCaseCammelCase();
+ doReturn("new Default()").when(attr).getNullableDefault();
return attr;
}
*/
package org.opendaylight.controller.config.yangjmxgenerator;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Sets;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static java.lang.String.format;
+import static org.opendaylight.controller.config.yangjmxgenerator.ConfigConstants.createConfigQName;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.AbstractDependencyAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.FullyQualifiedNameHelper;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.NameConflictException;
import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
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.LeafListSchemaNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-import static java.lang.String.format;
-import static org.opendaylight.controller.config.yangjmxgenerator.ConfigConstants.createConfigQName;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
/**
* Represents part of yang model that describes a module.
}
/**
- * @return services implemented by this module. Keys are fully qualified java names of generated
- * ServiceInterface classes, values are identity local names.
+ * @return services implemented by this module. Keys are fully qualified
+ * java names of generated ServiceInterface classes, values are
+ * identity local names.
*/
public Map<String, QName> getProvidedServices() {
return providedServices;
moduleLocalNameFromXPath);
yangToAttributes = fillConfiguration(choiceCaseNode,
currentModule, typeProviderWrapper,
- qNamesToSIEs, schemaContext);
+ qNamesToSIEs, schemaContext, packageName);
checkUniqueAttributesWithGeneratedClass(
uniqueGeneratedClassesNames, when.getQName(),
yangToAttributes);
e.getConflictingName(), when.getQName(),
when.getQName());
}
-
checkUniqueRuntimeBeansGeneratedClasses(
uniqueGeneratedClassesNames, when, runtimeBeans);
Set<RuntimeBeanEntry> runtimeBeanEntryValues = Sets
.<RuntimeBeanEntry> emptyList());
}
}
+ // check attributes name uniqueness
+ for (Entry<String, ModuleMXBeanEntry> entry : result.entrySet()) {
+ checkUniqueRuntimeBeanAttributesName(entry.getValue(),
+ uniqueGeneratedClassesNames);
+ }
if (unaugmentedModuleIdentities.size() > 0) {
logger.warn("Augmentation not found for all module identities: {}",
unaugmentedModuleIdentities.keySet());
}
}
+ private static void checkUniqueRuntimeBeanAttributesName(
+ ModuleMXBeanEntry mxBeanEntry,
+ Map<String, QName> uniqueGeneratedClassesNames) {
+ for (RuntimeBeanEntry runtimeBeanEntry : mxBeanEntry.getRuntimeBeans()) {
+ for (String runtimeAttName : runtimeBeanEntry
+ .getYangPropertiesToTypesMap().keySet()) {
+ if (mxBeanEntry.getAttributes().keySet()
+ .contains(runtimeAttName)) {
+ QName qName1 = uniqueGeneratedClassesNames
+ .get(runtimeBeanEntry.getJavaNameOfRuntimeMXBean());
+ QName qName2 = uniqueGeneratedClassesNames.get(mxBeanEntry
+ .getGloballyUniqueName());
+ throw new NameConflictException(runtimeAttName, qName1,
+ qName2);
+ }
+ }
+ }
+ }
+
private static void checkUniqueAttributesWithGeneratedClass(
Map<String, QName> uniqueGeneratedClassNames, QName parentQName,
Map<String, AttributeIfc> yangToAttributes) {
ChoiceCaseNode choiceCaseNode, Module currentModule,
TypeProviderWrapper typeProviderWrapper,
Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
- SchemaContext schemaContext) {
+ SchemaContext schemaContext, String packageName) {
Map<String, AttributeIfc> yangToAttributes = new HashMap<>();
for (DataSchemaNode attrNode : choiceCaseNode.getChildNodes()) {
AttributeIfc attributeValue = getAttributeValue(attrNode,
currentModule, qNamesToSIEs, typeProviderWrapper,
- schemaContext);
+ schemaContext, packageName);
yangToAttributes.put(attributeValue.getAttributeYangName(),
attributeValue);
}
}
}
- private static int getChildNodeSizeWithoutUses(ContainerSchemaNode csn) {
+ private static int getChildNodeSizeWithoutUses(DataNodeContainer csn) {
int result = 0;
for (DataSchemaNode dsn : csn.getChildNodes()) {
- if (dsn.isAddedByUses() == false)
+ if (dsn.isAddedByUses() == false) {
result++;
+ }
}
return result;
}
private static AttributeIfc getAttributeValue(DataSchemaNode attrNode,
Module currentModule,
Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
- TypeProviderWrapper typeProviderWrapper, SchemaContext schemaContext) {
+ TypeProviderWrapper typeProviderWrapper,
+ SchemaContext schemaContext, String packageName) {
if (attrNode instanceof LeafSchemaNode) {
// simple type
} else if (attrNode instanceof ContainerSchemaNode) {
// reference or TO
ContainerSchemaNode containerSchemaNode = (ContainerSchemaNode) attrNode;
- if (containerSchemaNode.getUses().size() == 1
- && getChildNodeSizeWithoutUses(containerSchemaNode) == 0) {
- // reference
- UsesNode usesNode = containerSchemaNode.getUses().iterator()
- .next();
- checkState(usesNode.getRefines().size() == 1,
- "Unexpected 'refine' child node size of "
- + containerSchemaNode);
- LeafSchemaNode refine = (LeafSchemaNode) usesNode.getRefines()
- .values().iterator().next();
- checkState(refine.getUnknownSchemaNodes().size() == 1,
- "Unexpected unknown schema node size of " + refine);
- UnknownSchemaNode requiredIdentity = refine
- .getUnknownSchemaNodes().iterator().next();
- checkState(
- ConfigConstants.REQUIRED_IDENTITY_EXTENSION_QNAME.equals(requiredIdentity
- .getNodeType()),
- "Unexpected language extension " + requiredIdentity);
- String prefixAndIdentityLocalName = requiredIdentity
- .getNodeParameter();
- // import should point to a module
- ServiceInterfaceEntry serviceInterfaceEntry = findSIE(
- prefixAndIdentityLocalName, currentModule,
- qNamesToSIEs, schemaContext);
- boolean mandatory = refine.getConstraints().isMandatory();
- return new DependencyAttribute(attrNode, serviceInterfaceEntry,
- mandatory, attrNode.getDescription());
+ Optional<? extends AbstractDependencyAttribute> dependencyAttributeOptional = extractDependency(
+ containerSchemaNode, attrNode, currentModule, qNamesToSIEs,
+ schemaContext);
+ if (dependencyAttributeOptional.isPresent()) {
+ return dependencyAttributeOptional.get();
} else {
return TOAttribute.create(containerSchemaNode,
- typeProviderWrapper);
+ typeProviderWrapper, packageName);
}
+
} else if (attrNode instanceof LeafListSchemaNode) {
return ListAttribute.create((LeafListSchemaNode) attrNode,
typeProviderWrapper);
} else if (attrNode instanceof ListSchemaNode) {
- return ListAttribute.create((ListSchemaNode) attrNode,
- typeProviderWrapper);
+ ListSchemaNode listSchemaNode = (ListSchemaNode) attrNode;
+ Optional<? extends AbstractDependencyAttribute> dependencyAttributeOptional = extractDependency(
+ listSchemaNode, attrNode, currentModule, qNamesToSIEs,
+ schemaContext);
+ if (dependencyAttributeOptional.isPresent()) {
+ return dependencyAttributeOptional.get();
+ } else {
+ return ListAttribute.create(listSchemaNode,
+ typeProviderWrapper, packageName);
+ }
} else {
throw new UnsupportedOperationException(
"Unknown configuration node " + attrNode.toString());
}
}
+ private static Optional<? extends AbstractDependencyAttribute> extractDependency(
+ DataNodeContainer dataNodeContainer, DataSchemaNode attrNode,
+ Module currentModule,
+ Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
+ SchemaContext schemaContext) {
+ if (dataNodeContainer.getUses().size() == 1
+ && getChildNodeSizeWithoutUses(dataNodeContainer) == 0) {
+ // reference
+ UsesNode usesNode = dataNodeContainer.getUses().iterator().next();
+ checkState(usesNode.getRefines().size() == 1,
+ "Unexpected 'refine' child node size of "
+ + dataNodeContainer);
+ LeafSchemaNode refine = (LeafSchemaNode) usesNode.getRefines()
+ .values().iterator().next();
+ checkState(refine.getUnknownSchemaNodes().size() == 1,
+ "Unexpected unknown schema node size of " + refine);
+ UnknownSchemaNode requiredIdentity = refine.getUnknownSchemaNodes()
+ .iterator().next();
+ checkState(
+ ConfigConstants.REQUIRED_IDENTITY_EXTENSION_QNAME.equals(requiredIdentity
+ .getNodeType()), "Unexpected language extension "
+ + requiredIdentity);
+ String prefixAndIdentityLocalName = requiredIdentity
+ .getNodeParameter();
+ // import should point to a module
+ ServiceInterfaceEntry serviceInterfaceEntry = findSIE(
+ prefixAndIdentityLocalName, currentModule, qNamesToSIEs,
+ schemaContext);
+ boolean mandatory = refine.getConstraints().isMandatory();
+ AbstractDependencyAttribute reference;
+ if (dataNodeContainer instanceof ContainerSchemaNode) {
+ reference = new DependencyAttribute(attrNode,
+ serviceInterfaceEntry, mandatory,
+ attrNode.getDescription());
+ } else {
+ reference = new ListDependenciesAttribute(attrNode,
+ serviceInterfaceEntry, mandatory,
+ attrNode.getDescription());
+ }
+ return Optional.of(reference);
+ }
+ return Optional.absent();
+ }
+
private static ServiceInterfaceEntry findSIE(
String prefixAndIdentityLocalName, Module currentModule,
Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
private final Set<Rpc> rpcs;
@VisibleForTesting
- public RuntimeBeanEntry(String packageName,
+ RuntimeBeanEntry(String packageName,
DataSchemaNode nodeForReporting, String yangName,
String javaNamePrefix, boolean isRoot,
Optional<String> keyYangName, List<AttributeIfc> attributes,
ContainerSchemaNode container = (ContainerSchemaNode) child;
// this can be either TO or hierarchical RB
TOAttribute toAttribute = TOAttribute.create(container,
- typeProviderWrapper);
+ typeProviderWrapper, packageName);
attributes.add(toAttribute);
} else if (child instanceof ListSchemaNode) {
if (isInnerStateBean(child)) {
runtimeBeanEntries.add(hierarchicalChild);
} else /* ordinary list attribute */{
ListAttribute listAttribute = ListAttribute.create(
- (ListSchemaNode) child, typeProviderWrapper);
+ (ListSchemaNode) child, typeProviderWrapper, packageName);
attributes.add(listAttribute);
}
} else if (rpcDefinition.getOutput().getChildNodes().size() == 1) {
DataSchemaNode returnDSN = rpcDefinition.getOutput()
.getChildNodes().iterator().next();
- returnType = getReturnTypeAttribute(returnDSN, typeProviderWrapper);
+ returnType = getReturnTypeAttribute(returnDSN, typeProviderWrapper, packageName);
} else {
throw new IllegalArgumentException(
attributes, rpcs);
}
- private static AttributeIfc getReturnTypeAttribute(DataSchemaNode child, TypeProviderWrapper typeProviderWrapper) {
+ private static AttributeIfc getReturnTypeAttribute(DataSchemaNode child, TypeProviderWrapper typeProviderWrapper,
+ String packageName) {
if (child instanceof LeafSchemaNode) {
LeafSchemaNode leaf = (LeafSchemaNode) child;
return new JavaAttribute(leaf, typeProviderWrapper);
} else if (child instanceof ContainerSchemaNode) {
ContainerSchemaNode container = (ContainerSchemaNode) child;
- TOAttribute toAttribute = TOAttribute.create(container, typeProviderWrapper);
+ TOAttribute toAttribute = TOAttribute.create(container, typeProviderWrapper, packageName);
return toAttribute;
} else if (child instanceof ListSchemaNode) {
- return ListAttribute.create((ListSchemaNode) child, typeProviderWrapper);
+ return ListAttribute.create((ListSchemaNode) child, typeProviderWrapper, packageName);
} else if (child instanceof LeafListSchemaNode) {
return ListAttribute.create((LeafListSchemaNode) child, typeProviderWrapper);
} else {
return getType(leaf, type);
}
+ public String getDefault(LeafSchemaNode node) {
+ return typeProvider.getTypeDefaultConstruction(node);
+ }
+
public Type getType(SchemaNode leaf, TypeDefinition<?> type) {
Type javaType;
try {
--- /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.yangjmxgenerator.attribute;
+
+import org.opendaylight.controller.config.yangjmxgenerator.ServiceInterfaceEntry;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+public abstract class AbstractDependencyAttribute extends AbstractAttribute implements TypedAttribute {
+
+ protected final Dependency dependency;
+ protected final String nullableDescription, nullableDefault;
+
+ public AbstractDependencyAttribute(DataSchemaNode attrNode,
+ ServiceInterfaceEntry sie, boolean mandatory,
+ String nullableDescription) {
+ super(attrNode);
+ dependency = new Dependency(sie, mandatory);
+ this.nullableDescription = nullableDescription;
+ nullableDefault = null;
+ }
+
+ public Dependency getDependency() {
+ return dependency;
+ }
+
+ @Override
+ public String getNullableDescription() {
+ return nullableDescription;
+ }
+
+ @Override
+ public String getNullableDefault() {
+ return nullableDefault;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o == null || getClass() != o.getClass())
+ return false;
+ if (!super.equals(o))
+ return false;
+
+ AbstractDependencyAttribute that = (AbstractDependencyAttribute) o;
+
+ if (dependency != null ? !dependency.equals(that.dependency)
+ : that.dependency != null)
+ return false;
+ if (nullableDefault != null ? !nullableDefault
+ .equals(that.nullableDefault) : that.nullableDefault != null)
+ return false;
+ if (nullableDescription != null ? !nullableDescription
+ .equals(that.nullableDescription)
+ : that.nullableDescription != null)
+ return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = super.hashCode();
+ result = 31 * result + (dependency != null ? dependency.hashCode() : 0);
+ result = 31
+ * result
+ + (nullableDescription != null ? nullableDescription.hashCode()
+ : 0);
+ result = 31 * result
+ + (nullableDefault != null ? nullableDefault.hashCode() : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getName() + "{" + getAttributeYangName() + ","
+ + "dependency=" + dependency + '}';
+ }
+
+
+}
--- /dev/null
+package org.opendaylight.controller.config.yangjmxgenerator.attribute;
+
+import org.opendaylight.controller.config.yangjmxgenerator.ServiceInterfaceEntry;
+
+public class Dependency {
+ private final ServiceInterfaceEntry sie;
+ private final boolean mandatory;
+
+ public Dependency(ServiceInterfaceEntry sie, boolean mandatory) {
+ this.sie = sie;
+ this.mandatory = mandatory;
+ }
+
+ public ServiceInterfaceEntry getSie() {
+ return sie;
+ }
+
+ public boolean isMandatory() {
+ return mandatory;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o == null || getClass() != o.getClass())
+ return false;
+
+ Dependency that = (Dependency) o;
+
+ if (mandatory != that.mandatory)
+ return false;
+ if (!sie.equals(that.sie))
+ return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = sie.hashCode();
+ result = 31 * result + (mandatory ? 1 : 0);
+ return result;
+ }
+ }
import javax.management.ObjectName;
import javax.management.openmbean.SimpleType;
-public class DependencyAttribute extends AbstractAttribute implements
- TypedAttribute {
+public class DependencyAttribute extends AbstractDependencyAttribute {
- private final Dependency dependency;
- private final String nullableDescription, nullableDefault;
public DependencyAttribute(DataSchemaNode attrNode,
ServiceInterfaceEntry sie, boolean mandatory,
String nullableDescription) {
- super(attrNode);
- dependency = new Dependency(sie, mandatory);
- this.nullableDescription = nullableDescription;
- nullableDefault = null;
+ super(attrNode, sie, mandatory, nullableDescription);
}
@Override
return Types.typeForClass(ObjectName.class);
}
- public Dependency getDependency() {
- return dependency;
- }
-
- @Override
- public String getNullableDescription() {
- return nullableDescription;
- }
-
- @Override
- public String getNullableDefault() {
- return nullableDefault;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o)
- return true;
- if (o == null || getClass() != o.getClass())
- return false;
- if (!super.equals(o))
- return false;
-
- DependencyAttribute that = (DependencyAttribute) o;
-
- if (dependency != null ? !dependency.equals(that.dependency)
- : that.dependency != null)
- return false;
- if (nullableDefault != null ? !nullableDefault
- .equals(that.nullableDefault) : that.nullableDefault != null)
- return false;
- if (nullableDescription != null ? !nullableDescription
- .equals(that.nullableDescription)
- : that.nullableDescription != null)
- return false;
-
- return true;
- }
-
- @Override
- public int hashCode() {
- int result = super.hashCode();
- result = 31 * result + (dependency != null ? dependency.hashCode() : 0);
- result = 31
- * result
- + (nullableDescription != null ? nullableDescription.hashCode()
- : 0);
- result = 31 * result
- + (nullableDefault != null ? nullableDefault.hashCode() : 0);
- return result;
- }
-
- @Override
- public String toString() {
- return "DependencyAttribute{" + getAttributeYangName() + ","
- + "dependency=" + dependency + '}';
- }
-
@Override
public SimpleType<?> getOpenType() {
return SimpleType.OBJECTNAME;
}
- public static class Dependency {
- private final ServiceInterfaceEntry sie;
- private final boolean mandatory;
-
- public Dependency(ServiceInterfaceEntry sie, boolean mandatory) {
- this.sie = sie;
- this.mandatory = mandatory;
- }
-
- public ServiceInterfaceEntry getSie() {
- return sie;
- }
-
- public boolean isMandatory() {
- return mandatory;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o)
- return true;
- if (o == null || getClass() != o.getClass())
- return false;
-
- Dependency that = (Dependency) o;
-
- if (mandatory != that.mandatory)
- return false;
- if (!sie.equals(that.sie))
- return false;
-
- return true;
- }
-
- @Override
- public int hashCode() {
- int result = sie.hashCode();
- result = 31 * result + (mandatory ? 1 : 0);
- return result;
- }
- }
-
}
public class JavaAttribute extends AbstractAttribute implements TypedAttribute {
private final Type type;
- private final String nullableDescription, nullableDefault;
+ private final String nullableDescription, nullableDefault, nullableDefaultWrappedForCode;
private final TypeProviderWrapper typeProviderWrapper;
private final TypeDefinition<?> typeDefinition;
this.typeDefinition = leaf.getType();
this.typeProviderWrapper = typeProviderWrapper;
this.nullableDefault = leaf.getDefault();
+ this.nullableDefaultWrappedForCode = leaf.getDefault() == null ? null : typeProviderWrapper.getDefault(leaf);
this.nullableDescription = leaf.getDescription();
}
this.type = typeProviderWrapper.getType(leaf);
this.typeDefinition = leaf.getType();
this.typeProviderWrapper = typeProviderWrapper;
- this.nullableDefault = null;
+ this.nullableDefault = nullableDefaultWrappedForCode = null;
this.nullableDescription = leaf.getDescription();
}
+ public TypeDefinition<?> getTypeDefinition() {
+ return typeDefinition;
+ }
+
/**
* Returns the most base type
*/
return baseType;
}
+ public String getNullableDefaultWrappedForCode() {
+ return nullableDefaultWrappedForCode;
+ }
+
@Override
public Type getType() {
return type;
*/
package org.opendaylight.controller.config.yangjmxgenerator.attribute;
-import javax.management.openmbean.ArrayType;
-import javax.management.openmbean.OpenDataException;
-import javax.management.openmbean.OpenType;
-
import org.opendaylight.controller.config.yangjmxgenerator.TypeProviderWrapper;
+import org.opendaylight.yangtools.binding.generator.util.Types;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
-public class ListAttribute extends AbstractAttribute {
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.OpenType;
+import java.util.List;
+
+public class ListAttribute extends AbstractAttribute implements TypedAttribute {
private final String nullableDescription, nullableDefault;
- private final AttributeIfc innerAttribute;
+ private final TypedAttribute innerAttribute;
public static ListAttribute create(ListSchemaNode node,
- TypeProviderWrapper typeProvider) {
+ TypeProviderWrapper typeProvider, String packageName) {
- AttributeIfc innerAttribute = TOAttribute.create(node, typeProvider);
+ TOAttribute innerAttribute = TOAttribute.create(node, typeProvider, packageName);
return new ListAttribute(node, innerAttribute, node.getDescription());
}
public static ListAttribute create(LeafListSchemaNode node,
TypeProviderWrapper typeProvider) {
- AttributeIfc innerAttribute = new JavaAttribute(node, typeProvider);
+ JavaAttribute innerAttribute = new JavaAttribute(node, typeProvider);
return new ListAttribute(node, innerAttribute, node.getDescription());
}
- ListAttribute(DataSchemaNode attrNode, AttributeIfc innerAttribute,
+ ListAttribute(DataSchemaNode attrNode, TypedAttribute innerAttribute,
String description) {
super(attrNode);
this.nullableDescription = description;
return true;
}
+
+ @Override
+ public Type getType() {
+ return Types.parameterizedTypeFor(Types.typeForClass(List.class), innerAttribute.getType());
+ }
+
@Override
public ArrayType<?> getOpenType() {
- OpenType<?> inerOpenType = innerAttribute.getOpenType();
+ OpenType<?> innerOpenType = innerAttribute.getOpenType();
+ return constructArrayType(innerOpenType);
+ }
+
+ static ArrayType<?> constructArrayType(OpenType<?> innerOpenType){
try {
- return new ArrayType<>(1, inerOpenType);
+ return new ArrayType<>(1, innerOpenType);
} catch (OpenDataException e) {
throw new RuntimeException("Unable to create " + ArrayType.class
- + " with inner element of type " + inerOpenType, e);
+ + " with inner element of type " + innerOpenType, 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.config.yangjmxgenerator.attribute;
+
+import org.opendaylight.controller.config.yangjmxgenerator.ServiceInterfaceEntry;
+import org.opendaylight.yangtools.binding.generator.util.Types;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+import javax.management.ObjectName;
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import java.util.List;
+
+public class ListDependenciesAttribute extends AbstractDependencyAttribute {
+
+ public ListDependenciesAttribute(DataSchemaNode attrNode, ServiceInterfaceEntry sie, boolean mandatory, String nullableDescription) {
+ super(attrNode, sie, mandatory, nullableDescription);
+ }
+
+ @Override
+ public Type getType() {
+ return Types.parameterizedTypeFor(Types.typeForClass(List.class), Types.typeForClass(ObjectName.class));
+ }
+
+ @Override
+ public ArrayType<?> getOpenType() {
+ OpenType<?> innerOpenType = SimpleType.OBJECTNAME;
+ return ListAttribute.constructArrayType(innerOpenType);
+ }
+
+}
import com.google.common.collect.Sets;
import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
import org.opendaylight.controller.config.yangjmxgenerator.TypeProviderWrapper;
+import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
import java.util.Map.Entry;
import java.util.Set;
-public class TOAttribute extends AbstractAttribute {
+public class TOAttribute extends AbstractAttribute implements TypedAttribute {
private final String nullableDescription, nullableDefault;
private final Map<String, AttributeIfc> yangNameToAttributeMap;
private final Map<String, String> attributeNameMap;
+ private final String packageName;
private static final Set<Class<? extends DataSchemaNode>> ALLOWED_CHILDREN = Sets
.newHashSet();
}
public static <T extends DataNodeContainer & AugmentationTarget & DataSchemaNode> TOAttribute create(
- T containerSchemaNode, TypeProviderWrapper typeProviderWrapper) {
+ T containerSchemaNode, TypeProviderWrapper typeProviderWrapper, String packageName) {
// Transfer Object: get the leaves
Map<String, AttributeIfc> map = new HashMap<>();
Map<String, String> attributeNameMap = new HashMap<>();
String yangName = dataSchemaNode.getQName().getLocalName();
map.put(yangName,
createInnerAttribute(dataSchemaNode,
- typeProviderWrapper));
+ typeProviderWrapper, packageName));
} catch (IllegalArgumentException e) {
throw new IllegalStateException("Unable to create TO", e);
}
}
return new TOAttribute(containerSchemaNode, map, attributeNameMap,
- containerSchemaNode.getDescription());
+ containerSchemaNode.getDescription(), packageName);
}
private static AttributeIfc createInnerAttribute(
DataSchemaNode dataSchemaNode,
- TypeProviderWrapper typeProviderWrapper) {
+ TypeProviderWrapper typeProviderWrapper, String packageName) {
Class<? extends DataSchemaNode> type = isAllowedType(dataSchemaNode);
if (type.equals(LeafSchemaNode.class))
typeProviderWrapper);
else if (type.equals(ListSchemaNode.class))
return ListAttribute.create((ListSchemaNode) dataSchemaNode,
- typeProviderWrapper);
+ typeProviderWrapper, packageName);
else if (type.equals(LeafListSchemaNode.class))
return ListAttribute.create((LeafListSchemaNode) dataSchemaNode,
typeProviderWrapper);
else if (type.equals(ContainerSchemaNode.class))
return TOAttribute.create((ContainerSchemaNode) dataSchemaNode,
- typeProviderWrapper);
+ typeProviderWrapper, packageName);
throw new IllegalStateException("This should never happen");
}
private TOAttribute(DataSchemaNode attrNode,
Map<String, AttributeIfc> transferObject,
- Map<String, String> attributeNameMap, String nullableDescription) {
+ Map<String, String> attributeNameMap, String nullableDescription, String packageName) {
super(attrNode);
yangNameToAttributeMap = transferObject;
this.attributeNameMap = attributeNameMap;
this.nullableDescription = nullableDescription;
nullableDefault = null;
+ this.packageName = packageName;
}
public Map<String, String> getAttributeNameMap() {
+ yangNameToAttributeMap + '}';
}
+ @Override
+ public Type getType() {
+ // TODO: ReferencedTypeImpl from Types
+ return new ReferencedTypeImpl(packageName, getUpperCaseCammelCase());
+ }
+
@Override
public CompositeType getOpenType() {
String description = getNullableDescription() == null ? getAttributeYangName()
}
}
+ public String getPackageName() {
+ return packageName;
+ }
+
private static final class FunctionImpl implements
Function<Entry<String, AttributeIfc>, OpenType<?>> {
private final String[] itemNames;
testedYangModulesToExpectedConflictingName.put(
"config-test-runtime-bean-name-conflict2",
"StateARuntimeMXBean");
+ testedYangModulesToExpectedConflictingName.put(
+ "config-test-duplicate-attribute-in-runtime-and-mxbean",
+ "port");
}
private String getYangModuleName(String name) {
*/
package org.opendaylight.controller.config.yangjmxgenerator;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-
-import javax.management.openmbean.ArrayType;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.SimpleType;
-
+import com.google.common.collect.Sets;
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.TypedAttribute;
import org.opendaylight.yangtools.binding.generator.util.Types;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
-import com.google.common.collect.Sets;
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.SimpleType;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
public class ModuleMXBeanEntryTest extends AbstractYangTest {
public static final String EVENTBUS_MXB_NAME = "eventbus";
public static final String ASYNC_EVENTBUS_MXB_NAME = "async-eventbus";
public static final String THREADFACTORY_NAMING_MXB_NAME = "threadfactory-naming";
public static final String THREADPOOL_DYNAMIC_MXB_NAME = "threadpool-dynamic";
+ public static final String THREADPOOL_REGISTRY_IMPL_NAME = "threadpool-registry-impl";
public static final String BGP_LISTENER_IMPL_MXB_NAME = "bgp-listener-impl";
assertNotNull(namesToMBEs);
Set<String> expectedMXBeanNames = Sets.newHashSet(EVENTBUS_MXB_NAME,
ASYNC_EVENTBUS_MXB_NAME, THREADFACTORY_NAMING_MXB_NAME,
- THREADPOOL_DYNAMIC_MXB_NAME);
+ THREADPOOL_DYNAMIC_MXB_NAME, THREADPOOL_REGISTRY_IMPL_NAME);
assertThat(namesToMBEs.keySet(), is(expectedMXBeanNames));
return namesToMBEs;
}
}
}
+ { // test multiple dependencies
+ ModuleMXBeanEntry threadPoolRegistry = namesToMBEs.get(THREADPOOL_REGISTRY_IMPL_NAME);
+ Map<String, AttributeIfc> attributes = threadPoolRegistry.getAttributes();
+ assertEquals(1, attributes.size());
+ AttributeIfc threadpoolsAttr = attributes.get("threadpools");
+ assertNotNull(threadpoolsAttr);
+ assertTrue(threadpoolsAttr instanceof ListDependenciesAttribute);
+ ListDependenciesAttribute threadpools = (ListDependenciesAttribute) threadpoolsAttr;
+ }
}
}
@Test
public void testReadingIdentities_threadsJavaModule() {
- Map<String /* identity name */, Optional<QName>> expectedIdentitiesToBases = ImmutableMap
- .of("eventbus", Optional.of(MODULE_TYPE_Q_NAME), "async-eventbus", Optional.of(MODULE_TYPE_Q_NAME),
- "threadfactory-naming", Optional.of(MODULE_TYPE_Q_NAME), "threadpool-dynamic",
- Optional.of(MODULE_TYPE_Q_NAME), "thread-rpc-context", Optional.<QName>absent());
+ Map<String /* identity name */, Optional<QName>> expectedIdentitiesToBases = new HashMap(){{
+ put(ModuleMXBeanEntryTest.EVENTBUS_MXB_NAME, Optional.of(MODULE_TYPE_Q_NAME));
+ put(ModuleMXBeanEntryTest.ASYNC_EVENTBUS_MXB_NAME, Optional.of(MODULE_TYPE_Q_NAME));
+ put(ModuleMXBeanEntryTest.THREADFACTORY_NAMING_MXB_NAME, Optional.of(MODULE_TYPE_Q_NAME));
+ put(ModuleMXBeanEntryTest.THREADPOOL_DYNAMIC_MXB_NAME, Optional.of(MODULE_TYPE_Q_NAME));
+ put("thread-rpc-context", Optional.absent());
+ put(ModuleMXBeanEntryTest.THREADPOOL_REGISTRY_IMPL_NAME, Optional.of(MODULE_TYPE_Q_NAME));
+ }};
+
assertAllIdentitiesAreExpected(threadsJavaModule,
expectedIdentitiesToBases);
}
--- /dev/null
+// vi: set smarttab et sw=4 tabstop=4:
+module config-test-duplicate-attribute-in-runtime-and-mxbean {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:jmx:duplicate:runtime";
+ prefix "th-java";
+
+ import config { prefix config; revision-date 2013-04-05; }
+ import rpc-context { prefix rpcx; revision-date 2013-06-17; }
+ import ietf-inet-types { prefix inet; revision-date 2010-09-24;}
+
+
+ description
+ "This module contains the base YANG definitions for NS-OS
+ thread services pure Java implementation.";
+
+ revision "2013-04-05" {
+ description
+ "Updated to work with new anchors.";
+ }
+
+ revision "2013-04-03" {
+ description
+ "Initial revision.";
+ }
+
+ identity async-eventbus {
+ base config:module-type;
+ config:java-name-prefix AsyncEventBus;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case async-eventbus {
+ when "/config:modules/config:module/config:type = 'async-eventbus'";
+ leaf port {
+ type string;
+ }
+ leaf core-size {
+ type uint32;
+ }
+ leaf simple-int3 {
+ type uint16;
+ }
+ }
+ }
+
+ augment "/config:modules/config:module/config:state" {
+ case async-eventbus {
+ when "/config:modules/config:module/config:type = 'async-eventbus'";
+ leaf simple-arg {
+ type uint32;
+ }
+ leaf port {
+ type inet:port-number;
+ }
+ }
+ }
+}
\ No newline at end of file
}
}
}
+
+ identity threadpool-registry-impl {
+ base config:module-type;
+ config:java-name-prefix ThreadPoolRegistryImpl;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case threadpool-registry-impl {
+ when "/config:modules/config:module/config:type = 'threadpool-registry-impl'";
+
+ // list of dependencies:
+ list threadpools {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity th2:threadpool;
+ }
+ }
+ }
+ }
+ }
}
container dto-a {
leaf simple-arg {
type uint32;
+ default 1;
}
leaf port {
type inet:port-number;
+ default 8080;
}
+ leaf ip4 {
+ type inet:ipv4-address;
+ default 127.0.0.1;
+ }
+
+ leaf ip {
+ type inet:ip-address;
+ // TODO defaults for union default 0:0:0:0:0:0:0:1;
+ }
}
leaf as-number {
- mandatory true;
type inet:as-number;
+ default 44;
}
leaf simpleInt {
type uint32;
- default 99L;
+ default 99;
}
container dto_b {
leaf simple-int1 {
type uint32;
+ default 32;
}
leaf simple-int2 {
when "/config:modules/config:module/config:type = 'impl-netconf'";
leaf binaryLeaf {
type binary;
+ default ZGVmYXVsdEJpbg==;
}
leaf type {
type string;
+ default "default-string";
}
leaf extended {
type tt:extend-once;
+ default 1;
}
leaf extended-twice {
type tt:extend-twice;
+ default 2;
}
leaf extended-enum {
type tt:extend-enum;
+ default ONE;
}
leaf sleep-factor {
type decimal64 {
fraction-digits 2;
}
+ default 2.00;
}
container dto-c {
}
leaf simple-long {
- type int64 ;
+ type int64;
+ default -45;
}
leaf simple-long-2 {
type uint32;
+ default 445;
}
leaf simple-BigInteger {
type uint64;
+ default 545454;
}
leaf simple-byte {
type int8;
+ default -4;
}
leaf simple-short {
type uint8;
+ default 45;
}
leaf simple-test {
container deep {
leaf simple-int3 {
type uint16;
+ default 0;
}
}
}
}
}
}
+
+ list testing-deps {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity test:testing;
+ }
+ }
+ }
}
}
container retValContainer {
leaf v1 {
type string;
+ default "from rpc";
}
leaf v2 {
<groupId>org.opendaylight.controller.thirdparty</groupId>
<artifactId>ganymed</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-remoterpc-connector</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>
+ zeromq-routingtable.implementation
+ </artifactId>
+ <version>0.4.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.zeromq</groupId>
+ <artifactId>jeromq</artifactId>
+ <version>0.3.1</version>
+ </dependency>
</dependencies>
</profile>
<profile>
<type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty">netty:netty-threadgroup</type>
<instance>
<name>global-boss-group</name>
- <provider>/config/modules/module[name='netty-threadgroup-fixed']/instance[name='global-boss-group']</provider>
+ <provider>/modules/module[type='netty-threadgroup-fixed'][name='global-boss-group']</provider>
</instance>
<instance>
<name>global-worker-group</name>
- <provider>/config/modules/module[name='netty-threadgroup-fixed']/instance[name='global-worker-group']</provider>
+ <provider>/modules/module[type='netty-threadgroup-fixed'][name='global-worker-group']</provider>
</instance>
</service>
<service>
<type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty">netty:netty-event-executor</type>
<instance>
<name>global-event-executor</name>
- <provider>/config/modules/module[name='netty-global-event-executor']/instance[name='global-event-executor']</provider>
+ <provider>/modules/module[type='netty-global-event-executor'][name='global-event-executor']</provider>
</instance>
</service>
<service>
<type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty">netty:netty-timer</type>
<instance>
<name>global-timer</name>
- <provider>/config/modules/module[name='netty-hashed-wheel-timer']/instance[name='global-timer']</provider>
+ <provider>/modules/module[type='netty-hashed-wheel-timer'][name='global-timer']</provider>
</instance>
</service>
//CAPABILITIES START
<type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
<instance>
<name>ref_yang-schema-service</name>
- <provider>/config/modules/module[name='schema-service-singleton']/instance[name='yang-schema-service']</provider>
+ <provider>/modules/module[type='schema-service-singleton'][name='yang-schema-service']</provider>
</instance>
</service>
<service>
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
<instance>
<name>ref_binding-notification-broker</name>
- <provider>/config/modules/module[name='binding-notification-broker']/instance[name='binding-notification-broker']</provider>
+ <provider>/modules/module[type='binding-notification-broker'][name='binding-notification-broker']</provider>
</instance>
</service>
<service>
<type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
<instance>
<name>ref_hash-map-data-store</name>
- <provider>/config/modules/module[name='hash-map-data-store']/instance[name='hash-map-data-store']</provider>
+ <provider>/modules/module[type='hash-map-data-store'][name='hash-map-data-store']</provider>
</instance>
<instance>
- <name>ref_cluster-data-store</name>
- <provider>/config/modules/module[name='dom-clustered-store-impl']/instance[name='cluster-data-store']</provider>
- </instance>
+ <name>ref_cluster-data-store</name>
+ <provider>/modules/module[type='dom-clustered-store-impl'][name='cluster-data-store']</provider>
+ </instance>
</service>
<service>
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
<instance>
<name>ref_binding-broker-impl</name>
- <provider>/config/modules/module[name='binding-broker-impl']/instance[name='binding-broker-impl']</provider>
+ <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
</instance>
</service>
<service>
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
<instance>
- <name>ref_binding-rpc-broker</name>
- <provider>/config/modules/module[name='binding-broker-impl']/instance[name='binding-broker-impl']</provider>
+ <name>binding-rpc-broker</name>
+ <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
</instance>
</service>
<service>
<type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding-impl:binding-dom-mapping-service</type>
<instance>
<name>ref_runtime-mapping-singleton</name>
- <provider>/config/modules/module[name='runtime-generated-mapping']/instance[name='runtime-mapping-singleton']</provider>
+ <provider>/modules/module[type='runtime-generated-mapping'][name='runtime-mapping-singleton']</provider>
</instance>
</service>
<service>
<type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
<instance>
<name>ref_dom-broker</name>
- <provider>/config/modules/module[name='dom-broker-impl']/instance[name='dom-broker']</provider>
+ <provider>/modules/module[type='dom-broker-impl'][name='dom-broker']</provider>
</instance>
</service>
<service>
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
<instance>
<name>ref_binding-data-broker</name>
- <provider>/config/modules/module[name='binding-data-broker']/instance[name='binding-data-broker']</provider>
+ <provider>/modules/module[type='binding-data-broker'][name='binding-data-broker']</provider>
</instance>
</service>
//CAPABILITIES START
sstr = Pattern.compile("OUTPUT=(.*)").matcher(actiongrp);
if (sstr.matches()) {
for (String t : sstr.group(1).split(",")) {
- Matcher n = Pattern.compile("(?:(\\d+))").matcher(t);
- if (n.matches()) {
- String port = n.group(1);
- if (port != null) {
- if (!isPortValid(sw, port)) {
- String msg = String.format("Output port %s is not valid for this switch", port);
- if (!containerName.equals(GlobalConstants.DEFAULT.toString())) {
- msg += " in Container " + containerName;
- }
- return new Status(StatusCode.BADREQUEST, msg);
+ if (t != null) {
+ if (!isPortValid(sw, t)) {
+ String msg = String.format("Output port %s is not valid for this switch", t);
+ if (!containerName.equals(GlobalConstants.DEFAULT.toString())) {
+ msg += " in Container " + containerName;
}
+ return new Status(StatusCode.BADREQUEST, msg);
}
- } else {
- String msg = String.format("Output port %s is not valid", t);
- return new Status(StatusCode.BADREQUEST, msg);
}
}
continue;
sstr = Pattern.compile("ENQUEUE=(.*)").matcher(actiongrp);
if (sstr.matches()) {
for (String t : sstr.group(1).split(",")) {
- Matcher n = Pattern.compile("(?:(\\d+:\\d+))").matcher(t);
- if (n.matches()) {
- if (n.group(1) != null) {
- String port = n.group(1).split(":")[0];
- if (!isPortValid(sw, port)) {
- String msg = String.format("Output port %d is not valid for this switch", port);
- if (!containerName.equals(GlobalConstants.DEFAULT.toString())) {
- msg += " in Container " + containerName;
- }
- return new Status(StatusCode.BADREQUEST, msg);
+ if (t != null) {
+ String port = t.split(":")[0];
+ if (!isPortValid(sw, port)) {
+ String msg = String.format("Output port %d is not valid for this switch", port);
+ if (!containerName.equals(GlobalConstants.DEFAULT.toString())) {
+ msg += " in Container " + containerName;
}
+ return new Status(StatusCode.BADREQUEST, msg);
}
- } else {
- String msg = String.format("Enqueue port %s is not valid", t);
- return new Status(StatusCode.BADREQUEST, msg);
}
}
continue;
sstr = Pattern.compile(ActionType.OUTPUT + "=(.*)").matcher(actiongrp);
if (sstr.matches()) {
for (String t : sstr.group(1).split(",")) {
- Matcher n = Pattern.compile("(?:(\\d+))").matcher(t);
- if (n.matches()) {
- if (n.group(1) != null) {
- String nc = String.format("%s|%s@%s", node.getType(), n.group(1), node.toString());
- actionList.add(new Output(NodeConnector.fromString(nc)));
- }
+ if (t != null) {
+ String nc = String.format("%s|%s@%s", node.getType(), t, node.toString());
+ actionList.add(new Output(NodeConnector.fromString(nc)));
}
}
continue;
sstr = Pattern.compile(ActionType.ENQUEUE + "=(.*)").matcher(actiongrp);
if (sstr.matches()) {
for (String t : sstr.group(1).split(",")) {
- Matcher n = Pattern.compile("(?:(\\d+:\\d+))").matcher(t);
- if (n.matches()) {
- if (n.group(1) != null) {
- String parts[] = n.group(1).split(":");
- String nc = String.format("%s|%s@%s", node.getType(), parts[0], node.toString());
- if (parts.length == 1) {
- actionList.add(new Enqueue(NodeConnector.fromString(nc)));
- } else {
- actionList
- .add(new Enqueue(NodeConnector.fromString(nc), Integer.parseInt(parts[1])));
- }
+ if (t != null) {
+ String parts[] = t.split(":");
+ String nc = String.format("%s|%s@%s", node.getType(), parts[0], node.toString());
+ if (parts.length == 1) {
+ actionList.add(new Enqueue(NodeConnector.fromString(nc)));
+ } else {
+ actionList
+ .add(new Enqueue(NodeConnector.fromString(nc), Integer.parseInt(parts[1])));
}
}
}
}
} else if (action instanceof SetDlDstAction) {
MacAddress address = ((SetDlDstAction) action).getAddress();
- if (address != null && !isL2AddressValid(address.toString())) {
+ if (address != null && !isL2AddressValid(address.getValue())) {
logger.error("SetDlDstAction: Address not valid");
return false;
}
} else if (action instanceof SetDlSrcAction) {
MacAddress address = ((SetDlSrcAction) action).getAddress();
- if (address != null && !isL2AddressValid(address.toString())) {
+ if (address != null && !isL2AddressValid(address.getValue())) {
logger.error("SetDlSrcAction: Address not valid");
return false;
}
import java.util.ArrayList;
import java.util.Collections;
-import java.util.EnumSet;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.Future;
-
-import org.opendaylight.controller.clustering.services.CacheConfigException;
-import org.opendaylight.controller.clustering.services.CacheExistException;
-import org.opendaylight.controller.clustering.services.IClusterContainerServices;
-import org.opendaylight.controller.clustering.services.IClusterServices;
+
import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
import org.opendaylight.controller.md.sal.common.api.data.DataModification;
import org.opendaylight.controller.sal.common.util.Rpcs;
-import org.opendaylight.controller.sal.core.IContainer;
-import org.opendaylight.controller.sal.utils.ServiceHelper;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowAdded;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowRemoved;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowTableRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowUpdated;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeErrorNotification;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeExperimenterErrorNotification;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeFlow;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowListener;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SwitchFlowRemoved;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlowBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlowBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.config.rev131024.Tables;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.config.rev131024.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.config.rev131024.tables.TableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.config.rev131024.tables.TableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableRef;
import org.opendaylight.yangtools.concepts.Registration;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public class FlowConsumerImpl implements IForwardingRulesManager {
+public class FlowConsumerImpl {
protected static final Logger logger = LoggerFactory.getLogger(FlowConsumerImpl.class);
private final FlowEventListener flowEventListener = new FlowEventListener();
private Registration<NotificationListener> listener1Reg;
private SalFlowService flowService;
// private FlowDataListener listener;
- private FlowDataCommitHandler commitHandler;
- private static ConcurrentHashMap<FlowKey, Flow> originalSwView;
- private static ConcurrentMap<FlowKey, Flow> installedSwView;
- private IClusterContainerServices clusterContainerService = null;
- private IContainer container;
- private static final String NAMEREGEX = "^[a-zA-Z0-9]+$";
- private static ConcurrentMap<Integer, Flow> staticFlows;
- private static ConcurrentMap<Integer, Integer> staticFlowsOrdinal = new ConcurrentHashMap<Integer, Integer>();
- /*
- * Inactive flow list. This is for the global instance of FRM It will
- * contain all the flow entries which were installed on the global container
- * when the first container is created.
- */
- private static ConcurrentMap<FlowKey, Flow> inactiveFlows;
-
- /*
- * /* Per node indexing
- */
- private static ConcurrentMap<Node, List<Flow>> nodeFlows;
- private boolean inContainerMode; // being used by global instance only
+ private FlowDataCommitHandler commitHandler;
public FlowConsumerImpl() {
InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(Flows.class).toInstance();
logger.error("Consumer SAL Service is down or NULL. FRM may not function as intended");
return;
}
-
- // listener = new FlowDataListener();
-
- // if (null ==
- // FRMConsumerImpl.getDataBrokerService().registerDataChangeListener(path,
- // listener)) {
- // logger.error("Failed to listen on flow data modifcation events");
- // System.out.println("Consumer SAL Service is down or NULL.");
- // return;
- // }
-
+
// For switch events
listener1Reg = FRMConsumerImpl.getNotificationService().registerNotificationListener(flowEventListener);
}
// addFlowTest();
commitHandler = new FlowDataCommitHandler();
- FRMConsumerImpl.getDataProviderService().registerCommitHandler(path, commitHandler);
- clusterContainerService = (IClusterContainerServices) ServiceHelper.getGlobalInstance(
- IClusterContainerServices.class, this);
- allocateCaches();
- /*
- * If we are not the first cluster node to come up, do not initialize
- * the static flow entries ordinal
- */
- if (staticFlowsOrdinal.size() == 0) {
- staticFlowsOrdinal.put(0, Integer.valueOf(0));
- }
+ FRMConsumerImpl.getDataProviderService().registerCommitHandler(path, commitHandler);
}
-
- private void allocateCaches() {
-
- if (this.clusterContainerService == null) {
- logger.warn("Un-initialized clusterContainerService, can't create cache");
- return;
- }
-
- try {
- clusterContainerService.createCache("frm.originalSwView",
- EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
- clusterContainerService.createCache("frm.installedSwView",
- EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
- clusterContainerService
- .createCache("frm.staticFlows", EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
- clusterContainerService.createCache("frm.staticFlowsOrdinal",
- EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
- clusterContainerService.createCache("frm.inactiveFlows",
- EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
- clusterContainerService.createCache("frm.nodeFlows", EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
- clusterContainerService.createCache("frm.groupFlows", EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
- } catch (CacheConfigException cce) {
- logger.error("CacheConfigException");
- } catch (CacheExistException cce) {
- logger.error("CacheExistException");
- }
- }
-
- private void addFlowTest() {
- try {
- NodeRef nodeOne = createNodeRef("foo:node:1");
- AddFlowInputBuilder input1 = new AddFlowInputBuilder();
-
- input1.setNode(nodeOne);
- AddFlowInput firstMsg = input1.build();
-
- if (null == flowService) {
- logger.error("ConsumerFlowService is NULL");
- }
- @SuppressWarnings("unused")
- Future<RpcResult<AddFlowOutput>> result1 = flowService.addFlow(firstMsg);
-
- } catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
-
+
/**
* Adds flow to the southbound plugin and our internal database
*
private void addFlow(InstanceIdentifier<?> path, Flow dataObject) {
AddFlowInputBuilder input = new AddFlowInputBuilder();
-
+ input.fieldsFrom(dataObject);
input.setNode((dataObject).getNode());
- input.setPriority((dataObject).getPriority());
- input.setMatch((dataObject).getMatch());
- input.setCookie((dataObject).getCookie());
- input.setInstructions((dataObject).getInstructions());
- input.setBufferId(dataObject.getBufferId());
- input.setTableId(dataObject.getTableId());
- input.setOutPort(dataObject.getOutPort());
- input.setOutGroup(dataObject.getOutGroup());
- input.setIdleTimeout(dataObject.getIdleTimeout());
- input.setHardTimeout(dataObject.getHardTimeout());
- input.setFlowName(dataObject.getFlowName());
- input.setFlags(dataObject.getFlags());
- input.setCookieMask(dataObject.getCookieMask());
- input.setContainerName(dataObject.getContainerName());
- input.setBarrier(dataObject.isBarrier());
- input.setInstallHw(dataObject.isInstallHw());
- input.setStrict(dataObject.isStrict());
-
- // updating the staticflow cache
- /*
- * Commented out... as in many other places... use of ClusteringServices
- * is breaking things insufficient time to debug Integer ordinal =
- * staticFlowsOrdinal.get(0); staticFlowsOrdinal.put(0, ++ordinal);
- * staticFlows.put(ordinal, dataObject);
- */
-
+ input.setFlowTable(new FlowTableRef(createTableInstance(dataObject.getId(), dataObject.getNode())));
// We send flow to the sounthbound plugin
-
flowService.addFlow(input.build());
-
- /*
- * Commented out as this will also break due to improper use of
- * ClusteringServices updateLocalDatabase((NodeFlow) dataObject, true);
- */
}
/**
* @param dataObject
*/
private void removeFlow(InstanceIdentifier<?> path, Flow dataObject) {
-
+
RemoveFlowInputBuilder input = new RemoveFlowInputBuilder();
+ input.fieldsFrom(dataObject);
input.setNode((dataObject).getNode());
- input.setPriority((dataObject).getPriority());
- input.setMatch((dataObject).getMatch());
- input.setCookie((dataObject).getCookie());
- input.setInstructions((dataObject).getInstructions());
- input.setBufferId(dataObject.getBufferId());
input.setTableId(dataObject.getTableId());
- input.setOutPort(dataObject.getOutPort());
- input.setOutGroup(dataObject.getOutGroup());
- input.setIdleTimeout(dataObject.getIdleTimeout());
- input.setHardTimeout(dataObject.getHardTimeout());
- input.setFlowName(dataObject.getFlowName());
- input.setFlags(dataObject.getFlags());
- input.setCookieMask(dataObject.getCookieMask());
- input.setContainerName(dataObject.getContainerName());
- input.setBarrier(dataObject.isBarrier());
- input.setInstallHw(dataObject.isInstallHw());
- input.setStrict(dataObject.isStrict());
- // updating the staticflow cache
- /*
- * Commented out due to problems caused by improper use of
- * ClusteringServices Integer ordinal = staticFlowsOrdinal.get(0);
- * staticFlowsOrdinal.put(0, ++ordinal); staticFlows.put(ordinal,
- * dataObject);
- */
-
+ input.setFlowTable(new FlowTableRef(createTableInstance((long)dataObject.getTableId(), (dataObject).getNode())));
// We send flow to the sounthbound plugin
flowService.removeFlow(input.build());
-
- /*
- * Commented out due to problems caused by improper use of
- * ClusteringServices updateLocalDatabase((NodeFlow) dataObject, false);
- */
}
/**
* @param path
* @param dataObject
*/
- private void updateFlow(InstanceIdentifier<?> path, Flow dataObject) {
+ private void updateFlow(InstanceIdentifier<?> path, Flow updatedFlow, Flow originalFlow) {
UpdateFlowInputBuilder input = new UpdateFlowInputBuilder();
UpdatedFlowBuilder updatedflowbuilder = new UpdatedFlowBuilder();
- updatedflowbuilder.fieldsFrom(dataObject);
- input.setNode(dataObject.getNode());
- input.setUpdatedFlow(updatedflowbuilder.build());
-
- // updating the staticflow cache
- /*
- * Commented out due to problems caused by improper use of
- * ClusteringServices. Integer ordinal = staticFlowsOrdinal.get(0);
- * staticFlowsOrdinal.put(0, ++ordinal); staticFlows.put(ordinal,
- * dataObject);
- */
-
+ updatedflowbuilder.fieldsFrom(updatedFlow);
+ input.setNode(updatedFlow.getNode());
+ input.setUpdatedFlow(updatedflowbuilder.build());
+ OriginalFlowBuilder ofb = new OriginalFlowBuilder(originalFlow);
+ input.setOriginalFlow(ofb.build());
// We send flow to the sounthbound plugin
flowService.updateFlow(input.build());
-
- /*
- * Commented out due to problems caused by improper use of
- * ClusteringServices. updateLocalDatabase((NodeFlow) dataObject, true);
- */
}
-
- @SuppressWarnings("unchecked")
+
private void commitToPlugin(internalTransaction transaction) {
Set<Entry<InstanceIdentifier<?>, DataObject>> createdEntries = transaction.getModification()
.getCreatedConfigurationData().entrySet();
addFlow(entry.getKey(), (Flow) entry.getValue());
}
}
- for (@SuppressWarnings("unused")
- Entry<InstanceIdentifier<?>, DataObject> entry : updatedEntries) {
+
+ for (Entry<InstanceIdentifier<?>, DataObject> entry : updatedEntries) {
if (entry.getValue() instanceof Flow) {
logger.debug("Coming update cc in FlowDatacommitHandler");
- Flow flow = (Flow) entry.getValue();
- boolean status = validate(flow);
+ Flow updatedFlow = (Flow) entry.getValue();
+ Flow originalFlow = (Flow) transaction.modification.getOriginalConfigurationData().get(entry.getKey());
+ boolean status = validate(updatedFlow);
if (!status) {
return;
}
- updateFlow(entry.getKey(), (Flow) entry.getValue());
+ updateFlow(entry.getKey(), updatedFlow, originalFlow);
}
}
logger.debug("Coming remove cc in FlowDatacommitHandler");
Flow flow = (Flow) removeValue;
boolean status = validate(flow);
+
if (!status) {
return;
}
+
removeFlow(instanceId, (Flow) removeValue);
-
}
}
-
}
- private final class FlowDataCommitHandler implements DataCommitHandler<InstanceIdentifier<?>, DataObject> {
-
+ private final class FlowDataCommitHandler implements DataCommitHandler<InstanceIdentifier<?>, DataObject> {
+
@SuppressWarnings("unchecked")
- @Override
- public DataCommitTransaction requestCommit(DataModification<InstanceIdentifier<?>, DataObject> modification) {
+ public DataCommitTransaction<InstanceIdentifier<?>, DataObject> requestCommit(DataModification<InstanceIdentifier<?>, DataObject> modification) {
// We should verify transaction
logger.debug("Coming in FlowDatacommitHandler");
internalTransaction transaction = new internalTransaction(modification);
public internalTransaction(DataModification<InstanceIdentifier<?>, DataObject> modification) {
this.modification = modification;
}
-
- Map<InstanceIdentifier<?>, Flow> additions = new HashMap<>();
- Map<InstanceIdentifier<?>, Flow> updates = new HashMap<>();
- Map<InstanceIdentifier<?>, Flow> removals = new HashMap<>();
-
+
/**
* We create a plan which flows will be added, which will be updated and
* which will be removed based on our internal state.
*
*/
- void prepareUpdate() {
+ void prepareUpdate() {
- Set<Entry<InstanceIdentifier<?>, DataObject>> puts = modification.getUpdatedConfigurationData().entrySet();
- for (Entry<InstanceIdentifier<?>, DataObject> entry : puts) {
- }
-
- // removals = modification.getRemovedConfigurationData();
- Set<InstanceIdentifier<?>> removedData = modification.getRemovedConfigurationData();
- for (InstanceIdentifier<?> removal : removedData) {
- DataObject value = modification.getOriginalConfigurationData().get(removal);
- if (value instanceof Flow) {
- removals.put(removal, (Flow) value);
- }
- }
-
- }
-
- private void preparePutEntry(InstanceIdentifier<?> key, Flow flow) {
- Flow original = originalSwView.get(key);
- if (original != null) {
- // It is update for us
- updates.put(key, flow);
- } else {
- // It is addition for us
- additions.put(key, flow);
- }
}
-
+
/**
* We are OK to go with execution of plan
*
*/
@Override
public RpcResult<Void> finish() throws IllegalStateException {
-
- commitToPlugin(this);
- // We return true if internal transaction is successful.
- // return Rpcs.getRpcResult(true, null, Collections.emptySet());
+ commitToPlugin(this);
return Rpcs.getRpcResult(true, null, Collections.<RpcError> emptySet());
}
*
*/
@Override
- public RpcResult<Void> rollback() throws IllegalStateException {
- // NOOP - we did not modified any internal state during
- // requestCommit phase
- // return Rpcs.getRpcResult(true, null, Collections.emptySet());
+ public RpcResult<Void> rollback() throws IllegalStateException {
+ rollBackFlows(modification);
return Rpcs.getRpcResult(true, null, Collections.<RpcError> emptySet());
- }
+ }
+ }
- private boolean flowEntryExists(Flow flow) {
- // Flow name has to be unique on per table id basis
- for (ConcurrentMap.Entry<FlowKey, Flow> entry : originalSwView.entrySet()) {
- if (entry.getValue().getFlowName().equals(flow.getFlowName())
- && entry.getValue().getTableId().equals(flow.getTableId())) {
- return true;
- }
- }
- return false;
+ private void rollBackFlows(DataModification<InstanceIdentifier<?>, DataObject> modification) {
+ Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries = modification.getCreatedConfigurationData().entrySet();
+
+ /*
+ * This little dance is because updatedEntries contains both created and modified entries
+ * The reason I created a new HashSet is because the collections we are returned are immutable.
+ */
+ Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updatedEntries = new HashSet<Entry<InstanceIdentifier<? extends DataObject>, DataObject>>();
+ updatedEntries.addAll(modification.getUpdatedConfigurationData().entrySet());
+ updatedEntries.removeAll(createdEntries);
+
+ Set<InstanceIdentifier<? >> removeEntriesInstanceIdentifiers = modification.getRemovedConfigurationData();
+ for (Entry<InstanceIdentifier<?>, DataObject> entry : createdEntries) {
+ if(entry.getValue() instanceof Flow) {
+ removeFlow(entry.getKey(),(Flow) entry.getValue()); // because we are rolling back, remove what we would have added.
}
}
+
+ for (Entry<InstanceIdentifier<?>, DataObject> entry : updatedEntries) {
+ if(entry.getValue() instanceof Flow) {
+ Flow updatedFlow = (Flow) entry.getValue();
+ Flow originalFlow = (Flow) modification.getOriginalConfigurationData().get(entry.getKey());
+ updateFlow(entry.getKey(), updatedFlow ,originalFlow);// because we are rolling back, replace the updated with the original
+ }
+ }
+
+ for (InstanceIdentifier<?> instanceId : removeEntriesInstanceIdentifiers ) {
+ DataObject removeValue = (Flow) modification.getOriginalConfigurationData().get(instanceId);
+ if(removeValue instanceof Flow) {
+ addFlow(instanceId,(Flow) removeValue);// because we are rolling back, add what we would have removed.
+ }
+ }
+}
final class FlowEventListener implements SalFlowListener {
List<FlowAdded> addedFlows = new ArrayList<>();
// TODO Auto-generated method stub
}
-
}
- // Commented out DataChangeListene - to be used by Stats
-
- // final class FlowDataListener implements DataChangeListener {
- // private SalFlowService flowService;
- //
- // public FlowDataListener() {
- //
- // }
- //
- // @Override
- // public void onDataChanged(
- // DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
- // System.out.println("Coming in onDataChange..............");
- // @SuppressWarnings("unchecked")
- // Collection<DataObject> additions = (Collection<DataObject>)
- // change.getCreatedConfigurationData();
- // // we can check for getCreated, getDeleted or getUpdated from DataChange
- // Event class
- // for (DataObject dataObject : additions) {
- // if (dataObject instanceof NodeFlow) {
- // NodeRef nodeOne = createNodeRef("foo:node:1");
- // // validating the dataObject here
- // AddFlowInputBuilder input = new AddFlowInputBuilder();
- // input.setNode(((NodeFlow) dataObject).getNode());
- // input.setNode(nodeOne);
- // // input.setPriority(((NodeFlow) dataObject).getPriority());
- // //input.setMatch(((NodeFlow) dataObject).getMatch());
- // //input.setFlowTable(((NodeFlow) dataObject).getFlowTable());
- // //input.setCookie(((NodeFlow) dataObject).getCookie());
- // //input.setAction(((NodeFlow) dataObject).getAction());
- //
- // @SuppressWarnings("unused")
- // Future<RpcResult<java.lang.Void>> result =
- // flowService.addFlow(input.build());
- // }
- // }
- // }
- // }
-
public boolean validate(Flow flow) {
-
String msg = ""; // Specific part of warn/error log
boolean result = true;
// flow Name validation
- if (flow.getFlowName() == null || flow.getFlowName().trim().isEmpty() || !flow.getFlowName().matches(NAMEREGEX)) {
+ if (!FRMUtil.isNameValid(flow.getFlowName())) {
msg = "Invalid Flow name";
result = false;
}
+
// Node Validation
if (result == true && flow.getNode() == null) {
msg = "Node is null";
result = false;
}
}
-
- // Presence check
- /*
- * This is breaking due to some improper use of caches...
- *
- * if (flowEntryExists(flow)) { String error =
- * "Entry with this name on specified table already exists";
- * logger.warn(
- * "Entry with this name on specified table already exists: {}" ,
- * entry); logger.error(error); return; } if
- * (originalSwView.containsKey(entry)) { logger.warn(
- * "Operation Rejected: A flow with same match and priority exists on the target node"
- * ); logger.trace("Aborting to install {}", entry); continue; }
- */
+
if (!FRMUtil.validateMatch(flow)) {
logger.error("Not a valid Match");
result = false;
}
return result;
}
-
- private static void updateLocalDatabase(NodeFlow entry, boolean add) {
-
- updateSwViewes(entry, add);
-
- updateNodeFlowsDB(entry, add);
-
- }
-
- /*
- * Update the node mapped flows database
- */
- private static void updateSwViewes(NodeFlow entry, boolean add) {
- if (add) {
- FlowConsumerImpl.originalSwView.put((FlowKey) entry, (Flow) entry);
- installedSwView.put((FlowKey) entry, (Flow) entry);
- } else {
- originalSwView.remove(entry);
- installedSwView.remove(entry);
-
- }
- }
-
- @Override
- public List<DataObject> get() {
-
- List<DataObject> orderedList = new ArrayList<DataObject>();
- ConcurrentMap<Integer, Flow> flowMap = staticFlows;
- int maxKey = staticFlowsOrdinal.get(0).intValue();
- for (int i = 0; i <= maxKey; i++) {
- Flow entry = flowMap.get(i);
- if (entry != null) {
- orderedList.add(entry);
- }
- }
- return orderedList;
- }
-
- @Override
- public DataObject getWithName(String name, org.opendaylight.controller.sal.core.Node n) {
- if (this instanceof FlowConsumerImpl) {
- for (ConcurrentMap.Entry<Integer, Flow> flowEntry : staticFlows.entrySet()) {
- Flow flow = flowEntry.getValue();
- if (flow.getNode().equals(n) && flow.getFlowName().equals(name)) {
-
- return flowEntry.getValue();
- }
- }
- }
- return null;
- }
-
- /*
- * Update the node mapped flows database
- */
- private static void updateNodeFlowsDB(NodeFlow entry, boolean add) {
- Node node = (Node) entry.getNode();
-
- List<Flow> nodeIndeces = nodeFlows.get(node);
- if (nodeIndeces == null) {
- if (!add) {
- return;
- } else {
- nodeIndeces = new ArrayList<Flow>();
- }
- }
-
- if (add) {
- nodeIndeces.add((Flow) entry);
- } else {
- nodeIndeces.remove(entry);
- }
-
- // Update cache across cluster
- if (nodeIndeces.isEmpty()) {
- nodeFlows.remove(node);
- } else {
- nodeFlows.put(node, nodeIndeces);
- }
- }
-
- private static NodeRef createNodeRef(String string) {
- NodeKey key = new NodeKey(new NodeId(string));
- InstanceIdentifier<Node> path = InstanceIdentifier.builder().node(Nodes.class).node(Node.class, key)
- .toInstance();
-
- return new NodeRef(path);
+
+ private InstanceIdentifier<?> createTableInstance(Long tableId, NodeRef nodeRef) {
+ Table table;
+ InstanceIdentifier<Table> tableInstance;
+ TableBuilder builder = new TableBuilder();
+ builder.setId(tableId);
+ builder.setKey(new TableKey(tableId, nodeRef));
+ table = builder.build();
+ tableInstance = InstanceIdentifier.builder(Tables.class).child(Table.class, table.getKey()).toInstance();
+ return tableInstance;
}
}
\ No newline at end of file
* @param dataObject
*/
private void updateGroup(InstanceIdentifier<?> path,
- Group originalGroupDataObject, Group updatedGroupDataObject) {
-
- GroupKey groupKey = updatedGroupDataObject.getKey();
- // Node nodeInstanceID = path.firstIdentifierOf("Node");
+ Group updatedGroupDataObject, Group originalGroupDataObject) {
UpdatedGroupBuilder updateGroupBuilder = null;
Status groupOperationStatus = validateGroup(updatedGroupDataObject);
-
+
if (!groupOperationStatus.isSuccess()) {
logger.error("Group data object validation failed %s" + updatedGroupDataObject.getGroupName());
return;
}
- UpdateGroupInputBuilder groupInputBuilder = new UpdateGroupInputBuilder();
+ UpdateGroupInputBuilder groupInputBuilder = new UpdateGroupInputBuilder();
+ updateGroupBuilder = new UpdatedGroupBuilder(updatedGroupDataObject);
+ updateGroupBuilder.setGroupId(new GroupId(updatedGroupDataObject.getId()));
groupInputBuilder.setNode(updatedGroupDataObject.getNode());
- updateGroupBuilder = new UpdatedGroupBuilder(updatedGroupDataObject);
- updateGroupBuilder.setGroupId(new GroupId(updatedGroupDataObject.getId()));
groupInputBuilder.setUpdatedGroup(updateGroupBuilder.build());
OriginalGroupBuilder originalGroupBuilder = new OriginalGroupBuilder(originalGroupDataObject);
- groupInputBuilder.setOriginalGroup(originalGroupBuilder.build());
+ groupInputBuilder.setOriginalGroup(originalGroupBuilder.build());
groupService.updateGroup(groupInputBuilder.build());
return;
}
}
AddGroupInputBuilder groupData = new AddGroupInputBuilder();
- groupData.setBuckets(groupAddDataObject.getBuckets());
- groupData.setContainerName(groupAddDataObject.getContainerName());
- groupData.setGroupId(new GroupId(groupAddDataObject.getId()));
- groupData.setGroupType(groupAddDataObject.getGroupType());
+ groupData.fieldsFrom(groupAddDataObject);
+ groupData.setGroupId(new GroupId(groupAddDataObject.getId()));
groupData.setNode(groupAddDataObject.getNode());
groupService.addGroup(groupData.build());
return;
}
RemoveGroupInputBuilder groupData = new RemoveGroupInputBuilder();
- groupData.setBuckets(groupRemoveDataObject.getBuckets());
- groupData.setContainerName(groupRemoveDataObject.getContainerName());
- groupData.setGroupId(new GroupId(groupRemoveDataObject.getId()));
- groupData.setGroupType(groupRemoveDataObject.getGroupType());
- groupData.setNode(groupRemoveDataObject.getNode());
+ groupData.fieldsFrom(groupRemoveDataObject);
+ groupData.setGroupId(new GroupId(groupRemoveDataObject.getId()));
+ groupData.setNode(groupRemoveDataObject.getNode());
groupService.removeGroup(groupData.build());
return;
}
import org.opendaylight.controller.sal.utils.GlobalConstants;
import org.opendaylight.controller.sal.utils.Status;
import org.opendaylight.controller.sal.utils.StatusCode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.OriginalGroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.UpdatedGroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.config.rev131024.Meters;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.config.rev131024.meters.Meter;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.config.rev131024.meters.MeterKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterListener;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.UpdateMeterInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.OriginalMeterBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.UpdatedMeterBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.BandType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public class MeterConsumerImpl implements IForwardingRulesManager {
+public class MeterConsumerImpl {
protected static final Logger logger = LoggerFactory.getLogger(MeterConsumerImpl.class);
private final MeterEventListener meterEventListener = new MeterEventListener();
private Registration<NotificationListener> meterListener;
private SalMeterService meterService;
private MeterDataCommitHandler commitHandler;
- private ConcurrentMap<MeterKey, Meter> originalSwMeterView;
- @SuppressWarnings("unused")
- private ConcurrentMap<MeterKey, Meter> installedSwMeterView;
- @SuppressWarnings("unused")
- private ConcurrentMap<Node, List<Meter>> nodeMeters;
- @SuppressWarnings("unused")
- private ConcurrentMap<MeterKey, Meter> inactiveMeters;
- @SuppressWarnings("unused")
- private IContainer container;
- private IClusterContainerServices clusterMeterContainerService = null;
-
public MeterConsumerImpl() {
InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(Meters.class).toInstance();
meterService = FRMConsumerImpl.getProviderSession().getRpcService(SalMeterService.class);
- clusterMeterContainerService = FRMConsumerImpl.getClusterContainerService();
- container = FRMConsumerImpl.getContainer();
-
- if (!(cacheStartup())) {
- logger.error("Unable to allocate/retrieve meter cache");
- System.out.println("Unable to allocate/retrieve meter cache");
- }
-
+
if (null == meterService) {
logger.error("Consumer SAL Meter Service is down or NULL. FRM may not function as intended");
System.out.println("Consumer SAL Meter Service is down or NULL.");
commitHandler = new MeterDataCommitHandler();
FRMConsumerImpl.getDataProviderService().registerCommitHandler(path, commitHandler);
}
-
- private boolean allocateMeterCaches() {
- if (this.clusterMeterContainerService == null) {
- logger.warn("Meter: Un-initialized clusterMeterContainerService, can't create cache");
- return false;
- }
-
- try {
- clusterMeterContainerService.createCache("frm.originalSwMeterView",
- EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
-
- clusterMeterContainerService.createCache("frm.installedSwMeterView",
- EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
-
- clusterMeterContainerService.createCache("frm.inactiveMeters",
- EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
-
- clusterMeterContainerService.createCache("frm.nodeMeters",
- EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
-
- // TODO for cluster mode
- /*
- * clusterMeterContainerService.createCache(WORK_STATUS_CACHE,
- * EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL,
- * IClusterServices.cacheMode.ASYNC));
- *
- * clusterMeterContainerService.createCache(WORK_ORDER_CACHE,
- * EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL,
- * IClusterServices.cacheMode.ASYNC));
- */
-
- } catch (CacheConfigException cce) {
- logger.error("Meter CacheConfigException");
- return false;
-
- } catch (CacheExistException cce) {
- logger.error(" Meter CacheExistException");
- }
-
- return true;
- }
-
- private void nonClusterMeterObjectCreate() {
- originalSwMeterView = new ConcurrentHashMap<MeterKey, Meter>();
- installedSwMeterView = new ConcurrentHashMap<MeterKey, Meter>();
- nodeMeters = new ConcurrentHashMap<Node, List<Meter>>();
- inactiveMeters = new ConcurrentHashMap<MeterKey, Meter>();
- }
-
- @SuppressWarnings({ "unchecked" })
- private boolean retrieveMeterCaches() {
- ConcurrentMap<?, ?> map;
-
- if (this.clusterMeterContainerService == null) {
- logger.warn("Meter: un-initialized clusterMeterContainerService, can't retrieve cache");
- nonClusterMeterObjectCreate();
- return false;
- }
-
- map = clusterMeterContainerService.getCache("frm.originalSwMeterView");
- if (map != null) {
- originalSwMeterView = (ConcurrentMap<MeterKey, Meter>) map;
- } else {
- logger.error("Retrieval of cache(originalSwMeterView) failed");
- return false;
- }
-
- map = clusterMeterContainerService.getCache("frm.installedSwMeterView");
- if (map != null) {
- installedSwMeterView = (ConcurrentMap<MeterKey, Meter>) map;
- } else {
- logger.error("Retrieval of cache(installedSwMeterView) failed");
- return false;
- }
-
- map = clusterMeterContainerService.getCache("frm.inactiveMeters");
- if (map != null) {
- inactiveMeters = (ConcurrentMap<MeterKey, Meter>) map;
- } else {
- logger.error("Retrieval of cache(inactiveMeters) failed");
- return false;
- }
-
- map = clusterMeterContainerService.getCache("frm.nodeMeters");
- if (map != null) {
- nodeMeters = (ConcurrentMap<Node, List<Meter>>) map;
- } else {
- logger.error("Retrieval of cache(nodeMeter) failed");
- return false;
- }
-
- return true;
- }
-
- private boolean cacheStartup() {
- if (allocateMeterCaches()) {
- if (retrieveMeterCaches()) {
- return true;
- }
- }
-
- return false;
- }
-
+
/**
* Adds Meter to the southbound plugin and our internal database
*
private Status addMeter(InstanceIdentifier<?> path, Meter meterAddDataObject) {
MeterKey meterKey = meterAddDataObject.getKey();
- if (null != meterKey && validateMeter(meterAddDataObject, FRMUtil.operation.ADD).isSuccess()) {
+ if (null != meterKey && validateMeter(meterAddDataObject).isSuccess()) {
AddMeterInputBuilder meterBuilder = new AddMeterInputBuilder();
- meterBuilder.setContainerName(meterAddDataObject.getContainerName());
- meterBuilder.setFlags(meterAddDataObject.getFlags());
- meterBuilder.setMeterBandHeaders(meterAddDataObject.getMeterBandHeaders());
+ meterBuilder.fieldsFrom(meterAddDataObject);
meterBuilder.setMeterId(new MeterId(meterAddDataObject.getId()));
meterBuilder.setNode(meterAddDataObject.getNode());
meterService.addMeter(meterBuilder.build());
*
* @param dataObject
*/
- private Status updateMeter(InstanceIdentifier<?> path, Meter meterUpdateDataObject) {
- MeterKey meterKey = meterUpdateDataObject.getKey();
+ private Status updateMeter(InstanceIdentifier<?> path,
+ Meter updatedMeter, Meter originalMeter) {
UpdatedMeterBuilder updateMeterBuilder = null;
- if (null != meterKey && validateMeter(meterUpdateDataObject, FRMUtil.operation.UPDATE).isSuccess()) { UpdateMeterInputBuilder updateMeterInputBuilder = new UpdateMeterInputBuilder();
+ if (validateMeter(updatedMeter).isSuccess()) {
+ UpdateMeterInputBuilder updateMeterInputBuilder = new UpdateMeterInputBuilder();
+ updateMeterInputBuilder.setNode(updatedMeter.getNode());
updateMeterBuilder = new UpdatedMeterBuilder();
- updateMeterBuilder.fieldsFrom(meterUpdateDataObject);
- updateMeterBuilder.setMeterId(new MeterId(meterUpdateDataObject.getId()));
-
+ updateMeterBuilder.fieldsFrom(updatedMeter);
+ updateMeterBuilder.setMeterId(new MeterId(updatedMeter.getId()));
updateMeterInputBuilder.setUpdatedMeter(updateMeterBuilder.build());
+ OriginalMeterBuilder originalMeterBuilder = new OriginalMeterBuilder(originalMeter);
+ updateMeterInputBuilder.setOriginalMeter(originalMeterBuilder.build());
meterService.updateMeter(updateMeterInputBuilder.build());
} else {
return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
private Status removeMeter(InstanceIdentifier<?> path, Meter meterRemoveDataObject) {
MeterKey meterKey = meterRemoveDataObject.getKey();
- if (null != meterKey && validateMeter(meterRemoveDataObject, FRMUtil.operation.DELETE).isSuccess()) {
+ if (null != meterKey && validateMeter(meterRemoveDataObject).isSuccess()) {
RemoveMeterInputBuilder meterBuilder = new RemoveMeterInputBuilder();
- meterBuilder.setContainerName(meterRemoveDataObject.getContainerName());
- meterBuilder.setNode(meterRemoveDataObject.getNode());
- meterBuilder.setFlags(meterRemoveDataObject.getFlags());
- meterBuilder.setMeterBandHeaders(meterRemoveDataObject.getMeterBandHeaders());
- meterBuilder.setMeterId(new MeterId(meterRemoveDataObject.getId()));
- meterBuilder.setNode(meterRemoveDataObject.getNode());
+ meterBuilder.fieldsFrom(meterRemoveDataObject);
+ meterBuilder.setNode(meterRemoveDataObject.getNode());
+ meterBuilder.setMeterId(new MeterId(meterRemoveDataObject.getId()));
meterService.removeMeter(meterBuilder.build());
} else {
return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
return new Status(StatusCode.SUCCESS);
}
- public Status validateMeter(Meter meter, FRMUtil.operation operation) {
- String containerName;
+ public Status validateMeter(Meter meter) {
String meterName;
Status returnStatus = null;
if (null != meter) {
- containerName = meter.getContainerName();
-
- if (null == containerName) {
- containerName = GlobalConstants.DEFAULT.toString();
- } else if (!FRMUtil.isNameValid(containerName)) {
- logger.error("Container Name is invalid %s" + containerName);
- returnStatus = new Status(StatusCode.BADREQUEST, "Container Name is invalid");
- return returnStatus;
- }
-
meterName = meter.getMeterName();
if (!FRMUtil.isNameValid(meterName)) {
logger.error("Meter Name is invalid %s" + meterName);
}
for (int i = 0; i < meter.getMeterBandHeaders().getMeterBandHeader().size(); i++) {
- if (!meter.getFlags().isMeterBurst()) {
+ if (null != meter.getFlags() && !meter.getFlags().isMeterBurst()) {
if (0 < meter.getMeterBandHeaders().getMeterBandHeader().get(i).getBurstSize()) {
logger.error("Burst size should only be associated when Burst FLAG is set");
returnStatus = new Status(StatusCode.BADREQUEST,
if (null != returnStatus && !returnStatus.isSuccess()) {
return returnStatus;
- } else {
+ } else if (null != meter.getMeterBandHeaders()) {
BandType setBandType = null;
DscpRemark dscpRemark = null;
for (int i = 0; i < meter.getMeterBandHeaders().getMeterBandHeader().size(); i++) {
return new Status(StatusCode.SUCCESS);
}
+ private RpcResult<Void> commitToPlugin(InternalTransaction transaction) {
+ DataModification<InstanceIdentifier<?>, DataObject> modification = transaction.modification;
+ //get created entries
+ Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries =
+ modification.getCreatedConfigurationData().entrySet();
+
+ //get updated entries
+ Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updatedEntries =
+ new HashSet<Entry<InstanceIdentifier<? extends DataObject>, DataObject>>();
+
+ updatedEntries.addAll(modification.getUpdatedConfigurationData().entrySet());
+ updatedEntries.removeAll(createdEntries);
+
+ //get removed entries
+ Set<InstanceIdentifier<? extends DataObject>> removeEntriesInstanceIdentifiers =
+ modification.getRemovedConfigurationData();
+
+ for (Entry<InstanceIdentifier<? extends DataObject >, DataObject> entry : createdEntries) {
+ if(entry.getValue() instanceof Meter) {
+ addMeter(entry.getKey(), (Meter)entry.getValue());
+ }
+ }
+
+ for (Entry<InstanceIdentifier<?>, DataObject> entry : updatedEntries) {
+ if(entry.getValue() instanceof Meter) {
+ Meter originalMeter = (Meter) modification.getOriginalConfigurationData().get(entry.getKey());
+ Meter updatedMeter = (Meter) entry.getValue();
+ updateMeter(entry.getKey(), originalMeter, updatedMeter);
+ }
+ }
+
+ for (InstanceIdentifier<?> instanceId : removeEntriesInstanceIdentifiers ) {
+ DataObject removeValue = modification.getOriginalConfigurationData().get(instanceId);
+ if(removeValue instanceof Meter) {
+ removeMeter(instanceId, (Meter)removeValue);
+ }
+ }
+
+ return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
+ }
+
final class InternalTransaction implements DataCommitTransaction<InstanceIdentifier<?>, DataObject> {
private final DataModification<InstanceIdentifier<?>, DataObject> modification;
this.modification = modification;
}
- Map<InstanceIdentifier<?>, Meter> additions = new HashMap<>();
- Map<InstanceIdentifier<?>, Meter> updates = new HashMap<>();
- Set<InstanceIdentifier<?>> removals = new HashSet<>();
-
/**
* We create a plan which flows will be added, which will be updated and
* which will be removed based on our internal state.
*
*/
- void prepareUpdate() {
-
- Set<Entry<InstanceIdentifier<?>, DataObject>> addMeter = modification.getCreatedConfigurationData().entrySet();
- for (Entry<InstanceIdentifier<?>, DataObject> entry : addMeter) {
- if (entry.getValue() instanceof Meter) {
- Meter meter = (Meter) entry.getValue();
- additions.put(entry.getKey(), meter);
- }
-
- }
+ void prepareUpdate() {
- Set<Entry<InstanceIdentifier<?>, DataObject>> updateMeter = modification.getUpdatedConfigurationData().entrySet();
- for (Entry<InstanceIdentifier<?>, DataObject> entry : updateMeter) {
- if (entry.getValue() instanceof Meter) {
- Meter meter = (Meter) entry.getValue();
- ///will be fixed once getUpdatedConfigurationData returns only updated data not created data with it.
- if (!additions.containsKey(entry.getKey())) {
- updates.put(entry.getKey(), meter);
- }
- }
- }
-
- removals = modification.getRemovedConfigurationData();
}
/**
@Override
public RpcResult<Void> finish() throws IllegalStateException {
- RpcResult<Void> rpcStatus = commitToPlugin(this);
- // We return true if internal transaction is successful.
- // return Rpcs.getRpcResult(true, null, Collections.emptySet());
+ RpcResult<Void> rpcStatus = commitToPlugin(this);
return rpcStatus;
}
*
*/
@Override
- public RpcResult<Void> rollback() throws IllegalStateException {
- // NOOP - we did not modified any internal state during
- // requestCommit phase
- // return Rpcs.getRpcResult(true, null, Collections.emptySet());
+ public RpcResult<Void> rollback() throws IllegalStateException {
return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
}
}
- private RpcResult<Void> commitToPlugin(InternalTransaction transaction) {
- for (Entry<InstanceIdentifier<?>, Meter> entry : transaction.additions.entrySet()) {
-
- if (!addMeter(entry.getKey(), entry.getValue()).isSuccess()) {
- return Rpcs.getRpcResult(false, null, Collections.<RpcError>emptySet());
- }
- }
- for (Entry<InstanceIdentifier<?>, Meter> entry : transaction.updates.entrySet()) {
-
- if (!updateMeter(entry.getKey(), entry.getValue()).isSuccess()) {
- return Rpcs.getRpcResult(false, null, Collections.<RpcError>emptySet());
- }
- }
-
- for (InstanceIdentifier<?> meterId : transaction.removals) {
- DataObject removeValue = transaction.getModification().getOriginalConfigurationData().get(meterId);
-
- if(removeValue instanceof Meter) {
- if(!removeMeter(meterId, (Meter)removeValue).isSuccess()) {
- return Rpcs.getRpcResult(false, null, Collections.<RpcError>emptySet());
- }
- }
- }
-
- return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
- }
-
private final class MeterDataCommitHandler implements DataCommitHandler<InstanceIdentifier<?>, DataObject> {
@Override
public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<InstanceIdentifier<?>, DataObject> requestCommit(
// TODO Auto-generated method stub
}
- }
-
- @Override
- public List<DataObject> get() {
-
- List<DataObject> orderedList = new ArrayList<DataObject>();
- Collection<Meter> meterList = originalSwMeterView.values();
- for (Iterator<Meter> iterator = meterList.iterator(); iterator.hasNext();) {
- orderedList.add(iterator.next());
- }
- return orderedList;
- }
-
- @Override
- public DataObject getWithName(String name, Node n) {
- if (this instanceof MeterConsumerImpl) {
- Collection<Meter> meterList = originalSwMeterView.values();
- for (Iterator<Meter> iterator = meterList.iterator(); iterator.hasNext();) {
- Meter meter = iterator.next();
- if (meter.getNode().equals(n) && meter.getMeterName().equals(name)) {
-
- return meter;
- }
- }
- }
-
- return null;
- }
+ }
}
</scm>
<modules>
- <!-- Common APIs & Implementation -->
+ <!-- Common APIs & Implementation -->
<module>sal-common</module>
<module>sal-common-api</module>
<module>sal-common-impl</module>
<module>sal-connector-api</module>
<module>sal-rest-connector</module>
<module>sal-netconf-connector</module>
-
+
+ <module>zeromq-routingtable/implementation</module>
+ <module>sal-remoterpc-connector/implementation</module>
<!-- Clustered Data Store -->
<module>clustered-data-store/implementation</module>
<module>inventory-manager</module>
<module>statistics-manager</module>
<module>forwardingrules-manager</module>
-
+
<!-- Compability Packages -->
<module>compatibility</module>
- <module>zeromq-routingtable/implementation</module>
- <module>sal-zeromq-connector</module>
</modules>
<profiles>
<profile>
- <id>integrationtests</id>
- <activation>
- <activeByDefault>false</activeByDefault>
- </activation>
+ <id>integrationtests</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ </activation>
<modules>
<module>sal-binding-it</module>
- <module>zeromq-routingtable/integrationtest</module>
<module>clustered-data-store/integrationtest</module>
- <module>test</module>
+ <!--module>zeromq-routingtable/integrationtest</module -->
+ <!--module>sal-remoterpc-connector/integrationtest</module -->
+ <!--module>test/sal-rest-connector-it</modulei -->
</modules>
</profile>
<profile>
- <id>IDE</id>
- <activation>
- <property>
- <name>m2e.version</name>
- </property>
- </activation>
- <build>
- <!-- Put the IDE's build output in a folder other than target, so that IDE builds don't interact with Maven builds -->
- <directory>target-ide</directory>
- </build>
+ <id>IDE</id>
+ <activation>
+ <property>
+ <name>m2e.version</name>
+ </property>
+ </activation>
+ <build>
+ <!-- Put the IDE's build output in a folder other than target,
+ so that IDE builds don't interact with Maven builds -->
+ <directory>target-ide</directory>
+ </build>
</profile>
</profiles>
<guava.version>14.0.1</guava.version>
<osgi.core.version>5.0.0</osgi.core.version>
<junit.version>4.8.1</junit.version>
+ <powermock.version>1.5.1</powermock.version>
+ <mockito.version>1.9.5</mockito.version>
<xtend.version>2.4.3</xtend.version>
<maven.clean.plugin.version>2.5</maven.clean.plugin.version>
<jacoco.version>0.5.3.201107060350</jacoco.version>
+ <sal.version>0.5.1-SNAPSHOT</sal.version> <!-- AD Sal version -->
+
<!-- Sonar properties using jacoco to retrieve integration test results -->
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
<pluginRepositories>
<!-- OpenDayLight Repo Mirror -->
<pluginRepository>
- <id>opendaylight-mirror</id>
- <name>opendaylight-mirror</name>
- <url>${nexusproxy}/groups/public/</url>
- <snapshots>
- <enabled>false</enabled>
- </snapshots>
- <releases>
- <enabled>true</enabled>
- <updatePolicy>never</updatePolicy>
- </releases>
+ <id>opendaylight-mirror</id>
+ <name>opendaylight-mirror</name>
+ <url>${nexusproxy}/groups/public/</url>
+ <snapshots>
+ <enabled>false</enabled>
+ </snapshots>
+ <releases>
+ <enabled>true</enabled>
+ <updatePolicy>never</updatePolicy>
+ </releases>
</pluginRepository>
<!-- OpenDayLight Snapshot artifact -->
<pluginRepository>
- <id>opendaylight-snapshot</id>
- <name>opendaylight-snapshot</name>
- <url> ${nexusproxy}/repositories/opendaylight.snapshot/</url>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- <releases>
- <enabled>false</enabled>
- </releases>
+ <id>opendaylight-snapshot</id>
+ <name>opendaylight-snapshot</name>
+ <url> ${nexusproxy}/repositories/opendaylight.snapshot/</url>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ <releases>
+ <enabled>false</enabled>
+ </releases>
</pluginRepository>
</pluginRepositories>
<repositories>
<!-- OpenDayLight Repo Mirror -->
<repository>
- <id>opendaylight-mirror</id>
- <name>opendaylight-mirror</name>
- <url>${nexusproxy}/groups/public/</url>
- <snapshots>
- <enabled>false</enabled>
- </snapshots>
- <releases>
- <enabled>true</enabled>
- <updatePolicy>never</updatePolicy>
- </releases>
+ <id>opendaylight-mirror</id>
+ <name>opendaylight-mirror</name>
+ <url>${nexusproxy}/groups/public/</url>
+ <snapshots>
+ <enabled>false</enabled>
+ </snapshots>
+ <releases>
+ <enabled>true</enabled>
+ <updatePolicy>never</updatePolicy>
+ </releases>
</repository>
<!-- OpenDayLight Snapshot artifact -->
<repository>
- <id>opendaylight-snapshot</id>
- <name>opendaylight-snapshot</name>
- <url> ${nexusproxy}/repositories/opendaylight.snapshot/</url>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- <releases>
- <enabled>false</enabled>
- </releases>
+ <id>opendaylight-snapshot</id>
+ <name>opendaylight-snapshot</name>
+ <url> ${nexusproxy}/repositories/opendaylight.snapshot/</url>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ <releases>
+ <enabled>false</enabled>
+ </releases>
</repository>
</repositories>
<artifactId>yang-data-api</artifactId>
<version>${yang.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-impl</artifactId>
+ <version>${yang.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-model-api</artifactId>
<artifactId>sal-connector-api</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal</artifactId>
+ <version>${sal.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
<!-- Supporting Libraries -->
<dependency>
<artifactId>org.eclipse.xtend.lib</artifactId>
<version>${xtend.version}</version>
</dependency>
-
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>${osgi.core.version}</version>
+ </dependency>
<!-- Testing Dependencies -->
<dependency>
<groupId>junit</groupId>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
- <version>1.9.5</version>
+ <version>${mockito.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.powermock</groupId>
+ <artifactId>powermock-module-junit4</artifactId>
+ <version>${powermock.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.powermock</groupId>
+ <artifactId>powermock-api-mockito</artifactId>
+ <version>${powermock.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.powermock</groupId>
+ <artifactId>powermock-core</artifactId>
+ <version>${powermock.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<artifactId>maven-bundle-plugin</artifactId>
<version>${bundle.plugin.version}</version>
<extensions>true</extensions>
- <!--executions>
- <execution>
- <id>bundle-manifest</id>
- <phase>process-classes</phase>
- <goals>
- <goal>manifest</goal>
- </goals>
- </execution>
- </executions-->
+ <!--executions> <execution> <id>bundle-manifest</id>
+ <phase>process-classes</phase> <goals> <goal>manifest</goal> </goals> </execution>
+ </executions -->
<configuration>
<instructions>
<Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
</plugin>
- <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
+ <!--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>
</goals>
</pluginExecutionFilter>
<action>
- <ignore/>
+ <ignore />
</action>
</pluginExecution>
<pluginExecution>
</goals>
</pluginExecutionFilter>
<action>
- <ignore/>
+ <ignore />
</action>
</pluginExecution>
<pluginExecution>
</goals>
</pluginExecutionFilter>
<action>
- <ignore/>
+ <ignore />
</action>
</pluginExecution>
</pluginExecutions>
package org.opendaylight.controller.config.yang.md.sal.binding.statistics;\r
\r
+import org.opendaylight.controller.config.yang.md.sal.binding.impl.Data;\r
import org.opendaylight.controller.config.yang.md.sal.binding.impl.DataBrokerImplRuntimeMXBean;\r
import org.opendaylight.controller.config.yang.md.sal.binding.impl.Transactions;\r
import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl;\r
\r
public class DataBrokerRuntimeMXBeanImpl extends DataBrokerImpl implements DataBrokerImplRuntimeMXBean {\r
\r
- private Transactions transactions = new Transactions();\r
+ private final Transactions transactions = new Transactions();\r
+ private final Data data = new Data();\r
\r
- @Override\r
public Transactions getTransactions() {\r
transactions.setCreated(getCreatedTransactionsCount().get());\r
transactions.setSubmitted(getSubmittedTransactionsCount().get());\r
transactions.setFailed(getFailedTransactionsCount().get());\r
return transactions;\r
}\r
+\r
+ @Override\r
+ public Data getData() {\r
+ transactions.setCreated(getCreatedTransactionsCount().get());\r
+ transactions.setSubmitted(getSubmittedTransactionsCount().get());\r
+ transactions.setSuccessful(getFinishedTransactionsCount().get());\r
+ transactions.setFailed(getFailedTransactionsCount().get());\r
+ data.setTransactions(transactions);\r
+ return data;\r
+ }\r
}\r
import org.opendaylight.yangtools.concepts.Identifiable;
import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.opendaylight.yangtools.yang.binding.Identifier;
public interface CodecRegistry {
InstanceIdentifierCodec getInstanceIdentifierCodec();
+
+ IdentitityCodec<?> getIdentityCodec();
<T extends DataContainer> DataContainerCodec<T> getCodecForDataObject(Class<T> object);
<T extends Identifier<?>> IdentifierCodec<T> getCodecForIdentifier(Class<T> object);
<T extends Augmentation<?>> AugmentationCodec<T> getCodecForAugmentation(Class<T> object);
+
+ <T extends BaseIdentity> IdentitityCodec<T> getCodecForIdentity(Class<T> codec);
Class<?> getClassForPath(List<QName> names);
--- /dev/null
+package org.opendaylight.controller.sal.binding.dom.serializer.api;
+
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.BindingCodec;
+import org.opendaylight.yangtools.yang.common.QName;
+
+public interface IdentitityCodec<T extends BaseIdentity> extends BindingCodec<QName, Class<T>>{
+
+ @Override
+ public QName serialize(Class<T> input);
+
+ @Override
+ public Class<T> deserialize(QName input);
+}
import java.lang.reflect.Field;
import java.util.Map;
+import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentitityCodec;
import org.opendaylight.controller.sal.binding.dom.serializer.api.InstanceIdentifierCodec;
import org.opendaylight.yangtools.yang.binding.BindingCodec;
import org.opendaylight.yangtools.yang.common.QName;
private static final Logger LOG = LoggerFactory.getLogger(CodecMapping.class);
public static final String INSTANCE_IDENTIFIER_CODEC = "INSTANCE_IDENTIFIER_CODEC";
+ public static final String IDENTITYREF_CODEC = "IDENTITYREF_CODEC";
+
public static final String CLASS_TO_CASE_MAP = "CLASS_TO_CASE";
public static final String COMPOSITE_TO_CASE = "COMPOSITE_TO_CASE";
public static final String AUGMENTATION_CODEC = "AUGMENTATION_CODEC";
instanceIdField.set(null, codec);
}
} catch (NoSuchFieldException e) {
- LOG.debug("Instance identifier codec is not needed for {}",obj.getName(),e);
+ LOG.trace("Instance identifier codec is not needed for {}",obj.getName(),e);
+ } catch (SecurityException | IllegalAccessException e) {
+ LOG.error("Instance identifier could not be set for {}",obj.getName(),e);
+ }
+ }
+
+
+ public static void setIdentityRefCodec(Class<?> obj,IdentitityCodec<?> codec) {
+ Field instanceIdField;
+ try {
+ instanceIdField = obj.getField(IDENTITYREF_CODEC);
+ if(obj != null) {
+ instanceIdField.set(null, codec);
+ }
+ } catch (NoSuchFieldException e) {
+ LOG.trace("Instance identifier codec is not needed for {}",obj.getName(),e);
} catch (SecurityException | IllegalAccessException e) {
LOG.error("Instance identifier could not be set for {}",obj.getName(),e);
}
LOG.error("Augmentation codec could not be set for {}",dataCodec.getName(),e);
}
}
+
+
+ public static BindingCodec<?,?> getAugmentationCodec(Class<? extends BindingCodec<?,?>> dataCodec) {
+ Field instanceIdField;
+ try {
+ instanceIdField = dataCodec.getField(AUGMENTATION_CODEC);
+ return (BindingCodec<?,?>) instanceIdField.get(null);
+ } catch (NoSuchFieldException e) {
+ LOG.debug("BUG: Augmentation codec is not needed for {}",dataCodec.getName(),e);
+ } catch (SecurityException | IllegalAccessException e) {
+ LOG.error("Augmentation codec could not be set for {}",dataCodec.getName(),e);
+ }
+ return null;
+ }
}
- static def Node<?> toNode(Map map) {
+ static def Node<?> toNode(Map<?,?> map) {
+ if(map instanceof Node<?>) {
+ return map as Node<?>;
+ }
val nodeMap = map as Map<QName,Object>;
Preconditions.checkArgument(map.size == 1);
val elem = nodeMap.entrySet.iterator.next;
toNodeImpl(qname, value);
}
+
static def dispatch Node<?> toNodeImpl(QName name, List<?> objects) {
val values = new ArrayList<Node<?>>(objects.size);
for (obj : objects) {
- values.add(toNode(obj as Map));
+ if(obj instanceof Node<?>) {
+ values.add(obj as Node<?>);
+ } else if(obj instanceof Map<?,?>) {
+ values.add(toNode(obj as Map<?,?>));
+ }
}
return new CompositeNodeTOImpl(name, null, values);
}
package org.opendaylight.controller.sal.binding.dom.serializer.impl;
+import java.awt.CompositeContext;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
+import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.Set;
import java.util.WeakHashMap;
+import org.apache.commons.lang3.text.translate.AggregateTranslator;
import org.opendaylight.controller.sal.binding.dom.serializer.api.AugmentationCodec;
import org.opendaylight.controller.sal.binding.dom.serializer.api.ChoiceCaseCodec;
import org.opendaylight.controller.sal.binding.dom.serializer.api.ChoiceCodec;
import org.opendaylight.controller.sal.binding.dom.serializer.api.DataContainerCodec;
import org.opendaylight.controller.sal.binding.dom.serializer.api.DomCodec;
import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentifierCodec;
+import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentitityCodec;
import org.opendaylight.controller.sal.binding.dom.serializer.api.InstanceIdentifierCodec;
import org.opendaylight.controller.sal.binding.dom.serializer.api.ValueWithQName;
import org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils;
import org.opendaylight.yangtools.concepts.Identifiable;
import org.opendaylight.yangtools.yang.binding.Augmentable;
import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
import org.opendaylight.yangtools.yang.binding.BindingCodec;
import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleContext;
import org.opendaylight.yangtools.sal.binding.model.api.ConcreteType;
import org.opendaylight.yangtools.sal.binding.model.api.Type;
+import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTOBuilder;
import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
+import com.google.common.collect.FluentIterable;
import com.google.common.util.concurrent.CycleDetectingLockFactory.WithExplicitOrdering;
public class LazyGeneratedCodecRegistry implements //
private final static LateMixinCodec NOT_READY_CODEC = new LateMixinCodec();
private final InstanceIdentifierCodec instanceIdentifierCodec = new InstanceIdentifierCodecImpl(this);
+ private final IdentityCompositeCodec identityRefCodec = new IdentityCompositeCodec();
private TransformerGenerator generator;
// Concrete class to codecs
- private Map<Class<?>, DataContainerCodec<?>> containerCodecs = new WeakHashMap<>();
- private Map<Class<?>, IdentifierCodec<?>> identifierCodecs = new WeakHashMap<>();
- private Map<Class<?>, ChoiceCodecImpl<?>> choiceCodecs = new WeakHashMap<>();
- private Map<Class<?>, ChoiceCaseCodecImpl<?>> caseCodecs = new WeakHashMap<>();
- private Map<Class<?>, AugmentableCompositeCodec> augmentableCodecs = new WeakHashMap<>();
-
+ private static final Map<Class<?>, DataContainerCodec<?>> containerCodecs = new WeakHashMap<>();
+ private static final Map<Class<?>, IdentifierCodec<?>> identifierCodecs = new WeakHashMap<>();
+ private static final Map<Class<?>, ChoiceCodecImpl<?>> choiceCodecs = new WeakHashMap<>();
+ private static final Map<Class<?>, ChoiceCaseCodecImpl<?>> caseCodecs = new WeakHashMap<>();
+ private static final Map<Class<?>, AugmentableCompositeCodec> augmentableCodecs = new WeakHashMap<>();
+ private static final Map<Class<?>, AugmentationCodec<?>> augmentationCodecs = new WeakHashMap<>();
+ private static final Map<Class<?>, QName> identityQNames = new WeakHashMap<>();
+ private static final Map<QName, Type> qnamesToIdentityMap = new ConcurrentHashMap<>();
/** Binding type to encountered classes mapping **/
@SuppressWarnings("rawtypes")
- Map<Type, WeakReference<Class>> typeToClass = new ConcurrentHashMap<>();
+ private static final Map<Type, WeakReference<Class>> typeToClass = new ConcurrentHashMap<>();
@SuppressWarnings("rawtypes")
- private ConcurrentMap<Type, ChoiceCaseCodecImpl> typeToCaseCodecs = new ConcurrentHashMap<>();
+ private static final ConcurrentMap<Type, ChoiceCaseCodecImpl> typeToCaseCodecs = new ConcurrentHashMap<>();
private CaseClassMapFacade classToCaseRawCodec = new CaseClassMapFacade();
- Map<SchemaPath, GeneratedTypeBuilder> pathToType = new ConcurrentHashMap<>();
- Map<List<QName>, Type> pathToInstantiatedType = new ConcurrentHashMap<>();
+ private static final Map<SchemaPath, GeneratedTypeBuilder> pathToType = new ConcurrentHashMap<>();
+ private static final Map<List<QName>, Type> pathToInstantiatedType = new ConcurrentHashMap<>();
+ private static final Map<Type, QName> typeToQname = new ConcurrentHashMap<>();
private SchemaContext currentSchema;
@Override
public <T extends Augmentation<?>> AugmentationCodec<T> getCodecForAugmentation(Class<T> object) {
- // TODO Auto-generated method stub
- return null;
+ AugmentationCodec<T> codec = null;
+ @SuppressWarnings("rawtypes")
+ AugmentationCodec potentialCodec = augmentationCodecs.get(object);
+ if (potentialCodec != null) {
+ codec = potentialCodec;
+ } else
+ try {
+ Class<? extends BindingCodec<Map<QName, Object>, Object>> augmentRawCodec = generator
+ .augmentationTransformerFor(object);
+ BindingCodec<Map<QName, Object>, Object> rawCodec = augmentRawCodec.newInstance();
+ codec = new AugmentationCodecWrapper<T>(rawCodec);
+ augmentationCodecs.put(augmentRawCodec, codec);
+ } catch (InstantiationException e) {
+ LOG.error("Can not instantiate raw augmentation codec {}", object.getSimpleName(), e);
+ } catch (IllegalAccessException e) {
+ LOG.debug("BUG: Constructor for {} is not accessible.", object.getSimpleName(), e);
+ }
+ Class<? extends Augmentable<?>> objectSupertype = getAugmentableArgumentFrom(object);
+ if (objectSupertype != null) {
+ getAugmentableCodec(objectSupertype).addAugmentationCodec(object, codec);
+ } else {
+ LOG.warn("Could not find augmentation target for augmentation {}", object);
+ }
+ return codec;
+ }
+
+ private static Class<? extends Augmentable<?>> getAugmentableArgumentFrom(
+ final Class<? extends Augmentation<?>> augmentation) {
+ try {
+ Class<? extends Augmentable<?>> ret = ClassLoaderUtils.withClassLoader(augmentation.getClassLoader(),
+ new Callable<Class<? extends Augmentable<?>>>() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public Class<? extends Augmentable<?>> call() throws Exception {
+ for (java.lang.reflect.Type supertype : augmentation.getGenericInterfaces()) {
+ if (supertype instanceof ParameterizedType
+ && Augmentation.class.equals(((ParameterizedType) supertype).getRawType())) {
+ ParameterizedType augmentationGeneric = (ParameterizedType) supertype;
+ return (Class<? extends Augmentable<?>>) augmentationGeneric
+ .getActualTypeArguments()[0];
+ }
+ }
+ return null;
+ }
+ });
+ return ret;
+ } catch (Exception e) {
+ LOG.error("Could not find augmentable for {}", augmentation, e);
+ return null;
+ }
}
@Override
return newWrapper;
}
- @Override
@SuppressWarnings("rawtypes")
public void bindingClassEncountered(Class cls) {
return newWrapper;
}
+ @Override
+ public IdentitityCodec<?> getIdentityCodec() {
+ return identityRefCodec;
+ }
+
+ @Override
+ public <T extends BaseIdentity> IdentitityCodec<T> getCodecForIdentity(Class<T> codec) {
+ bindingClassEncountered(codec);
+ return identityRefCodec;
+ }
+
@Override
public void onCodecCreated(Class<?> cls) {
CodecMapping.setIdentifierCodec(cls, instanceIdentifierCodec);
+ CodecMapping.setIdentityRefCodec(cls, identityRefCodec);
}
@Override
public void onModuleContextAdded(SchemaContext schemaContext, Module module, ModuleContext context) {
pathToType.putAll(context.getChildNodes());
+ qnamesToIdentityMap.putAll(context.getIdentities());
+ for(Entry<QName, GeneratedTOBuilder> identity : context.getIdentities().entrySet()) {
+ typeToQname.put(new ReferencedTypeImpl(identity.getValue().getPackageName(), identity.getValue().getName()),identity.getKey());
+ }
captureCases(context.getCases(), schemaContext);
}
ReferencedTypeImpl typeref = new ReferencedTypeImpl(caseNode.getValue().getPackageName(), caseNode
.getValue().getName());
- LOG.info("Case path: {} Type : {}", caseNode.getKey(), caseNode.getValue().getFullyQualifiedName());
pathToType.put(caseNode.getKey(), caseNode.getValue());
ChoiceCaseNode node = (ChoiceCaseNode) SchemaContextUtil.findDataSchemaNode(module, caseNode.getKey());
if (path != null && (type = pathToType.get(path)) != null) {
ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
ChoiceCaseCodecImpl partialCodec = typeToCaseCodecs.get(typeref);
- if(partialCodec.getSchema() == null ) {
+ if (partialCodec.getSchema() == null) {
partialCodec.setSchema(caseNode);
}
-
+
Class<?> caseClass = ClassLoaderUtils.tryToLoadClassWithTCCL(type.getFullyQualifiedName());
if (caseClass != null) {
getCaseCodecFor(caseClass);
}
- private AugmentableCompositeCodec getAugmentableCodec(Class<?> dataClass) {
+ public AugmentableCompositeCodec getAugmentableCodec(Class<?> dataClass) {
AugmentableCompositeCodec ret = augmentableCodecs.get(dataClass);
if (ret != null) {
return ret;
private final Class augmentableType;
- Map<Class, BindingCodec> rawAugmentationCodecs = new WeakHashMap<>();
+ Map<Class, AugmentationCodec<?>> localAugmentationCodecs = new WeakHashMap<>();
public AugmentableCompositeCodec(Class type) {
checkArgument(Augmentable.class.isAssignableFrom(type));
private List serializeImpl(Map<Class, Augmentation> input) {
List ret = new ArrayList<>();
for (Entry<Class, Augmentation> entry : input.entrySet()) {
- BindingCodec codec = getRawCodecForAugmentation(entry.getKey());
- List output = (List) codec.serialize(new ValueWithQName(null, entry.getValue()));
- ret.addAll(output);
+ AugmentationCodec codec = getCodecForAugmentation(entry.getKey());
+ CompositeNode node = codec.serialize(new ValueWithQName(null, entry.getValue()));
+ ret.addAll(node.getChildren());
}
return ret;
}
- private BindingCodec getRawCodecForAugmentation(Class key) {
- BindingCodec ret = rawAugmentationCodecs.get(key);
- if (ret != null) {
- return ret;
- }
- try {
- Class<? extends BindingCodec> retClass = generator.augmentationTransformerFor(key);
- ret = retClass.newInstance();
- rawAugmentationCodecs.put(key, ret);
- return ret;
- } catch (InstantiationException e) {
- LOG.error("Can not instantiate raw augmentation codec {}", key.getSimpleName(), e);
- } catch (IllegalAccessException e) {
- LOG.debug("BUG: Constructor for {} is not accessible.", key.getSimpleName(), e);
- }
- return null;
+ public synchronized <T extends Augmentation<?>> void addAugmentationCodec(Class<T> augmentationClass,
+ AugmentationCodec<T> value) {
+ localAugmentationCodecs.put(augmentationClass, value);
}
@Override
public Map<Class, Augmentation> deserialize(Object input) {
Map<Class, Augmentation> ret = new HashMap<>();
if (input instanceof CompositeNode) {
- for (Entry<Class, BindingCodec> codec : rawAugmentationCodecs.entrySet()) {
- Augmentation value = (Augmentation) codec.getValue().deserialize(input);
- if (value != null) {
- ret.put(codec.getKey(), value);
+ List<Entry<Class, AugmentationCodec<?>>> codecs = new ArrayList<>(localAugmentationCodecs.entrySet());
+ for (Entry<Class, AugmentationCodec<?>> codec : codecs) {
+ ValueWithQName<?> value = codec.getValue().deserialize((CompositeNode) input);
+ if (value != null && value.getValue() != null) {
+ ret.put(codec.getKey(), (Augmentation) value.getValue());
}
}
}
return ret;
}
- public Map<Class, BindingCodec> getRawAugmentationCodecs() {
- return rawAugmentationCodecs;
- }
-
- public void setRawAugmentationCodecs(Map<Class, BindingCodec> rawAugmentationCodecs) {
- this.rawAugmentationCodecs = rawAugmentationCodecs;
- }
-
public Class getAugmentableType() {
return augmentableType;
}
return getDelegate().serialize(input);
}
}
+
+ private static class AugmentationCodecWrapper<T extends Augmentation<?>> implements AugmentationCodec<T>,
+ Delegator<BindingCodec> {
+
+ private BindingCodec delegate;
+
+ public AugmentationCodecWrapper(BindingCodec<Map<QName, Object>, Object> rawCodec) {
+ this.delegate = rawCodec;
+ }
+
+ @Override
+ public BindingCodec getDelegate() {
+ return delegate;
+ }
+
+ @Override
+ public CompositeNode serialize(ValueWithQName<T> input) {
+ @SuppressWarnings("unchecked")
+ List<Map<QName, Object>> rawValues = (List<Map<QName, Object>>) getDelegate().serialize(input);
+ List<Node<?>> serialized = new ArrayList<>(rawValues.size());
+ for (Map<QName, Object> val : rawValues) {
+ serialized.add(toNode(val));
+ }
+ return new CompositeNodeTOImpl(input.getQname(), null, serialized);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public ValueWithQName<T> deserialize(Node<?> input) {
+ Object rawCodecValue = getDelegate().deserialize((Map<QName, Object>) input);
+ return new ValueWithQName<T>(input.getNodeType(), (T) rawCodecValue);
+ }
+ }
+
+ private class IdentityCompositeCodec implements IdentitityCodec {
+
+ @Override
+ public Object deserialize(Object input) {
+ checkArgument(input instanceof QName);
+ return deserialize((QName) input);
+ }
+
+ @Override
+ public Class<?> deserialize(QName input) {
+ Type type = qnamesToIdentityMap.get(input);
+ if(type == null) {
+ return null;
+ }
+ ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
+ WeakReference<Class> softref = typeToClass.get(typeref);
+ if(softref == null) {
+ return null;
+ }
+ return softref.get();
+ }
+
+ @Override
+ public QName serialize(Class input) {
+ checkArgument(BaseIdentity.class.isAssignableFrom(input));
+ bindingClassEncountered(input);
+ QName qname = identityQNames.get(input);
+ if(qname != null) {
+ return qname;
+ }
+ ConcreteType typeref = Types.typeForClass(input);
+ qname = typeToQname.get(typeref);
+ if(qname != null) {
+ identityQNames.put(input, qname);
+ }
+ return qname;
+ }
+
+ @Override
+ public Object serialize(Object input) {
+ checkArgument(input instanceof Class);
+ return serialize((Class) input);
+ }
+ }
}
\ No newline at end of file
import java.util.concurrent.Callable
import org.opendaylight.yangtools.yang.binding.Augmentation
import org.opendaylight.controller.sal.binding.impl.util.YangSchemaUtils
+import org.opendaylight.controller.sal.binding.dom.serializer.api.AugmentationCodec
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
+import java.util.ArrayList
+import org.opendaylight.yangtools.yang.data.api.Node
+import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener, AutoCloseable {
override Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> toDataDom(
Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry) {
+
+ try {
val key = toDataDom(entry.key)
- val data = toCompositeNodeImpl(entry.value);
+ var CompositeNode data;
+ if(Augmentation.isAssignableFrom(entry.key.targetType)) {
+ data = toCompositeNodeImpl(key,entry.value);
+ } else {
+ data = toCompositeNodeImpl(entry.value);
+ }
return new SimpleEntry(key, data);
+
+ } catch (Exception e) {
+ LOG.error("Error during serialization for {}.", entry.key,e);
+ throw e;
+ }
}
private def CompositeNode toCompositeNodeImpl(DataObject object) {
val ret = codec.serialize(new ValueWithQName(null, object));
return ret as CompositeNode;
}
+
+
+ private def CompositeNode toCompositeNodeImpl(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier identifier,DataObject object) {
+
+ //val cls = object.implementedInterface;
+ //waitForSchema(cls);
+ val last = identifier.path.last;
+ val codec = registry.getCodecForAugmentation(object.implementedInterface as Class) as AugmentationCodec;
+ val ret = codec.serialize(new ValueWithQName(last.nodeType, object));
+ if(last instanceof NodeIdentifierWithPredicates) {
+ val predicates = last as NodeIdentifierWithPredicates;
+ val newNodes = new ArrayList<Node<?>>(predicates.keyValues.size);
+ for(predicate : predicates.keyValues.entrySet) {
+ newNodes.add(new SimpleNodeTOImpl(predicate.key,null,predicate.value));
+ }
+ newNodes.addAll(ret.children);
+ return new CompositeNodeTOImpl(last.nodeType,null,newNodes);
+ }
+ return ret as CompositeNode;
+ }
private def void waitForSchema(Class<? extends DataContainer> class1) {
if(Augmentation.isAssignableFrom(class1)) {
@Property
var GeneratorListener listener;
+
+ public static val CLASS_TYPE = Types.typeForClass(Class);
public new(ClassPool pool) {
classPool = pool;
val ctCls = createClass(inputType.codecClassName) [
//staticField(Map,"AUGMENTATION_SERIALIZERS");
staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+ staticField(it, IDENTITYREF_CODEC, BindingCodec)
staticQNameField(node.QName);
implementsType(BINDING_CODEC)
method(Object, "toDomStatic", QName, Object) [
staticQNameField(node.QName);
staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
staticField(it, AUGMENTATION_CODEC, BindingCodec)
+ staticField(it, IDENTITYREF_CODEC, BindingCodec)
method(Object, "toDomStatic", QName, Object) [
modifiers = PUBLIC + FINAL + STATIC
body = '''
//staticField(Map,"AUGMENTATION_SERIALIZERS");
staticQNameField(node.QName);
staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+ staticField(it, IDENTITYREF_CODEC, BindingCodec)
staticField(it, AUGMENTATION_CODEC, BindingCodec)
implementsType(BINDING_CODEC)
method(Object, "toDomStatic", QName, Object) [
staticQNameField(node.augmentationQName);
staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
staticField(it, AUGMENTATION_CODEC, BindingCodec)
+ staticField(it, IDENTITYREF_CODEC, BindingCodec)
implementsType(BINDING_CODEC)
method(Object, "toDomStatic", QName, Object) [
modifiers = PUBLIC + FINAL + STATIC
{
//System.out.println("Qname " + $1);
//System.out.println("Value " + $2);
- «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName());
+ «QName.name» _resultName = «QName.name».create(QNAME,QNAME.getLocalName());
java.util.List _childNodes = new java.util.ArrayList();
«type.resolvedName» value = («type.resolvedName») $2;
«FOR child : node.childNodes»
//staticField(Map,"AUGMENTATION_SERIALIZERS");
//staticQNameField(inputType);
staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+ staticField(it, IDENTITYREF_CODEC, BindingCodec)
staticField(it, CLASS_TO_CASE_MAP, Map)
staticField(it, COMPOSITE_TO_CASE, Map)
//staticField(it,QNAME_TO_CASE_MAP,BindingCodec)
if (hasYangBinding) {
implementsType(BINDING_CODEC)
staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+ staticField(it, IDENTITYREF_CODEC, BindingCodec)
implementsType(BindingDeserializer.asCtClass)
}
method(Object, "toDomValue", Object) [
private def dispatch String deserializeValue(Type type, String domParameter) {
if (INSTANCE_IDENTIFIER.equals(type)) {
-
return '''(«InstanceIdentifier.name») «INSTANCE_IDENTIFIER_CODEC».deserialize(«domParameter»)'''
+ } else if (CLASS_TYPE.equals(type)) {
+ return '''(«Class.name») «IDENTITYREF_CODEC».deserialize(«domParameter»)'''
}
-
return '''(«type.resolvedName») «domParameter»'''
}
private def dispatch serializeValue(Type signature, String property) {
if (INSTANCE_IDENTIFIER == signature) {
return '''«INSTANCE_IDENTIFIER_CODEC».serialize(«property»)'''
+ }else if (CLASS_TYPE.equals(signature)) {
+ return '''(«QName.resolvedName») «IDENTITYREF_CODEC».serialize(«property»)'''
}
return '''«property»''';
}
import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.binding.Augmentable;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcError;
public DataObject readOperationalData(InstanceIdentifier<? extends DataObject> path) {
try {
org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
+
+
CompositeNode result = biDataService.readOperationalData(biPath);
+ Class<? extends DataObject> targetType = path.getTargetType();
+
+ if(Augmentation.class.isAssignableFrom(targetType)) {
+ path = mappingService.fromDataDom(biPath);
+ Class<? extends Augmentation<?>> augmentType = (Class<? extends Augmentation<?>>) targetType;
+ DataObject parentTo = mappingService.dataObjectFromDataDom(path, result);
+ if(parentTo instanceof Augmentable<?>) {
+ return (DataObject) ((Augmentable) parentTo).getAugmentation(augmentType);
+ }
+
+ }
return mappingService.dataObjectFromDataDom(path, result);
+
} catch (DeserializationException e) {
throw new IllegalStateException(e);
}
DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
target.putConfigurationData(baKey, baData);
} catch (DeserializationException e) {
- LOG.error("Ommiting from BA transaction: {}. Reason {}.", entry.getKey(), e);
+ LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e);
}
}
for (Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> entry : source
DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
target.putOperationalData(baKey, baData);
} catch (DeserializationException e) {
- LOG.error("Ommiting from BA transaction: {}. Reason {}.", entry.getKey(), e);
+ LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e);
}
}
for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedConfigurationData()) {
InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
target.removeConfigurationData(baEntry);
} catch (DeserializationException e) {
- LOG.error("Ommiting from BA transaction: {}. Reason {}.", entry, e);
+ LOG.error("Ommiting from BA transaction: {}.", entry, e);
}
}
for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedOperationalData()) {
InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
target.removeOperationalData(baEntry);
} catch (DeserializationException e) {
- LOG.error("Ommiting from BA transaction: {}. Reason{}.", entry, e);
+ LOG.error("Ommiting from BA transaction: {}.", entry, e);
}
}
return target;
augment "/config:modules/config:module/config:state" {
case binding-data-broker {
when "/config:modules/config:module/config:type = 'binding-data-broker'";
- uses common:data-state;
+ container data {
+ uses common:data-state;
+ }
}
}
augment "/config:modules/config:module/config:state" {
</build>
<dependencies>
- <dependency>
+ <dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-broker-impl</artifactId>
<version>1.0-SNAPSHOT</version>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <scope>test</scope>
+ <version>1.7.2</version>
+ </dependency>
</dependencies>
</project>
--- /dev/null
+package org.opendaylight.controller.sal.binding.test.bugfix;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SupportedActions;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SupportedActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.supported.actions.ActionType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.supported.actions.ActionTypeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.SupportType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesKey;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+import static org.junit.Assert.*;
+
+public class PutAugmentationTest extends AbstractDataServiceTest implements DataChangeListener {
+
+ private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
+ private static final String NODE_ID = "openflow:1";
+
+ private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID));
+
+ private static final Map<QName, Object> NODE_KEY_BI = Collections.<QName, Object> singletonMap(NODE_ID_QNAME,
+ NODE_ID);
+
+ private static final InstanceIdentifier<Nodes> NODES_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) //
+ .toInstance();
+
+
+ private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier//
+ .builder(NODES_INSTANCE_ID_BA) //
+ .child(Node.class, NODE_KEY).toInstance();
+
+
+ private static final InstanceIdentifier<SupportedActions> SUPPORTED_ACTIONS_INSTANCE_ID_BA = InstanceIdentifier//
+ .builder(NODES_INSTANCE_ID_BA) //
+ .child(Node.class, NODE_KEY) //
+ .augmentation(FlowCapableNode.class) //
+ .child(SupportedActions.class)
+ .toInstance();
+
+
+ private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODE_INSTANCE_ID_BI = //
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
+ .node(Nodes.QNAME) //
+ .nodeWithKey(Node.QNAME, NODE_KEY_BI) //
+ .toInstance();
+ private static final QName SUPPORTED_ACTIONS_QNAME = QName.create(FlowCapableNode.QNAME, SupportedActions.QNAME.getLocalName());
+
+
+ private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier SUPPORTED_ACTIONS_INSTANCE_ID_BI = //
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
+ .node(Nodes.QNAME) //
+ .nodeWithKey(Node.QNAME, NODE_KEY_BI) //
+ .node(SUPPORTED_ACTIONS_QNAME) //
+ .toInstance();
+
+ private DataChangeEvent<InstanceIdentifier<?>, DataObject> receivedChangeEvent;
+
+
+
+ /**
+ * Test for Bug 148
+ *
+ * @throws Exception
+ */
+ @Test
+ public void putNodeAndAugmentation() throws Exception {
+
+ baDataService.registerDataChangeListener(NODES_INSTANCE_ID_BA, this);
+
+ NodeBuilder nodeBuilder = new NodeBuilder();
+ nodeBuilder.setId(new NodeId(NODE_ID));
+ nodeBuilder.setKey(NODE_KEY);
+ DataModificationTransaction baseTransaction = baDataService.beginTransaction();
+ baseTransaction.putOperationalData(NODE_INSTANCE_ID_BA, nodeBuilder.build());
+ RpcResult<TransactionStatus> result = baseTransaction.commit().get();
+ assertEquals(TransactionStatus.COMMITED, result.getResult());
+ assertNotNull(receivedChangeEvent);
+ Node node = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
+ assertNotNull(node);
+ assertEquals(NODE_KEY, node.getKey());
+
+ FlowCapableNodeBuilder fnub = new FlowCapableNodeBuilder();
+ fnub.setHardware("Hardware Foo");
+ fnub.setManufacturer("Manufacturer Foo");
+ fnub.setSerialNumber("Serial Foo");
+ fnub.setDescription("Description Foo");
+ fnub.setSoftware("JUnit emulated");
+ FlowCapableNode fnu = fnub.build();
+ InstanceIdentifier<FlowCapableNode> augmentIdentifier = InstanceIdentifier.builder(NODE_INSTANCE_ID_BA).augmentation(FlowCapableNode.class).toInstance();
+ DataModificationTransaction augmentedTransaction = baDataService.beginTransaction();
+ augmentedTransaction.putOperationalData(augmentIdentifier, fnu);
+
+ result = augmentedTransaction.commit().get();
+ assertEquals(TransactionStatus.COMMITED, result.getResult());
+
+
+ Node augmentedNode = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
+ assertNotNull(node);
+ assertEquals(NODE_KEY, augmentedNode.getKey());
+ System.out.println("Before assertion");
+ assertNotNull(augmentedNode.getAugmentation(FlowCapableNode.class));
+ FlowCapableNode readedAugmentation = augmentedNode.getAugmentation(FlowCapableNode.class);
+ assertEquals(fnu.getDescription(), readedAugmentation.getDescription());
+ assertBindingIndependentVersion(NODE_INSTANCE_ID_BI);
+ testNodeRemove();
+ }
+
+
+ private void testNodeRemove() throws Exception {
+ DataModificationTransaction transaction = baDataService.beginTransaction();
+ transaction.removeOperationalData(NODE_INSTANCE_ID_BA);
+ RpcResult<TransactionStatus> result = transaction.commit().get();
+ assertEquals(TransactionStatus.COMMITED, result.getResult());
+
+ Node node = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
+ assertNull(node);
+ }
+
+ private void verifyNodes(Nodes nodes,Node original) {
+ assertNotNull(nodes);
+ assertNotNull(nodes.getNode());
+ assertEquals(1, nodes.getNode().size());
+ Node readedNode = nodes.getNode().get(0);
+ assertEquals(original.getId(), readedNode.getId());
+ assertEquals(original.getKey(), readedNode.getKey());
+
+ FlowCapableNode fnu = original.getAugmentation(FlowCapableNode.class);
+ FlowCapableNode readedAugment = readedNode.getAugmentation(FlowCapableNode.class);
+ assertNotNull(fnu);
+ assertEquals(fnu.getDescription(), readedAugment.getDescription());
+ assertEquals(fnu.getSerialNumber(), readedAugment.getSerialNumber());
+
+ }
+
+ private void assertBindingIndependentVersion(
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier nodeId) {
+ CompositeNode node = biDataService.readOperationalData(nodeId);
+ assertNotNull(node);
+ }
+
+ private Nodes checkForNodes() {
+ return (Nodes) baDataService.readOperationalData(NODES_INSTANCE_ID_BA);
+ }
+
+ @Override
+ public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+ receivedChangeEvent = change;
+ }
+
+}
@Test
public void simpleModifyOperation() throws Exception {
+ assertNull(biDataService.readConfigurationData(FLOW_INSTANCE_ID_BI));
registerCommitHandler();
DataModificationTransaction biTransaction = biDataService.beginTransaction();
biTransaction.putConfigurationData(FLOW_INSTANCE_ID_BI, domflow);
RpcResult<TransactionStatus> biResult = biTransaction.commit().get();
-
+ assertEquals(TransactionStatus.COMMITED, biResult.getResult());
assertNotNull(modificationCapture);
Flow flow = (Flow) modificationCapture.getCreatedConfigurationData().get(FLOW_INSTANCE_ID_BA);
assertNotNull(flow);
*/
package org.opendaylight.controller.sal.common.util;
+import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
return ret;
}
- private static class RpcResultTO<T> implements RpcResult<T> {
+ private static class RpcResultTO<T> implements RpcResult<T>, Serializable {
private final Collection<RpcError> errors;
private final T result;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
-public abstract class AbstractConsumer implements Consumer, BundleActivator {
+public abstract class AbstractConsumer implements Consumer, BundleActivator,ServiceTrackerCustomizer<Broker, Broker> {
+
+
+
+
+ private BundleContext context;
+ private ServiceTracker<Broker, Broker> tracker;
+ private Broker broker;
- Broker broker;
- ServiceReference<Broker> brokerRef;
@Override
public final void start(BundleContext context) throws Exception {
+ this.context = context;
this.startImpl(context);
- brokerRef = context.getServiceReference(Broker.class);
- broker = context.getService(brokerRef);
- broker.registerConsumer(this,context);
+ tracker = new ServiceTracker<>(context, Broker.class, this);
+ tracker.open();
}
public final void stop(BundleContext context) throws Exception {
stopImpl(context);
broker = null;
- if(brokerRef != null) {
- context.ungetService(brokerRef);
- }
+ tracker.close();
}
protected void startImpl(BundleContext context) {
return Collections.emptySet();
}
+
+ @Override
+ public Broker addingService(ServiceReference<Broker> reference) {
+ if(broker == null) {
+ broker = context.getService(reference);
+ broker.registerConsumer(this, context);
+ return broker;
+ }
+
+ return null;
+ }
+
+ @Override
+ public void modifiedService(ServiceReference<Broker> reference, Broker service) {
+ // NOOP
+ }
+
+ @Override
+ public void removedService(ServiceReference<Broker> reference, Broker service) {
+ stopImpl(context);
+ }
}
import java.util.Collection;
import java.util.Collections;
+import javax.naming.Context;
+
import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
-public abstract class AbstractProvider implements BundleActivator, Provider {
+public abstract class AbstractProvider implements BundleActivator, Provider,ServiceTrackerCustomizer<Broker, Broker> {
- private ServiceReference<Broker> brokerRef;
private Broker broker;
-
+ private BundleContext context;
+ private ServiceTracker<Broker, Broker> tracker;
@Override
public Collection<ProviderFunctionality> getProviderFunctionality() {
return Collections.emptySet();
@Override
public final void start(BundleContext context) throws Exception {
- brokerRef = context.getServiceReference(Broker.class);
- broker = context.getService(brokerRef);
-
+ this.context = context;
this.startImpl(context);
-
- broker.registerProvider(this,context);
+ tracker = new ServiceTracker<>(context, Broker.class, this);
+ tracker.open();
}
protected void startImpl(BundleContext context) {
@Override
public final void stop(BundleContext context) throws Exception {
+ broker = null;
+ tracker.close();
+ tracker = null;
stopImpl(context);
}
+ @Override
+ public Broker addingService(ServiceReference<Broker> reference) {
+ if(broker == null) {
+ broker = context.getService(reference);
+ broker.registerProvider(this, context);
+ return broker;
+ }
+
+ return null;
+ }
+
+ @Override
+ public void modifiedService(ServiceReference<Broker> reference, Broker service) {
+ // NOOP
+ }
+
+ @Override
+ public void removedService(ServiceReference<Broker> reference, Broker service) {
+ stopImpl(context);
+ }
+
}
*/
package org.opendaylight.controller.config.yang.md.sal.dom.impl;
+import org.opendaylight.controller.config.yang.md.sal.dom.statistics.DomBrokerRuntimeMXBeanImpl;
import org.opendaylight.controller.sal.core.api.data.DataStore;
import org.opendaylight.controller.sal.dom.broker.BrokerConfigActivator;
import org.opendaylight.controller.sal.dom.broker.BrokerImpl;
import org.osgi.framework.BundleContext;
+
import static com.google.common.base.Preconditions.*;
/**
checkArgument(getDataStore() != null, "Data Store needs to be provided for DomBroker");
}
-
-
@Override
public java.lang.AutoCloseable createInstance() {
- BrokerImpl broker = new BrokerImpl();
- BrokerConfigActivator activator = new BrokerConfigActivator();
- DataStore store = getDataStoreDependency();
- activator.start(broker, store,getBundleContext());
+ final BrokerImpl broker = new BrokerImpl();
+ final BrokerConfigActivator activator = new BrokerConfigActivator();
+ final DataStore store = getDataStoreDependency();
+ activator.start(broker, store, getBundleContext());
+
+ final DomBrokerImplRuntimeMXBean domBrokerRuntimeMXBean = new DomBrokerRuntimeMXBeanImpl(activator.getDataService());
+ getRootRuntimeBeanRegistratorWrapper().register(domBrokerRuntimeMXBean);
return broker;
}
--- /dev/null
+package org.opendaylight.controller.config.yang.md.sal.dom.statistics;
+
+import org.opendaylight.controller.config.yang.md.sal.dom.impl.Data;
+import org.opendaylight.controller.config.yang.md.sal.dom.impl.DomBrokerImplRuntimeMXBean;
+import org.opendaylight.controller.config.yang.md.sal.dom.impl.Transactions;
+import org.opendaylight.controller.sal.dom.broker.DataBrokerImpl;
+
+public class DomBrokerRuntimeMXBeanImpl implements
+ DomBrokerImplRuntimeMXBean {
+
+ private final DataBrokerImpl dataService;
+ private final Transactions transactions = new Transactions();
+ private final Data data = new Data();
+
+ public DomBrokerRuntimeMXBeanImpl(DataBrokerImpl dataService) {
+ this.dataService = dataService;
+ }
+
+ public Transactions getTransactions() {
+ transactions.setCreated(dataService.getCreatedTransactionsCount().get());
+ transactions.setSubmitted(dataService.getSubmittedTransactionsCount().get());
+ transactions.setSuccessful(dataService.getFinishedTransactionsCount().get());
+ transactions.setFailed(dataService.getFailedTransactionsCount().get());
+ return transactions;
+ }
+
+ @Override
+ public Data getData() {
+ transactions.setCreated(dataService.getCreatedTransactionsCount().get());
+ transactions.setSubmitted(dataService.getSubmittedTransactionsCount().get());
+ transactions.setSuccessful(dataService.getFinishedTransactionsCount().get());
+ transactions.setFailed(dataService.getFailedTransactionsCount().get());
+ data.setTransactions(transactions);
+ return data;
+ }
+}
import org.opendaylight.controller.sal.core.api.data.DataStore
import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter
import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener
+import org.opendaylight.controller.sal.dom.broker.impl.RpcRouterImpl
class BrokerConfigActivator implements AutoCloseable {
private static val ROOT = InstanceIdentifier.builder().toInstance();
+
+ @Property
+ private var DataBrokerImpl dataService;
private var ServiceRegistration<SchemaService> schemaReg;
private var ServiceRegistration<DataBrokerService> dataReg;
private var ServiceRegistration<DataProviderService> dataProviderReg;
private var ServiceRegistration<MountService> mountReg;
private var ServiceRegistration<MountProvisionService> mountProviderReg;
-
private var SchemaServiceImpl schemaService;
- private var DataBrokerImpl dataService;
private var MountPointManagerImpl mountService;
SchemaAwareDataStoreAdapter wrappedStore
val emptyProperties = new Hashtable<String, String>();
broker.setBundleContext(context);
-
+ broker.setRouter(new RpcRouterImpl("Rpc router"))
schemaService = new SchemaServiceImpl();
schemaService.setContext(context);
schemaService.setParser(new YangParserImpl());
import java.util.concurrent.atomic.AtomicLong;
-import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
import org.opendaylight.controller.md.sal.common.api.data.DataReader;
import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataBroker;
import org.opendaylight.controller.sal.common.DataStoreIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
public class DataBrokerImpl extends AbstractDataBroker<InstanceIdentifier, CompositeNode, DataChangeListener> implements
- DataProviderService {
+ DataProviderService, AutoCloseable {
+ private AtomicLong nextTransaction = new AtomicLong();
+ private final AtomicLong createdTransactionsCount = new AtomicLong();
+
public DataBrokerImpl() {
setDataReadRouter(new DataReaderRouter());
}
-
- private AtomicLong nextTransaction = new AtomicLong();
+
+ public AtomicLong getCreatedTransactionsCount() {
+ return createdTransactionsCount;
+ }
@Override
public DataTransactionImpl beginTransaction() {
String transactionId = "DOM-" + nextTransaction.getAndIncrement();
+ createdTransactionsCount.getAndIncrement();
return new DataTransactionImpl(transactionId,this);
}
throw new UnsupportedOperationException("Deprecated");
}
+ @Override
+ public void close() throws Exception {
+
+ }
+
}
\ No newline at end of file
import config { prefix config; revision-date 2013-04-05; }
import opendaylight-md-sal-dom {prefix sal;}
+ import opendaylight-md-sal-common {prefix common;}
description
"Service definition for Binding Aware MD-SAL.";
base config:module-type;
config:provided-service sal:dom-broker-osgi-registry;
config:java-name-prefix DomBrokerImpl;
- }
+ }
identity hash-map-data-store {
base config:module-type;
}
}
+ augment "/config:modules/config:module/config:state" {
+ case dom-broker-impl {
+ when "/config:modules/config:module/config:type = 'dom-broker-impl'";
+ container data {
+ uses common:data-state;
+ }
+ }
+ }
}
\ No newline at end of file
package org.opendaylight.controller.config.yang.md.sal.connector.netconf;
import io.netty.channel.EventLoopGroup;
+import io.netty.util.concurrent.GlobalEventExecutor;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
import org.opendaylight.controller.netconf.util.handler.ssh.authentication.LoginPassword;
import org.opendaylight.controller.sal.connect.netconf.NetconfDevice;
+import org.opendaylight.protocol.framework.ReconnectStrategy;
+import org.opendaylight.protocol.framework.TimedReconnectStrategy;
import org.osgi.framework.BundleContext;
import static com.google.common.base.Preconditions.*;
String addressValue = getAddress();
+ int attemptMsTimeout = 60*1000;
+ int connectionAttempts = 5;
/*
* Uncomment after Switch to IP Address
if(getAddress().getIpv4Address() != null) {
}
*/
+ ReconnectStrategy strategy = new TimedReconnectStrategy(GlobalEventExecutor.INSTANCE, attemptMsTimeout, 1000, 1.0, null,
+ Long.valueOf(connectionAttempts), null);
+
+
+ device.setStrategy(strategy);
+
InetAddress addr = InetAddresses.forString(addressValue);
InetSocketAddress socketAddress = new InetSocketAddress(addr , getPort().intValue());
device.setSocketAddress(socketAddress);
import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction
import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
+import org.opendaylight.protocol.framework.ReconnectStrategy
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler
+import org.opendaylight.controller.md.sal.common.api.data.DataModification
-class NetconfDevice implements Provider, DataReader<InstanceIdentifier, CompositeNode>, RpcImplementation, AutoCloseable {
+class NetconfDevice implements
+ Provider, //
+ DataReader<InstanceIdentifier, CompositeNode>, //
+ DataCommitHandler<InstanceIdentifier, CompositeNode>, //
+ RpcImplementation, //
+ AutoCloseable {
var NetconfClient client;
@Property
var InstanceIdentifier path;
- Registration<DataReader<InstanceIdentifier, CompositeNode>> operReaderReg
+ @Property
+ var ReconnectStrategy strategy;
+ Registration<DataReader<InstanceIdentifier, CompositeNode>> operReaderReg
Registration<DataReader<InstanceIdentifier, CompositeNode>> confReaderReg
-
- String name
-
+ Registration<DataCommitHandler<InstanceIdentifier, CompositeNode>> commitHandlerReg
+
+ val String name
MountProvisionService mountService
-
+
+
public new(String name) {
this.name = name;
this.path = InstanceIdentifier.builder(INVENTORY_PATH).nodeWithKey(INVENTORY_NODE,
}
def start(NetconfClientDispatcher dispatcher) {
- client = new NetconfClient(name, socketAddress, dispatcher);
+ client = NetconfClient.clientFor(name, socketAddress, strategy, dispatcher);
confReaderReg = mountInstance.registerConfigurationReader(path, this);
operReaderReg = mountInstance.registerOperationalReader(path, this);
+ //commitHandlerReg = mountInstance.registerCommitHandler(path,this);
}
override readConfigurationData(InstanceIdentifier path) {
- val result = invokeRpc(NETCONF_GET_CONFIG_QNAME, wrap(NETCONF_GET_CONFIG_QNAME, path.toFilterStructure()));
+ val result = invokeRpc(NETCONF_GET_CONFIG_QNAME, wrap(NETCONF_GET_CONFIG_QNAME, CONFIG_SOURCE_RUNNING, path.toFilterStructure()));
val data = result.result.getFirstCompositeByName(NETCONF_DATA_QNAME);
return data?.findNode(path) as CompositeNode;
}
return current;
}
+ override requestCommit(DataModification<InstanceIdentifier, CompositeNode> modification) {
+ throw new UnsupportedOperationException("TODO: auto-generated method stub")
+ }
+
override close() {
confReaderReg?.close()
operReaderReg?.close()
import org.w3c.dom.Document
import org.w3c.dom.Element
import org.opendaylight.controller.sal.common.util.Rpcs
+import java.util.List
+import com.google.common.collect.ImmutableList
class NetconfMapping {
public static val NETCONF_RPC_QNAME = new QName(NETCONF_QNAME,"rpc");
public static val NETCONF_GET_QNAME = new QName(NETCONF_QNAME,"get");
public static val NETCONF_GET_CONFIG_QNAME = new QName(NETCONF_QNAME,"get-config");
+ public static val NETCONF_SOURCE_QNAME = new QName(NETCONF_QNAME,"source");
+ public static val NETCONF_RUNNING_QNAME = new QName(NETCONF_QNAME,"running");
public static val NETCONF_RPC_REPLY_QNAME = new QName(NETCONF_QNAME,"rpc-reply");
public static val NETCONF_OK_QNAME = new QName(NETCONF_QNAME,"ok");
public static val NETCONF_DATA_QNAME = new QName(NETCONF_QNAME,"data");
+ static List<Node<?>> RUNNING = Collections.<Node<?>>singletonList(new SimpleNodeTOImpl(NETCONF_RUNNING_QNAME,null,null));
+ public static val CONFIG_SOURCE_RUNNING = new CompositeNodeTOImpl(NETCONF_SOURCE_QNAME,null,RUNNING);
static val messageId = new AtomicInteger(0);
+
+
}
}
+ static def wrap(QName name,Node<?> additional,Node<?> node) {
+ if(node != null) {
+ return new CompositeNodeTOImpl(name,null,ImmutableList.of(additional,node));
+ }
+ else {
+ return new CompositeNodeTOImpl(name,null,ImmutableList.of(additional));
+ }
+ }
+
public static def Node<?> toCompositeNode(Document document) {
return XmlDocumentUtils.toCompositeNode(document) as Node<?>
--- /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>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-parent</artifactId>
+ <relativePath>../..</relativePath>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>sal-remoterpc-connector</artifactId>
+ <packaging>bundle</packaging>
+
+ <properties>
+ <zeromq.version>0.3.1</zeromq.version>
+ <jackson.version>1.9.8</jackson.version>
+ <stax.version>1.0.1</stax.version>
+ </properties>
+
+ <dependencies>
+ <!-- MD Sal interdependencies -->
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>sal-core-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>sal-connector-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>sal-common-util</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>zeromq-routingtable.implementation</artifactId>
+ <!-- TODO: fix the version. Why is it not MD Sal project version?-->
+ <version>0.4.1-SNAPSHOT</version>
+ </dependency>
+
+ <!-- AD Sal -->
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal</artifactId>
+ </dependency>
+
+ <!-- Yang tools -->
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-common</artifactId>
+ </dependency>
+
+ <!-- Third Party -->
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.zeromq</groupId>
+ <artifactId>jeromq</artifactId>
+ <version>${zeromq.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId> org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-core-asl</artifactId>
+ <version>${jackson.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-mapper-asl</artifactId>
+ <version>${jackson.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>stax</groupId>
+ <artifactId>stax-api</artifactId>
+ <version>${stax.version}</version>
+ </dependency>
+
+ <!-- Tests -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.powermock</groupId>
+ <artifactId>powermock-module-junit4</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.powermock</groupId>
+ <artifactId>powermock-api-mockito</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.powermock</groupId>
+ <artifactId>powermock-core</artifactId>
+ </dependency>
+
+ </dependencies>
+
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>${bundle.plugin.version}</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Import-Package>
+ *,
+ !org.codehaus.enunciate.jaxrs
+ </Import-Package>
+ <Export-Package>
+ org.opendaylight.controller.config.yang.md.sal.remote.rpc,
+ org.opendaylight.controller.sal.connector.remoterpc,
+ org.opendaylight.controller.sal.connector.remoterpc.*
+ </Export-Package>
+ <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+ </instructions>
+ </configuration>
+ </plugin>
+
+
+ <plugin>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-maven-plugin</artifactId>
+ <version>0.5.9-SNAPSHOT</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>generate-sources</goal>
+ </goals>
+ <configuration>
+ <codeGenerators>
+ <generator>
+ <codeGeneratorClass>
+ org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+ </codeGeneratorClass>
+ <outputBaseDir>${project.build.directory}/generated-sources/config</outputBaseDir>
+ <additionalConfiguration>
+ <namespaceToPackage1>
+ urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang
+ </namespaceToPackage1>
+ </additionalConfiguration>
+ </generator>
+ <generator>
+ <codeGeneratorClass>org.opendaylight.yangtools.yang.unified.doc.generator.maven.DocumentationGeneratorImpl</codeGeneratorClass>
+ <outputBaseDir>target/site/models</outputBaseDir>
+ </generator>
+ </codeGenerators>
+ <inspectDependencies>true</inspectDependencies>
+ </configuration>
+ </execution>
+ </executions>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>yang-jmx-generator-plugin</artifactId>
+ <version>0.2.3-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>maven-sal-api-gen-plugin</artifactId>
+ <version>0.6.0-SNAPSHOT</version>
+ <type>jar</type>
+ </dependency>
+ </dependencies>
+ </plugin>
+ </plugins>
+ </build>
+</project>
--- /dev/null
+/**
+* Generated file
+
+* Generated from: yang module name: odl-sal-dom-rpc-remote-cfg yang module local name: remote-zeromq-rpc-server
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Thu Dec 05 14:25:21 CET 2013
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.md.sal.remote.rpc;
+
+import org.opendaylight.controller.sal.connector.remoterpc.Client;
+import org.opendaylight.controller.sal.connector.remoterpc.RemoteRpcProvider;
+import org.opendaylight.controller.sal.connector.remoterpc.RoutingTableProvider;
+import org.opendaylight.controller.sal.connector.remoterpc.ServerImpl;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.osgi.framework.BundleContext;
+
+/**
+*
+*/
+public final class ZeroMQServerModule extends org.opendaylight.controller.config.yang.md.sal.remote.rpc.AbstractZeroMQServerModule
+ {
+
+ private static final Integer ZEROMQ_ROUTER_PORT = 5554;
+ private BundleContext bundleContext;
+
+ public ZeroMQServerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public ZeroMQServerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+ ZeroMQServerModule oldModule, java.lang.AutoCloseable oldInstance) {
+
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ protected void customValidation(){
+ // Add custom validation for module attributes here.
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+
+ Broker broker = getDomBrokerDependency();
+ RoutingTableProvider provider = new RoutingTableProvider(bundleContext);
+
+
+ final int port = getPort() != null ? getPort() : ZEROMQ_ROUTER_PORT;
+
+ ServerImpl serverImpl = new ServerImpl(port);
+
+ Client clientImpl = new Client();
+ RemoteRpcProvider facade = new RemoteRpcProvider(serverImpl, clientImpl);
+
+ facade.setRoutingTableProvider(provider );
+
+ broker.registerProvider(facade, bundleContext);
+ return facade;
+ }
+
+ public void setBundleContext(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+}
--- /dev/null
+/**
+* Generated file
+
+* Generated from: yang module name: odl-sal-dom-rpc-remote-cfg yang module local name: remote-zeromq-rpc-server
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Thu Dec 05 14:25:21 CET 2013
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.md.sal.remote.rpc;
+
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.DynamicMBeanWithInstance;
+import org.opendaylight.controller.config.spi.Module;
+import org.osgi.framework.BundleContext;
+
+/**
+*
+*/
+public class ZeroMQServerModuleFactory extends org.opendaylight.controller.config.yang.md.sal.remote.rpc.AbstractZeroMQServerModuleFactory
+{
+
+ @Override
+ public Module createModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) {
+ ZeroMQServerModule module = (ZeroMQServerModule) super.createModule(instanceName, dependencyResolver, bundleContext);
+ module.setBundleContext(bundleContext);
+ return module;
+ }
+
+ @Override
+ public Module createModule(String instanceName, DependencyResolver dependencyResolver,
+ DynamicMBeanWithInstance old, BundleContext bundleContext) throws Exception {
+ ZeroMQServerModule module = (ZeroMQServerModule) super.createModule(instanceName, dependencyResolver, old,bundleContext);
+ module.setBundleContext(bundleContext);
+ return module;
+ }
+}
--- /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.sal.connector.remoterpc;
+
+import com.google.common.base.Optional;
+
+import org.opendaylight.controller.sal.common.util.RpcErrors;
+import org.opendaylight.controller.sal.common.util.Rpcs;
+import org.opendaylight.controller.sal.connector.api.RpcRouter;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.Message;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.MessageWrapper;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.RouteIdentifierImpl;
+import org.opendaylight.controller.sal.connector.remoterpc.util.XmlUtils;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.zeromq.ZMQ;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.*;
+
+import static com.google.common.base.Preconditions.*;
+
+/**
+ * An implementation of {@link RpcImplementation} that makes remote RPC calls
+ */
+public class Client implements RemoteRpcClient {
+
+ private final Logger _logger = LoggerFactory.getLogger(Client.class);
+
+ private final LinkedBlockingQueue<MessageWrapper> requestQueue = new LinkedBlockingQueue<MessageWrapper>(100);
+
+ private final ExecutorService pool = Executors.newSingleThreadExecutor();
+ private final long TIMEOUT = 5000; // in ms
+
+ private RoutingTableProvider routingTableProvider;
+
+ public RoutingTableProvider getRoutingTableProvider() {
+ return routingTableProvider;
+ }
+
+ public void setRoutingTableProvider(RoutingTableProvider routingTableProvider) {
+ this.routingTableProvider = routingTableProvider;
+ }
+
+ public LinkedBlockingQueue<MessageWrapper> getRequestQueue() {
+ return requestQueue;
+ }
+
+ @Override
+ public Set<QName> getSupportedRpcs() {
+ // TODO: Find the entries from routing table
+ return Collections.emptySet();
+ }
+
+ public void start() {
+ pool.execute(new Sender(this));
+
+ }
+
+ public void stop() {
+
+ _logger.debug("Client stopping...");
+ Context.getInstance().getZmqContext().term();
+ _logger.debug("ZMQ context terminated");
+
+ pool.shutdown(); // intiate shutdown
+ try {
+ if (!pool.awaitTermination(10, TimeUnit.SECONDS)) {
+ pool.shutdownNow();
+ if (!pool.awaitTermination(10, TimeUnit.SECONDS))
+ _logger.error("Client thread pool did not shut down");
+ }
+ } catch (InterruptedException e) {
+ // (Re-)Cancel if current thread also interrupted
+ pool.shutdownNow();
+ // Preserve interrupt status
+ Thread.currentThread().interrupt();
+ }
+ _logger.debug("Client stopped");
+ }
+
+ @Override
+ public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
+
+ RouteIdentifierImpl routeId = new RouteIdentifierImpl();
+ routeId.setType(rpc);
+
+ String address = lookupRemoteAddress(routeId);
+
+ Message request = new Message.MessageBuilder().type(Message.MessageType.REQUEST)
+ .sender(Context.getInstance().getLocalUri()).recipient(address).route(routeId)
+ .payload(XmlUtils.compositeNodeToXml(input)).build();
+
+ List<RpcError> errors = new ArrayList<RpcError>();
+
+ try (SocketPair pair = new SocketPair()) {
+
+ MessageWrapper messageWrapper = new MessageWrapper(request, pair.getSender());
+ process(messageWrapper);
+ Message response = parseMessage(pair.getReceiver());
+
+ CompositeNode payload = XmlUtils.xmlToCompositeNode((String) response.getPayload());
+
+ return Rpcs.getRpcResult(true, payload, errors);
+
+ } catch (Exception e) {
+ collectErrors(e, errors);
+ return Rpcs.getRpcResult(false, null, errors);
+ }
+
+ }
+
+ public void process(MessageWrapper msg) throws TimeoutException, InterruptedException {
+ _logger.debug("Processing message [{}]", msg);
+
+ boolean success = requestQueue.offer(msg, TIMEOUT, TimeUnit.MILLISECONDS);
+ if (!success)
+ throw new TimeoutException("Queue is full");
+ }
+
+ /**
+ * Block on socket for reply
+ *
+ * @param receiver
+ * @return
+ */
+ private Message parseMessage(ZMQ.Socket receiver) throws IOException, ClassNotFoundException {
+ return (Message) Message.deserialize(receiver.recv());
+ }
+
+ /**
+ * Find address for the given route identifier in routing table
+ *
+ * @param routeId
+ * route identifier
+ * @return remote network address
+ */
+ private String lookupRemoteAddress(RpcRouter.RouteIdentifier routeId) {
+ checkNotNull(routeId, "route must not be null");
+
+ Optional<RoutingTable<String, String>> routingTable = routingTableProvider.getRoutingTable();
+ checkNotNull(routingTable.isPresent(), "Routing table is null");
+
+ Set<String> addresses = routingTable.get().getRoutes(routeId.toString());
+ checkNotNull(addresses, "Address not found for route [%s]", routeId);
+ checkState(addresses.size() == 1, "Multiple remote addresses found for route [%s], \nonly 1 expected", routeId); // its
+ // a
+ // global
+ // service.
+
+ String address = addresses.iterator().next();
+ checkNotNull(address, "Address not found for route [%s]", routeId);
+
+ return address;
+ }
+
+ private void collectErrors(Exception e, List<RpcError> errors) {
+ if (e == null)
+ return;
+ if (errors == null)
+ errors = new ArrayList<RpcError>();
+
+ errors.add(RpcErrors.getRpcError(null, null, null, null, e.getMessage(), null, e.getCause()));
+ for (Throwable t : e.getSuppressed()) {
+ errors.add(RpcErrors.getRpcError(null, null, null, null, t.getMessage(), null, t));
+ }
+ }
+
+ @Override
+ public void close() throws Exception {
+ stop();
+ }
+}
--- /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.sal.connector.remoterpc;
+
+import org.zeromq.ZMQ;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.Enumeration;
+
+/**
+ * Provides a ZeroMQ Context object
+ */
+public class Context {
+ private ZMQ.Context zmqContext = ZMQ.context(1);
+ private String uri;
+
+ private static Context _instance = new Context();
+
+ private Context() {}
+
+ public static Context getInstance(){
+ return _instance;
+ }
+
+ public ZMQ.Context getZmqContext(){
+ return this.zmqContext;
+ }
+
+ public String getLocalUri(){
+ uri = (uri != null) ? uri
+ : new StringBuilder("tcp://").append(getIpAddress()).append(":")
+ .append(getRpcPort()).toString();
+
+ return uri;
+ }
+
+ public String getRpcPort(){
+ String rpcPort = (System.getProperty("rpc.port") != null)
+ ? System.getProperty("rpc.port")
+ : "5554";
+
+ return rpcPort;
+ }
+
+ private String getIpAddress(){
+ String ipAddress = (System.getProperty("local.ip") != null)
+ ? System.getProperty("local.ip")
+ : findIpAddress();
+
+ return ipAddress;
+ }
+
+ /**
+ * Finds IPv4 address of the local VM
+ * TODO: This method is non-deterministic. There may be more than one IPv4 address. Cant say which
+ * address will be returned. Read IP from a property file or enhance the code to make it deterministic.
+ * Should we use IP or hostname?
+ *
+ * @return
+ */
+ private String findIpAddress() {
+ String hostAddress = null;
+ Enumeration e = null;
+ try {
+ e = NetworkInterface.getNetworkInterfaces();
+ } catch (SocketException e1) {
+ e1.printStackTrace();
+ }
+ while (e.hasMoreElements()) {
+
+ NetworkInterface n = (NetworkInterface) e.nextElement();
+
+ Enumeration ee = n.getInetAddresses();
+ while (ee.hasMoreElements()) {
+ InetAddress i = (InetAddress) ee.nextElement();
+ if ((i instanceof Inet4Address) && (i.isSiteLocalAddress()))
+ hostAddress = i.getHostAddress();
+ }
+ }
+ return hostAddress;
+
+ }
+}
--- /dev/null
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+
+public interface RemoteRpcClient extends RpcImplementation,AutoCloseable{
+
+
+ void setRoutingTableProvider(RoutingTableProvider provider);
+
+ void stop();
+
+ void start();
+}
--- /dev/null
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+import java.util.Collection;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+
+import org.opendaylight.controller.sal.connector.remoterpc.Client;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.controller.sal.core.api.Provider;
+import org.opendaylight.controller.sal.core.api.Provider.ProviderFunctionality;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+public class RemoteRpcProvider implements
+ RemoteRpcServer,
+ RemoteRpcClient,
+ Provider {
+
+ private final ServerImpl server;
+ private final Client client;
+ private RoutingTableProvider provider;
+
+ @Override
+ public void setRoutingTableProvider(RoutingTableProvider provider) {
+ this.provider = provider;
+ server.setRoutingTableProvider(provider);
+ client.setRoutingTableProvider(provider);
+ }
+
+ @Override
+ public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
+ return client.invokeRpc(rpc, input);
+ }
+
+ @Override
+ public Set<QName> getSupportedRpcs() {
+ return client.getSupportedRpcs();
+ }
+
+
+ public RemoteRpcProvider(ServerImpl server, Client client) {
+ this.server = server;
+ this.client = client;
+ }
+
+ public void setBrokerSession(ProviderSession session) {
+ server.setBrokerSession(session);
+ }
+ public void setServerPool(ExecutorService serverPool) {
+ server.setServerPool(serverPool);
+ }
+ public void start() {
+ client.setRoutingTableProvider(provider);
+ server.setRoutingTableProvider(provider);
+ server.start();
+ client.start();
+ }
+ public void onRouteUpdated(String key, Set values) {
+ server.onRouteUpdated(key, values);
+ }
+ public void onRouteDeleted(String key) {
+ server.onRouteDeleted(key);
+ }
+
+
+ @Override
+ public Collection<ProviderFunctionality> getProviderFunctionality() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+
+ @Override
+ public void onSessionInitiated(ProviderSession session) {
+ server.setBrokerSession(session);
+ start();
+ }
+
+
+ public void close() throws Exception {
+ server.close();
+ client.close();
+ }
+
+
+
+
+ @Override
+ public void stop() {
+ server.stop();
+ client.stop();
+ }
+}
--- /dev/null
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+
+public interface RemoteRpcServer extends AutoCloseable {
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.osgi.framework.BundleContext;
+import org.osgi.util.tracker.ServiceTracker;
+
+import com.google.common.base.Optional;
+
+public class RoutingTableProvider implements AutoCloseable {
+
+ @SuppressWarnings("rawtypes")
+ final ServiceTracker<RoutingTable,RoutingTable> tracker;
+
+
+ public RoutingTableProvider(BundleContext ctx) {
+ @SuppressWarnings("rawtypes")
+ ServiceTracker<RoutingTable, RoutingTable> rawTracker = new ServiceTracker<>(ctx, RoutingTable.class, null);
+ tracker = rawTracker;
+ tracker.open();
+ }
+
+ public Optional<RoutingTable<String, String>> getRoutingTable() {
+ @SuppressWarnings("unchecked")
+ RoutingTable<String,String> tracked = tracker.getService();
+ return Optional.fromNullable(tracked);
+ }
+
+ @Override
+ public void close() throws Exception {
+ tracker.close();
+ }
+}
--- /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.sal.connector.remoterpc;
+
+import org.opendaylight.controller.sal.connector.remoterpc.dto.Message;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.MessageWrapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.zeromq.ZMQ;
+
+import java.io.IOException;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * A class encapsulating {@link ZMQ.Socket} of type {@link ZMQ.REQ}.
+ * It adds following capabilities:
+ * <li> Retry logic - Tries 3 times before giving up
+ * <li> Request times out after {@link TIMEOUT} property
+ * <li> The limitation of {@link ZMQ.REQ}/{@link ZMQ.REP} pair is that no 2 requests can be sent before
+ * the response for the 1st request is received. To overcome that, this socket queues all messages until
+ * the previous request has been responded.
+ */
+public class RpcSocket {
+
+ // Constants
+ public static final int TIMEOUT = 2000;
+ public static final int QUEUE_SIZE = 10;
+ public static final int NUM_RETRIES = 3;
+ private static final Logger log = LoggerFactory.getLogger(RpcSocket.class);
+
+ private ZMQ.Socket socket;
+ private ZMQ.Poller poller;
+ private String address;
+ private SocketState state;
+ private long sendTime;
+ private int retriesLeft;
+ private LinkedBlockingQueue<MessageWrapper> inQueue;
+
+
+ public RpcSocket(String address, ZMQ.Poller poller) {
+ this.socket = null;
+ this.state = new IdleSocketState();
+ this.sendTime = -1;
+ this.retriesLeft = NUM_RETRIES;
+ this.inQueue = new LinkedBlockingQueue<MessageWrapper>(QUEUE_SIZE);
+ this.address = address;
+ this.poller = poller;
+ createSocket();
+ }
+
+ public ZMQ.Socket getSocket() {
+ return socket;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public int getRetriesLeft() {
+ return retriesLeft;
+ }
+
+ public void setRetriesLeft(int retriesLeft) {
+ this.retriesLeft = retriesLeft;
+ }
+
+ public SocketState getState() {
+ return state;
+ }
+
+ public void setState(SocketState state) {
+ this.state = state;
+ }
+
+ public int getQueueSize() {
+ return inQueue.size();
+ }
+
+ public MessageWrapper removeCurrentRequest() {
+ return inQueue.poll();
+ }
+
+ public boolean hasTimedOut() {
+ return (System.currentTimeMillis() - sendTime > RpcSocket.TIMEOUT);
+ }
+
+ public void send(MessageWrapper request) throws TimeoutException {
+ try {
+ boolean success = inQueue.offer(request, TIMEOUT, TimeUnit.MILLISECONDS);
+ if (!success) {
+ throw new TimeoutException("send :: Queue is full");
+ }
+ process();
+ }
+ catch (InterruptedException e) {
+ log.error("send : Thread interrupted while attempting to add request to inQueue", e);
+ }
+ }
+
+ public MessageWrapper receive() {
+ Message response = parseMessage();
+ MessageWrapper messageWrapper = inQueue.poll(); //remove the message from queue
+ MessageWrapper responseMessageWrapper = new MessageWrapper(response, messageWrapper.getReceiveSocket());
+
+ state = new IdleSocketState();
+ retriesLeft = NUM_RETRIES;
+ return responseMessageWrapper;
+ }
+
+ public void process() {
+ if (getQueueSize() > 0) //process if there's message in the queue
+ state.process(this);
+ }
+
+ // Called by IdleSocketState & BusySocketState
+ public void sendMessage() {
+ //Get the message from queue without removing it. For retries
+ MessageWrapper messageWrapper = inQueue.peek();
+ if (messageWrapper != null) {
+ Message message = messageWrapper.getMessage();
+ try {
+ socket.send(Message.serialize(message));
+ }
+ catch (IOException e) {
+ log.debug("Message send failed [{}]", message);
+ log.debug("Exception [{}]", e);
+ }
+ sendTime = System.currentTimeMillis();
+ }
+ }
+
+ public Message parseMessage() {
+ Message parsedMessage = null;
+ byte[] bytes = socket.recv();
+ log.debug("Received bytes:[{}]", bytes.length);
+ try {
+ parsedMessage = (Message)Message.deserialize(bytes);
+ }
+ catch (IOException|ClassNotFoundException e) {
+ log.debug("parseMessage : Deserializing received bytes failed", e);
+ }
+
+ return parsedMessage;
+ }
+
+ public void recycleSocket() {
+ close();
+ }
+
+ public void close() {
+ socket.setLinger(10);
+ socket.close();
+ }
+
+ private void createSocket() {
+ socket = Context.getInstance().getZmqContext().socket(ZMQ.REQ);
+ socket.connect(address);
+ poller.register(socket, ZMQ.Poller.POLLIN);
+ state = new IdleSocketState();
+ }
+
+
+ /**
+ * Represents the state of a {@link org.opendaylight.controller.sal.connector.remoterpc.RpcSocket}
+ */
+ public static interface SocketState {
+
+ /* The processing actions to be performed in this state
+ */
+ public void process(RpcSocket socket);
+ }
+
+ /**
+ * Represents the idle state of a {@link org.opendaylight.controller.sal.connector.remoterpc.RpcSocket}
+ */
+ public static class IdleSocketState implements SocketState {
+
+ @Override
+ public void process(RpcSocket socket) {
+ socket.sendMessage();
+ socket.setState(new BusySocketState());
+ socket.setRetriesLeft(socket.getRetriesLeft()-1);
+ }
+ }
+
+ /**
+ * Represents the busy state of a {@link org.opendaylight.controller.sal.connector.remoterpc.RpcSocket}
+ */
+ public static class BusySocketState implements SocketState {
+
+ private static Logger log = LoggerFactory.getLogger(BusySocketState.class);
+
+ @Override
+ public void process(RpcSocket socket) {
+ if (socket.hasTimedOut()) {
+ if (socket.getRetriesLeft() > 0) {
+ log.debug("process : Request timed out, retrying now...");
+ socket.sendMessage();
+ socket.setRetriesLeft(socket.getRetriesLeft() - 1);
+ }
+ else {
+ // No more retries for current request, so stop processing the current request
+ MessageWrapper message = socket.removeCurrentRequest();
+ if (message != null) {
+ log.error("Unable to process rpc request [{}]", message);
+ socket.setState(new IdleSocketState());
+ socket.setRetriesLeft(NUM_RETRIES);
+ }
+ }
+ }
+ // Else no timeout, so allow processing to continue
+ }
+ }
+}
--- /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.sal.connector.remoterpc;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.Message;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.MessageWrapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.zeromq.ZMQ;
+
+import java.io.IOException;
+import java.util.concurrent.TimeoutException;
+
+import static com.google.common.base.Preconditions.*;
+
+/**
+ * Main server thread for sending requests.
+ */
+public class Sender implements Runnable{
+
+ private final static Logger _logger = LoggerFactory.getLogger(Sender.class);
+ private final Client client;
+
+
+
+
+ public Sender(Client client) {
+ super();
+ this.client = client;
+ }
+
+@Override
+ public void run() {
+ _logger.info("Starting...");
+
+ try (SocketManager socketManager = new SocketManager()){
+ while (!Thread.currentThread().isInterrupted()) {
+
+ //read incoming messages from blocking queue
+ MessageWrapper request = pollForRequest();
+
+ if (request != null) {
+ processRequest(socketManager, request);
+ }
+
+ flushSockets(socketManager);
+ pollForResponse(socketManager);
+ processResponse(socketManager);
+
+ }
+ } catch(Exception t){
+ _logger.error("Exception: [{}]", t);
+ _logger.error("Stopping...");
+ }
+ }
+
+ private void processResponse(SocketManager socketManager) {
+ for (int i = 0; i < socketManager.getPoller().getSize(); i++) {
+ // If any sockets get a response, process it
+ if (socketManager.getPoller().pollin(i)) {
+ Optional<RpcSocket> socket = socketManager.getManagedSocketFor(
+ socketManager.getPoller().getItem(i).getSocket());
+
+ checkState(socket.isPresent(), "Managed socket not found");
+
+ MessageWrapper response = socket.get().receive();
+ _logger.debug("Received rpc response [{}]", response.getMessage());
+
+ //TODO: handle exception and introduce timeout on receiver side
+ try {
+ response.getReceiveSocket().send(Message.serialize(response.getMessage()));
+ } catch (IOException e) {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ }
+ }
+ }
+ }
+
+ private void processRequest(SocketManager socketManager, MessageWrapper request) throws TimeoutException {
+
+ if ((request.getMessage() == null) ||
+ (request.getMessage().getRecipient() == null)) {
+ //invalid message. log and drop
+ _logger.error("Invalid request [{}]", request);
+ return;
+ }
+
+ RpcSocket socket =
+ socketManager.getManagedSocket(request.getMessage().getRecipient());
+
+ socket.send(request);
+ }
+
+ private void flushSockets(SocketManager socketManager){
+ for (RpcSocket socket : socketManager.getManagedSockets()){
+ socket.process();
+ }
+ }
+
+ private MessageWrapper pollForRequest(){
+ return client.getRequestQueue().poll();
+ }
+
+ private void pollForResponse(SocketManager socketManager){
+ try{
+ socketManager.getPoller().poll(10); //poll every 10ms
+ }catch (Throwable t) { /*Ignore and continue*/ }
+ }
+}
+
+
+/*
+SCALA
+
+package org.opendaylight.controller.sal.connector.remoterpc
+
+ import org.slf4j.{LoggerFactory, Logger}
+ import scala.collection.JavaConverters._
+ import scala.Some
+ import org.opendaylight.controller.sal.connector.remoterpc.dto.{MessageWrapper, Message}
+*/
+/**
+ * Main server thread for sending requests. This does not maintain any state. If the
+ * thread dies, it will be restarted
+ */
+/*class Sender extends Runnable {
+ private val _logger: Logger = LoggerFactory.getLogger(Sender.this.getClass())
+
+ override def run = {
+ _logger.info("Sender starting...")
+ val socketManager = new SocketManager()
+
+ try {
+ while (!Thread.currentThread().isInterrupted) {
+ //read incoming messages from blocking queue
+ val request: MessageWrapper = Client.requestQueue.poll()
+
+ if (request != null) {
+ if ((request.message != null) &&
+ (request.message.getRecipient != null)) {
+
+ val socket = socketManager.getManagedSocket(request.message.getRecipient)
+ socket.send(request)
+ } else {
+ //invalid message. log and drop
+ _logger.error("Invalid request [{}]", request)
+ }
+ }
+
+ socketManager.getManagedSockets().asScala.map(s => s.process)
+
+ // Poll all sockets for responses every 1 sec
+ poll(socketManager)
+
+ // If any sockets get a response, process it
+ for (i <- 0 until socketManager.poller.getSize) {
+ if (socketManager.poller.pollin(i)) {
+ val socket = socketManager.getManagedSocketFor(socketManager.poller.getItem(i).getSocket)
+
+ socket match {
+ case None => //{
+ _logger.error("Could not find a managed socket for zmq socket")
+ throw new IllegalStateException("Could not find a managed socket for zmq socket")
+ //}
+ case Some(s) => {
+ val response = s.receive()
+ _logger.debug("Received rpc response [{}]", response.message)
+ response.receiveSocket.send(Message.serialize(response.message))
+ }
+ }
+ }
+ }
+
+ }
+ } catch{
+ case e:Exception => {
+ _logger.debug("Sender stopping due to exception")
+ e.printStackTrace()
+ }
+ } finally {
+ socketManager.stop
+ }
+ }
+
+ def poll(socketManager:SocketManager) = {
+ try{
+ socketManager.poller.poll(10)
+ }catch{
+ case t:Throwable => //ignore and continue
+ }
+ }
+}
+
+
+// def newThread(r: Runnable): Thread = {
+// val t = new RequestHandler()
+// t.setUncaughtExceptionHandler(new RequestProcessorExceptionHandler)
+// t
+// }
+
+
+
+/**
+ * Restarts the request processing server in the event of unforeseen exceptions
+ */
+//private class RequestProcessorExceptionHandler extends UncaughtExceptionHandler {
+// def uncaughtException(t: Thread, e: Throwable) = {
+// _logger.error("Exception caught during request processing [{}]", e)
+// _logger.info("Restarting request processor server...")
+// RequestProcessor.start()
+// }
--- /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.sal.connector.remoterpc;
+
+import com.google.common.base.Optional;
+
+import org.opendaylight.controller.sal.connector.remoterpc.api.RouteChangeListener;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException;
+import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.Message;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.Message.MessageType;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.RouteIdentifierImpl;
+import org.opendaylight.controller.sal.connector.remoterpc.util.XmlUtils;
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.zeromq.ZMQ;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+/**
+ * ZeroMq based implementation of RpcRouter TODO: 1. Make rpc request handling
+ * async and non-blocking. Note zmq socket is not thread safe 2. Read properties
+ * from config file using existing(?) ODL properties framework
+ */
+public class ServerImpl implements RemoteRpcServer, RouteChangeListener<String, Set> {
+
+ private Logger _logger = LoggerFactory.getLogger(ServerImpl.class);
+
+ private ExecutorService serverPool;
+
+ // private RoutingTable<RpcRouter.RouteIdentifier, String> routingTable;
+ private RoutingTableProvider routingTable;
+ private Set<QName> remoteServices;
+ private ProviderSession brokerSession;
+ private ZMQ.Context context;
+ private ZMQ.Socket replySocket;
+
+ private final RpcListener listener = new RpcListener();
+
+ private final String localUri = Context.getInstance().getLocalUri();
+
+ private final int rpcPort;
+
+ private RpcImplementation client;
+
+ public RpcImplementation getClient() {
+ return client;
+ }
+
+ public void setClient(RpcImplementation client) {
+ this.client = client;
+ }
+
+ // Prevent instantiation
+ public ServerImpl(int rpcPort) {
+ this.rpcPort = rpcPort;
+ }
+
+ public void setBrokerSession(ProviderSession session) {
+ this.brokerSession = session;
+ }
+
+ public ExecutorService getServerPool() {
+ return serverPool;
+ }
+
+ public void setServerPool(ExecutorService serverPool) {
+ this.serverPool = serverPool;
+ }
+
+ public void start() {
+ context = ZMQ.context(1);
+ serverPool = Executors.newSingleThreadExecutor();
+ remoteServices = new HashSet<QName>();
+
+ // Start listening rpc requests
+ serverPool.execute(receive());
+
+ brokerSession.addRpcRegistrationListener(listener);
+ // routingTable.registerRouteChangeListener(routeChangeListener);
+
+ Set<QName> currentlySupported = brokerSession.getSupportedRpcs();
+ for (QName rpc : currentlySupported) {
+ listener.onRpcImplementationAdded(rpc);
+ }
+
+ _logger.debug("RPC Server started [{}]", localUri);
+ }
+
+ public void stop() {
+ // TODO: un-subscribe
+
+ // if (context != null)
+ // context.term();
+ //
+ // _logger.debug("ZMQ Context is terminated.");
+
+ if (serverPool != null)
+ serverPool.shutdown();
+
+ _logger.debug("Thread pool is closed.");
+ }
+
+ private Runnable receive() {
+ return new Runnable() {
+ public void run() {
+
+ // Bind to RPC reply socket
+ replySocket = context.socket(ZMQ.REP);
+ replySocket.bind("tcp://*:" + Context.getInstance().getRpcPort());
+
+ // Poller enables listening on multiple sockets using a single
+ // thread
+ ZMQ.Poller poller = new ZMQ.Poller(1);
+ poller.register(replySocket, ZMQ.Poller.POLLIN);
+ try {
+ // TODO: Add code to restart the thread after exception
+ while (!Thread.currentThread().isInterrupted()) {
+
+ poller.poll();
+
+ if (poller.pollin(0)) {
+ handleRpcCall();
+ }
+ }
+ } catch (Exception e) {
+ // log and continue
+ _logger.error("Unhandled exception [{}]", e);
+ } finally {
+ poller.unregister(replySocket);
+ replySocket.close();
+ }
+
+ }
+ };
+ }
+
+ /**
+ * @throws InterruptedException
+ * @throws ExecutionException
+ */
+ private void handleRpcCall() {
+
+ Message request = parseMessage(replySocket);
+
+ _logger.debug("Received rpc request [{}]", request);
+
+ // Call broker to process the message then reply
+ Future<RpcResult<CompositeNode>> rpc = null;
+ RpcResult<CompositeNode> result = null;
+ try {
+ rpc = brokerSession.rpc((QName) request.getRoute().getType(),
+ XmlUtils.xmlToCompositeNode((String) request.getPayload()));
+
+ result = (rpc != null) ? rpc.get() : null;
+
+ } catch (Exception e) {
+ _logger.debug("Broker threw [{}]", e);
+ }
+
+ CompositeNode payload = (result != null) ? result.getResult() : null;
+
+ Message response = new Message.MessageBuilder().type(MessageType.RESPONSE).sender(localUri)
+ .route(request.getRoute()).payload(XmlUtils.compositeNodeToXml(payload)).build();
+
+ _logger.debug("Sending rpc response [{}]", response);
+
+ try {
+ replySocket.send(Message.serialize(response));
+ } catch (Exception e) {
+ _logger.debug("rpc response send failed for message [{}]", response);
+ _logger.debug("{}", e);
+ }
+
+ }
+
+ /**
+ * @param socket
+ * @return
+ */
+ private Message parseMessage(ZMQ.Socket socket) {
+
+ Message msg = null;
+ try {
+ byte[] bytes = socket.recv();
+ _logger.debug("Received bytes:[{}]", bytes.length);
+ msg = (Message) Message.deserialize(bytes);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ return msg;
+ }
+
+ @Override
+ public void onRouteUpdated(String key, Set values) {
+ RouteIdentifierImpl rId = new RouteIdentifierImpl();
+ try {
+ _logger.debug("Updating key/value {}-{}", key, values);
+ brokerSession.addRpcImplementation((QName) rId.fromString(key).getType(), client);
+
+ } catch (Exception e) {
+ _logger.info("Route update failed {}", e);
+ }
+ }
+
+ @Override
+ public void onRouteDeleted(String key) {
+ // TODO: Broker session needs to be updated to support this
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Listener for rpc registrations
+ */
+ private class RpcListener implements RpcRegistrationListener {
+
+
+
+ @Override
+ public void onRpcImplementationAdded(QName name) {
+
+ // if the service name exists in the set, this notice
+ // has bounced back from the broker. It should be ignored
+ if (remoteServices.contains(name))
+ return;
+
+ _logger.debug("Adding registration for [{}]", name);
+ RouteIdentifierImpl routeId = new RouteIdentifierImpl();
+ routeId.setType(name);
+
+ try {
+ routingTable.getRoutingTable().get().addGlobalRoute(routeId.toString(), localUri);
+ _logger.debug("Route added [{}-{}]", name, localUri);
+ } catch (RoutingTableException | SystemException e) {
+ // TODO: This can be thrown when route already exists in the
+ // table. Broker
+ // needs to handle this.
+ _logger.error("Unhandled exception while adding global route to routing table [{}]", e);
+
+ }
+ }
+
+ @Override
+ public void onRpcImplementationRemoved(QName name) {
+
+ _logger.debug("Removing registration for [{}]", name);
+ RouteIdentifierImpl routeId = new RouteIdentifierImpl();
+ routeId.setType(name);
+
+ try {
+ routingTable.getRoutingTable().get().removeGlobalRoute(routeId.toString());
+ } catch (RoutingTableException | SystemException e) {
+ _logger.error("Route delete failed {}", e);
+ }
+ }
+ }
+
+ @Override
+ public void close() throws Exception {
+ stop();
+ }
+
+ public void setRoutingTableProvider(RoutingTableProvider provider) {
+ this.routingTable = provider;
+ }
+
+}
--- /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.sal.connector.remoterpc;
+
+import com.google.common.base.Optional;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.zeromq.ZMQ;
+import java.net.UnknownHostException;
+import java.util.Collection;
+import java.util.concurrent.ConcurrentHashMap;
+
+
+/**
+ * Manages creation of {@link RpcSocket} and their registration with {@link ZMQ.Poller}
+ */
+public class SocketManager implements AutoCloseable{
+ private static final Logger log = LoggerFactory.getLogger(SocketManager.class);
+
+ /*
+ * RpcSockets mapped by network address its connected to
+ */
+ private ConcurrentHashMap<String, RpcSocket> managedSockets = new ConcurrentHashMap<String, RpcSocket>();
+
+ private ZMQ.Poller _poller = new ZMQ.Poller(2); //randomly selected size. Poller grows automatically
+
+ /**
+ * Returns a {@link RpcSocket} for the given address
+ * @param address network address with port eg: 10.199.199.20:5554
+ * @return
+ */
+ public RpcSocket getManagedSocket(String address) throws IllegalArgumentException {
+ //Precondition
+ if (!address.matches("(tcp://)(.*)(:)(\\d*)")) {
+ throw new IllegalArgumentException("Address must of format 'tcp://<ip address>:<port>' but is " + address);
+ }
+
+ if (!managedSockets.containsKey(address)) {
+ log.debug("{} Creating new socket for {}", Thread.currentThread().getName());
+ RpcSocket socket = new RpcSocket(address, _poller);
+ managedSockets.put(address, socket);
+ }
+
+ return managedSockets.get(address);
+ }
+
+ /**
+ * Returns a {@link RpcSocket} for the given {@link ZMQ.Socket}
+ * @param socket
+ * @return
+ */
+ public Optional<RpcSocket> getManagedSocketFor(ZMQ.Socket socket) {
+ for (RpcSocket rpcSocket : managedSockets.values()) {
+ if (rpcSocket.getSocket().equals(socket)) {
+ return Optional.of(rpcSocket);
+ }
+ }
+ return Optional.absent();
+ }
+
+ /**
+ * Return a collection of all managed sockets
+ * @return
+ */
+ public Collection<RpcSocket> getManagedSockets() {
+ return managedSockets.values();
+ }
+
+ /**
+ * Returns the {@link ZMQ.Poller}
+ * @return
+ */
+ public ZMQ.Poller getPoller() {
+ return _poller;
+ }
+
+ /**
+ * This should be called when stopping the server to close all the sockets
+ * @return
+ */
+ @Override
+ public void close() throws Exception {
+ log.debug("Stopping...");
+ for (RpcSocket socket : managedSockets.values()) {
+ socket.close();
+ }
+ managedSockets.clear();
+ log.debug("Stopped");
+ }
+}
--- /dev/null
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+import org.zeromq.ZMQ;
+
+import java.util.UUID;
+
+/**
+ *
+ */
+public class SocketPair implements AutoCloseable{
+ private ZMQ.Socket sender;
+ private ZMQ.Socket receiver;
+
+ private static final String INPROC_PREFIX = "inproc://";
+
+ public SocketPair(){
+ String address = new StringBuilder(INPROC_PREFIX)
+ .append(UUID.randomUUID())
+ .toString();
+
+ receiver = Context.getInstance().getZmqContext().socket(ZMQ.PAIR);
+ receiver.bind(address);
+
+ sender = Context.getInstance().getZmqContext().socket(ZMQ.PAIR);
+ sender.connect(address);
+ }
+
+ public ZMQ.Socket getSender(){
+ return this.sender;
+ }
+
+ public ZMQ.Socket getReceiver(){
+ return this.receiver;
+ }
+
+ @Override
+ public void close() throws Exception {
+ sender.close();
+ receiver.close();
+ }
+}
--- /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.sal.connector.remoterpc.dto;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.*;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class CompositeNodeImpl implements CompositeNode, Serializable {
+
+ private QName key;
+ private List<Node<?>> children;
+
+ @Override
+ public List<Node<?>> getChildren() {
+ return children;
+ }
+
+ @Override
+ public List<CompositeNode> getCompositesByName(QName children) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List<CompositeNode> getCompositesByName(String children) {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public List<SimpleNode<?>> getSimpleNodesByName(QName children) {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public List<SimpleNode<?>> getSimpleNodesByName(String children) {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public CompositeNode getFirstCompositeByName(QName container) {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public SimpleNode<?> getFirstSimpleByName(QName leaf) {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public MutableCompositeNode asMutable() {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public QName getKey() {
+ return key; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public List<Node<?>> setValue(List<Node<?>> value) {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public int size() {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public boolean containsKey(Object key) {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public boolean containsValue(Object value) {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public List<Node<?>> get(Object key) {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public List<Node<?>> put(QName key, List<Node<?>> value) {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public List<Node<?>> remove(Object key) {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public void putAll(Map<? extends QName, ? extends List<Node<?>>> m) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public void clear() {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public Set<QName> keySet() {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public Collection<List<Node<?>>> values() {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public Set<Entry<QName, List<Node<?>>>> entrySet() {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public QName getNodeType() {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public CompositeNode getParent() {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public List<Node<?>> getValue() {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public ModifyAction getModificationAction() {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+}
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-package org.opendaylight.controller.sal.connector.remoterpc.router.zeromq;
+package org.opendaylight.controller.sal.connector.remoterpc.dto;
-
-import org.codehaus.jackson.map.ObjectMapper;
import org.opendaylight.controller.sal.connector.api.RpcRouter;
import java.io.*;
ANNOUNCE((byte) 0), //TODO: Remove announce, add rpc registration and deregistration
HEARTBEAT((byte) 1),
REQUEST((byte) 2),
- RESPONSE((byte) 3);
+ RESPONSE((byte) 3),
+ ERROR((byte)4);
private final byte type;
private MessageType type;
private String sender;
+ private String recipient;
private RpcRouter.RouteIdentifier route;
private Object payload;
this.payload = payload;
}
+ public String getRecipient() {
+ return recipient;
+ }
+
+ public void setRecipient(String recipient) {
+ this.recipient = recipient;
+ }
@Override
public String toString() {
return "Message{" +
"type=" + type +
", sender='" + sender + '\'' +
+ ", recipient='" + recipient + '\'' +
", route=" + route +
", payload=" + payload +
'}';
return o.readObject();
}
- public static byte[] toJsonBytes(Message m) throws IOException {
- ObjectMapper o = new ObjectMapper();
- return o.writeValueAsBytes(m);
- }
-
- public static Message fromJsonBytes(byte [] bytes) throws IOException {
-
- ObjectMapper o = new ObjectMapper();
- return o.readValue(bytes, Message.class);
- }
-
public static class Response extends Message implements RpcRouter.RpcReply {
private ResponseCode code; // response code
return this;
}
+ public MessageBuilder recipient(String recipient){
+ message.setRecipient(recipient);
+ return this;
+ }
+
public MessageBuilder route(RpcRouter.RouteIdentifier route){
message.setRoute(route);
return this;
--- /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.sal.connector.remoterpc.dto;
+
+import org.zeromq.ZMQ;
+
+/**
+ * A class encapsulating {@link Message} and the {@link ZMQ.Socket} over which it is transmitted
+ */
+public class MessageWrapper {
+
+ private Message _message;
+ private ZMQ.Socket _receiveSocket;
+
+ public MessageWrapper(Message message, ZMQ.Socket receiveSocket) {
+ this._message = message;
+ this._receiveSocket = receiveSocket;
+ }
+
+ public Message getMessage() {
+ return _message;
+ }
+
+ public ZMQ.Socket getReceiveSocket() {
+ return _receiveSocket;
+ }
+}
* 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.sal.connector.remoterpc.router.zeromq;
+package org.opendaylight.controller.sal.connector.remoterpc.dto;
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.map.ObjectMapper;
import org.opendaylight.controller.sal.connector.api.RpcRouter;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import java.io.Serializable;
+import java.net.URI;
-/**
- * User: abhishk2
- */
public class RouteIdentifierImpl implements RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier>,Serializable {
+ transient ObjectMapper mapper = new ObjectMapper();
+
private QName context;
private QName type;
private InstanceIdentifier route;
@Override
public String toString() {
- return "RouteIdentifierImpl{" +
- "context=" + context +
- ", type=" + type +
- ", route=" + route +
- '}';
+ try {
+ return mapper.writeValueAsString(this);
+ } catch (Throwable e) {
+ //do nothing
+ }
+
+ return super.toString();
+ }
+
+ public RpcRouter.RouteIdentifier fromString(String input)
+ throws Exception {
+
+ JsonNode root = mapper.readTree(input);
+ this.context = parseQName(root.get("context"));
+ this.type = parseQName(root.get("type"));
+
+ return this;
+ }
+
+ private QName parseQName(JsonNode node){
+ if (node == null) return null;
+
+ String namespace = (node.get("namespace") != null) ?
+ node.get("namespace").asText() : "";
+
+ String localName = (node.get("localName") != null) ?
+ node.get("localName").asText() : "";
+
+ URI uri = URI.create(namespace);
+ return new QName(uri, localName);
}
}
* 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.sal.connector.remoterpc.router.zeromq;
+package org.opendaylight.controller.sal.connector.remoterpc.dto;
import org.opendaylight.controller.sal.connector.api.RpcRouter;
import org.opendaylight.yangtools.yang.common.QName;
--- /dev/null
+package org.opendaylight.controller.sal.connector.remoterpc.util;
+
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.SimpleNode;
+import org.opendaylight.yangtools.yang.data.impl.NodeUtils;
+import org.opendaylight.yangtools.yang.data.impl.XmlTreeBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.ByteArrayInputStream;
+import java.io.StringWriter;
+
+public class XmlUtils {
+
+ private static final Logger _logger = LoggerFactory.getLogger(XmlUtils.class);
+
+ public static String compositeNodeToXml(CompositeNode cNode){
+ if (cNode == null) return new String();
+
+ Document domTree = NodeUtils.buildShadowDomTree(cNode);
+ StringWriter writer = new StringWriter();
+ try {
+ TransformerFactory tf = TransformerFactory.newInstance();
+ Transformer transformer = tf.newTransformer();
+ transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+ transformer.transform(new DOMSource(domTree), new StreamResult(writer));
+ } catch (TransformerException e) {
+ _logger.error("Error during translation of Document to OutputStream", e);
+ }
+
+ return writer.toString();
+ }
+
+ public static CompositeNode xmlToCompositeNode(String xml){
+ if (xml==null || xml.length()==0) return null;
+
+ Node<?> dataTree;
+ try {
+ dataTree = XmlTreeBuilder.buildDataTree(new ByteArrayInputStream(xml.getBytes()));
+ } catch (XMLStreamException e) {
+ _logger.error("Error during building data tree from XML", e);
+ return null;
+ }
+ if (dataTree == null) {
+ _logger.error("data tree is null");
+ return null;
+ }
+ if (dataTree instanceof SimpleNode) {
+ _logger.error("RPC XML was resolved as SimpleNode");
+ return null;
+ }
+ return (CompositeNode) dataTree;
+ }
+}
--- /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.sal.connector.remoterpc
+
+import org.opendaylight.yangtools.yang.data.api.CompositeNode
+import org.opendaylight.yangtools.yang.common.{RpcError, RpcResult, QName}
+import org.opendaylight.controller.sal.core.api.RpcImplementation
+import java.util
+import java.util.{UUID, Collections}
+import org.zeromq.ZMQ
+import org.opendaylight.controller.sal.common.util.{RpcErrors, Rpcs}
+import org.slf4j.LoggerFactory
+import org.opendaylight.controller.sal.connector.remoterpc.dto.{MessageWrapper, RouteIdentifierImpl, Message}
+import Message.MessageType
+import java.util.concurrent._
+import java.lang.InterruptedException
+
+
+/**
+ * An implementation of {@link RpcImplementation} that makes
+ * remote RPC calls
+ */
+class Client extends RemoteRpcClient {
+
+ private val _logger = LoggerFactory.getLogger(this.getClass);
+
+ val requestQueue = new LinkedBlockingQueue[MessageWrapper](100)
+ val pool: ExecutorService = Executors.newSingleThreadExecutor()
+ private val TIMEOUT = 5000 //in ms
+ var routingTableProvider: RoutingTableProvider = null
+
+
+ def getInstance = this
+
+
+ def setRoutingTableProvider(provider : RoutingTableProvider) = {
+ routingTableProvider = provider;
+ }
+
+ def getSupportedRpcs: util.Set[QName] = {
+ Collections.emptySet()
+ }
+
+ def invokeRpc(rpc: QName, input: CompositeNode): RpcResult[CompositeNode] = {
+
+ val routeId = new RouteIdentifierImpl()
+ routeId.setType(rpc)
+
+ //lookup address for the rpc request
+ val routingTable = routingTableProvider.getRoutingTable()
+ require( routingTable != null, "Routing table not found. Exiting" )
+
+ val addresses:util.Set[String] = routingTable.getRoutes(routeId.toString)
+ require(addresses != null, "Address not found for rpc " + rpc);
+ require(addresses.size() == 1) //its a global service.
+
+ val address = addresses.iterator().next()
+ require(address != null, "Address is null")
+
+ //create in-process "pair" socket and pass it to sender thread
+ //Sender replies on this when result is available
+ val inProcAddress = "inproc://" + UUID.randomUUID()
+ val receiver = Context.zmqContext.socket(ZMQ.PAIR)
+ receiver.bind(inProcAddress);
+
+ val sender = Context.zmqContext.socket(ZMQ.PAIR)
+ sender.connect(inProcAddress)
+
+ val requestMessage = new Message.MessageBuilder()
+ .`type`(MessageType.REQUEST)
+ //.sender("tcp://localhost:8081")
+ .recipient(address)
+ .route(routeId)
+ .payload(input)
+ .build()
+
+ _logger.debug("Queuing up request and expecting response on [{}]", inProcAddress)
+
+ val messageWrapper = new MessageWrapper(requestMessage, sender)
+ val errors = new util.ArrayList[RpcError]
+
+ try {
+ process(messageWrapper)
+ val response = parseMessage(receiver)
+
+ return Rpcs.getRpcResult(
+ true, response.getPayload.asInstanceOf[CompositeNode], Collections.emptySet())
+
+ } catch {
+ case e: Exception => {
+ errors.add(RpcErrors.getRpcError(null,null,null,null,e.getMessage,null,e.getCause))
+ return Rpcs.getRpcResult(false, null, errors)
+ }
+ } finally {
+ receiver.close();
+ sender.close();
+ }
+
+ }
+
+ /**
+ * Block on socket for reply
+ * @param receiver
+ * @return
+ */
+ private def parseMessage(receiver:ZMQ.Socket): Message = {
+ val bytes = receiver.recv()
+ return Message.deserialize(bytes).asInstanceOf[Message]
+ }
+
+ def start() = {
+ pool.execute(new Sender)
+ }
+
+ def process(msg: MessageWrapper) = {
+ _logger.debug("Processing message [{}]", msg)
+ val success = requestQueue.offer(msg, TIMEOUT, TimeUnit.MILLISECONDS)
+
+ if (!success) throw new TimeoutException("Queue is full");
+
+ }
+
+ def stop() = {
+ pool.shutdown() //intiate shutdown
+ _logger.debug("Client stopping...")
+ // Context.zmqContext.term();
+ // _logger.debug("ZMQ context terminated")
+
+ try {
+
+ if (!pool.awaitTermination(10, TimeUnit.SECONDS)) {
+ pool.shutdownNow();
+ if (!pool.awaitTermination(10, TimeUnit.SECONDS))
+ _logger.error("Client thread pool did not shut down");
+ }
+ } catch {
+ case ie:InterruptedException =>
+ // (Re-)Cancel if current thread also interrupted
+ pool.shutdownNow();
+ // Preserve interrupt status
+ Thread.currentThread().interrupt();
+ }
+ _logger.debug("Client stopped")
+ }
+
+ def close() = {
+ stop();
+ }
+}
--- /dev/null
+module odl-sal-dom-rpc-remote-cfg {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote:rpc";
+ prefix "rpc-cluster";
+
+ import config { prefix config; revision-date 2013-04-05; }
+ import opendaylight-md-sal-dom {prefix dom;}
+
+ description
+ "Service definition for Binding Aware MD-SAL.";
+
+ revision "2013-10-28" {
+ description
+ "Initial revision";
+ }
+
+ identity remote-rpc-server {
+ base config:service-type;
+ config:java-class "org.opendaylight.controller.sal.connector.remoterpc.RemoteRpcServer";
+ }
+
+ identity remote-rpc-client {
+ base config:service-type;
+ config:java-class "org.opendaylight.controller.sal.connector.remoterpc.RemoteRpcClient";
+ }
+
+ identity remote-zeromq-rpc-server {
+ base config:module-type;
+ config:provided-service remote-rpc-server;
+ config:provided-service remote-rpc-client;
+ config:java-name-prefix ZeroMQServer;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case remote-zeromq-rpc-server {
+ when "/config:modules/config:module/config:type = 'remote-zeromq-rpc-server'";
+
+ container dom-broker {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity dom:dom-broker-osgi-registry;
+ }
+ }
+ }
+
+ leaf port {
+ type uint16;
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+import junit.framework.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.MessageWrapper;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.Message;
+
+import java.util.concurrent.TimeoutException;
+
+public class ClientTest {
+
+ Client client;
+
+ @Before
+ public void setup(){
+ client = new Client();
+ client.getRequestQueue().clear();
+ }
+
+ @Test
+ public void testStop() throws Exception {
+
+ }
+
+ @Test
+ public void testPool() throws Exception {
+
+ }
+
+ @Test
+ public void process_AddAMessage_ShouldAddToQueue() throws Exception {
+ client.process(getEmptyMessageWrapper());
+ Assert.assertEquals(1, client.getRequestQueue().size());
+ }
+
+ /**
+ * Queue size is 100. Adding 101 message should time out in 2 sec
+ * if server does not process it
+ * @throws Exception
+ */
+ @Test(expected = TimeoutException.class)
+ public void process_Add101Message_ShouldThrow() throws Exception {
+ for (int i=0;i<101;i++){
+ client.process(getEmptyMessageWrapper());
+ }
+ }
+
+ @Test
+ public void testStart() throws Exception {
+ }
+
+ private MessageWrapper getEmptyMessageWrapper(){
+ return new MessageWrapper(new Message(), null);
+ }
+}
--- /dev/null
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+import org.codehaus.jackson.JsonParseException;
+import org.junit.Assert;
+import org.junit.Test;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.RouteIdentifierImpl;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.URI;
+
+public class RouteIdentifierImplTest {
+
+ Logger _logger = LoggerFactory.getLogger(RouteIdentifierImplTest.class);
+
+ private final URI namespace = URI.create("http://cisco.com/example");
+ private final QName QNAME = new QName(namespace, "heartbeat");
+
+ @Test
+ public void testToString() throws Exception {
+ RouteIdentifierImpl rId = new RouteIdentifierImpl();
+ rId.setType(QNAME);
+
+ _logger.debug(rId.toString());
+
+ Assert.assertTrue(true);
+
+ }
+
+ @Test
+ public void testFromString() throws Exception {
+ RouteIdentifierImpl rId = new RouteIdentifierImpl();
+ rId.setType(QNAME);
+
+ _logger.debug("route: " + rId.fromString(rId.toString()));
+
+ Assert.assertTrue(true);
+ }
+
+ @Test(expected = JsonParseException.class)
+ public void testFromInvalidString() throws Exception {
+ String invalidInput = "aklhdgadfa;;;;;;;]]]]=]ag" ;
+ RouteIdentifierImpl rId = new RouteIdentifierImpl();
+ rId.fromString(invalidInput);
+
+ _logger.debug("" + rId);
+ Assert.assertTrue(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.sal.connector.remoterpc;
+
+import junit.framework.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.Message;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.MessageWrapper;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.zeromq.ZMQ;
+
+import java.util.concurrent.TimeoutException;
+
+import static org.mockito.Mockito.doNothing;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest(RpcSocket.class)
+public class RpcSocketTest {
+ RpcSocket rpcSocket = new RpcSocket("tcp://localhost:5554", new ZMQ.Poller(1));
+ RpcSocket spy = PowerMockito.spy(rpcSocket);
+
+ @Test
+ public void testCreateSocket() throws Exception {
+ Assert.assertEquals("tcp://localhost:5554", spy.getAddress());
+ Assert.assertEquals(ZMQ.REQ, spy.getSocket().getType());
+ }
+
+ @Test(expected = TimeoutException.class)
+ public void send_WhenQueueGetsFull_ShouldThrow() throws Exception {
+
+ doNothing().when(spy).process();
+
+ //10 is queue size
+ for (int i=0;i<10;i++){
+ spy.send(getEmptyMessageWrapper());
+ }
+
+ //sending 11th message should throw
+ spy.send(getEmptyMessageWrapper());
+ }
+
+ @Test
+ public void testHasTimedOut() throws Exception {
+ spy.send(getEmptyMessageWrapper());
+ Assert.assertFalse(spy.hasTimedOut());
+ Thread.sleep(1000);
+ Assert.assertFalse(spy.hasTimedOut());
+ Thread.sleep(1000);
+ Assert.assertTrue(spy.hasTimedOut());
+ }
+
+ @Test
+ public void testProcess() throws Exception {
+ PowerMockito.doNothing().when(spy, "sendMessage");
+ spy.send(getEmptyMessageWrapper());
+
+ //Next message should get queued
+ spy.send(getEmptyMessageWrapper());
+
+ //queue size should be 2
+ Assert.assertEquals(2, spy.getQueueSize());
+
+
+ spy.process();
+ //sleep for 2 secs (timeout)
+ //message send would be retried
+ Thread.sleep(2000);
+ spy.process();
+ Thread.sleep(2000);
+ spy.process();
+ Thread.sleep(2000);
+ spy.process(); //retry fails, next message will get picked up
+ Assert.assertEquals(1, spy.getQueueSize());
+ }
+
+ @Test
+ public void testProcessStateTransitions() throws Exception {
+ PowerMockito.doNothing().when(spy, "sendMessage");
+ Assert.assertTrue(spy.getState() instanceof RpcSocket.IdleSocketState);
+ spy.send(getEmptyMessageWrapper());
+ Assert.assertEquals(1, spy.getQueueSize());
+ Thread.sleep(200);
+ Assert.assertTrue(spy.getState() instanceof RpcSocket.BusySocketState);
+ Thread.sleep(1800);
+
+ //1st timeout, 2nd try
+ spy.process();
+ Thread.sleep(200);
+ Assert.assertTrue(spy.getState() instanceof RpcSocket.BusySocketState);
+ Thread.sleep(1800);
+
+ //2nd timeout, 3rd try
+ spy.process();
+ Thread.sleep(200);
+ Assert.assertTrue(spy.getState() instanceof RpcSocket.BusySocketState);
+ Thread.sleep(1800);
+
+ //3rd timeout, no more tries => remove
+ spy.process();
+ Thread.sleep(200);
+ Assert.assertTrue(spy.getState() instanceof RpcSocket.IdleSocketState);
+ Assert.assertEquals(0, spy.getQueueSize());
+ }
+
+ @Test
+ public void testParseMessage() throws Exception {
+ // Write an integration test for parseMessage
+ }
+
+ @Test
+ public void testRecycleSocket() throws Exception {
+ // This will need to be updated in the future...for now, recycleSocket() calls close()
+ Assert.assertTrue(spy.getSocket().base().check_tag());
+ spy.close();
+ Assert.assertEquals(10, spy.getSocket().getLinger());
+ Assert.assertFalse(spy.getSocket().base().check_tag());
+ }
+
+ @Test
+ public void testClose() throws Exception {
+ Assert.assertTrue(spy.getSocket().base().check_tag());
+ spy.close();
+ Assert.assertEquals(10, spy.getSocket().getLinger());
+ Assert.assertFalse(spy.getSocket().base().check_tag());
+ }
+
+ @Test
+ public void testReceive() throws Exception {
+ PowerMockito.doReturn(null).when(spy, "parseMessage");
+ PowerMockito.doNothing().when(spy, "process");
+ spy.send(getEmptyMessageWrapper());
+
+ //There should be 1 message waiting in the queue
+ Assert.assertEquals(1, spy.getQueueSize());
+
+ spy.receive();
+ //This should complete message processing
+ //The message should be removed from the queue
+ Assert.assertEquals(0, spy.getQueueSize());
+ Assert.assertEquals(RpcSocket.NUM_RETRIES, spy.getRetriesLeft());
+
+ }
+
+ @Test
+ public void testReceiveStateTransitions() throws Exception {
+ PowerMockito.doReturn(null).when(spy, "parseMessage");
+ Assert.assertTrue(spy.getState() instanceof RpcSocket.IdleSocketState);
+ spy.send(getEmptyMessageWrapper());
+
+ //There should be 1 message waiting in the queue
+ Assert.assertEquals(1, spy.getQueueSize());
+ Assert.assertTrue(spy.getState() instanceof RpcSocket.BusySocketState);
+
+ spy.receive();
+ //This should complete message processing
+ //The message should be removed from the queue
+ Assert.assertEquals(0, spy.getQueueSize());
+ Assert.assertTrue(spy.getState() instanceof RpcSocket.IdleSocketState);
+ }
+
+ private MessageWrapper getEmptyMessageWrapper(){
+ return new MessageWrapper(new Message(), null);
+ }
+
+ @Test
+ public void testProcessReceiveSequence() throws Exception {
+ PowerMockito.doNothing().when(spy, "sendMessage");
+ PowerMockito.doReturn(null).when(spy, "parseMessage");
+ Assert.assertTrue(spy.getState() instanceof RpcSocket.IdleSocketState);
+ spy.send(getEmptyMessageWrapper());
+ spy.send(getEmptyMessageWrapper());
+ Assert.assertEquals(2, spy.getQueueSize());
+ Assert.assertTrue(spy.getState() instanceof RpcSocket.BusySocketState);
+
+
+ Thread.sleep(2000);
+ Assert.assertTrue(spy.getState() instanceof RpcSocket.BusySocketState);
+ spy.receive();
+ Assert.assertTrue(spy.getState() instanceof RpcSocket.IdleSocketState);
+ Assert.assertEquals(1, spy.getQueueSize());
+
+ spy.process();
+ Assert.assertTrue(spy.getState() instanceof RpcSocket.BusySocketState);
+ spy.receive();
+ Assert.assertTrue(spy.getState() instanceof RpcSocket.IdleSocketState);
+ Assert.assertEquals(0, spy.getQueueSize());
+ }
+}
--- /dev/null
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.SimpleNode;
+import org.opendaylight.yangtools.yang.data.impl.NodeUtils;
+import org.opendaylight.yangtools.yang.data.impl.XmlTreeBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.StringWriter;
+
+public class SerilizationTest {
+
+ private static final Logger _logger = LoggerFactory.getLogger(SerilizationTest.class);
+
+ public void fromXml() {
+ }
+
+ @Test
+ public void toXml() throws FileNotFoundException {
+
+ InputStream xmlStream = SerilizationTest.class.getResourceAsStream("/FourSimpleChildren.xml");
+ StringWriter writer = new StringWriter();
+
+ CompositeNode data = loadCompositeNode(xmlStream);
+ Document domTree = NodeUtils.buildShadowDomTree(data);
+ try {
+ TransformerFactory tf = TransformerFactory.newInstance();
+ Transformer transformer = tf.newTransformer();
+ transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+ //transformer.setOutputProperty(OutputKeys.METHOD, "xml");
+ //transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ //transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+ //transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
+ transformer.transform(new DOMSource(domTree), new StreamResult(writer));
+ } catch (TransformerException e) {
+ _logger.error("Error during translation of Document to OutputStream", e);
+ }
+
+ _logger.info("Parsed xml [{}]", writer.toString());
+ }
+
+ //Note to self: Stolen from TestUtils
+ ///Users/alefan/odl/controller4/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java
+ // Figure out how to include TestUtils through pom ...was getting errors
+ private CompositeNode loadCompositeNode(InputStream xmlInputStream) throws FileNotFoundException {
+ if (xmlInputStream == null) {
+ throw new IllegalArgumentException();
+ }
+ Node<?> dataTree;
+ try {
+ dataTree = XmlTreeBuilder.buildDataTree(xmlInputStream);
+ } catch (XMLStreamException e) {
+ _logger.error("Error during building data tree from XML", e);
+ return null;
+ }
+ if (dataTree == null) {
+ _logger.error("data tree is null");
+ return null;
+ }
+ if (dataTree instanceof SimpleNode) {
+ _logger.error("RPC XML was resolved as SimpleNode");
+ return null;
+ }
+ return (CompositeNode) dataTree;
+ }
+}
--- /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.sal.connector.remoterpc;
+
+import com.google.common.base.Optional;
+import junit.framework.Assert;
+import org.junit.After;
+import org.junit.Before;
+import org.zeromq.ZMQ;
+import org.opendaylight.controller.sal.connector.remoterpc.SocketManager;
+import org.opendaylight.controller.sal.connector.remoterpc.RpcSocket;
+import org.opendaylight.controller.sal.connector.remoterpc.Context;
+import org.junit.Test;
+
+public class SocketManagerTest {
+
+ SocketManager manager;
+
+ @Before
+ public void setup(){
+ manager = new SocketManager();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ manager.close();
+ }
+
+ @Test
+ public void getManagedSockets_When2NewAdded_ShouldContain2() throws Exception {
+
+ //Prepare data
+ manager.getManagedSocket("tcp://localhost:5554");
+ manager.getManagedSocket("tcp://localhost:5555");
+
+ Assert.assertTrue( 2 == manager.getManagedSockets().size());
+ }
+
+ @Test
+ public void getManagedSockets_When2NewAddedAnd1Existing_ShouldContain2() throws Exception {
+
+ //Prepare data
+ manager.getManagedSocket("tcp://localhost:5554");
+ manager.getManagedSocket("tcp://localhost:5555");
+ manager.getManagedSocket("tcp://localhost:5554"); //ask for the first one
+
+ Assert.assertTrue( 2 == manager.getManagedSockets().size());
+ }
+
+ @Test
+ public void getManagedSocket_WhenPassedAValidAddress_ShouldReturnARpcSocket() throws Exception {
+ String testAddress = "tcp://localhost:5554";
+ RpcSocket rpcSocket = manager.getManagedSocket(testAddress);
+ Assert.assertEquals(testAddress, rpcSocket.getAddress());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void getManagedSocket_WhenPassedInvalidHostAddress_ShouldThrow() throws Exception {
+ String testAddress = "tcp://nonexistenthost:5554";
+ RpcSocket rpcSocket = manager.getManagedSocket(testAddress);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void getManagedSocket_WhenPassedInvalidAddress_ShouldThrow() throws Exception {
+ String testAddress = "xxx";
+ RpcSocket rpcSocket = manager.getManagedSocket(testAddress);
+ }
+
+ @Test
+ public void getManagedSocket_WhenPassedAValidZmqSocket_ShouldReturnARpcSocket() throws Exception {
+ //Prepare data
+ String firstAddress = "tcp://localhost:5554";
+ RpcSocket firstRpcSocket = manager.getManagedSocket(firstAddress);
+ ZMQ.Socket firstZmqSocket = firstRpcSocket.getSocket();
+
+ String secondAddress = "tcp://localhost:5555";
+ RpcSocket secondRpcSocket = manager.getManagedSocket(secondAddress);
+ ZMQ.Socket secondZmqSocket = secondRpcSocket.getSocket();
+
+ Assert.assertEquals(firstRpcSocket, manager.getManagedSocketFor(firstZmqSocket).get());
+ Assert.assertEquals(secondRpcSocket, manager.getManagedSocketFor(secondZmqSocket).get());
+ }
+
+ @Test
+ public void getManagedSocket_WhenPassedNonManagedZmqSocket_ShouldReturnNone() throws Exception {
+ ZMQ.Socket nonManagedSocket = Context.getInstance().getZmqContext().socket(ZMQ.REQ);
+ nonManagedSocket.connect("tcp://localhost:5000");
+
+ //Prepare data
+ String firstAddress = "tcp://localhost:5554";
+ RpcSocket firstRpcSocket = manager.getManagedSocket(firstAddress);
+ ZMQ.Socket firstZmqSocket = firstRpcSocket.getSocket();
+
+ Assert.assertSame(Optional.<RpcSocket>absent(), manager.getManagedSocketFor(nonManagedSocket) );
+ Assert.assertSame(Optional.<RpcSocket>absent(), manager.getManagedSocketFor(null) );
+ }
+
+ @Test
+ public void stop_WhenCalled_ShouldEmptyManagedSockets() throws Exception {
+ manager.getManagedSocket("tcp://localhost:5554");
+ manager.getManagedSocket("tcp://localhost:5555");
+ Assert.assertTrue( 2 == manager.getManagedSockets().size());
+
+ manager.close();
+ Assert.assertTrue( 0 == manager.getManagedSockets().size());
+ }
+
+ @Test
+ public void poller_WhenCalled_ShouldReturnAnInstanceOfPoller() throws Exception {
+ Assert.assertTrue (manager.getPoller() instanceof ZMQ.Poller);
+ }
+
+}
--- /dev/null
+<rpc>
+ <name>eth0</name>
+ <type>ethernetCsmacd</type>
+ <enabled>false</enabled>
+ <description>some interface</description>
+</rpc>
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>sal-test-parent</artifactId>
+ <artifactId>sal-remoterpc-connector-test-parent</artifactId>
<groupId>org.opendaylight.controller.tests</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
- <artifactId>zeromq-test-consumer</artifactId>
+ <artifactId>sal-remoterpc-connector-test-consumer</artifactId>
<packaging>bundle</packaging>
<scm>
<connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
<configuration>
<instructions>
<Bundle-Activator>org.opendaylight.controller.sample.zeromq.consumer.ExampleConsumer</Bundle-Activator>
- <Import-Package>
- org.opendaylight.controller.sal.core.api,
- org.opendaylight.yangtools.yang.common;version="[0.5,1)",
- org.opendaylight.yangtools.yang.data.api,
- </Import-Package>
</instructions>
</configuration>
</plugin>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-data-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-impl</artifactId>
+ <version>0.5.9-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
--- /dev/null
+package org.opendaylight.controller.sample.zeromq.consumer;
+
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.Hashtable;
+import java.util.concurrent.*;
+
+import org.opendaylight.controller.sal.core.api.AbstractConsumer;
+import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.SimpleNode;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.opendaylight.yangtools.yang.data.impl.XmlTreeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
+
+import javax.xml.stream.XMLStreamException;
+
+public class ExampleConsumer extends AbstractConsumer {
+
+ private final URI namespace = URI.create("http://cisco.com/example");
+ private final QName QNAME = new QName(namespace, "heartbeat");
+
+ private ConsumerSession session;
+
+ private ServiceRegistration<ExampleConsumer> thisReg;
+ private Logger _logger = LoggerFactory.getLogger(ExampleConsumer.class);
+
+ @Override
+ public void onSessionInitiated(ConsumerSession session) {
+ this.session = session;
+ }
+
+ public RpcResult<CompositeNode> invokeRpc(QName qname, CompositeNode input) {
+ _logger.info("Invoking RPC:[{}] with Input:[{}]", qname.getLocalName(), input);
+ RpcResult<CompositeNode> result = null;
+ Future<RpcResult<CompositeNode>> future = ExampleConsumer.this.session.rpc(qname, input);
+ try {
+ result = future.get();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ _logger.info("Returning Result:[{}]", result);
+ return result;
+ }
+
+ @Override
+ protected void startImpl(BundleContext context){
+ thisReg = context.registerService(ExampleConsumer.class, this, new Hashtable<String,String>());
+ }
+ @Override
+ protected void stopImpl(BundleContext context) {
+ super.stopImpl(context);
+ thisReg.unregister();
+ }
+
+ public CompositeNode getValidCompositeNodeWithOneSimpleChild() throws FileNotFoundException {
+ InputStream xmlStream = ExampleConsumer.class.getResourceAsStream("/OneSimpleChild.xml");
+ return loadCompositeNode(xmlStream);
+ }
+
+ public CompositeNode getValidCompositeNodeWithTwoSimpleChildren() throws FileNotFoundException {
+ InputStream xmlStream = ExampleConsumer.class.getResourceAsStream("/TwoSimpleChildren.xml");
+ return loadCompositeNode(xmlStream);
+ }
+
+ public CompositeNode getValidCompositeNodeWithFourSimpleChildren() throws FileNotFoundException {
+ InputStream xmlStream = ExampleConsumer.class.getResourceAsStream("/FourSimpleChildren.xml");
+ return loadCompositeNode(xmlStream);
+ }
+
+ public CompositeNode getValidCompositeNodeWithOneSimpleOneCompositeChild() throws FileNotFoundException {
+ InputStream xmlStream = ExampleConsumer.class.getResourceAsStream("/OneSimpleOneCompositeChild.xml");
+ return loadCompositeNode(xmlStream);
+ }
+
+ public CompositeNode getValidCompositeNodeWithTwoCompositeChildren() throws FileNotFoundException {
+ InputStream xmlStream = ExampleConsumer.class.getResourceAsStream("/TwoCompositeChildren.xml");
+ return loadCompositeNode(xmlStream);
+ }
+
+ public CompositeNode getInvalidCompositeNodeSimpleChild() throws FileNotFoundException {
+ InputStream xmlStream = ExampleConsumer.class.getResourceAsStream("/InvalidSimpleChild.xml");
+ return loadCompositeNode(xmlStream);
+ }
+
+ public CompositeNode getInvalidCompositeNodeCompositeChild() throws FileNotFoundException {
+ InputStream xmlStream = ExampleConsumer.class.getResourceAsStream("/InvalidCompositeChild.xml");
+ return loadCompositeNode(xmlStream);
+ }
+
+ //Note to self: Stolen from TestUtils
+ ///Users/alefan/odl/controller4/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java
+ // Figure out how to include TestUtils through pom ...was getting errors
+ private CompositeNode loadCompositeNode(InputStream xmlInputStream) throws FileNotFoundException {
+ if (xmlInputStream == null) {
+ throw new IllegalArgumentException();
+ }
+ Node<?> dataTree;
+ try {
+ dataTree = XmlTreeBuilder.buildDataTree(xmlInputStream);
+ } catch (XMLStreamException e) {
+ _logger.error("Error during building data tree from XML", e);
+ return null;
+ }
+ if (dataTree == null) {
+ _logger.error("data tree is null");
+ return null;
+ }
+ if (dataTree instanceof SimpleNode) {
+ _logger.error("RPC XML was resolved as SimpleNode");
+ return null;
+ }
+ return (CompositeNode) dataTree;
+ }
+}
--- /dev/null
+<rpc>
+ <name>eth0</name>
+ <type>ethernetCsmacd</type>
+ <enabled>false</enabled>
+ <description>some interface</description>
+</rpc>
--- /dev/null
+<rpc>
+ <innerinterface1>
+ <name>eth1</name>
+ <type>ethernet</type>
+ <enabled>false</enabled>
+ <description>some interface</description>
+ </innerinterface1>
+ <innerinterface2>
+ <name>error</name>
+ <type>ethernet</type>
+ <enabled>true</enabled>
+ <description>some interface</description>
+ </innerinterface2>
+</rpc>
--- /dev/null
+<rpc>
+ <name>error</name>
+</rpc>
--- /dev/null
+<rpc>
+ <name>eth0</name>
+</rpc>
--- /dev/null
+<rpc>
+ <name>eth0</name>
+ <innerinterface>
+ <name>eth1</name>
+ <type>ethernetCsmacd</type>
+ <enabled>false</enabled>
+ <description>some interface</description>
+ </innerinterface>
+</rpc>
--- /dev/null
+<rpc>
+ <innerinterface1>
+ <name>eth1</name>
+ <type>ethernet</type>
+ <enabled>false</enabled>
+ <description>some interface</description>
+ </innerinterface1>
+ <innerinterface2>
+ <name>eth2</name>
+ <type>ethernet</type>
+ <enabled>true</enabled>
+ <description>some interface</description>
+ </innerinterface2>
+</rpc>
--- /dev/null
+<rpc>
+ <name>eth0</name>
+ <type>ethernetCsmacd</type>
+</rpc>
\ No newline at end of file
--- /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>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-parent</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <relativePath>../..</relativePath>
+ </parent>
+ <packaging>pom</packaging>
+ <groupId>org.opendaylight.controller.tests</groupId>
+ <artifactId>sal-remoterpc-connector-test-parent</artifactId>
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
+ </scm>
+
+ <modules>
+ <module>consumer-service</module>
+ <module>provider-service</module>
+ <module>test-it</module>
+ <module>test-nb</module>
+ </modules>
+
+</project>
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>sal-test-parent</artifactId>
+ <artifactId>sal-remoterpc-connector-test-parent</artifactId>
<groupId>org.opendaylight.controller.tests</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
- <artifactId>zeromq-test-provider</artifactId>
+ <artifactId>sal-remoterpc-connector-test-provider</artifactId>
<packaging>bundle</packaging>
<scm>
<connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-data-api</artifactId>
</dependency>
-
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-impl</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-util</artifactId>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-zeromq-connector</artifactId>
+ <artifactId>sal-remoterpc-connector</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
--- /dev/null
+package org.opendaylight.controller.sample.zeromq.provider;
+
+import org.opendaylight.controller.sal.common.util.RpcErrors;
+import org.opendaylight.controller.sal.common.util.Rpcs;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.CompositeNodeImpl;
+import org.opendaylight.controller.sal.core.api.AbstractProvider;
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
+import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.URI;
+import java.util.*;
+
+public class ExampleProvider extends AbstractProvider implements RpcImplementation {
+
+ private final URI namespace = URI.create("http://cisco.com/example");
+ private final QName QNAME = new QName(namespace, "heartbeat");
+ private RpcRegistration reg;
+
+ private ServiceRegistration thisReg;
+
+ private ProviderSession session;
+ private Logger _logger = LoggerFactory.getLogger(ExampleProvider.class);
+
+ @Override
+ public void onSessionInitiated(ProviderSession session) {
+ this.session = session;
+ }
+
+ @Override
+ public Set<QName> getSupportedRpcs() {
+ Set<QName> supportedRpcs = new HashSet<QName>();
+ supportedRpcs.add(QNAME);
+ return supportedRpcs;
+ }
+
+ @Override
+ public RpcResult<CompositeNode> invokeRpc(final QName rpc, CompositeNode input) {
+ boolean success = false;
+ CompositeNode output = null;
+ Collection<RpcError> errors = new ArrayList<>();
+
+ // Only handle supported RPC calls
+ if (getSupportedRpcs().contains(rpc)) {
+ if (input == null) {
+ errors.add(RpcErrors.getRpcError("app", "tag", "info", RpcError.ErrorSeverity.WARNING, "message:null input", RpcError.ErrorType.RPC, null));
+ }
+ else {
+ if (isErroneousInput(input)) {
+ errors.add(RpcErrors.getRpcError("app", "tag", "info", RpcError.ErrorSeverity.ERROR, "message:error", RpcError.ErrorType.RPC, null));
+ }
+ else {
+ success = true;
+ output = addSuccessNode(input);
+ }
+ }
+ }
+ return Rpcs.getRpcResult(success, output, errors);
+ }
+
+ // Examines input -- dives into CompositeNodes and finds any value equal to "error"
+ private boolean isErroneousInput(CompositeNode input) {
+ for (Node<?> n : input.getChildren()) {
+ if (n instanceof CompositeNode) {
+ if (isErroneousInput((CompositeNode)n)) {
+ return true;
+ }
+ }
+ else { //SimpleNode
+ if ((input.getChildren().get(0).getValue()).equals("error")) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ // Adds a child SimpleNode containing the value "success" to the input CompositeNode
+ private CompositeNode addSuccessNode(CompositeNode input) {
+ List<Node<?>> list = new ArrayList<Node<?>>(input.getChildren());
+ SimpleNodeTOImpl<String> simpleNode = new SimpleNodeTOImpl<String>(QNAME, input, "success");
+ list.add(simpleNode);
+ return new CompositeNodeTOImpl(QNAME, null, list);
+ }
+
+ @Override
+ protected void startImpl(BundleContext context) {
+ thisReg = context.registerService(ExampleProvider.class, this, new Hashtable<String, String>());
+ }
+
+ @Override
+ protected void stopImpl(BundleContext context) {
+ if (reg != null) {
+ try {
+ reg.close();
+ thisReg.unregister();
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public void announce(QName name) {
+ _logger.debug("Announcing [{}]\n\n\n", name);
+ reg = this.session.addRpcImplementation(name, this);
+ }
+
+}
--- /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>sal-remoterpc-connector-test-parent</artifactId>
+ <groupId>org.opendaylight.controller.tests</groupId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>sal-remoterpc-connector-test-it</artifactId>
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
+ </scm>
+
+ <properties>
+ <exam.version>3.0.0</exam.version>
+ <url.version>1.5.0</url.version>
+ <config.version>0.2.3-SNAPSHOT</config.version>
+ <netconf.version>0.2.3-SNAPSHOT</netconf.version>
+ </properties>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>commons-codec</groupId>
+ <artifactId>commons-codec</artifactId>
+ <version>1.7</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>maven-paxexam-plugin</artifactId>
+ <version>1.2.4</version>
+ <executions>
+ <execution>
+ <id>generate-config</id>
+ <goals>
+ <goal>generate-depends-file</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ <pluginManagement>
+ <plugins>
+ <!--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.ops4j.pax.exam
+ </groupId>
+ <artifactId>
+ maven-paxexam-plugin
+ </artifactId>
+ <versionRange>
+ [1.2.4,)
+ </versionRange>
+ <goals>
+ <goal>
+ generate-depends-file
+ </goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <ignore></ignore>
+ </action>
+ </pluginExecution>
+ </pluginExecutions>
+ </lifecycleMappingMetadata>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.thirdparty</groupId>
+ <artifactId>xtend-lib-osgi</artifactId>
+ <version>2.4.3</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller.tests</groupId>
+ <artifactId>sal-remoterpc-connector-test-provider</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller.tests</groupId>
+ <artifactId>sal-remoterpc-connector-test-consumer</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-broker-impl</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-container-native</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-junit4</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-link-mvn</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-aether</artifactId>
+ <version>1.5.2</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>equinoxSDK381</groupId>
+ <artifactId>org.eclipse.osgi</artifactId>
+ <version>3.8.1.v20120830-144521</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>log4j-over-slf4j</artifactId>
+ <version>1.7.2</version>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-core</artifactId>
+ <version>1.0.9</version>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>1.0.9</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-api</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-common-util</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-core-api</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-remoterpc-connector</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>containermanager</artifactId>
+ <version>0.5.1-SNAPSHOT</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </exclusion>
+ <exclusion>
+ <artifactId>commons-io</artifactId>
+ <groupId>commons-io</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-binding</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-api</artifactId>
+ </dependency>
+ <!--dependency> <groupId>org.opendaylight.yangtools</groupId> <artifactId>yang-data-impl</artifactId>
+ <version>0.5.9-SNAPSHOT</version> </dependency -->
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-parser-impl</artifactId>
+ <version>0.5.9-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-common-util</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.thirdparty</groupId>
+ <artifactId>antlr4-runtime-osgi-nohead</artifactId>
+ <version>4.0</version>
+ </dependency>
+
+ <!-- routing table dependencies -->
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>zeromq-routingtable.implementation</artifactId>
+ <version>0.4.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>clustering.services</artifactId>
+ <version>0.4.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal</artifactId>
+ <version>0.5.1-SNAPSHOT</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal.implementation</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ <exclusions>
+ <exclusion>
+ <artifactId>commons-io</artifactId>
+ <groupId>commons-io</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>containermanager</artifactId>
+ <version>0.5.0-SNAPSHOT</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </exclusion>
+ <exclusion>
+ <artifactId>commons-io</artifactId>
+ <groupId>commons-io</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>containermanager.it.implementation</artifactId>
+ <version>0.5.0-SNAPSHOT</version>
+ <exclusions>
+ <exclusion>
+ <artifactId>commons-io</artifactId>
+ <groupId>commons-io</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>clustering.stub</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ <exclusions>
+ <exclusion>
+ <artifactId>commons-io</artifactId>
+ <groupId>commons-io</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.dependencymanager.shell</artifactId>
+ <version>3.0.1</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>eclipselink</groupId>
+ <artifactId>javax.resource</artifactId>
+ <version>1.5.0.v200906010428</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal</artifactId>
+ <version>0.5.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>ietf-netconf-monitoring</artifactId>
+ <version>${netconf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-binding</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>yang-ext</artifactId>
+ <version>2013.09.07.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>opendaylight-l2-types</artifactId>
+ <version>2013.08.27.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-it</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-config</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-broker-impl</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-broker-impl</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.opendaylight.controller.model</groupId>
+ <artifactId>model-inventory</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-connector-api</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-common-util</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>clustering.services</artifactId>
+ <version>0.4.1-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>equinoxSDK381</groupId>
+ <artifactId>org.eclipse.osgi</artifactId>
+ <version>3.8.1.v20120830-144521</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-mapper-asl</artifactId>
+ <version>1.9.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-core-asl</artifactId>
+ <version>1.9.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.zeromq</groupId>
+ <artifactId>jeromq</artifactId>
+ <version>0.3.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.thirdparty</groupId>
+ <artifactId>xtend-lib-osgi</artifactId>
+ <version>2.4.3</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-broker-impl</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-container-native</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-junit4</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-netconf-connector</artifactId>
+ <version>${netconf.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>yang-store-impl</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>logback-config</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-persister-impl</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-persister-file-adapter</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-impl</artifactId>
+ <version>${netconf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-client</artifactId>
+ <version>${netconf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam</artifactId>
+ <version>${exam.version}</version>
+ <!-- Compile scope here is intentional, it is used in TestHelper
+ class which could be downloaded via nexus and reused in other integration
+ tests. -->
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-link-mvn</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>equinoxSDK381</groupId>
+ <artifactId>org.eclipse.osgi</artifactId>
+ <version>3.8.1.v20120830-144521</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>log4j-over-slf4j</artifactId>
+ <version>1.7.2</version>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-core</artifactId>
+ <version>1.0.9</version>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>1.0.9</version>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller.model</groupId>
+ <artifactId>model-flow-service</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-manager</artifactId>
+ <version>0.2.3-SNAPSHOT</version>
+ <exclusions>
+ <exclusion>
+ <artifactId>commons-io</artifactId>
+ <groupId>commons-io</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller.model</groupId>
+ <artifactId>model-flow-management</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.thirdparty</groupId>
+ <artifactId>antlr4-runtime-osgi-nohead</artifactId>
+ <version>4.0</version>
+ </dependency>
+ </dependencies>
+</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.sample.zeromq.test.it;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.opendaylight.controller.sal.connector.remoterpc.Client;
+import org.opendaylight.controller.sal.connector.remoterpc.RemoteRpcClient;
+import org.opendaylight.controller.sal.connector.remoterpc.RemoteRpcServer;
+import org.opendaylight.controller.sal.connector.remoterpc.ServerImpl;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.Message;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.controller.sample.zeromq.provider.ExampleProvider;
+import org.opendaylight.controller.sample.zeromq.consumer.ExampleConsumer;
+import org.opendaylight.controller.test.sal.binding.it.TestHelper;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.util.Filter;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.zeromq.ZMQ;
+
+import javax.inject.Inject;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.Hashtable;
+
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.baseModelBundles;
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.bindingAwareSalBundles;
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.configMinumumBundles;
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.mdSalCoreBundles;
+import static org.ops4j.pax.exam.CoreOptions.*;
+
+@RunWith(PaxExam.class)
+public class RouterTest {
+
+ private Logger _logger = LoggerFactory.getLogger(RouterTest.class);
+
+ public static final String ODL = "org.opendaylight.controller";
+ public static final String YANG = "org.opendaylight.yangtools";
+ public static final String SAMPLE = "org.opendaylight.controller.tests";
+ private final URI namespace = URI.create("http://cisco.com/example");
+ private final QName QNAME = new QName(namespace, "heartbeat");
+
+
+ @Inject
+ org.osgi.framework.BundleContext ctx;
+
+ @Inject
+ @Filter(timeout=60*1000)
+ Broker broker;
+
+ private ZMQ.Context zmqCtx = ZMQ.context(1);
+ //private Server router;
+ //private ExampleProvider provider;
+
+ //@Test
+ public void testInvokeRpc() throws Exception{
+ //Thread.sleep(1000);
+ //Send announcement
+ ServiceReference providerRef = ctx.getServiceReference(ExampleProvider.class);
+ Assert.assertNotNull(providerRef);
+
+ ExampleProvider provider = (ExampleProvider)ctx.getService(providerRef);
+ Assert.assertNotNull(provider);
+
+ ServiceReference consumerRef = ctx.getServiceReference(ExampleConsumer.class);
+ Assert.assertNotNull(consumerRef);
+ ExampleConsumer consumer = (ExampleConsumer)ctx.getService(consumerRef);
+ Assert.assertNotNull(consumer);
+
+
+ _logger.debug("Provider sends announcement [{}]", "heartbeat");
+ provider.announce(QNAME);
+ ServiceReference routerRef = ctx.getServiceReference(Client.class);
+ Client router = (Client) ctx.getService(routerRef);
+ _logger.debug("Found router[{}]", router);
+ _logger.debug("Invoking RPC [{}]", QNAME);
+ for (int i = 0; i < 3; i++) {
+ RpcResult<CompositeNode> result = router.invokeRpc(QNAME, consumer.getValidCompositeNodeWithOneSimpleChild());
+ _logger.debug("{}-> Result is: Successful:[{}], Payload:[{}], Errors: [{}]", i, result.isSuccessful(), result.getResult(), result.getErrors());
+ Assert.assertNotNull(result);
+ }
+ }
+
+ @Test
+ public void testInvokeRpcWithValidSimpleNode() throws Exception{
+ //Thread.sleep(1500);
+
+ ServiceReference providerRef = ctx.getServiceReference(ExampleProvider.class);
+ Assert.assertNotNull(providerRef);
+ ExampleProvider provider = (ExampleProvider)ctx.getService(providerRef);
+ Assert.assertNotNull(provider);
+ ServiceReference consumerRef = ctx.getServiceReference(ExampleConsumer.class);
+ Assert.assertNotNull(consumerRef);
+ ExampleConsumer consumer = (ExampleConsumer)ctx.getService(consumerRef);
+ Assert.assertNotNull(consumer);
+
+ // Provider sends announcement
+ _logger.debug("Provider sends announcement [{}]", "heartbeat");
+ provider.announce(QNAME);
+ // Consumer invokes RPC
+ _logger.debug("Invoking RPC [{}]", QNAME);
+ CompositeNode input = consumer.getValidCompositeNodeWithOneSimpleChild();
+ for (int i = 0; i < 3; i++) {
+ RpcResult<CompositeNode> result = consumer.invokeRpc(QNAME, input);
+ Assert.assertNotNull(result);
+ _logger.debug("{}-> Result is: Successful:[{}], Payload:[{}], Errors: [{}]", i, result.isSuccessful(), result.getResult(), result.getErrors());
+ Assert.assertTrue(result.isSuccessful());
+ Assert.assertNotNull(result.getResult());
+ Assert.assertEquals(0, result.getErrors().size());
+ Assert.assertEquals(input.getChildren().size()+1, result.getResult().getChildren().size());
+ }
+ }
+
+ @Test
+ public void testInvokeRpcWithValidSimpleNodes() throws Exception{
+ //Thread.sleep(1500);
+
+ ServiceReference providerRef = ctx.getServiceReference(ExampleProvider.class);
+ Assert.assertNotNull(providerRef);
+ ExampleProvider provider = (ExampleProvider)ctx.getService(providerRef);
+ Assert.assertNotNull(provider);
+ ServiceReference consumerRef = ctx.getServiceReference(ExampleConsumer.class);
+ Assert.assertNotNull(consumerRef);
+ ExampleConsumer consumer = (ExampleConsumer)ctx.getService(consumerRef);
+ Assert.assertNotNull(consumer);
+
+ // Provider sends announcement
+ _logger.debug("Provider sends announcement [{}]", "heartbeat");
+ provider.announce(QNAME);
+ // Consumer invokes RPC
+ _logger.debug("Invoking RPC [{}]", QNAME);
+ CompositeNode input = consumer.getValidCompositeNodeWithFourSimpleChildren();
+ for (int i = 0; i < 3; i++) {
+ RpcResult<CompositeNode> result = consumer.invokeRpc(QNAME, input);
+ Assert.assertNotNull(result);
+ _logger.debug("{}-> Result is: Successful:[{}], Payload:[{}], Errors: [{}]", i, result.isSuccessful(), result.getResult(), result.getErrors());
+ Assert.assertTrue(result.isSuccessful());
+ Assert.assertNotNull(result.getResult());
+ Assert.assertEquals(0, result.getErrors().size());
+ Assert.assertEquals(input.getChildren().size()+1, result.getResult().getChildren().size());
+ }
+ }
+
+ @Test
+ public void testInvokeRpcWithValidCompositeNode() throws Exception{
+ //Thread.sleep(1500);
+
+ ServiceReference providerRef = ctx.getServiceReference(ExampleProvider.class);
+ Assert.assertNotNull(providerRef);
+ ExampleProvider provider = (ExampleProvider)ctx.getService(providerRef);
+ Assert.assertNotNull(provider);
+ ServiceReference consumerRef = ctx.getServiceReference(ExampleConsumer.class);
+ Assert.assertNotNull(consumerRef);
+ ExampleConsumer consumer = (ExampleConsumer)ctx.getService(consumerRef);
+ Assert.assertNotNull(consumer);
+
+ // Provider sends announcement
+ _logger.debug("Provider sends announcement [{}]", "heartbeat");
+ provider.announce(QNAME);
+ // Consumer invokes RPC
+ _logger.debug("Invoking RPC [{}]", QNAME);
+ CompositeNode input = consumer.getValidCompositeNodeWithTwoCompositeChildren();
+ for (int i = 0; i < 3; i++) {
+ RpcResult<CompositeNode> result = consumer.invokeRpc(QNAME, input);
+ Assert.assertNotNull(result);
+ _logger.debug("{}-> Result is: Successful:[{}], Payload:[{}], Errors: [{}]", i, result.isSuccessful(), result.getResult(), result.getErrors());
+ Assert.assertTrue(result.isSuccessful());
+ Assert.assertNotNull(result.getResult());
+ Assert.assertEquals(0, result.getErrors().size());
+ Assert.assertEquals(input.getChildren().size()+1, result.getResult().getChildren().size());
+ }
+ }
+
+ @Test
+ public void testInvokeRpcWithNullInput() throws Exception{
+ //Thread.sleep(1500);
+
+ ServiceReference providerRef = ctx.getServiceReference(ExampleProvider.class);
+ Assert.assertNotNull(providerRef);
+ ExampleProvider provider = (ExampleProvider)ctx.getService(providerRef);
+ Assert.assertNotNull(provider);
+ ServiceReference consumerRef = ctx.getServiceReference(ExampleConsumer.class);
+ Assert.assertNotNull(consumerRef);
+ ExampleConsumer consumer = (ExampleConsumer)ctx.getService(consumerRef);
+ Assert.assertNotNull(consumer);
+
+ // Provider sends announcement
+ _logger.debug("Provider sends announcement [{}]", QNAME.getLocalName());
+ provider.announce(QNAME);
+ // Consumer invokes RPC
+ _logger.debug("Invoking RPC [{}]", QNAME);
+ for (int i = 0; i < 3; i++) {
+ RpcResult<CompositeNode> result = consumer.invokeRpc(QNAME, null);
+ Assert.assertNotNull(result);
+ _logger.debug("{}-> Result is: Successful:[{}], Payload:[{}], Errors: [{}]", i, result.isSuccessful(), result.getResult(), result.getErrors());
+ Assert.assertFalse(result.isSuccessful());
+ Assert.assertNull(result.getResult());
+ Assert.assertEquals(1, result.getErrors().size());
+ Assert.assertEquals(RpcError.ErrorSeverity.WARNING, ((RpcError)result.getErrors().toArray()[0]).getSeverity());
+ }
+ }
+
+ @Test
+ public void testInvokeRpcWithInvalidSimpleNode() throws Exception{
+ //Thread.sleep(1500);
+
+ ServiceReference providerRef = ctx.getServiceReference(ExampleProvider.class);
+ Assert.assertNotNull(providerRef);
+ ExampleProvider provider = (ExampleProvider)ctx.getService(providerRef);
+ Assert.assertNotNull(provider);
+ ServiceReference consumerRef = ctx.getServiceReference(ExampleConsumer.class);
+ Assert.assertNotNull(consumerRef);
+ ExampleConsumer consumer = (ExampleConsumer)ctx.getService(consumerRef);
+ Assert.assertNotNull(consumer);
+
+ // Provider sends announcement
+ _logger.debug("Provider sends announcement [{}]", QNAME.getLocalName());
+ provider.announce(QNAME);
+ // Consumer invokes RPC
+ _logger.debug("Invoking RPC [{}]", QNAME);
+ CompositeNode input = consumer.getInvalidCompositeNodeSimpleChild();
+ for (int i = 0; i < 3; i++) {
+ RpcResult<CompositeNode> result = consumer.invokeRpc(QNAME, input);
+ Assert.assertNotNull(result);
+ _logger.debug("{}-> Result is: Successful:[{}], Payload:[{}], Errors: [{}]", i, result.isSuccessful(), result.getResult(), result.getErrors());
+ Assert.assertFalse(result.isSuccessful());
+ Assert.assertNull(result.getResult());
+ Assert.assertEquals(1, result.getErrors().size());
+ Assert.assertEquals(RpcError.ErrorSeverity.ERROR, ((RpcError)result.getErrors().toArray()[0]).getSeverity());
+ }
+ }
+
+ @Test
+ public void testInvokeRpcWithInvalidCompositeNode() throws Exception{
+ //Thread.sleep(1500);
+
+ ServiceReference providerRef = ctx.getServiceReference(ExampleProvider.class);
+ Assert.assertNotNull(providerRef);
+ ExampleProvider provider = (ExampleProvider)ctx.getService(providerRef);
+ Assert.assertNotNull(provider);
+ ServiceReference consumerRef = ctx.getServiceReference(ExampleConsumer.class);
+ Assert.assertNotNull(consumerRef);
+ ExampleConsumer consumer = (ExampleConsumer)ctx.getService(consumerRef);
+ Assert.assertNotNull(consumer);
+
+ // Provider sends announcement
+ _logger.debug("Provider sends announcement [{}]", QNAME.getLocalName());
+ provider.announce(QNAME);
+ // Consumer invokes RPC
+ _logger.debug("Invoking RPC [{}]", QNAME);
+ CompositeNode input = consumer.getInvalidCompositeNodeCompositeChild();
+ for (int i = 0; i < 3; i++) {
+ RpcResult<CompositeNode> result = consumer.invokeRpc(QNAME, input);
+ Assert.assertNotNull(result);
+ _logger.debug("{}-> Result is: Successful:[{}], Payload:[{}], Errors: [{}]", i, result.isSuccessful(), result.getResult(), result.getErrors());
+ Assert.assertFalse(result.isSuccessful());
+ Assert.assertNull(result.getResult());
+ Assert.assertEquals(1, result.getErrors().size());
+ Assert.assertEquals(RpcError.ErrorSeverity.ERROR, ((RpcError)result.getErrors().toArray()[0]).getSeverity());
+ }
+ }
+
+ //@Test
+ // This method is UNTESTED -- need to get around the bundling issues before I know if this even work
+// public void testInvokeRpcWithValidCompositeNode() throws Exception{
+// Thread.sleep(10000);
+// //Send announcement
+// ServiceReference providerRef = ctx.getServiceReference(ExampleProvider.class);
+// Assert.assertNotNull(providerRef);
+//
+// ExampleProvider provider = (ExampleProvider)ctx.getService(providerRef);
+// Assert.assertNotNull(provider);
+//
+// ServiceReference consumerRef = ctx.getServiceReference(ExampleConsumer.class);
+// Assert.assertNotNull(consumerRef);
+//
+// ExampleConsumer consumer = (ExampleConsumer)ctx.getService(consumerRef);
+// Assert.assertNotNull(consumer);
+//
+// _logger.debug("Provider sends announcement [{}]", "heartbeat");
+// provider.announce(QNAME);
+// ServiceReference routerRef = ctx.getServiceReference(Client.class);
+// Client router = (Client) ctx.getService(routerRef);
+// _logger.debug("Found router[{}]", router);
+// _logger.debug("Invoking RPC [{}]", QNAME);
+// for (int i = 0; i < 3; i++) {
+// RpcResult<CompositeNode> result = router.getInstance().invokeRpc(QNAME, consumer.getValidCompositeNodeWithOneSimpleChild());
+// _logger.debug("{}-> Result is: Successful:[{}], Payload:[{}], Errors: [{}]", i, result.isSuccessful(), result.getResult(), result.getErrors());
+// Assert.assertNotNull(result);
+// }
+// }
+
+ private Message send(Message msg) throws IOException {
+ ZMQ.Socket reqSocket = zmqCtx.socket(ZMQ.REQ);
+ reqSocket.connect("tcp://localhost:5555");
+ reqSocket.send(Message.serialize(msg));
+ Message response = parseMessage(reqSocket);
+
+ return response;
+ }
+
+ /**
+ * @param socket
+ * @return
+ */
+ private Message parseMessage(ZMQ.Socket socket) {
+
+ Message msg = null;
+ try {
+ byte[] bytes = socket.recv();
+ _logger.debug("Received bytes:[{}]", bytes.length);
+ msg = (Message) Message.deserialize(bytes);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ return msg;
+ }
+
+
+ private void printState(){
+ Bundle[] b = ctx.getBundles();
+ _logger.debug("\n\nNumber of bundles [{}]\n\n]", b.length);
+ for (int i=0;i<b.length;i++){
+ _logger.debug("Bundle States {}-{} ",b[i].getSymbolicName(), stateToString(b[i].getState()));
+
+ if ( Bundle.INSTALLED == b[i].getState() || (Bundle.RESOLVED == b[i].getState())){
+ try {
+ b[i].start();
+ } catch (BundleException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ private String stateToString(int state) {
+ switch (state) {
+ case Bundle.ACTIVE:
+ return "ACTIVE";
+ case Bundle.INSTALLED:
+ return "INSTALLED";
+ case Bundle.RESOLVED:
+ return "RESOLVED";
+ case Bundle.UNINSTALLED:
+ return "UNINSTALLED";
+ default:
+ return "Not CONVERTED";
+ }
+ }
+
+ @Configuration
+ public Option[] config() {
+ return options(systemProperty("osgi.console").value("2401"),
+ systemProperty("rpc.port").value("5555"),
+ mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(), //
+ mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(), //
+ mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(), //
+ mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(), //
+
+ //mavenBundle(ODL, "sal-binding-broker-impl").versionAsInProject().update(), //
+ mavenBundle(ODL, "sal-common").versionAsInProject(), //
+ mavenBundle(ODL, "sal-common-api").versionAsInProject(),//
+ mavenBundle(ODL, "sal-common-impl").versionAsInProject(), //
+ mavenBundle(ODL, "sal-common-util").versionAsInProject(), //
+ mavenBundle(ODL, "sal-core-api").versionAsInProject().update(), //
+ mavenBundle(ODL, "sal-broker-impl").versionAsInProject(), //
+ mavenBundle(ODL, "sal-core-spi").versionAsInProject().update(), //
+ mavenBundle(ODL, "sal-connector-api").versionAsInProject(), //
+
+
+
+ baseModelBundles(),
+ bindingAwareSalBundles(),
+ TestHelper.bindingIndependentSalBundles(),
+ TestHelper.configMinumumBundles(),
+ TestHelper.mdSalCoreBundles(),
+
+ //Added the consumer
+ mavenBundle(SAMPLE, "sal-remoterpc-connector-test-consumer").versionAsInProject(), //
+ //**** These two bundles below are NOT successfully resolved -- some of their dependencies must be missing
+ //**** This causes the "Message" error to occur, the class cannot be found
+ mavenBundle(SAMPLE, "sal-remoterpc-connector-test-provider").versionAsInProject(), //
+ mavenBundle(ODL, "sal-remoterpc-connector").versionAsInProject(), //
+
+ mavenBundle(ODL, "zeromq-routingtable.implementation").versionAsInProject(),
+ mavenBundle(YANG, "concepts").versionAsInProject(),
+ mavenBundle(YANG, "yang-binding").versionAsInProject(), //
+ mavenBundle(YANG, "yang-common").versionAsInProject(), //
+ mavenBundle(YANG, "yang-data-api").versionAsInProject(), //
+ mavenBundle(YANG, "yang-data-impl").versionAsInProject(), //
+ mavenBundle(YANG, "yang-model-api").versionAsInProject(), //
+ mavenBundle(YANG, "yang-parser-api").versionAsInProject(), //
+ mavenBundle(YANG, "yang-parser-impl").versionAsInProject(), //
+ mavenBundle(YANG, "yang-model-util").versionAsInProject(), //
+ mavenBundle(YANG + ".thirdparty", "xtend-lib-osgi").versionAsInProject(), //
+ mavenBundle(YANG + ".thirdparty", "antlr4-runtime-osgi-nohead").versionAsInProject(), //
+ mavenBundle("com.google.guava", "guava").versionAsInProject(), //
+ mavenBundle("org.zeromq", "jeromq").versionAsInProject(),
+ mavenBundle("org.codehaus.jackson", "jackson-mapper-asl").versionAsInProject(),
+ mavenBundle("org.codehaus.jackson", "jackson-core-asl").versionAsInProject(),
+ //routingtable dependencies
+ systemPackages("sun.reflect", "sun.reflect.misc", "sun.misc"),
+ // List framework bundles
+ mavenBundle("equinoxSDK381", "org.eclipse.equinox.console").versionAsInProject(),
+ mavenBundle("equinoxSDK381", "org.eclipse.equinox.util").versionAsInProject(),
+ mavenBundle("equinoxSDK381", "org.eclipse.osgi.services").versionAsInProject(),
+ mavenBundle("equinoxSDK381", "org.eclipse.equinox.ds").versionAsInProject(),
+ mavenBundle("equinoxSDK381", "org.apache.felix.gogo.command").versionAsInProject(),
+ mavenBundle("equinoxSDK381", "org.apache.felix.gogo.runtime").versionAsInProject(),
+ mavenBundle("equinoxSDK381", "org.apache.felix.gogo.shell").versionAsInProject(),
+ // List logger bundles
+
+ mavenBundle("org.opendaylight.controller", "clustering.services")
+ .versionAsInProject(),
+ mavenBundle("org.opendaylight.controller", "clustering.stub")
+ .versionAsInProject(),
+
+
+ // List all the bundles on which the test case depends
+ mavenBundle("org.opendaylight.controller", "sal")
+ .versionAsInProject(),
+ mavenBundle("org.opendaylight.controller", "sal.implementation")
+ .versionAsInProject(),
+ mavenBundle("org.jboss.spec.javax.transaction",
+ "jboss-transaction-api_1.1_spec").versionAsInProject(),
+ mavenBundle("org.apache.commons", "commons-lang3")
+ .versionAsInProject(),
+ mavenBundle("org.apache.felix",
+ "org.apache.felix.dependencymanager")
+ .versionAsInProject(),
+
+ junitBundles()
+ );
+ }
+
+}
--- /dev/null
+//START OF CONFIG-LAST
+<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+<modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:schema-service-singleton</type>
+ <name>yang-schema-service</name>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:hash-map-data-store</type>
+ <name>hash-map-data-store</name>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-broker-impl</type>
+ <name>dom-broker</name>
+ <data-store xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
+ <name>ref_hash-map-data-store</name>
+ </data-store>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-broker-impl</type>
+ <name>binding-broker-impl</name>
+ <notification-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
+ <name>ref_binding-notification-broker</name>
+ </notification-service>
+ <data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
+ <name>ref_binding-data-broker</name>
+ </data-broker>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:runtime-generated-mapping</type>
+ <name>runtime-mapping-singleton</name>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-notification-broker</type>
+ <name>binding-notification-broker</name>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-data-broker</type>
+ <name>binding-data-broker</name>
+ <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+ <name>ref_dom-broker</name>
+ </dom-broker>
+ <mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
+ <name>ref_runtime-mapping-singleton</name>
+ </mapping-service>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote:rpc">prefix:remote-zeromq-rpc-server</type>
+ <name>remoter</name>
+ <port xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote:rpc">5666</port>
+ <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote:rpc">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-broker-osgi-registry</type>
+ <name>ref_dom-broker</name>
+ </dom-broker>
+ </module>
+</modules>
+<services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <instance>
+ <name>ref_yang-schema-service</name>
+ <provider>/config/modules/module[name='schema-service-singleton']/instance[name='yang-schema-service']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
+ <instance>
+ <name>ref_binding-notification-broker</name>
+ <provider>/config/modules/module[name='binding-notification-broker']/instance[name='binding-notification-broker']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
+ <instance>
+ <name>ref_hash-map-data-store</name>
+ <provider>/config/modules/module[name='hash-map-data-store']/instance[name='hash-map-data-store']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
+ <instance>
+ <name>ref_binding-broker-impl</name>
+ <provider>/config/modules/module[name='binding-broker-impl']/instance[name='binding-broker-impl']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding-impl:binding-dom-mapping-service</type>
+ <instance>
+ <name>ref_runtime-mapping-singleton</name>
+ <provider>/config/modules/module[name='runtime-generated-mapping']/instance[name='runtime-mapping-singleton']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+ <instance>
+ <name>ref_dom-broker</name>
+ <provider>/config/modules/module[name='dom-broker-impl']/instance[name='dom-broker']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
+ <instance>
+ <name>ref_binding-data-broker</name>
+ <provider>/config/modules/module[name='binding-data-broker']/instance[name='binding-data-broker']</provider>
+ </instance>
+ </service>
+</services>
+</data>
+
+
+//END OF SNAPSHOT
+urn:opendaylight:params:xml:ns:yang:controller:config?module=config&revision=2013-04-05
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&revision=2013-10-28
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&revision=2013-10-28
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&revision=2013-10-28
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote:rpc?module=odl-sal-dom-rpc-remote-cfg&revision=2013-10-28
+//END OF CONFIG
--- /dev/null
+<configuration scan="true">
+
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+ </pattern>
+ </encoder>
+ </appender>
+
+
+ <logger name="org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort" level="ERROR"/>
+
+ <root level="info">
+ <appender-ref ref="STDOUT" />
+ </root>
+</configuration>
--- /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>sal-remoterpc-connector-test-parent</artifactId>
+ <groupId>org.opendaylight.controller.tests</groupId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>sal-remoterpc-connector-test-nb</artifactId>
+ <packaging>bundle</packaging>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>${bundle.plugin.version}</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Export-Package>
+ </Export-Package>
+ <Import-Package>
+ com.sun.jersey.spi.container.servlet,
+ org.codehaus.jackson.annotate,
+ javax.ws.rs,
+ javax.ws.rs.core,
+ javax.xml.bind,
+ javax.xml.bind.annotation,
+ org.slf4j,
+ org.apache.catalina.filters,
+ org.codehaus.jackson.jaxrs,
+ org.opendaylight.controller.sample.zeromq.provider,
+ org.opendaylight.controller.sample.zeromq.consumer,
+ org.opendaylight.controller.sal.utils,
+ org.opendaylight.yangtools.yang.common,
+ org.opendaylight.controller.sal.connector.api,
+ org.opendaylight.controller.sal.connector.remoterpc.api;version="[0.4,1)",
+ org.opendaylight.controller.sal.connector.remoterpc.impl;version="[0.4,1)",
+ org.opendaylight.controller.sal.connector.remoterpc.dto,
+ org.opendaylight.controller.sal.connector.remoterpc.util,
+ org.osgi.framework,
+ com.google.common.base,
+ org.opendaylight.yangtools.yang.data.api,
+ !org.codehaus.enunciate.jaxrs
+
+ </Import-Package>
+ <Web-ContextPath>/controller/nb/v2/zmqnb</Web-ContextPath>
+ <Jaxrs-Resources>,${classes;ANNOTATION;javax.ws.rs.Path}</Jaxrs-Resources>
+ </instructions>
+ <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>containermanager</artifactId>
+ <version>0.5.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.northbound</artifactId>
+ <version>0.4.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal</artifactId>
+ <version>0.5.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller.tests</groupId>
+ <artifactId>sal-remoterpc-connector-test-provider</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller.tests</groupId>
+ <artifactId>sal-remoterpc-connector-test-consumer</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-remoterpc-connector</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>5.0.0</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>zeromq-routingtable.implementation</artifactId>
+ <version>0.4.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ </dependencies>
+
+ </project>
--- /dev/null
+package org.opendaylight.controller.tests.zmqrouter.rest;
+
+import org.opendaylight.controller.sal.connector.api.RpcRouter;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException;
+import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.CompositeNodeImpl;
+import org.opendaylight.controller.sal.connector.remoterpc.impl.RoutingTableImpl;
+import org.opendaylight.controller.sal.connector.remoterpc.util.XmlUtils;
+import org.opendaylight.controller.sample.zeromq.consumer.ExampleConsumer;
+import org.opendaylight.controller.sample.zeromq.provider.ExampleProvider;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.osgi.framework.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import java.io.Serializable;
+import java.net.URI;
+import java.util.Set;
+
+@Path("router")
+public class Router {
+ private Logger _logger = LoggerFactory.getLogger(Router.class);
+ private final URI namespace = URI.create("http://cisco.com/example");
+ private final QName QNAME = new QName(namespace, "heartbeat");
+
+
+ @GET
+ @Path("/hello")
+ @Produces(MediaType.TEXT_PLAIN)
+ public String hello() {
+ return "Hello";
+ }
+
+ @GET
+ @Path("/announce")
+ @Produces(MediaType.TEXT_PLAIN)
+ public String announce() {
+ _logger.info("Announce request received");
+
+ BundleContext ctx = getBundleContext();
+ ServiceReference providerRef = ctx.getServiceReference(ExampleProvider.class);
+ if (providerRef == null) {
+ _logger.debug("Could not get provider reference");
+ return "Could not get provider reference";
+ }
+
+ ExampleProvider provider = (ExampleProvider) ctx.getService(providerRef);
+ if (provider == null) {
+ _logger.info("Could not get provider service");
+ return "Could not get provider service";
+ }
+
+ provider.announce(QNAME);
+ return "Announcement sent ";
+
+ }
+
+ @GET
+ @Path("/rpc")
+ @Produces(MediaType.TEXT_PLAIN)
+ public String invokeRpc() throws Exception {
+ _logger.info("Invoking RPC");
+
+ ExampleConsumer consumer = getConsumer();
+ RpcResult<CompositeNode> result = consumer.invokeRpc(QNAME, new CompositeNodeImpl());
+ _logger.info("Result [{}]", result.isSuccessful());
+
+ return stringify(result);
+ }
+
+ @GET
+ @Path("/rpc-success")
+ @Produces(MediaType.TEXT_PLAIN)
+ public String invokeRpcSuccess() throws Exception {
+ ExampleConsumer consumer = getConsumer();
+ RpcResult<CompositeNode> result = consumer.invokeRpc(QNAME, consumer.getValidCompositeNodeWithFourSimpleChildren()); //TODO: Change this
+ _logger.info("Result [{}]", result.isSuccessful());
+
+ return stringify(result);
+ }
+
+ @GET
+ @Path("/rpc-failure")
+ @Produces(MediaType.TEXT_PLAIN)
+ public String invokeRpcFailure() throws Exception {
+ ExampleConsumer consumer = getConsumer();
+ //RpcResult<CompositeNode> result = consumer.invokeRpc(QNAME, consumer.getInvalidCompositeNodeCompositeChild()); //TODO: Change this
+ RpcResult<CompositeNode> result = consumer.invokeRpc(QNAME, null); //TODO: Change this
+ _logger.info("Result [{}]", result.isSuccessful());
+
+ return stringify(result);
+ }
+
+ @GET
+ @Path("/routingtable")
+ @Produces(MediaType.TEXT_PLAIN)
+ public String invokeRoutingTable() {
+ _logger.info("Invoking adding an entry in routing table");
+
+ BundleContext ctx = getBundleContext();
+ ServiceReference routingTableServiceReference = ctx.getServiceReference(RoutingTable.class);
+ if (routingTableServiceReference == null) {
+ _logger.debug("Could not get routing table impl reference");
+ return "Could not get routingtable referen ";
+ }
+ RoutingTable routingTable = (RoutingTableImpl) ctx.getService(routingTableServiceReference);
+ if (routingTable == null) {
+ _logger.info("Could not get routing table service");
+ return "Could not get routing table service";
+ }
+
+
+ RoutingIdentifierImpl rii = new RoutingIdentifierImpl();
+ try {
+ routingTable.addGlobalRoute(rii.toString(), "172.27.12.1:5000");
+ } catch (RoutingTableException e) {
+ _logger.error("error in adding routing identifier" + e.getMessage());
+
+ } catch (SystemException e) {
+ _logger.error("error in adding routing identifier" + e.getMessage());
+ }
+
+ Set<String> routes = routingTable.getRoutes(rii.toString());
+
+ StringBuilder stringBuilder = new StringBuilder();
+ for (String route : routes) {
+ stringBuilder.append(route);
+ }
+
+ _logger.info("Result [{}] routes added for route" + rii + stringBuilder.toString());
+
+ return stringBuilder.toString();
+ }
+
+ @GET
+ @Path("/routingtabledelete")
+ @Produces(MediaType.TEXT_PLAIN)
+ public String invokeDeleteRoutingTable() {
+ _logger.info("Invoking adding an entry in routing table");
+
+ BundleContext ctx = getBundleContext();
+ ServiceReference routingTableServiceReference = ctx.getServiceReference(RoutingTable.class);
+ if (routingTableServiceReference == null) {
+ _logger.debug("Could not get routing table impl reference");
+ return "Could not get routingtable referen ";
+ }
+ RoutingTable routingTable = (RoutingTableImpl) ctx.getService(routingTableServiceReference);
+ if (routingTable == null) {
+ _logger.info("Could not get routing table service");
+ return "Could not get routing table service";
+ }
+
+
+ RoutingIdentifierImpl rii = new RoutingIdentifierImpl();
+ try {
+ routingTable.removeGlobalRoute(rii.toString());
+ } catch (RoutingTableException e) {
+ _logger.error("error in adding routing identifier" + e.getMessage());
+
+ } catch (SystemException e) {
+ _logger.error("error in adding routing identifier" + e.getMessage());
+ }
+
+ Set<String> routes = routingTable.getRoutes(rii.toString());
+
+ StringBuilder stringBuilder = new StringBuilder();
+ if (routes != null) {
+ for (String route : routes) {
+ stringBuilder.append(route);
+ }
+ } else {
+ stringBuilder.append(" successfully");
+ }
+
+ _logger.info("Result [{}] routes removed for route" + rii + stringBuilder.toString());
+
+ return stringBuilder.toString();
+ }
+
+ private String stringify(RpcResult<CompositeNode> result) {
+ CompositeNode node = result.getResult();
+ StringBuilder builder = new StringBuilder("result:").append(XmlUtils.compositeNodeToXml(node)).append("\n")
+ .append("error:").append(result.getErrors()).append("\n");
+
+ return builder.toString();
+ }
+
+ private BundleContext getBundleContext() {
+ ClassLoader tlcl = Thread.currentThread().getContextClassLoader();
+ Bundle bundle = null;
+
+ if (tlcl instanceof BundleReference) {
+ bundle = ((BundleReference) tlcl).getBundle();
+ } else {
+ _logger.info("Unable to determine the bundle context based on " +
+ "thread context classloader.");
+ bundle = FrameworkUtil.getBundle(this.getClass());
+ }
+ return (bundle == null ? null : bundle.getBundleContext());
+ }
+
+ private ExampleConsumer getConsumer() {
+ BundleContext ctx = getBundleContext();
+ ServiceReference consumerRef = ctx.getServiceReference(ExampleConsumer.class);
+ if (consumerRef == null) {
+ _logger.debug("Could not get consumer reference");
+ throw new NullPointerException("Could not get consumer reference");
+ }
+ ExampleConsumer consumer = (ExampleConsumer) ctx.getService(consumerRef);
+ if (consumer == null) {
+ _logger.info("Could not get consumer service");
+ throw new NullPointerException("Could not get consumer service");
+ }
+ return consumer;
+ }
+
+ class RoutingIdentifierImpl implements RpcRouter.RouteIdentifier, Serializable {
+
+ private final URI namespace = URI.create("http://cisco.com/example");
+ private final QName QNAME = new QName(namespace, "global");
+ private final QName instance = new QName(URI.create("127.0.0.1"), "local");
+
+ @Override
+ public QName getContext() {
+ return QNAME;
+ }
+
+ @Override
+ public QName getType() {
+ return QNAME;
+ }
+
+ @Override
+ public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier getRoute() {
+ return InstanceIdentifier.of(instance);
+ }
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
+ <servlet>
+ <servlet-name>JAXRSZmq</servlet-name>
+ <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
+ <init-param>
+ <param-name>javax.ws.rs.Application</param-name>
+ <param-value>org.opendaylight.controller.northbound.commons.NorthboundApplication</param-value>
+ </init-param>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>JAXRSZmq</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+
+
+
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>NB api</web-resource-name>
+ <url-pattern>/*</url-pattern>
+ <http-method>POST</http-method>
+ <http-method>GET</http-method>
+ <http-method>PUT</http-method>
+ <http-method>PATCH</http-method>
+ <http-method>DELETE</http-method>
+ <http-method>HEAD</http-method>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>System-Admin</role-name>
+ <role-name>Network-Admin</role-name>
+ <role-name>Network-Operator</role-name>
+ <role-name>Container-User</role-name>
+ </auth-constraint>
+ </security-constraint>
+
+ <security-role>
+ <role-name>System-Admin</role-name>
+ </security-role>
+ <security-role>
+ <role-name>Network-Admin</role-name>
+ </security-role>
+ <security-role>
+ <role-name>Network-Operator</role-name>
+ </security-role>
+ <security-role>
+ <role-name>Container-User</role-name>
+ </security-role>
+
+ <login-config>
+ <auth-method>BASIC</auth-method>
+ <realm-name>opendaylight</realm-name>
+ </login-config>
+</web-app>
import org.opendaylight.controller.sal.rest.api.Draft01;
import org.opendaylight.controller.sal.rest.api.Draft02;
import org.opendaylight.controller.sal.rest.api.RestconfService;
+import org.opendaylight.controller.sal.restconf.impl.ResponseException;
import org.opendaylight.controller.sal.restconf.impl.StructuredData;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
throws IOException, WebApplicationException {
CompositeNode data = t.getData();
if (data == null) {
- throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build());
+ throw new ResponseException(Response.Status.NOT_FOUND, "No data exists.");
}
JsonWriter writer = new JsonWriter(new OutputStreamWriter(entityStream, "UTF-8"));
throws UnsupportedDataTypeException {
QName dataType = data.getNodeType();
Element itemEl = doc.createElementNS(dataType.getNamespace().toString(), dataType.getLocalName());
-
if (data instanceof SimpleNode<?>) {
if (schema instanceof LeafListSchemaNode) {
writeValueOfNodeByType(itemEl, (SimpleNode<?>) data, ((LeafListSchemaNode) schema).getType());
}
} else { // CompositeNode
for (Node<?> child : ((CompositeNode) data).getChildren()) {
- DataSchemaNode childSchema = findFirstSchemaForNode(child, ((DataNodeContainer) schema).getChildNodes());
- if (logger.isDebugEnabled()) {
- if (childSchema == null) {
- logger.debug("Probably the data node \"" + ((child == null) ? "" : child.getNodeType().getLocalName())
- + "\" is not conform to schema");
+ DataSchemaNode childSchema = null;
+ if(schema != null){
+ childSchema = findFirstSchemaForNode(child, ((DataNodeContainer) schema).getChildNodes());
+ if (logger.isDebugEnabled()) {
+ if (childSchema == null) {
+ logger.debug("Probably the data node \"" + ((child == null) ? "" : child.getNodeType().getLocalName())
+ + "\" is not conform to schema");
+ }
}
}
itemEl.appendChild(translateToXmlAndReturnRootElement(doc, child, childSchema));
import org.opendaylight.yangtools.yang.common.RpcResult
import org.opendaylight.yangtools.yang.data.api.CompositeNode
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
+import org.slf4j.LoggerFactory
class BrokerFacade implements DataReader<InstanceIdentifier, CompositeNode> {
+
+ val static LOG = LoggerFactory.getLogger(BrokerFacade)
val static BrokerFacade INSTANCE = new BrokerFacade
@Property
override readConfigurationData(InstanceIdentifier path) {
checkPreconditions
+ LOG.info("Read Configuration via Restconf: {}",path)
return dataService.readConfigurationData(path);
}
override readOperationalData(InstanceIdentifier path) {
checkPreconditions
+ LOG.info("Read Operational via Restconf: {}",path)
return dataService.readOperationalData(path);
}
import static com.google.common.base.Preconditions.*
import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec
+import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition
class ControllerContext implements SchemaServiceListener {
checkArgument(node instanceof LeafSchemaNode);
val urlDecoded = URLDecoder.decode(uriValue);
val typedef = (node as LeafSchemaNode).type;
- val decoded = TypeDefinitionAwareCodec.from(typedef)?.deserialize(urlDecoded)
+ var decoded = TypeDefinitionAwareCodec.from(typedef)?.deserialize(urlDecoded)
+ if(decoded == null) {
+ var baseType = typedef
+ while (baseType.baseType != null) {
+ baseType = baseType.baseType;
+ }
+ if(baseType instanceof IdentityrefTypeDefinition) {
+ decoded = toQName(urlDecoded)
+ }
+ }
map.put(node.QName, decoded);
}
import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
import org.opendaylight.yangtools.yang.common.QName
import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
+import static javax.ws.rs.core.Response.Status.*
class RestconfImpl implements RestconfService {
-
+
val static RestconfImpl INSTANCE = new RestconfImpl
@Property
@Property
extension ControllerContext controllerContext
-
+
private new() {
if (INSTANCE !== null) {
throw new IllegalStateException("Already instantiated");
}
}
-
+
static def getInstance() {
return INSTANCE
}
override createConfigurationData(String identifier, CompositeNode payload) {
val identifierWithSchemaNode = identifier.resolveInstanceIdentifier
val value = normalizeNode(payload, identifierWithSchemaNode.schemaNode)
- val status = broker.commitConfigurationDataPut(identifierWithSchemaNode.instanceIdentifier,value).get();
+ val status = broker.commitConfigurationDataPut(identifierWithSchemaNode.instanceIdentifier, value).get();
switch status.result {
- case TransactionStatus.COMMITED: Response.status(Response.Status.OK).build
- default: Response.status(Response.Status.INTERNAL_SERVER_ERROR).build
+ case TransactionStatus.COMMITED: Response.status(NO_CONTENT).build
+ default: Response.status(INTERNAL_SERVER_ERROR).build
}
}
override updateConfigurationData(String identifier, CompositeNode payload) {
val identifierWithSchemaNode = identifier.resolveInstanceIdentifier
val value = normalizeNode(payload, identifierWithSchemaNode.schemaNode)
- val status = broker.commitConfigurationDataPut(identifierWithSchemaNode.instanceIdentifier,value).get();
+ val status = broker.commitConfigurationDataPut(identifierWithSchemaNode.instanceIdentifier, value).get();
switch status.result {
- case TransactionStatus.COMMITED: Response.status(Response.Status.NO_CONTENT).build
- default: Response.status(Response.Status.INTERNAL_SERVER_ERROR).build
+ case TransactionStatus.COMMITED: Response.status(OK).build
+ default: Response.status(INTERNAL_SERVER_ERROR).build
}
}
override invokeRpc(String identifier, CompositeNode payload) {
val rpc = identifier.rpcDefinition
if (rpc === null) {
- throw new ResponseException(Response.Status.NOT_FOUND, "RPC does not exist.");
+ throw new ResponseException(NOT_FOUND, "RPC does not exist.");
}
val value = normalizeNode(payload, rpc.input)
val List<Node<?>> input = new ArrayList
input.add(value)
val rpcRequest = NodeFactory.createMutableCompositeNode(rpc.QName, null, input, null, null)
val rpcResult = broker.invokeRpc(rpc.QName, rpcRequest);
- return new StructuredData(rpcResult.result, rpc.output);
+ if (!rpcResult.successful) {
+ throw new ResponseException(INTERNAL_SERVER_ERROR, "Operation failed")
+ }
+ if (rpcResult.result === null) {
+ return null
+ }
+ return new StructuredData(rpcResult.result, rpc.output)
}
-
+
override readConfigurationData(String identifier) {
val instanceIdentifierWithSchemaNode = identifier.resolveInstanceIdentifier
val data = broker.readConfigurationData(instanceIdentifierWithSchemaNode.getInstanceIdentifier);
return new StructuredData(data, instanceIdentifierWithSchemaNode.schemaNode)
}
-
+
override readOperationalData(String identifier) {
val instanceIdentifierWithSchemaNode = identifier.resolveInstanceIdentifier
val data = broker.readOperationalData(instanceIdentifierWithSchemaNode.getInstanceIdentifier);
return new StructuredData(data, instanceIdentifierWithSchemaNode.schemaNode)
}
-
+
override updateConfigurationDataLegacy(String identifier, CompositeNode payload) {
- updateConfigurationData(identifier,payload);
+ updateConfigurationData(identifier, payload);
}
-
+
override createConfigurationDataLegacy(String identifier, CompositeNode payload) {
- createConfigurationData(identifier,payload);
+ createConfigurationData(identifier, payload);
}
-
+
private def InstanceIdWithSchemaNode resolveInstanceIdentifier(String identifier) {
val identifierWithSchemaNode = identifier.toInstanceIdentifier
if (identifierWithSchemaNode === null) {
- throw new ResponseException(Response.Status.BAD_REQUEST, "URI has bad format");
+ throw new ResponseException(BAD_REQUEST, "URI has bad format");
}
return identifierWithSchemaNode
}
-
+
private def CompositeNode normalizeNode(CompositeNode node, DataSchemaNode schema) {
if (node instanceof CompositeNodeWrapper) {
- normalizeNode(node as CompositeNodeWrapper, schema,null)
+ normalizeNode(node as CompositeNodeWrapper, schema, null)
return (node as CompositeNodeWrapper).unwrap()
}
return node
}
- private def void normalizeNode(NodeWrapper<?> nodeBuilder, DataSchemaNode schema,QName previousAugment) {
+ private def void normalizeNode(NodeWrapper<?> nodeBuilder, DataSchemaNode schema, QName previousAugment) {
if (schema === null) {
- throw new ResponseException(Response.Status.BAD_REQUEST,
+ throw new ResponseException(BAD_REQUEST,
"Data has bad format\n" + nodeBuilder.localName + " does not exist in yang schema.");
}
var validQName = schema.QName
var currentAugment = previousAugment;
- if(schema.augmenting) {
+ if (schema.augmenting) {
currentAugment = schema.QName
- } else if(previousAugment !== null && schema.QName.namespace !== previousAugment.namespace) {
- validQName = QName.create(currentAugment,schema.QName.localName);
+ } else if (previousAugment !== null && schema.QName.namespace !== previousAugment.namespace) {
+ validQName = QName.create(currentAugment, schema.QName.localName);
}
val moduleName = controllerContext.findModuleByNamespace(validQName.namespace);
if (nodeBuilder.namespace === null || nodeBuilder.namespace == validQName.namespace ||
nodeBuilder.namespace.path == moduleName) {
nodeBuilder.qname = validQName
} else {
- throw new ResponseException(Response.Status.BAD_REQUEST,
+ throw new ResponseException(BAD_REQUEST,
"Data has bad format\nIf data is in XML format then namespace for " + nodeBuilder.localName +
" should be " + schema.QName.namespace + ".\n If data is in Json format then module name for " +
nodeBuilder.localName + " should be " + moduleName + ".");
}
-
+
if (nodeBuilder instanceof CompositeNodeWrapper) {
val List<NodeWrapper<?>> children = (nodeBuilder as CompositeNodeWrapper).getValues
for (child : children) {
normalizeNode(child,
- findFirstSchemaByLocalName(child.localName, (schema as DataNodeContainer).childNodes),currentAugment)
+ findFirstSchemaByLocalName(child.localName, (schema as DataNodeContainer).childNodes),
+ currentAugment)
}
} else if (nodeBuilder instanceof SimpleNodeWrapper) {
val simpleNode = (nodeBuilder as SimpleNodeWrapper)
val stringValue = simpleNode.value as String;
-
+
val objectValue = TypeDefinitionAwareCodec.from(schema.typeDefinition)?.deserialize(stringValue);
simpleNode.setValue(objectValue)
} else if (nodeBuilder instanceof EmptyNodeWrapper) {
val emptyNodeBuilder = nodeBuilder as EmptyNodeWrapper
- if(schema instanceof LeafSchemaNode) {
+ if (schema instanceof LeafSchemaNode) {
emptyNodeBuilder.setComposite(false);
- } else if(schema instanceof ContainerSchemaNode) {
+ } else if (schema instanceof ContainerSchemaNode) {
+
// FIXME: Add presence check
emptyNodeBuilder.setComposite(true);
}
}
}
-
+
private def dispatch TypeDefinition<?> typeDefinition(LeafSchemaNode node) {
node.type
}
-
+
private def dispatch TypeDefinition<?> typeDefinition(LeafListSchemaNode node) {
node.type
}
-
-
+
private def DataSchemaNode findFirstSchemaByLocalName(String localName, Set<DataSchemaNode> schemas) {
for (schema : schemas) {
if (schema instanceof ChoiceNode) {
for (caze : (schema as ChoiceNode).cases) {
- val result = findFirstSchemaByLocalName(localName, caze.childNodes)
+ val result = findFirstSchemaByLocalName(localName, caze.childNodes)
if (result !== null) {
return result
}
}
} else {
val result = schemas.findFirst[n|n.QName.localName.equals(localName)]
- if(result !== null) {
+ if (result !== null) {
return result;
-
+
}
}
}
@Override
public RpcResult<CompositeNode> answer(InvocationOnMock invocation) throws Throwable {
CompositeNode compNode = (CompositeNode) invocation.getArguments()[1];
- return new DummyRpcResult.Builder<CompositeNode>().result(compNode).build();
+ return new DummyRpcResult.Builder<CompositeNode>().result(compNode).isSuccessful(true).build();
}
}
String uri = createUri("/config/", "ietf-interfaces:interfaces/interface/eth0");
Response response = target(uri).request(MEDIA_TYPE_DRAFT02).put(entity);
- assertEquals(204, response.getStatus());
- response = target(uri).request(MEDIA_TYPE_DRAFT02).post(entity);
assertEquals(200, response.getStatus());
+ response = target(uri).request(MEDIA_TYPE_DRAFT02).post(entity);
+ assertEquals(204, response.getStatus());
uri = createUri("/config/", "ietf-interfaces:interfaces/interface/eth0");
response = target(uri).request(MEDIA_TYPE_DRAFT02).put(entity);
- assertEquals(204, response.getStatus());
- response = target(uri).request(MEDIA_TYPE_DRAFT02).post(entity);
assertEquals(200, response.getStatus());
+ response = target(uri).request(MEDIA_TYPE_DRAFT02).post(entity);
+ assertEquals(204, response.getStatus());
uri = createUri("/datastore/", "ietf-interfaces:interfaces/interface/eth0");
response = target(uri).request(MEDIA_TYPE).put(entity);
- assertEquals(204, response.getStatus());
- response = target(uri).request(MEDIA_TYPE).post(entity);
assertEquals(200, response.getStatus());
+ response = target(uri).request(MEDIA_TYPE).post(entity);
+ assertEquals(204, response.getStatus());
}
@Test
+++ /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>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-parent</artifactId>
- <version>1.0-SNAPSHOT</version>
- </parent>
-
- <artifactId>sal-zeromq-connector</artifactId>
- <packaging>bundle</packaging>
-
- <properties>
- <scala.version>2.10.3</scala.version>
- </properties>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <extensions>true</extensions>
- <configuration>
- <instructions>
- <Import-Package>
- org.opendaylight.controller.sal.connector.api,
- org.opendaylight.controller.sal.core.api,
- org.opendaylight.yangtools.concepts;version="[0.1,1)",
- org.opendaylight.yangtools.yang.common;version="[0.5,1)",
- org.opendaylight.yangtools.yang.data.api;version="[0.5,1)",
- org.zeromq;version="[0.3,1)"
- </Import-Package>
- <Bundle-Activator>org.opendaylight.controller.sal.connector.remoterpc.router.zeromq.Activator</Bundle-Activator>
- </instructions>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>net.alchim31.maven</groupId>
- <artifactId>scala-maven-plugin</artifactId>
- <version>3.1.6</version>
- <configuration>
- <recompileMode>incremental</recompileMode>
- <args>
- <arg>-target:jvm-1.7</arg>
- </args>
- <javacArgs>
- <javacArg>-source</javacArg><javacArg>1.7</javacArg>
- <javacArg>-target</javacArg><javacArg>1.7</javacArg>
- </javacArgs>
- </configuration>
- <executions>
- <execution>
- <id>scala-compile</id>
- <goals>
- <goal>compile</goal>
- </goals>
- </execution>
- <execution>
- <id>scala-test-compile</id>
- <goals>
- <goal>testCompile</goal>
- </goals>
- </execution>
- </executions>
-
- </plugin>
- <plugin>
- <artifactId>maven-compiler-plugin</artifactId>
- <executions>
- <execution>
- <id>default-compile</id>
- <phase>none</phase>
- </execution>
- <execution>
- <id>default-testCompile</id>
- <phase>none</phase>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
-
- <dependencies>
- <dependency>
- <groupId>org.scala-lang</groupId>
- <artifactId>scala-library</artifactId>
- <version>${scala.version}</version>
- </dependency>
-
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>containermanager</artifactId>
- <version>0.5.1-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>commons.northbound</artifactId>
- <version>0.4.1-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal</artifactId>
- <version>0.5.1-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-binding</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-common</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-connector-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-common-util</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
-
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- </dependency>
- <dependency>
- <groupId>org.jeromq</groupId>
- <artifactId>jeromq</artifactId>
- <version>0.3.0-SNAPSHOT</version>
- </dependency>
-
- </dependencies>
- <repositories>
- <repository>
- <id>sonatype-nexus-snapshots</id>
- <url>https://oss.sonatype.org/content/repositories/snapshots</url>
- <releases>
- <enabled>false</enabled>
- </releases>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- </repository>
- </repositories>
-
-</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.sal.connector.remoterpc.api;
-
-import java.util.Map;
-import java.util.Set;
-
-public interface RouteChange<I, R> {
-
- Map<I, Set<R>> getRemovals();
- Map<I, Set<R>> getAnnouncements();
-}
+++ /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.sal.connector.remoterpc.router.zeromq;
-
-import org.opendaylight.controller.sal.core.api.AbstractProvider;
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
-import org.osgi.framework.BundleContext;
-
-public class Activator extends AbstractProvider {
-
- ZeroMqRpcRouter router;
-
- @Override
- public void onSessionInitiated(ProviderSession session) {
- router = ZeroMqRpcRouter.getInstance();
- router.setBrokerSession(session);
- router.start();
- }
-
- @Override
- protected void stopImpl(BundleContext context) {
- router.stop();
- }
-
-}
+++ /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.sal.connector.remoterpc.router.zeromq;
-
-import java.io.IOException;
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-
-import org.opendaylight.controller.sal.connector.api.RpcRouter;
-import org.opendaylight.controller.sal.connector.remoterpc.router.zeromq.Message.MessageType;
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
-import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
-import org.opendaylight.controller.sal.core.api.RpcImplementation;
-import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.RpcError;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.zeromq.ZMQ;
-
-/**
- * ZeroMq based implementation of RpcRouter
- * TODO:
- * 1. Make it multi VM aware
- * 2. Make rpc request handling async and non-blocking. Note zmq socket is not thread safe
- * 3. sendRpc() should use connection pooling
- * 4. Read properties from config file using existing(?) ODL properties framework
- */
-public class ZeroMqRpcRouter implements RpcRouter<QName, QName, InstanceIdentifier, Object> {
-
- private ExecutorService serverPool;
- private static ExecutorService handlersPool;
-
- private Map<RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier>, String> routingTable;
-
- private ProviderSession brokerSession;
-
- private ZMQ.Context context;
- private ZMQ.Socket publisher;
- private ZMQ.Socket subscriber;
- private ZMQ.Socket replySocket;
-
- private static ZeroMqRpcRouter _instance = new ZeroMqRpcRouter();
-
- private final RpcFacade facade = new RpcFacade();
- private final RpcListener listener = new RpcListener();
-
- private final String localIp = getLocalIpAddress();
-
- private String pubPort = System.getProperty("pub.port");// port on which announcements are sent
- private String subPort = System.getProperty("sub.port");// other controller's pub port
- private String pubIp = System.getProperty("pub.ip"); // other controller's ip
- private String rpcPort = System.getProperty("rpc.port");// port on which RPC messages are received
-
- private Logger _logger = LoggerFactory.getLogger(ZeroMqRpcRouter.class);
-
- //Prevent instantiation
- private ZeroMqRpcRouter() {
- }
-
- public static ZeroMqRpcRouter getInstance() {
- return _instance;
- }
-
- public void start() {
- context = ZMQ.context(2);
- publisher = context.socket(ZMQ.PUB);
- int ret = publisher.bind("tcp://*:" + pubPort);
- // serverPool = Executors.newSingleThreadExecutor();
- serverPool = Executors.newCachedThreadPool();
- handlersPool = Executors.newCachedThreadPool();
- routingTable = new ConcurrentHashMap<RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier>, String>();
-
- // Start listening for announce and rpc messages
- serverPool.execute(receive());
-
- brokerSession.addRpcRegistrationListener(listener);
-
- Set<QName> currentlySupported = brokerSession.getSupportedRpcs();
- for (QName rpc : currentlySupported) {
- listener.onRpcImplementationAdded(rpc);
- }
-
- }
-
- public void stop() {
- if (handlersPool != null)
- handlersPool.shutdown();
- if (serverPool != null)
- serverPool.shutdown();
- if (publisher != null) {
- publisher.setLinger(0);
- publisher.close();
- }
- if (replySocket != null) {
- replySocket.setLinger(0);
- replySocket.close();
- }
- if (subscriber != null) {
- subscriber.setLinger(0);
- subscriber.close();
- }
- if (context != null)
- context.term();
-
- }
-
- private Runnable receive() {
- return new Runnable() {
- public void run() {
- try {
- // Bind to RPC reply socket
- replySocket = context.socket(ZMQ.REP);
- replySocket.bind("tcp://*:" + rpcPort);
-
- // Bind to publishing controller
- subscriber = context.socket(ZMQ.SUB);
- String pubAddress = "tcp://" + pubIp + ":" + subPort;
- subscriber.connect(pubAddress);
- _logger.debug("{} Subscribing at[{}]", Thread.currentThread().getName(), pubAddress);
-
- //subscribe for announcements
- //TODO: Message type would be changed. Update this
- subscriber.subscribe(Message.serialize(Message.MessageType.ANNOUNCE));
-
- // Poller enables listening on multiple sockets using a single thread
- ZMQ.Poller poller = new ZMQ.Poller(2);
- poller.register(replySocket, ZMQ.Poller.POLLIN);
- poller.register(subscriber, ZMQ.Poller.POLLIN);
-
- //TODO: Add code to restart the thread after exception
- while (!Thread.currentThread().isInterrupted()) {
-
- poller.poll();
-
- if (poller.pollin(0)) {
- handleRpcCall();
- }
- if (poller.pollin(1)) {
- handleAnnouncement();
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- replySocket.setLinger(0);
- replySocket.close();
- subscriber.setLinger(0);
- subscriber.close();
- }
- };
- }
-
- /**
- * @throws IOException
- * @throws ClassNotFoundException
- */
- private void handleAnnouncement() throws IOException, ClassNotFoundException {
-
- _logger.info("Announcement received");
- Message.MessageType topic = (MessageType) Message.deserialize(subscriber.recv());
-
- if (subscriber.hasReceiveMore()) {
- try {
- Message m = (Message) Message.deserialize(subscriber.recv());
- _logger.debug("Announcement message [{}]", m);
-
- // TODO: check on msg type or topic. Both
- // should be same. Need to normalize.
- if (Message.MessageType.ANNOUNCE == m.getType())
- updateRoutingTable(m);
- } catch (IOException | ClassNotFoundException e) {
- e.printStackTrace();
- }
- }
-
- }
-
- /**
- * @throws InterruptedException
- * @throws ExecutionException
- */
- private void handleRpcCall() throws InterruptedException, ExecutionException {
- try {
- Message request = parseMessage(replySocket);
-
- _logger.debug("Received rpc request [{}]", request);
-
- // Call broker to process the message then reply
- Future<RpcResult<CompositeNode>> rpc = brokerSession.rpc(
- (QName) request.getRoute().getType(), (CompositeNode) request.getPayload());
-
- RpcResult<CompositeNode> result = rpc.get();
-
- Message response = new Message.MessageBuilder()
- .type(MessageType.RESPONSE)
- .sender(localIp + ":" + rpcPort)
- .route(request.getRoute())
- //.payload(result) TODO: enable and test
- .build();
-
- replySocket.send(Message.serialize(response));
-
- _logger.debug("Sent rpc response [{}]", response);
-
- } catch (IOException ex) {
- //TODO: handle exception and send error codes to caller
- ex.printStackTrace();
- }
- }
-
-
- @Override
- public Future<RpcReply<Object>> sendRpc(
- final RpcRequest<QName, QName, InstanceIdentifier, Object> input) {
-
- return handlersPool.submit(new Callable<RpcReply<Object>>() {
-
- @Override
- public RpcReply<Object> call() {
- ZMQ.Socket requestSocket = context.socket(ZMQ.REQ);
-
- // TODO pick the ip and port from routing table based on routing identifier
- requestSocket.connect("tcp://" + pubIp + ":5554");
-
- Message requestMessage = new Message.MessageBuilder()
- .type(MessageType.REQUEST)
- .sender(localIp + ":" + rpcPort)
- .route(input.getRoutingInformation())
- .payload(input.getPayload())
- .build();
-
- _logger.debug("Sending rpc request [{}]", requestMessage);
-
- RpcReply<Object> reply = null;
-
- try {
-
- requestSocket.send(Message.serialize(requestMessage));
- final Message response = parseMessage(requestSocket);
-
- _logger.debug("Received response [{}]", response);
-
- reply = new RpcReply<Object>() {
-
- @Override
- public Object getPayload() {
- return response.getPayload();
- }
- };
- } catch (IOException ex) {
- // TODO: Pass exception back to the caller
- ex.printStackTrace();
- }
-
- return reply;
- }
- });
- }
-
- /**
- * TODO: Remove this implementation and use RoutingTable implementation to send announcements
- * Publishes a notice to other controllers in the cluster
- *
- * @param notice
- */
- public void publish(final Message notice) {
- Runnable task = new Runnable() {
- public void run() {
-
- try {
-
- publisher.sendMore(Message.serialize(Message.MessageType.ANNOUNCE));
- publisher.send(Message.serialize(notice));
- _logger.debug("Announcement sent [{}]", notice);
- } catch (IOException ex) {
- _logger.error("Error in sending announcement [{}]", notice);
- ex.printStackTrace();
- }
- }
- };
- handlersPool.execute(task);
- }
-
- /**
- * Finds IPv4 address of the local VM
- * TODO: This method is non-deterministic. There may be more than one IPv4 address. Cant say which
- * address will be returned. Read IP from a property file or enhance the code to make it deterministic.
- * Should we use IP or hostname?
- *
- * @return
- */
- private String getLocalIpAddress() {
- String hostAddress = null;
- Enumeration e = null;
- try {
- e = NetworkInterface.getNetworkInterfaces();
- } catch (SocketException e1) {
- e1.printStackTrace();
- }
- while (e.hasMoreElements()) {
-
- NetworkInterface n = (NetworkInterface) e.nextElement();
-
- Enumeration ee = n.getInetAddresses();
- while (ee.hasMoreElements()) {
- InetAddress i = (InetAddress) ee.nextElement();
- if ((i instanceof Inet4Address) && (i.isSiteLocalAddress()))
- hostAddress = i.getHostAddress();
- }
- }
- return hostAddress;
-
- }
-
- /**
- * TODO: Change to use external routing table implementation
- *
- * @param msg
- */
- private void updateRoutingTable(Message msg) {
- routingTable.put(msg.getRoute(), msg.getSender());
- RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> route = msg.getRoute();
-
- // Currently only registers rpc implementation.
- // TODO: do registration for instance based routing
- QName rpcType = route.getType();
- RpcRegistration registration = brokerSession.addRpcImplementation(rpcType, facade);
- _logger.debug("Routing table updated");
- }
-
- /**
- * @param socket
- * @return
- */
- private Message parseMessage(ZMQ.Socket socket) {
-
- Message msg = null;
- try {
- byte[] bytes = socket.recv();
- _logger.debug("Received bytes:[{}]", bytes.length);
- msg = (Message) Message.deserialize(bytes);
- } catch (Throwable t) {
- t.printStackTrace();
- }
- return msg;
- }
-
- private class RpcFacade implements RpcImplementation {
-
- @Override
- public Set<QName> getSupportedRpcs() {
- return Collections.emptySet();
- }
-
- @Override
- public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
-
- RouteIdentifierImpl routeId = new RouteIdentifierImpl();
- routeId.setType(rpc);
-
- RpcRequestImpl request = new RpcRequestImpl();
- request.setRouteIdentifier(routeId);
- request.setPayload(input);
-
- final Future<RpcReply<Object>> ret = sendRpc(request);
-
- //TODO: Review result handling
- RpcResult<CompositeNode> result = new RpcResult<CompositeNode>() {
- @Override
- public boolean isSuccessful() {
- try {
- ret.get();
- } catch (InterruptedException | ExecutionException e) {
- e.printStackTrace();
- return false;
- }
- return true;
- }
-
- @Override
- public CompositeNode getResult() {
- return null;
- }
-
- @Override
- public Collection<RpcError> getErrors() {
- return Collections.EMPTY_LIST;
- }
- };
- return result;
- }
- }
-
- /**
- * Listener for rpc registrations
- */
- private class RpcListener implements RpcRegistrationListener {
-
- @Override
- public void onRpcImplementationAdded(QName name) {
-
- _logger.debug("Announcing registration for [{}]", name);
- RouteIdentifierImpl routeId = new RouteIdentifierImpl();
- routeId.setType(name);
-
- //TODO: Make notice immutable and change message type
- Message notice = new Message.MessageBuilder()
- .type(MessageType.ANNOUNCE)
- .sender("tcp://" + localIp + ":" + rpcPort)
- .route(routeId)
- .build();
-
- publish(notice);
- }
-
- @Override
- public void onRpcImplementationRemoved(QName name) {
- // TODO: send a rpc-deregistrtation notice
-
- }
- }
-
- public void setBrokerSession(ProviderSession session) {
- this.brokerSession = session;
-
- }
-
-}
+++ /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>sal-parent</artifactId>
- <version>1.0-SNAPSHOT</version>
- <groupId>org.opendaylight.controller</groupId>
- </parent>
- <packaging>pom</packaging>
- <groupId>org.opendaylight.controller.tests</groupId>
- <artifactId>sal-test-parent</artifactId>
- <scm>
- <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
- <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
- <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
- </scm>
-
- <modules>
- <module>zeromq-test-consumer</module>
- <module>zeromq-test-it</module>
- <module>zeromq-test-provider</module>
- </modules>
-
-</project>
+++ /dev/null
-package org.opendaylight.controller.sample.zeromq.consumer;
-
-import java.net.URI;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-import org.opendaylight.controller.sal.core.api.AbstractConsumer;
-import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.osgi.framework.BundleContext;
-
-public class ExampleConsumer extends AbstractConsumer {
-
- private final URI namespace = URI.create("http://cisco.com/example");
- private final QName QNAME = new QName(namespace,"heartbeat");
-
- ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
- private ConsumerSession session;
-
-
- @Override
- public void onSessionInitiated(ConsumerSession session) {
- this.session = session;
- executor.scheduleAtFixedRate(new Runnable() {
-
- @Override
- public void run() {
- int count = 0;
- try {
- Future<RpcResult<CompositeNode>> future = ExampleConsumer.this.session.rpc(QNAME, null);
- RpcResult<CompositeNode> result = future.get();
- System.out.println("Result received. Status is :" + result.isSuccessful());
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- }
- }, 0, 10, TimeUnit.SECONDS);
- }
-
- @Override
- protected void stopImpl(BundleContext context) {
- // TODO Auto-generated method stub
- super.stopImpl(context);
- executor.shutdown();
- }
-}
+++ /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>sal-test-parent</artifactId>
- <groupId>org.opendaylight.controller.tests</groupId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <artifactId>zeromq-test-it</artifactId>
- <scm>
- <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
- <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
- <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
- </scm>
-
- <properties>
- <exam.version>3.0.0</exam.version>
- <url.version>1.5.0</url.version>
- </properties>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.ops4j.pax.exam</groupId>
- <artifactId>maven-paxexam-plugin</artifactId>
- <version>1.2.4</version>
- <executions>
- <execution>
- <id>generate-config</id>
- <goals>
- <goal>generate-depends-file</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- </plugins>
- <pluginManagement>
- <plugins>
- <!--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.ops4j.pax.exam
- </groupId>
- <artifactId>
- maven-paxexam-plugin
- </artifactId>
- <versionRange>
- [1.2.4,)
- </versionRange>
- <goals>
- <goal>
- generate-depends-file
- </goal>
- </goals>
- </pluginExecutionFilter>
- <action>
- <ignore></ignore>
- </action>
- </pluginExecution>
- </pluginExecutions>
- </lifecycleMappingMetadata>
- </configuration>
- </plugin>
- </plugins>
- </pluginManagement>
- </build>
-
- <dependencies>
- <dependency>
- <groupId>org.opendaylight.yangtools.thirdparty</groupId>
- <artifactId>xtend-lib-osgi</artifactId>
- <version>2.4.3</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller.tests</groupId>
- <artifactId>zeromq-test-provider</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller.tests</groupId>
- <artifactId>zeromq-test-consumer</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-broker-impl</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.ops4j.pax.exam</groupId>
- <artifactId>pax-exam-container-native</artifactId>
- <version>${exam.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.ops4j.pax.exam</groupId>
- <artifactId>pax-exam-junit4</artifactId>
- <version>${exam.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.ops4j.pax.exam</groupId>
- <artifactId>pax-exam-link-mvn</artifactId>
- <version>${exam.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>equinoxSDK381</groupId>
- <artifactId>org.eclipse.osgi</artifactId>
- <version>3.8.1.v20120830-144521</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>log4j-over-slf4j</artifactId>
- <version>1.7.2</version>
- </dependency>
- <dependency>
- <groupId>ch.qos.logback</groupId>
- <artifactId>logback-core</artifactId>
- <version>1.0.9</version>
- </dependency>
- <dependency>
- <groupId>ch.qos.logback</groupId>
- <artifactId>logback-classic</artifactId>
- <version>1.0.9</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-binding-api</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-common-util</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-core-api</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
-
-
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>containermanager</artifactId>
- <version>0.5.1-SNAPSHOT</version>
- </dependency>
-
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal</artifactId>
- <version>0.5.1-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-binding</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-common</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-data-api</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-common-util</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- </dependencies>
-</project>
+++ /dev/null
-package org.opendaylight.controller.sample.zeromq.test.it;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.ops4j.pax.exam.Configuration;
-import org.ops4j.pax.exam.Option;
-import org.ops4j.pax.exam.junit.PaxExam;
-import org.osgi.framework.BundleContext;
-
-import javax.inject.Inject;
-
-import static org.junit.Assert.assertTrue;
-import static org.ops4j.pax.exam.CoreOptions.*;
-
-@RunWith(PaxExam.class)
-public class ServiceConsumerController {
-
- public static final String ODL = "org.opendaylight.controller";
- public static final String YANG = "org.opendaylight.yangtools";
- public static final String SAMPLE = "org.opendaylight.controller.samples";
-
- @Test
- public void properInitialized() throws Exception {
-
- Thread.sleep(30000); // Waiting for services to get wired.
- assertTrue(true);
- //assertTrue(consumer.createToast(WhiteBread.class, 5));
-
- }
-
-// @Inject
-// BindingAwareBroker broker;
-
-// @Inject
-// ToastConsumer consumer;
-
- @Inject
- BundleContext ctx;
-
- @Configuration
- public Option[] config() {
- return options(systemProperty("osgi.console").value("2401"),
- systemProperty("pub.port").value("5557"),
- systemProperty("sub.port").value("5556"),
- systemProperty("rpc.port").value("5555"),
- systemProperty("pub.ip").value("localhost"),
- mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(), //
- mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(), //
- mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(), //
- mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(), //
-
- //mavenBundle(ODL, "sal-binding-broker-impl").versionAsInProject().update(), //
- mavenBundle(ODL, "sal-common").versionAsInProject(), //
- mavenBundle(ODL, "sal-common-api").versionAsInProject(),//
- mavenBundle(ODL, "sal-common-impl").versionAsInProject(), //
- mavenBundle(ODL, "sal-common-util").versionAsInProject(), //
- mavenBundle(ODL, "sal-core-api").versionAsInProject().update(), //
- mavenBundle(ODL, "sal-broker-impl").versionAsInProject(), //
- mavenBundle(ODL, "sal-core-spi").versionAsInProject().update(), //
- mavenBundle(ODL, "sal-connector-api").versionAsInProject(), //
- mavenBundle(SAMPLE, "zeromq-test-consumer").versionAsInProject(), //
- mavenBundle(ODL, "sal-zeromq-connector").versionAsInProject(), //
- mavenBundle(YANG, "concepts").versionAsInProject(),
- mavenBundle(YANG, "yang-binding").versionAsInProject(), //
- mavenBundle(YANG, "yang-common").versionAsInProject(), //
- mavenBundle(YANG, "yang-data-api").versionAsInProject(), //
- mavenBundle(YANG, "yang-model-api").versionAsInProject(), //
- mavenBundle(YANG+".thirdparty", "xtend-lib-osgi").versionAsInProject(), //
- mavenBundle("com.google.guava", "guava").versionAsInProject(), //
- mavenBundle("org.jeromq", "jeromq").versionAsInProject(),
- junitBundles()
- );
- }
-
-}
+++ /dev/null
-package org.opendaylight.controller.sample.zeromq.test.it;
-
-import static org.junit.Assert.*;
-import static org.ops4j.pax.exam.CoreOptions.junitBundles;
-import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
-import static org.ops4j.pax.exam.CoreOptions.options;
-import static org.ops4j.pax.exam.CoreOptions.systemPackages;
-import static org.ops4j.pax.exam.CoreOptions.systemProperty;
-import static org.ops4j.pax.exam.CoreOptions.maven;
-
-import java.util.Collection;
-
-import javax.inject.Inject;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
-import org.ops4j.pax.exam.Configuration;
-import org.ops4j.pax.exam.CoreOptions;
-import org.ops4j.pax.exam.Option;
-import org.ops4j.pax.exam.junit.PaxExam;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
-
-@RunWith(PaxExam.class)
-public class ServiceProviderController {
-
- public static final String ODL = "org.opendaylight.controller";
- public static final String YANG = "org.opendaylight.yangtools";
- public static final String SAMPLE = "org.opendaylight.controller.samples";
-
- @Test
- public void properInitialized() throws Exception {
-
- Thread.sleep(30000); // Waiting for services to get wired.
- assertTrue(true);
- //assertTrue(consumer.createToast(WhiteBread.class, 5));
-
- }
-
-// @Inject
-// BindingAwareBroker broker;
-
-// @Inject
-// ToastConsumer consumer;
-
- @Inject
- BundleContext ctx;
-
- @Configuration
- public Option[] config() {
- return options(systemProperty("osgi.console").value("2401"),
- systemProperty("pub.port").value("5556"),
- systemProperty("sub.port").value("5557"),
- systemProperty("rpc.port").value("5554"),
- systemProperty("pub.ip").value("localhost"),
- mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(), //
- mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(), //
- mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(), //
- mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(), //
-
- //mavenBundle(ODL, "sal-binding-broker-impl").versionAsInProject().update(), //
- mavenBundle(ODL, "sal-common").versionAsInProject(), //
- mavenBundle(ODL, "sal-common-api").versionAsInProject(),//
- mavenBundle(ODL, "sal-common-impl").versionAsInProject(), //
- mavenBundle(ODL, "sal-common-util").versionAsInProject(), //
- mavenBundle(ODL, "sal-core-api").versionAsInProject().update(), //
- mavenBundle(ODL, "sal-broker-impl").versionAsInProject(), //
- mavenBundle(ODL, "sal-core-spi").versionAsInProject().update(), //
- mavenBundle(ODL, "sal-connector-api").versionAsInProject(), //
- mavenBundle(SAMPLE, "zeromq-test-provider").versionAsInProject(), //
- mavenBundle(ODL, "sal-zeromq-connector").versionAsInProject(), //
- mavenBundle(YANG, "concepts").versionAsInProject(),
- mavenBundle(YANG, "yang-binding").versionAsInProject(), //
- mavenBundle(YANG, "yang-common").versionAsInProject(), //
- mavenBundle(YANG, "yang-data-api").versionAsInProject(), //
- mavenBundle(YANG, "yang-model-api").versionAsInProject(), //
- mavenBundle(YANG+".thirdparty", "xtend-lib-osgi").versionAsInProject(), //
- mavenBundle("com.google.guava", "guava").versionAsInProject(), //
- mavenBundle("org.jeromq", "jeromq").versionAsInProject(),
- junitBundles()
- );
- }
-
-}
+++ /dev/null
-package org.opendaylight.controller.sample.zeromq.provider;
-
-import java.net.URI;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Set;
-
-import org.opendaylight.controller.sal.common.util.Rpcs;
-import org.opendaylight.controller.sal.core.api.AbstractProvider;
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
-import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
-import org.opendaylight.controller.sal.core.api.RpcImplementation;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.RpcError;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.osgi.framework.BundleContext;
-
-public class ExampleProvider extends AbstractProvider implements RpcImplementation {
-
- private final URI namespace = URI.create("http://cisco.com/example");
- private final QName QNAME = new QName(namespace,"heartbeat");
- private RpcRegistration reg;
-
-
- @Override
- public void onSessionInitiated(ProviderSession session) {
- //Adding heartbeat 10 times just to make sure subscriber get it
- for (int i=0;i<10;i++){
- System.out.println("ExampleProvider: Adding " + QNAME + " " + i);
- reg = session.addRpcImplementation(QNAME, this);
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
- }
- }
- }
-
- @Override
- public Set<QName> getSupportedRpcs() {
- return Collections.singleton(QNAME);
- }
-
- @Override
- public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
- if(QNAME.equals(rpc)) {
- RpcResult<CompositeNode> output = Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
- return output;
- }
- RpcResult<CompositeNode> output = Rpcs.getRpcResult(false, null, Collections.<RpcError>emptySet());
- return output;
- }
-
- @Override
- protected void stopImpl(BundleContext context) {
- if(reg != null) {
- try {
- reg.close();
- } catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
-
-}
<?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">
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.opendaylight.controller</groupId>
<extensions>true</extensions>
<configuration>
<instructions>
-
+ <Export-Package>
+ org.opendaylight.controller.sal.connector.remoterpc.api,
+ org.opendaylight.controller.sal.connector.remoterpc.impl
+ </Export-Package>
<Import-Package>
javax.xml.bind.annotation,
org.opendaylight.controller.sal.core,
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal</artifactId>
- <version>0.5.1-SNAPSHOT</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
org.osgi.framework,
org.osgi.util.tracker,
org.slf4j,
- org.w3c.dom
+ org.w3c.dom,
+ com.google.common.io,
+ org.opendaylight.yangtools.yang.model.api.type
</Import-Package>
<Export-Package>
</Export-Package>
import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
+import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
import javax.management.openmbean.ArrayType;
import javax.management.openmbean.CompositeType;
if (attributeIfc instanceof JavaAttribute) {
try {
- return caseJavaAttribute(attributeIfc.getOpenType());
+ if(((JavaAttribute)attributeIfc).getTypeDefinition() instanceof BinaryTypeDefinition) {
+ return caseJavaBinaryAttribute(attributeIfc.getOpenType());
+ } else
+ return caseJavaAttribute(attributeIfc.getOpenType());
} catch (UnknownOpenTypeException e) {
throw getIllegalArgumentException(attributeIfc);
}
} else if (attributeIfc instanceof DependencyAttribute) {
return caseDependencyAttribute(((DependencyAttribute) attributeIfc).getOpenType());
} else if (attributeIfc instanceof ListAttribute) {
- return caseListAttribute(((ListAttribute) attributeIfc).getOpenType());
+ return caseListAttribute((ArrayType<?>) attributeIfc.getOpenType());
+ } else if (attributeIfc instanceof ListDependenciesAttribute) {
+ return caseListDependeciesAttribute((ArrayType<?>) attributeIfc.getOpenType());
} else if (attributeIfc instanceof TOAttribute) {
return caseTOAttribute(((TOAttribute) attributeIfc).getOpenType());
}
throw getIllegalArgumentException(attributeIfc);
}
+ protected T caseJavaBinaryAttribute(OpenType<?> openType) {
+ return caseJavaAttribute(openType);
+ }
+
private IllegalArgumentException getIllegalArgumentException(AttributeIfc attributeIfc) {
return new IllegalArgumentException("Unknown attribute type " + attributeIfc.getClass() + ", " + attributeIfc
+ " with open type:" + attributeIfc.getOpenType());
protected abstract T caseListAttribute(ArrayType<?> openType);
+ protected abstract T caseListDependeciesAttribute(ArrayType<?> openType);
private static class UnknownOpenTypeException extends RuntimeException {
public UnknownOpenTypeException(String message) {
@Override
public AttributeConfigElement readElement(List<XmlElement> configNodes) {
if (configNodes.size() == 0)
- return AttributeConfigElement.createNullValue(nullableDefault);
+ return AttributeConfigElement.createNullValue(postprocessNullableDefault(nullableDefault));
return readElementHook(configNodes);
}
abstract AttributeConfigElement readElementHook(List<XmlElement> configNodes);
+ protected Object postprocessNullableDefault(String nullableDefault) {
+ return nullableDefault;
+ }
}
package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml;
import com.google.common.base.Optional;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving.AttributeResolvingStrategy;
import javax.management.openmbean.OpenType;
}
- public static AttributeConfigElement create(AttributeIfc attributeIfc, Object value) {
- String nullableDefault = attributeIfc.getNullableDefault();
- return create(nullableDefault, value);
- }
-
- public static AttributeConfigElement create(String nullableDefault, Object value) {
+ public static AttributeConfigElement create(Object nullableDefault, Object value) {
return new AttributeConfigElement(nullableDefault, value);
}
- public static AttributeConfigElement createNullValue(AttributeIfc attributeIfc) {
- return new AttributeConfigElement(attributeIfc.getNullableDefault(), null);
- }
-
- public static AttributeConfigElement createNullValue(String nullableDefault) {
+ public static AttributeConfigElement createNullValue(Object nullableDefault) {
return new AttributeConfigElement(nullableDefault, null);
}
-
public Object getValue() {
return value;
}
import com.google.common.collect.Maps;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
import javax.management.openmbean.ArrayType;
import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
import javax.management.openmbean.SimpleType;
import java.util.Map;
import java.util.Map.Entry;
return switchAttribute(attributeIfc);
}
+ @Override
+ protected AttributeReadingStrategy caseJavaBinaryAttribute(OpenType<?> openType) {
+ return new SimpleBinaryAttributeReadingStrategy(lastAttribute.getNullableDefault());
+ }
+
@Override
public AttributeReadingStrategy caseJavaSimpleAttribute(SimpleType<?> openType) {
return new SimpleAttributeReadingStrategy(lastAttribute.getNullableDefault());
return new ArrayAttributeReadingStrategy(lastAttribute.getNullableDefault(), innerStrategy);
}
+ @Override
+ protected AttributeReadingStrategy caseListDependeciesAttribute(ArrayType<?> openType) {
+ Preconditions.checkState(lastAttribute instanceof ListDependenciesAttribute);
+ AttributeReadingStrategy innerStrategy = caseDependencyAttribute(SimpleType.OBJECTNAME);
+ return new ArrayAttributeReadingStrategy(lastAttribute.getNullableDefault(), innerStrategy);
+ }
+
}
String textContent = xmlElement.getTextContent();
Preconditions.checkNotNull(textContent, "This element should contain text %s", xmlElement);
- return AttributeConfigElement.create(getNullableDefault(), postprocessParsedValue(textContent));
+ return AttributeConfigElement.create(postprocessNullableDefault(getNullableDefault()),
+ postprocessParsedValue(textContent));
+ }
+
+ @Override
+ protected Object postprocessNullableDefault(String nullableDefault) {
+ return nullableDefault;
}
protected Object postprocessParsedValue(String textContent) {
--- /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 com.google.common.io.BaseEncoding;
+
+import java.util.List;
+
+public class SimpleBinaryAttributeReadingStrategy extends SimpleAttributeReadingStrategy {
+
+ public SimpleBinaryAttributeReadingStrategy(String nullableDefault) {
+ super(nullableDefault);
+ }
+
+ protected Object postprocessParsedValue(String textContent) {
+ BaseEncoding en = BaseEncoding.base64();
+ byte[] decode = en.decode(textContent);
+ List<String> parsed = Lists.newArrayListWithCapacity(decode.length);
+ for (byte b : decode) {
+ parsed.add(Byte.toString(b));
+ }
+ return parsed;
+ }
+
+ @Override
+ protected Object postprocessNullableDefault(String nullableDefault) {
+ return nullableDefault == null ? null : postprocessParsedValue(nullableDefault);
+ }
+}
public class SimpleCompositeAttributeReadingStrategy extends SimpleAttributeReadingStrategy {
-
private final String key;
public SimpleCompositeAttributeReadingStrategy(String nullableDefault, String key) {
return map;
}
+ @Override
+ protected Object postprocessNullableDefault(String nullableDefault) {
+ return nullableDefault == null ? null : postprocessParsedValue(nullableDefault);
+ }
}
import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
prepareStrategy(((ListAttribute) lastAttribute).getInnerAttribute()));
}
+ @Override
+ protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseListDependeciesAttribute(ArrayType<?> openType) {
+ Preconditions.checkState(lastAttribute instanceof ListDependenciesAttribute);
+ return new ArrayAttributeMappingStrategy(openType, caseDependencyAttribute(SimpleType.OBJECTNAME));
+ }
+
}
parsedInnerValue.isPresent() ? parsedInnerValue.get() : null);
}
- CompositeDataSupport parsedValue = null;
+ CompositeDataSupport parsedValue;
try {
parsedValue = new CompositeDataSupport(getOpenType(), items);
} catch (OpenDataException e) {
import com.google.common.collect.Maps;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
return new ArrayAttributeResolvingStrategy(prepareStrategy(innerAttribute), openType);
}
+ @Override
+ protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseListDependeciesAttribute(ArrayType<?> openType) {
+ Preconditions.checkState(lastAttribute instanceof ListDependenciesAttribute);
+ return new ArrayAttributeResolvingStrategy(caseDependencyAttribute(SimpleType.OBJECTNAME), openType);
+ }
+
}
import com.google.common.collect.Maps;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
import org.w3c.dom.Document;
import javax.management.openmbean.ArrayType;
import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
import javax.management.openmbean.SimpleType;
import java.util.Map;
import java.util.Map.Entry;
return switchAttribute(expectedAttr);
}
+ @Override
+ protected AttributeWritingStrategy caseJavaBinaryAttribute(OpenType<?> openType) {
+ return new SimpleBinaryAttributeWritingStrategy(document, key);
+ }
+
@Override
protected AttributeWritingStrategy caseJavaSimpleAttribute(SimpleType<?> openType) {
return new SimpleAttributeWritingStrategy(document, key);
return new ArrayAttributeWritingStrategy(innerStrategy);
}
+ @Override
+ protected AttributeWritingStrategy caseListDependeciesAttribute(ArrayType<?> openType) {
+ Preconditions.checkState(lastAttribute instanceof ListDependenciesAttribute);
+ AttributeWritingStrategy innerStrategy = caseDependencyAttribute(SimpleType.OBJECTNAME);
+ 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 com.google.common.base.Preconditions;
+import com.google.common.io.BaseEncoding;
+import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
+import org.w3c.dom.Document;
+
+import java.util.List;
+
+public class SimpleBinaryAttributeWritingStrategy extends SimpleAttributeWritingStrategy {
+
+ /**
+ * @param document
+ * @param key
+ */
+ public SimpleBinaryAttributeWritingStrategy(Document document, String key) {
+ super(document, key);
+ }
+
+ protected Object preprocess(Object value) {
+ Util.checkType(value, List.class);
+ BaseEncoding en = BaseEncoding.base64();
+
+ List<?> list = (List<?>) value;
+ byte[] decoded = new byte[list.size()];
+ int i = 0;
+ for (Object bAsStr : list) {
+ Preconditions.checkArgument(bAsStr instanceof String, "Unexpected inner value for %s, expected string", value);
+ byte b = Byte.parseByte((String) bAsStr);
+ decoded[i++] = b;
+ }
+
+ return en.encode(decoded);
+ }
+
+}
public static ServiceInstance fromString(String instanceId) {
instanceId = instanceId.trim();
Matcher matcher = p.matcher(instanceId);
+ if(matcher.matches() == false) {
+ matcher = pDeprecated.matcher(instanceId);
+ }
+
Preconditions.checkArgument(matcher.matches(), "Unexpected format for provider, expected " + p.toString()
- + " but was " + instanceId);
+ + " or " + pDeprecated.toString() + " but was " + instanceId);
+
String factoryName = matcher.group(1);
String instanceName = matcher.group(2);
return new ServiceInstance(factoryName, instanceName);
return instanceName;
}
- private static final String blueprint = "/" + XmlNetconfConstants.CONFIG_KEY + "/"
+ private static final String blueprint = "/"
+ XmlNetconfConstants.MODULES_KEY + "/" + XmlNetconfConstants.MODULE_KEY + "["
- + XmlNetconfConstants.NAME_KEY + "='%s']/" + XmlNetconfConstants.INSTANCE_KEY + "["
+ + XmlNetconfConstants.TYPE_KEY + "='%s']["
+ XmlNetconfConstants.NAME_KEY + "='%s']";
- private static final String blueprintR = "/" + XmlNetconfConstants.CONFIG_KEY + "/"
+ // TODO unify with xpath in RuntimeRpc
+
+ // Previous version of xpath, needs to be supported for backwards compatibility (persisted configs by config-persister)
+ private static final String blueprintRDeprecated = "/" + 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.MODULES_KEY + "/" + XmlNetconfConstants.MODULE_KEY + "\\["
+ + XmlNetconfConstants.TYPE_KEY + "='%s'\\]\\["
+ + XmlNetconfConstants.NAME_KEY + "='%s'\\]";
+
+ private static final Pattern pDeprecated = Pattern.compile(String.format(blueprintRDeprecated, "(.+)", "(.+)"));
private static final Pattern p = Pattern.compile(String.format(blueprintR, "(.+)", "(.+)"));
@Override
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.management.InstanceAlreadyExistsException;
edit("netconfMessages/editConfig.xml");
checkBinaryLeafEdited(getConfigCandidate());
+
// default-operation:none, should not affect binary leaf
edit("netconfMessages/editConfig_none.xml");
checkBinaryLeafEdited(getConfigCandidate());
checkBinaryLeafEdited(response);
checkTypeConfigAttribute(response);
checkTypedefs(response);
+ checkTestingDeps(response);
checkEnum(response);
checkBigDecimal(response);
}
private void checkBigDecimal(Element response) {
- int size = response.getElementsByTagName("sleep-factor").getLength();
- assertEquals(1, size);
+ String responseTrimmed = XmlUtil.toString(response).replaceAll("\\s", "");
+
+ assertContainsString(responseTrimmed, "<sleep-factorxmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">2.58</sleep-factor>");
+ // Default
+ assertContainsString(responseTrimmed, "<sleep-factorxmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">2.00</sleep-factor>");
+
}
private void closeSession() throws NetconfDocumentedException, ParserConfigurationException, SAXException,
edit("netconfMessages/namespaces/editConfig_sameAttrDifferentNamespaces.xml");
} catch (NetconfDocumentedException e) {
String message = e.getMessage();
- assertThat(message,
- JUnitMatchers
- .containsString("Element simple-long-2 present multiple times with different namespaces"));
- assertThat(message,
- JUnitMatchers.containsString("urn:opendaylight:params:xml:ns:yang:controller:test:impl"));
- assertThat(message,
- JUnitMatchers
- .containsString(XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG));
+ assertContainsString(message, "Element simple-long-2 present multiple times with different namespaces");
+ assertContainsString(message, "urn:opendaylight:params:xml:ns:yang:controller:test:impl");
+ assertContainsString(message, XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
throw e;
}
}
edit("netconfMessages/namespaces/editConfig_differentNamespaceTO.xml");
} catch (NetconfDocumentedException e) {
String message = e.getMessage();
- assertThat(message, JUnitMatchers.containsString("Unrecognised elements"));
- assertThat(message, JUnitMatchers.containsString("simple-int2"));
- assertThat(message, JUnitMatchers.containsString("dto_d"));
+ assertContainsString(message, "Unrecognised elements");
+ assertContainsString(message, "simple-int2");
+ assertContainsString(message, "dto_d");
throw e;
}
}
edit("netconfMessages/namespaces/editConfig_sameAttrDifferentNamespacesList.xml");
} catch (NetconfDocumentedException e) {
String message = e.getMessage();
- assertThat(message,
- JUnitMatchers.containsString("Element binaryLeaf present multiple times with different namespaces"));
- assertThat(message,
- JUnitMatchers.containsString("urn:opendaylight:params:xml:ns:yang:controller:test:impl"));
- assertThat(message,
- JUnitMatchers
- .containsString(XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG));
+ assertContainsString(message, "Element binaryLeaf present multiple times with different namespaces");
+ assertContainsString(message, "urn:opendaylight:params:xml:ns:yang:controller:test:impl");
+ assertContainsString(message, XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
throw e;
}
}
try {
edit(file);
} catch (NetconfDocumentedException e) {
- assertThat(e.getMessage(), JUnitMatchers.containsString("Unrecognised elements"));
- assertThat(e.getMessage(), JUnitMatchers.containsString("unknownAttribute"));
+ assertContainsString(e.getMessage(), "Unrecognised elements");
+ assertContainsString(e.getMessage(), "unknownAttribute");
continue;
}
fail("Unrecognised test should throw exception " + file);
}
private void checkBinaryLeafEdited(final Element response) {
- final NodeList children = response.getElementsByTagName("binaryLeaf");
- assertEquals(3, children.getLength());
- final StringBuffer buf = new StringBuffer();
- for (int i = 0; i < 3; i++) {
- final Element e = (Element) children.item(i);
- buf.append(XmlElement.fromDomElement(e).getTextContent());
- }
- assertEquals("810", buf.toString());
+ String responseTrimmed = XmlUtil.toString(response).replaceAll("\\s", "");
+ String substring = "<binaryLeafxmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">YmluYXJ5</binaryLeaf>";
+ assertContainsString(responseTrimmed, substring);
+ substring = "<binaryLeafxmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">ZGVmYXVsdEJpbg==</binaryLeaf>";
+ assertContainsString(responseTrimmed, substring);
}
private void checkTypedefs(final Element response) {
- NodeList children = response.getElementsByTagName("extended");
- assertEquals(1, children.getLength());
+ String responseTrimmed = XmlUtil.toString(response).replaceAll("\\s", "");
+
+ String substring = "<extendedxmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">10</extended>";
+ assertContainsString(responseTrimmed, substring);
+ // Default
+ assertContainsString(responseTrimmed,
+ "<extendedxmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">1</extended>");
- children = response.getElementsByTagName("extended-twice");
- assertEquals(1, children.getLength());
+ assertContainsString(responseTrimmed,
+ "<extended-twicexmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">20</extended-twice>");
+ // Default
+ assertContainsString(responseTrimmed,
+ "<extended-twicexmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">2</extended-twice>");
+
+ assertContainsString(responseTrimmed,
+ "<extended-enumxmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">TWO</extended-enum>");
+ // Default
+ assertContainsString(responseTrimmed,
+ "<extended-enumxmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">ONE</extended-enum>");
+ }
+
+ private void assertContainsString(String string, String substring) {
+ assertThat(string, JUnitMatchers.containsString(substring));
}
private void checkEnum(final Element response) {
fail("Enum attribute " + enumName + ":" + enumContent + " not present in " + XmlUtil.toString(response));
}
+ private void checkTestingDeps(Element response) {
+ int testingDepsSize = response.getElementsByTagName("testing-deps").getLength();
+ assertEquals(2, testingDepsSize);
+ }
+
private void checkTypeConfigAttribute(Element response) {
XmlElement modulesElement = XmlElement.fromDomElement(response).getOnlyChildElement("data")
RuntimeRpc netconf = new RuntimeRpc(yangStoreSnapshot, configRegistryClient, NETCONF_SESSION_ID);
response = executeOp(netconf, "netconfMessages/rpc.xml");
- assertThat(XmlUtil.toString(response), JUnitMatchers.containsString("testarg1".toUpperCase()));
+ assertContainsString(XmlUtil.toString(response), "testarg1".toUpperCase());
response = executeOp(netconf, "netconfMessages/rpcInner.xml");
- assertThat(XmlUtil.toString(response), JUnitMatchers.containsString("ok"));
+ assertContainsString(XmlUtil.toString(response), "ok");
response = executeOp(netconf, "netconfMessages/rpcInnerInner.xml");
- assertThat(XmlUtil.toString(response), JUnitMatchers.containsString("true"));
+ assertContainsString(XmlUtil.toString(response), "true");
response = executeOp(netconf, "netconfMessages/rpcInnerInner_complex_output.xml");
- assertThat(XmlUtil.toString(response), JUnitMatchers.containsString("1"));
- assertThat(XmlUtil.toString(response), JUnitMatchers.containsString("2"));
+ assertContainsString(XmlUtil.toString(response), "1");
+ assertContainsString(XmlUtil.toString(response), "2");
}
private Element get() throws NetconfDocumentedException, ParserConfigurationException, SAXException, IOException {
package org.opendaylight.controller.netconf.persist.impl;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Sets;
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.nio.NioEventLoopGroup;
-import java.io.Closeable;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.InetSocketAddress;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.regex.Pattern;
-import javax.annotation.concurrent.ThreadSafe;
-import javax.management.InstanceNotFoundException;
-import javax.management.MBeanServerConnection;
-import javax.management.Notification;
-import javax.management.NotificationListener;
-import javax.management.ObjectName;
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathExpression;
-import org.opendaylight.controller.config.api.ConflictingVersionException;
-import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
-import org.opendaylight.controller.config.persist.api.Persister;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.jmx.CommitJMXNotification;
import org.opendaylight.controller.netconf.api.jmx.DefaultCommitOperationMXBean;
import org.opendaylight.controller.netconf.api.jmx.NetconfJMXNotification;
import org.opendaylight.controller.netconf.client.NetconfClient;
-import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
-import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil;
-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.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.xml.sax.SAXException;
+
+import javax.annotation.concurrent.ThreadSafe;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanServerConnection;
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.regex.Pattern;
/**
* Responsible for listening for notifications from netconf containing latest
public class ConfigPersisterNotificationHandler implements NotificationListener, Closeable {
private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterNotificationHandler.class);
- private static final int NETCONF_SEND_ATTEMPT_MS_DELAY = 1000;
- private static final int NETCONF_SEND_ATTEMPTS = 20;
-
- private final InetSocketAddress address;
- private final EventLoopGroup nettyThreadgroup;
-
- private NetconfClientDispatcher netconfClientDispatcher;
- private NetconfClient netconfClient;
-
- private final Persister persister;
- private final MBeanServerConnection mbeanServer;
-
-
- private final ObjectName on = DefaultCommitOperationMXBean.objectName;
-
- public static final long DEFAULT_TIMEOUT = 120000L;// 120 seconds until netconf must be stable
- private final long timeout;
+ private final MBeanServerConnection mBeanServerConnection;
+ private final NetconfClient netconfClient;
+ private final PersisterAggregator persisterAggregator;
private final Pattern ignoredMissingCapabilityRegex;
- public ConfigPersisterNotificationHandler(Persister persister, InetSocketAddress address,
- MBeanServerConnection mbeanServer, Pattern ignoredMissingCapabilityRegex) {
- this(persister, address, mbeanServer, DEFAULT_TIMEOUT, ignoredMissingCapabilityRegex);
-
- }
-
- public ConfigPersisterNotificationHandler(Persister persister, InetSocketAddress address,
- MBeanServerConnection mbeanServer, long timeout, Pattern ignoredMissingCapabilityRegex) {
- this.persister = persister;
- this.address = address;
- this.mbeanServer = mbeanServer;
- this.timeout = timeout;
-
- this.nettyThreadgroup = new NioEventLoopGroup();
+ public ConfigPersisterNotificationHandler(MBeanServerConnection mBeanServerConnection, NetconfClient netconfClient,
+ PersisterAggregator persisterAggregator, Pattern ignoredMissingCapabilityRegex) {
+ this.mBeanServerConnection = mBeanServerConnection;
+ this.netconfClient = netconfClient;
+ this.persisterAggregator = persisterAggregator;
this.ignoredMissingCapabilityRegex = ignoredMissingCapabilityRegex;
}
- public void init() throws InterruptedException {
- Optional<ConfigSnapshotHolder> maybeConfig = loadLastConfig();
-
- if (maybeConfig.isPresent()) {
- logger.debug("Last config found {}", persister);
- ConflictingVersionException lastException = null;
- pushLastConfigWithRetries(maybeConfig, lastException);
-
- } else {
- // this ensures that netconf is initialized, this is first
- // connection
- // this means we can register as listener for commit
- registerToNetconf(Collections.<String>emptySet());
-
- logger.info("No last config provided by backend storage {}", persister);
- }
+ public void init() {
registerAsJMXListener();
}
- private void pushLastConfigWithRetries(Optional<ConfigSnapshotHolder> maybeConfig, ConflictingVersionException lastException) throws InterruptedException {
- int maxAttempts = 30;
- for(int i = 0 ; i < maxAttempts; i++) {
- registerToNetconf(maybeConfig.get().getCapabilities());
-
- final String configSnapshot = maybeConfig.get().getConfigSnapshot();
- logger.trace("Pushing following xml to netconf {}", configSnapshot);
- try {
- pushLastConfig(XmlUtil.readXmlToElement(configSnapshot));
- return;
- } catch(ConflictingVersionException e) {
- closeClientAndDispatcher(netconfClient, netconfClientDispatcher);
- lastException = e;
- Thread.sleep(1000);
- } catch (SAXException | IOException e) {
- throw new IllegalStateException("Unable to load last config", e);
- }
- }
- throw new IllegalStateException("Failed to push configuration, maximum attempt count has been reached: "
- + maxAttempts, lastException);
- }
-
- private synchronized long registerToNetconf(Set<String> expectedCaps) throws InterruptedException {
-
- Set<String> currentCapabilities = Sets.newHashSet();
-
- // TODO think about moving capability subset check to netconf client
- // could be utilized by integration tests
-
- long pollingStart = System.currentTimeMillis();
- int delay = 5000;
-
- int attempt = 0;
-
- long deadline = pollingStart + timeout;
- while (System.currentTimeMillis() < deadline) {
- attempt++;
- netconfClientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup);
- try {
- netconfClient = new NetconfClient(this.toString(), address, delay, netconfClientDispatcher);
- } catch (IllegalStateException e) {
- logger.debug("Netconf {} was not initialized or is not stable, attempt {}", address, attempt, e);
- netconfClientDispatcher.close();
- Thread.sleep(delay);
- continue;
- }
- currentCapabilities = netconfClient.getCapabilities();
-
- if (isSubset(currentCapabilities, expectedCaps)) {
- logger.debug("Hello from netconf stable with {} capabilities", currentCapabilities);
- long currentSessionId = netconfClient.getSessionId();
- logger.info("Session id received from netconf server: {}", currentSessionId);
- return currentSessionId;
- }
-
-
-
- logger.debug("Polling hello from netconf, attempt {}, capabilities {}", attempt, currentCapabilities);
-
- closeClientAndDispatcher(netconfClient, netconfClientDispatcher);
-
- Thread.sleep(delay);
- }
- Set<String> allNotFound = new HashSet<>(expectedCaps);
- allNotFound.removeAll(currentCapabilities);
- logger.error("Netconf server did not provide required capabilities. Expected but not found: {}, all expected {}, current {}",
- allNotFound, expectedCaps ,currentCapabilities);
- throw new RuntimeException("Netconf server did not provide required capabilities. Expected but not found:" + allNotFound);
-
- }
-
- private static void closeClientAndDispatcher(Closeable client, Closeable dispatcher) {
- Exception fromClient = null;
- try {
- client.close();
- } catch (Exception e) {
- fromClient = e;
- } finally {
- try {
- dispatcher.close();
- } catch (Exception e) {
- if (fromClient != null) {
- e.addSuppressed(fromClient);
- }
-
- throw new RuntimeException("Error closing temporary client ", e);
- }
- }
- }
-
- private boolean isSubset(Set<String> currentCapabilities, Set<String> expectedCaps) {
- for (String exCap : expectedCaps) {
- if (currentCapabilities.contains(exCap) == false)
- return false;
- }
- return true;
- }
-
private void registerAsJMXListener() {
logger.trace("Called registerAsJMXListener");
try {
- mbeanServer.addNotificationListener(on, this, null, null);
+ mBeanServerConnection.addNotificationListener(DefaultCommitOperationMXBean.objectName, this, null, null);
} catch (InstanceNotFoundException | IOException e) {
throw new RuntimeException("Cannot register as JMX listener to netconf", e);
}
private void handleAfterCommitNotification(final CommitJMXNotification notification) {
try {
- persister.persistConfig(new CapabilityStrippingConfigSnapshotHolder(notification.getConfigSnapshot(),
+ persisterAggregator.persistConfig(new CapabilityStrippingConfigSnapshotHolder(notification.getConfigSnapshot(),
notification.getCapabilities(), ignoredMissingCapabilityRegex));
logger.info("Configuration persisted successfully");
} catch (IOException e) {
}
}
- private Optional<ConfigSnapshotHolder> loadLastConfig() {
- Optional<ConfigSnapshotHolder> maybeConfigElement;
- try {
- maybeConfigElement = persister.loadLastConfig();
- } catch (IOException e) {
- throw new RuntimeException("Unable to load configuration", e);
- }
- return maybeConfigElement;
- }
-
- private synchronized void pushLastConfig(Element xmlToBePersisted) throws ConflictingVersionException {
- logger.info("Pushing last configuration to netconf");
- StringBuilder response = new StringBuilder("editConfig response = {");
-
-
- NetconfMessage message = createEditConfigMessage(xmlToBePersisted, "/netconfOp/editConfig.xml");
-
- // sending message to netconf
- NetconfMessage responseMessage = netconfClient.sendMessage(message, NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
-
- XmlElement element = XmlElement.fromDomDocument(responseMessage.getDocument());
- Preconditions.checkState(element.getName().equals(XmlNetconfConstants.RPC_REPLY_KEY));
- element = element.getOnlyChildElement();
-
- checkIsOk(element, responseMessage);
- response.append(XmlUtil.toString(responseMessage.getDocument()));
- response.append("}");
- responseMessage = netconfClient.sendMessage(getNetconfMessageFromResource("/netconfOp/commit.xml"), NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
-
- element = XmlElement.fromDomDocument(responseMessage.getDocument());
- Preconditions.checkState(element.getName().equals(XmlNetconfConstants.RPC_REPLY_KEY));
- element = element.getOnlyChildElement();
-
- checkIsOk(element, responseMessage);
- response.append("commit response = {");
- response.append(XmlUtil.toString(responseMessage.getDocument()));
- response.append("}");
- logger.info("Last configuration loaded successfully");
- logger.trace("Detailed message {}", response);
- }
-
- static void checkIsOk(XmlElement element, NetconfMessage responseMessage) throws ConflictingVersionException {
- if (element.getName().equals(XmlNetconfConstants.OK)) {
- return;
- }
-
- if (element.getName().equals(XmlNetconfConstants.RPC_ERROR)) {
- logger.warn("Can not load last configuration, operation failed");
- // is it ConflictingVersionException ?
- XPathExpression xPathExpression = XMLNetconfUtil.compileXPath("/netconf:rpc-reply/netconf:rpc-error/netconf:error-info/netconf:error");
- String error = (String) XmlUtil.evaluateXPath(xPathExpression, element.getDomElement(), XPathConstants.STRING);
- if (error!=null && error.contains(ConflictingVersionException.class.getCanonicalName())) {
- throw new ConflictingVersionException(error);
- }
- throw new IllegalStateException("Can not load last configuration, operation failed: "
- + XmlUtil.toString(responseMessage.getDocument()));
- }
-
- logger.warn("Can not load last configuration. Operation failed.");
- throw new IllegalStateException("Can not load last configuration. Operation failed: "
- + XmlUtil.toString(responseMessage.getDocument()));
- }
-
- private static NetconfMessage createEditConfigMessage(Element dataElement, String editConfigResourcename) {
- try (InputStream stream = ConfigPersisterNotificationHandler.class.getResourceAsStream(editConfigResourcename)) {
- Preconditions.checkNotNull(stream, "Unable to load resource " + editConfigResourcename);
-
- Document doc = XmlUtil.readXmlToDocument(stream);
-
- doc.getDocumentElement();
- XmlElement editConfigElement = XmlElement.fromDomDocument(doc).getOnlyChildElement();
- XmlElement configWrapper = editConfigElement.getOnlyChildElement(XmlNetconfConstants.CONFIG_KEY);
- editConfigElement.getDomElement().removeChild(configWrapper.getDomElement());
- for (XmlElement el : XmlElement.fromDomElement(dataElement).getChildElements()) {
- configWrapper.appendChild((Element) doc.importNode(el.getDomElement(), true));
- }
- editConfigElement.appendChild(configWrapper.getDomElement());
- return new NetconfMessage(doc);
- } catch (IOException | SAXException e) {
- throw new RuntimeException("Unable to parse message from resources " + editConfigResourcename, e);
- }
- }
-
- private NetconfMessage getNetconfMessageFromResource(String resource) {
- try (InputStream stream = getClass().getResourceAsStream(resource)) {
- Preconditions.checkNotNull(stream, "Unable to load resource " + resource);
- return new NetconfMessage(XmlUtil.readXmlToDocument(stream));
- } catch (SAXException | IOException e) {
- throw new RuntimeException("Unable to parse message from resources " + resource, e);
- }
- }
-
@Override
public synchronized void close() {
- // TODO persister is received from constructor, should not be closed
- // here
- try {
- persister.close();
- } catch (Exception e) {
- logger.warn("Unable to close config persister {}", persister, e);
- }
-
- if (netconfClient != null) {
- try {
- netconfClient.close();
- } catch (Exception e) {
- logger.warn("Unable to close connection to netconf {}", netconfClient, e);
- }
- }
-
- if (netconfClientDispatcher != null) {
- try {
- netconfClientDispatcher.close();
- } catch (Exception e) {
- logger.warn("Unable to close connection to netconf {}", netconfClientDispatcher, e);
- }
- }
-
- try {
- nettyThreadgroup.shutdownGracefully();
- } catch (Exception e) {
- logger.warn("Unable to close netconf client thread group {}", netconfClientDispatcher, e);
- }
-
// unregister from JMX
+ ObjectName on = DefaultCommitOperationMXBean.objectName;
try {
- if (mbeanServer.isRegistered(on)) {
- mbeanServer.removeNotificationListener(on, this);
+ if (mBeanServerConnection.isRegistered(on)) {
+ mBeanServerConnection.removeNotificationListener(on, this);
}
} catch (Exception e) {
logger.warn("Unable to unregister {} as listener for {}", this, on, e);
}
}
+
+ public NetconfClient getNetconfClient() {
+ return netconfClient;
+ }
+
}
--- /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.persist.impl;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import io.netty.channel.EventLoopGroup;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.client.NetconfClient;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+import javax.annotation.concurrent.Immutable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@Immutable
+public class ConfigPusher {
+ private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterNotificationHandler.class);
+ private static final int NETCONF_SEND_ATTEMPT_MS_DELAY = 1000;
+ private static final int NETCONF_SEND_ATTEMPTS = 20;
+
+ private final InetSocketAddress address;
+ private final EventLoopGroup nettyThreadgroup;
+
+
+ public static final long DEFAULT_TIMEOUT = 120000L;// 120 seconds until netconf must be stable
+ private final long timeout;
+
+ public ConfigPusher(InetSocketAddress address, EventLoopGroup nettyThreadgroup) {
+ this(address, DEFAULT_TIMEOUT, nettyThreadgroup);
+
+ }
+
+ public ConfigPusher(InetSocketAddress address, long timeout, EventLoopGroup nettyThreadgroup) {
+ this.address = address;
+ this.timeout = timeout;
+
+ this.nettyThreadgroup = nettyThreadgroup;
+ }
+
+ public synchronized NetconfClient init(List<ConfigSnapshotHolder> configs) throws InterruptedException {
+ logger.debug("Last config snapshots to be pushed to netconf: {}", configs);
+ return pushAllConfigs(configs);
+ }
+
+ private synchronized NetconfClient pushAllConfigs(List<ConfigSnapshotHolder> configs) throws InterruptedException {
+ NetconfClient netconfClient = makeNetconfConnection(Collections.<String>emptySet(), Optional.<NetconfClient>absent());
+ for (ConfigSnapshotHolder configSnapshotHolder: configs){
+ netconfClient = pushSnapshotWithRetries(configSnapshotHolder, Optional.of(netconfClient));
+ }
+ return netconfClient;
+ }
+
+ private synchronized NetconfClient pushSnapshotWithRetries(ConfigSnapshotHolder configSnapshotHolder,
+ Optional<NetconfClient> oldClientForPossibleReuse)
+ throws InterruptedException {
+
+ ConflictingVersionException lastException = null;
+ int maxAttempts = 30;
+ for(int i = 0 ; i < maxAttempts; i++) {
+ NetconfClient netconfClient = makeNetconfConnection(configSnapshotHolder.getCapabilities(), oldClientForPossibleReuse);
+ final String configSnapshot = configSnapshotHolder.getConfigSnapshot();
+ logger.trace("Pushing following xml to netconf {}", configSnapshot);
+ try {
+ pushLastConfig(configSnapshotHolder, netconfClient);
+ return netconfClient;
+ } catch(ConflictingVersionException e) {
+ Util.closeClientAndDispatcher(netconfClient);
+ lastException = e;
+ Thread.sleep(1000);
+ } catch (SAXException | IOException e) {
+ throw new IllegalStateException("Unable to load last config", e);
+ }
+ }
+ throw new IllegalStateException("Failed to push configuration, maximum attempt count has been reached: "
+ + maxAttempts, lastException);
+ }
+
+ /**
+ * @param expectedCaps capabilities that server hello must contain. Will retry until all are found or throws RuntimeException.
+ * If empty set is provided, will only make sure netconf client successfuly connected to the server.
+ * @param oldClientForPossibleReuse if present, try to get expected capabilities from it before closing it and retrying with
+ * new client connection.
+ * @return NetconfClient that has all required capabilities from server.
+ */
+ private synchronized NetconfClient makeNetconfConnection(Set<String> expectedCaps,
+ Optional<NetconfClient> oldClientForPossibleReuse)
+ throws InterruptedException {
+
+ if (oldClientForPossibleReuse.isPresent()) {
+ NetconfClient oldClient = oldClientForPossibleReuse.get();
+ if (Util.isSubset(oldClient, expectedCaps)) {
+ return oldClient;
+ } else {
+ Util.closeClientAndDispatcher(oldClient);
+ }
+ }
+
+ // TODO think about moving capability subset check to netconf client
+ // could be utilized by integration tests
+
+ long pollingStart = System.currentTimeMillis();
+ int delay = 5000;
+
+ int attempt = 0;
+
+ long deadline = pollingStart + timeout;
+
+ Set<String> latestCapabilities = new HashSet<>();
+ while (System.currentTimeMillis() < deadline) {
+ attempt++;
+ NetconfClientDispatcher netconfClientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup);
+ NetconfClient netconfClient;
+ try {
+ netconfClient = new NetconfClient(this.toString(), address, delay, netconfClientDispatcher);
+ } catch (IllegalStateException e) {
+ logger.debug("Netconf {} was not initialized or is not stable, attempt {}", address, attempt, e);
+ netconfClientDispatcher.close();
+ Thread.sleep(delay);
+ continue;
+ }
+ latestCapabilities = netconfClient.getCapabilities();
+ if (Util.isSubset(netconfClient, expectedCaps)) {
+ logger.debug("Hello from netconf stable with {} capabilities", latestCapabilities);
+ logger.info("Session id received from netconf server: {}", netconfClient.getClientSession());
+ return netconfClient;
+ }
+ logger.debug("Polling hello from netconf, attempt {}, capabilities {}", attempt, latestCapabilities);
+ Util.closeClientAndDispatcher(netconfClient);
+ Thread.sleep(delay);
+ }
+ Set<String> allNotFound = new HashSet<>(expectedCaps);
+ allNotFound.removeAll(latestCapabilities);
+ logger.error("Netconf server did not provide required capabilities. Expected but not found: {}, all expected {}, current {}",
+ allNotFound, expectedCaps, latestCapabilities);
+ throw new RuntimeException("Netconf server did not provide required capabilities. Expected but not found:" + allNotFound);
+ }
+
+
+ private synchronized void pushLastConfig(ConfigSnapshotHolder configSnapshotHolder, NetconfClient netconfClient)
+ throws ConflictingVersionException, IOException, SAXException {
+
+ Element xmlToBePersisted = XmlUtil.readXmlToElement(configSnapshotHolder.getConfigSnapshot());
+ logger.info("Pushing last configuration to netconf: {}", configSnapshotHolder);
+ StringBuilder response = new StringBuilder("editConfig response = {");
+
+
+ NetconfMessage message = createEditConfigMessage(xmlToBePersisted, "/netconfOp/editConfig.xml");
+
+ // sending message to netconf
+ NetconfMessage responseMessage = netconfClient.sendMessage(message, NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
+
+ XmlElement element = XmlElement.fromDomDocument(responseMessage.getDocument());
+ Preconditions.checkState(element.getName().equals(XmlNetconfConstants.RPC_REPLY_KEY));
+ element = element.getOnlyChildElement();
+
+ Util.checkIsOk(element, responseMessage);
+ response.append(XmlUtil.toString(responseMessage.getDocument()));
+ response.append("}");
+ responseMessage = netconfClient.sendMessage(getNetconfMessageFromResource("/netconfOp/commit.xml"), NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
+
+ element = XmlElement.fromDomDocument(responseMessage.getDocument());
+ Preconditions.checkState(element.getName().equals(XmlNetconfConstants.RPC_REPLY_KEY));
+ element = element.getOnlyChildElement();
+
+ Util.checkIsOk(element, responseMessage);
+ response.append("commit response = {");
+ response.append(XmlUtil.toString(responseMessage.getDocument()));
+ response.append("}");
+ logger.info("Last configuration loaded successfully");
+ logger.trace("Detailed message {}", response);
+ }
+
+ private static NetconfMessage createEditConfigMessage(Element dataElement, String editConfigResourcename) {
+ try (InputStream stream = ConfigPersisterNotificationHandler.class.getResourceAsStream(editConfigResourcename)) {
+ Preconditions.checkNotNull(stream, "Unable to load resource " + editConfigResourcename);
+
+ Document doc = XmlUtil.readXmlToDocument(stream);
+
+ doc.getDocumentElement();
+ XmlElement editConfigElement = XmlElement.fromDomDocument(doc).getOnlyChildElement();
+ XmlElement configWrapper = editConfigElement.getOnlyChildElement(XmlNetconfConstants.CONFIG_KEY);
+ editConfigElement.getDomElement().removeChild(configWrapper.getDomElement());
+ for (XmlElement el : XmlElement.fromDomElement(dataElement).getChildElements()) {
+ configWrapper.appendChild((Element) doc.importNode(el.getDomElement(), true));
+ }
+ editConfigElement.appendChild(configWrapper.getDomElement());
+ return new NetconfMessage(doc);
+ } catch (IOException | SAXException e) {
+ throw new RuntimeException("Unable to parse message from resources " + editConfigResourcename, e);
+ }
+ }
+
+ private static NetconfMessage getNetconfMessageFromResource(String resource) {
+ try (InputStream stream = ConfigPusher.class.getResourceAsStream(resource)) {
+ Preconditions.checkNotNull(stream, "Unable to load resource " + resource);
+ return new NetconfMessage(XmlUtil.readXmlToDocument(stream));
+ } catch (SAXException | IOException e) {
+ throw new RuntimeException("Unable to parse message from resources " + resource, e);
+ }
+ }
+}
package org.opendaylight.controller.netconf.persist.impl;
-import com.google.common.base.Optional;
import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
import org.opendaylight.controller.config.persist.api.Persister;
import org.opendaylight.controller.config.persist.api.PropertiesProvider;
import org.slf4j.LoggerFactory;
import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
public class NoOpStorageAdapter implements StorageAdapter, Persister {
private static final Logger logger = LoggerFactory.getLogger(NoOpStorageAdapter.class);
}
@Override
- public Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException {
+ public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
logger.debug("loadLastConfig called");
- return Optional.absent();
+ return Collections.emptyList();
}
@Override
package org.opendaylight.controller.netconf.persist.impl;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Optional;
import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
import org.opendaylight.controller.config.persist.api.Persister;
import org.opendaylight.controller.config.persist.api.StorageAdapter;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
</pre>
* During server startup {@link ConfigPersisterNotificationHandler} requests last snapshot from underlying storages.
* Each storage can respond by giving snapshot or absent response.
- * The {@link #loadLastConfig()} will search for first non-absent response from storages ordered backwards as user
+ * The {@link #loadLastConfigs()} will search for first non-absent response from storages ordered backwards as user
* specified (first '3', then '2').
*
* When a commit notification is received, '2' will be omitted because readonly flag is set to true, so
}
}
+ /**
+ * @return last non-empty result from input persisters
+ */
@Override
- public Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException {
+ public List<ConfigSnapshotHolder> loadLastConfigs() {
// iterate in reverse order
ListIterator<PersisterWithConfiguration> li = persisterWithConfigurations.listIterator(persisterWithConfigurations.size());
while(li.hasPrevious()) {
PersisterWithConfiguration persisterWithConfiguration = li.previous();
- Optional<ConfigSnapshotHolder> configSnapshotHolderOptional = persisterWithConfiguration.storage.loadLastConfig();
- if (configSnapshotHolderOptional.isPresent()) {
- return configSnapshotHolderOptional;
+ List<ConfigSnapshotHolder> configs = null;
+ try {
+ configs = persisterWithConfiguration.storage.loadLastConfigs();
+ } catch (IOException e) {
+ throw new RuntimeException("Error while calling loadLastConfig on " + persisterWithConfiguration, e);
+ }
+ if (configs.isEmpty() == false) {
+ logger.debug("Found non empty configs using {}:{}", persisterWithConfiguration, configs);
+ return configs;
}
}
// no storage had an answer
- return Optional.absent();
+ logger.debug("No non-empty list of configuration snapshots found");
+ return Collections.emptyList();
}
@VisibleForTesting
package org.opendaylight.controller.netconf.persist.impl;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ThreadFactory;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.client.NetconfClient;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import java.util.Set;
public final class Util {
+ private static final Logger logger = LoggerFactory.getLogger(Util.class);
+
+
+ public static boolean isSubset(NetconfClient netconfClient, Set<String> expectedCaps) {
+ return isSubset(netconfClient.getCapabilities(), expectedCaps);
+
+ }
+
+ private static boolean isSubset(Set<String> currentCapabilities, Set<String> expectedCaps) {
+ for (String exCap : expectedCaps) {
+ if (currentCapabilities.contains(exCap) == false)
+ return false;
+ }
+ return true;
+ }
+
+
+ // TODO: check if closing in correct order
+ public static void closeClientAndDispatcher(NetconfClient client) {
+ NetconfClientDispatcher dispatcher = client.getNetconfClientDispatcher();
+ Exception fromClient = null;
+ try {
+ client.close();
+ } catch (Exception e) {
+ fromClient = e;
+ } finally {
+ try {
+ dispatcher.close();
+ } catch (Exception e) {
+ if (fromClient != null) {
+ e.addSuppressed(fromClient);
+ }
+ throw new RuntimeException("Error closing temporary client ", e);
+ }
+ }
+ }
- public static ScheduledExecutorService getExecutorServiceWithThreadName(final String threadNamePrefix,
- int threadCount) {
- return Executors.newScheduledThreadPool(threadCount, new ThreadFactory() {
- private int i = 1;
+ public static void checkIsOk(XmlElement element, NetconfMessage responseMessage) throws ConflictingVersionException {
+ if (element.getName().equals(XmlNetconfConstants.OK)) {
+ return;
+ }
- @Override
- public Thread newThread(Runnable r) {
- Thread thread = new Thread(r);
- thread.setName(threadNamePrefix + ":" + i++);
- return thread;
+ if (element.getName().equals(XmlNetconfConstants.RPC_ERROR)) {
+ logger.warn("Can not load last configuration, operation failed");
+ // is it ConflictingVersionException ?
+ XPathExpression xPathExpression = XMLNetconfUtil.compileXPath("/netconf:rpc-reply/netconf:rpc-error/netconf:error-info/netconf:error");
+ String error = (String) XmlUtil.evaluateXPath(xPathExpression, element.getDomElement(), XPathConstants.STRING);
+ if (error!=null && error.contains(ConflictingVersionException.class.getCanonicalName())) {
+ throw new ConflictingVersionException(error);
}
- });
+ throw new IllegalStateException("Can not load last configuration, operation failed: "
+ + XmlUtil.toString(responseMessage.getDocument()));
+ }
+
+ logger.warn("Can not load last configuration. Operation failed.");
+ throw new IllegalStateException("Can not load last configuration. Operation failed: "
+ + XmlUtil.toString(responseMessage.getDocument()));
}
}
package org.opendaylight.controller.netconf.persist.impl.osgi;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import org.opendaylight.controller.netconf.client.NetconfClient;
import org.opendaylight.controller.netconf.persist.impl.ConfigPersisterNotificationHandler;
+import org.opendaylight.controller.netconf.persist.impl.ConfigPusher;
import org.opendaylight.controller.netconf.persist.impl.PersisterAggregator;
+import org.opendaylight.controller.netconf.persist.impl.Util;
import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
private final static MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
private static final String IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX = "ignoredMissingCapabilityRegex";
- private ConfigPersisterNotificationHandler configPersisterNotificationHandler;
+ public static final String NETCONF_CONFIG_PERSISTER = "netconf.config.persister";
- private Thread initializationThread;
+ public static final String STORAGE_ADAPTER_CLASS_PROP_SUFFIX = "storageAdapterClass";
- public static final String NETCONF_CONFIG_PERSISTER = "netconf.config.persister";
- public static final String STORAGE_ADAPTER_CLASS_PROP_SUFFIX = "storageAdapterClass";
public static final String DEFAULT_IGNORED_REGEX = "^urn:ietf:params:xml:ns:netconf:base:1.0";
+
+ private volatile ConfigPersisterNotificationHandler jmxNotificationHandler;
+ private volatile NetconfClient netconfClient;
+ private Thread initializationThread;
+ private EventLoopGroup nettyThreadgroup;
+ private PersisterAggregator persisterAggregator;
+
@Override
public void start(final BundleContext context) throws Exception {
logger.debug("ConfigPersister starting");
} else {
regex = DEFAULT_IGNORED_REGEX;
}
- Pattern ignoredMissingCapabilityRegex = Pattern.compile(regex);
- PersisterAggregator persister = PersisterAggregator.createFromProperties(propertiesProvider);
+ final Pattern ignoredMissingCapabilityRegex = Pattern.compile(regex);
+ nettyThreadgroup = new NioEventLoopGroup();
+
+ persisterAggregator = PersisterAggregator.createFromProperties(propertiesProvider);
+ final InetSocketAddress address = NetconfConfigUtil.extractTCPNetconfAddress(context, "Netconf is not configured, persister is not operational", true);
+ final ConfigPusher configPusher = new ConfigPusher(address, nettyThreadgroup);
- InetSocketAddress address = NetconfConfigUtil.extractTCPNetconfAddress(context,
- "Netconf is not configured, persister is not operational",true);
- configPersisterNotificationHandler = new ConfigPersisterNotificationHandler(persister, address,
- platformMBeanServer, ignoredMissingCapabilityRegex);
// offload initialization to another thread in order to stop blocking activator
Runnable initializationRunnable = new Runnable() {
@Override
public void run() {
try {
- configPersisterNotificationHandler.init();
+ netconfClient = configPusher.init(persisterAggregator.loadLastConfigs());
+ jmxNotificationHandler = new ConfigPersisterNotificationHandler(
+ platformMBeanServer, netconfClient, persisterAggregator,
+ ignoredMissingCapabilityRegex);
+ jmxNotificationHandler.init();
} catch (InterruptedException e) {
logger.info("Interrupted while waiting for netconf connection");
}
@Override
public void stop(BundleContext context) throws Exception {
initializationThread.interrupt();
- configPersisterNotificationHandler.close();
+ if (jmxNotificationHandler != null) {
+ jmxNotificationHandler.close();
+ }
+ if (netconfClient != null) {
+ netconfClient = jmxNotificationHandler.getNetconfClient();
+ try {
+ Util.closeClientAndDispatcher(netconfClient);
+ } catch (Exception e) {
+ logger.warn("Unable to close connection to netconf {}", netconfClient, e);
+ }
+ }
+ nettyThreadgroup.shutdownGracefully();
+ persisterAggregator.close();
}
}
public void testConflictingVersionDetection() throws Exception {
Document document = XmlUtil.readXmlToDocument(getClass().getResourceAsStream("/conflictingVersionResponse.xml"));
try{
- ConfigPersisterNotificationHandler.checkIsOk(XmlElement.fromDomDocument(document).getOnlyChildElement(), new NetconfMessage(document));
+ Util.checkIsOk(XmlElement.fromDomDocument(document).getOnlyChildElement(), new NetconfMessage(document));
fail();
}catch(ConflictingVersionException e){
assertThat(e.getMessage(), containsString("Optimistic lock failed. Expected parent version 21, was 18"));
*/
package org.opendaylight.controller.netconf.persist.impl;
-import com.google.common.base.Optional;
import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
import org.opendaylight.controller.config.persist.api.Persister;
import org.opendaylight.controller.config.persist.api.PropertiesProvider;
import org.opendaylight.controller.config.persist.api.StorageAdapter;
import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
public class DummyAdapter implements StorageAdapter, Persister {
static int load = 0;
@Override
- public Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException {
+ public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
load++;
- return Optional.absent();
+ return Collections.emptyList();
}
static int props = 0;
package org.opendaylight.controller.netconf.persist.impl;
-import com.google.common.base.Optional;
import org.junit.Test;
import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
import org.opendaylight.controller.config.persist.api.Persister;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Properties;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.fail;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
import static org.junit.matchers.JUnitMatchers.containsString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
assertFalse(persister.isReadOnly());
persisterAggregator.persistConfig(null);
- persisterAggregator.loadLastConfig();
+ persisterAggregator.loadLastConfigs();
persisterAggregator.persistConfig(null);
- persisterAggregator.loadLastConfig();
+ persisterAggregator.loadLastConfigs();
assertEquals(2, DummyAdapter.persist);
assertEquals(2, DummyAdapter.load);
}
}
+ private ConfigSnapshotHolder mockHolder(String name){
+ ConfigSnapshotHolder result = mock(ConfigSnapshotHolder.class);
+ doReturn("mock:" + name).when(result).toString();
+ return result;
+ }
+
+ private Persister mockPersister(String name){
+ Persister result = mock(Persister.class);
+ doReturn("mock:" + name).when(result).toString();
+ return result;
+ }
+
@Test
public void loadLastConfig() throws Exception {
List<PersisterWithConfiguration> persisterWithConfigurations = new ArrayList<>();
PersisterWithConfiguration first = new PersisterWithConfiguration(mock(Persister.class), false);
- ConfigSnapshotHolder ignored = mock(ConfigSnapshotHolder.class);
- doReturn(Optional.of(ignored)).when(first.getStorage()).loadLastConfig(); // should be ignored
+ ConfigSnapshotHolder ignored = mockHolder("ignored");
+ doReturn(Arrays.asList(ignored)).when(first.getStorage()).loadLastConfigs(); // should be ignored
- ConfigSnapshotHolder used = mock(ConfigSnapshotHolder.class);
- PersisterWithConfiguration second = new PersisterWithConfiguration(mock(Persister.class), false);
- doReturn(Optional.of(used)).when(second.getStorage()).loadLastConfig(); // should be used
- PersisterWithConfiguration third = new PersisterWithConfiguration(mock(Persister.class), false);
- doReturn(Optional.absent()).when(third.getStorage()).loadLastConfig();
+ ConfigSnapshotHolder used = mockHolder("used");
+ PersisterWithConfiguration second = new PersisterWithConfiguration(mockPersister("p1"), false);
+ doReturn(Arrays.asList(used)).when(second.getStorage()).loadLastConfigs(); // should be used
+
+ PersisterWithConfiguration third = new PersisterWithConfiguration(mockPersister("p2"), false);
+ doReturn(Arrays.asList()).when(third.getStorage()).loadLastConfigs();
persisterWithConfigurations.add(first);
persisterWithConfigurations.add(second);
persisterWithConfigurations.add(third);
PersisterAggregator persisterAggregator = new PersisterAggregator(persisterWithConfigurations);
- Optional<ConfigSnapshotHolder> configSnapshotHolderOptional = persisterAggregator.loadLastConfig();
- assertTrue(configSnapshotHolderOptional.isPresent());
- assertEquals(used, configSnapshotHolderOptional.get());
+ List<ConfigSnapshotHolder> configSnapshotHolderOptional = persisterAggregator.loadLastConfigs();
+ assertEquals(1, configSnapshotHolderOptional.size());
+ assertEquals(used, configSnapshotHolderOptional.get(0));
}
-
}
@Override
protected void handleMessage(NetconfMessage netconfMessage) {
- logger.debug("handlign incomming message");
+ logger.debug("handling incoming message");
sessionListener.onMessage(this, netconfMessage);
}
}
}
+ public static NetconfClient clientFor(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strat, NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
+ return new NetconfClient(clientLabelForLogging,address,strat,netconfClientDispatcher);
+ }
+
public NetconfClient(String clientLabelForLogging, InetSocketAddress address, int connectTimeoutMs,
NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
this(clientLabelForLogging, address,
clientSession.close();
}
+ public NetconfClientDispatcher getNetconfClientDispatcher() {
+ return dispatch;
+ }
+
private static ReconnectStrategy getReconnectStrategy(int connectionAttempts, int attemptMsTimeout) {
return new TimedReconnectStrategy(GlobalEventExecutor.INSTANCE, attemptMsTimeout, 1000, 1.0, null,
Long.valueOf(connectionAttempts), null);
<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<capabilities>
<capability>urn:ietf:params:netconf:base:1.0</capability>
+ <capability>urn:ietf:params:netconf:base:1.1</capability>
<capability>urn:ietf:params:netconf:capability:exi:1.0</capability>
</capabilities>
</hello>
\ No newline at end of file
package org.opendaylight.controller.netconf.it;
-import ch.ethz.ssh2.Connection;
-import ch.ethz.ssh2.Session;
-import com.google.common.base.Optional;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
+import static java.util.Collections.emptyList;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.HashedWheelTimer;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.management.ManagementFactory;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import javax.management.ObjectName;
+import javax.xml.parsers.ParserConfigurationException;
+
import junit.framework.Assert;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
-import org.opendaylight.controller.config.persist.api.Persister;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
import org.opendaylight.controller.config.yang.store.api.YangStoreException;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshot;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
-import org.opendaylight.controller.netconf.persist.impl.ConfigPersisterNotificationHandler;
-import org.opendaylight.controller.netconf.persist.impl.osgi.ConfigPersisterActivator;
import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
import org.opendaylight.controller.netconf.util.xml.ExiParameters;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
-import javax.management.ObjectName;
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.management.ManagementFactory;
-import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-import java.util.regex.Pattern;
+import ch.ethz.ssh2.Connection;
+import ch.ethz.ssh2.Session;
-import static java.util.Collections.emptyList;
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertTrue;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
public class NetconfITTest extends AbstractConfigTest {
}
}
+
+ //TODO: test persister actually
+ @Ignore
@Test(timeout = 10000)
public void testPersister() throws Exception {
- Persister persister = mock(Persister.class);
- doReturn("mockPersister").when(persister).toString();
- doReturn(Optional.absent()).when(persister).loadLastConfig();
- ConfigPersisterNotificationHandler h =
- new ConfigPersisterNotificationHandler(persister, tcpAddress, ManagementFactory.getPlatformMBeanServer(), Pattern.compile(ConfigPersisterActivator.DEFAULT_IGNORED_REGEX));
- h.init();
+// Persister persister = mock(Persister.class);
+// doReturn("mockPersister").when(persister).toString();
+// doReturn(Collections.emptyList()).when(persister).loadLastConfigs();
+// ConfigPersisterNotificationHandler h =
+// new ConfigPersisterNotificationHandler(persister, tcpAddress, ManagementFactory.getPlatformMBeanServer(),
+// Pattern.compile(ConfigPersisterActivator.DEFAULT_IGNORED_REGEX));
+// h.init();
}
@Ignore
<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<capabilities>
<capability>urn:ietf:params:netconf:base:1.0</capability>
+ <capability>urn:ietf:params:netconf:base:1.1</capability>
</capabilities>
</hello>
<name>test1</name>
<sleep-factor>
- 2.00
+ 2.58
</sleep-factor>
<extended>
- 1
+ 10
</extended>
<extended-twice>
- 1
+ 20
</extended-twice>
<extended-enum>
</extended-enum>
<simple-long-2>44</simple-long-2>
- <binaryLeaf>8</binaryLeaf>
- <binaryLeaf>1</binaryLeaf>
- <binaryLeaf>0</binaryLeaf>
+ <binaryLeaf>YmluYXJ5</binaryLeaf>
+
<type xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">configAttributeType</type>
<dto_d xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
<simple-int1>444</simple-int1>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
<name>ref_dep</name>
</testing-dep>
+
+ <testing-deps>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <name>ref_dep</name>
+ </testing-deps>
+ <testing-deps>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <name>ref_dep_2</name>
+ </testing-deps>
</module>
<module>
<testing-dep>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep</name>
+ <name>ref_dep_2</name>
</testing-dep>
</module>
</modules>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
<instance>
<name>ref_dep</name>
- <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+ <provider>/modules/module[type='impl-dep'][name='dep']
</provider>
</instance>
<instance>
</instance>
<instance>
<name>ref_test1</name>
- <provider>/config/modules/module[name='impl-netconf']/instance[name='test1']
+ <provider>
+ /modules/module[type='impl-netconf'][name='test1']
</provider>
</instance>
</service>
</type>
<name>test1</name>
<simple-long-2>44</simple-long-2>
- <binaryLeaf>8</binaryLeaf>
- <binaryLeaf>7</binaryLeaf>
- <binaryLeaf>9</binaryLeaf>
+ <binaryLeaf>8ad1</binaryLeaf>
<dto_d>
<simple-int1>444</simple-int1>
<simple-int2>4444</simple-int2>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
<instance>
<name>ref_dep</name>
- <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+ <provider>/modules/module[type='impl-dep'][name='dep']
</provider>
</instance>
<instance>
<name>ref_dep_2</name>
- <provider>/config/modules/module[name='impl-dep']/instance[name='dep2']
+ <provider>/modules/module[type='impl-dep'][name='dep2']
</provider>
</instance>
<instance>
<name>ref_test1</name>
- <provider>/config/modules/module[name='impl-netconf']/instance[name='test1']
+ <provider>
+ /modules/module[type='impl-netconf'][name='test1']
</provider>
</instance>
</service>
<name>test1</name>
<simple-long-2>44</simple-long-2>
- <binaryLeaf>8</binaryLeaf>
- <binaryLeaf>1</binaryLeaf>
- <binaryLeaf>0</binaryLeaf>
+ <binaryLeaf>8545649856</binaryLeaf>
<type xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">configAttributeType</type>
<dto_d>
<simple-int1>444</simple-int1>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
<instance>
<name>ref_dep</name>
- <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+ <provider>/modules/module[type='impl-dep'][name='dep']
</provider>
</instance>
<instance>
<name>ref_dep_2</name>
- <provider>/config/modules/module[name='impl-dep']/instance[name='dep2']
+ <provider>/modules/module[type='impl-dep'][name='dep2']
</provider>
</instance>
<instance>
<name>ref_test1</name>
- <provider>/config/modules/module[name='impl-netconf']/instance[name='test1']
+ <provider>
+ /modules/module[type='impl-netconf'][name='test1']
</provider>
</instance>
</service>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
<instance>
<name>ref_dep</name>
- <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+ <provider>/modules/module[type='impl-dep'][name='dep']
</provider>
</instance>
<instance>
<name>ref_dep_2</name>
- <provider>/config/modules/module[name='impl-dep']/instance[name='dep2']
+ <provider>/modules/module[type='impl-dep'][name='dep2']
</provider>
</instance>
<instance>
<name>ref_test1</name>
- <provider>/config/modules/module[name='impl-netconf']/instance[name='test1']
+ <provider>
+ /modules/module[type='impl-netconf'][name='test1']
</provider>
</instance>
</service>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
<instance>
<name>ref_dep</name>
- <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+ <provider>/modules/module[type='impl-dep'][name='dep']
</provider>
</instance>
<instance>
<name>ref_dep_2</name>
- <provider>/config/modules/module[name='impl-dep']/instance[name='dep2']
+ <provider>/modules/module[type='impl-dep'][name='dep2']
</provider>
</instance>
<instance>
<name>ref_test1</name>
- <provider>/config/modules/module[name='impl-netconf']/instance[name='test1']
+ <provider>
+ /modules/module[type='impl-netconf'][name='test1']
</provider>
</instance>
</service>
<name>test1</name>
<simple-long-2>44</simple-long-2>
- <binaryLeaf>8</binaryLeaf>
- <binaryLeaf>1</binaryLeaf>
- <binaryLeaf>0</binaryLeaf>
+ <binaryLeaf>8545649856</binaryLeaf>
<dto_d xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
<simple-int1>444</simple-int1>
<simple-int2>4444</simple-int2>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
<instance>
<name>ref_dep</name>
- <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+ <provider>/modules/module[type='impl-dep'][name='dep']
</provider>
</instance>
<instance>
<name>ref_dep_2</name>
- <provider>/config/modules/module[name='impl-dep']/instance[name='dep2']
+ <provider>/modules/module[type='impl-dep'][name='dep2']
</provider>
</instance>
<instance>
<name>ref_test1</name>
- <provider>/config/modules/module[name='impl-netconf']/instance[name='test1']
+ <provider>
+ /modules/module[type='impl-netconf'][name='test1']
</provider>
</instance>
</service>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
<instance>
<name>ref_dep</name>
- <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+ <provider>/modules/module[type='impl-dep'][name='dep']
</provider>
</instance>
</service>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
<instance>
<name>ref_dep</name>
- <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+ <provider>/modules/module[type='impl-dep'][name='dep']
</provider>
</instance>
</service>
<instance>
<name>ref_dep</name>
- <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+ <provider>/modules/module[type='impl-dep'][name='dep']
</provider>
</instance>
</service>
<instance>
<name>ref_dep</name>
<unknownAttribute>error</unknownAttribute>
- <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+ <provider>/modules/module[type='impl-dep'][name='dep']
</provider>
</instance>
</service>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
<instance>
<name>ref_dep</name>
- <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+ <provider>/modules/module[type='impl-dep'][name='dep']
</provider>
</instance>
</service>
<name>test1</name>
<simple-long-2>44</simple-long-2>
- <binaryLeaf>8</binaryLeaf>
- <binaryLeaf>1</binaryLeaf>
- <binaryLeaf>0</binaryLeaf>
+ <binaryLeaf>8545649856</binaryLeaf>
<dto_d>
<unknownAttribute>error</unknownAttribute>
<simple-int1>444</simple-int1>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
<instance>
<name>ref_dep</name>
- <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+ <provider>/modules/module[type='impl-dep'][name='dep']
</provider>
</instance>
<instance>
<name>ref_dep_2</name>
- <provider>/config/modules/module[name='impl-dep']/instance[name='dep2']
+ <provider>/modules/module[type='impl-dep'][name='dep2']
</provider>
</instance>
<instance>
<name>ref_test1</name>
- <provider>/config/modules/module[name='impl-netconf']/instance[name='test1']
+ <provider>
+ /modules/module[type='impl-netconf'][name='test1']
</provider>
</instance>
</service>
<name>test1</name>
<simple-long-2>44</simple-long-2>
- <binaryLeaf>8</binaryLeaf>
- <binaryLeaf>1</binaryLeaf>
- <binaryLeaf>0</binaryLeaf>
+ <binaryLeaf>8545649856</binaryLeaf>
<dto_d>
<simple-int1>444</simple-int1>
<simple-int2>4444</simple-int2>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
<instance>
<name>ref_dep</name>
- <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+ <provider>/modules/module[type='impl-dep'][name='dep']
</provider>
</instance>
<instance>
<name>ref_dep_2</name>
- <provider>/config/modules/module[name='impl-dep']/instance[name='dep2']
+ <provider>/modules/module[type='impl-dep'][name='dep2']
</provider>
</instance>
<instance>
<name>ref_test1</name>
- <provider>/config/modules/module[name='impl-netconf']/instance[name='test1']
+ <provider>
+ /modules/module[type='impl-netconf'][name='test1']
</provider>
</instance>
</service>
}
Map<String, Object> nodes = new HashMap<String, Object>();
- Map<Short, String> port;
+ Map<String, String> port;
for (Switch node : switchManager.getNetworkDevices()) {
- port = new HashMap<Short, String>(); // new port
+ port = new HashMap<String, String>(); // new port
Set<NodeConnector> nodeConnectorSet = node.getNodeConnectors();
if (nodeConnectorSet != null) {
for (NodeConnector nodeConnector : nodeConnectorSet) {
String nodeConnectorName = ((Name) switchManager.getNodeConnectorProp(nodeConnector,
Name.NamePropName)).getValue();
- port.put((Short) nodeConnector.getID(),
+ port.put( nodeConnector.getID().toString(),
nodeConnectorName + "(" + nodeConnector.getNodeConnectorIDString() + ")");
}
}