<containermanager.version>0.5.2-SNAPSHOT</containermanager.version>
<controllermanager.northbound.version>0.0.2-SNAPSHOT</controllermanager.northbound.version>
<corsfilter.version>7.0.42</corsfilter.version>
+ <ctrie.version>0.2.0</ctrie.version>
<devices.web.version>0.4.2-SNAPSHOT</devices.web.version>
<eclipse.persistence.version>2.5.0</eclipse.persistence.version>
<!-- enforcer version -->
<artifactId>jackson-module-jaxb-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
+ <dependency>
+ <groupId>com.github.romix</groupId>
+ <artifactId>java-concurrent-hash-trie-map</artifactId>
+ <version>${ctrie.version}</version>
+ </dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
+
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<artifactId>restconf-client-impl</artifactId>
<version>${yangtools.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>util</artifactId>
+ <version>${yangtools.version}</version>
+ </dependency>
<!-- yangtools dependencies -->
<dependency>
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
-
import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.FullyQualifiedNameHelper;
import org.opendaylight.yangtools.yang.common.QName;
private final Map<String, QName> providedServices;
private Collection<RuntimeBeanEntry> runtimeBeans;
+ private String nullableDummyContainerName;
ModuleMXBeanEntry(ModuleMXBeanEntryInitial initials, Map<String, AttributeIfc> yangToAttributes,
Map<String, QName> providedServices2, Collection<RuntimeBeanEntry> runtimeBeans) {
+ '\'' + '}';
}
+ public String getNullableDummyContainerName() {
+ return nullableDummyContainerName;
+ }
+
+ public void setNullableDummyContainerName(String nullableDummyContainerName) {
+ this.nullableDummyContainerName = nullableDummyContainerName;
+ }
+
+
static final class ModuleMXBeanEntryInitial {
private String localName;
*/
package org.opendaylight.controller.config.yangjmxgenerator;
+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.Function;
import com.google.common.base.Optional;
import com.google.common.collect.Collections2;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.annotation.Nullable;
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.yangtools.yang.model.api.ModuleImport;
import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
import org.opendaylight.yangtools.yang.model.api.SchemaPath;
import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
import org.opendaylight.yangtools.yang.model.api.UsesNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import javax.annotation.Nullable;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import static com.google.common.base.Preconditions.checkState;
-import static java.lang.String.format;
-import static org.opendaylight.controller.config.yangjmxgenerator.ConfigConstants.createConfigQName;
-
final class ModuleMXBeanEntryBuilder {
private Module currentModule;
return true;
}
- private void processChoiceCaseNode(Map<String, ModuleMXBeanEntry> result,
+ private <HAS_CHILDREN_AND_QNAME extends DataNodeContainer & SchemaNode> void processChoiceCaseNode(Map<String, ModuleMXBeanEntry> result,
Map<String, QName> uniqueGeneratedClassesNames, String configModulePrefix,
Map<String, IdentitySchemaNode> moduleIdentities,
Map<String, IdentitySchemaNode> unaugmentedModuleIdentities, AugmentationSchema augmentation,
// runtime-data
Collection<RuntimeBeanEntry> runtimeBeans = null;
+ HAS_CHILDREN_AND_QNAME dataNodeContainer = getDataNodeContainer(choiceCaseNode);
+
if (expectedConfigurationAugmentationSchemaPath.equals(augmentation.getTargetPath())) {
logger.debug("Parsing configuration of {}", moduleLocalNameFromXPath);
- yangToAttributes = fillConfiguration(choiceCaseNode, currentModule, typeProviderWrapper, qNamesToSIEs,
+ yangToAttributes = fillConfiguration(dataNodeContainer, currentModule, typeProviderWrapper, qNamesToSIEs,
schemaContext, packageName);
checkUniqueAttributesWithGeneratedClass(uniqueGeneratedClassesNames, when.getQName(), yangToAttributes);
} else if (expectedStateAugmentationSchemaPath.equals(augmentation.getTargetPath())) {
logger.debug("Parsing state of {}", moduleLocalNameFromXPath);
try {
- runtimeBeans = fillRuntimeBeans(choiceCaseNode, currentModule, typeProviderWrapper, packageName,
+ runtimeBeans = fillRuntimeBeans(dataNodeContainer, currentModule, typeProviderWrapper, packageName,
moduleLocalNameFromXPath, javaNamePrefix);
} catch (NameConflictException e) {
throw new NameConflictException(e.getConflictingName(), when.getQName(), when.getQName());
} else {
throw new IllegalArgumentException("Cannot parse augmentation " + augmentation);
}
+ boolean hasDummyContainer = choiceCaseNode.equals(dataNodeContainer) == false;
+
+ String nullableDummyContainerName = hasDummyContainer ? dataNodeContainer.getQName().getLocalName() : null;
if (result.containsKey(moduleLocalNameFromXPath)) {
- // either fill runtimeBeans or yangToAttributes
+ // either fill runtimeBeans or yangToAttributes, merge
ModuleMXBeanEntry moduleMXBeanEntry = result.get(moduleLocalNameFromXPath);
if (yangToAttributes != null && moduleMXBeanEntry.getAttributes() == null) {
moduleMXBeanEntry.setYangToAttributes(yangToAttributes);
} else if (runtimeBeans != null && moduleMXBeanEntry.getRuntimeBeans() == null) {
moduleMXBeanEntry.setRuntimeBeans(runtimeBeans);
}
+ checkState(Objects.equals(nullableDummyContainerName, moduleMXBeanEntry.getNullableDummyContainerName()),
+ "Mismatch in module " + moduleMXBeanEntry.toString() + " - dummy container must be present/missing in" +
+ " both state and configuration");
} else {
ModuleMXBeanEntry.ModuleMXBeanEntryInitial initial = new ModuleMXBeanEntry.ModuleMXBeanEntryInitialBuilder()
.setIdSchemaNode(moduleIdentity).setPackageName(packageName).setJavaNamePrefix(javaNamePrefix)
moduleMXBeanEntry.setYangModuleName(currentModule.getName());
moduleMXBeanEntry.setYangModuleLocalname(moduleLocalNameFromXPath);
+ moduleMXBeanEntry.setNullableDummyContainerName(nullableDummyContainerName);
result.put(moduleLocalNameFromXPath, moduleMXBeanEntry);
}
}
}
private void checkUniqueTOAttr(Map<String, QName> uniqueGeneratedClassNames, QName parentQName, TOAttribute attr) {
- final String upperCaseCammelCase = attr.getUpperCaseCammelCase();
- if (uniqueGeneratedClassNames.containsKey(upperCaseCammelCase)) {
- QName firstDefinedQName = uniqueGeneratedClassNames.get(upperCaseCammelCase);
- throw new NameConflictException(upperCaseCammelCase, firstDefinedQName, parentQName);
+ final String upperCaseCamelCase = attr.getUpperCaseCammelCase();
+ if (uniqueGeneratedClassNames.containsKey(upperCaseCamelCase)) {
+ QName firstDefinedQName = uniqueGeneratedClassNames.get(upperCaseCamelCase);
+ throw new NameConflictException(upperCaseCamelCase, firstDefinedQName, parentQName);
} else {
- uniqueGeneratedClassNames.put(upperCaseCammelCase, parentQName);
+ uniqueGeneratedClassNames.put(upperCaseCamelCase, parentQName);
}
}
- private Collection<RuntimeBeanEntry> fillRuntimeBeans(ChoiceCaseNode choiceCaseNode, Module currentModule,
+ private Collection<RuntimeBeanEntry> fillRuntimeBeans(DataNodeContainer dataNodeContainer, Module currentModule,
TypeProviderWrapper typeProviderWrapper, String packageName, String moduleLocalNameFromXPath,
String javaNamePrefix) {
- return RuntimeBeanEntry.extractClassNameToRuntimeBeanMap(packageName, choiceCaseNode, moduleLocalNameFromXPath,
+ return RuntimeBeanEntry.extractClassNameToRuntimeBeanMap(packageName, dataNodeContainer, moduleLocalNameFromXPath,
typeProviderWrapper, javaNamePrefix, currentModule).values();
}
- private Map<String, AttributeIfc> fillConfiguration(ChoiceCaseNode choiceCaseNode, Module currentModule,
+ /**
+ * Since each case statement within a module must provide unique child nodes, it is allowed to wrap
+ * the actual configuration with a container node with name equal to case name.
+ *
+ * @param choiceCaseNode state or configuration case statement
+ * @return either choiceCaseNode or its only child container
+ */
+ private <HAS_CHILDREN_AND_QNAME extends DataNodeContainer & SchemaNode> HAS_CHILDREN_AND_QNAME getDataNodeContainer(ChoiceCaseNode choiceCaseNode) {
+ Set<DataSchemaNode> childNodes = choiceCaseNode.getChildNodes();
+ if (childNodes.size() == 1) {
+ DataSchemaNode onlyChild = childNodes.iterator().next();
+ if (onlyChild instanceof ContainerSchemaNode) {
+ ContainerSchemaNode onlyContainer = (ContainerSchemaNode) onlyChild;
+ if (Objects.equals(onlyContainer.getQName().getLocalName(), choiceCaseNode.getQName().getLocalName())) {
+ // the actual configuration is inside dummy container
+ return (HAS_CHILDREN_AND_QNAME) onlyContainer;
+ }
+ }
+ }
+ return (HAS_CHILDREN_AND_QNAME) choiceCaseNode;
+ }
+
+ private Map<String, AttributeIfc> fillConfiguration(DataNodeContainer dataNodeContainer, Module currentModule,
TypeProviderWrapper typeProviderWrapper, Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
SchemaContext schemaContext, String packageName) {
Map<String, AttributeIfc> yangToAttributes = new HashMap<>();
- for (DataSchemaNode attrNode : choiceCaseNode.getChildNodes()) {
+ Set<DataSchemaNode> childNodes = dataNodeContainer.getChildNodes();
+ for (DataSchemaNode attrNode : childNodes) {
AttributeIfc attributeValue = getAttributeValue(attrNode, currentModule, qNamesToSIEs, typeProviderWrapper,
schemaContext, packageName);
yangToAttributes.put(attributeValue.getAttributeYangName(), attributeValue);
String prefix = m.group(1);
ModuleImport moduleImport = findModuleImport(currentModule, prefix);
foundModule = schemaContext.findModuleByName(moduleImport.getModuleName(), moduleImport.getRevision());
- checkState(foundModule != null, format("Module not found in SchemaContext by %s", moduleImport));
+ checkNotNull(foundModule, format("Module not found in SchemaContext by %s", moduleImport));
localSIName = m.group(2);
} else {
foundModule = currentModule; // no prefix => SIE is in currentModule
*/
package org.opendaylight.controller.config.yangjmxgenerator;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
import com.google.common.collect.Lists;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.FullyQualifiedNameHelper;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.NameConflictException;
import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
import org.opendaylight.yangtools.yang.model.api.UsesNode;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
-
/**
* Holds information about runtime bean to be generated. There are two kinds of
* RuntimeBeanEntry instances: if isRoot flag is set to true, this bean
@VisibleForTesting
RuntimeBeanEntry(String packageName,
- DataSchemaNode nodeForReporting, String yangName,
+ DataNodeContainer nodeForReporting, String yangName,
String javaNamePrefix, boolean isRoot,
Optional<String> keyYangName, List<AttributeIfc> attributes,
List<RuntimeBeanEntry> children, Set<Rpc> rpcs) {
* not contain special configuration for it.
*/
public static Map<String, RuntimeBeanEntry> extractClassNameToRuntimeBeanMap(
- String packageName, ChoiceCaseNode container,
+ String packageName, DataNodeContainer container,
String moduleYangName, TypeProviderWrapper typeProviderWrapper,
String javaNamePrefix, Module currentModule) {
}
private static RuntimeBeanEntry createRoot(String packageName,
- DataSchemaNode nodeForReporting, String attributeYangName,
+ DataNodeContainer nodeForReporting, String attributeYangName,
List<AttributeIfc> attributes, String javaNamePrefix,
List<RuntimeBeanEntry> children, Set<Rpc> rpcs) {
return new RuntimeBeanEntry(packageName, nodeForReporting,
*/
package org.opendaylight.controller.config.yangjmxgenerator;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.format;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
import org.junit.Assert;
import org.junit.Before;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.YangModelSearchUtils;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.format;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-
public abstract class AbstractYangTest {
protected SchemaContext context;
protected Map<String, Module> namesToModules; // are module names globally
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import com.google.common.base.Optional;
import java.net.URI;
import java.util.Collections;
import java.util.List;
-
import org.junit.Test;
import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry.Rpc;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
import org.opendaylight.yangtools.sal.binding.model.api.Type;
import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
-import com.google.common.base.Optional;
-
public class RuntimeRegistratorTest {
// TODO add more tests
protected RuntimeBeanEntry prepareRootRB(List<RuntimeBeanEntry> children) {
- DataSchemaNode dataSchemaNodeForReporting = mock(DataSchemaNode.class);
- doReturn("DataSchemaNode").when(dataSchemaNodeForReporting).toString();
- return new RuntimeBeanEntry("pa.cka.ge", dataSchemaNodeForReporting,
+ DataNodeContainer nodeContainer = mock(DataNodeContainer.class);
+ doReturn("DataSchemaNode").when(nodeContainer).toString();
+ return new RuntimeBeanEntry("pa.cka.ge", nodeContainer,
"module-name", "ModuleName", true, Optional.<String> absent(),
Collections.<AttributeIfc> emptyList(), children,
Collections.<Rpc> emptySet());
protected RuntimeBeanEntry prepareChildRB(List<RuntimeBeanEntry> children,
String prefix) {
- DataSchemaNode dataSchemaNodeForReporting = mock(DataSchemaNode.class);
- doReturn("DataSchemaNode").when(dataSchemaNodeForReporting).toString();
- return new RuntimeBeanEntry("pa.cka.ge", dataSchemaNodeForReporting,
+ DataNodeContainer nodeContainer = mock(DataNodeContainer.class);
+ doReturn("DataSchemaNode").when(nodeContainer).toString();
+ return new RuntimeBeanEntry("pa.cka.ge", nodeContainer,
prefix + "child-name", capitalize(prefix) + "ChildName", false,
Optional.<String> absent(),
Collections.<AttributeIfc> emptyList(), children,
augment "/config:modules/config:module/config:state" {
case bgp-listener-impl {
when "/config:modules/config:module/config:type = 'bgp-listener-impl'";
- list peers {
- config:inner-state-bean;
- leaf port {
- type inet:port-number;
- default 179;
+ container bgp-listener-impl {
+ list peers {
+ config:inner-state-bean;
+ leaf port {
+ type inet:port-number;
+ default 179;
+ }
+ leaf core-size {
+ type uint32;
+ }
}
- leaf core-size {
- type uint32;
- }
- }
- leaf as-number {
- mandatory true;
- type inet:as-number;
+ leaf as-number {
+ mandatory true;
+ type inet:as-number;
+ }
}
}
}
augment "/config:modules/config:module/config:configuration" {
case threadpool-dynamic {
when "/config:modules/config:module/config:type = 'threadpool-dynamic'";
- leaf core-size {
- type uint32;
- }
+ container threadpool-dynamic {
+ leaf core-size {
+ type uint32;
+ }
- leaf keep-alive {
- type uint32;
- units seconds;
- default 10;
- }
+ leaf keep-alive {
+ type uint32;
+ units seconds;
+ default 10;
+ }
- leaf maximum-size {
- type uint32;
- description "maximum-size description";
- }
+ leaf maximum-size {
+ type uint32;
+ description "maximum-size description";
+ }
- leaf binary {
- type binary;
- }
+ leaf binary {
+ type binary;
+ }
- container threadfactory {
- description "threadfactory description";
- uses config:service-ref {
- refine type {
- mandatory true;
- config:required-identity th2:threadfactory;
+ container threadfactory {
+ description "threadfactory description";
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity th2:threadfactory;
+ }
}
}
- }
- leaf-list users {
- type string;
- }
+ leaf-list users {
+ type string;
+ }
- leaf-list users-numbers {
- type uint32;
- description "numbers of users description";
+ leaf-list users-numbers {
+ type uint32;
+ description "numbers of users description";
+ }
}
}
}
augment "/config:modules/config:module/config:state" {
case threadpool-dynamic {
when "/config:modules/config:module/config:type = 'threadpool-dynamic'";
- // root runtime bean
- leaf created-sessions {
- type uint32;
+ container threadpool-dynamic {
+ // root runtime bean
+ leaf created-sessions {
+ type uint32;
+ }
}
}
}
augment "/config:modules/config:module/config:configuration" {
case impl-netconf {
when "/config:modules/config:module/config:type = 'impl-netconf'";
- leaf binaryLeaf {
- type binary;
- default ZGVmYXVsdEJpbg==;
- }
-
- leaf type {
- type string;
- default "default-string";
- }
+ container impl-netconf {
+ leaf binaryLeaf {
+ type binary;
+ default ZGVmYXVsdEJpbg==;
+ }
- leaf extended {
- type tt:extend-once;
- default 1;
- }
+ leaf type {
+ type string;
+ default "default-string";
+ }
- leaf extended-twice {
- type tt:extend-twice;
- default 2;
- }
+ leaf extended {
+ type tt:extend-once;
+ default 1;
+ }
- leaf extended-enum {
- type tt:extend-enum;
- default ONE;
- }
+ leaf extended-twice {
+ type tt:extend-twice;
+ default 2;
+ }
- leaf ip {
- type inet:ip-address;
- default 0:0:0:0:0:0:0:1;
- }
+ leaf extended-enum {
+ type tt:extend-enum;
+ default ONE;
+ }
- leaf union-test-attr {
- type tt:unionTest;
- default 456;
- }
+ leaf ip {
+ type inet:ip-address;
+ default 0:0:0:0:0:0:0:1;
+ }
- leaf sleep-factor {
- type decimal64 {
- fraction-digits 2;
+ leaf union-test-attr {
+ type tt:unionTest;
+ default 456;
}
- default 2.00;
- }
- container dto-c {
- leaf simple-arg {
- type uint32;
+ leaf sleep-factor {
+ type decimal64 {
+ fraction-digits 2;
+ }
+ default 2.00;
}
- container dto-a-inner {
+ container dto-c {
leaf simple-arg {
type uint32;
}
- container dto-a-inner-inner {
+ container dto-a-inner {
leaf simple-arg {
type uint32;
}
+
+ container dto-a-inner-inner {
+ leaf simple-arg {
+ type uint32;
+ }
+ }
}
}
- }
-
- leaf simpleInt {
- type uint32;
- }
-
- leaf simpleBoolean {
- type boolean;
- default false;
- }
-
- leaf simple-long {
- type int64;
- default -45;
- }
-
- leaf simple-long-2 {
- type uint32;
- default 445;
- }
- leaf simple-BigInteger {
- type uint64;
- default 545454;
- }
+ leaf simpleInt {
+ type uint32;
+ }
- leaf simple-byte {
- type int8;
- default -4;
- }
+ leaf simpleBoolean {
+ type boolean;
+ default false;
+ }
- leaf simple-short {
- type uint8;
- default 45;
- }
+ leaf simple-long {
+ type int64;
+ default -45;
+ }
- leaf simple-test {
- type uint16;
- default 99;
- }
+ leaf simple-long-2 {
+ type uint32;
+ default 445;
+ }
- leaf-list simple-list {
- type uint16;
- }
+ leaf simple-BigInteger {
+ type uint64;
+ default 545454;
+ }
- container dto_d {
- leaf simple-int1 {
- type uint32;
+ leaf simple-byte {
+ type int8;
+ default -4;
}
- leaf simple-int2 {
- type uint32;
+ leaf simple-short {
+ type uint8;
+ default 45;
}
- leaf simple-int3 {
+ leaf simple-test {
type uint16;
+ default 99;
}
leaf-list simple-list {
type uint16;
}
- list complex-dto-bInner {
- leaf-list simple-list {
- type uint16;
+ container dto_d {
+ leaf simple-int1 {
+ type uint32;
}
+
+ leaf simple-int2 {
+ type uint32;
+ }
+
leaf simple-int3 {
type uint16;
}
- container deep {
+ leaf-list simple-list {
+ type uint16;
+ }
+
+ list complex-dto-bInner {
+ leaf-list simple-list {
+ type uint16;
+ }
leaf simple-int3 {
type uint16;
- default 0;
+ }
+
+ container deep {
+ leaf simple-int3 {
+ type uint16;
+ default 0;
+ }
}
}
}
- }
- list complex-list {
- list simple-list {
- leaf simple-int3 {
- type uint16;
+ list complex-list {
+ list simple-list {
+ leaf simple-int3 {
+ type uint16;
+ }
}
}
- }
- list peers {
- leaf port {
- type string;
- }
- leaf core-size {
- type uint32;
- }
- leaf simple-int3 {
- type uint16;
- }
- }
+ list peers {
+ leaf port {
+ type string;
+ }
+ leaf core-size {
+ type uint32;
+ }
+ leaf simple-int3 {
+ type uint16;
+ }
+ }
- container testing-dep {
- uses config:service-ref {
- refine type {
- mandatory true;
- config:required-identity test:testing;
+ container testing-dep {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity test:testing;
+ }
}
}
- }
- list testing-deps {
- uses config:service-ref {
- refine type {
- mandatory true;
- config:required-identity test:testing;
+ list testing-deps {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity test:testing;
+ }
}
}
}
augment "/config:modules/config:module/config:state" {
case impl-netconf {
when "/config:modules/config:module/config:type = 'impl-netconf'";
- // rpc
- rpcx:rpc-context-instance "test-rpc";
-
- // root runtime bean
- leaf created-sessions {
- type uint32;
- }
-
- container asdf {
- leaf simpleInt {
- type uint16;
- }
+ container impl-netconf {
+ // rpc
+ rpcx:rpc-context-instance "test-rpc";
- leaf simpleString {
- type string;
+ // root runtime bean
+ leaf created-sessions {
+ type uint32;
}
- }
+ container asdf {
+ leaf simpleInt {
+ type uint16;
+ }
- list inner-running-data-additional {
- config:inner-state-bean;
+ leaf simpleString {
+ type string;
+ }
+ }
- // rpc
- rpcx:rpc-context-instance "inner-test-rpc";
- key "simpleString";
+ list inner-running-data-additional {
+ config:inner-state-bean;
- leaf simple-int3 {
- type uint16;
- }
+ // rpc
+ rpcx:rpc-context-instance "inner-test-rpc";
- leaf simpleString {
- type string;
- }
+ key "simpleString";
- container deep4 {
- leaf boool {
- type boolean;
+ leaf simple-int3 {
+ type uint16;
}
- }
- }
-
- list inner-running-data {
- config:inner-state-bean;
- key "simple-int3";
-
- leaf simple-int3 {
- type uint16;
+ leaf simpleString {
+ type string;
}
- container deep2 {
- leaf boool {
- type boolean;
+ container deep4 {
+ leaf boool {
+ type boolean;
+ }
}
- }
+ }
- list inner-inner-running-data {
+ list inner-running-data {
config:inner-state-bean;
- rpcx:rpc-context-instance "inner-inner-test-rpc";
- rpcx:rpc-context-instance "complex-output-rpc";
-
key "simple-int3";
leaf simple-int3 {
- type uint16;
- }
+ type uint16;
+ }
- leaf-list list-of-strings {
- type string;
- }
+ container deep2 {
+ leaf boool {
+ type boolean;
+ }
+ }
- list not-state-bean {
- leaf element {
- type string;
+ list inner-inner-running-data {
+ config:inner-state-bean;
+
+ rpcx:rpc-context-instance "inner-inner-test-rpc";
+ rpcx:rpc-context-instance "complex-output-rpc";
+
+ key "simple-int3";
+
+ leaf simple-int3 {
+ type uint16;
}
- list not-state-bean-internal {
- // This should be ignored
- config:inner-state-bean;
+ leaf-list list-of-strings {
+ type string;
+ }
- leaf element2 {
+ list not-state-bean {
+ leaf element {
type string;
}
+
+ list not-state-bean-internal {
+ // This should be ignored
+ config:inner-state-bean;
+
+ leaf element2 {
+ type string;
+ }
+ }
}
- }
- container deep3 {
- leaf boool {
- type boolean;
+ container deep3 {
+ leaf boool {
+ type boolean;
+ }
}
}
}
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>restconf-client-impl</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>util</artifactId>
+ </dependency>
<!-- yangtools dependencies I'm pretty sure we can trim -->
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
reference\:file\:../lib/jersey-server-1.17.jar@2:start
# Netconf startup configuration
-netconf.tcp.address=127.0.0.1
-netconf.tcp.port=8383
-netconf.tcp.client.address=127.0.0.1
-netconf.tcp.client.port=8383
+# Netconf tcp address:port is optional with default value 127.0.0.1:8383
+#netconf.tcp.address=127.0.0.1
+#netconf.tcp.port=8384
+
+#netconf.tcp.client.address=127.0.0.1
+#netconf.tcp.client.port=8384
netconf.ssh.address=0.0.0.0
netconf.ssh.port=1830
--- /dev/null
+/**
+ * Copyright (c) 2014 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.compatibility;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.felix.dm.Component;
+import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.compatibility.adsal.DataPacketServiceAdapter;
+import org.opendaylight.controller.sal.compatibility.topology.TopologyAdapter;
+import org.opendaylight.controller.sal.compatibility.topology.TopologyProvider;
+import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
+import org.opendaylight.controller.sal.core.Node.NodeIDType;
+import org.opendaylight.controller.sal.core.NodeConnector.NodeConnectorIDType;
+import org.opendaylight.controller.sal.discovery.IDiscoveryService;
+import org.opendaylight.controller.sal.flowprogrammer.IPluginInFlowProgrammerService;
+import org.opendaylight.controller.sal.flowprogrammer.IPluginOutFlowProgrammerService;
+import org.opendaylight.controller.sal.inventory.IPluginInInventoryService;
+import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService;
+import org.opendaylight.controller.sal.packet.IPluginInDataPacketService;
+import org.opendaylight.controller.sal.packet.IPluginOutDataPacketService;
+import org.opendaylight.controller.sal.reader.IPluginInReadService;
+import org.opendaylight.controller.sal.reader.IPluginOutReadService;
+import org.opendaylight.controller.sal.topology.IPluginInTopologyService;
+import org.opendaylight.controller.sal.topology.IPluginOutTopologyService;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
+import org.opendaylight.controller.sal.utils.INodeConnectorFactory;
+import org.opendaylight.controller.sal.utils.INodeFactory;
+import org.osgi.framework.BundleContext;
+
+import com.google.common.base.Preconditions;
+
+public class ComponentActivator extends ComponentActivatorAbstractBase {
+ private final INodeConnectorFactory nodeConnectorFactory = new MDSalNodeConnectorFactory();
+ private final DataPacketServiceAdapter dataPacketService = new DataPacketServiceAdapter();
+ private final InventoryAndReadAdapter inventory = new InventoryAndReadAdapter();
+ private final FlowProgrammerAdapter flow = new FlowProgrammerAdapter();
+ private final DataPacketAdapter dataPacket = new DataPacketAdapter();
+ private final TopologyProvider tpProvider = new TopologyProvider();
+ private final INodeFactory nodeFactory = new MDSalNodeFactory();
+ private final TopologyAdapter topology = new TopologyAdapter();
+ private BundleContext context;
+
+ public INodeConnectorFactory getNodeConnectorFactory() {
+ return nodeConnectorFactory;
+ }
+
+ public DataPacketServiceAdapter getDataPacketService() {
+ return dataPacketService;
+ }
+
+ public InventoryAndReadAdapter getInventory() {
+ return inventory;
+ }
+
+ public FlowProgrammerAdapter getFlow() {
+ return flow;
+ }
+
+ public DataPacketAdapter getDataPacket() {
+ return dataPacket;
+ }
+
+ public TopologyProvider getTpProvider() {
+ return tpProvider;
+ }
+
+ public INodeFactory getNodeFactory() {
+ return nodeFactory;
+ }
+
+ public TopologyAdapter getTopology() {
+ return topology;
+ }
+
+ @Override
+ protected void init() {
+ NodeIDType.registerIDType(NodeMapping.MD_SAL_TYPE, String.class);
+ NodeConnectorIDType.registerIDType(NodeMapping.MD_SAL_TYPE, String.class, NodeMapping.MD_SAL_TYPE);
+ }
+
+ @Override
+ public void start(final BundleContext context) {
+ super.start(context);
+ this.context = Preconditions.checkNotNull(context);
+ }
+
+ public ProviderContext setBroker(final BindingAwareBroker broker) {
+ return broker.registerProvider(new SalCompatibilityProvider(this), context);
+ }
+
+ @Override
+ protected Object[] getGlobalImplementations() {
+ return new Object[] {
+ flow,
+ inventory,
+ dataPacket,
+ nodeFactory,
+ nodeConnectorFactory,
+ topology,
+ tpProvider,
+ this // Used for setBroker callback
+ };
+ }
+
+ @Override
+ protected void configureGlobalInstance(final Component c, final Object imp) {
+ if (imp instanceof DataPacketAdapter) {
+ _configure((DataPacketAdapter)imp, c);
+ } else if (imp instanceof FlowProgrammerAdapter) {
+ _configure((FlowProgrammerAdapter)imp, c);
+ } else if (imp instanceof InventoryAndReadAdapter) {
+ _configure((InventoryAndReadAdapter)imp, c);
+ } else if (imp instanceof ComponentActivator) {
+ _configure((ComponentActivator)imp, c);
+ } else if (imp instanceof MDSalNodeConnectorFactory) {
+ _configure((MDSalNodeConnectorFactory)imp, c);
+ } else if (imp instanceof MDSalNodeFactory) {
+ _configure((MDSalNodeFactory)imp, c);
+ } else if (imp instanceof TopologyAdapter) {
+ _configure((TopologyAdapter)imp, c);
+ } else if (imp instanceof TopologyProvider) {
+ _configure((TopologyProvider)imp, c);
+ } else {
+ throw new IllegalArgumentException(String.format("Unhandled implementation class %s", imp.getClass()));
+ }
+ }
+
+ @Override
+ protected Object[] getImplementations() {
+ return new Object[] {
+ dataPacketService,
+ };
+ }
+
+ @Override
+ protected void configureInstance(final Component c, final Object imp, final String containerName) {
+ if (imp instanceof ComponentActivator) {
+ _instanceConfigure((ComponentActivator)imp, c, containerName);
+ } else if (imp instanceof DataPacketServiceAdapter) {
+ _instanceConfigure((DataPacketServiceAdapter)imp, c, containerName);
+ } else {
+ throw new IllegalArgumentException(String.format("Unhandled implementation class %s", imp.getClass()));
+ }
+ }
+
+ private void _configure(final MDSalNodeFactory imp, final Component it) {
+ it.setInterface(INodeFactory.class.getName(), properties());
+ }
+
+ private void _configure(final MDSalNodeConnectorFactory imp, final Component it) {
+ it.setInterface(INodeConnectorFactory.class.getName(), properties());
+ }
+
+ private void _configure(final ComponentActivator imp, final Component it) {
+ it.add(createServiceDependency()
+ .setService(BindingAwareBroker.class)
+ .setCallbacks("setBroker", "setBroker")
+ .setRequired(true));
+ }
+
+ private void _configure(final DataPacketAdapter imp, final Component it) {
+ it.add(createServiceDependency()
+ .setService(IPluginOutDataPacketService.class)
+ .setCallbacks("setDataPacketPublisher", "setDataPacketPublisher")
+ .setRequired(false));
+ }
+
+ private void _configure(final FlowProgrammerAdapter imp, final Component it) {
+ it.setInterface(IPluginInFlowProgrammerService.class.getName(), properties());
+ it.add(createServiceDependency()
+ .setService(IPluginOutFlowProgrammerService.class)
+ .setCallbacks("setFlowProgrammerPublisher", "setFlowProgrammerPublisher")
+ .setRequired(false));
+ it.add(createServiceDependency()
+ .setService(IClusterGlobalServices.class)
+ .setCallbacks("setClusterGlobalServices", "unsetClusterGlobalServices")
+ .setRequired(false));
+ }
+
+ private void _instanceConfigure(final DataPacketServiceAdapter imp, final Component it, final String containerName) {
+ it.setInterface(IPluginInDataPacketService.class.getName(), properties());
+ }
+
+ private void _instanceConfigure(final ComponentActivator imp, final Component it, final String containerName) {
+ // No-op
+ }
+
+ private void _configure(final InventoryAndReadAdapter imp, final Component it) {
+ it.setInterface(new String[] {
+ IPluginInInventoryService.class.getName(),
+ IPluginInReadService.class.getName(),
+ }, properties());
+
+ it.add(createServiceDependency()
+ .setService(IPluginOutReadService.class)
+ .setCallbacks("setReadPublisher", "unsetReadPublisher")
+ .setRequired(false));
+ it.add(createServiceDependency()
+ .setService(IPluginOutInventoryService.class)
+ .setCallbacks("setInventoryPublisher", "unsetInventoryPublisher")
+ .setRequired(false));
+ it.add(createServiceDependency()
+ .setService(IDiscoveryService.class)
+ .setCallbacks("setDiscoveryPublisher", "setDiscoveryPublisher")
+ .setRequired(false));
+ }
+
+ private void _configure(final TopologyAdapter imp, final Component it) {
+ it.setInterface(IPluginInTopologyService.class.getName(), properties());
+
+ it.add(createServiceDependency()
+ .setService(IPluginOutTopologyService.class)
+ .setCallbacks("setTopologyPublisher", "setTopologyPublisher")
+ .setRequired(false));
+ }
+
+ private void _configure(final TopologyProvider imp, final Component it) {
+ it.add(createServiceDependency()
+ .setService(IPluginOutTopologyService.class)
+ .setCallbacks("setTopologyPublisher", "setTopologyPublisher")
+ .setRequired(false));
+ }
+
+ private Dictionary<String,Object> properties() {
+ final Hashtable<String,Object> props = new Hashtable<String, Object>();
+ props.put(GlobalConstants.PROTOCOLPLUGINTYPE.toString(), NodeMapping.MD_SAL_TYPE);
+ props.put("protocolName", NodeMapping.MD_SAL_TYPE);
+ return props;
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 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.compatibility
-
-import java.util.Arrays
-import java.util.Dictionary
-import java.util.Hashtable
-import org.apache.felix.dm.Component
-import org.opendaylight.controller.clustering.services.IClusterGlobalServices
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext
-import org.opendaylight.controller.sal.binding.api.BindingAwareProvider
-import org.opendaylight.controller.sal.binding.api.NotificationService
-import org.opendaylight.controller.sal.binding.api.data.DataBrokerService
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.controller.sal.compatibility.adsal.DataPacketServiceAdapter
-import org.opendaylight.controller.sal.compatibility.topology.TopologyAdapter
-import org.opendaylight.controller.sal.compatibility.topology.TopologyProvider
-import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase
-import org.opendaylight.controller.sal.core.Node
-import org.opendaylight.controller.sal.core.NodeConnector
-import org.opendaylight.controller.sal.discovery.IDiscoveryService
-import org.opendaylight.controller.sal.flowprogrammer.IPluginInFlowProgrammerService
-import org.opendaylight.controller.sal.flowprogrammer.IPluginOutFlowProgrammerService
-import org.opendaylight.controller.sal.inventory.IPluginInInventoryService
-import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService
-import org.opendaylight.controller.sal.packet.IPluginInDataPacketService
-import org.opendaylight.controller.sal.packet.IPluginOutDataPacketService
-import org.opendaylight.controller.sal.reader.IPluginInReadService
-import org.opendaylight.controller.sal.reader.IPluginOutReadService
-import org.opendaylight.controller.sal.topology.IPluginInTopologyService
-import org.opendaylight.controller.sal.topology.IPluginOutTopologyService
-import org.opendaylight.controller.sal.utils.GlobalConstants
-import org.opendaylight.controller.sal.utils.INodeConnectorFactory
-import org.opendaylight.controller.sal.utils.INodeFactory
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.FlowTopologyDiscoveryService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService
-import org.osgi.framework.BundleContext
-
-import static org.opendaylight.controller.sal.compatibility.NodeMapping.*
-
-class ComponentActivator extends ComponentActivatorAbstractBase {
-
- private BundleContext context;
-
- @Property
- FlowProgrammerAdapter flow = new FlowProgrammerAdapter;
-
- @Property
- InventoryAndReadAdapter inventory = new InventoryAndReadAdapter;
-
- @Property
- DataPacketAdapter dataPacket = new DataPacketAdapter;
-
- @Property
- INodeFactory nodeFactory = new MDSalNodeFactory
-
- @Property
- INodeConnectorFactory nodeConnectorFactory = new MDSalNodeConnectorFactory
-
- @Property
- TopologyAdapter topology = new TopologyAdapter
-
- @Property
- TopologyProvider tpProvider = new TopologyProvider()
-
- @Property
- DataPacketServiceAdapter dataPacketService = new DataPacketServiceAdapter()
-
-
-
- override protected init() {
- Node.NodeIDType.registerIDType(MD_SAL_TYPE, String);
- NodeConnector.NodeConnectorIDType.registerIDType(MD_SAL_TYPE, String, MD_SAL_TYPE);
- }
-
- override start(BundleContext context) {
- super.start(context)
- this.context = context;
- }
-
- def setBroker(BindingAwareBroker broker) {
- broker.registerProvider(new SalCompatibilityProvider(this), context)
- }
-
-
- override protected getGlobalImplementations() {
- return Arrays.asList(this, flow, inventory, dataPacket, nodeFactory, nodeConnectorFactory,topology,tpProvider)
- }
-
- override protected configureGlobalInstance(Component c, Object imp) {
- configure(imp, c);
- }
-
- override protected getImplementations() {
- return Arrays.asList(dataPacketService)
- }
-
- override protected configureInstance(Component c, Object imp, String containerName) {
- instanceConfigure(imp, c, containerName);
- }
-
- private def dispatch configure(MDSalNodeFactory imp, Component it) {
- setInterface(INodeFactory.name, properties);
- }
-
- private def dispatch configure(MDSalNodeConnectorFactory imp, Component it) {
- setInterface(INodeConnectorFactory.name, properties);
- }
-
- private def dispatch configure(ComponentActivator imp, Component it) {
- add(
- createServiceDependency().setService(BindingAwareBroker) //
- .setCallbacks("setBroker", "setBroker") //
- .setRequired(true))
-
-
- }
-
- private def dispatch configure(DataPacketAdapter imp, Component it) {
- add(
- createServiceDependency() //
- .setService(IPluginOutDataPacketService) //
- .setCallbacks("setDataPacketPublisher", "setDataPacketPublisher") //
- .setRequired(false))
- }
-
- private def dispatch configure(FlowProgrammerAdapter imp, Component it) {
- setInterface(IPluginInFlowProgrammerService.name, properties)
- add(
- createServiceDependency() //
- .setService(IPluginOutFlowProgrammerService) //
- .setCallbacks("setFlowProgrammerPublisher", "setFlowProgrammerPublisher") //
- .setRequired(false))
-
- add(
- createServiceDependency() //
- .setService(IClusterGlobalServices) //
- .setCallbacks("setClusterGlobalServices", "unsetClusterGlobalServices") //
- .setRequired(false))
-
- }
-
- private def dispatch instanceConfigure(DataPacketServiceAdapter imp, Component it, String containerName) {
- setInterface(IPluginInDataPacketService.name, properties)
- }
-
- private def dispatch instanceConfigure(ComponentActivator imp, Component it, String containerName) {
- }
-
-
- private def dispatch configure(InventoryAndReadAdapter imp, Component it) {
- setInterface(Arrays.asList(IPluginInInventoryService.name, IPluginInReadService.name), properties)
- add(
- createServiceDependency() //
- .setService(IPluginOutReadService) //
- .setCallbacks("setReadPublisher", "unsetReadPublisher") //
- .setRequired(false))
- add(
- createServiceDependency() //
- .setService(IPluginOutInventoryService) //
- .setCallbacks("setInventoryPublisher", "unsetInventoryPublisher") //
- .setRequired(false))
- add(
- createServiceDependency() //
- .setService(IDiscoveryService) //
- .setCallbacks("setDiscoveryPublisher", "setDiscoveryPublisher") //
- .setRequired(false))
-
-
- }
-
- private def dispatch configure (TopologyAdapter imp, Component it) {
- setInterface(Arrays.asList(IPluginInTopologyService.name), properties)
- add(
- createServiceDependency() //
- .setService(IPluginOutTopologyService) //
- .setCallbacks("setTopologyPublisher", "setTopologyPublisher") //
- .setRequired(false))
- }
-
- private def dispatch configure (TopologyProvider imp, Component it) {
- add(
- createServiceDependency() //
- .setService(IPluginOutTopologyService) //
- .setCallbacks("setTopologyPublisher", "setTopologyPublisher") //
- .setRequired(false))
- }
-
- private def Dictionary<String, Object> properties() {
- val props = new Hashtable<String, Object>();
- props.put(GlobalConstants.PROTOCOLPLUGINTYPE.toString, MD_SAL_TYPE)
- props.put("protocolName", MD_SAL_TYPE);
- return props;
- }
-}
-package class SalCompatibilityProvider implements BindingAwareProvider {
-
- private val ComponentActivator activator;
-
- new(ComponentActivator cmpAct) {
- activator = cmpAct;
- }
-
- override getFunctionality() {
- // Noop
- }
-
- override getImplementations() {
- // Noop
- }
-
-
- override onSessionInitialized(ConsumerContext session) {
- // Noop
- }
-
-
- override onSessionInitiated(ProviderContext session) {
- val it = activator
- val subscribe = session.getSALService(NotificationService)
-
- // Registration of Flow Service
- flow.delegate = session.getRpcService(SalFlowService)
- flow.dataBrokerService = session.getSALService(DataBrokerService);
- subscribe.registerNotificationListener(flow);
-
- // Data Packet Service
- subscribe.registerNotificationListener(inventory);
- dataPacketService.delegate = session.getRpcService(PacketProcessingService)
-
- // Inventory Service
- inventory.dataService = session.getSALService(DataBrokerService);
- inventory.flowStatisticsService = session.getRpcService(OpendaylightFlowStatisticsService);
- inventory.flowTableStatisticsService = session.getRpcService(OpendaylightFlowTableStatisticsService);
- inventory.nodeConnectorStatisticsService = session.getRpcService(OpendaylightPortStatisticsService);
- inventory.topologyDiscovery = session.getRpcService(FlowTopologyDiscoveryService);
- inventory.dataProviderService = session.getSALService(DataProviderService)
- topology.dataService = session.getSALService(DataProviderService)
- tpProvider.dataService = session.getSALService(DataProviderService)
-
- inventory.startAdapter();
-
- tpProvider.startAdapter();
-
- subscribe.registerNotificationListener(dataPacket)
- }
-}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.compatibility;
+
+import org.opendaylight.controller.sal.core.ConstructionException;
+import org.opendaylight.controller.sal.packet.IPluginOutDataPacketService;
+import org.opendaylight.controller.sal.packet.RawPacket;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+class DataPacketAdapter implements PacketProcessingListener {
+ private static final Logger LOG = LoggerFactory.getLogger(DataPacketAdapter.class);
+
+ // These are injected via Apache DM (see ComponentActivator)
+ private IPluginOutDataPacketService dataPacketPublisher;
+
+ @Override
+ public void onPacketReceived(final PacketReceived packet) {
+ try {
+ RawPacket inPacket = toRawPacket(packet);
+ if (dataPacketPublisher != null) {
+ dataPacketPublisher.receiveDataPacket(inPacket);
+ } else {
+ LOG.warn("IPluginOutDataPacketService is not available. Not forwarding packet to AD-SAL.");
+ }
+ } catch (ConstructionException e) {
+ LOG.warn("Failed to construct raw packet from {}, dropping it", packet, e);
+ }
+ }
+
+ public static RawPacket toRawPacket(final PacketReceived received) throws ConstructionException {
+ final RawPacket ret = new RawPacket(received.getPayload());
+ ret.setIncomingNodeConnector(NodeMapping.toADNodeConnector(received.getIngress()));
+ return ret;
+ }
+
+ public IPluginOutDataPacketService getDataPacketPublisher() {
+ return dataPacketPublisher;
+ }
+
+ // These are injected via Apache DM (see ComponentActivator)
+ public void setDataPacketPublisher(final IPluginOutDataPacketService dataPacketPublisher) {
+ this.dataPacketPublisher = dataPacketPublisher;
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 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.compatibility
-
-import org.opendaylight.controller.sal.packet.IPluginOutDataPacketService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener
-import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived
-import org.opendaylight.controller.sal.packet.RawPacket
-
-class DataPacketAdapter implements PacketProcessingListener {
-
- @Property
- IPluginOutDataPacketService dataPacketPublisher;
-
- override onPacketReceived(PacketReceived packet) {
- val RawPacket inPacket = packet.toRawPacket();
- dataPacketPublisher.receiveDataPacket(inPacket);
- }
-
- public static def RawPacket toRawPacket(PacketReceived received) {
- val ret = new RawPacket(received.payload);
- ret.setIncomingNodeConnector(NodeMapping.toADNodeConnector(received.ingress))
- return ret;
- }
-
-}
--- /dev/null
+/**
+ * Copyright (c) 2014 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.compatibility;
+
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+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.IClusterGlobalServices;
+import org.opendaylight.controller.clustering.services.IClusterServices.cacheMode;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.core.ConstructionException;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.flowprogrammer.Flow;
+import org.opendaylight.controller.sal.flowprogrammer.IPluginInFlowProgrammerService;
+import org.opendaylight.controller.sal.flowprogrammer.IPluginOutFlowProgrammerService;
+import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.controller.sal.utils.StatusCode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
+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.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.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.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.NodeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FlowProgrammerAdapter implements IPluginInFlowProgrammerService, SalFlowListener {
+ private final static Logger LOG = LoggerFactory.getLogger(FlowProgrammerAdapter.class);
+
+ // Note: clustering services manipulate this
+ private final Map<Flow, UUID> flowToFlowId = new ConcurrentHashMap<Flow, UUID>();
+ private final static String CACHE_NAME = "flowprogrammeradapter.flowtoid";
+
+ // These are injected via Apache DM (see ComponentActivator)
+ private IPluginOutFlowProgrammerService flowProgrammerPublisher;
+ private IClusterGlobalServices clusterGlobalServices;
+ private DataBrokerService dataBrokerService;
+ private SalFlowService delegate;
+
+ public SalFlowService getDelegate() {
+ return this.delegate;
+ }
+
+ public void setDelegate(final SalFlowService delegate) {
+ this.delegate = delegate;
+ }
+
+ public DataBrokerService getDataBrokerService() {
+ return this.dataBrokerService;
+ }
+
+ public void setDataBrokerService(final DataBrokerService dataBrokerService) {
+ this.dataBrokerService = dataBrokerService;
+ }
+
+ public IPluginOutFlowProgrammerService getFlowProgrammerPublisher() {
+ return this.flowProgrammerPublisher;
+ }
+
+ public void setFlowProgrammerPublisher(final IPluginOutFlowProgrammerService flowProgrammerPublisher) {
+ this.flowProgrammerPublisher = flowProgrammerPublisher;
+ }
+
+ public IClusterGlobalServices getClusterGlobalServices() {
+ return this.clusterGlobalServices;
+ }
+
+ public void setClusterGlobalServices(final IClusterGlobalServices clusterGlobalServices) {
+ this.clusterGlobalServices = clusterGlobalServices;
+ }
+
+ @Override
+ public Status addFlow(final Node node, final Flow flow) {
+ return toFutureStatus(internalAddFlowAsync(node, flow, 0));
+ }
+
+ @Override
+ public Status modifyFlow(final Node node, final Flow oldFlow, final Flow newFlow) {
+ return toFutureStatus(internalModifyFlowAsync(node, oldFlow, newFlow, 0));
+ }
+
+ @Override
+ public Status removeFlow(final Node node, final Flow flow) {
+ return toFutureStatus(internalRemoveFlowAsync(node, flow, 0));
+ }
+
+ @Override
+ public Status addFlowAsync(final Node node, final Flow flow, final long rid) {
+ // FIXME is this correct? What if the future fails?
+ this.internalAddFlowAsync(node, flow, rid);
+ return FlowProgrammerAdapter.toStatus(true);
+ }
+
+ @Override
+ public Status modifyFlowAsync(final Node node, final Flow oldFlow, final Flow newFlow, final long rid) {
+ // FIXME is this correct? What if the future fails?
+ this.internalModifyFlowAsync(node, oldFlow, newFlow, rid);
+ return FlowProgrammerAdapter.toStatus(true);
+ }
+
+ @Override
+ public Status removeFlowAsync(final Node node, final Flow flow, final long rid) {
+ // FIXME is this correct? What if the future fails?
+ this.internalRemoveFlowAsync(node, flow, rid);
+ return FlowProgrammerAdapter.toStatus(true);
+ }
+
+ @Override
+ public Status removeAllFlows(final Node node) {
+ // FIXME: unfinished?
+ return new Status(StatusCode.SUCCESS);
+ }
+
+ @Override
+ public Status syncSendBarrierMessage(final Node node) {
+ // FIXME: unfinished?
+ return null;
+ }
+
+ @Override
+ public Status asyncSendBarrierMessage(final Node node) {
+ // FIXME: unfinished?
+ return null;
+ }
+
+ private static Status toStatus(final boolean successful) {
+ return new Status(successful ? StatusCode.SUCCESS : StatusCode.INTERNALERROR);
+ }
+
+ public static Status toStatus(final RpcResult<? extends Object> result) {
+ return toStatus(result.isSuccessful());
+ }
+
+ @Override
+ public void onFlowAdded(final FlowAdded notification) {
+ // FIXME: unfinished?
+ }
+
+ @Override
+ public void onFlowRemoved(final FlowRemoved notification) {
+ if (notification == null) {
+ return;
+ }
+
+ final NodeRef node = notification.getNode();
+ if (node == null) {
+ LOG.debug("Notification {} has not node, ignoring it", notification);
+ return;
+ }
+
+ Node adNode;
+ try {
+ adNode = NodeMapping.toADNode(notification.getNode());
+ } catch (ConstructionException e) {
+ LOG.warn("Failed to construct AD node for {}, ignoring notification", node, e);
+ return;
+ }
+ flowProgrammerPublisher.flowRemoved(adNode, ToSalConversionsUtils.toFlow(notification, adNode));
+ }
+
+ @Override
+ public void onFlowUpdated(final FlowUpdated notification) {
+ // FIXME: unfinished?
+ }
+
+ @Override
+ public void onSwitchFlowRemoved(final SwitchFlowRemoved notification) {
+ // FIXME: unfinished?
+ }
+
+ @Override
+ public void onNodeErrorNotification(final NodeErrorNotification notification) {
+ // FIXME: unfinished?
+ }
+
+ @Override
+ public void onNodeExperimenterErrorNotification(final NodeExperimenterErrorNotification notification) {
+ // FIXME: unfinished?
+ }
+
+ private static final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow> flowPath(
+ final org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow flow, final NodeKey nodeKey) {
+ return InstanceIdentifier.builder(Nodes.class)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, nodeKey)
+ .augmentation(FlowCapableNode.class)
+ .child(Table.class, new TableKey(flow.getTableId()))
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow.class, new FlowKey(flow.getId()))
+ .toInstance();
+ }
+
+ private Future<RpcResult<TransactionStatus>> writeFlowAsync(final org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow flow, final NodeKey nodeKey) {
+ final DataModificationTransaction modification = this.dataBrokerService.beginTransaction();
+ modification.putConfigurationData(flowPath(flow, nodeKey), flow);
+ return modification.commit();
+ }
+
+ private Future<RpcResult<TransactionStatus>> internalAddFlowAsync(final Node node, final Flow flow, final long rid) {
+ final Map<Flow,UUID> cache = this.getCache();
+ UUID flowId = cache.get(flow);
+ if (flowId != null) {
+ this.removeFlow(node, flow);
+ }
+
+ flowId = UUID.randomUUID();
+ cache.put(flow, flowId);
+ return this.writeFlowAsync(MDFlowMapping.toMDFlow(flow, flowId.toString()), new NodeKey(new NodeId(node.getNodeIDString())));
+ }
+
+ private Future<RpcResult<TransactionStatus>> internalModifyFlowAsync(final Node node, final Flow oldFlow, final Flow newFlow, final long rid) {
+ final Map<Flow,UUID> cache = this.getCache();
+
+ UUID flowId = cache.remove(oldFlow);
+ if (flowId == null) {
+ flowId = UUID.randomUUID();
+ cache.put(oldFlow, flowId);
+ LOG.warn("Could not find flow {} in cache, assigned new ID {}", oldFlow.hashCode(), flowId);
+ }
+
+ cache.put(newFlow, flowId);
+ return this.writeFlowAsync(MDFlowMapping.toMDFlow(newFlow, flowId.toString()), new NodeKey(new NodeId(node.getNodeIDString())));
+ }
+
+ private Future<RpcResult<TransactionStatus>> internalRemoveFlowAsync(final Node node, final Flow adflow, final long rid) {
+ final Map<Flow,UUID> cache = this.getCache();
+
+ final UUID flowId = cache.remove(adflow);
+ if (flowId == null) {
+ LOG.warn("Could not find flow {} in cache, nothing to do", adflow.hashCode());
+ return null;
+ }
+
+ final org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow flow = MDFlowMapping.toMDFlow(adflow, flowId.toString());
+ final DataModificationTransaction modification = this.dataBrokerService.beginTransaction();
+ modification.removeConfigurationData(flowPath(flow, new NodeKey(new NodeId(node.getNodeIDString()))));
+ return modification.commit();
+ }
+
+ private static Status toFutureStatus(final Future<RpcResult<TransactionStatus>> future) {
+ if (future == null) {
+ // FIXME: really?
+ return FlowProgrammerAdapter.toStatus(true);
+ }
+
+ try {
+ final RpcResult<TransactionStatus> result = future.get();
+ return FlowProgrammerAdapter.toStatus(result);
+ } catch (final InterruptedException e) {
+ FlowProgrammerAdapter.LOG.error("Interrupted while processing flow", e);
+ } catch (ExecutionException e) {
+ FlowProgrammerAdapter.LOG.error("Failed to process flow", e);
+ }
+
+ return new Status(StatusCode.INTERNALERROR);
+ }
+
+ @SuppressWarnings("unchecked")
+ private Map<Flow,UUID> getCache() {
+ final IClusterGlobalServices cgs = getClusterGlobalServices();
+ if (cgs == null) {
+ return new ConcurrentHashMap<Flow, UUID>();
+ }
+
+ Map<Flow, UUID> cache = (Map<Flow, UUID>) cgs.getCache(FlowProgrammerAdapter.CACHE_NAME);
+ if (cache != null) {
+ return cache;
+ }
+
+ try {
+ return (Map<Flow, UUID>) cgs.createCache(CACHE_NAME, EnumSet.of(cacheMode.TRANSACTIONAL));
+ } catch (CacheExistException e) {
+ return (Map<Flow, UUID>) cgs.getCache(CACHE_NAME);
+ } catch (CacheConfigException e) {
+ throw new IllegalStateException("Unexpected cache configuration problem", e);
+ }
+ }
+
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 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.compatibility
-
-import java.util.Map
-import java.util.UUID
-import java.util.concurrent.ExecutionException
-import java.util.concurrent.ConcurrentHashMap
-import java.util.concurrent.Future
-import java.util.EnumSet
-import org.opendaylight.controller.sal.core.Node
-import org.opendaylight.controller.sal.flowprogrammer.Flow
-import org.opendaylight.controller.sal.flowprogrammer.IPluginInFlowProgrammerService
-import org.opendaylight.controller.sal.flowprogrammer.IPluginOutFlowProgrammerService
-import org.opendaylight.controller.sal.utils.Status
-import org.opendaylight.controller.sal.utils.StatusCode
-import org.opendaylight.controller.clustering.services.CacheExistException
-import org.opendaylight.controller.clustering.services.IClusterGlobalServices
-import org.opendaylight.controller.clustering.services.IClusterServices
-
-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.SwitchFlowRemoved
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowUpdated
-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.NodeErrorNotification
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeExperimenterErrorNotification
-import org.opendaylight.yangtools.yang.common.RpcResult
-import org.slf4j.LoggerFactory
-
-import org.opendaylight.controller.sal.binding.api.data.DataBrokerService
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId
-
-
-import static extension org.opendaylight.controller.sal.compatibility.MDFlowMapping.*
-
-import static extension org.opendaylight.controller.sal.compatibility.NodeMapping.*
-import static extension org.opendaylight.controller.sal.compatibility.ToSalConversionsUtils.*
-
-class FlowProgrammerAdapter implements IPluginInFlowProgrammerService, SalFlowListener {
-
- private static val LOG = LoggerFactory.getLogger(FlowProgrammerAdapter);
- private static val CACHE_NAME = "flowprogrammeradapter.flowtoid";
-
- @Property
- private SalFlowService delegate;
-
- @Property
- private DataBrokerService dataBrokerService;
-
- @Property
- private IPluginOutFlowProgrammerService flowProgrammerPublisher;
-
- @Property
- private IClusterGlobalServices clusterGlobalServices;
-
-
- @Property
- private Map<Flow, UUID> flowToFlowId = new ConcurrentHashMap<Flow, UUID>();
-
-
- override addFlow(Node node, Flow flow) {
- return toFutureStatus(internalAddFlowAsync(node,flow,0));
- }
-
- override modifyFlow(Node node, Flow oldFlow, Flow newFlow) {
- return toFutureStatus(internalModifyFlowAsync(node, oldFlow,newFlow,0));
- }
-
- override removeFlow(Node node, Flow flow) {
- return toFutureStatus(internalRemoveFlowAsync(node, flow,0));
- }
-
- override addFlowAsync(Node node, Flow flow, long rid) {
- internalAddFlowAsync(node, flow, rid);
- return toStatus(true);
- }
-
- override modifyFlowAsync(Node node, Flow oldFlow, Flow newFlow, long rid) {
- internalModifyFlowAsync(node, oldFlow, newFlow, rid);
- return toStatus(true);
- }
-
- override removeFlowAsync(Node node, Flow flow, long rid) {
- internalRemoveFlowAsync(node, flow, rid);
- return toStatus(true);
- }
-
- override removeAllFlows(Node node) {
- // I know this looks like a copout... but its exactly what the legacy OFplugin did
- return new Status(StatusCode.SUCCESS);
- }
-
- override syncSendBarrierMessage(Node node) {
-
- // FIXME: Update YANG model
- return null;
- }
-
- override asyncSendBarrierMessage(Node node) {
-
- // FIXME: Update YANG model
- return null;
- }
-
- private static def toStatus(boolean successful) {
- if (successful) {
- return new Status(StatusCode.SUCCESS);
- } else {
- return new Status(StatusCode.INTERNALERROR);
- }
- }
-
- public static def toStatus(RpcResult<?> result) {
- return toStatus(result.isSuccessful());
- }
-
- private static dispatch def Status processException(InterruptedException e) {
- LOG.error("Interruption occured during processing flow",e);
- return new Status(StatusCode.INTERNALERROR);
- }
-
- private static dispatch def Status processException(ExecutionException e) {
- LOG.error("Execution exception occured during processing flow",e.cause);
- return new Status(StatusCode.INTERNALERROR);
- }
-
- private static dispatch def Status processException(Exception e) {
- throw new RuntimeException(e);
- }
-
- override onFlowAdded(FlowAdded notification) {
- // NOOP : Not supported by AD SAL
- }
-
- override onFlowRemoved(FlowRemoved notification) {
- if(notification != null && notification.node != null) {
- val adNode = notification.node.toADNode
- if(adNode != null) {
- flowProgrammerPublisher.flowRemoved(adNode,notification.toFlow(adNode));
- }
- }
- }
-
- override onFlowUpdated(FlowUpdated notification) {
- // NOOP : Not supported by AD SAL
- }
-
- override onSwitchFlowRemoved(SwitchFlowRemoved notification) {
- // NOOP : Not supported by AD SAL
- }
-
- override onNodeErrorNotification(NodeErrorNotification notification) {
- // NOOP : Not supported by AD SAL
- }
-
- override onNodeExperimenterErrorNotification(
- NodeExperimenterErrorNotification notification) {
- // NOOP : Not supported by AD SAL
- }
-
- private def Future<RpcResult<TransactionStatus>> writeFlowAsync(org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow flow, NodeKey nodeKey){
- val modification = this._dataBrokerService.beginTransaction();
- val flowPath = InstanceIdentifier.builder(Nodes)
- .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, nodeKey)
- .augmentation(FlowCapableNode)
- .child(Table, new TableKey(flow.getTableId()))
- .child(org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow, new FlowKey(flow.id))
- .build;
- modification.putConfigurationData(flowPath, flow);
- return modification.commit();
- }
-
- private def Future<RpcResult<TransactionStatus>> internalAddFlowAsync(Node node, Flow flow, long rid){
- var flowId = getCache().get(flow);
- if(flowId != null) {
- removeFlow(node, flow);
- return internalAddFlowAsync(node, flow, rid);
- }
-
- flowId = UUID.randomUUID();
- getCache().put(flow, flowId);
-
- return writeFlowAsync(flow.toMDFlow(flowId.toString()), new NodeKey(new NodeId(node.getNodeIDString())));
- }
-
- private def Future<RpcResult<TransactionStatus>> internalModifyFlowAsync(Node node, Flow oldFlow, Flow newFlow, long rid) {
- var flowId = getCache().remove(oldFlow);
- if(flowId == null){
- LOG.error("oldFlow not found in cache : " + oldFlow.hashCode);
- flowId = UUID.randomUUID();
- getCache().put(oldFlow, flowId);
- }
-
- getCache().put(newFlow, flowId);
- return writeFlowAsync(newFlow.toMDFlow(flowId.toString()), new NodeKey(new NodeId(node.getNodeIDString())));
- }
-
-
- private def Future<RpcResult<TransactionStatus>> internalRemoveFlowAsync(Node node, Flow adflow, long rid){
- val flowId = getCache().remove(adflow);
- if(flowId == null){
- //throw new IllegalArgumentException("adflow not found in cache : " + adflow.hashCode);
- LOG.error("adflow not found in cache : " + adflow.hashCode);
- return null;
- }
- val flow = adflow.toMDFlow(flowId.toString());
- val modification = this._dataBrokerService.beginTransaction();
- val flowPath = InstanceIdentifier.builder(Nodes)
- .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, new NodeKey(new NodeId(node.getNodeIDString())))
- .augmentation(FlowCapableNode)
- .child(Table, new TableKey(flow.getTableId()))
- .child(org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow, new FlowKey(flow.id))
- .build;
- modification.removeConfigurationData(flowPath);
- return modification.commit();
- }
-
- private def toFutureStatus(Future<RpcResult<TransactionStatus>> future){
- if(future == null){
- return toStatus(true);
- }
-
- try {
- val result = future.get();
- return toStatus(result);
- } catch (InterruptedException e) {
- return processException(e);
- } catch (ExecutionException e) {
- return processException(e);
- } catch (Exception e){
- processException(e);
- }
- return toStatus(false);
- }
-
- private def Map<Flow, UUID> getCache(){
- if(clusterGlobalServices == null){
- return new ConcurrentHashMap<Flow, UUID>();
- }
-
- var cache = clusterGlobalServices.getCache(CACHE_NAME);
-
- if(cache == null) {
- try {
- cache = clusterGlobalServices.createCache(CACHE_NAME, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
- } catch (CacheExistException e) {
- cache = clusterGlobalServices.getCache(CACHE_NAME);
- }
- }
- return cache as Map<Flow, UUID>;
-
- }
-
-}
--- /dev/null
+/**
+ * Copyright (c) 2014 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.compatibility;
+
+import java.math.BigInteger;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.opendaylight.controller.sal.action.Action;
+import org.opendaylight.controller.sal.action.Controller;
+import org.opendaylight.controller.sal.action.Drop;
+import org.opendaylight.controller.sal.action.Flood;
+import org.opendaylight.controller.sal.action.FloodAll;
+import org.opendaylight.controller.sal.action.HwPath;
+import org.opendaylight.controller.sal.action.Loopback;
+import org.opendaylight.controller.sal.action.Output;
+import org.opendaylight.controller.sal.action.PopVlan;
+import org.opendaylight.controller.sal.action.PushVlan;
+import org.opendaylight.controller.sal.action.SetDlDst;
+import org.opendaylight.controller.sal.action.SetDlSrc;
+import org.opendaylight.controller.sal.action.SetDlType;
+import org.opendaylight.controller.sal.action.SetNextHop;
+import org.opendaylight.controller.sal.action.SetNwDst;
+import org.opendaylight.controller.sal.action.SetNwSrc;
+import org.opendaylight.controller.sal.action.SetNwTos;
+import org.opendaylight.controller.sal.action.SetTpDst;
+import org.opendaylight.controller.sal.action.SetTpSrc;
+import org.opendaylight.controller.sal.action.SetVlanCfi;
+import org.opendaylight.controller.sal.action.SetVlanId;
+import org.opendaylight.controller.sal.action.SetVlanPcp;
+import org.opendaylight.controller.sal.action.SwPath;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.flowprogrammer.Flow;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.VlanCfi;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.ControllerActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.ControllerActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.DropActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.DropActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.FloodActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.FloodActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.FloodAllActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.FloodAllActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.HwPathActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.HwPathActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.LoopbackActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.LoopbackActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopVlanActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopVlanActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetDlDstActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetDlDstActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetDlSrcActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetDlSrcActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetDlTypeActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetDlTypeActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNextHopActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNextHopActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNwDstActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNwDstActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNwSrcActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNwSrcActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNwTosActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNwTosActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetTpDstActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetTpDstActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetTpSrcActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetTpSrcActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanCfiActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanCfiActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanIdActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanIdActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanPcpActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanPcpActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SwPathActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SwPathActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.controller.action._case.ControllerActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.drop.action._case.DropActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.flood.action._case.FloodActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.flood.all.action._case.FloodAllActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.hw.path.action._case.HwPathActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.loopback.action._case.LoopbackActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.push.vlan.action._case.PushVlanActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.dl.dst.action._case.SetDlDstActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.dl.src.action._case.SetDlSrcActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.dl.type.action._case.SetDlTypeActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.next.hop.action._case.SetNextHopActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.nw.dst.action._case.SetNwDstActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.nw.src.action._case.SetNwSrcActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.nw.tos.action._case.SetNwTosActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.tp.dst.action._case.SetTpDstActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.tp.src.action._case.SetTpSrcActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.vlan.cfi.action._case.SetVlanCfiActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.vlan.id.action._case.SetVlanIdActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.vlan.pcp.action._case.SetVlanPcpActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.sw.path.action._case.SwPathActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.Address;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.address.Ipv4Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.address.Ipv6Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+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.FlowAdded;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowAddedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput;
+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.flow.types.rev131026.FlowCookie;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanPcp;
+
+import com.google.common.base.Preconditions;
+import com.google.common.net.InetAddresses;
+
+public final class MDFlowMapping {
+ private MDFlowMapping() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ private static List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> toMDActions(final List<Action> actions) {
+ final ArrayList<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> ret =
+ new ArrayList<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action>(actions.size());
+ int action = 0;
+ for (final Action sourceAction : actions) {
+ ret.add(toAction(sourceAction, action));
+ action++;
+ }
+
+ return ret;
+ }
+
+ public static FlowAdded flowAdded(final Flow sourceFlow) {
+ Preconditions.checkArgument(sourceFlow != null);
+
+ return new FlowAddedBuilder()
+ .setHardTimeout(Integer.valueOf(sourceFlow.getHardTimeout()))
+ .setIdleTimeout(Integer.valueOf(sourceFlow.getIdleTimeout()))
+ .setCookie(new FlowCookie(BigInteger.valueOf(sourceFlow.getId())))
+ .setPriority(Integer.valueOf(sourceFlow.getPriority()))
+ .setInstructions(MDFlowMapping.toApplyInstruction(toMDActions(sourceFlow.getActions())))
+ .setMatch(FromSalConversionsUtils.toMatch(sourceFlow.getMatch()))
+ .setTableId((short)0)
+ .build();
+ }
+
+ private static FlowBuilder internalToMDFlow(final Flow sourceFlow) {
+ Preconditions.checkArgument(sourceFlow != null);
+
+ return new FlowBuilder()
+ .setHardTimeout(Integer.valueOf(sourceFlow.getHardTimeout()))
+ .setIdleTimeout(Integer.valueOf(sourceFlow.getIdleTimeout()))
+ .setCookie(new FlowCookie(BigInteger.valueOf(sourceFlow.getId())))
+ .setPriority(Integer.valueOf((sourceFlow.getPriority())))
+ .setInstructions(MDFlowMapping.toApplyInstruction(toMDActions(sourceFlow.getActions())))
+ .setMatch(FromSalConversionsUtils.toMatch(sourceFlow.getMatch()));
+ }
+
+ public static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow toMDFlow(final Flow sourceFlow, final String flowId) {
+ return internalToMDFlow(sourceFlow)
+ .setTableId((short)0)
+ .setId(new FlowId(flowId))
+ .build();
+ }
+
+ public static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow toMDSalflow(final Flow sourceFlow) {
+ return internalToMDFlow(sourceFlow).build();
+ }
+
+ public static Instructions toApplyInstruction(final List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> actions) {
+ return new InstructionsBuilder()
+ .setInstruction(
+ Collections.singletonList(
+ new InstructionBuilder()
+ .setOrder(0)
+ .setInstruction(
+ new ApplyActionsCaseBuilder()
+ .setApplyActions(new ApplyActionsBuilder().setAction(actions).build())
+ .build()
+ ).build())
+ ).build();
+ }
+
+ public static RemoveFlowInput removeFlowInput(final Node sourceNode, final Flow sourceFlow) {
+ final FlowAdded source = MDFlowMapping.flowAdded(sourceFlow);
+ return new RemoveFlowInputBuilder((org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow) source)
+ .setNode(NodeMapping.toNodeRef(sourceNode))
+ .build();
+ }
+
+ public static AddFlowInput addFlowInput(final Node sourceNode, final Flow sourceFlow) {
+ final FlowAdded source = MDFlowMapping.flowAdded(sourceFlow);
+ return new AddFlowInputBuilder(((org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow) source))
+ .setNode(NodeMapping.toNodeRef(sourceNode))
+ .build();
+ }
+
+ public static UpdateFlowInput updateFlowInput(final Node sourceNode, final Flow oldFlow, final Flow newFlow) {
+ return new UpdateFlowInputBuilder()
+ .setOriginalFlow(new OriginalFlowBuilder(MDFlowMapping.flowAdded(newFlow)).build())
+ .setUpdatedFlow(new UpdatedFlowBuilder(MDFlowMapping.flowAdded(newFlow)).build())
+ .setNode(NodeMapping.toNodeRef(sourceNode))
+ .build();
+ }
+
+ private static ControllerActionCase _toAction(final Controller sourceAction) {
+ return new ControllerActionCaseBuilder().setControllerAction(new ControllerActionBuilder().build()).build();
+ }
+
+ private static DropActionCase _toAction(final Drop sourceAction) {
+ return new DropActionCaseBuilder().setDropAction(new DropActionBuilder().build()).build();
+ }
+
+ private static FloodActionCase _toAction(final Flood sourceAction) {
+ return new FloodActionCaseBuilder().setFloodAction(new FloodActionBuilder().build()).build();
+ }
+
+ private static FloodAllActionCase _toAction(final FloodAll sourceAction) {
+ return new FloodAllActionCaseBuilder().setFloodAllAction(new FloodAllActionBuilder().build()).build();
+ }
+
+ private static HwPathActionCase _toAction(final HwPath sourceAction) {
+ return new HwPathActionCaseBuilder().setHwPathAction(new HwPathActionBuilder().build()).build();
+ }
+
+ private static LoopbackActionCase _toAction(final Loopback sourceAction) {
+ return new LoopbackActionCaseBuilder().setLoopbackAction( new LoopbackActionBuilder().build()).build();
+ }
+
+ private static OutputActionCase _toAction(final Output sourceAction) {
+ return new OutputActionCaseBuilder()
+ .setOutputAction(
+ new OutputActionBuilder().setOutputNodeConnector(MDFlowMapping.toUri(sourceAction.getPort())).build()
+ ).build();
+ }
+
+ private static PopVlanActionCase _toAction(final PopVlan sourceAction) {
+ return new PopVlanActionCaseBuilder().build();
+ }
+
+ private static PushVlanActionCase _toAction(final PushVlan sourceAction) {
+ return new PushVlanActionCaseBuilder()
+ .setPushVlanAction(
+ new PushVlanActionBuilder()
+ .setCfi(new VlanCfi(sourceAction.getCfi()))
+ .setPcp(sourceAction.getPcp())
+ .setTag(sourceAction.getTag())
+ .setVlanId(new VlanId(sourceAction.getVlanId()))
+ .build()
+ ).build();
+ }
+
+ private static SetDlDstActionCase _toAction(final SetDlDst sourceAction) {
+ return new SetDlDstActionCaseBuilder()
+ .setSetDlDstAction(new SetDlDstActionBuilder().setAddress(MDFlowMapping.toMacAddress(sourceAction.getDlAddress())).build())
+ .build();
+ }
+
+ private static SetDlSrcActionCase _toAction(final SetDlSrc sourceAction) {
+ return new SetDlSrcActionCaseBuilder()
+ .setSetDlSrcAction(new SetDlSrcActionBuilder().setAddress(MDFlowMapping.toMacAddress(sourceAction.getDlAddress())).build())
+ .build();
+ }
+
+ private static SetDlTypeActionCase _toAction(final SetDlType sourceAction) {
+ return new SetDlTypeActionCaseBuilder()
+ .setSetDlTypeAction(new SetDlTypeActionBuilder().setDlType(new EtherType(Long.valueOf(sourceAction.getDlType()))).build())
+ .build();
+ }
+
+ private static SetNextHopActionCase _toAction(final SetNextHop sourceAction) {
+ return new SetNextHopActionCaseBuilder()
+ .setSetNextHopAction(new SetNextHopActionBuilder().setAddress(MDFlowMapping.toInetAddress(sourceAction.getAddress())).build())
+ .build();
+ }
+
+ private static SetNwDstActionCase _toAction(final SetNwDst sourceAction) {
+ return new SetNwDstActionCaseBuilder()
+ .setSetNwDstAction(new SetNwDstActionBuilder().setAddress(MDFlowMapping.toInetAddress(sourceAction.getAddress())).build())
+ .build();
+ }
+
+ private static SetNwSrcActionCase _toAction(final SetNwSrc sourceAction) {
+ return new SetNwSrcActionCaseBuilder()
+ .setSetNwSrcAction(new SetNwSrcActionBuilder().setAddress(MDFlowMapping.toInetAddress(sourceAction.getAddress())).build())
+ .build();
+ }
+
+ private static SetNwTosActionCase _toAction(final SetNwTos sourceAction) {
+ return new SetNwTosActionCaseBuilder()
+ .setSetNwTosAction(new SetNwTosActionBuilder().setTos(sourceAction.getNwTos()).build())
+ .build();
+ }
+
+ private static SetTpDstActionCase _toAction(final SetTpDst sourceAction) {
+ return new SetTpDstActionCaseBuilder()
+ .setSetTpDstAction(new SetTpDstActionBuilder().setPort(new PortNumber(sourceAction.getPort())).build())
+ .build();
+ }
+
+ private static SetTpSrcActionCase _toAction(final SetTpSrc sourceAction) {
+ return new SetTpSrcActionCaseBuilder()
+ .setSetTpSrcAction(new SetTpSrcActionBuilder().setPort(new PortNumber(sourceAction.getPort())).build())
+ .build();
+ }
+
+ private static SetVlanCfiActionCase _toAction(final SetVlanCfi sourceAction) {
+ return new SetVlanCfiActionCaseBuilder()
+ .setSetVlanCfiAction(new SetVlanCfiActionBuilder().setVlanCfi(new VlanCfi(sourceAction.getCfi())).build())
+ .build();
+ }
+
+ private static SetVlanIdActionCase _toAction(final SetVlanId sourceAction) {
+ return new SetVlanIdActionCaseBuilder()
+ .setSetVlanIdAction(new SetVlanIdActionBuilder().setVlanId(new VlanId(sourceAction.getVlanId())).build())
+ .build();
+ }
+
+ private static SetVlanPcpActionCase _toAction(final SetVlanPcp sourceAction) {
+ return new SetVlanPcpActionCaseBuilder()
+ .setSetVlanPcpAction(new SetVlanPcpActionBuilder().setVlanPcp(new VlanPcp((short) sourceAction.getPcp())).build())
+ .build();
+ }
+
+ private static SwPathActionCase _toAction(final SwPath sourceAction) {
+ return new SwPathActionCaseBuilder().setSwPathAction(new SwPathActionBuilder().build()).build();
+ }
+
+ public static Uri toUri(final NodeConnector connector) {
+ return new NodeConnectorId(((String) connector.getID()));
+ }
+
+ public static MacAddress toMacAddress(final byte[] bytes) {
+ final StringBuilder sb = new StringBuilder(18);
+ boolean first = true;
+
+ for (final byte b : bytes) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(':');
+ }
+ sb.append(String.format("%02x", Byte.valueOf(b)));
+ }
+ return new MacAddress(sb.toString());
+ }
+
+ public static org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action toAction(final Action sourceAction, final int order) {
+ final ActionBuilder ret = new ActionBuilder().setOrder(order);
+
+ if (sourceAction instanceof Controller) {
+ ret.setAction(_toAction((Controller)sourceAction));
+ } else if (sourceAction instanceof Drop) {
+ ret.setAction(_toAction((Drop)sourceAction));
+ } else if (sourceAction instanceof Flood) {
+ ret.setAction(_toAction((Flood)sourceAction));
+ } else if (sourceAction instanceof FloodAll) {
+ ret.setAction(_toAction((FloodAll)sourceAction));
+ } else if (sourceAction instanceof HwPath) {
+ ret.setAction(_toAction((HwPath)sourceAction));
+ } else if (sourceAction instanceof Loopback) {
+ ret.setAction(_toAction((Loopback)sourceAction));
+ } else if (sourceAction instanceof Output) {
+ ret.setAction(_toAction((Output)sourceAction));
+ } else if (sourceAction instanceof PopVlan) {
+ ret.setAction(_toAction((PopVlan)sourceAction));
+ } else if (sourceAction instanceof PushVlan) {
+ ret.setAction(_toAction((PushVlan)sourceAction));
+ } else if (sourceAction instanceof SetDlDst) {
+ ret.setAction(_toAction((SetDlDst)sourceAction));
+ } else if (sourceAction instanceof SetDlSrc) {
+ ret.setAction(_toAction((SetDlSrc)sourceAction));
+ } else if (sourceAction instanceof SetDlType) {
+ ret.setAction(_toAction((SetDlType)sourceAction));
+ } else if (sourceAction instanceof SetNextHop) {
+ ret.setAction(_toAction((SetNextHop)sourceAction));
+ } else if (sourceAction instanceof SetNwDst) {
+ ret.setAction(_toAction((SetNwDst)sourceAction));
+ } else if (sourceAction instanceof SetNwSrc) {
+ ret.setAction(_toAction((SetNwSrc)sourceAction));
+ } else if (sourceAction instanceof SetNwTos) {
+ ret.setAction(_toAction((SetNwTos)sourceAction));
+ } else if (sourceAction instanceof SetTpDst) {
+ ret.setAction(_toAction((SetTpDst)sourceAction));
+ } else if (sourceAction instanceof SetTpSrc) {
+ ret.setAction(_toAction((SetTpSrc)sourceAction));
+ } else if (sourceAction instanceof SetVlanCfi) {
+ ret.setAction(_toAction((SetVlanCfi)sourceAction));
+ } else if (sourceAction instanceof SetVlanId) {
+ ret.setAction(_toAction((SetVlanId)sourceAction));
+ } else if (sourceAction instanceof SetVlanPcp) {
+ ret.setAction(_toAction((SetVlanPcp)sourceAction));
+ } else if (sourceAction instanceof SwPath) {
+ ret.setAction(_toAction((SwPath)sourceAction));
+ } else {
+ throw new IllegalArgumentException(String.format("Unhandled action class %s", sourceAction.getClass()));
+ }
+
+ return ret.build();
+ }
+
+ public static Address toInetAddress(final InetAddress address) {
+ if (address instanceof Inet4Address) {
+ return new Ipv4Builder()
+ .setIpv4Address(new Ipv4Prefix(InetAddresses.toAddrString(address)))
+ .build();
+ }
+ if (address instanceof Inet6Address) {
+ return new Ipv6Builder()
+ .setIpv6Address(new Ipv6Prefix(InetAddresses.toAddrString(address)))
+ .build();
+ }
+
+ throw new IllegalArgumentException(String.format("Unhandled address class %s", address.getClass()));
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 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.compatibility;
-
-import com.google.common.net.InetAddresses
-import java.math.BigInteger
-import java.net.Inet4Address
-import java.net.Inet6Address
-import java.util.ArrayList
-import org.opendaylight.controller.sal.action.Controller
-import org.opendaylight.controller.sal.action.Drop
-import org.opendaylight.controller.sal.action.Flood
-import org.opendaylight.controller.sal.action.FloodAll
-import org.opendaylight.controller.sal.action.HwPath
-import org.opendaylight.controller.sal.action.Loopback
-import org.opendaylight.controller.sal.action.Output
-import org.opendaylight.controller.sal.action.PopVlan
-import org.opendaylight.controller.sal.action.PushVlan
-import org.opendaylight.controller.sal.action.SetDlDst
-import org.opendaylight.controller.sal.action.SetDlSrc
-import org.opendaylight.controller.sal.action.SetDlType
-import org.opendaylight.controller.sal.action.SetNextHop
-import org.opendaylight.controller.sal.action.SetNwDst
-import org.opendaylight.controller.sal.action.SetNwSrc
-import org.opendaylight.controller.sal.action.SetNwTos
-import org.opendaylight.controller.sal.action.SetTpDst
-import org.opendaylight.controller.sal.action.SetTpSrc
-import org.opendaylight.controller.sal.action.SetVlanCfi
-import org.opendaylight.controller.sal.action.SetVlanId
-import org.opendaylight.controller.sal.action.SetVlanPcp
-import org.opendaylight.controller.sal.action.SwPath
-import org.opendaylight.controller.sal.core.Node
-import org.opendaylight.controller.sal.core.NodeConnector
-import org.opendaylight.controller.sal.flowprogrammer.Flow
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowAddedBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInputBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInputBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.VlanCfi
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.Address
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.address.Ipv4Builder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.address.Ipv6Builder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType
-import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId
-import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanPcp
-
-import static extension org.opendaylight.controller.sal.compatibility.FromSalConversionsUtils.*
-import static extension org.opendaylight.controller.sal.compatibility.NodeMapping.*
-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.flow.types.rev131026.flow.Instructions
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder
-import java.util.Collections
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.controller.action._case.ControllerActionBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.drop.action._case.DropActionBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.flood.action._case.FloodActionBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.flood.all.action._case.FloodAllActionBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.hw.path.action._case.HwPathActionBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.loopback.action._case.LoopbackActionBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.push.vlan.action._case.PushVlanActionBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.dl.dst.action._case.SetDlDstActionBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.dl.src.action._case.SetDlSrcActionBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.dl.type.action._case.SetDlTypeActionBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.next.hop.action._case.SetNextHopActionBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.nw.dst.action._case.SetNwDstActionBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.nw.src.action._case.SetNwSrcActionBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.nw.tos.action._case.SetNwTosActionBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.tp.dst.action._case.SetTpDstActionBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.tp.src.action._case.SetTpSrcActionBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.vlan.cfi.action._case.SetVlanCfiActionBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.vlan.id.action._case.SetVlanIdActionBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.vlan.pcp.action._case.SetVlanPcpActionBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.sw.path.action._case.SwPathActionBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetTpSrcActionCaseBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetTpDstActionCaseBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNwTosActionCaseBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNwSrcActionCaseBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNwDstActionCaseBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNextHopActionCaseBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetDlTypeActionCaseBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetDlDstActionCaseBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.ControllerActionCaseBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.DropActionCaseBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.FloodActionCaseBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.FloodAllActionCaseBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.HwPathActionCaseBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.LoopbackActionCaseBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopVlanActionCaseBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCaseBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetDlSrcActionCaseBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanCfiActionCaseBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanIdActionCaseBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanPcpActionCaseBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SwPathActionCaseBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie
-
-public class MDFlowMapping {
-
- private new() {
- throw new UnsupportedOperationException()
- }
-
- public static def flowAdded(Flow sourceFlow) {
- if (sourceFlow == null)
- throw new IllegalArgumentException();
- val it = new FlowAddedBuilder();
-
- hardTimeout = sourceFlow.hardTimeout as int
- idleTimeout = sourceFlow.idleTimeout as int
- cookie = new FlowCookie(BigInteger.valueOf(sourceFlow.id))
- priority = sourceFlow.priority as int
-
- val sourceActions = sourceFlow.actions;
- val targetActions = new ArrayList<Action>();
- var int action = 0;
- for (sourceAction : sourceActions) {
- targetActions.add(sourceAction.toAction(action));
- action = action + 1;
- }
- instructions = targetActions.toApplyInstruction();
- match = sourceFlow.match.toMatch();
- tableId = new Integer(0).shortValue
- return it.build();
-
- }
-
- public static def toMDFlow(Flow sourceFlow, String flowId) {
- if (sourceFlow == null)
- throw new IllegalArgumentException();
- val it = new FlowBuilder();
- hardTimeout = sourceFlow.hardTimeout as int
- idleTimeout = sourceFlow.idleTimeout as int
- cookie = new FlowCookie(BigInteger.valueOf(sourceFlow.id))
- priority = sourceFlow.priority as int
- id = new FlowId(flowId)
-
- val sourceActions = sourceFlow.actions;
- val targetActions = new ArrayList<Action>();
- var int action = 0;
- for (sourceAction : sourceActions) {
- targetActions.add(sourceAction.toAction(action));
- action = action+ 1;
- }
- instructions = targetActions.toApplyInstruction();
- match = sourceFlow.match.toMatch();
- tableId = new Integer(0).shortValue
- return it.build();
- }
-
- public static def Instructions toApplyInstruction(ArrayList<Action> actions) {
- val it = new InstructionsBuilder;
- val applyActions = new InstructionBuilder;
- applyActions.instruction = new ApplyActionsCaseBuilder().setApplyActions(new ApplyActionsBuilder().setAction(actions).build()).build()
- applyActions.setOrder(new Integer(0))
- instruction = Collections.<Instruction>singletonList(applyActions.build)
- return it.build;
- }
-
- public static def removeFlowInput(Node sourceNode, Flow sourceFlow) {
- val source = flowAdded(sourceFlow);
- val it = new RemoveFlowInputBuilder(source as org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow);
- node = sourceNode.toNodeRef()
- return it.build();
- }
-
- public static def addFlowInput(Node sourceNode, Flow sourceFlow) {
- val source = flowAdded(sourceFlow);
- val it = new AddFlowInputBuilder(source as org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow);
- it.setNode(sourceNode.toNodeRef)
- return it.build();
- }
-
- public static def updateFlowInput(Node sourceNode, Flow oldFlow, Flow newFlow) {
- val it = new UpdateFlowInputBuilder();
- val sourceOld = flowAdded(newFlow);
-
- val original = new OriginalFlowBuilder(sourceOld as org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow);
- val sourceNew = flowAdded(newFlow);
- val updated = new UpdatedFlowBuilder(sourceNew as org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow);
- originalFlow = original.build()
- updatedFlow = updated.build();
- node = sourceNode.toNodeRef()
- return it.build();
- }
-
- public static dispatch def toAction(Controller sourceAction, int order) {
- val actionBuilder = new ActionBuilder().setOrder(order);
- actionBuilder.action = new ControllerActionCaseBuilder().setControllerAction(new ControllerActionBuilder().build()).build();
- return actionBuilder.build();
- }
-
- public static dispatch def toAction(Drop sourceAction, int order) {
- val actionBuilder = new ActionBuilder().setOrder(order);
- actionBuilder.action = new DropActionCaseBuilder().setDropAction(new DropActionBuilder().build()).build();
- return actionBuilder.build();
- }
-
- public static dispatch def toAction(Flood sourceAction, int order) {
- val actionBuilder = new ActionBuilder().setOrder(order);
- actionBuilder.action = new FloodActionCaseBuilder().setFloodAction(new FloodActionBuilder().build).build();
- return actionBuilder.build();
- }
-
- public static dispatch def toAction(FloodAll sourceAction, int order) {
- val actionBuilder = new ActionBuilder().setOrder(order);
- actionBuilder.action = new FloodAllActionCaseBuilder().setFloodAllAction(new FloodAllActionBuilder().build()).build();
- return actionBuilder.build();
- }
-
- public static dispatch def toAction(HwPath sourceAction, int order) {
- val actionBuilder = new ActionBuilder().setOrder(order);
- actionBuilder.action = new HwPathActionCaseBuilder().setHwPathAction(new HwPathActionBuilder().build()).build();
- return actionBuilder.build();
- }
-
- public static dispatch def toAction(Loopback sourceAction, int order) {
- val actionBuilder = new ActionBuilder().setOrder(order);
- actionBuilder.action = new LoopbackActionCaseBuilder().setLoopbackAction(new LoopbackActionBuilder().build()).build();
- return actionBuilder.build();
- }
-
- public static dispatch def toAction(Output sourceAction, int order) {
- val actionBuilder = new ActionBuilder().setOrder(order);
- val it = new OutputActionBuilder();
- outputNodeConnector = sourceAction.port.toUri;
- actionBuilder.action = new OutputActionCaseBuilder().setOutputAction(it.build()).build();
- return actionBuilder.build();
-
- }
-
- public static dispatch def toAction(PopVlan sourceAction, int order) {
- val actionBuilder = new ActionBuilder().setOrder(order);
- actionBuilder.action = new PopVlanActionCaseBuilder().build();
- return actionBuilder.build();
- }
-
- public static dispatch def toAction(PushVlan sourceAction, int order) {
- val actionBuilder = new ActionBuilder().setOrder(order);
- val it = new PushVlanActionBuilder();
- cfi = new VlanCfi(sourceAction.cfi);
- vlanId = new VlanId(sourceAction.vlanId);
- pcp = sourceAction.pcp;
- tag = sourceAction.tag;
- actionBuilder.action = new PushVlanActionCaseBuilder().setPushVlanAction(it.build()).build();
- return actionBuilder.build();
- }
-
- public static dispatch def toAction(SetDlDst sourceAction, int order) {
- val actionBuilder = new ActionBuilder().setOrder(order);
- val it = new SetDlDstActionBuilder();
- address = sourceAction.dlAddress.toMacAddress();
- actionBuilder.action = new SetDlDstActionCaseBuilder().setSetDlDstAction(it.build()).build;
- return actionBuilder.build();
- }
-
- public static dispatch def toAction(SetDlSrc sourceAction, int order) {
- val actionBuilder = new ActionBuilder().setOrder(order);
- val it = new SetDlSrcActionBuilder();
- address = sourceAction.dlAddress.toMacAddress;
- actionBuilder.action = new SetDlSrcActionCaseBuilder().setSetDlSrcAction(it.build()).build;
- return actionBuilder.build();
- }
-
- public static dispatch def toAction(SetDlType sourceAction, int order) {
- val actionBuilder = new ActionBuilder().setOrder(order);
- val it = new SetDlTypeActionBuilder();
- dlType = new EtherType(sourceAction.dlType as long);
- actionBuilder.action = new SetDlTypeActionCaseBuilder().setSetDlTypeAction(it.build()).build();
- return actionBuilder.build();
- }
-
- public static dispatch def toAction(SetNextHop sourceAction, int order) {
- val actionBuilder = new ActionBuilder().setOrder(order);
- val it = new SetNextHopActionBuilder();
- val inetAddress = sourceAction.address;
- address = inetAddress.toInetAddress;
- actionBuilder.action = new SetNextHopActionCaseBuilder().setSetNextHopAction(it.build).build();
- return actionBuilder.build();
- }
-
- public static dispatch def toAction(SetNwDst sourceAction, int order) {
- val actionBuilder = new ActionBuilder().setOrder(order);
- val it = new SetNwDstActionBuilder();
- val inetAddress = sourceAction.address;
- address = inetAddress.toInetAddress;
- actionBuilder.action = new SetNwDstActionCaseBuilder().setSetNwDstAction(it.build()).build();
- return actionBuilder.build();
- }
-
- public static dispatch def toAction(SetNwSrc sourceAction, int order) {
- val actionBuilder = new ActionBuilder().setOrder(order);
- val it = new SetNwSrcActionBuilder();
- val inetAddress = sourceAction.address;
- address = inetAddress.toInetAddress;
- actionBuilder.action = new SetNwSrcActionCaseBuilder().setSetNwSrcAction(it.build()).build();
- return actionBuilder.build();
- }
-
- public static dispatch def toAction(SetNwTos sourceAction, int order) {
- val actionBuilder = new ActionBuilder().setOrder(order);
- val it = new SetNwTosActionBuilder();
- tos = sourceAction.nwTos;
- actionBuilder.action = new SetNwTosActionCaseBuilder().setSetNwTosAction(it.build).build;
- return actionBuilder.build();
- }
-
- public static dispatch def toAction(SetTpDst sourceAction, int order) {
- val actionBuilder = new ActionBuilder().setOrder(order);
- val it = new SetTpDstActionBuilder();
- port = new PortNumber(sourceAction.port);
- actionBuilder.action = new SetTpDstActionCaseBuilder().setSetTpDstAction(it.build()).build();
- return actionBuilder.build();
- }
-
- public static dispatch def toAction(SetTpSrc sourceAction, int order) {
- val actionBuilder = new ActionBuilder().setOrder(order);
- val it = new SetTpSrcActionBuilder();
- port = new PortNumber(sourceAction.port);
- actionBuilder.action = new SetTpSrcActionCaseBuilder().setSetTpSrcAction(it.build()).build();
- return actionBuilder.build();
- }
-
- public static dispatch def toAction(SetVlanCfi sourceAction, int order) {
- val actionBuilder = new ActionBuilder().setOrder(order);
- val it = new SetVlanCfiActionBuilder();
- vlanCfi = new VlanCfi(sourceAction.cfi);
- actionBuilder.action = new SetVlanCfiActionCaseBuilder().setSetVlanCfiAction(it.build()).build();
- return actionBuilder.build();
- }
-
- public static dispatch def toAction(SetVlanId sourceAction, int order) {
- val actionBuilder = new ActionBuilder().setOrder(order);
-
- val it = new SetVlanIdActionBuilder();
- vlanId = new VlanId(sourceAction.vlanId);
- actionBuilder.action = new SetVlanIdActionCaseBuilder().setSetVlanIdAction(it.build()).build();
- return actionBuilder.build();
- }
-
- public static dispatch def toAction(SetVlanPcp sourceAction, int order) {
- val actionBuilder = new ActionBuilder().setOrder(order);
- val it = new SetVlanPcpActionBuilder();
- vlanPcp = new VlanPcp(sourceAction.pcp as short);
- actionBuilder.action = new SetVlanPcpActionCaseBuilder().setSetVlanPcpAction(it.build).build;
- return actionBuilder.build();
- }
-
- public static dispatch def toAction(SwPath sourceAction, int order) {
- val actionBuilder = new ActionBuilder().setOrder(order);
- actionBuilder.action = new SwPathActionCaseBuilder().setSwPathAction(new SwPathActionBuilder().build()).build();
- return actionBuilder.build();
- }
-
- public static def dispatch Address toInetAddress(Inet4Address address) {
- val it = new Ipv4Builder
- ipv4Address = new Ipv4Prefix(InetAddresses.toAddrString(address))
- return it.build()
- }
-
- public static def dispatch Address toInetAddress(Inet6Address address) {
- val it = new Ipv6Builder
- ipv6Address = new Ipv6Prefix(InetAddresses.toAddrString(address))
- return it.build()
- }
-
- public static def Uri toUri(NodeConnector connector) {
- return new NodeConnectorId(connector.ID as String);
- }
-
- public static def MacAddress toMacAddress(byte[] bytes) {
- val sb = new StringBuilder(18);
- for (byte b : bytes) {
- if (sb.length() > 0)
- sb.append(':');
- sb.append(String.format("%02x", b));
- }
- return new MacAddress(sb.toString());
- }
-
- public static def toMDSalflow(Flow sourceFlow) {
- if (sourceFlow == null)
- throw new IllegalArgumentException();
- val it = new FlowBuilder();
-
- hardTimeout = sourceFlow.hardTimeout as int
- idleTimeout = sourceFlow.idleTimeout as int
- cookie = new FlowCookie(BigInteger.valueOf(sourceFlow.id))
- priority = sourceFlow.priority as int
-
- val sourceActions = sourceFlow.actions;
- val targetActions = new ArrayList<Action>();
- var int action = 0;
- for (sourceAction : sourceActions) {
- targetActions.add(sourceAction.toAction(action));
- action = action + 1;
- }
- instructions = targetActions.toApplyInstruction();
- match = sourceFlow.match.toMatch();
- return it.build();
- }
-
-}
--- /dev/null
+/**
+ * Copyright (c) 2014 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.compatibility;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.controller.sal.binding.api.NotificationService;
+import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.controller.sal.compatibility.adsal.DataPacketServiceAdapter;
+import org.opendaylight.controller.sal.compatibility.topology.TopologyAdapter;
+import org.opendaylight.controller.sal.compatibility.topology.TopologyProvider;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.FlowTopologyDiscoveryService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+
+import com.google.common.base.Preconditions;
+
+class SalCompatibilityProvider implements BindingAwareProvider {
+ private final ComponentActivator activator;
+
+ public SalCompatibilityProvider(final ComponentActivator cmpAct) {
+ this.activator = Preconditions.checkNotNull(cmpAct);
+ }
+
+ @Override
+ public Collection<? extends ProviderFunctionality> getFunctionality() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public Collection<? extends RpcService> getImplementations() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public void onSessionInitialized(final ConsumerContext session) {
+ // No-op
+ }
+
+ @Override
+ public void onSessionInitiated(final ProviderContext session) {
+ final NotificationService subscribe = session.getSALService(NotificationService.class);
+
+ final FlowProgrammerAdapter flow = activator.getFlow();
+ flow.setDelegate(session.getRpcService(SalFlowService.class));
+ flow.setDataBrokerService(session.getSALService(DataBrokerService.class));
+ // FIXME: remember registration for clean shutdown
+ subscribe.registerNotificationListener(flow);
+
+ final InventoryAndReadAdapter inv = activator.getInventory();
+ inv.setDataService(session.getSALService(DataBrokerService.class));
+ inv.setFlowStatisticsService(session.getRpcService(OpendaylightFlowStatisticsService.class));
+ inv.setFlowTableStatisticsService(session.getRpcService(OpendaylightFlowTableStatisticsService.class));
+ inv.setNodeConnectorStatisticsService(session.getRpcService(OpendaylightPortStatisticsService.class));
+ inv.setTopologyDiscovery(session.getRpcService(FlowTopologyDiscoveryService.class));
+ inv.setDataProviderService(session.getSALService(DataProviderService.class));
+ // FIXME: remember registration for clean shutdown
+ subscribe.registerNotificationListener(inv);
+
+ final DataPacketServiceAdapter dps = activator.getDataPacketService();
+ dps.setDelegate(session.getRpcService(PacketProcessingService.class));
+
+ final TopologyAdapter topo = activator.getTopology();
+ topo.setDataService(session.getSALService(DataProviderService.class));
+
+ final TopologyProvider tpp = activator.getTpProvider();
+ tpp.setDataService(session.getSALService(DataProviderService.class));
+
+ inv.startAdapter();
+ tpp.startAdapter();
+
+ subscribe.registerNotificationListener(activator.getDataPacket());
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.compatibility.topology;
+
+import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.controller.sal.topology.IPluginInTopologyService;
+import org.opendaylight.controller.sal.topology.IPluginOutTopologyService;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.base.Preconditions;
+
+public class TopologyAdapter implements IPluginInTopologyService {
+ private final InstanceIdentifier<Topology> topology = InstanceIdentifier.builder(NetworkTopology.class)
+ .child(Topology.class, new TopologyKey(new TopologyId("flow:1"))).toInstance();
+
+ // Injected via Apache DM
+ private IPluginOutTopologyService topologyPublisher;
+
+
+ private DataProviderService dataService;
+
+ public void setDataService(final DataProviderService dataService) {
+ this.dataService = Preconditions.checkNotNull(dataService);
+ }
+
+ @Override
+ public void sollicitRefresh() {
+ final TypeSafeDataReader reader = TypeSafeDataReader.forReader(dataService);
+ final Topology t = reader.readOperationalData(topology);
+ topologyPublisher.edgeUpdate(TopologyMapping.toADEdgeUpdates(t, reader));
+ }
+
+ public IPluginOutTopologyService getTopologyPublisher() {
+ return topologyPublisher;
+ }
+
+ public void setTopologyPublisher(final IPluginOutTopologyService topologyPublisher) {
+ this.topologyPublisher = topologyPublisher;
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 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.compatibility.topology
-
-import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.controller.sal.topology.IPluginInTopologyService
-import org.opendaylight.controller.sal.topology.IPluginOutTopologyService
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-
-import static extension org.opendaylight.controller.sal.compatibility.topology.TopologyMapping.*
-
-class TopologyAdapter implements IPluginInTopologyService {
-
- @Property
- DataProviderService dataService;
-
- @Property
- IPluginOutTopologyService topologyPublisher;
-
- override sollicitRefresh() {
- val path = InstanceIdentifier.builder(NetworkTopology).child(Topology,new TopologyKey(new TopologyId("flow:1"))).toInstance;
- val reader = TypeSafeDataReader.forReader(dataService)
- val topology = reader.readOperationalData(path)
- topologyPublisher.edgeUpdate(topology.toADEdgeUpdates(reader))
- }
-
-}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.compatibility.topology;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader;
+import org.opendaylight.controller.sal.compatibility.NodeMapping;
+import org.opendaylight.controller.sal.core.ConstructionException;
+import org.opendaylight.controller.sal.core.Edge;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.Property;
+import org.opendaylight.controller.sal.core.UpdateType;
+import org.opendaylight.controller.sal.topology.TopoEdgeUpdate;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+
+public final class TopologyMapping {
+ private static final Logger LOG = LoggerFactory.getLogger(TopologyMapping.class);
+
+ private TopologyMapping() {
+ throw new UnsupportedOperationException("Utility class. Instantiation is not allowed.");
+ }
+
+ public static List<TopoEdgeUpdate> toADEdgeUpdates(final Topology topology,final TypeSafeDataReader reader) {
+ final List<TopoEdgeUpdate> result = new CopyOnWriteArrayList<>();
+ return FluentIterable.from(topology.getLink()).transform(
+ new Function<Link, TopoEdgeUpdate>() {
+ @Override
+ public TopoEdgeUpdate apply(final Link input) {
+ try {
+ return toTopoEdgeUpdate(toAdEdge(input, topology), reader);
+ } catch (ConstructionException e) {
+ throw new IllegalArgumentException(String.format("Failed to construct edge update for {}", input), e);
+ }
+ }}
+ ).copyInto(result);
+ }
+
+ public static Edge toAdEdge(final Link link, final Topology topology) throws ConstructionException {
+ final NodeConnector adSrc = toADNodeConnector(link.getSource().getSourceTp(), link.getSource().getSourceNode());
+ final NodeConnector adDst = toADNodeConnector(link.getDestination().getDestTp(), link.getDestination().getDestNode());
+ return new Edge(adSrc, adDst);
+ }
+
+ public static TopoEdgeUpdate toTopoEdgeUpdate(final Edge e, final TypeSafeDataReader reader) {
+ return toTopoEdgeUpdate(e, UpdateType.ADDED, reader);
+ }
+
+ public static TopoEdgeUpdate toTopoEdgeUpdate(final Edge e,final UpdateType type,final TypeSafeDataReader reader) {
+ return new TopoEdgeUpdate(e, toAdEdgeProperties(e, reader), type);
+ }
+
+ public static Set<Property> toAdEdgeProperties(final Edge e,final TypeSafeDataReader reader) {
+ final NodeConnectorRef ncref = NodeMapping.toNodeConnectorRef(e.getTailNodeConnector());
+ if(ncref == null) {
+ LOG.debug("Edge {} ncref {}",e,ncref);
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector> ncInstanceId =
+ (InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector>) ncref.getValue();
+ if(ncInstanceId == null) {
+ LOG.debug("Edge {} ncref {}",e,ncref);
+ return null;
+ }
+
+ final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector nc = reader.readOperationalData(ncInstanceId);
+ if(nc == null) {
+ return null;
+ }
+ return NodeMapping.toADNodeConnectorProperties(nc);
+ }
+
+ public static String toADNodeId(final NodeId nodeId) {
+ return nodeId.getValue();
+ }
+
+ public static NodeConnector toADNodeConnector(final TpId source, final NodeId nodeId) throws ConstructionException {
+ checkNotNull(source);
+ return new NodeConnector(NodeMapping.MD_SAL_TYPE, toADNodeConnectorId(source), toADNode(nodeId));
+ }
+
+ public static String toADNodeConnectorId(final TpId nodeConnectorId) {
+ return nodeConnectorId.getValue();
+ }
+
+ public static Node toADNode(final NodeId nodeId) throws ConstructionException {
+ checkNotNull(nodeId);
+ return new Node(NodeMapping.MD_SAL_TYPE, toADNodeId(nodeId));
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 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.compatibility.topology
-
-import com.google.common.collect.FluentIterable
-import java.util.List
-import java.util.concurrent.CopyOnWriteArrayList
-import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader
-import org.opendaylight.controller.sal.core.ConstructionException
-import org.opendaylight.controller.sal.core.Edge
-import org.opendaylight.controller.sal.core.Node
-import org.opendaylight.controller.sal.core.NodeConnector
-import org.opendaylight.controller.sal.core.UpdateType
-import org.opendaylight.controller.sal.topology.TopoEdgeUpdate
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.slf4j.LoggerFactory
-
-import static com.google.common.base.Preconditions.*
-
-import static extension org.opendaylight.controller.sal.compatibility.NodeMapping.*
-
-class TopologyMapping {
- private static val LOG = LoggerFactory.getLogger(TopologyMapping);
- private new() {
- throw new UnsupportedOperationException("Utility class. Instantiation is not allowed.");
- }
-
- public static def toADEdgeUpdates(Topology topology,TypeSafeDataReader reader) {
- val List<TopoEdgeUpdate> result = new CopyOnWriteArrayList<TopoEdgeUpdate>()
- return FluentIterable.from(topology.link).transform[toAdEdge(topology).toTopoEdgeUpdate(reader)].copyInto(result)
- }
-
- public static def toAdEdge(Link link,Topology topology) {
- val adSrc = link.source.sourceTp.toADNodeConnector(link.source.sourceNode)
- val adDst = link.destination.destTp.toADNodeConnector(link.destination.destNode)
- return new Edge(adSrc,adDst);
- }
-
- public static def toTopoEdgeUpdate(Edge e,TypeSafeDataReader reader) {
- return toTopoEdgeUpdate(e,UpdateType.ADDED,reader)
- }
-
- public static def toTopoEdgeUpdate(Edge e,UpdateType type,TypeSafeDataReader reader) {
- return new TopoEdgeUpdate(e,e.toAdEdgeProperties(reader),type)
- }
-
- public static def toAdEdgeProperties(Edge e,TypeSafeDataReader reader) {
- val ncref = e.tailNodeConnector.toNodeConnectorRef
- if(ncref == null) {
- LOG.debug("Edge {} ncref {}",e,ncref)
- return null;
- }
- val ncInstanceId = (ncref.value as InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector>)
- if(ncInstanceId == null) {
- LOG.debug("Edge {} ncref {}",e,ncref)
- return null;
- }
- val nc = reader.readOperationalData(ncInstanceId)
- if(nc == null) {
- return null;
- }
- return nc.toADNodeConnectorProperties
- }
-
- public static def toADNodeId(NodeId nodeId) {
- checkNotNull(nodeId);
- return nodeId.value
- }
- public static def toADNodeConnector(TpId source,NodeId nodeId) throws ConstructionException {
- checkNotNull(source);
- return new NodeConnector(MD_SAL_TYPE,source.toADNodeConnectorId,nodeId.toADNode)
- }
-
- public static def toADNodeConnectorId(TpId nodeConnectorId) {
- return nodeConnectorId.value
- }
-
- public static def toADNode(NodeId nodeId) {
- checkNotNull(nodeId);
- return new Node(MD_SAL_TYPE,nodeId.toADNodeId);
- }
-}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.compatibility.topology;
+
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.controller.sal.topology.IPluginOutTopologyService;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+public class TopologyProvider implements AutoCloseable{
+ private static final Logger LOG = LoggerFactory.getLogger(TopologyProvider.class);
+ private static final InstanceIdentifier<Link> PATH = InstanceIdentifier.builder(NetworkTopology.class)
+ .child(Topology.class ,new TopologyKey(new TopologyId("flow:1")))
+ .child(Link.class)
+ .toInstance();
+ private TopologyCommitHandler commitHandler;
+
+ private ListenerRegistration<DataChangeListener> listenerRegistration;
+ private IPluginOutTopologyService topologyPublisher;
+ private DataProviderService dataService;
+
+ public void startAdapter() {
+ if(dataService == null){
+ LOG.error("dataService not set");
+ return;
+ }
+ commitHandler = new TopologyCommitHandler(dataService,topologyPublisher);
+ listenerRegistration = dataService.registerDataChangeListener(PATH, commitHandler);
+ LOG.info("TopologyProvider started");
+ }
+
+ @Override
+ public void close() {
+ if (listenerRegistration != null) {
+ listenerRegistration.close();
+ }
+ }
+
+ void setTopologyPublisher(final IPluginOutTopologyService topologyPublisher) {
+ this.topologyPublisher = topologyPublisher;
+ if (commitHandler != null) {
+ commitHandler.setTopologyPublisher(topologyPublisher);
+ }
+ }
+
+ public void setDataService(final DataProviderService dataService) {
+ this.dataService = Preconditions.checkNotNull(dataService);
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 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.compatibility.topology
-
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.controller.sal.topology.IPluginOutTopologyService
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link
-import org.slf4j.LoggerFactory
-import org.opendaylight.yangtools.concepts.ListenerRegistration
-import org.opendaylight.controller.sal.binding.api.data.DataChangeListener
-
-class TopologyProvider implements AutoCloseable{
- static val LOG = LoggerFactory.getLogger(TopologyProvider);
- TopologyCommitHandler commitHandler
-
- @Property
- IPluginOutTopologyService topologyPublisher;
-
- @Property
- DataProviderService dataService;
-
- ListenerRegistration<DataChangeListener> listenerRegistration
-
-
- def void start() {
-
- }
- def void startAdapter() {
- if(dataService == null){
- LOG.error("dataService not set");
- return;
- }
- commitHandler = new TopologyCommitHandler(dataService,topologyPublisher);
- val InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(NetworkTopology)
- .child(Topology,new TopologyKey(new TopologyId("flow:1")))
- .child(Link)
- .toInstance();
- listenerRegistration = dataService.registerDataChangeListener(path,commitHandler);
- LOG.info("TopologyProvider started")
- }
-
- override close() throws Exception {
- listenerRegistration.close
- }
-
- def setTopologyPublisher(IPluginOutTopologyService topologyPublisher) {
- _topologyPublisher = topologyPublisher;
- if(commitHandler != null){
- commitHandler.setTopologyPublisher(topologyPublisher);
- }
- }
-
-}
--- /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.binding.codegen;
+
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.NotificationListener;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+
+public final class RuntimeCodeSpecification {
+ public final static String DIRECT_PROXY_SUFFIX = "DirectProxy";
+ public final static String INVOKER_SUFFIX = "ListenerInvoker";
+ public final static String ROUTER_SUFFIX = "Router";
+
+ public final static String DELEGATE_FIELD = "_delegate";
+ public final static String ROUTING_TABLE_FIELD_PREFIX = "_routes_";
+
+ private RuntimeCodeSpecification() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ /**
+ * Returns a name for generated interface
+ */
+ private static String getGeneratedName(final Class<? extends Object> cls, final String suffix) {
+ return cls.getName() + "$$Broker$" + suffix;
+ }
+
+ public static String getInvokerName(final Class<? extends NotificationListener> listener) {
+ return getGeneratedName(listener, RuntimeCodeSpecification.INVOKER_SUFFIX);
+ }
+
+ /**
+ * Returns a name for DirectProxy implementation
+ */
+ public static String getDirectProxyName(final Class<? extends RpcService> base) {
+ return getGeneratedName(base, RuntimeCodeSpecification.DIRECT_PROXY_SUFFIX);
+ }
+
+ /**
+ * Returns a name for Router implementation
+ */
+ public static String getRouterName(final Class<? extends RpcService> base) {
+ return getGeneratedName(base, RuntimeCodeSpecification.ROUTER_SUFFIX);
+ }
+
+ /**
+ * Returns a field name for specified routing context
+ */
+ public static String getRoutingTableField(final Class<? extends BaseIdentity> routingContext) {
+ return "_routes_" + routingContext.getSimpleName();
+ }
+}
+++ /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.binding.codegen
-
-import org.opendaylight.yangtools.yang.binding.RpcService
-import org.opendaylight.yangtools.yang.binding.BaseIdentity
-import org.opendaylight.yangtools.yang.binding.NotificationListener
-
-/**
- *
- *
- */
-class RuntimeCodeSpecification {
-
- //public static val PACKAGE_PREFIX = "_gen.";
-
- public static val DIRECT_PROXY_SUFFIX = "DirectProxy";
- public static val ROUTER_SUFFIX = "Router";
- public static val INVOKER_SUFFIX = "ListenerInvoker";
-
- public static val DELEGATE_FIELD = "_delegate"
- public static val ROUTING_TABLE_FIELD_PREFIX = "_routes_"
-
- public static def getInvokerName(Class<? extends NotificationListener> listener) {
- getGeneratedName(listener, INVOKER_SUFFIX);
- }
-
- /**
- * Returns a name for DirectProxy implementation
- *
- *
- */
- public static def getDirectProxyName(Class<? extends RpcService> base) {
- getGeneratedName(base, DIRECT_PROXY_SUFFIX);
- }
-
- /**
- * Returns a name for Router implementation
- *
- */
- public static def getRouterName(Class<? extends RpcService> base) {
- getGeneratedName(base, ROUTER_SUFFIX);
- }
-
- /**
- * Returns a name for generated interface
- *
- */
- public static def getGeneratedName(Class<?> cls, String suffix) {
- '''«cls.name»$$Broker$«suffix»'''.toString()
- }
-
- /**
- * Returns a field name for specified routing context
- *
- */
- public static def getRoutingTableField(Class<? extends BaseIdentity> routingContext) {
- return '''_routes_«routingContext.simpleName»'''.toString;
- }
-}
* 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.binding.codegen;
import java.lang.reflect.Method;
+
import org.opendaylight.yangtools.yang.binding.Notification;
-@SuppressWarnings("all")
-public class YangtoolsMappingHelper {
- public static boolean isNotificationCallback(final Method it) {
- return it.getName().startsWith("on") && (it.getParameterTypes().length == 1) &&
- Notification.class.isAssignableFrom(it.getParameterTypes()[0]);
- }
+public final class YangtoolsMappingHelper {
+ private YangtoolsMappingHelper() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+ public static boolean isNotificationCallback(final Method it) {
+ return it.getName().startsWith("on") && (it.getParameterTypes().length == 1) &&
+ Notification.class.isAssignableFrom(it.getParameterTypes()[0]);
+ }
}
\ No newline at end of file
public static Option mdSalCoreBundles() {
return new DefaultCompositeOption( //
mavenBundle(YANGTOOLS, "concepts").versionAsInProject(), // //
+ mavenBundle(YANGTOOLS, "util").versionAsInProject(), // //
mavenBundle(YANGTOOLS, "yang-binding").versionAsInProject(), // //
mavenBundle(YANGTOOLS, "yang-common").versionAsInProject(), // //
mavenBundle(CONTROLLER, "sal-common").versionAsInProject(), // //
<packaging>bundle</packaging>
<dependencies>
+ <dependency>
+ <groupId>com.github.romix</groupId>
+ <artifactId>java-concurrent-hash-trie-map</artifactId>
+ </dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
- <dependency>
- <groupId>org.eclipse.xtend</groupId>
- <artifactId>org.eclipse.xtend.lib</artifactId>
- </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-api</artifactId>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-core-spi</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>util</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-data-impl</artifactId>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-parser-impl</artifactId>
</dependency>
+
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
org.opendaylight.yangtools.yang.util,
org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.dom.impl.rev131028.*</Private-Package>
<Import-Package>*</Import-Package>
+ <Embed-Dependency>java-concurrent-hash-trie-map;inline=true</Embed-Dependency>
</instructions>
</configuration>
</plugin>
- <plugin>
- <groupId>org.eclipse.xtend</groupId>
- <artifactId>xtend-maven-plugin</artifactId>
- </plugin>
<!-- TODO - unite yang-maven-plugin configuration in md-sal-->
<plugin>
<groupId>org.opendaylight.yangtools</groupId>
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-/**
-*
-*/
public final class SchemaServiceImplSingletonModule extends
- org.opendaylight.controller.config.yang.md.sal.dom.impl.AbstractSchemaServiceImplSingletonModule {
+org.opendaylight.controller.config.yang.md.sal.dom.impl.AbstractSchemaServiceImplSingletonModule {
private static final Logger LOG = LoggerFactory.getLogger(SchemaServiceImplSingletonModule.class);
BundleContext bundleContext;
- public SchemaServiceImplSingletonModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
- org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ public SchemaServiceImplSingletonModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+ final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
super(identifier, dependencyResolver);
}
- public SchemaServiceImplSingletonModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
- org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
- SchemaServiceImplSingletonModule oldModule, java.lang.AutoCloseable oldInstance) {
+ public SchemaServiceImplSingletonModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+ final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+ final SchemaServiceImplSingletonModule oldModule, final java.lang.AutoCloseable oldInstance) {
super(identifier, dependencyResolver, oldModule, oldInstance);
}
@Override
- public boolean canReuseInstance(AbstractSchemaServiceImplSingletonModule oldModule) {
+ public boolean canReuseInstance(final AbstractSchemaServiceImplSingletonModule oldModule) {
return true;
}
return bundleContext;
}
- public void setBundleContext(BundleContext bundleContext) {
+ public void setBundleContext(final BundleContext bundleContext) {
this.bundleContext = bundleContext;
}
return new GlobalSchemaServiceProxy(getBundleContext(), ref);
}
- GlobalBundleScanningSchemaServiceImpl newInstance = new GlobalBundleScanningSchemaServiceImpl();
- newInstance.setContext(getBundleContext());
+ GlobalBundleScanningSchemaServiceImpl newInstance = new GlobalBundleScanningSchemaServiceImpl(getBundleContext());
newInstance.start();
return newInstance;
}
private ServiceReference<SchemaService> reference;
private SchemaService delegate;
- public GlobalSchemaServiceProxy(BundleContext bundleContext, ServiceReference<SchemaService> ref) {
+ public GlobalSchemaServiceProxy(final BundleContext bundleContext, final ServiceReference<SchemaService> ref) {
this.bundleContext = bundleContext;
this.reference = ref;
this.delegate = bundleContext.getService(reference);
}
@Override
- public void addModule(Module arg0) {
+ public void addModule(final Module arg0) {
delegate.addModule(arg0);
}
}
@Override
- public ListenerRegistration<SchemaServiceListener> registerSchemaServiceListener(SchemaServiceListener arg0) {
+ public ListenerRegistration<SchemaServiceListener> registerSchemaServiceListener(final SchemaServiceListener arg0) {
return delegate.registerSchemaServiceListener(arg0);
}
@Override
- public void removeModule(Module arg0) {
+ public void removeModule(final Module arg0) {
delegate.removeModule(arg0);
}
ready = true;
LOG.debug("Store transaction: {} : Ready", getIdentifier());
- mutableTree.seal();
+ mutableTree.ready();
return store.submit(this);
}
package org.opendaylight.controller.md.sal.dom.store.impl;
import static org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.builder;
-import static org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreUtils.append;
import java.util.Collection;
import java.util.Collections;
import com.google.common.collect.Multimap;
/**
- *
* Resolve Data Change Events based on modifications and listeners
*
* Computes data change events for all affected registered listeners in data
* tree.
- *
- * Prerequisites for computation is to set all parameters properly:
- * <ul>
- * <li>{@link #setRootPath(InstanceIdentifier)} - Root path of datastore
- * <li>{@link #setListenerRoot(ListenerTree)} - Root of listener registration
- * tree, which contains listeners to be notified
- * <li>{@link #setModificationRoot(NodeModification)} - Modification root, for
- * which events should be computed
- * <li>{@link #setBeforeRoot(Optional)} - State of before modification occurred
- * <li>{@link #setAfterRoot(Optional)} - State of after modification occurred
- * </ul>
- *
*/
final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListenerNotifyTask>> {
private static final Logger LOG = LoggerFactory.getLogger(ResolveDataChangeEventsTask.class);
private final DataTreeCandidate candidate;
private final ListenerTree listenerRoot;
- public ResolveDataChangeEventsTask(DataTreeCandidate candidate, ListenerTree listenerTree) {
+ public ResolveDataChangeEventsTask(final DataTreeCandidate candidate, final ListenerTree listenerTree) {
this.candidate = Preconditions.checkNotNull(candidate);
this.listenerRoot = Preconditions.checkNotNull(listenerTree);
}
* Implementation of done as Map-Reduce with two steps: 1. resolving events
* and their mapping to listeners 2. merging events affecting same listener
*
- * @return Iterable of Notification Tasks which needs to be executed in
+ * @return An {@link Iterable} of Notification Tasks which needs to be executed in
* order to delivery data change events.
*/
@Override
for (NormalizedNode<PathArgument, ?> beforeChild : beforeCont.getValue()) {
PathArgument childId = beforeChild.getIdentifier();
alreadyProcessed.add(childId);
- InstanceIdentifier childPath = append(path, childId);
+ InstanceIdentifier childPath = path.node(childId);
Collection<ListenerTree.Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
Optional<NormalizedNode<PathArgument, ?>> afterChild = afterCont.getChild(childId);
DOMImmutableDataChangeEvent childChange = resolveNodeContainerChildUpdated(childPath, childListeners,
// and it was not present in previous loop, that means it is
// created.
Collection<ListenerTree.Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
- InstanceIdentifier childPath = append(path,childId);
+ InstanceIdentifier childPath = path.node(childId);
childChanges.add(resolveSameEventRecursivelly(childPath , childListeners, afterChild,
DOMImmutableDataChangeEvent.getCreateEventFactory()));
}
PathArgument childId = child.getIdentifier();
LOG.trace("Resolving event for child {}", childId);
Collection<Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
- eventBuilder.merge(resolveSameEventRecursivelly(append(path, childId), childListeners, child, eventFactory));
+ eventBuilder.merge(resolveSameEventRecursivelly(path.node(childId), childListeners, child, eventFactory));
}
propagateEvent = eventBuilder.build();
} else {
for (DataTreeCandidateNode childMod : modification.getChildNodes()) {
PathArgument childId = childMod.getIdentifier();
- InstanceIdentifier childPath = append(path, childId);
+ InstanceIdentifier childPath = path.node(childId);
Collection<ListenerTree.Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
switch (childMod.getModificationType()) {
}
}
- public static ResolveDataChangeEventsTask create(DataTreeCandidate candidate, ListenerTree listenerTree) {
+ public static ResolveDataChangeEventsTask create(final DataTreeCandidate candidate, final ListenerTree listenerTree) {
return new ResolveDataChangeEventsTask(candidate, listenerTree);
}
}
import com.google.common.base.Preconditions;
+/**
+ * Exception thrown when a proposed change fails validation before being
+ * applied into the datastore. This can have multiple reasons, for example
+ * the datastore has been concurrently modified such that a conflicting
+ * node is present, or the modification is structurally incorrect.
+ */
public class DataPreconditionFailedException extends Exception {
private static final long serialVersionUID = 1L;
private final InstanceIdentifier path;
+ /**
+ * Create a new instance.
+ *
+ * @param path Object path which caused this exception
+ * @param message Specific message describing the failure
+ */
public DataPreconditionFailedException(final InstanceIdentifier path, final String message) {
- super(message);
- this.path = Preconditions.checkNotNull(path);
+ this(path, message, null);
}
-
+ /**
+ * Create a new instance, initializing
+ *
+ * @param path Object path which caused this exception
+ * @param message Specific message describing the failure
+ * @param cause Exception which triggered this failure, may be null
+ */
public DataPreconditionFailedException(final InstanceIdentifier path, final String message, final Throwable cause) {
super(message, cause);
this.path = Preconditions.checkNotNull(path);
}
+ /**
+ * Returns the offending object path.
+ *
+ * @return Path of the offending object
+ */
public InstanceIdentifier getPath() {
return path;
}
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+/**
+ * An encapsulation of a validated data tree modification. This candidate
+ * is ready for atomic commit to the datastore. It allows access to before-
+ * and after-state as it will be seen in to subsequent commit. This capture
+ * can be accessed for reference, but cannot be modified and the content
+ * is limited to nodes which were affected by the modification from which
+ * this instance originated.
+ */
public interface DataTreeCandidate {
+ /**
+ * Get the candidate tree root node.
+ *
+ * @return Candidate tree root node
+ */
DataTreeCandidateNode getRootNode();
+
+ /**
+ * Get the candidate tree root path. This is the path of the root node
+ * relative to the root of InstanceIdentifier namespace.
+ *
+ * @return Relative path of the root node
+ */
InstanceIdentifier getRootPath();
}
import com.google.common.base.Optional;
+/**
+ * A single node within a {@link DataTreeCandidate}. The nodes are organized
+ * in tree hierarchy, reflecting the modification from which this candidate
+ * was created. The node itself exposes the before- and after-image of the
+ * tree restricted to the modified nodes.
+ */
public interface DataTreeCandidateNode {
+ /**
+ * Get the node identifier.
+ *
+ * @return The node identifier.
+ */
PathArgument getIdentifier();
+
+ /**
+ * Get an unmodifiable iterable of modified child nodes.
+ *
+ * @return Unmodifiable iterable of modified child nodes.
+ */
Iterable<DataTreeCandidateNode> getChildNodes();
+ /**
+ * Return the type of modification this node is undergoing.
+ *
+ * @return Node modification type.
+ */
ModificationType getModificationType();
+
+ /**
+ * Return the before-image of data corresponding to the node.
+ *
+ * @return Node data as they were present in the tree before
+ * the modification was applied.
+ */
Optional<NormalizedNode<?, ?>> getDataAfter();
+
+ /**
+ * Return the after-image of data corresponding to the node.
+ *
+ * @return Node data as they will be present in the tree after
+ * the modification is applied.
+ */
Optional<NormalizedNode<?, ?>> getDataBefore();
}
* has the ability to rebase itself to a new snapshot.
*/
public interface DataTreeModification extends DataTreeSnapshot {
- void delete(InstanceIdentifier path);
- void merge(InstanceIdentifier path, NormalizedNode<?, ?> data);
- void write(InstanceIdentifier path, NormalizedNode<?, ?> data);
- void seal();
+ /**
+ * Delete the node at specified path.
+ *
+ * @param path Node path
+ */
+ void delete(InstanceIdentifier path);
+
+ /**
+ * Merge the specified data with the currently-present data
+ * at specified path.
+ *
+ * @param path Node path
+ * @param data Data to be merged
+ */
+ void merge(InstanceIdentifier path, NormalizedNode<?, ?> data);
+
+ /**
+ * Replace the data at specified path with supplied data.
+ *
+ * @param path Node path
+ * @param data New node data
+ */
+ void write(InstanceIdentifier path, NormalizedNode<?, ?> data);
+
+ /**
+ * Finish creation of a modification, making it ready for application
+ * to the data tree. Any calls to this object's methods will result
+ * in undefined behavior, possibly with an
+ * {@link IllegalStateException} being thrown.
+ */
+ void ready();
}
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
+/**
+ * A set of listeners organized as a tree by node to which they listen. This class
+ * allows for efficient lookup of listeners when we walk the DataTreeCandidate.
+ */
public final class ListenerTree {
private static final Logger LOG = LoggerFactory.getLogger(ListenerTree.class);
private final ReadWriteLock rwLock = new ReentrantReadWriteLock(true);
private final Node rootNode = new Node(null, null);
private ListenerTree() {
-
+ // Private to disallow direct instantiation
}
+ /**
+ * Create a new empty instance of the listener tree.
+ *
+ * @return An empty instance.
+ */
public static ListenerTree create() {
return new ListenerTree();
}
}
}
+ /**
+ * Obtain a tree walking context. This context ensures a consistent view of
+ * the listener registrations. The context should be closed as soon as it
+ * is not required, because each unclosed instance blocks modification of
+ * the listener tree.
+ *
+ * @return A walker instance.
+ */
public Walker getWalker() {
/*
* TODO: The only current user of this method is local to the datastore.
return ret;
}
+ /**
+ * A walking context, pretty much equivalent to an iterator, but it
+ * exposes the undelying tree structure.
+ */
public static final class Walker implements AutoCloseable {
private final Lock lock;
private final Node node;
*/
package org.opendaylight.controller.md.sal.dom.store.impl.tree;
+/**
+ * Enumeration of all possible node modification states. These are used in
+ * data tree modification context to quickly assess what sort of modification
+ * the node is undergoing.
+ */
public enum ModificationType {
-
/**
- *
- * Node is unmodified
- *
- *
+ * Node is currently unmodified.
*/
UNMODIFIED,
+
/**
- *
- * Child of tree node was modified
- *
+ * A child node, either direct or indirect, has been modified. This means
+ * that the data representation of this node has potentially changed.
*/
SUBTREE_MODIFIED,
+
/**
- * Tree node was replaced with new value / subtree
- *
+ * This node has been placed into the tree, potentially completely replacing
+ * pre-existing contents.
*/
WRITE,
+
/**
- *
- * Tree node is to be deleted.
- *
+ * This node has been deleted along with any of its child nodes.
*/
DELETE,
/**
- *
- * Tree node is to be merged with existing one.
- *
+ * Node has been written into the tree, but instead of replacing pre-existing
+ * contents, it has been merged. This means that any incoming nodes which
+ * were present in the tree have been replaced, but their child nodes have
+ * been retained.
*/
- MERGE
+ MERGE,
}
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import com.google.common.base.Optional;
+
/**
- *
- * Tree node which contains references to it's leafs
+ * A tree node which has references to its child leaves. This are typically
+ * internal non-data leaves, such as containers, lists, etc.
*
* @param <C> Final node type
*/
public interface StoreTreeNode<C extends StoreTreeNode<C>> {
/**
- *
- * Returns direct child of the node
+ * Returns a direct child of the node
*
* @param child Identifier of child
* @return Optional with node if the child is existing, {@link Optional#absent()} otherwise.
*/
package org.opendaylight.controller.md.sal.dom.store.impl.tree;
-import java.util.Set;
-
-import org.opendaylight.yangtools.concepts.Identifiable;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
-import com.google.common.base.Function;
import com.google.common.base.Strings;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableList;
-import com.google.common.primitives.UnsignedLong;
+/**
+ * Data store tree manipulation utilities.
+ */
public final class StoreUtils {
private static final int STRINGTREE_INDENT = 4;
- private final static Function<Identifiable<Object>, Object> EXTRACT_IDENTIFIER = new Function<Identifiable<Object>, Object>() {
- @Override
- public Object apply(final Identifiable<Object> input) {
- return input.getIdentifier();
- }
- };
-
private StoreUtils() {
throw new UnsupportedOperationException("Utility class should not be instantiated");
}
- /*
- * Suppressing warnings here allows us to fool the compiler enough
- * such that we can reuse a single function for all applicable types
- * and present it in a type-safe manner to our users.
+ /**
+ * Convert a data subtree under a node into a human-readable string format.
+ *
+ * @param node Data subtree root
+ * @return String containing a human-readable form of the subtree.
*/
- @SuppressWarnings({ "unchecked", "rawtypes" })
- public static <V> Function<Identifiable<V>, V> identifierExtractor() {
- return (Function) EXTRACT_IDENTIFIER;
- }
-
- public static final UnsignedLong increase(final UnsignedLong original) {
- return original.plus(UnsignedLong.ONE);
- }
-
- public static final InstanceIdentifier append(final InstanceIdentifier parent, final PathArgument arg) {
- return new InstanceIdentifier(ImmutableList.<PathArgument> builder().addAll(parent.getPath()).add(arg).build());
- }
-
- public static <V> Set<V> toIdentifierSet(final Iterable<? extends Identifiable<V>> children) {
- return FluentIterable.from(children).transform(StoreUtils.<V> identifierExtractor()).toSet();
- }
-
public static String toStringTree(final NormalizedNode<?, ?> node) {
- StringBuilder builder = new StringBuilder();
+ final StringBuilder builder = new StringBuilder();
toStringTree(builder, node, 0);
return builder.toString();
}
import java.util.List;
import java.util.Map;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.TreeNode;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
+/**
+ * A set of utility methods for interacting with {@link TreeNode} objects.
+ */
public final class TreeNodeUtils {
private TreeNodeUtils() {
throw new UnsupportedOperationException("Utility class should not be instantiated");
* @param tree Data Tree
* @param path Path to the node
* @return Optional with node if the node is present in tree, {@link Optional#absent()} otherwise.
- *
*/
public static <T extends StoreTreeNode<T>> Optional<T> findNode(final T tree, final InstanceIdentifier path) {
Optional<T> current = Optional.<T> of(tree);
final class AlwaysFailOperation implements ModificationApplyOperation {
@Override
public Optional<TreeNode> apply(final ModifiedNode modification,
- final Optional<TreeNode> storeMeta, final Version subtreeVersion) {
+ final Optional<TreeNode> storeMeta, final Version version) {
throw new IllegalStateException("Schema Context is not available.");
}
}
@Override
- public synchronized void seal() {
+ public synchronized void ready() {
Preconditions.checkState(!sealed, "Attempted to seal an already-sealed Data Tree.");
sealed = true;
rootNode.seal();
* @param storeMeta
* Store Metadata Node on which NodeModification should be
* applied
- * @param subtreeVersion New subtree version of parent node
+ * @param version New subtree version of parent node
* @throws IllegalArgumentException
* If it is not possible to apply Operation on provided Metadata
* node
* node, {@link Optional#absent()} if {@link ModifiedNode}
* resulted in deletion of this node.
*/
- Optional<TreeNode> apply(ModifiedNode modification, Optional<TreeNode> storeMeta, Version subtreeVersion);
+ Optional<TreeNode> apply(ModifiedNode modification, Optional<TreeNode> storeMeta, Version version);
/**
*
import com.google.common.base.Optional;
+/**
+ * Internal interface representing a modification action of a particular node.
+ * It is used by the validation code to allow for a read-only view of the
+ * modification tree as we should never modify that during validation.
+ */
interface NodeModification extends Identifiable<PathArgument> {
+ /**
+ * Get the type of modification.
+ *
+ * @return Modification type.
+ */
ModificationType getType();
+
+ /**
+ * Get the original tree node to which the modification is to be applied.
+ *
+ * @return The original node, or {@link Optional#absent()} if the node is
+ * a new node.
+ */
Optional<TreeNode> getOriginal();
+
+ /**
+ * Get a read-only view of children nodes.
+ *
+ * @return Iterable of all children nodes.
+ */
Iterable<? extends NodeModification> getChildren();
}
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
+/**
+ * Internal utility class for an empty candidate. We instantiate this class
+ * for empty modifications, saving memory and processing speed. Instances
+ * of this class are explicitly recognized and processing of them is skipped.
+ */
final class NoopDataTreeCandidate extends AbstractDataTreeCandidate {
private static final DataTreeCandidateNode ROOT = new DataTreeCandidateNode() {
@Override
import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataPreconditionFailedException;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreUtils;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.DataNodeContainerModificationStrategy.ListEntryModificationStrategy;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.ValueNodeModificationStrategy.LeafSetEntryModificationStrategy;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.MutableTreeNode;
@Override
protected TreeNode applyWrite(final ModifiedNode modification,
- final Optional<TreeNode> currentMeta, final Version subtreeVersion) {
- final Version nodeVersion;
- if (currentMeta.isPresent()) {
- nodeVersion = currentMeta.get().getVersion().next();
- } else {
- nodeVersion = subtreeVersion;
- }
-
+ final Optional<TreeNode> currentMeta, final Version version) {
final NormalizedNode<?, ?> newValue = modification.getWrittenValue();
- final TreeNode newValueMeta = TreeNodeFactory.createTreeNode(newValue, nodeVersion);
+ final TreeNode newValueMeta = TreeNodeFactory.createTreeNode(newValue, version);
if (Iterables.isEmpty(modification.getChildren())) {
return newValueMeta;
* and run the common parts on it -- which end with the node being sealed.
*/
final MutableTreeNode mutable = newValueMeta.mutable();
- mutable.setSubtreeVersion(subtreeVersion);
+ mutable.setSubtreeVersion(version);
@SuppressWarnings("rawtypes")
final NormalizedNodeContainerBuilder dataBuilder = createBuilder(newValue);
- return mutateChildren(mutable, dataBuilder, nodeVersion, modification.getChildren());
+ return mutateChildren(mutable, dataBuilder, version, modification.getChildren());
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
protected TreeNode applyMerge(final ModifiedNode modification, final TreeNode currentMeta,
- final Version subtreeVersion) {
+ final Version version) {
// For Node Containers - merge is same as subtree change - we only replace children.
- return applySubtreeChange(modification, currentMeta, subtreeVersion);
+ return applySubtreeChange(modification, currentMeta, version);
}
@Override
public TreeNode applySubtreeChange(final ModifiedNode modification,
- final TreeNode currentMeta, final Version subtreeVersion) {
- // Bump subtree version to its new target
- final Version updatedSubtreeVersion = currentMeta.getSubtreeVersion().next();
-
+ final TreeNode currentMeta, final Version version) {
final MutableTreeNode newMeta = currentMeta.mutable();
- newMeta.setSubtreeVersion(updatedSubtreeVersion);
+ newMeta.setSubtreeVersion(version);
@SuppressWarnings("rawtypes")
NormalizedNodeContainerBuilder dataBuilder = createBuilder(currentMeta.getData());
- return mutateChildren(newMeta, dataBuilder, updatedSubtreeVersion, modification.getChildren());
+ return mutateChildren(newMeta, dataBuilder, version, modification.getChildren());
}
@Override
final PathArgument childId = childMod.getIdentifier();
final Optional<TreeNode> childMeta = currentMeta.getChild(childId);
- InstanceIdentifier childPath = StoreUtils.append(path, childId);
+ InstanceIdentifier childPath = path.node(childId);
resolveChildOperation(childId).checkApplicable(childPath, childMod, childMeta);
}
}
return applyOperation;
}
- public Optional<TreeNode> apply(final Optional<TreeNode> data, final Version subtreeVersion) {
- return applyOperation.apply(modification, data, subtreeVersion);
+ public Optional<TreeNode> apply(final Optional<TreeNode> data, final Version version) {
+ return applyOperation.apply(modification, data, version);
}
public static OperationWithModification from(final ModificationApplyOperation operation,
@Override
public final Optional<TreeNode> apply(final ModifiedNode modification,
- final Optional<TreeNode> currentMeta, final Version subtreeVersion) {
+ final Optional<TreeNode> currentMeta, final Version version) {
switch (modification.getType()) {
case DELETE:
Preconditions.checkArgument(currentMeta.isPresent(), "Metadata not available for modification",
modification);
return modification.storeSnapshot(Optional.of(applySubtreeChange(modification, currentMeta.get(),
- subtreeVersion)));
+ version)));
case MERGE:
if(currentMeta.isPresent()) {
- return modification.storeSnapshot(Optional.of(applyMerge(modification,currentMeta.get(),subtreeVersion)));
+ return modification.storeSnapshot(Optional.of(applyMerge(modification,currentMeta.get(), version)));
} // Fallback to write is intentional - if node is not preexisting merge is same as write
case WRITE:
- return modification.storeSnapshot(Optional.of(applyWrite(modification, currentMeta, subtreeVersion)));
+ return modification.storeSnapshot(Optional.of(applyWrite(modification, currentMeta, version)));
case UNMODIFIED:
return currentMeta;
default:
}
protected abstract TreeNode applyMerge(ModifiedNode modification,
- TreeNode currentMeta, Version subtreeVersion);
+ TreeNode currentMeta, Version version);
protected abstract TreeNode applyWrite(ModifiedNode modification,
- Optional<TreeNode> currentMeta, Version subtreeVersion);
+ Optional<TreeNode> currentMeta, Version version);
protected abstract TreeNode applySubtreeChange(ModifiedNode modification,
- TreeNode currentMeta, Version subtreeVersion);
+ TreeNode currentMeta, Version version);
protected abstract void checkSubtreeModificationApplicable(InstanceIdentifier path, final NodeModification modification,
final Optional<TreeNode> current) throws DataPreconditionFailedException;
@Override
protected TreeNode applyMerge(final ModifiedNode modification, final TreeNode currentMeta,
- final Version subtreeVersion) {
- return applyWrite(modification, Optional.of(currentMeta), subtreeVersion);
+ final Version version) {
+ return applyWrite(modification, Optional.of(currentMeta), version);
}
@Override
protected TreeNode applySubtreeChange(final ModifiedNode modification,
- final TreeNode currentMeta, final Version subtreeVersion) {
+ final TreeNode currentMeta, final Version version) {
throw new UnsupportedOperationException("UnkeyedList does not support subtree change.");
}
@Override
protected TreeNode applyWrite(final ModifiedNode modification,
- final Optional<TreeNode> currentMeta, final Version subtreeVersion) {
- return TreeNodeFactory.createTreeNode(modification.getWrittenValue(), subtreeVersion);
+ final Optional<TreeNode> currentMeta, final Version version) {
+ return TreeNodeFactory.createTreeNode(modification.getWrittenValue(), version);
}
@Override
@Override
protected TreeNode applySubtreeChange(final ModifiedNode modification,
- final TreeNode currentMeta, final Version subtreeVersion) {
+ final TreeNode currentMeta, final Version version) {
throw new UnsupportedOperationException("Node " + schema.getPath()
+ "is leaf type node. Subtree change is not allowed.");
}
@Override
protected TreeNode applyMerge(final ModifiedNode modification, final TreeNode currentMeta,
- final Version subtreeVersion) {
+ final Version version) {
// Just overwrite whatever was there
- return applyWrite(modification, null, subtreeVersion);
+ return applyWrite(modification, null, version);
}
@Override
protected TreeNode applyWrite(final ModifiedNode modification,
- final Optional<TreeNode> currentMeta, final Version subtreeVersion) {
- return TreeNodeFactory.createTreeNode(modification.getWrittenValue(), subtreeVersion);
+ final Optional<TreeNode> currentMeta, final Version version) {
+ return TreeNodeFactory.createTreeNode(modification.getWrittenValue(), version);
}
@Override
import com.google.common.base.Preconditions;
-/*
+/**
* A very basic data tree node.
*/
abstract class AbstractTreeNode implements TreeNode {
*/
package org.opendaylight.controller.md.sal.dom.store.impl.tree.spi;
-import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import org.opendaylight.yangtools.util.MapAdaptor;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
}
private static final class Mutable implements MutableTreeNode {
- private final Map<PathArgument, TreeNode> children;
private final Version version;
+ private Map<PathArgument, TreeNode> children;
private NormalizedNode<?, ?> data;
private Version subtreeVersion;
private Mutable(final ContainerNode parent) {
this.data = parent.getData();
- this.children = new HashMap<>(parent.children);
+ this.children = MapAdaptor.getDefaultInstance().takeSnapshot(parent.children);
this.subtreeVersion = parent.getSubtreeVersion();
this.version = parent.getVersion();
}
@Override
public TreeNode seal() {
- final Map<PathArgument, TreeNode> realChildren;
+ final TreeNode ret = new ContainerNode(data, version, MapAdaptor.getDefaultInstance().optimize(children), subtreeVersion);
- if (children.isEmpty()) {
- realChildren = Collections.emptyMap();
- } else {
- realChildren = children;
- }
-
- return new ContainerNode(data, version, realChildren, subtreeVersion);
+ // This forces a NPE if this class is accessed again. Better than corruption.
+ children = null;
+ return ret;
}
@Override
private static ContainerNode create(final Version version, final NormalizedNode<?, ?> data,
final Iterable<NormalizedNode<?, ?>> children) {
- final Map<PathArgument, TreeNode> map = new HashMap<>();
+ final Map<PathArgument, TreeNode> map = new HashMap<>();
for (NormalizedNode<?, ?> child : children) {
map.put(child.getIdentifier(), TreeNodeFactory.createTreeNode(child, version));
}
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+/**
+ * A mutable tree node. This is a transient view materialized from a pre-existing
+ * node. Modifications are isolated. Once this object is {@link #seal()}-ed,
+ * any interactions with it will result in undefined behavior.
+ */
public interface MutableTreeNode extends StoreTreeNode<TreeNode> {
+ /**
+ * Set the data component of the node.
+ *
+ * @param data New data component, may not be null.
+ */
void setData(NormalizedNode<?, ?> data);
+
+ /**
+ * Set the new subtree version. This is typically invoked when the user
+ * has modified some of this node's children.
+ *
+ * @param subtreeVersion New subtree version.
+ */
void setSubtreeVersion(Version subtreeVersion);
+
+ /**
+ * Add a new child node. This acts as add-or-replace operation, e.g. it
+ * succeeds even if a conflicting child is already present.
+ *
+ * @param child New child node.
+ */
void addChild(TreeNode child);
+
+ /**
+ * Remove a child node. This acts as delete-or-nothing operation, e.g. it
+ * succeeds even if the corresponding child is not present.
+ *
+ * @param id Child identificator.
+ */
void removeChild(PathArgument id);
+
+ /**
+ * Finish node modification and return a read-only view of this node. After
+ * this method is invoked, any further calls to this object's method result
+ * in undefined behavior.
+ *
+ * @return Read-only view of this node.
+ */
TreeNode seal();
}
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-/*
+/**
* A very basic data tree node. It has a version (when it was last modified),
* a subtree version (when any of its children were modified) and some read-only
* data.
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
import org.opendaylight.yangtools.yang.data.api.schema.OrderedNodeContainer;
+/**
+ * Public entrypoint for other packages. Allows instantiating a tree node
+ * with specified version.
+ */
public final class TreeNodeFactory {
private TreeNodeFactory() {
throw new UnsupportedOperationException("Utility class should not be instantiated");
import com.google.common.base.Optional;
+/**
+ * Concretization of AbstractTreeNode for leaf nodes which only contain data.
+ * Instances of this class report all children as absent, subtree version
+ * equal to this node's version and do not support mutable view.
+ */
final class ValueNode extends AbstractTreeNode {
private static final Logger LOG = LoggerFactory.getLogger(ValueNode.class);
--- /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.dom.broker;
+
+import java.util.Hashtable;
+
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.broker.impl.compat.BackwardsCompatibleDataBroker;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
+import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.core.api.data.DataProviderService;
+import org.opendaylight.controller.sal.core.api.data.DataStore;
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
+import org.opendaylight.controller.sal.core.api.mount.MountService;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProviders;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+public class BrokerConfigActivator implements AutoCloseable {
+
+ private static InstanceIdentifier ROOT = InstanceIdentifier.builder()
+ .toInstance();
+
+ private DataProviderService dataService;
+
+ private ServiceRegistration<DataBrokerService> dataReg = null;
+ private ServiceRegistration<DataProviderService> dataProviderReg = null;
+ private ServiceRegistration<MountService> mountReg = null;
+ private ServiceRegistration<MountProvisionService> mountProviderReg = null;
+ private SchemaService schemaService = null;
+ private ServiceRegistration<RpcProvisionRegistry> rpcProvisionRegistryReg = null;
+ private MountPointManagerImpl mountService = null;
+
+ private SchemaAwareDataStoreAdapter wrappedStore = null;
+
+ public void start(final BrokerImpl broker, final DataStore store,
+ final DOMDataBroker asyncBroker, final BundleContext context) {
+
+ final Hashtable<String, String> emptyProperties = new Hashtable<String, String>();
+ broker.setBundleContext(context);
+
+ final ServiceReference<SchemaService> serviceRef = context
+ .getServiceReference(SchemaService.class);
+ schemaService = context.<SchemaService> getService(serviceRef);
+
+ broker.setRouter(new SchemaAwareRpcBroker("/", SchemaContextProviders
+ .fromSchemaService(schemaService)));
+
+ if (asyncBroker == null) {
+ dataService = new DataBrokerImpl();
+ dataProviderReg = context.registerService(
+ DataProviderService.class, dataService, emptyProperties);
+
+ wrappedStore = new SchemaAwareDataStoreAdapter();
+ wrappedStore.changeDelegate(store);
+ wrappedStore.setValidationEnabled(false);
+ context.registerService(SchemaServiceListener.class, wrappedStore,
+ emptyProperties);
+
+ dataService.registerConfigurationReader(ROOT, wrappedStore);
+ dataService.registerCommitHandler(ROOT, wrappedStore);
+ dataService.registerOperationalReader(ROOT, wrappedStore);
+ } else {
+ BackwardsCompatibleDataBroker compatibleDataBroker = new BackwardsCompatibleDataBroker(
+ asyncBroker);
+ context.registerService(SchemaServiceListener.class,
+ compatibleDataBroker, emptyProperties);
+ dataService = compatibleDataBroker;
+ }
+
+ mountService = new MountPointManagerImpl();
+ dataReg = context.registerService(DataBrokerService.class, dataService,
+ emptyProperties);
+ mountReg = context.registerService(MountService.class, mountService,
+ emptyProperties);
+ mountProviderReg = context.registerService(MountProvisionService.class,
+ mountService, emptyProperties);
+
+ rpcProvisionRegistryReg = context
+ .registerService(RpcProvisionRegistry.class,
+ broker.getRouter(), emptyProperties);
+ }
+
+ @Override
+ public void close() {
+
+ if (dataReg != null) {
+ dataReg.unregister();
+ dataReg = null;
+ }
+ if (dataProviderReg != null) {
+ dataProviderReg.unregister();
+ dataProviderReg = null;
+ }
+ if (mountReg != null) {
+ mountReg.unregister();
+ mountReg = null;
+ }
+ if (mountProviderReg != null) {
+ mountProviderReg.unregister();
+ mountProviderReg = null;
+ }
+ if (rpcProvisionRegistryReg != null) {
+ rpcProvisionRegistryReg.unregister();
+ rpcProvisionRegistryReg = null;
+ }
+ }
+
+ /**
+ * @return the dataService
+ */
+ public DataProviderService getDataService() {
+ return dataService;
+ }
+
+ /**
+ * @param dataService
+ * the dataService to set
+ */
+ public void setDataService(final DataProviderService dataService) {
+ this.dataService = dataService;
+ }
+}
+++ /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.dom.broker
-
-import java.util.Hashtable
-import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker
-import org.opendaylight.controller.md.sal.dom.broker.impl.compat.BackwardsCompatibleDataBroker
-import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry
-import org.opendaylight.controller.sal.core.api.data.DataBrokerService
-import org.opendaylight.controller.sal.core.api.data.DataProviderService
-import org.opendaylight.controller.sal.core.api.data.DataStore
-import org.opendaylight.controller.sal.core.api.model.SchemaService
-import org.opendaylight.controller.sal.core.api.mount.MountProvisionService
-import org.opendaylight.controller.sal.core.api.mount.MountService
-import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter
-import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker
-import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProviders
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
-import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener
-import org.osgi.framework.BundleContext
-import org.osgi.framework.ServiceRegistration
-
-class BrokerConfigActivator implements AutoCloseable {
-
- private static val ROOT = InstanceIdentifier.builder().toInstance();
-
- @Property
- private var DataProviderService dataService;
-
- private var ServiceRegistration<DataBrokerService> dataReg;
- private var ServiceRegistration<DataProviderService> dataProviderReg;
- private var ServiceRegistration<MountService> mountReg;
- private var ServiceRegistration<MountProvisionService> mountProviderReg;
- private var SchemaService schemaService;
- private var ServiceRegistration<RpcProvisionRegistry> rpcProvisionRegistryReg;
- private var MountPointManagerImpl mountService;
-
- SchemaAwareDataStoreAdapter wrappedStore
-
- public def void start(BrokerImpl broker, DataStore store, DOMDataBroker asyncBroker,BundleContext context) {
- val emptyProperties = new Hashtable<String, String>();
- broker.setBundleContext(context);
-
- val serviceRef = context.getServiceReference(SchemaService);
- schemaService = context.getService(serviceRef);
-
- broker.setRouter(new SchemaAwareRpcBroker("/", SchemaContextProviders.fromSchemaService(schemaService)));
-
-
- if(asyncBroker == null) {
- dataService = new DataBrokerImpl();
- dataProviderReg = context.registerService(DataProviderService, dataService, emptyProperties);
-
- wrappedStore = new SchemaAwareDataStoreAdapter();
- wrappedStore.changeDelegate(store);
- wrappedStore.setValidationEnabled(false);
- context.registerService(SchemaServiceListener, wrappedStore, emptyProperties)
-
- dataService.registerConfigurationReader(ROOT, wrappedStore);
- dataService.registerCommitHandler(ROOT, wrappedStore);
- dataService.registerOperationalReader(ROOT, wrappedStore);
- } else {
- val compatibleDataBroker = new BackwardsCompatibleDataBroker(asyncBroker);
- context.registerService(SchemaServiceListener,compatibleDataBroker,emptyProperties);
- dataService = compatibleDataBroker;
- }
-
-
-//
-
- mountService = new MountPointManagerImpl();
- dataReg = context.registerService(DataBrokerService, dataService, emptyProperties);
- mountReg = context.registerService(MountService, mountService, emptyProperties);
- mountProviderReg = context.registerService(MountProvisionService, mountService, emptyProperties);
-
- rpcProvisionRegistryReg = context.registerService(RpcProvisionRegistry, broker.getRouter(), emptyProperties);
- }
-
- override def close() {
- dataReg?.unregister();
- dataProviderReg?.unregister();
- mountReg?.unregister();
- mountProviderReg?.unregister();
- rpcProvisionRegistryReg?.unregister();
- }
-
-}
--- /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.dom.broker;
+
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.controller.sal.core.api.Consumer;
+import org.opendaylight.controller.sal.core.api.Provider;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+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;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.opendaylight.controller.sal.dom.broker.spi.RpcRouter;
+import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.RpcRoutingContext;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation;
+
+public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable {
+ private final static Logger log = LoggerFactory.getLogger(BrokerImpl.class);
+
+ // Broker Generic Context
+ private final Set<ConsumerContextImpl> sessions = Collections
+ .synchronizedSet(new HashSet<ConsumerContextImpl>());
+ private final Set<ProviderContextImpl> providerSessions = Collections
+ .synchronizedSet(new HashSet<ProviderContextImpl>());
+
+ private BundleContext bundleContext = null;
+
+ private AutoCloseable deactivator = null;
+
+ private RpcRouter router = null;
+
+ @Override
+ public ConsumerSession registerConsumer(final Consumer consumer,
+ final BundleContext ctx) {
+ checkPredicates(consumer);
+ log.trace("Registering consumer {}", consumer);
+ final ConsumerContextImpl session = newSessionFor(consumer, ctx);
+ consumer.onSessionInitiated(session);
+ sessions.add(session);
+ return session;
+ }
+
+ @Override
+ public ProviderSession registerProvider(final Provider provider,
+ final BundleContext ctx) {
+ checkPredicates(provider);
+ final ProviderContextImpl session = newSessionFor(provider, ctx);
+ provider.onSessionInitiated(session);
+ providerSessions.add(session);
+ return session;
+ }
+
+ protected Future<RpcResult<CompositeNode>> invokeRpcAsync(final QName rpc,
+ final CompositeNode input) {
+ return router.invokeRpc(rpc, input);
+ }
+
+ // Validation
+ private void checkPredicates(final Provider prov) {
+ Preconditions.checkNotNull(prov, "Provider should not be null.");
+ for (ProviderContextImpl session : providerSessions) {
+ if (prov.equals(session.getProvider()))
+ throw new IllegalStateException("Provider already registered");
+ }
+
+ }
+
+ private void checkPredicates(final Consumer cons) {
+ Preconditions.checkNotNull(cons, "Consumer should not be null.");
+ for (ConsumerContextImpl session : sessions) {
+ if (cons.equals(session.getConsumer()))
+ throw new IllegalStateException("Consumer already registered");
+ }
+ }
+
+ // Private Factory methods
+ private ConsumerContextImpl newSessionFor(final Consumer provider,
+ final BundleContext ctx) {
+ ConsumerContextImpl ret = new ConsumerContextImpl(provider, ctx);
+ ret.setBroker(this);
+ return ret;
+ }
+
+ private ProviderContextImpl newSessionFor(final Provider provider,
+ final BundleContext ctx) {
+ ProviderContextImpl ret = new ProviderContextImpl(provider, ctx);
+ ret.setBroker(this);
+ return ret;
+ }
+
+ protected void consumerSessionClosed(
+ final ConsumerContextImpl consumerContextImpl) {
+ sessions.remove(consumerContextImpl);
+ providerSessions.remove(consumerContextImpl);
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (deactivator != null) {
+ deactivator.close();
+ deactivator = null;
+ }
+ }
+
+ @Override
+ public RpcRegistration addRpcImplementation(final QName rpcType,
+ final RpcImplementation implementation)
+ throws IllegalArgumentException {
+ return router.addRpcImplementation(rpcType, implementation);
+ }
+
+ @Override
+ public RoutedRpcRegistration addRoutedRpcImplementation(
+ final QName rpcType, final RpcImplementation implementation) {
+ return router.addRoutedRpcImplementation(rpcType, implementation);
+ }
+
+ @Override
+ public void setRoutedRpcDefaultDelegate(
+ final RoutedRpcDefaultImplementation defaultImplementation) {
+ router.setRoutedRpcDefaultDelegate(defaultImplementation);
+ }
+
+ @Override
+ public ListenerRegistration<RpcRegistrationListener> addRpcRegistrationListener(
+ final RpcRegistrationListener listener) {
+ return router.addRpcRegistrationListener(listener);
+ }
+
+ @Override
+ public <L extends RouteChangeListener<RpcRoutingContext, InstanceIdentifier>> ListenerRegistration<L> registerRouteChangeListener(
+ final L listener) {
+ return router.registerRouteChangeListener(listener);
+ }
+
+ @Override
+ public Set<QName> getSupportedRpcs() {
+ return router.getSupportedRpcs();
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(
+ final QName rpc, final CompositeNode input) {
+ return router.invokeRpc(rpc, input);
+ }
+
+ /**
+ * @return the bundleContext
+ */
+ public BundleContext getBundleContext() {
+ return bundleContext;
+ }
+
+ /**
+ * @param bundleContext
+ * the bundleContext to set
+ */
+ public void setBundleContext(final BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ /**
+ * @return the deactivator
+ */
+ public AutoCloseable getDeactivator() {
+ return deactivator;
+ }
+
+ /**
+ * @param deactivator
+ * the deactivator to set
+ */
+ public void setDeactivator(final AutoCloseable deactivator) {
+ this.deactivator = deactivator;
+ }
+
+ /**
+ * @return the router
+ */
+ public RpcRouter getRouter() {
+ return router;
+ }
+
+ /**
+ * @param router
+ * the router to set
+ */
+ public void setRouter(final RpcRouter router) {
+ this.router = router;
+ }
+}
+++ /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.dom.broker;
-
-import com.google.common.util.concurrent.ListenableFuture
-import java.util.Collections
-import java.util.HashSet
-import java.util.Set
-import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener
-import org.opendaylight.controller.sal.core.api.Broker
-import org.opendaylight.controller.sal.core.api.Consumer
-import org.opendaylight.controller.sal.core.api.Provider
-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
-import org.slf4j.LoggerFactory
-import org.opendaylight.controller.sal.dom.broker.spi.RpcRouter
-import org.opendaylight.controller.sal.core.api.RpcRegistrationListener
-import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry
-import org.opendaylight.controller.sal.core.api.RpcImplementation
-import org.opendaylight.controller.sal.core.api.RpcRoutingContext
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
-import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation
-
-public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable {
- private static val log = LoggerFactory.getLogger(BrokerImpl);
-
- // Broker Generic Context
- private val Set<ConsumerContextImpl> sessions = Collections.synchronizedSet(new HashSet<ConsumerContextImpl>());
- private val Set<ProviderContextImpl> providerSessions = Collections.synchronizedSet(
- new HashSet<ProviderContextImpl>());
-
- @Property
- private var BundleContext bundleContext;
-
- @Property
- private var AutoCloseable deactivator;
-
- @Property
- private var RpcRouter router;
-
- override registerConsumer(Consumer consumer, BundleContext ctx) {
- checkPredicates(consumer);
- log.trace("Registering consumer " + consumer);
- val session = newSessionFor(consumer, ctx);
- consumer.onSessionInitiated(session);
- sessions.add(session);
- return session;
- }
-
- override registerProvider(Provider provider, BundleContext ctx) {
- checkPredicates(provider);
-
- val session = newSessionFor(provider, ctx);
- provider.onSessionInitiated(session);
- providerSessions.add(session);
- return session;
- }
-
- protected def ListenableFuture<RpcResult<CompositeNode>> invokeRpcAsync(QName rpc, CompositeNode input) {
- return router.invokeRpc(rpc, input);
- }
-
- // Validation
- private def void checkPredicates(Provider prov) {
- if (prov == null)
- throw new IllegalArgumentException("Provider should not be null.");
- for (ProviderContextImpl session : providerSessions) {
- if (prov.equals(session.getProvider()))
- throw new IllegalStateException("Provider already registered");
- }
-
- }
-
- private def void checkPredicates(Consumer cons) {
- if (cons == null)
- throw new IllegalArgumentException("Consumer should not be null.");
- for (ConsumerContextImpl session : sessions) {
- if (cons.equals(session.getConsumer()))
- throw new IllegalStateException("Consumer already registered");
- }
- }
-
- // Private Factory methods
- private def ConsumerContextImpl newSessionFor(Consumer provider, BundleContext ctx) {
- val ret = new ConsumerContextImpl(provider, ctx);
- ret.broker = this;
- return ret;
- }
-
- private def ProviderContextImpl newSessionFor(Provider provider, BundleContext ctx) {
- val ret = new ProviderContextImpl(provider, ctx);
- ret.broker = this;
- return ret;
- }
-
- protected def void consumerSessionClosed(ConsumerContextImpl consumerContextImpl) {
- sessions.remove(consumerContextImpl);
- providerSessions.remove(consumerContextImpl);
- }
-
- override close() throws Exception {
- deactivator?.close();
- }
-
- override addRpcImplementation(QName rpcType, RpcImplementation implementation) throws IllegalArgumentException {
- router.addRpcImplementation(rpcType,implementation);
- }
-
- override addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) {
- router.addRoutedRpcImplementation(rpcType,implementation);
- }
-
- override setRoutedRpcDefaultDelegate(RoutedRpcDefaultImplementation defaultImplementation) {
- router.setRoutedRpcDefaultDelegate(defaultImplementation);
- }
-
- override addRpcRegistrationListener(RpcRegistrationListener listener) {
- return router.addRpcRegistrationListener(listener);
- }
-
- override <L extends RouteChangeListener<RpcRoutingContext, InstanceIdentifier>> registerRouteChangeListener(L listener) {
- return router.registerRouteChangeListener(listener);
- }
-
- override getSupportedRpcs() {
- return router.getSupportedRpcs();
- }
-
- override invokeRpc(QName rpc, CompositeNode input) {
- return router.invokeRpc(rpc,input)
- }
-
-}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.dom.broker;
+
+import java.util.Collection;
+import java.util.concurrent.Future;
+
+import javax.annotation.concurrent.GuardedBy;
+
+import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
+import org.opendaylight.controller.sal.core.api.BrokerService;
+import org.opendaylight.controller.sal.core.api.Consumer;
+import org.opendaylight.controller.sal.dom.broker.osgi.AbstractBrokerServiceProxy;
+import org.opendaylight.controller.sal.dom.broker.osgi.ProxyFactory;
+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;
+import org.osgi.framework.ServiceReference;
+
+import com.google.common.collect.ClassToInstanceMap;
+import com.google.common.collect.MutableClassToInstanceMap;
+
+class ConsumerContextImpl implements ConsumerSession {
+
+ private final ClassToInstanceMap<BrokerService> instantiatedServices = MutableClassToInstanceMap
+ .create();
+ private final BundleContext context;
+ private final Consumer consumer;
+
+ private BrokerImpl broker = null;
+ @GuardedBy("this")
+ private boolean closed = false;
+
+ public ConsumerContextImpl(final Consumer consumer, final BundleContext ctx) {
+ this.consumer = consumer;
+ this.context = ctx;
+ }
+
+ @Override
+ public Future<RpcResult<CompositeNode>> rpc(final QName rpc,
+ final CompositeNode input) {
+ return broker.invokeRpcAsync(rpc, input);
+ }
+
+ @Override
+ public <T extends BrokerService> T getService(final Class<T> service) {
+ final T localProxy = instantiatedServices.getInstance(service);
+ if (localProxy != null) {
+ return localProxy;
+ }
+ final ServiceReference<T> serviceRef = context
+ .getServiceReference(service);
+ if (serviceRef == null) {
+ return null;
+ }
+ final T serviceImpl = context.getService(serviceRef);
+ final T ret = ProxyFactory.createProxy(serviceRef, serviceImpl);
+ if (ret != null) {
+ instantiatedServices.putInstance(service, ret);
+ }
+ return ret;
+ }
+
+ @Override
+ public void close() {
+ synchronized (this) {
+ if (closed) {
+ return;
+ }
+ this.closed = true;
+ }
+
+ Collection<BrokerService> toStop = instantiatedServices.values();
+ for (BrokerService brokerService : toStop) {
+ if (brokerService instanceof AbstractBrokerServiceProxy<?>) {
+ ((AbstractBrokerServiceProxy<?>) brokerService).close();
+ }
+ }
+ broker.consumerSessionClosed(this);
+ }
+
+ @Override
+ public synchronized boolean isClosed() {
+ return closed;
+ }
+
+ /**
+ * @return the broker
+ */
+ public BrokerImpl getBroker() {
+ return broker;
+ }
+
+ /**
+ * @param broker
+ * the broker to set
+ */
+ public void setBroker(final BrokerImpl broker) {
+ this.broker = broker;
+ }
+
+ /**
+ * @return the _consumer
+ */
+ public Consumer getConsumer() {
+ return consumer;
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 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.dom.broker
-
-import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession
-import org.opendaylight.controller.sal.core.api.BrokerService
-import org.opendaylight.controller.sal.core.api.Consumer
-import org.osgi.framework.BundleContext
-import org.opendaylight.yangtools.yang.common.QName
-import org.opendaylight.yangtools.yang.data.api.CompositeNode
-import org.opendaylight.controller.sal.dom.broker.osgi.AbstractBrokerServiceProxy
-import com.google.common.collect.ClassToInstanceMap
-import com.google.common.collect.MutableClassToInstanceMap
-import org.opendaylight.controller.sal.dom.broker.osgi.ProxyFactory
-
-class ConsumerContextImpl implements ConsumerSession {
-
- @Property
- private val Consumer consumer;
-
- @Property
- private var BrokerImpl broker;
-
- private val ClassToInstanceMap<BrokerService> instantiatedServices = MutableClassToInstanceMap.create();
- private boolean closed = false;
-
- private BundleContext context;
-
- public new(Consumer consumer, BundleContext ctx) {
- this._consumer = consumer;
- this.context = ctx;
- }
-
- override rpc(QName rpc, CompositeNode input) {
- return broker.invokeRpcAsync(rpc, input);
- }
-
- override <T extends BrokerService> T getService(Class<T> service) {
- val localProxy = instantiatedServices.getInstance(service);
- if(localProxy != null) {
- return localProxy;
- }
- val serviceRef = context.getServiceReference(service);
- if(serviceRef == null) {
- return null;
- }
- val serviceImpl = context.getService(serviceRef);
-
-
- val ret = ProxyFactory.createProxy(serviceRef,serviceImpl);
- if(ret != null) {
- instantiatedServices.putInstance(service, ret);
- }
- return ret;
- }
-
- override close() {
- val toStop = instantiatedServices.values();
- this.closed = true;
- for (BrokerService brokerService : toStop) {
- if(brokerService instanceof AbstractBrokerServiceProxy<?>) {
- (brokerService as AutoCloseable).close();
- }
- }
- broker.consumerSessionClosed(this);
- }
-
- override isClosed() {
- return closed;
- }
-}
import static com.google.common.base.Preconditions.checkState;
import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.Enumeration;
+import java.util.List;
import org.opendaylight.controller.sal.core.api.model.SchemaService;
import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider;
import org.slf4j.LoggerFactory;
import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSet.Builder;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
-public class GlobalBundleScanningSchemaServiceImpl implements //
- SchemaContextProvider, //
- SchemaService, //
- ServiceTrackerCustomizer<SchemaServiceListener, SchemaServiceListener>, //
- AutoCloseable {
- private static final Logger logger = LoggerFactory.getLogger(GlobalBundleScanningSchemaServiceImpl.class);
-
- private ListenerRegistry<SchemaServiceListener> listeners;
-
- private BundleContext context;
- private final BundleScanner scanner = new BundleScanner();
-
- private BundleTracker<ImmutableSet<Registration<URL>>> bundleTracker;
+public class GlobalBundleScanningSchemaServiceImpl implements SchemaContextProvider, SchemaService, ServiceTrackerCustomizer<SchemaServiceListener, SchemaServiceListener>, AutoCloseable {
+ private static final Logger LOG = LoggerFactory.getLogger(GlobalBundleScanningSchemaServiceImpl.class);
+ private final ListenerRegistry<SchemaServiceListener> listeners = new ListenerRegistry<>();
private final URLSchemaContextResolver contextResolver = new URLSchemaContextResolver();
+ private final BundleScanner scanner = new BundleScanner();
+ private final BundleContext context;
private ServiceTracker<SchemaServiceListener, SchemaServiceListener> listenerTracker;
-
+ private BundleTracker<Iterable<Registration<URL>>> bundleTracker;
private boolean starting = true;
- public ListenerRegistry<SchemaServiceListener> getListeners() {
- return listeners;
- }
-
- public void setListeners(final ListenerRegistry<SchemaServiceListener> listeners) {
- this.listeners = listeners;
+ public GlobalBundleScanningSchemaServiceImpl(final BundleContext context) {
+ this.context = Preconditions.checkNotNull(context);
}
public BundleContext getContext() {
return context;
}
- public void setContext(final BundleContext context) {
- this.context = context;
- }
-
public void start() {
checkState(context != null);
- if (listeners == null) {
- listeners = new ListenerRegistry<>();
- }
listenerTracker = new ServiceTracker<>(context, SchemaServiceListener.class, GlobalBundleScanningSchemaServiceImpl.this);
- bundleTracker = new BundleTracker<ImmutableSet<Registration<URL>>>(context, BundleEvent.RESOLVED
- | BundleEvent.UNRESOLVED, scanner);
+ bundleTracker = new BundleTracker<>(context, BundleEvent.RESOLVED | BundleEvent.UNRESOLVED, scanner);
bundleTracker.open();
listenerTracker.open();
starting = false;
try {
listener.getInstance().onGlobalContextUpdated(snapshot);
} catch (Exception e) {
- logger.error("Exception occured during invoking listener", e);
+ LOG.error("Exception occured during invoking listener", e);
}
}
if (services != null) {
try {
listener.onGlobalContextUpdated(snapshot);
} catch (Exception e) {
- logger.error("Exception occured during invoking listener", e);
+ LOG.error("Exception occured during invoking listener {}", listener, e);
}
}
}
}
- private class BundleScanner implements BundleTrackerCustomizer<ImmutableSet<Registration<URL>>> {
+ private class BundleScanner implements BundleTrackerCustomizer<Iterable<Registration<URL>>> {
@Override
- public ImmutableSet<Registration<URL>> addingBundle(final Bundle bundle, final BundleEvent event) {
+ public Iterable<Registration<URL>> addingBundle(final Bundle bundle, final BundleEvent event) {
if (bundle.getBundleId() == 0) {
- return ImmutableSet.of();
+ return Collections.emptyList();
}
- Enumeration<URL> enumeration = bundle.findEntries("META-INF/yang", "*.yang", false);
- Builder<Registration<URL>> builder = ImmutableSet.<Registration<URL>> builder();
- while (enumeration != null && enumeration.hasMoreElements()) {
- Registration<URL> reg = contextResolver.registerSource(enumeration.nextElement());
- builder.add(reg);
+ final Enumeration<URL> enumeration = bundle.findEntries("META-INF/yang", "*.yang", false);
+ if (enumeration == null) {
+ return Collections.emptyList();
}
- ImmutableSet<Registration<URL>> urls = builder.build();
- if(urls.isEmpty()) {
- return urls;
+
+ final List<Registration<URL>> urls = new ArrayList<>();
+ while (enumeration.hasMoreElements()) {
+ final URL u = enumeration.nextElement();
+ try {
+ urls.add(contextResolver.registerSource(u));
+ LOG.debug("Registered {}", u);
+ } catch (Exception e) {
+ LOG.warn("Failed to register {}, ignoring it", e);
+ }
}
- tryToUpdateSchemaContext();
- return urls;
+
+ if (!urls.isEmpty()) {
+ LOG.debug("Loaded {} new URLs, rebuilding schema context", urls.size());
+ tryToUpdateSchemaContext();
+ }
+
+ return ImmutableList.copyOf(urls);
}
@Override
- public void modifiedBundle(final Bundle bundle, final BundleEvent event, final ImmutableSet<Registration<URL>> object) {
- logger.debug("Modified bundle {} {} {}", bundle, event, object);
+ public void modifiedBundle(final Bundle bundle, final BundleEvent event, final Iterable<Registration<URL>> object) {
+ LOG.debug("Modified bundle {} {} {}", bundle, event, object);
}
/**
*/
@Override
- public synchronized void removedBundle(final Bundle bundle, final BundleEvent event, final ImmutableSet<Registration<URL>> urls) {
+ public synchronized void removedBundle(final Bundle bundle, final BundleEvent event, final Iterable<Registration<URL>> urls) {
for (Registration<URL> url : urls) {
try {
url.close();
} catch (Exception e) {
- e.printStackTrace();
+ LOG.warn("Failed do unregister URL {}, proceeding", url, e);
}
}
tryToUpdateSchemaContext();
}
public synchronized void tryToUpdateSchemaContext() {
- if(starting ) {
+ if (starting) {
return;
}
Optional<SchemaContext> schema = contextResolver.tryToUpdateSchemaContext();
--- /dev/null
+/**
+ * Copyright (c) 2014 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.dom.broker;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.opendaylight.controller.sal.core.api.data.DataProviderService;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+public class MountPointManagerImpl implements MountProvisionService {
+
+ private final ListenerRegistry<MountProvisionListener> listeners =
+ ListenerRegistry.create();
+ private final ConcurrentMap<InstanceIdentifier, MountPointImpl> mounts =
+ new ConcurrentHashMap<>();
+ private DataProviderService dataBroker = null;
+
+ @Override
+ public MountProvisionInstance createMountPoint(final InstanceIdentifier path) {
+ checkState(!mounts.containsKey(path), "Mount already created");
+ final MountPointImpl mount = new MountPointImpl(path);
+ registerMountPoint(mount);
+ mounts.put(path, mount);
+ notifyMountCreated(path);
+ return mount;
+ }
+
+ public void notifyMountCreated(final InstanceIdentifier identifier) {
+ for (final ListenerRegistration<MountProvisionListener> listener : listeners
+ .getListeners()) {
+ listener.getInstance().onMountPointCreated(identifier);
+ }
+ }
+
+ public Object registerMountPoint(final MountPointImpl impl) {
+ // FIXME: Why is thie commented out? Either we need it or we don't
+ // dataBroker?.registerConfigurationReader(impl.mountPath,impl.readWrapper);
+ // dataBroker?.registerOperationalReader(impl.mountPath,impl.readWrapper);
+ return null;
+ }
+
+ @Override
+ public MountProvisionInstance createOrGetMountPoint(
+ final InstanceIdentifier path) {
+ final MountPointImpl mount = mounts.get(path);
+ if (mount == null) {
+ return createMountPoint(path);
+ }
+ return mount;
+ }
+
+ @Override
+ public MountProvisionInstance getMountPoint(final InstanceIdentifier path) {
+ return mounts.get(path);
+ }
+
+ /**
+ * @return the dataBroker
+ */
+ public DataProviderService getDataBroker() {
+ return dataBroker;
+ }
+
+ /**
+ * @param dataBroker
+ * the dataBroker to set
+ */
+ public void setDataBroker(final DataProviderService dataBroker) {
+ this.dataBroker = dataBroker;
+ }
+
+ @Override
+ public ListenerRegistration<MountProvisionListener> registerProvisionListener(
+ final MountProvisionListener listener) {
+ return listeners.register(listener);
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 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.dom.broker
-
-
-import org.opendaylight.controller.sal.core.api.mount.MountProvisionService
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
-import java.util.concurrent.ConcurrentMap
-import java.util.concurrent.ConcurrentHashMap
-import static com.google.common.base.Preconditions.*;
-import org.opendaylight.controller.sal.core.api.data.DataProviderService
-import org.opendaylight.controller.sal.core.api.mount.MountProvisionService.MountProvisionListener
-import org.opendaylight.yangtools.concepts.util.ListenerRegistry
-
-class MountPointManagerImpl implements MountProvisionService {
-
- @Property
- DataProviderService dataBroker;
-
- val ListenerRegistry<MountProvisionListener> listeners = ListenerRegistry.create()
-
- ConcurrentMap<InstanceIdentifier,MountPointImpl> mounts = new ConcurrentHashMap();
-
- override createMountPoint(InstanceIdentifier path) {
- checkState(!mounts.containsKey(path),"Mount already created");
- val mount = new MountPointImpl(path);
- registerMountPoint(mount);
- mounts.put(path,mount);
- notifyMountCreated(path);
- return mount;
- }
-
- def notifyMountCreated(InstanceIdentifier identifier) {
- for(listener : listeners) {
- listener.instance.onMountPointCreated(identifier);
- }
- }
-
- def registerMountPoint(MountPointImpl impl) {
- //dataBroker?.registerConfigurationReader(impl.mountPath,impl.readWrapper);
- //dataBroker?.registerOperationalReader(impl.mountPath,impl.readWrapper);
- }
-
- override registerProvisionListener(MountProvisionListener listener) {
- listeners.register(listener)
- }
-
-
- override createOrGetMountPoint(InstanceIdentifier path) {
- val mount = mounts.get(path);
- if(mount === null) {
- return createMountPoint(path)
- }
- return mount;
- }
-
-
- override getMountPoint(InstanceIdentifier path) {
- mounts.get(path);
- }
-}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.dom.broker;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
+import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
+import org.opendaylight.controller.sal.core.api.Provider;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.osgi.framework.BundleContext;
+
+class ProviderContextImpl extends ConsumerContextImpl implements ProviderSession {
+ private final Set<RpcRegistrationWrapper> registrations = new HashSet<>();
+ private final Provider provider;
+
+ public ProviderContextImpl(final Provider provider, final BundleContext ctx) {
+ super(null, ctx);
+ this.provider = provider;
+ }
+
+ @Override
+ public RpcRegistrationWrapper addRpcImplementation(final QName rpcType,
+ final RpcImplementation implementation) throws IllegalArgumentException {
+ final RpcRegistration origReg = getBroker().getRouter()
+ .addRpcImplementation(rpcType, implementation);
+ final RpcRegistrationWrapper newReg = new RpcRegistrationWrapper(
+ origReg);
+ registrations.add(newReg);
+ return newReg;
+ }
+
+ protected boolean removeRpcImplementation(final RpcRegistrationWrapper implToRemove) {
+ return registrations.remove(implToRemove);
+ }
+
+ @Override
+ public void close() {
+ for (final RpcRegistrationWrapper reg : registrations) {
+ reg.close();
+ }
+ }
+
+ @Override
+ public RoutedRpcRegistration addMountedRpcImplementation(
+ final QName rpcType, final RpcImplementation implementation) {
+ throw new UnsupportedOperationException(
+ "TODO: auto-generated method stub");
+ }
+
+ @Override
+ public RoutedRpcRegistration addRoutedRpcImplementation(
+ final QName rpcType, final RpcImplementation implementation) {
+ throw new UnsupportedOperationException(
+ "TODO: auto-generated method stub");
+ }
+
+ @Override
+ public Set<QName> getSupportedRpcs() {
+ return getBroker().getRouter().getSupportedRpcs();
+ }
+
+ @Override
+ public ListenerRegistration<RpcRegistrationListener> addRpcRegistrationListener(
+ final RpcRegistrationListener listener) {
+ return getBroker().getRouter().addRpcRegistrationListener(listener);
+ }
+
+ /**
+ * @return the provider
+ */
+ public Provider getProvider() {
+ return provider;
+ }
+
+ /**
+ * @param provider
+ * the provider to set
+ */
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 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.dom.broker
-
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession
-import org.opendaylight.controller.sal.core.api.Provider
-import org.opendaylight.controller.sal.core.api.RpcImplementation
-import org.opendaylight.yangtools.yang.common.QName
-import org.osgi.framework.BundleContext
-import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration
-import org.opendaylight.controller.sal.core.api.RpcRegistrationListener
-import org.opendaylight.yangtools.concepts.Registration
-
-import java.util.Set
-import java.util.HashSet
-
-class ProviderContextImpl extends ConsumerContextImpl implements ProviderSession {
-
- @Property
- private val Provider provider;
-
- private val Set<Registration<?>> registrations = new HashSet();
-
- new(Provider provider, BundleContext ctx) {
- super(null, ctx);
- this._provider = provider;
- }
-
- override addRpcImplementation(QName rpcType, RpcImplementation implementation) throws IllegalArgumentException {
- val origReg = broker.router.addRpcImplementation(rpcType, implementation);
- val newReg = new RpcRegistrationWrapper(origReg);
- registrations.add(newReg);
- return newReg;
- }
-
- protected def removeRpcImplementation(RpcRegistrationWrapper implToRemove) throws IllegalArgumentException {
- registrations.remove(implToRemove);
- }
-
- override close() {
-
- for (reg : registrations) {
- reg.close()
- }
- super.close
- }
-
- override addMountedRpcImplementation(QName rpcType, RpcImplementation implementation) {
- throw new UnsupportedOperationException("TODO: auto-generated method stub")
- }
-
- override addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) {
- throw new UnsupportedOperationException("TODO: auto-generated method stub")
- }
-
- override getSupportedRpcs() {
- broker.router.supportedRpcs;
- }
-
- override addRpcRegistrationListener(RpcRegistrationListener listener) {
- broker.router.addRpcRegistrationListener(listener);
- }
-}
-
-class RpcRegistrationWrapper implements RpcRegistration {
-
-
- @Property
- val RpcRegistration delegate
-
- new(RpcRegistration delegate) {
- _delegate = delegate
- }
-
- override getInstance() {
- delegate.instance
- }
-
- override close() {
- delegate.close
- }
-
- override getType() {
- delegate.type
- }
-}
-
--- /dev/null
+/**
+ * Copyright (c) 2014 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.dom.broker;
+
+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 com.google.common.base.Preconditions;
+
+public class RpcRegistrationWrapper implements RpcRegistration {
+
+ private final RpcRegistration delegate;
+
+ public RpcRegistrationWrapper(final RpcRegistration delegate) {
+ this.delegate = Preconditions.checkNotNull(delegate);
+ }
+
+ @Override
+ public RpcImplementation getInstance() {
+ return delegate.getInstance();
+ }
+
+ @Override
+ public void close() {
+ delegate.close();
+ }
+
+ @Override
+ public QName getType() {
+ return delegate.getType();
+ }
+
+ /**
+ * @return the delegate
+ */
+ public RpcRegistration getDelegate() {
+ return delegate;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 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.dom.broker.impl;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.SimpleNode;
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Iterables;
+
+public class DataReaderRouter extends
+AbstractDataReadRouter<InstanceIdentifier, CompositeNode> {
+ private final static Logger LOG = LoggerFactory
+ .getLogger(DataReaderRouter.class);
+ private final static URI NETCONF_NAMESPACE = URI
+ .create("urn:ietf:params:xml:ns:netconf:base:1.0");
+ private final static QName NETCONF_DATA = new QName(NETCONF_NAMESPACE,
+ "data");
+
+ @Override
+ protected CompositeNodeTOImpl merge(final InstanceIdentifier path,
+ final Iterable<CompositeNode> data) {
+ PathArgument pathArgument = Iterables.getLast(path.getPath(), null);
+ boolean empty = true;
+ QName name = (pathArgument == null ? null : pathArgument.getNodeType());
+ final ArrayList<Node<?>> nodes = new ArrayList<Node<?>>();
+ final HashMap<QName, SimpleNode<?>> keyNodes = new HashMap<QName, SimpleNode<?>>();
+ for (final CompositeNode dataBit : data) {
+ try {
+ if (pathArgument != null && dataBit != null) {
+ empty = false;
+ final Map<QName, SimpleNode<?>> keyNodesLocal = getKeyNodes(
+ pathArgument, dataBit);
+ nodes.addAll(this.childrenWithout(dataBit,
+ keyNodesLocal.entrySet()));
+ } else if (dataBit != null) {
+ empty = false;
+ nodes.addAll(dataBit.getValue());
+ }
+ } catch (IllegalStateException e) {
+ LOG.error("BUG: Readed data for path {} was invalid", path, e);
+ }
+ }
+ if (empty) {
+ return null;
+ }
+ /**
+ * Reading from Root
+ *
+ */
+ if (pathArgument == null) {
+ return new CompositeNodeTOImpl(NETCONF_DATA, null, nodes);
+ }
+ final ArrayList<Node<?>> finalNodes = new ArrayList<Node<?>>(
+ nodes.size() + keyNodes.size());
+ finalNodes.addAll(keyNodes.values());
+ finalNodes.addAll(nodes);
+ return new CompositeNodeTOImpl(name, null, finalNodes);
+ }
+
+ protected Map<QName, SimpleNode<?>> _getKeyNodes(
+ final PathArgument argument, final CompositeNode node) {
+ return Collections.emptyMap();
+ }
+
+ protected Map<QName, SimpleNode<?>> _getKeyNodes(
+ final NodeIdentifierWithPredicates argument,
+ final CompositeNode node) {
+ final HashMap<QName, SimpleNode<?>> ret = new HashMap<QName, SimpleNode<?>>();
+ for (final Entry<QName, Object> keyValue : argument.getKeyValues()
+ .entrySet()) {
+ final List<SimpleNode<?>> simpleNode = node
+ .getSimpleNodesByName(keyValue.getKey());
+ if (simpleNode != null && !simpleNode.isEmpty()) {
+ checkState(
+ simpleNode.size() <= 1,
+ "Only one simple node for key $s is allowed in node $s",
+ keyValue.getKey(), node);
+ checkState(
+ simpleNode.get(0).getValue() == keyValue.getValue(),
+ "Key node must equal to instance identifier value in node $s",
+ node);
+ ret.put(keyValue.getKey(), simpleNode.get(0));
+ }
+ final List<CompositeNode> compositeNode = node
+ .getCompositesByName(keyValue.getKey());
+ checkState(compositeNode == null || compositeNode.isEmpty(),
+ "Key node must be Simple Node, not composite node.");
+ }
+ return ret;
+ }
+
+ public Map<QName, SimpleNode<?>> getKeyNodes(
+ final InstanceIdentifier.PathArgument argument,
+ final CompositeNode node) {
+ if (argument instanceof InstanceIdentifier.NodeIdentifierWithPredicates) {
+ return _getKeyNodes(
+ (InstanceIdentifier.NodeIdentifierWithPredicates) argument,
+ node);
+ } else if (argument != null) {
+ return _getKeyNodes(argument, node);
+ } else {
+ throw new IllegalArgumentException("Unhandled parameter types: "
+ + Arrays.<Object> asList(argument, node).toString());
+ }
+ }
+
+ private Collection<? extends Node<?>> childrenWithout(
+ final CompositeNode node,
+ final Set<Entry<QName, SimpleNode<?>>> entries) {
+ if (entries.isEmpty()) {
+ return node.getValue();
+ }
+ final List<Node<?>> filteredNodes = new ArrayList<Node<?>>();
+ for (final Node<?> scannedNode : node.getValue()) {
+ if (!entries.contains(scannedNode.getNodeType())) {
+ filteredNodes.add(scannedNode);
+ }
+ }
+ return filteredNodes;
+ }
+
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 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.dom.broker.impl
-
-import java.net.URI
-import java.util.ArrayList
-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 org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter
-import org.opendaylight.yangtools.yang.common.QName
-import org.opendaylight.yangtools.yang.data.api.CompositeNode
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
-import org.opendaylight.yangtools.yang.data.api.Node
-import org.opendaylight.yangtools.yang.data.api.SimpleNode
-import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
-import org.slf4j.LoggerFactory
-
-import static com.google.common.base.Preconditions.*
-
-class DataReaderRouter extends AbstractDataReadRouter<InstanceIdentifier, CompositeNode> {
- private static val LOG = LoggerFactory.getLogger(DataReaderRouter);
- private static val NETCONF_NAMESPACE = URI.create("urn:ietf:params:xml:ns:netconf:base:1.0")
- private static val NETCONF_DATA = new QName(NETCONF_NAMESPACE,"data");
-
- override protected merge(InstanceIdentifier path, Iterable<CompositeNode> data) {
- val pathArgument = path.path.last;
- var empty = true;
- var name = pathArgument?.nodeType;
- val nodes = new ArrayList<Node<?>>();
- val keyNodes = new HashMap<QName, SimpleNode<?>>();
- for(dataBit : data) {
- try {
- if(pathArgument != null && dataBit != null) {
- empty = false;
- val keyNodesLocal = getKeyNodes(pathArgument,dataBit);
- nodes.addAll(dataBit.childrenWithout(keyNodesLocal.entrySet));
- } else if (dataBit != null) {
- empty = false;
- nodes.addAll(dataBit.children)
- }
- } catch (IllegalStateException e) {
- LOG.error("BUG: Readed data for path {} was invalid",path,e);
- }
- }
- if(empty) {
- return null;
- }
- /**
- * Reading from Root
- *
- */
- if(pathArgument == null) {
- return new CompositeNodeTOImpl(NETCONF_DATA,null,nodes);
- }
- val finalNodes = new ArrayList<Node<?>>();
- finalNodes.addAll(keyNodes.values);
- finalNodes.addAll(nodes);
- return new CompositeNodeTOImpl(name,null,finalNodes);
- }
-
-
-
- dispatch def Map<QName, SimpleNode<?>> getKeyNodes(PathArgument argument, CompositeNode node) {
- return Collections.emptyMap();
- }
-
- dispatch def getKeyNodes(NodeIdentifierWithPredicates argument, CompositeNode node) {
- val ret = new HashMap<QName, SimpleNode<?>>();
- for (keyValue : argument.keyValues.entrySet) {
- val simpleNode = node.getSimpleNodesByName(keyValue.key);
- if(simpleNode !== null && !simpleNode.empty) {
- checkState(simpleNode.size <= 1,"Only one simple node for key $s is allowed in node $s",keyValue.key,node);
- checkState(simpleNode.get(0).value == keyValue.value,"Key node must equal to instance identifier value in node $s",node);
- ret.put(keyValue.key,simpleNode.get(0));
- }
- val compositeNode = node.getCompositesByName(keyValue.key);
- checkState(compositeNode === null || compositeNode.empty,"Key node must be Simple Node, not composite node.");
- }
- return ret;
- }
-
- def Collection<? extends Node<?>> childrenWithout(CompositeNode node, Set<Entry<QName, SimpleNode<?>>> entries) {
- if(entries.empty) {
- return node.children;
- }
- val filteredNodes = new ArrayList<Node<?>>();
- for(scannedNode : node.children) {
- if(!entries.contains(scannedNode.nodeType)) {
- filteredNodes.add(scannedNode);
- }
- }
- return filteredNodes;
- }
-
-}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.dom.broker.impl;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
+import org.opendaylight.controller.md.sal.common.api.data.DataModification;
+import org.opendaylight.controller.sal.common.util.Rpcs;
+import org.opendaylight.controller.sal.core.api.data.DataStore;
+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;
+
+public final class HashMapDataStore implements DataStore, AutoCloseable {
+ private static final Logger LOG = LoggerFactory
+ .getLogger(HashMapDataStore.class);
+
+ private final Map<InstanceIdentifier, CompositeNode> configuration = new ConcurrentHashMap<InstanceIdentifier, CompositeNode>();
+ private final Map<InstanceIdentifier, CompositeNode> operational = new ConcurrentHashMap<InstanceIdentifier, CompositeNode>();
+
+ @Override
+ public boolean containsConfigurationPath(final InstanceIdentifier path) {
+ return configuration.containsKey(path);
+ }
+
+ @Override
+ public boolean containsOperationalPath(final InstanceIdentifier path) {
+ return operational.containsKey(path);
+ }
+
+ @Override
+ public Iterable<InstanceIdentifier> getStoredConfigurationPaths() {
+ return configuration.keySet();
+ }
+
+ @Override
+ public Iterable<InstanceIdentifier> getStoredOperationalPaths() {
+ return operational.keySet();
+ }
+
+ @Override
+ public CompositeNode readConfigurationData(final InstanceIdentifier path) {
+ LOG.trace("Reading configuration path {}", path);
+ return configuration.get(path);
+ }
+
+ @Override
+ public CompositeNode readOperationalData(InstanceIdentifier path) {
+ LOG.trace("Reading operational path {}", path);
+ return operational.get(path);
+ }
+
+ @Override
+ public DataCommitHandler.DataCommitTransaction<InstanceIdentifier, CompositeNode> requestCommit(
+ final DataModification<InstanceIdentifier, CompositeNode> modification) {
+ return new HashMapDataStoreTransaction(modification, this);
+ }
+
+ public RpcResult<Void> rollback(HashMapDataStoreTransaction transaction) {
+ return Rpcs.<Void> getRpcResult(true, null,
+ Collections.<RpcError> emptySet());
+ }
+
+ public RpcResult<Void> finish(HashMapDataStoreTransaction transaction) {
+ final DataModification<InstanceIdentifier, CompositeNode> modification = transaction
+ .getModification();
+ for (final InstanceIdentifier removal : modification
+ .getRemovedConfigurationData()) {
+ LOG.trace("Removing configuration path {}", removal);
+ remove(configuration, removal);
+ }
+ for (final InstanceIdentifier removal : modification
+ .getRemovedOperationalData()) {
+ LOG.trace("Removing operational path {}", removal);
+ remove(operational, removal);
+ }
+ if (LOG.isTraceEnabled()) {
+ for (final InstanceIdentifier a : modification
+ .getUpdatedConfigurationData().keySet()) {
+ LOG.trace("Adding configuration path {}", a);
+ }
+ for (final InstanceIdentifier a : modification
+ .getUpdatedOperationalData().keySet()) {
+ LOG.trace("Adding operational path {}", a);
+ }
+ }
+ configuration.putAll(modification.getUpdatedConfigurationData());
+ operational.putAll(modification.getUpdatedOperationalData());
+
+ return Rpcs.<Void> getRpcResult(true, null,
+ Collections.<RpcError> emptySet());
+ }
+
+ public void remove(final Map<InstanceIdentifier, CompositeNode> map,
+ final InstanceIdentifier identifier) {
+ Set<InstanceIdentifier> affected = new HashSet<InstanceIdentifier>();
+ for (final InstanceIdentifier path : map.keySet()) {
+ if (identifier.contains(path)) {
+ affected.add(path);
+ }
+ }
+ for (final InstanceIdentifier pathToRemove : affected) {
+ LOG.trace("Removed path {}", pathToRemove);
+ map.remove(pathToRemove);
+ }
+ }
+
+ @Override
+ public void close() {
+ // NOOP
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 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.dom.broker.impl
-
-import org.opendaylight.controller.md.sal.common.api.data.DataModification
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction
-import org.opendaylight.yangtools.yang.common.RpcResult
-import java.util.Map
-import java.util.concurrent.ConcurrentHashMap
-import org.opendaylight.controller.sal.common.util.Rpcs
-import java.util.Collections
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
-import org.opendaylight.yangtools.yang.data.api.CompositeNode
-import org.opendaylight.controller.sal.core.api.data.DataStore
-import java.util.HashSet
-import org.slf4j.LoggerFactory
-import org.slf4j.Logger
-
-final class HashMapDataStore implements DataStore, AutoCloseable {
- private val Logger LOG = LoggerFactory.getLogger(HashMapDataStore)
-
- val Map<InstanceIdentifier, CompositeNode> configuration = new ConcurrentHashMap();
- val Map<InstanceIdentifier, CompositeNode> operational = new ConcurrentHashMap();
-
-
-
- override containsConfigurationPath(InstanceIdentifier path) {
- return configuration.containsKey(path)
- }
-
- override containsOperationalPath(InstanceIdentifier path) {
- return operational.containsKey(path)
- }
-
- override getStoredConfigurationPaths() {
- configuration.keySet
- }
-
- override getStoredOperationalPaths() {
- operational.keySet
- }
-
- override readConfigurationData(InstanceIdentifier path) {
- LOG.trace("Reading configuration path {}", path)
- configuration.get(path);
- }
-
- override readOperationalData(InstanceIdentifier path) {
- LOG.trace("Reading operational path {}", path)
- operational.get(path);
- }
-
-
-
- override requestCommit(DataModification<InstanceIdentifier, CompositeNode> modification) {
- return new HashMapDataStoreTransaction(modification, this);
- }
-
- def RpcResult<Void> rollback(HashMapDataStoreTransaction transaction) {
- return Rpcs.getRpcResult(true, null, Collections.emptySet);
- }
-
- def RpcResult<Void> finish(HashMapDataStoreTransaction transaction) {
- val modification = transaction.modification;
- for (removal : modification.removedConfigurationData) {
- LOG.trace("Removing configuration path {}", removal)
- remove(configuration,removal);
- }
- for (removal : modification.removedOperationalData) {
- LOG.trace("Removing operational path {}", removal)
- remove(operational,removal);
- }
- if (LOG.isTraceEnabled()) {
- for (a : modification.updatedConfigurationData.keySet) {
- LOG.trace("Adding configuration path {}", a)
- }
- for (a : modification.updatedOperationalData.keySet) {
- LOG.trace("Adding operational path {}", a)
- }
- }
- configuration.putAll(modification.updatedConfigurationData);
- operational.putAll(modification.updatedOperationalData);
-
- return Rpcs.getRpcResult(true, null, Collections.emptySet);
- }
-
- def remove(Map<InstanceIdentifier, CompositeNode> map, InstanceIdentifier identifier) {
- val affected = new HashSet<InstanceIdentifier>();
- for(path : map.keySet) {
- if(identifier.contains(path)) {
- affected.add(path);
- }
- }
- for(pathToRemove : affected) {
- LOG.trace("Removed path {}", pathToRemove)
- map.remove(pathToRemove);
- }
-
- }
-
-
- override close() {
- // NOOP
- }
-
-}
-
-class HashMapDataStoreTransaction implements //
-DataCommitTransaction<InstanceIdentifier, CompositeNode> {
- @Property
- val DataModification<InstanceIdentifier, CompositeNode> modification
-
- @Property
- val HashMapDataStore datastore;
-
- new(
- DataModification<InstanceIdentifier, CompositeNode> modify,
- HashMapDataStore store
- ) {
- _modification = modify;
- _datastore = store;
- }
-
- override finish() throws IllegalStateException {
- datastore.finish(this);
-
- }
-
- override getModification() {
- this._modification;
- }
-
- override rollback() throws IllegalStateException {
- datastore.rollback(this);
- }
-}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.dom.broker.impl;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataModification;
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+public class HashMapDataStoreTransaction implements
+ DataCommitTransaction<InstanceIdentifier, CompositeNode> {
+ private final DataModification<InstanceIdentifier, CompositeNode> modification;
+ private final HashMapDataStore datastore;
+
+ HashMapDataStoreTransaction(
+ final DataModification<InstanceIdentifier, CompositeNode> modify,
+ final HashMapDataStore store) {
+ modification = modify;
+ datastore = store;
+ }
+
+ @Override
+ public RpcResult<Void> finish() throws IllegalStateException {
+ return datastore.finish(this);
+ }
+
+ @Override
+ public DataModification<InstanceIdentifier, CompositeNode> getModification() {
+ return this.modification;
+ }
+
+ @Override
+ public RpcResult<Void> rollback() throws IllegalStateException {
+ return datastore.rollback(this);
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 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.dom.broker.osgi;
+
+import java.util.Arrays;
+
+import org.opendaylight.controller.sal.core.api.BrokerService;
+import org.osgi.framework.ServiceReference;
+import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.core.api.data.DataProviderService;
+import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
+import org.opendaylight.controller.sal.core.api.notify.NotificationService;
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+
+@SuppressWarnings("unchecked")
+public class ProxyFactory {
+
+ public static <T extends BrokerService> T createProxy(
+ final ServiceReference<T> serviceRef, final T service) {
+
+ Object _createProxyImpl = ProxyFactory.createProxyImpl(serviceRef,
+ service);
+ return ((T) _createProxyImpl);
+ }
+
+ private static Object _createProxyImpl(final ServiceReference<?> ref,
+ final DataBrokerService service) {
+
+ return new DataBrokerServiceProxy(
+ ((ServiceReference<DataBrokerService>) ref), service);
+ }
+
+ private static Object _createProxyImpl(final ServiceReference<?> ref,
+ final DataProviderService service) {
+
+ return new DataProviderServiceProxy(
+ ((ServiceReference<DataProviderService>) ref), service);
+ }
+
+ private static Object _createProxyImpl(final ServiceReference<?> ref,
+ final NotificationPublishService service) {
+
+ return new NotificationPublishServiceProxy(
+ ((ServiceReference<NotificationPublishService>) ref), service);
+ }
+
+ private static Object _createProxyImpl(final ServiceReference<?> ref,
+ final NotificationService service) {
+
+ return new NotificationServiceProxy(
+ ((ServiceReference<NotificationService>) ref), service);
+ }
+
+ private static Object _createProxyImpl(final ServiceReference<?> ref,
+ final MountProvisionService service) {
+
+ return new MountProviderServiceProxy(
+ ((ServiceReference<MountProvisionService>) ref), service);
+ }
+
+ private static Object _createProxyImpl(final ServiceReference<?> ref,
+ final SchemaService service) {
+
+ return new SchemaServiceProxy(((ServiceReference<SchemaService>) ref),
+ service);
+ }
+
+ private static Object _createProxyImpl(final ServiceReference<?> ref,
+ final RpcProvisionRegistry service) {
+
+ return new RpcProvisionRegistryProxy(
+ ((ServiceReference<RpcProvisionRegistry>) ref), service);
+ }
+
+ private static DOMDataBrokerProxy _createProxyImpl(
+ final ServiceReference<?> ref, final DOMDataBroker service) {
+
+ return new DOMDataBrokerProxy(((ServiceReference<DOMDataBroker>) ref),
+ service);
+ }
+
+ private static Object _createProxyImpl(final ServiceReference<?> reference,
+ final BrokerService service) {
+
+ throw new IllegalArgumentException("Not supported class: "
+ + service.getClass().getName());
+ }
+
+ private static Object createProxyImpl(final ServiceReference<?> ref,
+ final BrokerService service) {
+
+ if (service instanceof DOMDataBroker) {
+ return _createProxyImpl(ref, (DOMDataBroker) service);
+ } else if (service instanceof RpcProvisionRegistry) {
+ return _createProxyImpl(ref, (RpcProvisionRegistry) service);
+ } else if (service instanceof DataProviderService) {
+ return _createProxyImpl(ref, (DataProviderService) service);
+ } else if (service instanceof MountProvisionService) {
+ return _createProxyImpl(ref, (MountProvisionService) service);
+ } else if (service instanceof NotificationPublishService) {
+ return _createProxyImpl(ref, (NotificationPublishService) service);
+ } else if (service instanceof DataBrokerService) {
+ return _createProxyImpl(ref, (DataBrokerService) service);
+ } else if (service instanceof SchemaService) {
+ return _createProxyImpl(ref, (SchemaService) service);
+ } else if (service instanceof NotificationService) {
+ return _createProxyImpl(ref, (NotificationService) service);
+ } else if (service != null) {
+ return _createProxyImpl(ref, service);
+ } else {
+ throw new IllegalArgumentException("Unhandled parameter types: "
+ + Arrays.<Object> asList(ref, service).toString());
+ }
+ }
+}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (c) 2014 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.dom.broker.osgi
-
-import org.opendaylight.controller.sal.core.api.BrokerService
-import org.osgi.framework.ServiceReference
-import org.opendaylight.controller.sal.core.api.data.DataBrokerService
-import org.opendaylight.controller.sal.core.api.data.DataProviderService
-import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService
-import org.opendaylight.controller.sal.core.api.notify.NotificationService
-import org.opendaylight.controller.sal.core.api.model.SchemaService
-import org.opendaylight.controller.sal.core.api.mount.MountProvisionService
-import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry
-import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker
-
-class ProxyFactory {
-
- static def <T extends BrokerService> T createProxy(ServiceReference<T> serviceRef, T service) {
- return createProxyImpl(serviceRef, service) as T;
- }
-
-
- private static def dispatch createProxyImpl(ServiceReference<?> ref, DataBrokerService service) {
- new DataBrokerServiceProxy(ref as ServiceReference<DataBrokerService>, service);
- }
-
- private static def dispatch createProxyImpl(ServiceReference<?> ref, DataProviderService service) {
- new DataProviderServiceProxy(ref as ServiceReference<DataProviderService>, service);
- }
-
- private static def dispatch createProxyImpl(ServiceReference<?> ref, NotificationPublishService service) {
- new NotificationPublishServiceProxy(ref as ServiceReference<NotificationPublishService>, service);
- }
-
- private static def dispatch createProxyImpl(ServiceReference<?> ref, NotificationService service) {
- new NotificationServiceProxy(ref as ServiceReference<NotificationService>, service);
- }
-
- private static def dispatch createProxyImpl(ServiceReference<?> ref, MountProvisionService service) {
- new MountProviderServiceProxy(ref as ServiceReference<MountProvisionService>, service);
- }
-
-
- private static def dispatch createProxyImpl(ServiceReference<?> ref, SchemaService service) {
- new SchemaServiceProxy(ref as ServiceReference<SchemaService>, service);
- }
-
- private static def dispatch createProxyImpl(ServiceReference<?> ref, RpcProvisionRegistry service) {
- new RpcProvisionRegistryProxy(ref as ServiceReference<RpcProvisionRegistry>, service);
- }
-
- private static def dispatch createProxyImpl(ServiceReference<?> ref, DOMDataBroker service) {
- new DOMDataBrokerProxy(ref as ServiceReference<DOMDataBroker>, service)
- }
-
-
- private static def dispatch createProxyImpl(ServiceReference<?> reference, BrokerService service) {
- throw new IllegalArgumentException("Not supported class");
- }
-
-}
public class SchemaServiceActivator implements BundleActivator {
-
+
private ServiceRegistration<SchemaService> schemaServiceReg;
private GlobalBundleScanningSchemaServiceImpl schemaService;
@Override
- public void start(BundleContext context) throws Exception {
- schemaService = new GlobalBundleScanningSchemaServiceImpl();
- schemaService.setContext(context);
+ public void start(final BundleContext context) {
+ schemaService = new GlobalBundleScanningSchemaServiceImpl(context);
schemaService.start();
schemaServiceReg = context.registerService(SchemaService.class, schemaService, new Hashtable<String,String>());
}
-
+
@Override
- public void stop(BundleContext context) throws Exception {
+ public void stop(final BundleContext context) throws Exception {
schemaServiceReg.unregister();
schemaService.close();
}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.dom.broker.util;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+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.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+
+public class YangDataOperations {
+
+ public static CompositeNode merge(final DataSchemaNode schema,
+ final CompositeNode stored, final CompositeNode modified,
+ final boolean config) {
+ if (stored == null) {
+ return modified;
+ }
+
+ Preconditions.checkArgument(schema instanceof ListSchemaNode
+ || schema instanceof ContainerSchemaNode,
+ "Supplied node is not data node container.");
+
+ return YangDataOperations.mergeContainer((DataNodeContainer) schema,
+ stored, modified, config);
+ }
+
+ private static Iterable<? extends Node<?>> _mergeMultiple(
+ final LeafSchemaNode node, final List<Node<?>> original,
+ final List<Node<?>> modified, final boolean configurational) {
+ checkArgument(original.size() == 1);
+ checkArgument(modified.size() == 1);
+
+ return modified;
+ }
+
+ private static Iterable<? extends Node<?>> _mergeMultiple(
+ final LeafListSchemaNode node, final List<Node<?>> original,
+ final List<Node<?>> modified, final boolean configurational) {
+ return modified;
+ }
+
+ private static Iterable<? extends Node<?>> _mergeMultiple(
+ final ContainerSchemaNode node, final List<Node<?>> original,
+ final List<Node<?>> modified, final boolean configurational) {
+ checkArgument(original.size() == 1);
+ checkArgument(modified.size() == 1);
+ return Collections.singletonList(merge(node,
+ (CompositeNode) original.get(0),
+ (CompositeNode) modified.get(0), configurational));
+ }
+
+ private static Iterable<? extends Node<?>> _mergeMultiple(
+ final ListSchemaNode node, final List<Node<?>> original,
+ final List<Node<?>> modified, final boolean configurational) {
+
+ if (node.getKeyDefinition() == null
+ || node.getKeyDefinition().isEmpty()) {
+ return modified;
+ }
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ final Map<Map<QName, Object>, CompositeNode> originalMap = YangDataUtils
+ .toIndexMap((List) original, node.getKeyDefinition());
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ final Map<Map<QName, Object>, CompositeNode> modifiedMap = YangDataUtils
+ .toIndexMap((List) modified, node.getKeyDefinition());
+
+ final List<Node<?>> mergedNodes = new ArrayList<Node<?>>(
+ original.size() + modified.size());
+ for (final Map.Entry<Map<QName, Object>, CompositeNode> entry : modifiedMap
+ .entrySet()) {
+ final CompositeNode originalEntry = originalMap.get(entry.getKey());
+ if (originalEntry != null) {
+ originalMap.remove(entry.getKey());
+ mergedNodes.add(merge(node, originalEntry, entry.getValue(),
+ configurational));
+ } else {
+ mergedNodes.add(entry.getValue());
+ }
+ }
+ mergedNodes.addAll(originalMap.values());
+ return mergedNodes;
+ }
+
+ private static Iterable<? extends Node<?>> mergeMultiple(
+ final DataSchemaNode node, final List<Node<?>> original,
+ final List<Node<?>> modified, final boolean configurational) {
+ if (node instanceof ContainerSchemaNode) {
+ return _mergeMultiple((ContainerSchemaNode) node, original,
+ modified, configurational);
+ } else if (node instanceof LeafListSchemaNode) {
+ return _mergeMultiple((LeafListSchemaNode) node, original,
+ modified, configurational);
+ } else if (node instanceof LeafSchemaNode) {
+ return _mergeMultiple((LeafSchemaNode) node, original, modified,
+ configurational);
+ } else if (node instanceof ListSchemaNode) {
+ return _mergeMultiple((ListSchemaNode) node, original, modified,
+ configurational);
+ } else {
+ throw new IllegalArgumentException("Unhandled parameter types: "
+ + Arrays.<Object> asList(node, original, modified,
+ configurational).toString());
+ }
+ }
+
+ private static CompositeNode mergeContainer(final DataNodeContainer schema,
+ final CompositeNode stored, final CompositeNode modified,
+ final boolean config) {
+ if (stored == null) {
+ return modified;
+ }
+ Preconditions.checkNotNull(stored);
+ Preconditions.checkNotNull(modified);
+ Preconditions.checkArgument(Objects.equals(stored.getNodeType(),
+ modified.getNodeType()));
+
+ final List<Node<?>> mergedChildNodes = new ArrayList<Node<?>>(stored
+ .getChildren().size() + modified.getChildren().size());
+ final Set<QName> toProcess = new HashSet<QName>(stored.keySet());
+ toProcess.addAll(modified.keySet());
+
+ for (QName qname : toProcess) {
+ final DataSchemaNode schemaChild = schema.getDataChildByName(qname);
+ final List<Node<?>> storedChildren = stored.get(qname);
+ final List<Node<?>> modifiedChildren = modified.get(qname);
+
+ if (modifiedChildren != null && !modifiedChildren.isEmpty()) {
+ if (storedChildren == null || storedChildren.isEmpty()
+ || schemaChild == null) {
+ mergedChildNodes.addAll(modifiedChildren);
+ } else {
+ final Iterable<? extends Node<?>> _mergeMultiple = mergeMultiple(
+ schemaChild, storedChildren, modifiedChildren,
+ config);
+ Iterables.addAll(mergedChildNodes, _mergeMultiple);
+ }
+ } else if (storedChildren != null && !storedChildren.isEmpty()) {
+ mergedChildNodes.addAll(storedChildren);
+ }
+ }
+ return new CompositeNodeTOImpl(stored.getNodeType(), null,
+ mergedChildNodes);
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 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.dom.broker.util
-
-import org.opendaylight.yangtools.yang.data.api.CompositeNode
-import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
-import static com.google.common.base.Preconditions.*;
-import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
-import java.util.ArrayList
-
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
-import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
-import org.opendaylight.yangtools.yang.data.api.Node
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
-import java.util.List
-import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
-import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
-import java.util.Collections
-import java.util.HashSet
-import org.opendaylight.yangtools.yang.common.QName
-import static extension org.opendaylight.controller.sal.dom.broker.util.YangDataUtils.*;
-
-class YangDataOperations {
-
- static def CompositeNode merge(DataSchemaNode schema, CompositeNode stored, CompositeNode modified, boolean config) {
- if (stored === null) {
- return modified;
- }
-
- if (schema instanceof ListSchemaNode || schema instanceof ContainerSchemaNode) {
- return mergeContainer(schema as DataNodeContainer, stored, modified, config);
- }
- throw new IllegalArgumentException("Supplied node is not data node container.");
- }
-
- private static dispatch def Iterable<? extends Node<?>> mergeMultiple(LeafSchemaNode node, List<Node<?>> original,
- List<Node<?>> modified, boolean configurational) {
- checkArgument(original.size === 1);
- checkArgument(modified.size === 1);
-
- return modified;
- }
-
- private static dispatch def Iterable<? extends Node<?>> mergeMultiple(LeafListSchemaNode node,
- List<Node<?>> original, List<Node<?>> modified, boolean configurational) {
- return modified;
- }
-
- private static dispatch def Iterable<? extends Node<?>> mergeMultiple(ContainerSchemaNode node,
- List<Node<?>> original, List<Node<?>> modified, boolean configurational) {
- checkArgument(original.size === 1);
- checkArgument(modified.size === 1);
- return Collections.singletonList(
- merge(node, original.get(0) as CompositeNode, modified.get(0) as CompositeNode, configurational));
- }
-
- private static dispatch def Iterable<? extends Node<?>> mergeMultiple(ListSchemaNode node, List<Node<?>> original,
- List<Node<?>> modified, boolean configurational) {
-
- if(node.keyDefinition === null || node.keyDefinition.empty) {
- return modified;
- }
- val originalMap = (original as List).toIndexMap(node.keyDefinition);
- val modifiedMap = (modified as List).toIndexMap(node.keyDefinition);
-
- val List<Node<?>> mergedNodes = new ArrayList(original.size + modified.size);
- for(entry : modifiedMap.entrySet) {
- val originalEntry = originalMap.get(entry.key);
- if(originalEntry != null) {
- originalMap.remove(entry.key);
- mergedNodes.add(merge(node,originalEntry,entry.value,configurational));
- } else {
- mergedNodes.add(entry.value);
- }
- }
- mergedNodes.addAll(originalMap.values);
- return mergedNodes;
- }
-
- static private def CompositeNode mergeContainer(DataNodeContainer schema, CompositeNode stored,
- CompositeNode modified, boolean config) {
- if (stored == null) {
- return modified;
- }
- checkNotNull(stored)
- checkNotNull(modified)
- checkArgument(stored.nodeType == modified.nodeType);
-
- val mergedChildNodes = new ArrayList<Node<?>>(stored.children.size + modified.children.size);
-
- val toProcess = new HashSet<QName>(stored.keySet);
- toProcess.addAll(modified.keySet);
-
- for (qname : toProcess) {
- val schemaChild = schema.getDataChildByName(qname);
- val storedChildren = stored.get(qname);
- val modifiedChildren = modified.get(qname);
-
- if (modifiedChildren !== null && !modifiedChildren.empty) {
- if (storedChildren === null || storedChildren.empty || schemaChild === null) {
- mergedChildNodes.addAll(modifiedChildren);
- } else {
- mergedChildNodes.addAll(mergeMultiple(schemaChild, storedChildren, modifiedChildren, config));
- }
- } else if (storedChildren !== null && !storedChildren.empty) {
- mergedChildNodes.addAll(storedChildren);
- }
- }
- return new CompositeNodeTOImpl(stored.nodeType, null, mergedChildNodes);
- }
-
-}
+++ /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>
- </parent>
- <artifactId>sal-dom-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>
-
- <dependencies>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-broker-impl</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>yang-data-util</artifactId>
- </dependency>
- <dependency>
- <groupId>org.mockito</groupId>
- <artifactId>mockito-all</artifactId>
- <version>1.9.5</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-simple</artifactId>
- <version>1.7.2</version>
- <scope>runtime</scope>
- </dependency>
- </dependencies>
- <build>
- <plugins>
- <plugin>
- <artifactId>maven-assembly-plugin</artifactId>
- <version>2.4</version>
- <configuration>
- <descriptorRefs>
- <descriptorRef>jar-with-dependencies</descriptorRef>
- </descriptorRefs>
- <archive>
- <manifest>
- <mainClass>org.opendaylight.controller.sal.demo.SALDemo</mainClass>
- </manifest>
- </archive>
- </configuration>
- <executions>
- <execution>
- <id>make-assembly</id>
- <phase>package</phase>
- <goals>
- <goal>single</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
-</project>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-common-util</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
*/
package org.opendaylight.controller.sal.rest.api;
+import org.opendaylight.yangtools.yang.common.QName;
+
public class Draft02 {
- public static class MediaTypes {
- public static final String API = "application/yang.api";
- public static final String DATASTORE = "application/yang.datastore";
- public static final String DATA = "application/yang.data";
- public static final String OPERATION = "application/yang.operation";
- public static final String PATCH = "application/yang.patch";
- public static final String PATCH_STATUS = "application/yang.patch-status";
- public static final String STREAM = "application/yang.stream";
+ public static interface MediaTypes {
+ String API = "application/yang.api";
+ String DATASTORE = "application/yang.datastore";
+ String DATA = "application/yang.data";
+ String OPERATION = "application/yang.operation";
+ String PATCH = "application/yang.patch";
+ String PATCH_STATUS = "application/yang.patch-status";
+ String STREAM = "application/yang.stream";
+ }
+
+ public static interface RestConfModule {
+ String REVISION = "2013-10-19";
+
+ String NAME = "ietf-restconf";
+
+ String NAMESPACE = "urn:ietf:params:xml:ns:yang:ietf-restconf";
+
+ String RESTCONF_GROUPING_SCHEMA_NODE = "restconf";
+
+ String RESTCONF_CONTAINER_SCHEMA_NODE = "restconf";
+
+ String MODULES_CONTAINER_SCHEMA_NODE = "modules";
+
+ String MODULE_LIST_SCHEMA_NODE = "module";
+
+ String STREAMS_CONTAINER_SCHEMA_NODE = "streams";
+
+ String STREAM_LIST_SCHEMA_NODE = "stream";
+
+ String OPERATIONS_CONTAINER_SCHEMA_NODE = "operations";
+
+ String ERRORS_GROUPING_SCHEMA_NODE = "errors";
+
+ String ERRORS_CONTAINER_SCHEMA_NODE = "errors";
+
+ String ERROR_LIST_SCHEMA_NODE = "error";
+
+ QName IETF_RESTCONF_QNAME = QName.create( Draft02.RestConfModule.NAMESPACE,
+ Draft02.RestConfModule.REVISION,
+ Draft02.RestConfModule.NAME );
+
+ QName ERRORS_CONTAINER_QNAME = QName.create( IETF_RESTCONF_QNAME, ERRORS_CONTAINER_SCHEMA_NODE );
+
+ QName ERROR_LIST_QNAME = QName.create( IETF_RESTCONF_QNAME, ERROR_LIST_SCHEMA_NODE );
+
+ QName ERROR_TYPE_QNAME = QName.create( IETF_RESTCONF_QNAME, "error-type" );
+
+ QName ERROR_TAG_QNAME = QName.create( IETF_RESTCONF_QNAME, "error-tag" );
+
+ QName ERROR_APP_TAG_QNAME = QName.create( IETF_RESTCONF_QNAME, "error-app-tag" );
+
+ QName ERROR_MESSAGE_QNAME = QName.create( IETF_RESTCONF_QNAME, "error-message" );
+
+ QName ERROR_INFO_QNAME = QName.create( IETF_RESTCONF_QNAME, "error-info" );
}
-
- public static class Paths {
-
+
+
+ public static interface Paths {
+
}
}
import java.io.IOException;
import java.net.URI;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
private void writeChildrenOfParent(final JsonWriter writer, final CompositeNode parent, final DataNodeContainer parentSchema)
throws IOException {
checkNotNull(parent);
- checkNotNull(parentSchema);
+
+ Set<DataSchemaNode> parentSchemaChildNodes = parentSchema == null ?
+ Collections.<DataSchemaNode>emptySet() : parentSchema.getChildNodes();
+
for (Node<?> child : parent.getValue()) {
- DataSchemaNode childSchema = findFirstSchemaForNode(child, parentSchema.getChildNodes());
+ DataSchemaNode childSchema = findFirstSchemaForNode(child, parentSchemaChildNodes);
if (childSchema == null) {
- throw new UnsupportedDataTypeException("Probably the data node \"" + child.getNodeType().getLocalName()
- + "\" is not conform to schema");
- }
+ // Node may not conform to schema or allows "anyxml" - we'll process it.
- if (childSchema instanceof ContainerSchemaNode) {
+ logger.debug( "No schema found for data node \"" + child.getNodeType() );
+
+ handleNoSchemaFound( writer, child, parent );
+ }
+ else if (childSchema instanceof ContainerSchemaNode) {
Preconditions.checkState(child instanceof CompositeNode,
"Data representation of Container should be CompositeNode - " + child.getNodeType());
writeContainer(writer, (CompositeNode) child, (ContainerSchemaNode) childSchema);
}
for (Node<?> child : parent.getValue()) {
- DataSchemaNode childSchema = findFirstSchemaForNode(child, parentSchema.getChildNodes());
+ DataSchemaNode childSchema = findFirstSchemaForNode(child, parentSchemaChildNodes);
if (childSchema instanceof LeafListSchemaNode) {
foundLeafLists.remove(childSchema);
} else if (childSchema instanceof ListSchemaNode) {
}
}
+ private void handleNoSchemaFound( final JsonWriter writer, final Node<?> node,
+ final CompositeNode parent ) throws IOException {
+ if( node instanceof SimpleNode<?> ) {
+ writeName( node, null, writer );
+ Object value = node.getValue();
+ if( value != null ) {
+ writer.value( String.valueOf( value ) );
+ }
+ } else { // CompositeNode
+ Preconditions.checkState( node instanceof CompositeNode,
+ "Data representation of Container should be CompositeNode - " + node.getNodeType() );
+
+ writeContainer( writer, (CompositeNode) node, null );
+ }
+ }
+
private DataSchemaNode findFirstSchemaForNode(final Node<?> node, final Set<DataSchemaNode> dataSchemaNode) {
for (DataSchemaNode dsn : dataSchemaNode) {
if (node.getNodeType().equals(dsn.getQName())) {
private void writeName(final Node<?> node, final DataSchemaNode schema, final JsonWriter writer) throws IOException {
String nameForOutput = node.getNodeType().getLocalName();
- if (schema.isAugmenting()) {
+ if ( schema != null && schema.isAugmenting()) {
ControllerContext contContext = ControllerContext.getInstance();
CharSequence moduleName = null;
if (mountPoint == null) {
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.core.Response;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.Provider;
import org.opendaylight.controller.sal.rest.api.Draft02;
import org.opendaylight.controller.sal.rest.api.RestconfService;
+import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
@Provider
@Consumes({ Draft02.MediaTypes.DATA + RestconfService.JSON, Draft02.MediaTypes.OPERATION + RestconfService.JSON,
public enum JsonToCompositeNodeProvider implements MessageBodyReader<CompositeNode> {
INSTANCE;
+ private final static Logger LOG = LoggerFactory.getLogger( JsonToCompositeNodeProvider.class );
+
@Override
public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return true;
JsonReader jsonReader = new JsonReader();
try {
return jsonReader.read(entityStream);
- } catch (UnsupportedFormatException e) {
- throw new WebApplicationException(e, Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage())
- .build());
+ } catch (Exception e) {
+ LOG.debug( "Error parsing json input", e );
+ throw new RestconfDocumentedException(
+ "Error parsing input: " + e.getMessage(),
+ ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE );
}
}
import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
import org.opendaylight.controller.sal.restconf.impl.RestconfImpl;
+import com.google.common.collect.ImmutableSet;
+
public class RestconfApplication extends Application {
+ @Override
+ public Set<Class<?>> getClasses() {
+ return ImmutableSet.<Class<?>>of( RestconfDocumentedExceptionMapper.class );
+ }
+
@Override
public Set<Object> getSingletons() {
Set<Object> singletons = new HashSet<>();
return singletons;
}
+
}
--- /dev/null
+/*
+ * Copyright (c) 2014 Brocade Communications 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.rest.impl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+import java.util.List;
+import java.util.Map.Entry;
+
+import javax.activation.UnsupportedDataTypeException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import static org.opendaylight.controller.sal.rest.api.Draft02.RestConfModule.*;
+
+import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
+import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError;
+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.ImmutableCompositeNode;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils;
+import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.gson.stream.JsonWriter;
+
+/**
+ * This class defines an ExceptionMapper that handles RestconfDocumentedExceptions thrown by
+ * resource implementations and translates appropriately to restconf error response as defined in
+ * the RESTCONF RFC draft.
+ *
+ * @author Thomas Pantelis
+ */
+@Provider
+public class RestconfDocumentedExceptionMapper implements ExceptionMapper<RestconfDocumentedException> {
+
+ private final static Logger LOG = LoggerFactory.getLogger( RestconfDocumentedExceptionMapper.class );
+
+ @Context
+ private HttpHeaders headers;
+
+ @Override
+ public Response toResponse( RestconfDocumentedException exception ) {
+
+ LOG.debug( "In toResponse: {}", exception.getMessage() );
+
+ // Default to the content type if there's no Accept header
+
+ MediaType mediaType = headers.getMediaType();
+
+ List<MediaType> accepts = headers.getAcceptableMediaTypes();
+
+ LOG.debug( "Accept headers: {}", accepts );
+
+ if( accepts != null && accepts.size() > 0 ) {
+ mediaType = accepts.get( 0 ); // just pick the first one
+ }
+
+ LOG.debug( "Using MediaType: {}", mediaType );
+
+ List<RestconfError> errors = exception.getErrors();
+ if( errors.isEmpty() ) {
+ // We don't actually want to send any content but, if we don't set any content here,
+ // the tomcat front-end will send back an html error report. To prevent that, set a
+ // single space char in the entity.
+
+ return Response.status( exception.getStatus() )
+ .type( MediaType.TEXT_PLAIN_TYPE )
+ .entity( " " ).build();
+ }
+
+ Status status = errors.iterator().next().getErrorTag().getStatusCode();
+
+ ControllerContext context = ControllerContext.getInstance();
+ DataNodeContainer errorsSchemaNode = (DataNodeContainer)context.getRestconfModuleErrorsSchemaNode();
+
+ if( errorsSchemaNode == null ) {
+ return Response.status( status )
+ .type( MediaType.TEXT_PLAIN_TYPE )
+ .entity( exception.getMessage() ).build();
+ }
+
+ ImmutableList.Builder<Node<?>> errorNodes = ImmutableList.<Node<?>> builder();
+ for( RestconfError error: errors ) {
+ errorNodes.add( toDomNode( error ) );
+ }
+
+ ImmutableCompositeNode errorsNode =
+ ImmutableCompositeNode.create( ERRORS_CONTAINER_QNAME, errorNodes.build() );
+
+ Object responseBody;
+ if( mediaType.getSubtype().endsWith( "json" ) ) {
+ responseBody = toJsonResponseBody( errorsNode, errorsSchemaNode );
+ }
+ else {
+ responseBody = toXMLResponseBody( errorsNode, errorsSchemaNode );
+ }
+
+ return Response.status( status ).type( mediaType ).entity( responseBody ).build();
+ }
+
+ private Object toJsonResponseBody( ImmutableCompositeNode errorsNode,
+ DataNodeContainer errorsSchemaNode ) {
+
+ JsonMapper jsonMapper = new JsonMapper();
+
+ Object responseBody = null;
+ try {
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+ JsonWriter writer = new JsonWriter( new OutputStreamWriter( outStream, "UTF-8" ) );
+ writer.setIndent( " " );
+
+ jsonMapper.write( writer, errorsNode, errorsSchemaNode, null );
+ writer.flush();
+
+ responseBody = outStream.toString( "UTF-8" );
+ }
+ catch( IOException e ) {
+ LOG.error( "Error writing error response body", e );
+ }
+
+ return responseBody;
+ }
+
+ private Object toXMLResponseBody( ImmutableCompositeNode errorsNode,
+ DataNodeContainer errorsSchemaNode ) {
+
+ XmlMapper xmlMapper = new XmlMapper();
+
+ Object responseBody = null;
+ try {
+ Document xmlDoc = xmlMapper.write( errorsNode, errorsSchemaNode );
+
+ responseBody = documentToString( xmlDoc );
+ }
+ catch( TransformerException | UnsupportedDataTypeException | UnsupportedEncodingException e ) {
+ LOG.error( "Error writing error response body", e );
+ }
+
+ return responseBody;
+ }
+
+ private String documentToString( Document doc ) throws TransformerException, UnsupportedEncodingException {
+ Transformer transformer = createTransformer();
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+
+ transformer.transform( new DOMSource( doc ), new StreamResult( outStream ) );
+
+ return outStream.toString( "UTF-8" );
+ }
+
+ private Transformer createTransformer() throws TransformerFactoryConfigurationError,
+ TransformerConfigurationException {
+ TransformerFactory tf = TransformerFactory.newInstance();
+ Transformer transformer = tf.newTransformer();
+ transformer.setOutputProperty( OutputKeys.OMIT_XML_DECLARATION, "no" );
+ 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" );
+ return transformer;
+ }
+
+ private Node<?> toDomNode( RestconfError error ) {
+
+ CompositeNodeBuilder<ImmutableCompositeNode> builder = ImmutableCompositeNode.builder();
+ builder.setQName( ERROR_LIST_QNAME );
+
+ addLeaf( builder, ERROR_TYPE_QNAME, error.getErrorType().getErrorTypeTag() );
+ addLeaf( builder, ERROR_TAG_QNAME, error.getErrorTag().getTagValue() );
+ addLeaf( builder, ERROR_MESSAGE_QNAME, error.getErrorMessage() );
+ addLeaf( builder, ERROR_APP_TAG_QNAME, error.getErrorAppTag() );
+
+ Node<?> errorInfoNode = parseErrorInfo( error.getErrorInfo() );
+ if( errorInfoNode != null ) {
+ builder.add( errorInfoNode );
+ }
+
+ return builder.toInstance();
+ }
+
+ private Node<?> parseErrorInfo( String errorInfo ) {
+ if( Strings.isNullOrEmpty( errorInfo ) ) {
+ return null;
+ }
+
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware( true );
+ factory.setCoalescing( true );
+ factory.setIgnoringElementContentWhitespace( true );
+ factory.setIgnoringComments( true );
+
+ // Wrap the error info content in a root <error-info> element so it can be parsed
+ // as XML. The error info content may or may not be XML. If not then it will be
+ // parsed as text content of the <error-info> element.
+
+ String errorInfoWithRoot =
+ new StringBuilder( "<error-info xmlns=\"" ).append( NAMESPACE ).append( "\">" )
+ .append( errorInfo ).append( "</error-info>" ).toString();
+
+ Document doc = null;
+ try {
+ doc = factory.newDocumentBuilder().parse(
+ new InputSource( new StringReader( errorInfoWithRoot ) ) );
+ }
+ catch( Exception e ) {
+ // TODO: what if the content is text that happens to contain invalid markup? Could
+ // wrap in CDATA and try again.
+
+ LOG.warn( "Error parsing restconf error-info, \"" + errorInfo + "\", as XML: " +
+ e.toString() );
+ return null;
+ }
+
+ Node<?> errorInfoNode = XmlDocumentUtils.toDomNode( doc );
+
+ if( errorInfoNode instanceof CompositeNode ) {
+ CompositeNode compositeNode = (CompositeNode)XmlDocumentUtils.toDomNode( doc );
+
+ // At this point the QName for the "error-info" CompositeNode doesn't contain the revision
+ // as it isn't present in the XML. So we'll copy all the child nodes and create a new
+ // CompositeNode with the full QName. This is done so the XML/JSON mapping code can
+ // locate the schema.
+
+ ImmutableList.Builder<Node<?>> childNodes = ImmutableList.builder();
+ for( Entry<QName, List<Node<?>>> entry: compositeNode.entrySet() ) {
+ childNodes.addAll( entry.getValue() );
+ }
+
+ errorInfoNode = ImmutableCompositeNode.create( ERROR_INFO_QNAME, childNodes.build() );
+ }
+
+ return errorInfoNode;
+ }
+
+ private void addLeaf( CompositeNodeBuilder<ImmutableCompositeNode> builder, QName qname,
+ String value ) {
+ if( !Strings.isNullOrEmpty( value ) ) {
+ builder.addLeaf( qname, value );
+ }
+ }
+}
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.RestconfDocumentedException;
import org.opendaylight.controller.sal.restconf.impl.StructuredData;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
@Override
public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
- return true;
+ return type.equals( StructuredData.class );
}
@Override
throws IOException, WebApplicationException {
CompositeNode data = t.getData();
if (data == null) {
- throw new ResponseException(Response.Status.NOT_FOUND, "No data exists.");
+ throw new RestconfDocumentedException(Response.Status.NOT_FOUND);
}
JsonWriter writer = new JsonWriter(new OutputStreamWriter(entityStream, "UTF-8"));
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.RestconfDocumentedException;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType;
import org.opendaylight.controller.sal.restconf.impl.StructuredData;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
@Override
public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
- return true;
+ return type.equals( StructuredData.class );
}
@Override
throws IOException, WebApplicationException {
CompositeNode data = t.getData();
if (data == null) {
- throw new ResponseException(Response.Status.NOT_FOUND, "No data exists.");
+ throw new RestconfDocumentedException(Response.Status.NOT_FOUND);
}
-
+
XmlMapper xmlMapper = new XmlMapper();
Document domTree = xmlMapper.write(data, (DataNodeContainer) t.getSchema());
try {
transformer.transform(new DOMSource(domTree), new StreamResult(entityStream));
} catch (TransformerException e) {
logger.error("Error during translation of Document to OutputStream", e);
- throw new ResponseException(Response.Status.INTERNAL_SERVER_ERROR, e.getMessage());
+ throw new RestconfDocumentedException( e.getMessage(), ErrorType.TRANSPORT,
+ ErrorTag.OPERATION_FAILED );
}
}
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.core.Response;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.Provider;
import javax.xml.stream.XMLStreamException;
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.RestconfDocumentedException;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
@Provider
@Consumes({ Draft02.MediaTypes.DATA + RestconfService.XML, Draft02.MediaTypes.OPERATION + RestconfService.XML,
public enum XmlToCompositeNodeProvider implements MessageBodyReader<CompositeNode> {
INSTANCE;
+ private final static Logger LOG = LoggerFactory.getLogger( XmlToCompositeNodeProvider.class );
+
@Override
public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return true;
try {
return xmlReader.read(entityStream);
} catch (XMLStreamException | UnsupportedFormatException e) {
- throw new ResponseException(Response.Status.BAD_REQUEST, e.getMessage());
+ LOG.debug( "Error parsing json input", e );
+ throw new RestconfDocumentedException(
+ "Error parsing input: " + e.getMessage(),
+ ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE );
}
}
import org.opendaylight.controller.sal.core.api.data.DataChangeListener;
import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
import org.opendaylight.controller.sal.core.api.mount.MountInstance;
-import org.opendaylight.controller.sal.rest.impl.RestconfProvider;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType;
import org.opendaylight.controller.sal.streams.listeners.ListenerAdapter;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.common.QName;
private void checkPreconditions() {
if( context == null || dataService == null ) {
- ResponseException _responseException = new ResponseException( Status.SERVICE_UNAVAILABLE,
- RestconfProvider.NOT_INITALIZED_MSG );
- throw _responseException;
+ throw new RestconfDocumentedException( Status.SERVICE_UNAVAILABLE );
}
}
return mountPoint.readOperationalData( path );
}
- public RpcResult<CompositeNode> invokeRpc( final QName type, final CompositeNode payload ) {
+ public Future<RpcResult<CompositeNode>> invokeRpc( final QName type, final CompositeNode payload ) {
this.checkPreconditions();
- final Future<RpcResult<CompositeNode>> future = context.rpc( type, payload );
-
- try {
- return future.get();
- }
- catch( Exception e ) {
- throw new ResponseException( e, "Error invoking RPC " + type );
- }
+ return context.rpc( type, payload );
}
public Future<RpcResult<TransactionStatus>> commitConfigurationDataPut( final InstanceIdentifier path,
if (availableNode != null) {
String errMsg = "Post Configuration via Restconf was not executed because data already exists";
BrokerFacade.LOG.warn((new StringBuilder(errMsg)).append(" : ").append(path).toString());
- // FIXME: return correct ietf-restconf:errors -> follow specification
- // (http://tools.ietf.org/html/draft-bierman-netconf-restconf-03#page-48)
- throw new ResponseException(Status.CONFLICT, errMsg);
+
+ throw new RestconfDocumentedException(
+ "Data already exists for path: " + path, ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS );
}
BrokerFacade.LOG.trace( "Post Configuration via Restconf: {}", path );
transaction.putConfigurationData( path, payload );
if (availableNode != null) {
String errMsg = "Post Configuration via Restconf was not executed because data already exists";
BrokerFacade.LOG.warn((new StringBuilder(errMsg)).append(" : ").append(path).toString());
- // FIXME: return correct ietf-restconf:errors -> follow specification
- // (http://tools.ietf.org/html/draft-bierman-netconf-restconf-03#page-48)
- throw new ResponseException(Status.CONFLICT, errMsg);
+
+ throw new RestconfDocumentedException(
+ "Data already exists for path: " + path, ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS );
}
BrokerFacade.LOG.trace( "Post Configuration via Restconf: {}", path );
transaction.putConfigurationData( path, payload );
import org.opendaylight.controller.sal.core.api.mount.MountInstance;
import org.opendaylight.controller.sal.core.api.mount.MountService;
+import org.opendaylight.controller.sal.rest.api.Draft02;
import org.opendaylight.controller.sal.rest.impl.RestUtil;
-import org.opendaylight.controller.sal.rest.impl.RestconfProvider;
import org.opendaylight.controller.sal.restconf.impl.InstanceIdWithSchemaNode;
-import org.opendaylight.controller.sal.restconf.impl.ResponseException;
import org.opendaylight.controller.sal.restconf.impl.RestCodec;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType;
import org.opendaylight.yangtools.concepts.Codec;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
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.GroupingDefinition;
import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
private void checkPreconditions() {
if( globalSchema == null ) {
- throw new ResponseException( Status.SERVICE_UNAVAILABLE, RestconfProvider.NOT_INITALIZED_MSG );
+ throw new RestconfDocumentedException( Status.SERVICE_UNAVAILABLE );
}
}
String first = pathArgs.iterator().next();
final String startModule = ControllerContext.toModuleName( first );
if( startModule == null ) {
- throw new ResponseException( Status.BAD_REQUEST,
- "First node in URI has to be in format \"moduleName:nodeName\"" );
+ throw new RestconfDocumentedException(
+ "First node in URI has to be in format \"moduleName:nodeName\"",
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
InstanceIdentifierBuilder builder = InstanceIdentifier.builder();
latestModule, null, toMountPointIdentifier );
if( iiWithSchemaNode == null ) {
- throw new ResponseException( Status.BAD_REQUEST, "URI has bad format" );
+ throw new RestconfDocumentedException(
+ "URI has bad format", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
return iiWithSchemaNode;
return builder.toString();
}
+ public Module getRestconfModule() {
+ return findModuleByNameAndRevision( Draft02.RestConfModule.IETF_RESTCONF_QNAME );
+ }
+
+ public DataSchemaNode getRestconfModuleErrorsSchemaNode() {
+ Module restconfModule = getRestconfModule();
+ if( restconfModule == null ) {
+ return null;
+ }
+
+ Set<GroupingDefinition> groupings = restconfModule.getGroupings();
+
+ final Predicate<GroupingDefinition> filter = new Predicate<GroupingDefinition>() {
+ @Override
+ public boolean apply(final GroupingDefinition g) {
+ return Objects.equal(g.getQName().getLocalName(),
+ Draft02.RestConfModule.ERRORS_GROUPING_SCHEMA_NODE);
+ }
+ };
+
+ Iterable<GroupingDefinition> filteredGroups = Iterables.filter(groupings, filter);
+
+ final GroupingDefinition restconfGrouping = Iterables.getFirst(filteredGroups, null);
+
+ List<DataSchemaNode> instanceDataChildrenByName =
+ this.findInstanceDataChildrenByName(restconfGrouping,
+ Draft02.RestConfModule.ERRORS_CONTAINER_SCHEMA_NODE);
+ return Iterables.getFirst(instanceDataChildrenByName, null);
+ }
+
+ public DataSchemaNode getRestconfModuleRestConfSchemaNode( Module inRestconfModule,
+ String schemaNodeName ) {
+ Module restconfModule = inRestconfModule;
+ if( restconfModule == null ) {
+ restconfModule = getRestconfModule();
+ }
+
+ if( restconfModule == null ) {
+ return null;
+ }
+
+ Set<GroupingDefinition> groupings = restconfModule.getGroupings();
+
+ final Predicate<GroupingDefinition> filter = new Predicate<GroupingDefinition>() {
+ @Override
+ public boolean apply(final GroupingDefinition g) {
+ return Objects.equal(g.getQName().getLocalName(),
+ Draft02.RestConfModule.RESTCONF_GROUPING_SCHEMA_NODE);
+ }
+ };
+
+ Iterable<GroupingDefinition> filteredGroups = Iterables.filter(groupings, filter);
+
+ final GroupingDefinition restconfGrouping = Iterables.getFirst(filteredGroups, null);
+
+ List<DataSchemaNode> instanceDataChildrenByName =
+ this.findInstanceDataChildrenByName(restconfGrouping,
+ Draft02.RestConfModule.RESTCONF_CONTAINER_SCHEMA_NODE);
+ final DataSchemaNode restconfContainer = Iterables.getFirst(instanceDataChildrenByName, null);
+
+ if (Objects.equal(schemaNodeName, Draft02.RestConfModule.OPERATIONS_CONTAINER_SCHEMA_NODE)) {
+ List<DataSchemaNode> instances =
+ this.findInstanceDataChildrenByName(((DataNodeContainer) restconfContainer),
+ Draft02.RestConfModule.OPERATIONS_CONTAINER_SCHEMA_NODE);
+ return Iterables.getFirst(instances, null);
+ }
+ else if(Objects.equal(schemaNodeName, Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE)) {
+ List<DataSchemaNode> instances =
+ this.findInstanceDataChildrenByName(((DataNodeContainer) restconfContainer),
+ Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE);
+ return Iterables.getFirst(instances, null);
+ }
+ else if(Objects.equal(schemaNodeName, Draft02.RestConfModule.STREAM_LIST_SCHEMA_NODE)) {
+ List<DataSchemaNode> instances =
+ this.findInstanceDataChildrenByName(((DataNodeContainer) restconfContainer),
+ Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE);
+ final DataSchemaNode modules = Iterables.getFirst(instances, null);
+ instances = this.findInstanceDataChildrenByName(((DataNodeContainer) modules),
+ Draft02.RestConfModule.STREAM_LIST_SCHEMA_NODE);
+ return Iterables.getFirst(instances, null);
+ }
+ else if(Objects.equal(schemaNodeName, Draft02.RestConfModule.MODULES_CONTAINER_SCHEMA_NODE)) {
+ List<DataSchemaNode> instances =
+ this.findInstanceDataChildrenByName(((DataNodeContainer) restconfContainer),
+ Draft02.RestConfModule.MODULES_CONTAINER_SCHEMA_NODE);
+ return Iterables.getFirst(instances, null);
+ }
+ else if(Objects.equal(schemaNodeName, Draft02.RestConfModule.MODULE_LIST_SCHEMA_NODE)) {
+ List<DataSchemaNode> instances =
+ this.findInstanceDataChildrenByName(((DataNodeContainer) restconfContainer),
+ Draft02.RestConfModule.MODULES_CONTAINER_SCHEMA_NODE);
+ final DataSchemaNode modules = Iterables.getFirst(instances, null);
+ instances = this.findInstanceDataChildrenByName(((DataNodeContainer) modules),
+ Draft02.RestConfModule.MODULE_LIST_SCHEMA_NODE);
+ return Iterables.getFirst(instances, null);
+ }
+ else if(Objects.equal(schemaNodeName, Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE)) {
+ List<DataSchemaNode> instances =
+ this.findInstanceDataChildrenByName(((DataNodeContainer) restconfContainer),
+ Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE);
+ return Iterables.getFirst(instances, null);
+ }
+
+ return null;
+ }
+
private static DataSchemaNode childByQName( final ChoiceNode container, final QName name ) {
for( final ChoiceCaseNode caze : container.getCases() ) {
final DataSchemaNode ret = ControllerContext.childByQName( caze, name );
if( Objects.equal( moduleName, ControllerContext.MOUNT_MODULE ) &&
Objects.equal( nodeName, ControllerContext.MOUNT_NODE ) ) {
if( mountPoint != null ) {
- throw new ResponseException( Status.BAD_REQUEST,
- "Restconf supports just one mount point in URI." );
+ throw new RestconfDocumentedException(
+ "Restconf supports just one mount point in URI.",
+ ErrorType.APPLICATION, ErrorTag.OPERATION_NOT_SUPPORTED );
}
if( mountService == null ) {
- throw new ResponseException( Status.SERVICE_UNAVAILABLE,
- "MountService was not found. Finding behind mount points does not work." );
+ throw new RestconfDocumentedException(
+ "MountService was not found. Finding behind mount points does not work.",
+ ErrorType.APPLICATION, ErrorTag.OPERATION_NOT_SUPPORTED );
}
final InstanceIdentifier partialPath = builder.toInstance();
final MountInstance mount = mountService.getMountPoint( partialPath );
if( mount == null ) {
LOG.debug( "Instance identifier to missing mount point: {}", partialPath );
- throw new ResponseException( Status.BAD_REQUEST,
- "Mount point does not exist." );
+ throw new RestconfDocumentedException(
+ "Mount point does not exist.", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT );
}
final SchemaContext mountPointSchema = mount.getSchemaContext();
if( mountPointSchema == null ) {
- throw new ResponseException( Status.BAD_REQUEST,
- "Mount point does not contain any schema with modules." );
+ throw new RestconfDocumentedException(
+ "Mount point does not contain any schema with modules.",
+ ErrorType.APPLICATION, ErrorTag.UNKNOWN_ELEMENT );
}
if( returnJustMountPoint ) {
final String moduleNameBehindMountPoint = toModuleName( strings.get( 1 ) );
if( moduleNameBehindMountPoint == null ) {
- throw new ResponseException( Status.BAD_REQUEST,
- "First node after mount point in URI has to be in format \"moduleName:nodeName\"" );
+ throw new RestconfDocumentedException(
+ "First node after mount point in URI has to be in format \"moduleName:nodeName\"",
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
final Module moduleBehindMountPoint = this.getLatestModule( mountPointSchema,
moduleNameBehindMountPoint );
if( moduleBehindMountPoint == null ) {
- throw new ResponseException( Status.BAD_REQUEST,
- "URI has bad format. \"" + moduleName +
- "\" module does not exist in mount point." );
+ throw new RestconfDocumentedException(
+ "\"" +moduleName + "\" module does not exist in mount point.",
+ ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT );
}
List<String> subList = strings.subList( 1, strings.size() );
if( mountPoint == null ) {
module = this.getLatestModule( globalSchema, moduleName );
if( module == null ) {
- throw new ResponseException( Status.BAD_REQUEST,
- "URI has bad format. \"" + moduleName + "\" module does not exist." );
+ throw new RestconfDocumentedException(
+ "\"" + moduleName + "\" module does not exist.",
+ ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT );
}
}
else {
module = schemaContext == null ? null :
this.getLatestModule( schemaContext, moduleName );
if( module == null ) {
- throw new ResponseException( Status.BAD_REQUEST,
- "URI has bad format. \"" + moduleName +
- "\" module does not exist in mount point." );
+ throw new RestconfDocumentedException(
+ "\"" + moduleName + "\" module does not exist in mount point.",
+ ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT );
}
}
targetNode = this.findInstanceDataChildByNameAndNamespace(
parentNode, nodeName, module.getNamespace() );;
if( targetNode == null ) {
- throw new ResponseException( Status.BAD_REQUEST,
- "URI has bad format. Possible reasons:\n" +
- "1. \"" + head + "\" was not found in parent data node.\n" +
- "2. \"" + head + "\" is behind mount point. Then it should be in format \"/" +
- MOUNT + "/" + head + "\"." );
+ throw new RestconfDocumentedException(
+ "URI has bad format. Possible reasons:\n" +
+ " 1. \"" + head + "\" was not found in parent data node.\n" +
+ " 2. \"" + head + "\" is behind mount point. Then it should be in format \"/" +
+ MOUNT + "/" + head + "\".", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
} else {
final List<DataSchemaNode> potentialSchemaNodes =
.append( "\n" );
}
- throw new ResponseException( Status.BAD_REQUEST,
+ throw new RestconfDocumentedException(
"URI has bad format. Node \"" + nodeName +
"\" is added as augment from more than one module. " +
"Therefore the node must have module name and it has to be in format \"moduleName:nodeName\"." +
"\nThe node is added as augment from modules with namespaces:\n" +
- strBuilder.toString() );
+ strBuilder.toString(), ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
if( potentialSchemaNodes.isEmpty() ) {
- throw new ResponseException( Status.BAD_REQUEST, "URI has bad format. \"" + nodeName +
- "\" was not found in parent data node.\n" );
+ throw new RestconfDocumentedException(
+ "\"" + nodeName + "\" in URI was not found in parent data node",
+ ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT );
}
targetNode = potentialSchemaNodes.iterator().next();
}
if( !this.isListOrContainer( targetNode ) ) {
- throw new ResponseException( Status.BAD_REQUEST,
- "URI has bad format. Node \"" + head +
- "\" must be Container or List yang type." );
+ throw new RestconfDocumentedException(
+ "URI has bad format. Node \"" + head + "\" must be Container or List yang type.",
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
int consumed = 1;
final ListSchemaNode listNode = ((ListSchemaNode) targetNode);
final int keysSize = listNode.getKeyDefinition().size();
if( (strings.size() - consumed) < keysSize ) {
- throw new ResponseException( Status.BAD_REQUEST, "Missing key for list \"" +
- listNode.getQName().getLocalName() + "\"." );
+ throw new RestconfDocumentedException(
+ "Missing key for list \"" + listNode.getQName().getLocalName() + "\".",
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
final List<String> uriKeyValues = strings.subList( consumed, consumed + keysSize );
{
final String uriKeyValue = uriKeyValues.get( i );
if( uriKeyValue.equals( NULL_VALUE ) ) {
- throw new ResponseException( Status.BAD_REQUEST,
- "URI has bad format. List \"" + listNode.getQName().getLocalName() +
- "\" cannot contain \"null\" value as a key." );
+ throw new RestconfDocumentedException(
+ "URI has bad format. List \"" + listNode.getQName().getLocalName() +
+ "\" cannot contain \"null\" value as a key.",
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
this.addKeyValue( keyValues, listNode.getDataChildByName( key ),
}
if( decoded == null ) {
- throw new ResponseException( Status.BAD_REQUEST, uriValue + " from URI can\'t be resolved. " +
- additionalInfo );
+ throw new RestconfDocumentedException(
+ uriValue + " from URI can't be resolved. " + additionalInfo,
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
map.put( node.getQName(), decoded );
return decodedPathArgs;
}
catch( UnsupportedEncodingException e ) {
- throw new ResponseException( Status.BAD_REQUEST,
- "Invalid URL path '" + strings + "': " + e.getMessage() );
+ throw new RestconfDocumentedException(
+ "Invalid URL path '" + strings + "': " + e.getMessage(),
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
}
return URLDecoder.decode( pathArg, URI_ENCODING_CHAR_SET );
}
catch( UnsupportedEncodingException e ) {
- throw new ResponseException( Status.BAD_REQUEST,
- "Invalid URL path arg '" + pathArg + "': " + e.getMessage() );
+ throw new RestconfDocumentedException(
+ "Invalid URL path arg '" + pathArg + "': " + e.getMessage(),
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
}
+++ /dev/null
-/*
- * Copyright (c) 2014 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.restconf.impl;
-
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.Status;
-
-public class ResponseException extends WebApplicationException {
-
- private static final long serialVersionUID = -5320114450593021655L;
-
- public ResponseException(Status status, String msg) {
- super(Response.status(status).type(MediaType.TEXT_PLAIN_TYPE).entity(msg).build());
- }
-
- public ResponseException(Throwable cause, String msg) {
- super(cause, Response.status(Status.INTERNAL_SERVER_ERROR).
- type(MediaType.TEXT_PLAIN_TYPE).entity(msg).build());
- }
-}
--- /dev/null
+/*
+ * Copyright (c) 2014 Brocade Communications 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.restconf.impl;
+
+import java.util.List;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response.Status;
+
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Unchecked exception to communicate error information, as defined in the ietf restcong draft,
+ * to be sent to the client.
+ *
+ * @author Devin Avery
+ * @author Thomas Pantelis
+ * @see {@link https://tools.ietf.org/html/draft-bierman-netconf-restconf-02}
+ */
+public class RestconfDocumentedException extends WebApplicationException {
+
+ private static final long serialVersionUID = 1L;
+
+ private final List<RestconfError> errors;
+ private final Status status;
+
+ /**
+ * Constructs an instance with an error message. The error type defaults to APPLICATION and
+ * the error tag defaults to OPERATION_FAILED.
+ *
+ * @param message A string which provides a plain text string describing the error.
+ */
+ public RestconfDocumentedException( String message ) {
+ this( message, RestconfError.ErrorType.APPLICATION, RestconfError.ErrorTag.OPERATION_FAILED );
+ }
+
+ /**
+ * Constructs an instance with an error message, error type, and error tag.
+ *
+ * @param message A string which provides a plain text string describing the error.
+ * @param errorType The enumerated type indicating the layer where the error occurred.
+ * @param errorTag The enumerated tag representing a more specific error cause.
+ */
+ public RestconfDocumentedException( String message, ErrorType errorType, ErrorTag errorTag ) {
+ this( null, new RestconfError( errorType, errorTag, message ) );
+ }
+
+ /**
+ * Constructs an instance with an error message and exception cause. The stack trace of the
+ * exception is included in the error info.
+ *
+ * @param message A string which provides a plain text string describing the error.
+ * @param cause The underlying exception cause.
+ */
+ public RestconfDocumentedException( String message, Throwable cause ) {
+ this( cause, new RestconfError( RestconfError.ErrorType.APPLICATION,
+ RestconfError.ErrorTag.OPERATION_FAILED, message,
+ null, RestconfError.toErrorInfo( cause ) ) );
+ }
+
+ /**
+ * Constructs an instance with the given error.
+ */
+ public RestconfDocumentedException( RestconfError error ) {
+ this( null, error );
+ }
+
+ /**
+ * Constructs an instance with the given errors.
+ */
+ public RestconfDocumentedException( List<RestconfError> errors ) {
+ this.errors = ImmutableList.copyOf( errors );
+ Preconditions.checkArgument( !this.errors.isEmpty(), "RestconfError list can't be empty" );
+ status = null;
+ }
+
+ /**
+ * Constructs an instance with an HTTP status and no error information.
+ *
+ * @param status the HTTP status.
+ */
+ public RestconfDocumentedException( Status status ) {
+ Preconditions.checkNotNull( status, "Status can't be null" );
+ errors = ImmutableList.of();
+ this.status = status;
+ }
+
+ private RestconfDocumentedException( Throwable cause, RestconfError error ) {
+ super( cause );
+ Preconditions.checkNotNull( error, "RestconfError can't be null" );
+ errors = ImmutableList.of( error );
+ status = null;
+ }
+
+ public List<RestconfError> getErrors() {
+ return errors;
+ }
+
+ public Status getStatus() {
+ return status;
+ }
+
+
+ @Override
+ public String getMessage() {
+ return "errors: " + errors + (status != null ? ", status: " + status : "");
+ }
+}
--- /dev/null
+/*
+* Copyright (c) 2014 Brocade Communications 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.restconf.impl;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.opendaylight.yangtools.yang.common.RpcError;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * Encapsulates a restconf error as defined in the ietf restconf draft.
+ *
+ * <br><br><b>Note:</b> Enumerations defined within are provided by the ietf restconf draft.
+ *
+ * @author Devin Avery
+ * @see {@link https://tools.ietf.org/html/draft-bierman-netconf-restconf-02}
+ */
+public class RestconfError {
+
+ public static enum ErrorType {
+ /** Errors relating to the transport layer */
+ TRANSPORT,
+ /** Errors relating to the RPC or notification layer */
+ RPC,
+ /** Errors relating to the protocol operation layer. */
+ PROTOCOL,
+ /** Errors relating to the server application layer. */
+ APPLICATION;
+
+ public String getErrorTypeTag() {
+ return name().toLowerCase();
+ }
+
+ public static ErrorType valueOfCaseInsensitive( String value )
+ {
+ try {
+ return ErrorType.valueOf( ErrorType.class, value.toUpperCase() );
+ }
+ catch( IllegalArgumentException e ) {
+ return APPLICATION;
+ }
+ }
+ }
+
+ public static enum ErrorTag {
+ IN_USE( "in-use", Status.fromStatusCode(409)),
+ INVALID_VALUE( "invalid-value", Status.fromStatusCode(400)),
+ TOO_BIG( "too-big", Status.fromStatusCode(413)),
+ MISSING_ATTRIBUTE( "missing-attribute", Status.fromStatusCode(400)),
+ BAD_ATTRIBUTE( "bad-attribute", Status.fromStatusCode(400)),
+ UNKNOWN_ATTRIBUTE( "unknown-attribute", Status.fromStatusCode(400)),
+ BAD_ELEMENT( "bad-element", Status.fromStatusCode(400)),
+ UNKNOWN_ELEMENT( "unknown-element", Status.fromStatusCode(400)),
+ UNKNOWN_NAMESPACE( "unknown-namespace", Status.fromStatusCode(400)),
+ ACCESS_DENIED( "access-denied", Status.fromStatusCode(403)),
+ LOCK_DENIED( "lock-denied", Status.fromStatusCode(409)),
+ RESOURCE_DENIED( "resource-denied", Status.fromStatusCode(409)),
+ ROLLBACK_FAILED( "rollback-failed", Status.fromStatusCode(500)),
+ DATA_EXISTS( "data-exists", Status.fromStatusCode(409)),
+ DATA_MISSING( "data-missing", Status.fromStatusCode(409)),
+ OPERATION_NOT_SUPPORTED( "operation-not-supported", Status.fromStatusCode(501)),
+ OPERATION_FAILED( "operation-failed", Status.fromStatusCode(500)),
+ PARTIAL_OPERATION( "partial-operation", Status.fromStatusCode(500)),
+ MALFORMED_MESSAGE( "malformed-message", Status.fromStatusCode(400));
+
+ private final String tagValue;
+ private final Status statusCode;
+
+ ErrorTag(final String tagValue, final Status statusCode) {
+ this.tagValue = tagValue;
+ this.statusCode = statusCode;
+ }
+
+ public String getTagValue() {
+ return this.tagValue.toLowerCase();
+ }
+
+ public static ErrorTag valueOfCaseInsensitive( String value )
+ {
+ try {
+ return ErrorTag.valueOf( ErrorTag.class, value.toUpperCase().replaceAll( "-","_" ) );
+ }
+ catch( IllegalArgumentException e ) {
+ return OPERATION_FAILED;
+ }
+ }
+
+ public Status getStatusCode() {
+ return statusCode;
+ }
+ }
+
+ private final ErrorType errorType;
+ private final ErrorTag errorTag;
+ private final String errorInfo;
+ private final String errorAppTag;
+ private final String errorMessage;
+ //TODO: Add in the error-path concept as defined in the ietf draft.
+
+ static String toErrorInfo( Throwable cause ) {
+ StringWriter writer = new StringWriter();
+ cause.printStackTrace( new PrintWriter( writer ) );
+ return writer.toString();
+ }
+
+ /**
+ * Constructs a RestConfError
+ *
+ * @param errorType The enumerated type indicating the layer where the error occurred.
+ * @param errorTag The enumerated tag representing a more specific error cause.
+ * @param errorMessage A string which provides a plain text string describing the error.
+ */
+ public RestconfError(ErrorType errorType, ErrorTag errorTag, String errorMessage) {
+ this( errorType, errorTag, errorMessage, null );
+ }
+
+ /**
+ * Constructs a RestConfError object.
+ *
+ * @param errorType The enumerated type indicating the layer where the error occurred.
+ * @param errorTag The enumerated tag representing a more specific error cause.
+ * @param errorMessage A string which provides a plain text string describing the error.
+ * @param errorAppTag A string which represents an application-specific error tag that further
+ * specifies the error cause.
+ */
+ public RestconfError(ErrorType errorType, ErrorTag errorTag, String errorMessage,
+ String errorAppTag) {
+ this( errorType, errorTag, errorMessage, errorAppTag, null );
+ }
+
+ /**
+ * Constructs a RestConfError object.
+ *
+ * @param errorType The enumerated type indicating the layer where the error occurred.
+ * @param errorTag The enumerated tag representing a more specific error cause.
+ * @param errorMessage A string which provides a plain text string describing the error.
+ * @param errorAppTag A string which represents an application-specific error tag that further
+ * specifies the error cause.
+ * @param errorInfo A string, <b>formatted as XML</b>, which contains additional error information.
+ */
+ public RestconfError(ErrorType errorType, ErrorTag errorTag, String errorMessage,
+ String errorAppTag, String errorInfo) {
+ Preconditions.checkNotNull( errorType, "Error type is required for RestConfError" );
+ Preconditions.checkNotNull( errorTag, "Error tag is required for RestConfError");
+ this.errorType = errorType;
+ this.errorTag = errorTag;
+ this.errorMessage = errorMessage;
+ this.errorAppTag = errorAppTag;
+ this.errorInfo = errorInfo;
+ }
+
+ /**
+ * Constructs a RestConfError object from an RpcError.
+ */
+ public RestconfError( RpcError rpcError ) {
+
+ this.errorType = rpcError.getErrorType() == null ? ErrorType.APPLICATION :
+ ErrorType.valueOfCaseInsensitive( rpcError.getErrorType().name() );
+
+ this.errorTag = rpcError.getTag() == null ? ErrorTag.OPERATION_FAILED :
+ ErrorTag.valueOfCaseInsensitive( rpcError.getTag().toString() );
+
+ this.errorMessage = rpcError.getMessage();
+ this.errorAppTag = rpcError.getApplicationTag();
+
+ String errorInfo = null;
+ if( rpcError.getInfo() == null ) {
+ if( rpcError.getCause() != null ) {
+ errorInfo = toErrorInfo( rpcError.getCause() );
+ }
+ else if( rpcError.getSeverity() != null ) {
+ errorInfo = "<severity>" + rpcError.getSeverity().toString().toLowerCase() +
+ "</severity>";
+ }
+ }
+ else {
+ errorInfo = rpcError.getInfo();
+ }
+
+ this.errorInfo = errorInfo;
+ }
+
+ public ErrorType getErrorType() {
+ return errorType;
+ }
+
+ public ErrorTag getErrorTag() {
+ return errorTag;
+ }
+
+ public String getErrorInfo() {
+ return errorInfo;
+ }
+
+ public String getErrorAppTag() {
+ return errorAppTag;
+ }
+
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+
+ @Override
+ public String toString() {
+ return "error-type: " + errorType.getErrorTypeTag()
+ + ", error-tag: " + errorTag.getTagValue() + ", "
+ + (errorAppTag != null ? "error-app-tag: " + errorAppTag + ", " : "")
+ + (errorMessage != null ? "error-message: " + errorMessage : "")
+ + (errorInfo != null ? "error-info: " + errorInfo + ", " : "") + "]";
+ }
+
+}
\ No newline at end of file
*/
package org.opendaylight.controller.sal.restconf.impl;
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
import java.net.URI;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import org.apache.commons.lang3.StringUtils;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
import org.opendaylight.controller.sal.core.api.mount.MountInstance;
+import org.opendaylight.controller.sal.rest.api.Draft02;
import org.opendaylight.controller.sal.rest.api.RestconfService;
import org.opendaylight.controller.sal.restconf.rpc.impl.BrokerRpcExecutor;
import org.opendaylight.controller.sal.restconf.rpc.impl.MountPointRpcExecutor;
import org.opendaylight.controller.sal.restconf.rpc.impl.RpcExecutor;
+import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
+import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
+import org.opendaylight.controller.sal.restconf.impl.EmptyNodeWrapper;
+import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO;
+import org.opendaylight.controller.sal.restconf.impl.InstanceIdWithSchemaNode;
+import org.opendaylight.controller.sal.restconf.impl.NodeWrapper;
+import org.opendaylight.controller.sal.restconf.impl.RestCodec;
+import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper;
+import org.opendaylight.controller.sal.restconf.impl.StructuredData;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType;
import org.opendaylight.controller.sal.streams.listeners.ListenerAdapter;
import org.opendaylight.controller.sal.streams.listeners.Notificator;
import org.opendaylight.controller.sal.streams.websockets.WebSocketServer;
import org.opendaylight.yangtools.concepts.Codec;
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.opendaylight.yangtools.yang.model.api.DataNodeContainer;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.FeatureDefinition;
-import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder;
-import com.google.common.base.Objects;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Predicate;
-import com.google.common.base.Splitter;
-import com.google.common.base.Strings;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-
-@SuppressWarnings("all")
public class RestconfImpl implements RestconfService {
private final static RestconfImpl INSTANCE = new RestconfImpl();
private final static SimpleDateFormat REVISION_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
- private final static String RESTCONF_MODULE_DRAFT02_REVISION = "2013-10-19";
-
- private final static String RESTCONF_MODULE_DRAFT02_NAME = "ietf-restconf";
-
- private final static String RESTCONF_MODULE_DRAFT02_NAMESPACE = "urn:ietf:params:xml:ns:yang:ietf-restconf";
-
- private final static String RESTCONF_MODULE_DRAFT02_RESTCONF_GROUPING_SCHEMA_NODE = "restconf";
-
- private final static String RESTCONF_MODULE_DRAFT02_RESTCONF_CONTAINER_SCHEMA_NODE = "restconf";
-
- private final static String RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE = "modules";
-
- private final static String RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE = "module";
-
- private final static String RESTCONF_MODULE_DRAFT02_STREAMS_CONTAINER_SCHEMA_NODE = "streams";
-
- private final static String RESTCONF_MODULE_DRAFT02_STREAM_LIST_SCHEMA_NODE = "stream";
-
- private final static String RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE = "operations";
-
private final static String SAL_REMOTE_NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote";
private final static String SAL_REMOTE_RPC_SUBSRCIBE = "create-data-change-event-subscription";
final Module restconfModule = this.getRestconfModule();
final List<Node<?>> modulesAsData = new ArrayList<Node<?>>();
- final DataSchemaNode moduleSchemaNode =
- this.getSchemaNode(restconfModule, RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE);
+ final DataSchemaNode moduleSchemaNode = controllerContext.getRestconfModuleRestConfSchemaNode(
+ restconfModule, Draft02.RestConfModule.MODULE_LIST_SCHEMA_NODE);
Set<Module> allModules = this.controllerContext.getAllModules();
for (final Module module : allModules) {
modulesAsData.add(moduleCompositeNode);
}
- final DataSchemaNode modulesSchemaNode =
- this.getSchemaNode(restconfModule, RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE);
+ final DataSchemaNode modulesSchemaNode = controllerContext.getRestconfModuleRestConfSchemaNode(
+ restconfModule, Draft02.RestConfModule.MODULES_CONTAINER_SCHEMA_NODE);
QName qName = modulesSchemaNode.getQName();
final CompositeNode modulesNode = NodeFactory.createImmutableCompositeNode(qName, null, modulesAsData);
return new StructuredData(modulesNode, modulesSchemaNode, null);
final List<Node<?>> streamsAsData = new ArrayList<Node<?>>();
Module restconfModule = this.getRestconfModule();
- final DataSchemaNode streamSchemaNode =
- this.getSchemaNode(restconfModule, RESTCONF_MODULE_DRAFT02_STREAM_LIST_SCHEMA_NODE);
+ final DataSchemaNode streamSchemaNode = controllerContext.getRestconfModuleRestConfSchemaNode(
+ restconfModule, Draft02.RestConfModule.STREAM_LIST_SCHEMA_NODE);
for (final String streamName : availableStreams) {
streamsAsData.add(this.toStreamCompositeNode(streamName, streamSchemaNode));
}
- final DataSchemaNode streamsSchemaNode =
- this.getSchemaNode(restconfModule, RESTCONF_MODULE_DRAFT02_STREAMS_CONTAINER_SCHEMA_NODE);
+ final DataSchemaNode streamsSchemaNode = controllerContext.getRestconfModuleRestConfSchemaNode(
+ restconfModule, Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE);
QName qName = streamsSchemaNode.getQName();
final CompositeNode streamsNode = NodeFactory.createImmutableCompositeNode(qName, null, streamsAsData);
return new StructuredData(streamsNode, streamsSchemaNode, null);
modules = this.controllerContext.getAllModules(mountPoint);
}
else {
- throw new ResponseException(Status.BAD_REQUEST,
- "URI has bad format. If modules behind mount point should be showed, URI has to end with " +
- ControllerContext.MOUNT);
+ throw new RestconfDocumentedException(
+ "URI has bad format. If modules behind mount point should be showed, URI has to end with " +
+ ControllerContext.MOUNT, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
final List<Node<?>> modulesAsData = new ArrayList<Node<?>>();
Module restconfModule = this.getRestconfModule();
- final DataSchemaNode moduleSchemaNode =
- this.getSchemaNode(restconfModule, RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE);
+ final DataSchemaNode moduleSchemaNode = controllerContext.getRestconfModuleRestConfSchemaNode(
+ restconfModule, Draft02.RestConfModule.MODULE_LIST_SCHEMA_NODE);
for (final Module module : modules) {
modulesAsData.add(this.toModuleCompositeNode(module, moduleSchemaNode));
}
- final DataSchemaNode modulesSchemaNode =
- this.getSchemaNode(restconfModule, RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE);
+ final DataSchemaNode modulesSchemaNode = controllerContext.getRestconfModuleRestConfSchemaNode(
+ restconfModule, Draft02.RestConfModule.MODULES_CONTAINER_SCHEMA_NODE);
QName qName = modulesSchemaNode.getQName();
final CompositeNode modulesNode = NodeFactory.createImmutableCompositeNode(qName, null, modulesAsData);
return new StructuredData(modulesNode, modulesSchemaNode, mountPoint);
}
if (module == null) {
- throw new ResponseException(Status.BAD_REQUEST,
+ throw new RestconfDocumentedException(
"Module with name '" + moduleNameAndRevision.getLocalName() + "' and revision '" +
- moduleNameAndRevision.getRevision() + "' was not found.");
+ moduleNameAndRevision.getRevision() + "' was not found.",
+ ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT );
}
Module restconfModule = this.getRestconfModule();
- final DataSchemaNode moduleSchemaNode =
- this.getSchemaNode(restconfModule, RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE);
+ final DataSchemaNode moduleSchemaNode = controllerContext.getRestconfModuleRestConfSchemaNode(
+ restconfModule, Draft02.RestConfModule.MODULE_LIST_SCHEMA_NODE);
final CompositeNode moduleNode = this.toModuleCompositeNode(module, moduleSchemaNode);
return new StructuredData(moduleNode, moduleSchemaNode, mountPoint);
}
modules = this.controllerContext.getAllModules(mountPoint);
}
else {
- throw new ResponseException(Status.BAD_REQUEST,
- "URI has bad format. If operations behind mount point should be showed, URI has to end with " +
- ControllerContext.MOUNT);
+ throw new RestconfDocumentedException(
+ "URI has bad format. If operations behind mount point should be showed, URI has to end with " +
+ ControllerContext.MOUNT, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
return this.operationsFromModulesToStructuredData(modules, mountPoint);
final MountInstance mountPoint) {
final List<Node<?>> operationsAsData = new ArrayList<Node<?>>();
Module restconfModule = this.getRestconfModule();
- final DataSchemaNode operationsSchemaNode =
- this.getSchemaNode(restconfModule, RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE);
+ final DataSchemaNode operationsSchemaNode = controllerContext.getRestconfModuleRestConfSchemaNode(
+ restconfModule, Draft02.RestConfModule.OPERATIONS_CONTAINER_SCHEMA_NODE);
QName qName = operationsSchemaNode.getQName();
SchemaPath path = operationsSchemaNode.getPath();
ContainerSchemaNodeBuilder containerSchemaNodeBuilder =
- new ContainerSchemaNodeBuilder(RESTCONF_MODULE_DRAFT02_NAME, 0, qName, path);
+ new ContainerSchemaNodeBuilder(Draft02.RestConfModule.NAME, 0, qName, path);
final ContainerSchemaNodeBuilder fakeOperationsSchemaNode = containerSchemaNodeBuilder;
for (final Module module : modules) {
Set<RpcDefinition> rpcs = module.getRpcs();
}
private Module getRestconfModule() {
- QName qName = QName.create(RESTCONF_MODULE_DRAFT02_NAMESPACE, RESTCONF_MODULE_DRAFT02_REVISION,
- RESTCONF_MODULE_DRAFT02_NAME);
- final Module restconfModule = this.controllerContext.findModuleByNameAndRevision(qName);
+ Module restconfModule = controllerContext.getRestconfModule();
if (restconfModule == null) {
- throw new ResponseException(Status.INTERNAL_SERVER_ERROR, "Restconf module was not found.");
+ throw new RestconfDocumentedException(
+ "ietf-restconf module was not found.", ErrorType.APPLICATION,
+ ErrorTag.OPERATION_NOT_SUPPORTED );
}
return restconfModule;
Iterable<String> split = splitter.split(moduleNameAndRevision);
final List<String> pathArgs = Lists.<String>newArrayList(split);
if (pathArgs.size() < 2) {
- throw new ResponseException(Status.BAD_REQUEST,
- "URI has bad format. End of URI should be in format \'moduleName/yyyy-MM-dd\'");
+ throw new RestconfDocumentedException(
+ "URI has bad format. End of URI should be in format \'moduleName/yyyy-MM-dd\'",
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
try {
return QName.create(null, moduleRevision, moduleName);
}
catch (ParseException e) {
- throw new ResponseException(Status.BAD_REQUEST, "URI has bad format. It should be \'moduleName/yyyy-MM-dd\'");
+ throw new RestconfDocumentedException(
+ "URI has bad format. It should be \'moduleName/yyyy-MM-dd\'",
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
}
return NodeFactory.createImmutableCompositeNode(moduleSchemaNode.getQName(), null, moduleNodeValues);
}
- private DataSchemaNode getSchemaNode(final Module restconfModule, final String schemaNodeName) {
- Set<GroupingDefinition> groupings = restconfModule.getGroupings();
-
- final Predicate<GroupingDefinition> filter = new Predicate<GroupingDefinition>() {
- @Override
- public boolean apply(final GroupingDefinition g) {
- return Objects.equal(g.getQName().getLocalName(),
- RESTCONF_MODULE_DRAFT02_RESTCONF_GROUPING_SCHEMA_NODE);
- }
- };
-
- Iterable<GroupingDefinition> filteredGroups = Iterables.filter(groupings, filter);
-
- final GroupingDefinition restconfGrouping = Iterables.getFirst(filteredGroups, null);
-
- List<DataSchemaNode> instanceDataChildrenByName =
- this.controllerContext.findInstanceDataChildrenByName(restconfGrouping,
- RESTCONF_MODULE_DRAFT02_RESTCONF_CONTAINER_SCHEMA_NODE);
- final DataSchemaNode restconfContainer = Iterables.getFirst(instanceDataChildrenByName, null);
-
- if (Objects.equal(schemaNodeName, RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE)) {
- List<DataSchemaNode> instances =
- this.controllerContext.findInstanceDataChildrenByName(((DataNodeContainer) restconfContainer),
- RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE);
- return Iterables.getFirst(instances, null);
- }
- else if(Objects.equal(schemaNodeName, RESTCONF_MODULE_DRAFT02_STREAMS_CONTAINER_SCHEMA_NODE)) {
- List<DataSchemaNode> instances =
- this.controllerContext.findInstanceDataChildrenByName(((DataNodeContainer) restconfContainer),
- RESTCONF_MODULE_DRAFT02_STREAMS_CONTAINER_SCHEMA_NODE);
- return Iterables.getFirst(instances, null);
- }
- else if(Objects.equal(schemaNodeName, RESTCONF_MODULE_DRAFT02_STREAM_LIST_SCHEMA_NODE)) {
- List<DataSchemaNode> instances =
- this.controllerContext.findInstanceDataChildrenByName(((DataNodeContainer) restconfContainer),
- RESTCONF_MODULE_DRAFT02_STREAMS_CONTAINER_SCHEMA_NODE);
- final DataSchemaNode modules = Iterables.getFirst(instances, null);
- instances = this.controllerContext.findInstanceDataChildrenByName(((DataNodeContainer) modules),
- RESTCONF_MODULE_DRAFT02_STREAM_LIST_SCHEMA_NODE);
- return Iterables.getFirst(instances, null);
- }
- else if(Objects.equal(schemaNodeName, RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE)) {
- List<DataSchemaNode> instances =
- this.controllerContext.findInstanceDataChildrenByName(((DataNodeContainer) restconfContainer),
- RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE);
- return Iterables.getFirst(instances, null);
- }
- else if(Objects.equal(schemaNodeName, RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE)) {
- List<DataSchemaNode> instances =
- this.controllerContext.findInstanceDataChildrenByName(((DataNodeContainer) restconfContainer),
- RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE);
- final DataSchemaNode modules = Iterables.getFirst(instances, null);
- instances = this.controllerContext.findInstanceDataChildrenByName(((DataNodeContainer) modules),
- RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE);
- return Iterables.getFirst(instances, null);
- }
-
- return null;
- }
-
@Override
public Object getRoot() {
return null;
final Object pathValue = pathNode == null ? null : pathNode.getValue();
if (!(pathValue instanceof InstanceIdentifier)) {
- throw new ResponseException(Status.INTERNAL_SERVER_ERROR,
- "Instance identifier was not normalized correctly.");
+ throw new RestconfDocumentedException(
+ "Instance identifier was not normalized correctly.",
+ ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED );
}
final InstanceIdentifier pathIdentifier = ((InstanceIdentifier) pathValue);
}
if (Strings.isNullOrEmpty(streamName)) {
- throw new ResponseException(Status.BAD_REQUEST,
- "Path is empty or contains data node which is not Container or List build-in type.");
+ throw new RestconfDocumentedException(
+ "Path is empty or contains data node which is not Container or List build-in type.",
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
final SimpleNode<String> streamNameNode = NodeFactory.<String>createImmutableSimpleNode(
@Override
public StructuredData invokeRpc(final String identifier, final String noPayload) {
if (StringUtils.isNotBlank(noPayload)) {
- throw new ResponseException(
- Status.UNSUPPORTED_MEDIA_TYPE, "Content-Type contains unsupported Media Type.");
+ throw new RestconfDocumentedException(
+ "Content must be empty.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
final RpcExecutor rpc = resolveIdentifierInInvokeRpc(identifier);
return callRpc(rpc, null);
.format("Identifier %n%s%ncan\'t contain slash "
+ "character (/).%nIf slash is part of identifier name then use %%2F placeholder.",
identifier);
- throw new ResponseException(Status.NOT_FOUND, slashErrorMsg);
+ throw new RestconfDocumentedException(
+ slashErrorMsg, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
} else {
identifierEncoded = identifier;
}
RpcDefinition rpc = controllerContext.getRpcDefinition(identifierDecoded);
if (rpc == null) {
- throw new ResponseException(Status.NOT_FOUND, "RPC does not exist.");
+ throw new RestconfDocumentedException(
+ "RPC does not exist.", ErrorType.RPC, ErrorTag.UNKNOWN_ELEMENT );
}
if (mountPoint == null) {
private StructuredData callRpc(final RpcExecutor rpcExecutor, final CompositeNode payload) {
if (rpcExecutor == null) {
- throw new ResponseException(Status.NOT_FOUND, "RPC does not exist.");
+ throw new RestconfDocumentedException(
+ "RPC does not exist.", ErrorType.RPC, ErrorTag.UNKNOWN_ELEMENT );
}
CompositeNode rpcRequest = null;
private void checkRpcSuccessAndThrowException(RpcResult<CompositeNode> rpcResult) {
if (rpcResult.isSuccessful() == false) {
- //TODO: Get smart about what error code we are return (Future Bug coming)
- throw new ResponseException(Status.INTERNAL_SERVER_ERROR,
- "The operation was not successful and there were no RPC errors returned");
+
+ Collection<RpcError> rpcErrors = rpcResult.getErrors();
+ if( rpcErrors == null || rpcErrors.isEmpty() ) {
+ throw new RestconfDocumentedException(
+ "The operation was not successful and there were no RPC errors returned",
+ ErrorType.RPC, ErrorTag.OPERATION_FAILED );
+ }
+
+ List<RestconfError> errorList = Lists.newArrayList();
+ for( RpcError rpcError: rpcErrors ) {
+ errorList.add( new RestconfError( rpcError ) );
+ }
+
+ throw new RestconfDocumentedException( errorList );
}
}
}
}
catch( Exception e ) {
- throw new ResponseException( e, "Error updating data" );
+ throw new RestconfDocumentedException( "Error updating data", e );
}
if( status.getResult() == TransactionStatus.COMMITED )
public Response createConfigurationData(final String identifier, final CompositeNode payload) {
URI payloadNS = this.namespace(payload);
if (payloadNS == null) {
- throw new ResponseException(Status.BAD_REQUEST,
- "Data has bad format. Root element node must have namespace (XML format) or module name(JSON format)");
+ throw new RestconfDocumentedException(
+ "Data has bad format. Root element node must have namespace (XML format) or module name(JSON format)",
+ ErrorType.PROTOCOL, ErrorTag.UNKNOWN_NAMESPACE );
}
InstanceIdWithSchemaNode iiWithData = null;
// payload represents mount point data and URI represents path to the mount point
if (this.endsWithMountPoint(identifier)) {
- throw new ResponseException(Status.BAD_REQUEST,
- "URI has bad format. URI should be without \"" + ControllerContext.MOUNT +
- "\" for POST operation.");
+ throw new RestconfDocumentedException(
+ "URI has bad format. URI should be without \"" + ControllerContext.MOUNT +
+ "\" for POST operation.",
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
final String completeIdentifier = this.addMountPointIdentifier(identifier);
MountInstance mountPoint = incompleteInstIdWithData.getMountPoint();
final Module module = this.findModule(mountPoint, payload);
if (module == null) {
- throw new ResponseException(Status.BAD_REQUEST,
- "Module was not found for \"" + payloadNS + "\"");
+ throw new RestconfDocumentedException(
+ "Module was not found for \"" + payloadNS + "\"",
+ ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT );
}
String payloadName = this.getName(payload);
status = future == null ? null : future.get();
}
}
- catch( ResponseException e ){ throw e; }
catch( Exception e ) {
- throw new ResponseException( e, "Error creating data" );
+ throw new RestconfDocumentedException( "Error creating data", e );
}
if (status == null) {
public Response createConfigurationData(final CompositeNode payload) {
URI payloadNS = this.namespace(payload);
if (payloadNS == null) {
- throw new ResponseException(Status.BAD_REQUEST,
- "Data has bad format. Root element node must have namespace (XML format) or module name(JSON format)");
+ throw new RestconfDocumentedException(
+ "Data has bad format. Root element node must have namespace (XML format) or module name(JSON format)",
+ ErrorType.PROTOCOL, ErrorTag.UNKNOWN_NAMESPACE );
}
final Module module = this.findModule(null, payload);
if (module == null) {
- throw new ResponseException(Status.BAD_REQUEST,
- "Data has bad format. Root element node has incorrect namespace (XML format) or module name(JSON format)");
+ throw new RestconfDocumentedException(
+ "Data has bad format. Root element node has incorrect namespace (XML format) or module name(JSON format)",
+ ErrorType.PROTOCOL, ErrorTag.UNKNOWN_NAMESPACE );
}
String payloadName = this.getName(payload);
status = future == null ? null : future.get();
}
}
- catch( ResponseException e ){ throw e; }
catch( Exception e ) {
- throw new ResponseException( e, "Error creating data" );
+ throw new RestconfDocumentedException( "Error creating data", e );
}
if (status == null) {
}
}
catch( Exception e ) {
- throw new ResponseException( e, "Error creating data" );
+ throw new RestconfDocumentedException( "Error creating data", e );
}
if( status.getResult() == TransactionStatus.COMMITED )
public Response subscribeToStream(final String identifier, final UriInfo uriInfo) {
final String streamName = Notificator.createStreamNameFromUri(identifier);
if (Strings.isNullOrEmpty(streamName)) {
- throw new ResponseException(Status.BAD_REQUEST, "Stream name is empty.");
+ throw new RestconfDocumentedException(
+ "Stream name is empty.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
final ListenerAdapter listener = Notificator.getListenerFor(streamName);
if (listener == null) {
- throw new ResponseException(Status.BAD_REQUEST, "Stream was not found.");
+ throw new RestconfDocumentedException(
+ "Stream was not found.", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT );
}
broker.registerToListenDataChanges(listener);
}
if (dataNodeKeyValueObject == null) {
- throw new ResponseException(Status.BAD_REQUEST,
- "Data contains list \"" + dataNode.getNodeType().getLocalName() +
- "\" which does not contain key: \"" + key.getLocalName() + "\"");
+ throw new RestconfDocumentedException(
+ "Data contains list \"" + dataNode.getNodeType().getLocalName() +
+ "\" which does not contain key: \"" + key.getLocalName() + "\"",
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
keyValues.put(key, dataNodeKeyValueObject);
if (schema == null) {
QName nodeType = node == null ? null : node.getNodeType();
String localName = nodeType == null ? null : nodeType.getLocalName();
- String _plus = ("Data schema node was not found for " + localName);
- throw new ResponseException(Status.INTERNAL_SERVER_ERROR,
- "Data schema node was not found for " + localName );
+
+ throw new RestconfDocumentedException(
+ "Data schema node was not found for " + localName,
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
if (!(schema instanceof DataNodeContainer)) {
- throw new ResponseException(Status.BAD_REQUEST,
- "Root element has to be container or list yang datatype.");
+ throw new RestconfDocumentedException(
+ "Root element has to be container or list yang datatype.",
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
if ((node instanceof CompositeNodeWrapper)) {
try {
this.normalizeNode(((CompositeNodeWrapper) node), schema, null, mountPoint);
}
- catch (NumberFormatException e) {
- throw new ResponseException(Status.BAD_REQUEST, e.getMessage());
+ catch (IllegalArgumentException e) {
+ throw new RestconfDocumentedException(
+ e.getMessage(), ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
}
final DataSchemaNode schema, final QName previousAugment,
final MountInstance mountPoint) {
if (schema == null) {
- throw new ResponseException(Status.BAD_REQUEST,
- "Data has bad format.\n\"" + nodeBuilder.getLocalName() +
- "\" does not exist in yang schema.");
+ throw new RestconfDocumentedException(
+ "Data has bad format.\n\"" + nodeBuilder.getLocalName() +
+ "\" does not exist in yang schema.",
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
QName currentAugment = null;
else {
currentAugment = this.normalizeNodeName(nodeBuilder, schema, previousAugment, mountPoint);
if (nodeBuilder.getQname() == null) {
- throw new ResponseException(Status.BAD_REQUEST,
+ throw new RestconfDocumentedException(
"Data has bad format.\nIf data is in XML format then namespace for \"" +
nodeBuilder.getLocalName() +
"\" should be \"" + schema.getQName().getNamespace() + "\".\n" +
"If data is in JSON format then module name for \"" + nodeBuilder.getLocalName() +
"\" should be corresponding to namespace \"" +
- schema.getQName().getNamespace() + "\".");
+ schema.getQName().getNamespace() + "\".",
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
}
.append("\n");
}
- throw new ResponseException(Status.BAD_REQUEST,
+ throw new RestconfDocumentedException(
"Node \"" + child.getLocalName() +
"\" is added as augment from more than one module. " +
"Therefore node must have namespace (XML format) or module name (JSON format)." +
- "\nThe node is added as augment from modules with namespaces:\n" + builder);
+ "\nThe node is added as augment from modules with namespaces:\n" + builder,
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
boolean rightNodeSchemaFound = false;
}
if (!rightNodeSchemaFound) {
- throw new ResponseException(Status.BAD_REQUEST,
- "Schema node \"" + child.getLocalName() + "\" was not found in module.");
+ throw new RestconfDocumentedException(
+ "Schema node \"" + child.getLocalName() + "\" was not found in module.",
+ ErrorType.APPLICATION, ErrorTag.UNKNOWN_ELEMENT );
}
}
}
if (!foundKey) {
- throw new ResponseException(Status.BAD_REQUEST,
+ throw new RestconfDocumentedException(
"Missing key in URI \"" + listKey.getLocalName() +
- "\" of list \"" + schema.getQName().getLocalName() + "\"");
+ "\" of list \"" + schema.getQName().getLocalName() + "\"",
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
}
}
*/
package org.opendaylight.controller.sal.restconf.rpc.impl;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
public abstract class AbstractRpcExecutor implements RpcExecutor {
public RpcDefinition getRpcDefinition() {
return rpcDef;
}
+
+ protected RpcResult<CompositeNode> getRpcResult(
+ Future<RpcResult<CompositeNode>> fromFuture ) {
+ try {
+ return fromFuture.get();
+ }
+ catch( InterruptedException e ) {
+ throw new RestconfDocumentedException(
+ "The operation was interrupted while executing and did not complete.",
+ ErrorType.RPC, ErrorTag.PARTIAL_OPERATION );
+ }
+ catch( ExecutionException e ) {
+ Throwable cause = e.getCause();
+ if( cause instanceof CancellationException ) {
+ throw new RestconfDocumentedException(
+ "The operation was cancelled while executing.",
+ ErrorType.RPC, ErrorTag.PARTIAL_OPERATION );
+ }
+ else if( cause != null ){
+ while( cause.getCause() != null ) {
+ cause = cause.getCause();
+ }
+
+ if( cause instanceof IllegalArgumentException ) {
+ throw new RestconfDocumentedException(
+ cause.getMessage(), ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
+ }
+
+ throw new RestconfDocumentedException(
+ "The operation encountered an unexpected error while executing.", cause );
+ }
+ else {
+ throw new RestconfDocumentedException(
+ "The operation encountered an unexpected error while executing.", e );
+ }
+ }
+ }
}
\ No newline at end of file
@Override
public RpcResult<CompositeNode> invokeRpc(CompositeNode rpcRequest) {
- return broker.invokeRpc( getRpcDefinition().getQName(), rpcRequest );
+ return getRpcResult( broker.invokeRpc( getRpcDefinition().getQName(), rpcRequest ) );
}
}
\ No newline at end of file
*/
package org.opendaylight.controller.sal.restconf.rpc.impl;
-import java.util.concurrent.ExecutionException;
-
-import javax.ws.rs.core.Response.Status;
-
import org.opendaylight.controller.sal.core.api.mount.MountInstance;
-import org.opendaylight.controller.sal.restconf.impl.ResponseException;
+import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
import com.google.common.base.Preconditions;
-import com.google.common.util.concurrent.ListenableFuture;
/**
* Provides an implementation which invokes rpc methods via a mounted yang data model.
}
@Override
- public RpcResult<CompositeNode> invokeRpc( CompositeNode rpcRequest ) throws ResponseException {
- ListenableFuture<RpcResult<CompositeNode>> rpcFuture =
- mountPoint.rpc( getRpcDefinition().getQName(), rpcRequest);
- try {
- return rpcFuture.get();
- } catch (InterruptedException | ExecutionException e) {
- throw new ResponseException(Status.INTERNAL_SERVER_ERROR,
- e.getCause().getMessage() );
- }
+ public RpcResult<CompositeNode> invokeRpc( CompositeNode rpcRequest )
+ throws RestconfDocumentedException {
+ return getRpcResult( mountPoint.rpc( getRpcDefinition().getQName(), rpcRequest ) );
}
}
\ No newline at end of file
package org.opendaylight.controller.sal.restconf.impl.json.to.cnsn.test;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.List;
import java.util.Set;
-import javax.ws.rs.WebApplicationException;
-
import org.junit.Ignore;
import org.junit.Test;
import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider;
import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
-import org.opendaylight.controller.sal.restconf.impl.ResponseException;
+import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.gson.JsonSyntaxException;
-
public class JsonToCnSnTest {
private static final Logger LOG = LoggerFactory.getLogger(JsonToCnSnTest.class);
@Test
public void incorrectTopLevelElementsTest() {
- Throwable cause1 = null;
+ RestconfDocumentedException cause1 = null;
try {
- TestUtils
- .readInputToCnSn("/json-to-cnsn/wrong-top-level1.json", true, JsonToCompositeNodeProvider.INSTANCE);
- } catch (WebApplicationException e) {
+ TestUtils.readInputToCnSn("/json-to-cnsn/wrong-top-level1.json", true, JsonToCompositeNodeProvider.INSTANCE);
+ } catch (RestconfDocumentedException e) {
cause1 = e;
}
assertNotNull(cause1);
- assertTrue(cause1
- .getCause()
- .getMessage()
- .contains(
- "First element in Json Object has to be \"Object\" or \"Array with one Object element\". Other scenarios are not supported yet."));
+ assertTrue(cause1.getErrors().get( 0 ).getErrorMessage().contains(
+ "First element in Json Object has to be \"Object\" or \"Array with one Object element\". Other scenarios are not supported yet."));
- Throwable cause2 = null;
+ RestconfDocumentedException cause2 = null;
try {
TestUtils
- .readInputToCnSn("/json-to-cnsn/wrong-top-level2.json", true, JsonToCompositeNodeProvider.INSTANCE);
- } catch (WebApplicationException e) {
+ .readInputToCnSn("/json-to-cnsn/wrong-top-level2.json", true, JsonToCompositeNodeProvider.INSTANCE);
+ } catch (RestconfDocumentedException e) {
cause2 = e;
}
assertNotNull(cause2);
- assertTrue(cause2.getCause().getMessage().contains("Json Object should contain one element"));
+ assertTrue(cause2.getErrors().get( 0 ).getErrorMessage().contains(
+ "Json Object should contain one element"));
- Throwable cause3 = null;
+ RestconfDocumentedException cause3 = null;
try {
TestUtils
- .readInputToCnSn("/json-to-cnsn/wrong-top-level3.json", true, JsonToCompositeNodeProvider.INSTANCE);
- } catch (WebApplicationException e) {
+
+ .readInputToCnSn("/json-to-cnsn/wrong-top-level3.json", true, JsonToCompositeNodeProvider.INSTANCE);
+ } catch (RestconfDocumentedException e) {
cause3 = e;
}
assertNotNull(cause3);
- assertTrue(cause3
- .getCause()
- .getMessage()
- .contains(
- "First element in Json Object has to be \"Object\" or \"Array with one Object element\". Other scenarios are not supported yet."));
+ assertTrue(cause3.getErrors().get( 0 ).getErrorMessage().contains(
+ "First element in Json Object has to be \"Object\" or \"Array with one Object element\". Other scenarios are not supported yet."));
}
String reason = null;
try {
TestUtils.readInputToCnSn("/json-to-cnsn/empty-data1.json", true, JsonToCompositeNodeProvider.INSTANCE);
- } catch (JsonSyntaxException e) {
- reason = e.getMessage();
+ } catch (RestconfDocumentedException e) {
+ reason = e.getErrors().get( 0 ).getErrorMessage();
}
assertTrue(reason.contains("Expected value at line"));
@Ignore
@Test
public void loadDataAugmentedSchemaMoreEqualNamesTest() {
- boolean exceptionCaught = false;
- try {
- loadAndNormalizeData("/common/augment/json/dataa.json", "/common/augment/yang", "cont", "main");
- loadAndNormalizeData("/common/augment/json/datab.json", "/common/augment/yang", "cont", "main");
- } catch (ResponseException e) {
- exceptionCaught = true;
- }
+ loadAndNormalizeData("/common/augment/json/dataa.json", "/common/augment/yang", "cont", "main");
+ loadAndNormalizeData("/common/augment/json/datab.json", "/common/augment/yang", "cont", "main");
- assertFalse(exceptionCaught);
}
private void simpleTest(final String jsonPath, final String yangPath, final String topLevelElementName, final String namespace,
try {
TestUtils.readInputToCnSn("/json-to-cnsn/unsupported-json-format.json", true,
JsonToCompositeNodeProvider.INSTANCE);
- } catch (WebApplicationException e) {
- exceptionMessage = e.getCause().getMessage();
+ } catch (RestconfDocumentedException e) {
+ exceptionMessage = e.getErrors().get( 0 ).getErrorMessage();
}
assertTrue(exceptionMessage.contains("Root element of Json has to be Object"));
}
package org.opendaylight.controller.sal.restconf.impl.test;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import java.util.Map;
import java.util.concurrent.Future;
-import javax.ws.rs.core.Response.Status;
-
import org.junit.Before;
import org.junit.Test;
import org.mockito.InOrder;
import org.opendaylight.controller.sal.core.api.mount.MountInstance;
import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider;
import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
-import org.opendaylight.controller.sal.restconf.impl.ResponseException;
+import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError;
import org.opendaylight.controller.sal.streams.listeners.ListenerAdapter;
import org.opendaylight.controller.sal.streams.listeners.Notificator;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
assertSame( "readOperationalDataBehindMountPoint", dataNode, actualNode );
}
- @Test(expected=ResponseException.class)
+ @Test(expected=RestconfDocumentedException.class)
public void testReadOperationalDataWithNoDataBroker() {
brokerFacade.setDataService( null );
@SuppressWarnings("unchecked")
@Test
- public void testInvokeRpc() {
+ public void testInvokeRpc() throws Exception {
RpcResult<CompositeNode> expResult = mock( RpcResult.class );
Future<RpcResult<CompositeNode>> future = Futures.immediateFuture( expResult );
when( mockConsumerSession.rpc( qname, dataNode ) ).thenReturn( future );
- RpcResult<CompositeNode> actualResult = brokerFacade.invokeRpc( qname, dataNode );
+ Future<RpcResult<CompositeNode>> actualFuture = brokerFacade.invokeRpc( qname, dataNode );
+ assertNotNull( "Future is null", actualFuture );
+ RpcResult<CompositeNode> actualResult = actualFuture.get();
assertSame( "invokeRpc", expResult, actualResult );
}
- @Test(expected=ResponseException.class)
- public void testInvokeRpcWithException() {
- Exception mockEx = new Exception( "mock" );
- Future<RpcResult<CompositeNode>> future = Futures.immediateFailedFuture( mockEx );
- when( mockConsumerSession.rpc( qname, dataNode ) ).thenReturn( future );
-
- brokerFacade.invokeRpc( qname, dataNode );
- }
-
- @Test(expected=ResponseException.class)
+ @Test(expected=RestconfDocumentedException.class)
public void testInvokeRpcWithNoConsumerSession() {
brokerFacade.setContext( null );
inOrder.verify( mockTransaction ).commit();
}
- @Test(expected=ResponseException.class)
+ @Test(expected=RestconfDocumentedException.class)
public void testCommitConfigurationDataPostAlreadyExists() {
when( dataBroker.beginTransaction() ).thenReturn( mockTransaction );
mockTransaction.putConfigurationData( instanceID, dataNode );
.thenReturn( dataNode );
try {
brokerFacade.commitConfigurationDataPost( instanceID, dataNode );
- } catch (ResponseException e) {
- assertEquals("Unexpect Exception Status -> "
- + "http://tools.ietf.org/html/draft-bierman-netconf-restconf-03#page-48",
- (e.getResponse().getStatus()), Status.CONFLICT.getStatusCode());
+ }
+ catch (RestconfDocumentedException e) {
+ assertEquals("getErrorTag",
+ RestconfError.ErrorTag.DATA_EXISTS, e.getErrors().get( 0 ).getErrorTag());
throw e;
}
}
inOrder.verify( mockTransaction ).commit();
}
- @Test(expected=ResponseException.class)
+ @Test(expected=RestconfDocumentedException.class)
public void testCommitConfigurationDataPostBehindMountPointAlreadyExists() {
when( mockMountInstance.beginTransaction() ).thenReturn( mockTransaction );
try {
brokerFacade.commitConfigurationDataPostBehindMountPoint( mockMountInstance,
instanceID, dataNode );
- } catch (ResponseException e) {
- assertEquals("Unexpect Exception Status -> "
- + "http://tools.ietf.org/html/draft-bierman-netconf-restconf-03#page-48",
- e.getResponse().getStatus(), Status.CONFLICT.getStatusCode());
+ }
+ catch (RestconfDocumentedException e) {
+ assertEquals("getErrorTag",
+ RestconfError.ErrorTag.DATA_EXISTS, e.getErrors().get( 0 ).getErrorTag());
throw e;
}
}
import org.junit.BeforeClass;
import org.junit.Test;
import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider;
+import org.opendaylight.controller.sal.rest.impl.RestconfDocumentedExceptionMapper;
import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider;
resourceConfig = resourceConfig.registerInstances(restConf, StructuredDataToXmlProvider.INSTANCE,
StructuredDataToJsonProvider.INSTANCE, XmlToCompositeNodeProvider.INSTANCE,
JsonToCompositeNodeProvider.INSTANCE);
+ resourceConfig.registerClasses( RestconfDocumentedExceptionMapper.class );
return resourceConfig;
}
import java.io.FileNotFoundException;
import java.net.URI;
import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.HashSet;
-import java.util.LinkedList;
import java.util.List;
import java.util.Set;
-import javax.ws.rs.core.Response.Status;
-
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
+import org.opendaylight.controller.sal.common.util.RpcErrors;
+import org.opendaylight.controller.sal.common.util.Rpcs;
import org.opendaylight.controller.sal.core.api.mount.MountInstance;
import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
import org.opendaylight.controller.sal.restconf.impl.InstanceIdWithSchemaNode;
-import org.opendaylight.controller.sal.restconf.impl.ResponseException;
+import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType;
import org.opendaylight.controller.sal.restconf.impl.RestconfImpl;
import org.opendaylight.controller.sal.restconf.impl.StructuredData;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorSeverity;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.data.api.ModifyAction;
import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
public class InvokeRpcMethodTest {
private RestconfImpl restconfImpl = null;
private static ControllerContext controllerContext = null;
- private class AnswerImpl implements Answer<RpcResult<CompositeNode>> {
- @Override
- public RpcResult<CompositeNode> answer(final InvocationOnMock invocation) throws Throwable {
- CompositeNode compNode = (CompositeNode) invocation.getArguments()[1];
- return new DummyRpcResult.Builder<CompositeNode>().result(compNode).isSuccessful(true).build();
- }
- }
@BeforeClass
public static void init() throws FileNotFoundException {
restconf.setBroker(mockedBrokerFacade);
restconf.setControllerContext(contContext);
- when(mockedBrokerFacade.invokeRpc(any(QName.class), any(CompositeNode.class))).thenAnswer(new AnswerImpl());
+ CompositeNode payload = preparePayload();
+
+ when(mockedBrokerFacade.invokeRpc(any(QName.class), any(CompositeNode.class)))
+ .thenReturn( Futures.<RpcResult<CompositeNode>>immediateFuture(
+ Rpcs.<CompositeNode>getRpcResult( true ) ) );
- StructuredData structData = restconf.invokeRpc("invoke-rpc-module:rpc-test", preparePayload());
+ StructuredData structData = restconf.invokeRpc("invoke-rpc-module:rpc-test", payload);
assertTrue(structData == null);
}
@Test
public void testInvokeRpcWithNoPayloadRpc_FailNoErrors() {
- RpcResult<CompositeNode> rpcResult = mock(RpcResult.class);
- when(rpcResult.isSuccessful()).thenReturn(false);
+ RpcResult<CompositeNode> rpcResult = Rpcs.<CompositeNode>getRpcResult( false );
- ArgumentCaptor<CompositeNode> payload = ArgumentCaptor
- .forClass(CompositeNode.class);
BrokerFacade brokerFacade = mock(BrokerFacade.class);
- when(
- brokerFacade.invokeRpc(
- eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast")),
- payload.capture())).thenReturn(rpcResult);
+ when( brokerFacade.invokeRpc(
+ eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast")),
+ any(CompositeNode.class)))
+ .thenReturn( Futures.<RpcResult<CompositeNode>>immediateFuture( rpcResult ) );
restconfImpl.setBroker(brokerFacade);
try {
restconfImpl.invokeRpc("toaster:cancel-toast", "");
fail("Expected an exception to be thrown.");
- } catch (ResponseException e) {
- assertEquals(e.getMessage(),
- Status.INTERNAL_SERVER_ERROR.getStatusCode(), e
- .getResponse().getStatus());
+ }
+ catch (RestconfDocumentedException e) {
+ verifyRestconfDocumentedException( e, 0, ErrorType.RPC, ErrorTag.OPERATION_FAILED,
+ Optional.<String>absent(), Optional.<String>absent() );
}
}
- @Test
- public void testInvokeRpcWithNoPayloadRpc_FailWithRpcError() {
- List<RpcError> rpcErrors = new LinkedList<RpcError>();
+ void verifyRestconfDocumentedException( final RestconfDocumentedException e, final int index,
+ final ErrorType expErrorType, final ErrorTag expErrorTag,
+ final Optional<String> expErrorMsg,
+ final Optional<String> expAppTag ) {
+ RestconfError actual = null;
+ try {
+ actual = e.getErrors().get( index );
+ }
+ catch( ArrayIndexOutOfBoundsException ex ) {
+ fail( "RestconfError not found at index " + index );
+ }
+
+ assertEquals( "getErrorType", expErrorType, actual.getErrorType() );
+ assertEquals( "getErrorTag", expErrorTag, actual.getErrorTag() );
+ assertNotNull( "getErrorMessage is null", actual.getErrorMessage() );
+
+ if( expErrorMsg.isPresent() ) {
+ assertEquals( "getErrorMessage", expErrorMsg.get(), actual.getErrorMessage() );
+ }
- RpcError unknownError = mock(RpcError.class);
- when( unknownError.getTag() ).thenReturn( "bogusTag" );
- rpcErrors.add( unknownError );
+ if( expAppTag.isPresent() ) {
+ assertEquals( "getErrorAppTag", expAppTag.get(), actual.getErrorAppTag() );
+ }
+ }
- RpcError knownError = mock( RpcError.class );
- when( knownError.getTag() ).thenReturn( "in-use" );
- rpcErrors.add( knownError );
+ @Test
+ public void testInvokeRpcWithNoPayloadRpc_FailWithRpcError() {
+ List<RpcError> rpcErrors = Arrays.asList(
+ RpcErrors.getRpcError( null, "bogusTag", null, ErrorSeverity.ERROR, "foo",
+ RpcError.ErrorType.TRANSPORT, null ),
+ RpcErrors.getRpcError( "app-tag", "in-use", null, ErrorSeverity.WARNING, "bar",
+ RpcError.ErrorType.RPC, null ));
- RpcResult<CompositeNode> rpcResult = mock(RpcResult.class);
- when(rpcResult.isSuccessful()).thenReturn(false);
- when(rpcResult.getErrors()).thenReturn( rpcErrors );
+ RpcResult<CompositeNode> rpcResult = Rpcs.<CompositeNode>getRpcResult( false, rpcErrors );
- ArgumentCaptor<CompositeNode> payload = ArgumentCaptor
- .forClass(CompositeNode.class);
BrokerFacade brokerFacade = mock(BrokerFacade.class);
- when(
- brokerFacade.invokeRpc(
- eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast")),
- payload.capture())).thenReturn(rpcResult);
+ when( brokerFacade.invokeRpc(
+ eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast")),
+ any(CompositeNode.class)))
+ .thenReturn( Futures.<RpcResult<CompositeNode>>immediateFuture( rpcResult ) );
restconfImpl.setBroker(brokerFacade);
try {
restconfImpl.invokeRpc("toaster:cancel-toast", "");
fail("Expected an exception to be thrown.");
- } catch (ResponseException e) {
- //TODO: Change to a 409 in the future - waiting on additional BUG to enhance this.
- assertEquals(e.getMessage(), 500, e.getResponse().getStatus());
+ }
+ catch (RestconfDocumentedException e) {
+ verifyRestconfDocumentedException( e, 0, ErrorType.TRANSPORT, ErrorTag.OPERATION_FAILED,
+ Optional.of( "foo" ), Optional.<String>absent() );
+ verifyRestconfDocumentedException( e, 1, ErrorType.RPC, ErrorTag.IN_USE,
+ Optional.of( "bar" ), Optional.of( "app-tag" ) );
}
}
@Test
public void testInvokeRpcWithNoPayload_Success() {
- RpcResult<CompositeNode> rpcResult = mock(RpcResult.class);
- when(rpcResult.isSuccessful()).thenReturn(true);
+ RpcResult<CompositeNode> rpcResult = Rpcs.<CompositeNode>getRpcResult( true );
BrokerFacade brokerFacade = mock(BrokerFacade.class);
- when(
- brokerFacade.invokeRpc(
- eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast")),
- any( CompositeNode.class ))).thenReturn(rpcResult);
+ when( brokerFacade.invokeRpc(
+ eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast")),
+ any( CompositeNode.class )))
+ .thenReturn( Futures.<RpcResult<CompositeNode>>immediateFuture( rpcResult ) );
restconfImpl.setBroker(brokerFacade);
try {
restconfImpl.invokeRpc("toaster:cancel-toast", " a payload ");
fail("Expected an exception");
- } catch (ResponseException e) {
- assertEquals(e.getMessage(),
- Status.UNSUPPORTED_MEDIA_TYPE.getStatusCode(), e
- .getResponse().getStatus());
+ } catch (RestconfDocumentedException e) {
+ verifyRestconfDocumentedException( e, 0, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
+ Optional.<String>absent(), Optional.<String>absent() );
}
}
try {
restconfImpl.invokeRpc("toaster:bad-method", "");
fail("Expected an exception");
- } catch (ResponseException e) {
- assertEquals(e.getMessage(), Status.NOT_FOUND.getStatusCode(), e
- .getResponse().getStatus());
+ }
+ catch (RestconfDocumentedException e) {
+ verifyRestconfDocumentedException( e, 0, ErrorType.RPC, ErrorTag.UNKNOWN_ELEMENT,
+ Optional.<String>absent(), Optional.<String>absent() );
}
}
@Test
public void testInvokeRpcMethodWithInput() {
- RpcResult<CompositeNode> rpcResult = mock(RpcResult.class);
- when(rpcResult.isSuccessful()).thenReturn(true);
+ RpcResult<CompositeNode> rpcResult = Rpcs.<CompositeNode>getRpcResult( true );
CompositeNode payload = mock(CompositeNode.class);
BrokerFacade brokerFacade = mock(BrokerFacade.class);
- when(
- brokerFacade.invokeRpc(
- eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)make-toast")),
- any(CompositeNode.class))).thenReturn(rpcResult);
+ when( brokerFacade.invokeRpc(
+ eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)make-toast")),
+ any(CompositeNode.class)))
+ .thenReturn( Futures.<RpcResult<CompositeNode>>immediateFuture( rpcResult ) );
restconfImpl.setBroker(brokerFacade);
try {
restconfImpl.invokeRpc("toaster/slash", "");
fail("Expected an exception.");
- } catch (ResponseException e) {
- assertEquals(e.getMessage(), Status.NOT_FOUND.getStatusCode(), e
- .getResponse().getStatus());
+ }
+ catch (RestconfDocumentedException e) {
+ verifyRestconfDocumentedException( e, 0, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
+ Optional.<String>absent(), Optional.<String>absent() );
}
}
@Test
public void testInvokeRpcWithNoPayloadWithOutput_Success() {
- RpcResult<CompositeNode> rpcResult = mock(RpcResult.class);
- when(rpcResult.isSuccessful()).thenReturn(true);
-
CompositeNode compositeNode = mock( CompositeNode.class );
- when( rpcResult.getResult() ).thenReturn( compositeNode );
+ RpcResult<CompositeNode> rpcResult = Rpcs.<CompositeNode>getRpcResult( true, compositeNode,
+ Collections.<RpcError>emptyList() );
BrokerFacade brokerFacade = mock(BrokerFacade.class);
when( brokerFacade.invokeRpc(
- eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)testOutput")),
- any( CompositeNode.class ))).thenReturn(rpcResult);
+ eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)testOutput")),
+ any( CompositeNode.class )))
+ .thenReturn( Futures.<RpcResult<CompositeNode>>immediateFuture( rpcResult ) );
restconfImpl.setBroker(brokerFacade);
- StructuredData output = restconfImpl.invokeRpc("toaster:testOutput",
- "");
+ StructuredData output = restconfImpl.invokeRpc("toaster:testOutput", "");
assertNotNull( output );
assertSame( compositeNode, output.getData() );
assertNotNull( output.getSchema() );
@Test
public void testMountedRpcCallNoPayload_Success() throws Exception
{
- RpcResult<CompositeNode> rpcResult = mock(RpcResult.class);
- when(rpcResult.isSuccessful()).thenReturn(true);
+ RpcResult<CompositeNode> rpcResult = Rpcs.<CompositeNode>getRpcResult( true );
ListenableFuture<RpcResult<CompositeNode>> mockListener = mock( ListenableFuture.class );
when( mockListener.get() ).thenReturn( rpcResult );
//additional validation in the fact that the restconfImpl does not throw an exception.
}
-
-
}
import org.junit.BeforeClass;
import org.junit.Test;
import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
-import org.opendaylight.controller.sal.restconf.impl.ResponseException;
+import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
dataLoad("/normalize-node/yang/");
}
- @Test
+ @Test(expected=RestconfDocumentedException.class)
public void namespaceNotNullAndInvalidNamespaceAndNoModuleNameTest() {
- boolean exceptionReised = false;
- try {
- TestUtils.normalizeCompositeNode(prepareCnSn("wrongnamespace"), modules, schemaNodePath);
- } catch (ResponseException e) {
- exceptionReised = true;
- }
- assertTrue(exceptionReised);
+
+ TestUtils.normalizeCompositeNode(prepareCnSn("wrongnamespace"), modules, schemaNodePath);
}
@Test
public void namespaceNullTest() {
- String exceptionMessage = null;
- try {
- TestUtils.normalizeCompositeNode(prepareCnSn(null), modules, schemaNodePath);
- } catch (ResponseException e) {
- exceptionMessage = String.valueOf(e.getResponse().getEntity());
- }
- assertNull(exceptionMessage);
+
+ TestUtils.normalizeCompositeNode(prepareCnSn(null), modules, schemaNodePath);
}
@Test
public void namespaceValidNamespaceTest() {
- String exceptionMessage = null;
- try {
- TestUtils.normalizeCompositeNode(prepareCnSn("normalize:node:module"), modules, schemaNodePath);
- } catch (ResponseException e) {
- exceptionMessage = String.valueOf(e.getResponse().getEntity());
- }
- assertNull(exceptionMessage);
+
+ TestUtils.normalizeCompositeNode(prepareCnSn("normalize:node:module"), modules, schemaNodePath);
}
@Test
public void namespaceValidModuleNameTest() {
- String exceptionMessage = null;
- try {
- TestUtils.normalizeCompositeNode(prepareCnSn("normalize-node-module"), modules, schemaNodePath);
- } catch (ResponseException e) {
- exceptionMessage = String.valueOf(e.getResponse().getEntity());
- }
- assertNull(exceptionMessage);
+
+ TestUtils.normalizeCompositeNode(prepareCnSn("normalize-node-module"), modules, schemaNodePath);
}
private CompositeNode prepareCnSn(String namespace) {
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import java.io.FileNotFoundException;
import org.junit.rules.ExpectedException;
import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
import org.opendaylight.controller.sal.restconf.impl.InstanceIdWithSchemaNode;
-import org.opendaylight.controller.sal.restconf.impl.ResponseException;
+import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
public class RestGetAugmentedElementWhenEqualNamesTest {
-
+
private static ControllerContext controllerContext = ControllerContext.getInstance();
-
+
@Rule
public ExpectedException exception = ExpectedException.none();
-
+
@BeforeClass
public static void init() throws FileNotFoundException {
SchemaContext schemaContextTestModule = TestUtils.loadSchemaContext("/common/augment/yang");
iiWithData = controllerContext.toInstanceIdentifier("main:cont/augment-main-b:cont1");
assertEquals("ns:augment:main:b", iiWithData.getSchemaNode().getQName().getNamespace().toString());
}
-
+
@Test
public void nodeWithoutNamespaceHasMoreAugments() {
- boolean exceptionCaught = false;
try {
controllerContext.toInstanceIdentifier("main:cont/cont1");
- } catch (ResponseException e) {
- assertTrue(((String) e.getResponse().getEntity()).contains("is added as augment from more than one module"));
- exceptionCaught = true;
+ fail( "Expected exception" );
+ } catch (RestconfDocumentedException e) {
+ assertTrue(e.getErrors().get( 0 ).getErrorMessage().contains(
+ "is added as augment from more than one module"));
}
- assertTrue(exceptionCaught);
}
-
}
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.BeforeClass;
-import org.junit.Ignore;
import org.junit.Test;
import org.opendaylight.controller.sal.core.api.mount.MountInstance;
import org.opendaylight.controller.sal.core.api.mount.MountService;
import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider;
+import org.opendaylight.controller.sal.rest.impl.RestconfDocumentedExceptionMapper;
import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider;
resourceConfig = resourceConfig.registerInstances(restconfImpl, StructuredDataToXmlProvider.INSTANCE,
StructuredDataToJsonProvider.INSTANCE, XmlToCompositeNodeProvider.INSTANCE,
JsonToCompositeNodeProvider.INSTANCE);
+ resourceConfig.registerClasses( RestconfDocumentedExceptionMapper.class );
return resourceConfig;
}
/**
* MountPoint test. URI represents mount point.
- *
+ *
* Slashes in URI behind mount point. lst1 element with key
* GigabitEthernet0%2F0%2F0%2F0 (GigabitEthernet0/0/0/0) is requested via
* GET HTTP operation. It is tested whether %2F character is replaced with
* simple / in InstanceIdentifier parameter in method
* {@link BrokerFacade#readConfigurationDataBehindMountPoint(MountInstance, InstanceIdentifier)}
* which is called in method {@link RestconfImpl#readConfigurationData}
- *
- *
+ *
+ *
* @throws ParseException
*/
@Test
import org.opendaylight.controller.sal.core.api.mount.MountService;
import org.opendaylight.controller.sal.rest.api.Draft02;
import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider;
+import org.opendaylight.controller.sal.rest.impl.RestconfDocumentedExceptionMapper;
import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import com.google.common.util.concurrent.Futures;
+
public class RestPostOperationTest extends JerseyTest {
private static String xmlDataAbsolutePath;
resourceConfig = resourceConfig.registerInstances(restconfImpl, StructuredDataToXmlProvider.INSTANCE,
StructuredDataToJsonProvider.INSTANCE, XmlToCompositeNodeProvider.INSTANCE,
JsonToCompositeNodeProvider.INSTANCE);
+ resourceConfig.registerClasses( RestconfDocumentedExceptionMapper.class );
return resourceConfig;
}
assertEquals(500, post(uri, MediaType.APPLICATION_XML, xmlDataRpcInput));
uri = "/operations/test-module:rpc-wrongtest";
- assertEquals(404, post(uri, MediaType.APPLICATION_XML, xmlDataRpcInput));
+ assertEquals(400, post(uri, MediaType.APPLICATION_XML, xmlDataRpcInput));
}
@Test
private void mockInvokeRpc(CompositeNode result, boolean sucessful) {
RpcResult<CompositeNode> rpcResult = new DummyRpcResult.Builder<CompositeNode>().result(result)
.isSuccessful(sucessful).build();
- when(brokerFacade.invokeRpc(any(QName.class), any(CompositeNode.class))).thenReturn(rpcResult);
+ when(brokerFacade.invokeRpc(any(QName.class), any(CompositeNode.class)))
+ .thenReturn(Futures.<RpcResult<CompositeNode>>immediateFuture( rpcResult ));
}
private void mockCommitConfigurationDataPostMethod(TransactionStatus statusName) {
--- /dev/null
+/*
+ * Copyright (c) 2014 Brocade Communications 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.restconf.impl.test;
+
+import static org.junit.Assert.*;
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathFactory;
+
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.sal.rest.api.Draft02;
+import org.opendaylight.controller.sal.rest.api.RestconfService;
+import org.opendaylight.controller.sal.rest.impl.RestconfDocumentedExceptionMapper;
+import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
+import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
+import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
+import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError;
+import org.opendaylight.controller.sal.restconf.impl.StructuredData;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import com.google.common.io.ByteStreams;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+
+/**
+ * Unit tests for RestconfDocumentedExceptionMapper.
+ *
+ * @author Thomas Pantelis
+ */
+public class RestconfDocumentedExceptionMapperTest extends JerseyTest {
+
+ interface ErrorInfoVerifier {
+ void verifyXML( Node errorInfoNode );
+ void verifyJson( JsonElement errorInfoElement );
+ }
+
+ static class ComplexErrorInfoVerifier implements ErrorInfoVerifier {
+
+ Map<String, String> expErrorInfo;
+
+ public ComplexErrorInfoVerifier( Map<String, String> expErrorInfo ) {
+ this.expErrorInfo = expErrorInfo;
+ }
+
+ @Override
+ public void verifyXML( Node errorInfoNode ) {
+
+ Map<String, String> mutableExpMap = Maps.newHashMap( expErrorInfo );
+ NodeList childNodes = errorInfoNode.getChildNodes();
+ for( int i = 0; i < childNodes.getLength(); i++ ) {
+ Node child = childNodes.item( i );
+ if( child instanceof Element ) {
+ String expValue = mutableExpMap.remove( child.getNodeName() );
+ assertNotNull( "Found unexpected \"error-info\" child node: " +
+ child.getNodeName(), expValue );
+ assertEquals( "Text content for \"error-info\" child node " +
+ child.getNodeName(), expValue, child.getTextContent() );
+ }
+ }
+
+ if( !mutableExpMap.isEmpty() ) {
+ fail( "Missing \"error-info\" child nodes: " + mutableExpMap );
+ }
+ }
+
+ @Override
+ public void verifyJson( JsonElement errorInfoElement ) {
+
+ assertTrue( "\"error-info\" Json element is not an Object",
+ errorInfoElement.isJsonObject() );
+
+ Map<String, String> actualErrorInfo = Maps.newHashMap();
+ for( Entry<String, JsonElement> entry: errorInfoElement.getAsJsonObject().entrySet() ) {
+ String leafName = entry.getKey();
+ JsonElement leafElement = entry.getValue();
+ actualErrorInfo.put( leafName, leafElement.getAsString() );
+ }
+
+ Map<String, String> mutableExpMap = Maps.newHashMap( expErrorInfo );
+ for( Entry<String,String> actual: actualErrorInfo.entrySet() ) {
+ String expValue = mutableExpMap.remove( actual.getKey() );
+ assertNotNull( "Found unexpected \"error-info\" child node: " +
+ actual.getKey(), expValue );
+ assertEquals( "Text content for \"error-info\" child node " +
+ actual.getKey(), expValue, actual.getValue() );
+ }
+
+ if( !mutableExpMap.isEmpty() ) {
+ fail( "Missing \"error-info\" child nodes: " + mutableExpMap );
+ }
+ }
+ }
+
+ static class SimpleErrorInfoVerifier implements ErrorInfoVerifier {
+
+ String expTextContent;
+
+ public SimpleErrorInfoVerifier( String expErrorInfo ) {
+ this.expTextContent = expErrorInfo;
+ }
+
+ void verifyContent( String actualContent ) {
+ assertNotNull( "Actual \"error-info\" text content is null", actualContent );
+ assertTrue( "", actualContent.contains( expTextContent ) );
+ }
+
+ @Override
+ public void verifyXML( Node errorInfoNode ) {
+ verifyContent( errorInfoNode.getTextContent() );
+ }
+
+ @Override
+ public void verifyJson( JsonElement errorInfoElement ) {
+ verifyContent( errorInfoElement.getAsString() );
+ }
+ }
+
+ static RestconfService mockRestConf = mock( RestconfService.class );
+
+ static XPath XPATH = XPathFactory.newInstance().newXPath();
+ static XPathExpression ERROR_LIST;
+ static XPathExpression ERROR_TYPE;
+ static XPathExpression ERROR_TAG;
+ static XPathExpression ERROR_MESSAGE;
+ static XPathExpression ERROR_APP_TAG;
+ static XPathExpression ERROR_INFO;
+
+ @BeforeClass
+ public static void init() throws Exception {
+ ControllerContext.getInstance().setGlobalSchema( TestUtils.loadSchemaContext("/modules") );
+
+ NamespaceContext nsContext = new NamespaceContext() {
+ @Override
+ public Iterator getPrefixes( String namespaceURI ) {
+ return null;
+ }
+
+ @Override
+ public String getPrefix( String namespaceURI ) {
+ return null;
+ }
+
+ @Override
+ public String getNamespaceURI( String prefix ) {
+ return "ietf-restconf".equals( prefix ) ? Draft02.RestConfModule.NAMESPACE : null;
+ }
+ };
+
+ XPATH.setNamespaceContext( nsContext );
+ ERROR_LIST = XPATH.compile( "ietf-restconf:errors/ietf-restconf:error" );
+ ERROR_TYPE = XPATH.compile( "ietf-restconf:error-type" );
+ ERROR_TAG = XPATH.compile( "ietf-restconf:error-tag" );
+ ERROR_MESSAGE = XPATH.compile( "ietf-restconf:error-message" );
+ ERROR_APP_TAG = XPATH.compile( "ietf-restconf:error-app-tag" );
+ ERROR_INFO = XPATH.compile( "ietf-restconf:error-info" );
+ }
+
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ reset( mockRestConf );
+ super.setUp();
+ }
+
+ @Override
+ protected Application configure() {
+ ResourceConfig resourceConfig = new ResourceConfig();
+ resourceConfig = resourceConfig.registerInstances( mockRestConf, StructuredDataToXmlProvider.INSTANCE,
+ StructuredDataToJsonProvider.INSTANCE );
+ resourceConfig.registerClasses( RestconfDocumentedExceptionMapper.class );
+ return resourceConfig;
+ }
+
+ void stageMockEx( RestconfDocumentedException ex ) {
+ reset( mockRestConf );
+ when( mockRestConf.readOperationalData( any( String.class ) ) ).thenThrow( ex );
+ }
+
+ void testJsonResponse( RestconfDocumentedException ex, Status expStatus, ErrorType expErrorType,
+ ErrorTag expErrorTag, String expErrorMessage, String expErrorAppTag,
+ ErrorInfoVerifier errorInfoVerifier ) throws Exception {
+
+ stageMockEx( ex );
+
+ Response resp = target("/operational/foo").request( MediaType.APPLICATION_JSON ).get();
+
+ InputStream stream = verifyResponse( resp, MediaType.APPLICATION_JSON, expStatus );
+
+ verifyJsonResponseBody( stream, expErrorType, expErrorTag, expErrorMessage,
+ expErrorAppTag, errorInfoVerifier );
+ }
+
+ @Test
+ public void testToJsonResponseWithMessageOnly() throws Exception {
+
+ testJsonResponse( new RestconfDocumentedException( "mock error" ), Status.INTERNAL_SERVER_ERROR,
+ ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, "mock error", null, null );
+
+ // To test verification code
+// String json =
+// "{ errors: {" +
+// " error: [{" +
+// " error-tag : \"operation-failed\"" +
+// " ,error-type : \"application\"" +
+// " ,error-message : \"An error occurred\"" +
+// " ,error-info : {" +
+// " session-id: \"123\"" +
+// " ,address: \"1.2.3.4\"" +
+// " }" +
+// " }]" +
+// " }" +
+// "}";
+//
+// verifyJsonResponseBody( new java.io.StringBufferInputStream(json ), ErrorType.APPLICATION,
+// ErrorTag.OPERATION_FAILED, "An error occurred", null,
+// com.google.common.collect.ImmutableMap.of( "session-id", "123", "address", "1.2.3.4" ) );
+ }
+
+ @Test
+ public void testToJsonResponseWithInUseErrorTag() throws Exception {
+
+ testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.IN_USE ),
+ Status.CONFLICT, ErrorType.PROTOCOL,
+ ErrorTag.IN_USE, "mock error", null, null );
+ }
+
+ @Test
+ public void testToJsonResponseWithInvalidValueErrorTag() throws Exception {
+
+ testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.RPC,
+ ErrorTag.INVALID_VALUE ),
+ Status.BAD_REQUEST, ErrorType.RPC,
+ ErrorTag.INVALID_VALUE, "mock error", null, null );
+
+ }
+
+ @Test
+ public void testToJsonResponseWithTooBigErrorTag() throws Exception {
+
+ testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.TRANSPORT,
+ ErrorTag.TOO_BIG ),
+ Status.REQUEST_ENTITY_TOO_LARGE, ErrorType.TRANSPORT,
+ ErrorTag.TOO_BIG, "mock error", null, null );
+
+ }
+
+ @Test
+ public void testToJsonResponseWithMissingAttributeErrorTag() throws Exception {
+
+ testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.MISSING_ATTRIBUTE ),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL,
+ ErrorTag.MISSING_ATTRIBUTE, "mock error", null, null );
+ }
+
+ @Test
+ public void testToJsonResponseWithBadAttributeErrorTag() throws Exception {
+
+ testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.BAD_ATTRIBUTE ),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL,
+ ErrorTag.BAD_ATTRIBUTE, "mock error", null, null );
+ }
+ @Test
+ public void testToJsonResponseWithUnknownAttributeErrorTag() throws Exception {
+
+ testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.UNKNOWN_ATTRIBUTE ),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL,
+ ErrorTag.UNKNOWN_ATTRIBUTE, "mock error", null, null );
+ }
+
+ @Test
+ public void testToJsonResponseWithBadElementErrorTag() throws Exception {
+
+ testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.BAD_ELEMENT ),
+ Status.BAD_REQUEST,
+ ErrorType.PROTOCOL, ErrorTag.BAD_ELEMENT, "mock error", null, null );
+ }
+
+ @Test
+ public void testToJsonResponseWithUnknownElementErrorTag() throws Exception {
+
+ testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.UNKNOWN_ELEMENT ),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL,
+ ErrorTag.UNKNOWN_ELEMENT, "mock error", null, null );
+ }
+
+ @Test
+ public void testToJsonResponseWithUnknownNamespaceErrorTag() throws Exception {
+
+ testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.UNKNOWN_NAMESPACE ),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL,
+ ErrorTag.UNKNOWN_NAMESPACE, "mock error", null, null );
+ }
+
+ @Test
+ public void testToJsonResponseWithMalformedMessageErrorTag() throws Exception {
+
+ testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.MALFORMED_MESSAGE ),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL,
+ ErrorTag.MALFORMED_MESSAGE, "mock error", null, null );
+ }
+
+ @Test
+ public void testToJsonResponseWithAccessDeniedErrorTag() throws Exception {
+
+ testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.ACCESS_DENIED ),
+ Status.FORBIDDEN, ErrorType.PROTOCOL,
+ ErrorTag.ACCESS_DENIED, "mock error", null, null );
+ }
+
+ @Test
+ public void testToJsonResponseWithLockDeniedErrorTag() throws Exception {
+
+ testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.LOCK_DENIED ),
+ Status.CONFLICT, ErrorType.PROTOCOL,
+ ErrorTag.LOCK_DENIED, "mock error", null, null );
+ }
+
+ @Test
+ public void testToJsonResponseWithResourceDeniedErrorTag() throws Exception {
+
+ testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.RESOURCE_DENIED ),
+ Status.CONFLICT, ErrorType.PROTOCOL,
+ ErrorTag.RESOURCE_DENIED, "mock error", null, null );
+ }
+
+ @Test
+ public void testToJsonResponseWithRollbackFailedErrorTag() throws Exception {
+
+ testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.ROLLBACK_FAILED ),
+ Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL,
+ ErrorTag.ROLLBACK_FAILED, "mock error", null, null );
+ }
+
+ @Test
+ public void testToJsonResponseWithDataExistsErrorTag() throws Exception {
+
+ testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.DATA_EXISTS ),
+ Status.CONFLICT, ErrorType.PROTOCOL,
+ ErrorTag.DATA_EXISTS, "mock error", null, null );
+ }
+
+ @Test
+ public void testToJsonResponseWithDataMissingErrorTag() throws Exception {
+
+ testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.DATA_MISSING ),
+ Status.CONFLICT, ErrorType.PROTOCOL,
+ ErrorTag.DATA_MISSING, "mock error", null, null );
+ }
+
+ @Test
+ public void testToJsonResponseWithOperationNotSupportedErrorTag() throws Exception {
+
+ testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.OPERATION_NOT_SUPPORTED ),
+ Status.NOT_IMPLEMENTED, ErrorType.PROTOCOL,
+ ErrorTag.OPERATION_NOT_SUPPORTED, "mock error", null, null );
+ }
+
+ @Test
+ public void testToJsonResponseWithOperationFailedErrorTag() throws Exception {
+
+ testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.OPERATION_FAILED ),
+ Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL,
+ ErrorTag.OPERATION_FAILED, "mock error", null, null );
+ }
+
+ @Test
+ public void testToJsonResponseWithPartialOperationErrorTag() throws Exception {
+
+ testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.PARTIAL_OPERATION ),
+ Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL,
+ ErrorTag.PARTIAL_OPERATION, "mock error", null, null );
+ }
+
+ @Test
+ public void testToJsonResponseWithErrorAppTag() throws Exception {
+
+ testJsonResponse( new RestconfDocumentedException( new RestconfError(
+ ErrorType.APPLICATION, ErrorTag.INVALID_VALUE,
+ "mock error", "mock-app-tag" ) ),
+ Status.BAD_REQUEST, ErrorType.APPLICATION,
+ ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag", null );
+ }
+
+ @Test
+ public void testToJsonResponseWithMultipleErrors() throws Exception {
+
+ List<RestconfError> errorList = Arrays.asList(
+ new RestconfError( ErrorType.APPLICATION, ErrorTag.LOCK_DENIED, "mock error1" ),
+ new RestconfError( ErrorType.RPC, ErrorTag.ROLLBACK_FAILED, "mock error2" ) );
+ stageMockEx( new RestconfDocumentedException( errorList ) );
+
+ Response resp = target("/operational/foo").request( MediaType.APPLICATION_JSON ).get();
+
+ InputStream stream = verifyResponse( resp, MediaType.APPLICATION_JSON, Status.CONFLICT );
+
+ JsonArray arrayElement = parseJsonErrorArrayElement( stream );
+
+ assertEquals( "\"error\" Json array element length", 2, arrayElement.size() );
+
+ verifyJsonErrorNode( arrayElement.get( 0 ), ErrorType.APPLICATION, ErrorTag.LOCK_DENIED,
+ "mock error1", null, null );
+
+ verifyJsonErrorNode( arrayElement.get( 1 ), ErrorType.RPC, ErrorTag.ROLLBACK_FAILED,
+ "mock error2", null, null );
+ }
+
+ @Test
+ public void testToJsonResponseWithErrorInfo() throws Exception {
+
+ String errorInfo = "<address>1.2.3.4</address> <session-id>123</session-id>";
+ testJsonResponse( new RestconfDocumentedException( new RestconfError(
+ ErrorType.APPLICATION, ErrorTag.INVALID_VALUE,
+ "mock error", "mock-app-tag", errorInfo ) ),
+ Status.BAD_REQUEST, ErrorType.APPLICATION,
+ ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag",
+ new ComplexErrorInfoVerifier( ImmutableMap.of(
+ "session-id", "123", "address", "1.2.3.4" ) ) );
+ }
+
+ @Test
+ public void testToJsonResponseWithExceptionCause() throws Exception {
+
+ Exception cause = new Exception( "mock exception cause" );
+ testJsonResponse( new RestconfDocumentedException( "mock error", cause ),
+ Status.INTERNAL_SERVER_ERROR, ErrorType.APPLICATION,
+ ErrorTag.OPERATION_FAILED, "mock error", null,
+ new SimpleErrorInfoVerifier( cause.getMessage() ) );
+ }
+
+ void testXMLResponse( RestconfDocumentedException ex, Status expStatus, ErrorType expErrorType,
+ ErrorTag expErrorTag, String expErrorMessage,
+ String expErrorAppTag, ErrorInfoVerifier errorInfoVerifier ) throws Exception
+ {
+ stageMockEx( ex );
+
+ Response resp = target("/operational/foo").request( MediaType.APPLICATION_XML ).get();
+
+ InputStream stream = verifyResponse( resp, MediaType.APPLICATION_XML, expStatus );
+
+ verifyXMLResponseBody( stream, expErrorType, expErrorTag, expErrorMessage,
+ expErrorAppTag, errorInfoVerifier );
+ }
+
+ @Test
+ public void testToXMLResponseWithMessageOnly() throws Exception {
+
+ testXMLResponse( new RestconfDocumentedException( "mock error" ), Status.INTERNAL_SERVER_ERROR,
+ ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, "mock error", null, null );
+
+ // To test verification code
+// String xml =
+// "<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\">"+
+// " <error>" +
+// " <error-type>application</error-type>"+
+// " <error-tag>operation-failed</error-tag>"+
+// " <error-message>An error occurred</error-message>"+
+// " <error-info>" +
+// " <session-id>123</session-id>" +
+// " <address>1.2.3.4</address>" +
+// " </error-info>" +
+// " </error>" +
+// "</errors>";
+//
+// verifyXMLResponseBody( new java.io.StringBufferInputStream(xml), ErrorType.APPLICATION,
+// ErrorTag.OPERATION_FAILED, "An error occurred", null,
+// com.google.common.collect.ImmutableMap.of( "session-id", "123", "address", "1.2.3.4" ) );
+ }
+
+ @Test
+ public void testToXMLResponseWithInUseErrorTag() throws Exception {
+
+ testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.IN_USE ),
+ Status.CONFLICT, ErrorType.PROTOCOL,
+ ErrorTag.IN_USE, "mock error", null, null );
+ }
+
+ @Test
+ public void testToXMLResponseWithInvalidValueErrorTag() throws Exception {
+
+ testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.RPC,
+ ErrorTag.INVALID_VALUE ),
+ Status.BAD_REQUEST, ErrorType.RPC,
+ ErrorTag.INVALID_VALUE, "mock error", null, null );
+ }
+
+ @Test
+ public void testToXMLResponseWithTooBigErrorTag() throws Exception {
+
+ testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.TRANSPORT,
+ ErrorTag.TOO_BIG ),
+ Status.REQUEST_ENTITY_TOO_LARGE, ErrorType.TRANSPORT,
+ ErrorTag.TOO_BIG, "mock error", null, null );
+ }
+
+ @Test
+ public void testToXMLResponseWithMissingAttributeErrorTag() throws Exception {
+
+ testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.MISSING_ATTRIBUTE ),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL,
+ ErrorTag.MISSING_ATTRIBUTE, "mock error", null, null );
+ }
+
+ @Test
+ public void testToXMLResponseWithBadAttributeErrorTag() throws Exception {
+
+ testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.BAD_ATTRIBUTE ),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL,
+ ErrorTag.BAD_ATTRIBUTE, "mock error", null, null );
+ }
+ @Test
+ public void testToXMLResponseWithUnknownAttributeErrorTag() throws Exception {
+
+ testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.UNKNOWN_ATTRIBUTE ),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL,
+ ErrorTag.UNKNOWN_ATTRIBUTE, "mock error", null, null );
+ }
+
+ @Test
+ public void testToXMLResponseWithBadElementErrorTag() throws Exception {
+
+ testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.BAD_ELEMENT ),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL,
+ ErrorTag.BAD_ELEMENT, "mock error", null, null );
+ }
+
+ @Test
+ public void testToXMLResponseWithUnknownElementErrorTag() throws Exception {
+
+ testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.UNKNOWN_ELEMENT ),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL,
+ ErrorTag.UNKNOWN_ELEMENT, "mock error", null, null );
+ }
+
+ @Test
+ public void testToXMLResponseWithUnknownNamespaceErrorTag() throws Exception {
+
+ testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.UNKNOWN_NAMESPACE ),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL,
+ ErrorTag.UNKNOWN_NAMESPACE, "mock error", null, null );
+ }
+
+ @Test
+ public void testToXMLResponseWithMalformedMessageErrorTag() throws Exception {
+
+ testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.MALFORMED_MESSAGE ),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL,
+ ErrorTag.MALFORMED_MESSAGE, "mock error", null, null );
+ }
+
+ @Test
+ public void testToXMLResponseWithAccessDeniedErrorTag() throws Exception {
+
+ testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.ACCESS_DENIED ),
+ Status.FORBIDDEN, ErrorType.PROTOCOL,
+ ErrorTag.ACCESS_DENIED, "mock error", null, null );
+ }
+
+ @Test
+ public void testToXMLResponseWithLockDeniedErrorTag() throws Exception {
+
+ testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.LOCK_DENIED ),
+ Status.CONFLICT, ErrorType.PROTOCOL,
+ ErrorTag.LOCK_DENIED, "mock error", null, null );
+ }
+
+ @Test
+ public void testToXMLResponseWithResourceDeniedErrorTag() throws Exception {
+
+ testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.RESOURCE_DENIED ),
+ Status.CONFLICT, ErrorType.PROTOCOL,
+ ErrorTag.RESOURCE_DENIED, "mock error", null, null );
+ }
+
+ @Test
+ public void testToXMLResponseWithRollbackFailedErrorTag() throws Exception {
+
+ testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.ROLLBACK_FAILED ),
+ Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL,
+ ErrorTag.ROLLBACK_FAILED, "mock error", null, null );
+ }
+
+ @Test
+ public void testToXMLResponseWithDataExistsErrorTag() throws Exception {
+
+ testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.DATA_EXISTS ),
+ Status.CONFLICT, ErrorType.PROTOCOL,
+ ErrorTag.DATA_EXISTS, "mock error", null, null );
+ }
+
+ @Test
+ public void testToXMLResponseWithDataMissingErrorTag() throws Exception {
+
+ testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.DATA_MISSING ),
+ Status.CONFLICT, ErrorType.PROTOCOL,
+ ErrorTag.DATA_MISSING, "mock error", null, null );
+ }
+
+ @Test
+ public void testToXMLResponseWithOperationNotSupportedErrorTag() throws Exception {
+
+ testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.OPERATION_NOT_SUPPORTED ),
+ Status.NOT_IMPLEMENTED, ErrorType.PROTOCOL,
+ ErrorTag.OPERATION_NOT_SUPPORTED, "mock error", null, null );
+ }
+
+ @Test
+ public void testToXMLResponseWithOperationFailedErrorTag() throws Exception {
+
+ testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.OPERATION_FAILED ),
+ Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL,
+ ErrorTag.OPERATION_FAILED, "mock error", null, null );
+ }
+
+ @Test
+ public void testToXMLResponseWithPartialOperationErrorTag() throws Exception {
+
+ testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL,
+ ErrorTag.PARTIAL_OPERATION ),
+ Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL,
+ ErrorTag.PARTIAL_OPERATION, "mock error", null, null );
+ }
+
+ @Test
+ public void testToXMLResponseWithErrorAppTag() throws Exception {
+
+ testXMLResponse( new RestconfDocumentedException( new RestconfError(
+ ErrorType.APPLICATION, ErrorTag.INVALID_VALUE,
+ "mock error", "mock-app-tag" ) ),
+ Status.BAD_REQUEST, ErrorType.APPLICATION,
+ ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag", null );
+ }
+
+ @Test
+ public void testToXMLResponseWithErrorInfo() throws Exception {
+
+ String errorInfo = "<address>1.2.3.4</address> <session-id>123</session-id>";
+ testXMLResponse( new RestconfDocumentedException( new RestconfError(
+ ErrorType.APPLICATION, ErrorTag.INVALID_VALUE,
+ "mock error", "mock-app-tag", errorInfo ) ),
+ Status.BAD_REQUEST, ErrorType.APPLICATION,
+ ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag",
+ new ComplexErrorInfoVerifier( ImmutableMap.of(
+ "session-id", "123", "address", "1.2.3.4" ) ) );
+ }
+
+ @Test
+ public void testToXMLResponseWithExceptionCause() throws Exception {
+
+ Exception cause = new Exception( "mock exception cause" );
+ testXMLResponse( new RestconfDocumentedException( "mock error", cause ),
+ Status.INTERNAL_SERVER_ERROR, ErrorType.APPLICATION,
+ ErrorTag.OPERATION_FAILED, "mock error", null,
+ new SimpleErrorInfoVerifier( cause.getMessage() ) );
+ }
+
+ @Test
+ public void testToXMLResponseWithMultipleErrors() throws Exception {
+
+ List<RestconfError> errorList = Arrays.asList(
+ new RestconfError( ErrorType.APPLICATION, ErrorTag.LOCK_DENIED, "mock error1" ),
+ new RestconfError( ErrorType.RPC, ErrorTag.ROLLBACK_FAILED, "mock error2" ) );
+ stageMockEx( new RestconfDocumentedException( errorList ) );
+
+ Response resp = target("/operational/foo").request( MediaType.APPLICATION_XML ).get();
+
+ InputStream stream = verifyResponse( resp, MediaType.APPLICATION_XML, Status.CONFLICT );
+
+ Document doc = parseXMLDocument( stream );
+
+ NodeList children = getXMLErrorList( doc, 2 );
+
+ verifyXMLErrorNode( children.item( 0 ), ErrorType.APPLICATION, ErrorTag.LOCK_DENIED,
+ "mock error1", null, null );
+
+ verifyXMLErrorNode( children.item( 1 ), ErrorType.RPC, ErrorTag.ROLLBACK_FAILED,
+ "mock error2", null, null );
+ }
+
+ @Test
+ public void testToResponseWithAcceptHeader() throws Exception {
+
+ stageMockEx( new RestconfDocumentedException( "mock error" ) );
+
+ Response resp = target("/operational/foo")
+ .request().header( "Accept", MediaType.APPLICATION_JSON ).get();
+
+ InputStream stream = verifyResponse( resp, MediaType.APPLICATION_JSON,
+ Status.INTERNAL_SERVER_ERROR );
+
+ verifyJsonResponseBody( stream, ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, "mock error",
+ null, null );
+ }
+
+ @Test
+ public void testToResponseWithStatusOnly() throws Exception {
+
+ // The StructuredDataToJsonProvider should throw a RestconfDocumentedException with no data
+
+ when( mockRestConf.readOperationalData( any( String.class ) ) )
+ .thenReturn( new StructuredData( null, null, null ) );
+
+ Response resp = target("/operational/foo").request( MediaType.APPLICATION_JSON ).get();
+
+ verifyResponse( resp, MediaType.TEXT_PLAIN, Status.NOT_FOUND );
+ }
+
+ InputStream verifyResponse( Response resp, String expMediaType, Status expStatus ) {
+ assertEquals( "getMediaType", MediaType.valueOf( expMediaType ), resp.getMediaType() );
+ assertEquals( "getStatus", expStatus.getStatusCode(), resp.getStatus() );
+
+ Object entity = resp.getEntity();
+ assertEquals( "Response entity", true, entity instanceof InputStream );
+ InputStream stream = (InputStream)entity;
+ return stream;
+ }
+
+ void verifyJsonResponseBody( InputStream stream, ErrorType expErrorType, ErrorTag expErrorTag,
+ String expErrorMessage, String expErrorAppTag,
+ ErrorInfoVerifier errorInfoVerifier ) throws Exception {
+
+ JsonArray arrayElement = parseJsonErrorArrayElement( stream );
+
+ assertEquals( "\"error\" Json array element length", 1, arrayElement.size() );
+
+ verifyJsonErrorNode( arrayElement.get( 0 ), expErrorType, expErrorTag, expErrorMessage,
+ expErrorAppTag, errorInfoVerifier );
+ }
+
+ private JsonArray parseJsonErrorArrayElement( InputStream stream ) throws IOException {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ByteStreams.copy( stream, bos );
+
+ System.out.println("JSON: "+bos.toString());
+
+ JsonParser parser = new JsonParser();
+ JsonElement rootElement;
+
+ try {
+ rootElement = parser.parse(
+ new InputStreamReader( new ByteArrayInputStream( bos.toByteArray() ) ) );
+ }
+ catch( Exception e ) {
+ throw new IllegalArgumentException( "Invalid JSON response:\n" + bos.toString(), e );
+ }
+
+ assertTrue( "Root element of Json is not an Object", rootElement.isJsonObject() );
+
+ Set<Entry<String, JsonElement>> errorsEntrySet = rootElement.getAsJsonObject().entrySet();
+ assertEquals( "Json Object element set count", 1, errorsEntrySet.size() );
+
+ Entry<String, JsonElement> errorsEntry = errorsEntrySet.iterator().next();
+ JsonElement errorsElement = errorsEntry.getValue();
+ assertEquals( "First Json element name", "errors", errorsEntry.getKey() );
+ assertTrue( "\"errors\" Json element is not an Object", errorsElement.isJsonObject() );
+
+ Set<Entry<String, JsonElement>> errorListEntrySet = errorsElement.getAsJsonObject().entrySet();
+ assertEquals( "Root \"errors\" element child count", 1, errorListEntrySet.size() );
+
+ JsonElement errorListElement = errorListEntrySet.iterator().next().getValue();
+ assertEquals( "\"errors\" child Json element name", "error",
+ errorListEntrySet.iterator().next().getKey() );
+ assertTrue( "\"error\" Json element is not an Array", errorListElement.isJsonArray() );
+
+ return errorListElement.getAsJsonArray();
+ }
+
+ void verifyJsonErrorNode( JsonElement errorEntryElement, ErrorType expErrorType, ErrorTag expErrorTag,
+ String expErrorMessage, String expErrorAppTag,
+ ErrorInfoVerifier errorInfoVerifier ) {
+
+ JsonElement errorInfoElement = null;
+ Map<String, String> actualErrorInfo = null;
+ Map<String, String> leafMap = Maps.newHashMap();
+ for( Entry<String, JsonElement> entry: errorEntryElement.getAsJsonObject().entrySet() ) {
+ String leafName = entry.getKey();
+ JsonElement leafElement = entry.getValue();
+
+ if( "error-info".equals( leafName ) ) {
+ assertNotNull( "Found unexpected \"error-info\" element", errorInfoVerifier );
+ errorInfoElement = leafElement;
+ }
+ else {
+ assertTrue( "\"error\" leaf Json element " + leafName +
+ " is not a Primitive", leafElement.isJsonPrimitive() );
+
+ leafMap.put( leafName, leafElement.getAsString() );
+ }
+ }
+
+ assertEquals( "error-type", expErrorType.getErrorTypeTag(), leafMap.remove( "error-type" ) );
+ assertEquals( "error-tag", expErrorTag.getTagValue(), leafMap.remove( "error-tag" ) );
+
+ verifyOptionalJsonLeaf( leafMap.remove( "error-message" ), expErrorMessage, "error-message" );
+ verifyOptionalJsonLeaf( leafMap.remove( "error-app-tag" ), expErrorAppTag, "error-app-tag" );
+
+ if( !leafMap.isEmpty() ) {
+ fail( "Found unexpected Json leaf elements for \"error\" element: " + leafMap );
+ }
+
+ if( errorInfoVerifier != null ) {
+ assertNotNull( "Missing \"error-info\" element", errorInfoElement );
+ errorInfoVerifier.verifyJson( errorInfoElement );
+ }
+ }
+
+ void verifyOptionalJsonLeaf( String actualValue, String expValue, String tagName ) {
+ if( expValue != null ) {
+ assertEquals( tagName, expValue, actualValue );
+ }
+ else {
+ assertNull( "Found unexpected \"error\" leaf entry for: " + tagName, actualValue );
+ }
+ }
+
+ void verifyXMLResponseBody( InputStream stream, ErrorType expErrorType, ErrorTag expErrorTag,
+ String expErrorMessage, String expErrorAppTag,
+ ErrorInfoVerifier errorInfoVerifier )
+ throws Exception {
+
+ Document doc = parseXMLDocument( stream );
+
+ NodeList children = getXMLErrorList( doc, 1 );
+
+ verifyXMLErrorNode( children.item( 0 ), expErrorType, expErrorTag, expErrorMessage,
+ expErrorAppTag, errorInfoVerifier );
+ }
+
+ private Document parseXMLDocument( InputStream stream ) throws IOException {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setCoalescing(true);
+ factory.setIgnoringElementContentWhitespace(true);
+ factory.setIgnoringComments(true);
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ByteStreams.copy( stream, bos );
+
+ System.out.println("XML: "+bos.toString());
+
+ Document doc = null;
+ try {
+ doc = factory.newDocumentBuilder().parse( new ByteArrayInputStream( bos.toByteArray() ) );
+ }
+ catch( Exception e ) {
+ throw new IllegalArgumentException( "Invalid XML response:\n" + bos.toString(), e );
+ }
+ return doc;
+ }
+
+ void verifyXMLErrorNode( Node errorNode, ErrorType expErrorType, ErrorTag expErrorTag,
+ String expErrorMessage, String expErrorAppTag,
+ ErrorInfoVerifier errorInfoVerifier ) throws Exception {
+
+ String errorType = (String)ERROR_TYPE.evaluate( errorNode, XPathConstants.STRING );
+ assertEquals( "error-type", expErrorType.getErrorTypeTag(), errorType );
+
+ String errorTag = (String)ERROR_TAG.evaluate( errorNode, XPathConstants.STRING );
+ assertEquals( "error-tag", expErrorTag.getTagValue(), errorTag );
+
+ verifyOptionalXMLLeaf( errorNode, ERROR_MESSAGE, expErrorMessage, "error-message" );
+ verifyOptionalXMLLeaf( errorNode, ERROR_APP_TAG, expErrorAppTag, "error-app-tag" );
+
+ Node errorInfoNode = (Node)ERROR_INFO.evaluate( errorNode, XPathConstants.NODE );
+ if( errorInfoVerifier != null ) {
+ assertNotNull( "Missing \"error-info\" node", errorInfoNode );
+
+ errorInfoVerifier.verifyXML( errorInfoNode );
+ }
+ else {
+ assertNull( "Found unexpected \"error-info\" node", errorInfoNode );
+ }
+ }
+
+ void verifyOptionalXMLLeaf( Node fromNode, XPathExpression xpath, String expValue,
+ String tagName ) throws Exception {
+ if( expValue != null ) {
+ String actual = (String)xpath.evaluate( fromNode, XPathConstants.STRING );
+ assertEquals( tagName, expValue, actual );
+ }
+ else {
+ assertNull( "Found unexpected \"error\" leaf entry for: " + tagName,
+ xpath.evaluate( fromNode, XPathConstants.NODE ) );
+ }
+ }
+
+ NodeList getXMLErrorList( Node fromNode, int count ) throws Exception {
+ NodeList errorList = (NodeList)ERROR_LIST.evaluate( fromNode, XPathConstants.NODESET );
+ assertNotNull( "Root errors node is empty", errorList );
+ assertEquals( "Root errors node child count", count, errorList.getLength() );
+ return errorList;
+ }
+}
--- /dev/null
+/*
+* Copyright (c) 2014 Brocade Communications 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.restconf.impl.test;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.junit.Test;
+
+import static org.opendaylight.controller.sal.common.util.RpcErrors.getRpcError;
+
+import org.opendaylight.controller.sal.restconf.impl.RestconfError;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType;
+import org.opendaylight.yangtools.yang.common.RpcError;
+
+/**
+ * Unit tests for RestconfError.
+ *
+ * @author Devin Avery
+ * @author Thomas Pantelis
+ *
+ */
+public class RestconfErrorTest {
+
+ static class Contains extends BaseMatcher<String> {
+
+ private final String text;
+
+ public Contains( String text ) {
+ this.text = text;
+ }
+
+ @Override
+ public void describeTo( Description desc ) {
+ desc.appendText( "contains " ).appendValue( text );
+ }
+
+ @Override
+ public boolean matches( Object arg ) {
+ return arg != null && arg.toString().contains( text );
+ }
+ }
+
+ @Test
+ public void testErrorTagValueOf()
+ {
+ assertEquals( ErrorTag.IN_USE,
+ ErrorTag.valueOfCaseInsensitive( ErrorTag.IN_USE.getTagValue() ) );
+ }
+
+ @Test
+ public void testErrorTagValueOfIsLowercase()
+ {
+ assertEquals( "in-use",
+ ErrorTag.IN_USE.getTagValue() );
+ }
+
+ @Test
+ public void testErrorTypeGetErrorTypeTagIsLowerCase()
+ {
+ assertEquals( ErrorType.APPLICATION.name().toLowerCase(),
+ ErrorType.APPLICATION.getErrorTypeTag() );
+ }
+
+ @Test
+ public void testErrorTypeValueOf()
+ {
+ assertEquals( ErrorType.APPLICATION,
+ ErrorType.valueOfCaseInsensitive( ErrorType.APPLICATION.getErrorTypeTag() ) );
+ }
+
+ @Test
+ public void testErrorTagStatusCodes()
+ {
+ Map<String,Status> lookUpMap = new HashMap<String,Status>();
+
+ lookUpMap.put( "in-use", Status.fromStatusCode(409));
+ lookUpMap.put( "invalid-value", Status.fromStatusCode(400));
+ lookUpMap.put( "too-big", Status.fromStatusCode(413));
+ lookUpMap.put( "missing-attribute", Status.fromStatusCode(400));
+ lookUpMap.put( "bad-attribute", Status.fromStatusCode(400));
+ lookUpMap.put( "unknown-attribute", Status.fromStatusCode(400));
+ lookUpMap.put( "bad-element", Status.fromStatusCode(400));
+ lookUpMap.put( "unknown-element", Status.fromStatusCode(400));
+ lookUpMap.put( "unknown-namespace", Status.fromStatusCode(400));
+ lookUpMap.put( "access-denied", Status.fromStatusCode(403));
+ lookUpMap.put( "lock-denied", Status.fromStatusCode(409));
+ lookUpMap.put( "resource-denied", Status.fromStatusCode(409));
+ lookUpMap.put( "rollback-failed", Status.fromStatusCode(500));
+ lookUpMap.put( "data-exists", Status.fromStatusCode(409));
+ lookUpMap.put( "data-missing", Status.fromStatusCode(409));
+ lookUpMap.put( "operation-not-supported", Status.fromStatusCode(501));
+ lookUpMap.put( "operation-failed", Status.fromStatusCode(500));
+ lookUpMap.put( "partial-operation", Status.fromStatusCode(500));
+ lookUpMap.put( "malformed-message", Status.fromStatusCode(400));
+
+ for( ErrorTag tag : ErrorTag.values() )
+ {
+ Status expectedStatusCode = lookUpMap.get( tag.getTagValue() );
+ assertNotNull( "Failed to find " + tag.getTagValue(), expectedStatusCode );
+ assertEquals( "Status Code does not match", expectedStatusCode, tag.getStatusCode() );
+ }
+ }
+
+ @Test
+ public void testRestConfDocumentedException_NoCause()
+ {
+ String expectedMessage = "Message";
+ ErrorType expectedErrorType = ErrorType.RPC;
+ ErrorTag expectedErrorTag = ErrorTag.IN_USE;
+ RestconfError e =
+ new RestconfError( expectedErrorType,
+ expectedErrorTag, expectedMessage );
+
+ validateRestConfError(expectedMessage, expectedErrorType, expectedErrorTag,
+ null, (String)null, e);
+ }
+
+ @Test
+ public void testRestConfDocumentedException_WithAppTag()
+ {
+ String expectedMessage = "Message";
+ ErrorType expectedErrorType = ErrorType.RPC;
+ ErrorTag expectedErrorTag = ErrorTag.IN_USE;
+ String expectedErrorAppTag = "application.tag";
+
+ RestconfError e =
+ new RestconfError( expectedErrorType,
+ expectedErrorTag, expectedMessage, expectedErrorAppTag );
+
+ validateRestConfError(expectedMessage, expectedErrorType, expectedErrorTag,
+ expectedErrorAppTag, (String)null, e);
+ }
+
+ @Test
+ public void testRestConfDocumentedException_WithAppTagErrorInfo()
+ {
+ String expectedMessage = "Message";
+ ErrorType expectedErrorType = ErrorType.RPC;
+ ErrorTag expectedErrorTag = ErrorTag.IN_USE;
+ String expectedErrorAppTag = "application.tag";
+ String errorInfo = "<extra><sessionid>session.id</sessionid></extra>";
+
+ RestconfError e = new RestconfError( expectedErrorType,
+ expectedErrorTag,
+ expectedMessage,
+ expectedErrorAppTag,
+ errorInfo );
+
+ validateRestConfError(expectedMessage, expectedErrorType, expectedErrorTag,
+ expectedErrorAppTag, errorInfo, e);
+ }
+
+ @Test
+ public void testRestConfErrorWithRpcError() {
+
+ // All fields set
+ RpcError rpcError = getRpcError( "mock app-tag", ErrorTag.BAD_ATTRIBUTE.getTagValue(),
+ "mock error-info", RpcError.ErrorSeverity.ERROR,
+ "mock error-message", RpcError.ErrorType.PROTOCOL,
+ new Exception( "mock cause" ) );
+
+ validateRestConfError( "mock error-message", ErrorType.PROTOCOL, ErrorTag.BAD_ATTRIBUTE,
+ "mock app-tag", "mock error-info",
+ new RestconfError( rpcError ) );
+
+ // All fields set except 'info' - expect error-info set to 'cause'
+ rpcError = getRpcError( "mock app-tag", ErrorTag.BAD_ATTRIBUTE.getTagValue(),
+ null, RpcError.ErrorSeverity.ERROR,
+ "mock error-message", RpcError.ErrorType.PROTOCOL,
+ new Exception( "mock cause" ) );
+
+ validateRestConfError( "mock error-message", ErrorType.PROTOCOL, ErrorTag.BAD_ATTRIBUTE,
+ "mock app-tag", new Contains( "mock cause" ),
+ new RestconfError( rpcError ) );
+
+ // Some fields set - expect error-info set to ErrorSeverity
+ rpcError = getRpcError( null, ErrorTag.ACCESS_DENIED.getTagValue(),
+ null, RpcError.ErrorSeverity.ERROR,
+ null, RpcError.ErrorType.RPC, null );
+
+ validateRestConfError( null, ErrorType.RPC, ErrorTag.ACCESS_DENIED,
+ null, "<severity>error</severity>",
+ new RestconfError( rpcError ) );
+
+ // 'tag' field not mapped to ErrorTag - expect error-tag set to OPERATION_FAILED
+ rpcError = getRpcError( null, "not mapped",
+ null, RpcError.ErrorSeverity.WARNING,
+ null, RpcError.ErrorType.TRANSPORT, null );
+
+ validateRestConfError( null, ErrorType.TRANSPORT, ErrorTag.OPERATION_FAILED,
+ null, "<severity>warning</severity>",
+ new RestconfError( rpcError ) );
+
+ // No fields set - edge case
+ rpcError = getRpcError( null, null, null, null, null, null, null );
+
+ validateRestConfError( null, ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED,
+ null, (String)null, new RestconfError( rpcError ) );
+ }
+
+ private void validateRestConfError(String expectedMessage, ErrorType expectedErrorType,
+ ErrorTag expectedErrorTag, String expectedErrorAppTag, String errorInfo, RestconfError e) {
+
+ validateRestConfError( expectedMessage, expectedErrorType, expectedErrorTag,
+ expectedErrorAppTag, equalTo( errorInfo ), e );
+ }
+
+ private void validateRestConfError(String expectedMessage, ErrorType expectedErrorType,
+ ErrorTag expectedErrorTag, String expectedErrorAppTag,
+ Matcher<String> errorInfoMatcher, RestconfError e) {
+
+ assertEquals( "getErrorMessage", expectedMessage, e.getErrorMessage() );
+ assertEquals( "getErrorType", expectedErrorType, e.getErrorType() );
+ assertEquals( "getErrorTag", expectedErrorTag, e.getErrorTag() );
+ assertEquals( "getErrorAppTag", expectedErrorAppTag, e.getErrorAppTag() );
+ assertThat( "getErrorInfo", e.getErrorInfo(), errorInfoMatcher );
+ e.toString(); // really just checking for NPE etc. Don't care about contents.
+ }
+}
import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
import org.opendaylight.controller.sal.restconf.impl.InstanceIdWithSchemaNode;
-import org.opendaylight.controller.sal.restconf.impl.ResponseException;
+import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
import org.opendaylight.controller.sal.restconf.impl.RestconfImpl;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
@Test
public void testToInstanceIdentifierListWithNullKey() {
- exception.expect(ResponseException.class);
- exception.expectMessage("HTTP 400 Bad Request");
+ exception.expect(RestconfDocumentedException.class);
controllerContext.toInstanceIdentifier("simple-nodes:user/null/boo");
}
@Test
public void testToInstanceIdentifierListWithMissingKey() {
- exception.expect(ResponseException.class);
- exception.expectMessage("HTTP 400 Bad Request");
+ exception.expect(RestconfDocumentedException.class);
controllerContext.toInstanceIdentifier("simple-nodes:user/foo");
}
@Test
public void testToInstanceIdentifierChoiceException() {
- exception.expect(ResponseException.class);
- exception.expectMessage("HTTP 400 Bad Request");
+ exception.expect(RestconfDocumentedException.class);
controllerContext.toInstanceIdentifier("simple-nodes:food/snack");
}
@Test
public void testToInstanceIdentifierCaseException() {
- exception.expect(ResponseException.class);
- exception.expectMessage("HTTP 400 Bad Request");
+ exception.expect(RestconfDocumentedException.class);
controllerContext.toInstanceIdentifier("simple-nodes:food/sports-arena");
}
@Test
public void testToInstanceIdentifierChoiceCaseException() {
- exception.expect(ResponseException.class);
- exception.expectMessage("HTTP 400 Bad Request");
+ exception.expect(RestconfDocumentedException.class);
controllerContext.toInstanceIdentifier("simple-nodes:food/snack/sports-arena");
}
-
+
@Test
public void testToInstanceIdentifierWithoutNode() {
- exception.expect(ResponseException.class);
- exception.expectMessage("HTTP 400 Bad Request");
+ exception.expect(RestconfDocumentedException.class);
controllerContext.toInstanceIdentifier("simple-nodes");
}
@Test
public void testMountPointWithoutMountService() throws FileNotFoundException {
- exception.expect(ResponseException.class);
- exception.expectMessage("HTTP 503 Service Unavailable");
-
+ exception.expect(RestconfDocumentedException.class);
+
controllerContext.setMountService(null);
InstanceIdWithSchemaNode instanceIdentifier = controllerContext
.toInstanceIdentifier("simple-nodes:users/yang-ext:mount/test-interface2:class/student/name");
}
-
+
@Test
public void testMountPointWithoutMountPointSchema() {
initMountService(false);
- exception.expect(ResponseException.class);
- exception.expectMessage("HTTP 400 Bad Request");
-
+ exception.expect(RestconfDocumentedException.class);
+
InstanceIdWithSchemaNode instanceIdentifier = controllerContext
.toInstanceIdentifier("simple-nodes:users/yang-ext:mount/test-interface2:class");
}
-
+
public void initMountService(boolean withSchema) {
MountService mountService = mock(MountService.class);
controllerContext.setMountService(mountService);
+++ /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">\r
- <modelVersion>4.0.0</modelVersion>\r
- <parent>\r
- <groupId>org.opendaylight.controller</groupId>\r
- <artifactId>sal-parent</artifactId>\r
- <version>1.0-SNAPSHOT</version>\r
- </parent>\r
- <artifactId>sal-schema-repository-api</artifactId>\r
- <scm>\r
- <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>\r
- <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>\r
- <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>\r
- </scm>\r
-\r
- <dependencies>\r
- <dependency>\r
- <groupId>org.opendaylight.controller</groupId>\r
- <artifactId>yang-model-api</artifactId>\r
- </dependency>\r
- </dependencies>\r
-</project>\r
+++ /dev/null
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
- *\r
- * This program and the accompanying materials are made available under the\r
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
- * and is available at http://www.eclipse.org/legal/epl-v10.html\r
- */\r
-package org.opendaylight.controller.sal.schema.api;
\ No newline at end of file
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorSeverity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
LOG.info( "Toaster is already making toast" );
RpcResult<Void> result = Rpcs.<Void> getRpcResult(false, null, Arrays.asList(
- RpcErrors.getRpcError( null, null, null, null,
- "Toaster is busy", null, null ) ) );
+ RpcErrors.getRpcError( "", "in-use", null, ErrorSeverity.WARNING,
+ "Toaster is busy", ErrorType.APPLICATION, null ) ) );
return Futures.immediateFuture(result);
}
else if( outOfBread() ) {
RpcResult<Void> result = Rpcs.<Void> getRpcResult(false, null, Arrays.asList(
- RpcErrors.getRpcError( null, null, null, null,
- "Toaster is out of bread", null, null ) ) );
+ RpcErrors.getRpcError( "out-of-stock", "resource-denied", null, null,
+ "Toaster is out of bread",
+ ErrorType.APPLICATION, null ) ) );
return Futures.immediateFuture(result);
}
else {
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
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;
private static final Logger logger = LoggerFactory.getLogger(InstanceConfig.class);
private final Map<String, AttributeIfc> yangToAttrConfig;
+ private final String nullableDummyContainerName;
private final Map<String, AttributeIfc> jmxToAttrConfig;
private final ConfigRegistryClient configRegistryClient;
- public InstanceConfig(ConfigRegistryClient configRegistryClient, Map<String, AttributeIfc> yangNamesToAttributes) {
+ public InstanceConfig(ConfigRegistryClient configRegistryClient, Map<String, AttributeIfc> yangNamesToAttributes,
+ String nullableDummyContainerName) {
+
this.yangToAttrConfig = yangNamesToAttributes;
+ this.nullableDummyContainerName = nullableDummyContainerName;
this.jmxToAttrConfig = reverseMap(yangNamesToAttributes);
this.configRegistryClient = configRegistryClient;
}
}
public Element toXml(ObjectName on, String namespace, Document document, Element rootElement) {
-
Map<String, AttributeWritingStrategy> strats = new ObjectXmlWriter().prepareWriting(yangToAttrConfig, document);
-
Map<String, Object> mappedConfig = getMappedConfiguration(on);
-
+ Element parentElement;
+ if (nullableDummyContainerName != null) {
+ Element dummyElement = XmlUtil.createElement(document, nullableDummyContainerName, Optional.of(namespace));
+ rootElement.appendChild(dummyElement);
+ parentElement = dummyElement;
+ } else {
+ parentElement = rootElement;
+ }
for (Entry<String, ?> mappingEntry : mappedConfig.entrySet()) {
try {
- strats.get(mappingEntry.getKey()).writeElement(rootElement, namespace, mappingEntry.getValue());
+ strats.get(mappingEntry.getKey()).writeElement(parentElement, namespace, mappingEntry.getValue());
} catch (Exception e) {
throw new IllegalStateException("Unable to write value " + mappingEntry.getValue() + " for attribute "
+ mappingEntry.getValue(), e);
}
}
-
return rootElement;
}
Map<String, AttributeReadingStrategy> strats = new ObjectXmlReader().prepareReading(yangToAttrConfig, identityMap);
List<XmlElement> recognisedChildren = Lists.newArrayList();
- XmlElement type;
- XmlElement name;
- type = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.TYPE_KEY);
- name = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.NAME_KEY);
- List<XmlElement> typeAndName = Lists.newArrayList(type, name);
+ XmlElement typeElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.TYPE_KEY);
+ XmlElement nameElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.NAME_KEY);
+ List<XmlElement> typeAndNameElements = Lists.newArrayList(typeElement, nameElement);
+
+ // if dummy container was defined in yang, set moduleElement to its content
+ if (nullableDummyContainerName != null) {
+ int size = moduleElement.getChildElements().size();
+ int expectedChildNodes = 1 + typeAndNameElements.size();
+ if (size > expectedChildNodes) {
+ throw new NetconfDocumentedException("Error reading module " + typeElement.getTextContent() + " : " +
+ nameElement.getTextContent() + " - Expected " + expectedChildNodes +" child nodes, " +
+ "one of them with name " + nullableDummyContainerName +
+ ", got " + size + " elements.");
+ }
+ if (size == expectedChildNodes) {
+ try {
+ moduleElement = moduleElement.getOnlyChildElement(nullableDummyContainerName, moduleNamespace);
+ } catch (NetconfDocumentedException e) {
+ throw new NetconfDocumentedException("Error reading module " + typeElement.getTextContent() + " : " +
+ nameElement.getTextContent() + " - Expected child node with name " + nullableDummyContainerName +
+ "." + e.getMessage());
+ }
+ } // else 2 elements, no need to descend
+ }
for (Entry<String, AttributeReadingStrategy> readStratEntry : strats.entrySet()) {
List<XmlElement> configNodes = getConfigNodes(moduleElement, moduleNamespace, readStratEntry.getKey(),
- recognisedChildren, typeAndName);
+ recognisedChildren, typeAndNameElements);
AttributeConfigElement readElement = readStratEntry.getValue().readElement(configNodes);
retVal.put(readStratEntry.getKey(), readElement);
}
- recognisedChildren.addAll(typeAndName);
- moduleElement.checkUnrecognisedElements(recognisedChildren);
-
+ recognisedChildren.addAll(typeAndNameElements);
+ try {
+ moduleElement.checkUnrecognisedElements(recognisedChildren);
+ } catch (NetconfDocumentedException e) {
+ throw new NetconfDocumentedException("Error reading module " + typeElement.getTextContent() + " : " +
+ nameElement.getTextContent() + " - " +
+ e.getMessage(), e.getErrorType(), e.getErrorTag(),e.getErrorSeverity(),e.getErrorInfo());
+ }
// TODO: add check for conflicts between global and local edit strategy
String perInstanceEditStrategy = moduleElement.getAttribute(XmlNetconfConstants.OPERATION_ATTR_KEY,
XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
String moduleName = moduleNameToMbe.getKey();
ModuleMXBeanEntry moduleMXBeanEntry = moduleNameToMbe.getValue();
- ModuleConfig moduleConfig = new ModuleConfig(moduleName, new InstanceConfig(configRegistryClient,
- moduleMXBeanEntry.getAttributes()));
+ ModuleConfig moduleConfig = new ModuleConfig(moduleName,
+ new InstanceConfig(configRegistryClient,moduleMXBeanEntry.getAttributes(), moduleMXBeanEntry.getNullableDummyContainerName()));
Map<String, ModuleConfig> moduleNameToModuleConfig = namespaceToModuleNameToModuleConfig.get(namespace);
if(moduleNameToModuleConfig == null) {
Map<RuntimeBeanEntry, InstanceConfig> cache = Maps.newHashMap();
RuntimeBeanEntry root = null;
for (RuntimeBeanEntry rbe : mbe.getRuntimeBeans()) {
- cache.put(rbe, new InstanceConfig(configRegistryClient, rbe.getYangPropertiesToTypesMap()));
+ cache.put(rbe, new InstanceConfig(configRegistryClient, rbe.getYangPropertiesToTypesMap(), mbe.getNullableDummyContainerName()));
if (rbe.isRoot()){
root = rbe;
}
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleFactory;
import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleMXBean;
import org.opendaylight.controller.config.yang.test.impl.Peers;
+import org.opendaylight.controller.config.yang.test.impl.TestImplModuleFactory;
import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.Commit;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
-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.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.test.types.rev131127.TestIdentity1;
private NetconfTestImplModuleFactory factory;
private DepTestImplModuleFactory factory2;
private IdentityTestModuleFactory factory3;
+ private TestImplModuleFactory factory4;
@Mock
YangStoreSnapshot yangStoreSnapshot;
this.factory = new NetconfTestImplModuleFactory();
this.factory2 = new DepTestImplModuleFactory();
this.factory3 = new IdentityTestModuleFactory();
+ factory4 = new TestImplModuleFactory();
super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext, this.factory, this.factory2,
- this.factory3));
+ this.factory3, factory4));
transactionProvider = new TransactionProvider(this.configRegistryClient, NETCONF_SESSION_ID);
}
assertEquals(2, afterReplace);
}
- @Test(expected = NetconfDocumentedException.class)
+ @Test
public void testSameAttrDifferentNamespaces() throws Exception {
try {
edit("netconfMessages/namespaces/editConfig_sameAttrDifferentNamespaces.xml");
+ fail();
} catch (NetconfDocumentedException e) {
String message = e.getMessage();
- assertContainsString(message, "Element simple-long-2 present multiple times with different namespaces");
+ assertContainsString(message, "Element simpleInt present multiple times with different namespaces");
assertContainsString(message, TEST_NAMESPACE);
assertContainsString(message, XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
- throw e;
}
}
- @Test(expected = NetconfDocumentedException.class)
+ @Test
public void testDifferentNamespaceInTO() throws Exception {
try {
edit("netconfMessages/namespaces/editConfig_differentNamespaceTO.xml");
+ fail();
} catch (NetconfDocumentedException e) {
String message = e.getMessage();
assertContainsString(message, "Unrecognised elements");
assertContainsString(message, "simple-int2");
assertContainsString(message, "dto_d");
- throw e;
}
}
- @Test(expected = NetconfDocumentedException.class)
+ @Test
public void testSameAttrDifferentNamespacesList() throws Exception {
try {
edit("netconfMessages/namespaces/editConfig_sameAttrDifferentNamespacesList.xml");
+ fail();
} catch (NetconfDocumentedException e) {
String message = e.getMessage();
- assertContainsString(message, "Element binaryLeaf present multiple times with different namespaces");
+ assertContainsString(message, "Element allow-user present multiple times with different namespaces");
assertContainsString(message, TEST_NAMESPACE);
assertContainsString(message, XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
- throw e;
}
}
for (int i = 0; i < TESTS_COUNT; i++) {
String file = String.format(format, i + 1);
+ logger.info("Reading {}", file);
try {
edit(file);
} catch (NetconfDocumentedException e) {
assertThat(string, JUnitMatchers.containsString(substring));
}
- private void checkEnum(final Document response) throws NetconfDocumentedException {
- XmlElement modulesElement = XmlElement.fromDomElement(response.getDocumentElement()).getOnlyChildElement("data")
- .getOnlyChildElement("modules");
+ private void checkEnum(final Document response) throws Exception {
- String enumName = "extended-enum";
- String enumContent = "TWO";
+ String expectedEnumContent = "TWO";
- for (XmlElement moduleElement : modulesElement.getChildElements("module")) {
- String name = moduleElement.getOnlyChildElement("name").getTextContent();
- if(name.equals(INSTANCE_NAME)) {
- XmlElement enumAttr = moduleElement.getOnlyChildElement(enumName);
- assertEquals(enumContent, enumAttr.getTextContent());
- return;
- }
- }
-
- fail("Enum attribute " + enumName + ":" + enumContent + " not present in " + XmlUtil.toString(response));
+ XMLAssert.assertXpathEvaluatesTo(expectedEnumContent,
+ getXpathForNetconfImplSubnode(INSTANCE_NAME,"extended-enum"),
+ response);
}
private void checkTestingDeps(Document response) {
assertEquals(2, testingDepsSize);
}
- private void checkTypeConfigAttribute(Document response) throws NetconfDocumentedException {
-
- XmlElement modulesElement = XmlElement.fromDomElement(response.getDocumentElement()).getOnlyChildElement("data")
- .getOnlyChildElement("modules");
-
- List<String> expectedValues = Lists.newArrayList("default-string", "configAttributeType");
- Set<String> configAttributeType = Sets.newHashSet();
+ private String getXpathForNetconfImplSubnode(String instanceName, String subnode) {
+ return "/urn:ietf:params:xml:ns:netconf:base:1.0:rpc-reply" +
+ "/urn:ietf:params:xml:ns:netconf:base:1.0:data" +
+ "/urn:opendaylight:params:xml:ns:yang:controller:config:modules" +
+ "/module[name='"+instanceName+"']" +
+ "/urn:opendaylight:params:xml:ns:yang:controller:test:impl:impl-netconf" +
+ "/urn:opendaylight:params:xml:ns:yang:controller:test:impl:"+subnode;
+ }
- for (XmlElement moduleElement : modulesElement.getChildElements("module")) {
- for (XmlElement type : moduleElement.getChildElements("type")) {
- if (type.getNamespaceOptionally().isPresent()) {
- configAttributeType.add(type.getTextContent());
- }
- }
- }
+ private void checkTypeConfigAttribute(Document response) throws Exception {
- for (String expectedValue : expectedValues) {
- assertTrue(configAttributeType.contains(expectedValue));
+ Map<String,String> namesToTypeValues = ImmutableMap.of("instance-from-code", "configAttributeType",
+ "test2", "default-string");
+ for (Entry<String, String> nameToExpectedValue : namesToTypeValues.entrySet()) {
+ XMLAssert.assertXpathEvaluatesTo(nameToExpectedValue.getValue(),
+ getXpathForNetconfImplSubnode(nameToExpectedValue.getKey(),"type"),
+ response);
}
}
private final ErrorSeverity errorSeverity;
private final Map<String, String> errorInfo;
+ public NetconfDocumentedException(String message) {
+ this(message,
+ NetconfDocumentedException.ErrorType.application,
+ NetconfDocumentedException.ErrorTag.invalid_value,
+ NetconfDocumentedException.ErrorSeverity.error
+ );
+ }
+
public NetconfDocumentedException(final String message, final ErrorType errorType, final ErrorTag errorTag,
final ErrorSeverity errorSeverity) {
this(message, errorType, errorTag, errorSeverity, Collections.<String, String> emptyMap());
*/
package org.opendaylight.controller.netconf.impl.osgi;
-import io.netty.channel.nio.NioEventLoopGroup;
-import io.netty.util.HashedWheelTimer;
+import java.lang.management.ManagementFactory;
+import java.net.InetSocketAddress;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.concurrent.TimeUnit;
+
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.lang.management.ManagementFactory;
-import java.net.InetSocketAddress;
-import java.util.Dictionary;
-import java.util.Hashtable;
-import java.util.concurrent.TimeUnit;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.util.HashedWheelTimer;
public class NetconfImplActivator implements BundleActivator {
private ServiceRegistration<NetconfMonitoringService> regMonitoring;
@Override
- public void start(final BundleContext context) {
- InetSocketAddress address = NetconfConfigUtil.extractTCPNetconfAddress(context,
- "TCP is not configured, netconf not available.", false);
-
- NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
+ public void start(final BundleContext context) {
+ final InetSocketAddress address = NetconfConfigUtil.extractTCPNetconfServerAddress(context,
+ NetconfConfigUtil.DEFAULT_NETCONF_TCP_ADDRESS);
+ final NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
startOperationServiceFactoryTracker(context, factoriesListener);
- SessionIdProvider idProvider = new SessionIdProvider();
+ final SessionIdProvider idProvider = new SessionIdProvider();
timer = new HashedWheelTimer();
- long connectionTimeoutMillis = NetconfConfigUtil.extractTimeoutMillis(context);
+ long connectionTimeoutMillis = NetconfConfigUtil.extractTimeoutMillis(context);
commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(
serverNegotiatorFactory);
- NetconfServerDispatcher dispatch = new NetconfServerDispatcher(serverChannelInitializer, eventLoopGroup, eventLoopGroup);
+
+ NetconfServerDispatcher dispatch = new NetconfServerDispatcher(serverChannelInitializer, eventLoopGroup,
+ eventLoopGroup);
logger.info("Starting TCP netconf server at {}", address);
dispatch.createServer(address);
context.registerService(NetconfOperationProvider.class, factoriesListener, null);
-
}
- private void startOperationServiceFactoryTracker(BundleContext context, NetconfOperationServiceFactoryListenerImpl factoriesListener) {
+ private void startOperationServiceFactoryTracker(final BundleContext context, final NetconfOperationServiceFactoryListenerImpl factoriesListener) {
factoriesTracker = new NetconfOperationServiceFactoryTracker(context, factoriesListener);
factoriesTracker.open();
}
- private NetconfMonitoringServiceImpl startMonitoringService(BundleContext context, NetconfOperationServiceFactoryListenerImpl factoriesListener) {
- NetconfMonitoringServiceImpl netconfMonitoringServiceImpl = new NetconfMonitoringServiceImpl(factoriesListener);
- Dictionary<String, ?> dic = new Hashtable<>();
+ private NetconfMonitoringServiceImpl startMonitoringService(final BundleContext context, final NetconfOperationServiceFactoryListenerImpl factoriesListener) {
+ final NetconfMonitoringServiceImpl netconfMonitoringServiceImpl = new NetconfMonitoringServiceImpl(factoriesListener);
+ final Dictionary<String, ?> dic = new Hashtable<>();
regMonitoring = context.registerService(NetconfMonitoringService.class, netconfMonitoringServiceImpl, dic);
return netconfMonitoringServiceImpl;
package org.opendaylight.controller.netconf.ssh.authentication;
+import java.security.NoSuchAlgorithmException;
import org.apache.commons.io.FileUtils;
import org.bouncycastle.openssl.PEMWriter;
import org.slf4j.Logger;
private static final Logger logger = LoggerFactory.getLogger(PEMGenerator.class);
private static final int KEY_SIZE = 4096;
- public static String generateTo(File privateFile) throws Exception {
+ public static String generateTo(File privateFile) throws IOException, NoSuchAlgorithmException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
SecureRandom sr = new SecureRandom();
keyGen.initialize(KEY_SIZE, sr);
*/
package org.opendaylight.controller.netconf.ssh.osgi;
-import com.google.common.base.Optional;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.List;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator;
import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
-import org.opendaylight.controller.sal.authorization.UserLevel;
import org.opendaylight.controller.usermanager.IUserManager;
-import org.opendaylight.controller.usermanager.UserConfig;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import static com.google.common.base.Preconditions.checkNotNull;
/**
* Activator for netconf SSH bundle which creates SSH bridge between netconf client and netconf server. Activator
private NetconfSSHServer server;
private static final Logger logger = LoggerFactory.getLogger(NetconfSSHActivator.class);
- private static final String EXCEPTION_MESSAGE = "Netconf ssh bridge is not available.";
private IUserManager iUserManager;
private BundleContext context = null;
- private Optional<String> defaultPassword;
- private Optional<String> defaultUser;
private ServiceTrackerCustomizer<IUserManager, IUserManager> customizer = new ServiceTrackerCustomizer<IUserManager, IUserManager>(){
@Override
- public IUserManager addingService(ServiceReference<IUserManager> reference) {
+ public IUserManager addingService(final ServiceReference<IUserManager> reference) {
logger.trace("Service {} added, let there be SSH bridge.", reference);
iUserManager = context.getService(reference);
try {
onUserManagerFound(iUserManager);
- } catch (Exception e) {
+ } catch (final Exception e) {
logger.trace("Can't start SSH server due to {}",e);
}
return iUserManager;
}
@Override
- public void modifiedService(ServiceReference<IUserManager> reference, IUserManager service) {
+ public void modifiedService(final ServiceReference<IUserManager> reference, final IUserManager service) {
logger.trace("Replacing modified service {} in netconf SSH.", reference);
server.addUserManagerService(service);
}
@Override
- public void removedService(ServiceReference<IUserManager> reference, IUserManager service) {
+ public void removedService(final ServiceReference<IUserManager> reference, final IUserManager service) {
logger.trace("Removing service {} from netconf SSH. " +
"SSH won't authenticate users until IUserManager service will be started.", reference);
removeUserManagerService();
@Override
- public void start(BundleContext context) {
+ public void start(final BundleContext context) {
this.context = context;
listenForManagerService();
}
@Override
public void stop(BundleContext context) throws IOException {
- if (this.defaultUser.isPresent()){
- this.iUserManager.removeLocalUser(this.defaultUser.get());
- }
if (server != null){
server.stop();
logger.trace("Netconf SSH bridge is down ...");
}
}
- private void startSSHServer() throws IllegalStateException, IOException {
+ private void startSSHServer() throws IOException {
checkNotNull(this.iUserManager, "No user manager service available.");
logger.trace("Starting netconf SSH bridge.");
- Optional<InetSocketAddress> sshSocketAddressOptional = NetconfConfigUtil.extractSSHNetconfAddress(context, EXCEPTION_MESSAGE);
- InetSocketAddress tcpSocketAddress = NetconfConfigUtil.extractTCPNetconfAddress(context,
- EXCEPTION_MESSAGE, true);
+ final InetSocketAddress sshSocketAddress = NetconfConfigUtil.extractSSHNetconfAddress(context,
+ NetconfConfigUtil.DEFAULT_NETCONF_SSH_ADDRESS);
+ final InetSocketAddress tcpSocketAddress = NetconfConfigUtil.extractTCPNetconfClientAddress(context,
+ NetconfConfigUtil.DEFAULT_NETCONF_TCP_ADDRESS);
- if (sshSocketAddressOptional.isPresent()){
- String path = FilenameUtils.separatorsToSystem(NetconfConfigUtil.getPrivateKeyPath(context));
- if (path.equals("")){
- throw new IllegalStateException("Missing netconf.ssh.pk.path key in configuration file.");
- }
+ String path = FilenameUtils.separatorsToSystem(NetconfConfigUtil.getPrivateKeyPath(context));
- File privateKeyFile = new File(path);
- String privateKeyPEMString = null;
- if (privateKeyFile.exists() == false) {
- try {
- privateKeyPEMString = PEMGenerator.generateTo(privateKeyFile);
- } catch (Exception e) {
- logger.error("Exception occurred while generating PEM string {}",e);
- }
- } else {
- // read from file
- try (FileInputStream fis = new FileInputStream(path)) {
- privateKeyPEMString = IOUtils.toString(fis);
- } catch (IOException e) {
- logger.error("Error reading RSA key from file '{}'", path);
- throw new IllegalStateException("Error reading RSA key from file " + path);
- }
- }
- AuthProvider authProvider = null;
+ if (path.isEmpty()) {
+ throw new IllegalStateException("Missing netconf.ssh.pk.path key in configuration file.");
+ }
+
+ final File privateKeyFile = new File(path);
+ final String privateKeyPEMString;
+ if (privateKeyFile.exists() == false) {
+ // generate & save to file
try {
- this.defaultPassword = NetconfConfigUtil.getSSHDefaultPassword(context);
- this.defaultUser = NetconfConfigUtil.getSSHDefaultUser(context);
- // Since there is no user data store yet (ldap, ...) this adds default user/password to UserManager
- // if these parameters are set in netconf configuration file.
- if (defaultUser.isPresent() &&
- defaultPassword.isPresent()){
- logger.trace(String.format("Default username and password for netconf ssh bridge found. Adding user %s to user manager.",defaultUser.get()));
- List<String> roles = new ArrayList<String>(1);
- roles.add(UserLevel.SYSTEMADMIN.toString());
- iUserManager.addLocalUser(new UserConfig(defaultUser.get(), defaultPassword.get(), roles));
- }
- authProvider = new AuthProvider(iUserManager, privateKeyPEMString);
+ privateKeyPEMString = PEMGenerator.generateTo(privateKeyFile);
} catch (Exception e) {
- logger.error("Error instantiating AuthProvider {}",e);
+ logger.error("Exception occurred while generating PEM string {}", e);
+ throw new IllegalStateException("Error generating RSA key from file " + path);
}
- this.server = NetconfSSHServer.start(sshSocketAddressOptional.get().getPort(),tcpSocketAddress,authProvider);
-
- Thread serverThread = new Thread(server,"netconf SSH server thread");
- serverThread.setDaemon(true);
- serverThread.start();
- logger.trace("Netconf SSH bridge up and running.");
} else {
- logger.trace("No valid connection configuration for SSH bridge found.");
- throw new IllegalStateException("No valid connection configuration for SSH bridge found.");
+ // read from file
+ try (FileInputStream fis = new FileInputStream(path)) {
+ privateKeyPEMString = IOUtils.toString(fis);
+ } catch (final IOException e) {
+ logger.error("Error reading RSA key from file '{}'", path);
+ throw new IOException("Error reading RSA key from file " + path, e);
+ }
}
+ final AuthProvider authProvider = new AuthProvider(iUserManager, privateKeyPEMString);
+ this.server = NetconfSSHServer.start(sshSocketAddress.getPort(), tcpSocketAddress, authProvider);
+
+ final Thread serverThread = new Thread(server, "netconf SSH server thread");
+ serverThread.setDaemon(true);
+ serverThread.start();
+ logger.trace("Netconf SSH bridge up and running.");
}
- private void onUserManagerFound(IUserManager userManager) throws IOException {
+
+ private void onUserManagerFound(final IUserManager userManager) throws Exception{
if (server!=null && server.isUp()){
server.addUserManagerService(userManager);
} else {
this.server.removeUserManagerService();
}
private void listenForManagerService(){
- ServiceTracker<IUserManager, IUserManager> listenerTracker = new ServiceTracker<>(context, IUserManager.class,customizer);
+ final ServiceTracker<IUserManager, IUserManager> listenerTracker = new ServiceTracker<>(context, IUserManager.class,customizer);
listenerTracker.open();
}
}
package org.opendaylight.controller.netconf.util.osgi;
import com.google.common.base.Optional;
-import com.google.common.base.Strings;
-import java.net.InetSocketAddress;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.net.InetSocketAddress;
public final class NetconfConfigUtil {
private static final Logger logger = LoggerFactory.getLogger(NetconfConfigUtil.class);
+ public static final InetSocketAddress DEFAULT_NETCONF_TCP_ADDRESS
+ = new InetSocketAddress("127.0.0.1", 8383);
+ public static final InetSocketAddress DEFAULT_NETCONF_SSH_ADDRESS
+ = new InetSocketAddress("0.0.0.0", 1830);
+
private static final String PREFIX_PROP = "netconf.";
- private NetconfConfigUtil() {}
+ private NetconfConfigUtil() {
+ }
private enum InfixProp {
tcp, ssh
private static final String ADDRESS_SUFFIX_PROP = ".address";
private static final String CLIENT_PROP = ".client";
private static final String PRIVATE_KEY_PATH_PROP = ".pk.path";
- private static final String SSH_DEFAULT_USER = ".default.user";
- private static final String SSH_DEFAULT_PASSWORD = ".default.password";
private static final String CONNECTION_TIMEOUT_MILLIS_PROP = "connectionTimeoutMillis";
private static final long DEFAULT_TIMEOUT_MILLIS = 5000;
- public static long extractTimeoutMillis(BundleContext bundleContext) {
- String key = PREFIX_PROP + CONNECTION_TIMEOUT_MILLIS_PROP;
- String timeoutString = bundleContext.getProperty(key);
+ public static long extractTimeoutMillis(final BundleContext bundleContext) {
+ final String key = PREFIX_PROP + CONNECTION_TIMEOUT_MILLIS_PROP;
+ final String timeoutString = bundleContext.getProperty(key);
if (timeoutString == null || timeoutString.length() == 0) {
return DEFAULT_TIMEOUT_MILLIS;
}
try {
return Long.parseLong(timeoutString);
- }catch(NumberFormatException e) {
+ } catch (final NumberFormatException e) {
logger.warn("Cannot parse {} property: {}, using defaults", key, timeoutString, e);
return DEFAULT_TIMEOUT_MILLIS;
}
}
- public static InetSocketAddress extractTCPNetconfAddress(BundleContext context, String exceptionMessageIfNotFound, boolean forClient) {
-
- Optional<InetSocketAddress> inetSocketAddressOptional = extractSomeNetconfAddress(context, InfixProp.tcp, exceptionMessageIfNotFound, forClient);
-
- if (!inetSocketAddressOptional.isPresent()) {
- throw new IllegalStateException("Netconf tcp address not found." + exceptionMessageIfNotFound);
- }
- InetSocketAddress inetSocketAddress = inetSocketAddressOptional.get();
- if (inetSocketAddress.getAddress().isAnyLocalAddress()) {
+ public static InetSocketAddress extractTCPNetconfServerAddress(final BundleContext context, final InetSocketAddress defaultAddress) {
+ final Optional<InetSocketAddress> extracted = extractNetconfServerAddress(context, InfixProp.tcp);
+ final InetSocketAddress netconfTcpAddress = getNetconfAddress(defaultAddress, extracted, InfixProp.tcp);
+ logger.debug("Using {} as netconf tcp address", netconfTcpAddress);
+ if (netconfTcpAddress.getAddress().isAnyLocalAddress()) {
logger.warn("Unprotected netconf TCP address is configured to ANY local address. This is a security risk. " +
"Consider changing {} to 127.0.0.1", PREFIX_PROP + InfixProp.tcp + ADDRESS_SUFFIX_PROP);
}
- return inetSocketAddress;
+ return netconfTcpAddress;
}
- public static Optional<InetSocketAddress> extractSSHNetconfAddress(BundleContext context, String exceptionMessage) {
- return extractSomeNetconfAddress(context, InfixProp.ssh, exceptionMessage, false);
+ public static InetSocketAddress extractTCPNetconfClientAddress(final BundleContext context, final InetSocketAddress defaultAddress) {
+ final Optional<InetSocketAddress> extracted = extractNetconfClientAddress(context, InfixProp.tcp);
+ return getNetconfAddress(defaultAddress, extracted, InfixProp.tcp);
}
- public static String getPrivateKeyPath(BundleContext context){
- return getPropertyValue(context,PREFIX_PROP + InfixProp.ssh +PRIVATE_KEY_PATH_PROP);
+ /**
+ * Get extracted address or default.
+ *
+ * @throws java.lang.IllegalStateException if neither address is present.
+ */
+ private static InetSocketAddress getNetconfAddress(final InetSocketAddress defaultAddress, Optional<InetSocketAddress> extractedAddress, InfixProp infix) {
+ InetSocketAddress inetSocketAddress;
+
+ if (extractedAddress.isPresent() == false) {
+ logger.debug("Netconf {} address not found, falling back to default {}", infix, defaultAddress);
+
+ if (defaultAddress == null) {
+ logger.warn("Netconf {} address not found, default address not provided", infix);
+ throw new IllegalStateException("Netconf " + infix + " address not found, default address not provided");
+ }
+ inetSocketAddress = defaultAddress;
+ } else {
+ inetSocketAddress = extractedAddress.get();
+ }
+
+ return inetSocketAddress;
}
- public static Optional<String> getSSHDefaultUser(BundleContext context){
- return getOptionalPropertyValue(context,PREFIX_PROP + InfixProp.ssh +SSH_DEFAULT_USER);
+
+ public static InetSocketAddress extractSSHNetconfAddress(final BundleContext context, final InetSocketAddress defaultAddress) {
+ Optional<InetSocketAddress> extractedAddress = extractNetconfServerAddress(context, InfixProp.ssh);
+ InetSocketAddress netconfSSHAddress = getNetconfAddress(defaultAddress, extractedAddress, InfixProp.ssh);
+ logger.debug("Using {} as netconf SSH address", netconfSSHAddress);
+ return netconfSSHAddress;
}
- public static Optional<String> getSSHDefaultPassword(BundleContext context){
- return getOptionalPropertyValue(context,PREFIX_PROP + InfixProp.ssh +SSH_DEFAULT_PASSWORD);
+
+ public static String getPrivateKeyPath(final BundleContext context) {
+ return getPropertyValue(context, PREFIX_PROP + InfixProp.ssh + PRIVATE_KEY_PATH_PROP);
}
- private static String getPropertyValue(BundleContext context, String propertyName){
- String propertyValue = context.getProperty(propertyName);
- if (propertyValue == null){
- throw new IllegalStateException("Cannot find initial property with name '"+propertyName+"'");
+ private static String getPropertyValue(final BundleContext context, final String propertyName) {
+ final String propertyValue = context.getProperty(propertyName);
+ if (propertyValue == null) {
+ throw new IllegalStateException("Cannot find initial property with name '" + propertyName + "'");
}
return propertyValue;
}
- private static Optional<String> getOptionalPropertyValue(BundleContext context, String propertyName){
- String propertyValue = context.getProperty(propertyName);
- if (Strings.isNullOrEmpty(propertyValue)){
- return Optional.absent();
- }
- return Optional.fromNullable(propertyValue);
- }
+
/**
- * @param context
- * from which properties are being read.
- * @param infixProp
- * either tcp or ssh
- * @return value if address and port are valid.
- * @throws IllegalStateException
- * if address or port are invalid, or configuration is missing
+ * @param context from which properties are being read.
+ * @param infixProp either tcp or ssh
+ * @return value if address and port are present and valid, Optional.absent otherwise.
+ * @throws IllegalStateException if address or port are invalid, or configuration is missing
*/
- private static Optional<InetSocketAddress> extractSomeNetconfAddress(BundleContext context,
- InfixProp infixProp,
- String exceptionMessage,
- boolean client) {
- String address = "";
- if (client) {
- address = context.getProperty(PREFIX_PROP + infixProp + CLIENT_PROP + ADDRESS_SUFFIX_PROP);
- }
- if (address == null || address.equals("")){
- address = context.getProperty(PREFIX_PROP + infixProp + ADDRESS_SUFFIX_PROP);
- }
- if (address == null || address.equals("")) {
- throw new IllegalStateException("Cannot find initial netconf configuration for parameter "
- +PREFIX_PROP + infixProp + ADDRESS_SUFFIX_PROP
- +" in config.ini. "+exceptionMessage);
- }
- String portKey = "";
- if (client) {
- portKey = PREFIX_PROP + infixProp + CLIENT_PROP + PORT_SUFFIX_PROP;
+ private static Optional<InetSocketAddress> extractNetconfServerAddress(final BundleContext context,
+ final InfixProp infixProp) {
+
+ final Optional<String> address = getProperty(context, PREFIX_PROP + infixProp + ADDRESS_SUFFIX_PROP);
+ final Optional<String> port = getProperty(context, PREFIX_PROP + infixProp + PORT_SUFFIX_PROP);
+
+ if (address.isPresent() && port.isPresent()) {
+ try {
+ return Optional.of(parseAddress(address, port));
+ } catch (final RuntimeException e) {
+ logger.warn("Unable to parse {} netconf address from {}:{}, fallback to default",
+ infixProp, address, port, e);
+ }
}
- if (portKey == null || portKey.equals("")){
- portKey = PREFIX_PROP + infixProp + PORT_SUFFIX_PROP;
+ return Optional.absent();
+ }
+
+ private static InetSocketAddress parseAddress(final Optional<String> address, final Optional<String> port) {
+ final int portNumber = Integer.valueOf(port.get());
+ return new InetSocketAddress(address.get(), portNumber);
+ }
+
+ private static Optional<InetSocketAddress> extractNetconfClientAddress(final BundleContext context,
+ final InfixProp infixProp) {
+ final Optional<String> address = getProperty(context,
+ PREFIX_PROP + infixProp + CLIENT_PROP + ADDRESS_SUFFIX_PROP);
+ final Optional<String> port = getProperty(context,
+ PREFIX_PROP + infixProp + CLIENT_PROP + PORT_SUFFIX_PROP);
+
+ if (address.isPresent() && port.isPresent()) {
+ try {
+ return Optional.of(parseAddress(address, port));
+ } catch (final RuntimeException e) {
+ logger.warn("Unable to parse client {} netconf address from {}:{}, fallback to server address",
+ infixProp, address, port, e);
+ }
}
- String portString = context.getProperty(portKey);
- checkNotNull(portString, "Netconf port must be specified in properties file with " + portKey);
- try {
- int port = Integer.valueOf(portString);
- return Optional.of(new InetSocketAddress(address, port));
- } catch (RuntimeException e) {
- throw new IllegalStateException("Cannot create " + infixProp + " netconf address from address:" + address
- + " and port:" + portString, e);
+ return extractNetconfServerAddress(context, infixProp);
+ }
+
+ private static Optional<String> getProperty(final BundleContext context, final String propKey) {
+ String value = context.getProperty(propKey);
+ if (value != null && value.isEmpty()) {
+ value = null;
}
+ return Optional.fromNullable(value);
}
}
import org.custommonkey.xmlunit.NodeTest;
import org.custommonkey.xmlunit.NodeTestException;
import org.custommonkey.xmlunit.NodeTester;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
@Override
public void noMoreNodes(NodeTest forTest) throws NodeTestException {
- assertTrue(elementFound);
+ assertTrue(XmlUtil.toString(doc), elementFound);
}
};
assertNodeTestPasses(nt, tester, new short[]{Node.ELEMENT_NODE}, true);
</type>
<name>instance-from-code</name>
+ <impl-netconf xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ <sleep-factor>
+ 2.58
+ </sleep-factor>
- <sleep-factor>
- 2.58
- </sleep-factor>
+ <extended>
+ 10
+ </extended>
- <extended>
- 10
- </extended>
+ <extended-twice>
+ 20
+ </extended-twice>
- <extended-twice>
- 20
- </extended-twice>
+ <extended-enum>
+ TWO
+ </extended-enum>
- <extended-enum>
- TWO
- </extended-enum>
+ <simple-long-2>44</simple-long-2>
+ <binaryLeaf>YmluYXJ5</binaryLeaf>
- <simple-long-2>44</simple-long-2>
- <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>
- <simple-int2>4444</simple-int2>
- <simple-int3>454</simple-int3>
- <complex-dto-bInner>
- <simple-int3>44</simple-int3>
- <deep>
- <simple-int3>4</simple-int3>
- </deep>
+ <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>
+ <simple-int2>4444</simple-int2>
+ <simple-int3>454</simple-int3>
+ <complex-dto-bInner>
+ <simple-int3>44</simple-int3>
+ <deep>
+ <simple-int3>4</simple-int3>
+ </deep>
+ <simple-list>4</simple-list>
+ </complex-dto-bInner>
<simple-list>4</simple-list>
- </complex-dto-bInner>
- <simple-list>4</simple-list>
- </dto_d>
- <simpleInt>44</simpleInt>
- <simple-test>545</simple-test>
- <simple-long>454545</simple-long>
- <simpleBoolean>false</simpleBoolean>
- <dto-c>
- <dto-a-inner>
- <dto-a-inner-inner>
- <simple-arg>456</simple-arg>
- </dto-a-inner-inner>
- <simple-arg>44</simple-arg>
- </dto-a-inner>
- </dto-c>
- <simple-short>4</simple-short>
- <simple-BigInteger>999</simple-BigInteger>
- <simple-byte>4</simple-byte>
- <peers>
- <port>port1</port>
- <simple-int3>456</simple-int3>
- <core-size>44</core-size>
- </peers>
- <peers>
- <port>port23</port>
- <simple-int3>456</simple-int3>
- <core-size>44</core-size>
- </peers>
- <testing-dep>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep_user</name>
- </testing-dep>
+ </dto_d>
+ <simpleInt>44</simpleInt>
+ <simple-test>545</simple-test>
+ <simple-long>454545</simple-long>
+ <simpleBoolean>false</simpleBoolean>
+ <dto-c>
+ <dto-a-inner>
+ <dto-a-inner-inner>
+ <simple-arg>456</simple-arg>
+ </dto-a-inner-inner>
+ <simple-arg>44</simple-arg>
+ </dto-a-inner>
+ </dto-c>
+ <simple-short>4</simple-short>
+ <simple-BigInteger>999</simple-BigInteger>
+ <simple-byte>4</simple-byte>
+ <peers>
+ <port>port1</port>
+ <simple-int3>456</simple-int3>
+ <core-size>44</core-size>
+ </peers>
+ <peers>
+ <port>port23</port>
+ <simple-int3>456</simple-int3>
+ <core-size>44</core-size>
+ </peers>
+ <testing-dep>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <name>ref_dep_user</name>
+ </testing-dep>
- <testing-deps>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep_user</name>
- </testing-deps>
- <testing-deps>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep_user_two</name>
- </testing-deps>
+ <testing-deps>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <name>ref_dep_user</name>
+ </testing-deps>
+ <testing-deps>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <name>ref_dep_user_two</name>
+ </testing-deps>
+ </impl-netconf>
</module>
<module>
test-impl:impl-netconf
</type>
<name>test2</name>
- <simple-short>4</simple-short>
-
- <testing-dep>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep_user_two</name>
- </testing-dep>
+ <impl-netconf xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ <simple-short>4</simple-short>
+ <testing-dep>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <name>ref_dep_user_two</name>
+ </testing-dep>
+ </impl-netconf>
</module>
</modules>
test-impl:impl-netconf
</type>
<name>instance-from-code</name>
- <simple-long-2>44</simple-long-2>
- <binaryLeaf>8ad1</binaryLeaf>
- <dto_d>
- <simple-int1>444</simple-int1>
- <simple-int2>4444</simple-int2>
- <simple-int3>454</simple-int3>
- <complex-dto-bInner>
- <simple-int3>44</simple-int3>
- <deep>
- <simple-int3>4</simple-int3>
- </deep>
+ <impl-netconf xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ <simple-long-2>44</simple-long-2>
+ <binaryLeaf>8ad1</binaryLeaf>
+ <dto_d>
+ <simple-int1>444</simple-int1>
+ <simple-int2>4444</simple-int2>
+ <simple-int3>454</simple-int3>
+ <complex-dto-bInner>
+ <simple-int3>44</simple-int3>
+ <deep>
+ <simple-int3>4</simple-int3>
+ </deep>
+ <simple-list>4</simple-list>
+ </complex-dto-bInner>
<simple-list>4</simple-list>
- </complex-dto-bInner>
- <simple-list>4</simple-list>
- </dto_d>
- <simpleInt>44</simpleInt>
- <simple-test>545</simple-test>
- <simple-long>454545</simple-long>
- <simpleBoolean>false</simpleBoolean>
- <dto-c>
- <dto-a-inner>
- <dto-a-inner-inner>
- <simple-arg>456</simple-arg>
- </dto-a-inner-inner>
- <simple-arg>44</simple-arg>
- </dto-a-inner>
- </dto-c>
- <simple-short>4</simple-short>
- <simple-BigInteger>999</simple-BigInteger>
- <simple-byte>4</simple-byte>
- <peers>
- <port>port1</port>
- <simple-int3>456</simple-int3>
- <core-size>44</core-size>
- </peers>
- <peers>
- <port>port23</port>
- <simple-int3>456</simple-int3>
- <core-size>44</core-size>
- </peers>
+ </dto_d>
+ <simpleInt>44</simpleInt>
+ <simple-test>545</simple-test>
+ <simple-long>454545</simple-long>
+ <simpleBoolean>false</simpleBoolean>
+ <dto-c>
+ <dto-a-inner>
+ <dto-a-inner-inner>
+ <simple-arg>456</simple-arg>
+ </dto-a-inner-inner>
+ <simple-arg>44</simple-arg>
+ </dto-a-inner>
+ </dto-c>
+ <simple-short>4</simple-short>
+ <simple-BigInteger>999</simple-BigInteger>
+ <simple-byte>4</simple-byte>
+ <peers>
+ <port>port1</port>
+ <simple-int3>456</simple-int3>
+ <core-size>44</core-size>
+ </peers>
+ <peers>
+ <port>port23</port>
+ <simple-int3>456</simple-int3>
+ <core-size>44</core-size>
+ </peers>
+ </impl-netconf>
</module>
<module>
<type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
</type>
<name>instance-from-code</name>
-
- <ip xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">127.1.2.3</ip>
- <union-test-attr xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">randomStringForUnion</union-test-attr>
-
+ <impl-netconf xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ <ip xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">127.1.2.3</ip>
+ <union-test-attr xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">randomStringForUnion</union-test-attr>
+ </impl-netconf>
</module>
</modules>
</type>
<name>test1</name>
-
- <simple-long-2>44</simple-long-2>
- <binaryLeaf>8545649856</binaryLeaf>
- <type xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">configAttributeType</type>
- <dto_d>
- <simple-int1>444</simple-int1>
- <simple-int2 xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">4444</simple-int2>
- <simple-int3>454</simple-int3>
- <complex-dto-bInner>
- <simple-int3>44</simple-int3>
- <deep>
- <simple-int3>4</simple-int3>
- </deep>
+ <impl-netconf xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ <simple-long-2>44</simple-long-2>
+ <binaryLeaf>8545649856</binaryLeaf>
+ <type xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">configAttributeType</type>
+ <dto_d>
+ <simple-int1>444</simple-int1>
+ <simple-int2 xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl2">4444</simple-int2>
+ <simple-int3>454</simple-int3>
+ <complex-dto-bInner>
+ <simple-int3>44</simple-int3>
+ <deep>
+ <simple-int3>4</simple-int3>
+ </deep>
+ <simple-list>4</simple-list>
+ </complex-dto-bInner>
<simple-list>4</simple-list>
- </complex-dto-bInner>
- <simple-list>4</simple-list>
- </dto_d>
- <simpleInt>44</simpleInt>
- <simple-test>545</simple-test>
- <simple-long>454545</simple-long>
- <simpleBoolean>false</simpleBoolean>
- <dto-c>
- <dto-a-inner>
- <dto-a-inner-inner>
- <simple-arg>456</simple-arg>
- </dto-a-inner-inner>
- <simple-arg>44</simple-arg>
- </dto-a-inner>
- </dto-c>
- <simple-short>4</simple-short>
- <simple-BigInteger>999</simple-BigInteger>
- <simple-byte>4</simple-byte>
- <peers>
- <port>port1</port>
- <simple-int3>456</simple-int3>
- <core-size>44</core-size>
- </peers>
- <peers>
- <port>port23</port>
- <simple-int3>456</simple-int3>
- <core-size>44</core-size>
- </peers>
- <testing-dep>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep</name>
- </testing-dep>
+ </dto_d>
+ <simpleInt>44</simpleInt>
+ <simple-test>545</simple-test>
+ <simple-long>454545</simple-long>
+ <simpleBoolean>false</simpleBoolean>
+ <dto-c>
+ <dto-a-inner>
+ <dto-a-inner-inner>
+ <simple-arg>456</simple-arg>
+ </dto-a-inner-inner>
+ <simple-arg>44</simple-arg>
+ </dto-a-inner>
+ </dto-c>
+ <simple-short>4</simple-short>
+ <simple-BigInteger>999</simple-BigInteger>
+ <simple-byte>4</simple-byte>
+ <peers>
+ <port>port1</port>
+ <simple-int3>456</simple-int3>
+ <core-size>44</core-size>
+ </peers>
+ <peers>
+ <port>port23</port>
+ <simple-int3>456</simple-int3>
+ <core-size>44</core-size>
+ </peers>
+ <testing-dep>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <name>ref_dep</name>
+ </testing-dep>
+ </impl-netconf>
</module>
<module>
test-impl:impl-netconf
</type>
<name>test2</name>
- <testing-dep>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep</name>
- </testing-dep>
+ <impl-netconf xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ <testing-dep>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <name>ref_dep</name>
+ </testing-dep>
+ </impl-netconf>
</module>
</modules>
</type>
</module>
+ <module>
+ <type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ test-impl:impl
+ </type>
+
+ <name>testimpl</name>
+ <simpleInt>1</simpleInt>
+ <simpleInt xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">2</simpleInt>
+ </module>
+
<module>
<type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
test-impl:impl-netconf
</type>
<name>test1</name>
-
- <simple-long-2>44</simple-long-2>
- <simple-long-2 xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">44</simple-long-2>
- <binaryLeaf>8</binaryLeaf>
- <binaryLeaf>1</binaryLeaf>
- <binaryLeaf>0</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>
- <simple-int2>4444</simple-int2>
- <simple-int3>454</simple-int3>
- <complex-dto-bInner>
- <simple-int3>44</simple-int3>
- <deep>
- <simple-int3>4</simple-int3>
- </deep>
+ <impl-netconf xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ <simple-long-2>44</simple-long-2>
+ <simple-long-2 xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">44</simple-long-2>
+ <binaryLeaf></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>
+ <simple-int2>4444</simple-int2>
+ <simple-int3>454</simple-int3>
+ <complex-dto-bInner>
+ <simple-int3>44</simple-int3>
+ <deep>
+ <simple-int3>4</simple-int3>
+ </deep>
+ <simple-list>4</simple-list>
+ </complex-dto-bInner>
<simple-list>4</simple-list>
- </complex-dto-bInner>
- <simple-list>4</simple-list>
- </dto_d>
- <simpleInt>44</simpleInt>
- <simple-test>545</simple-test>
- <simple-long>454545</simple-long>
- <simpleBoolean>false</simpleBoolean>
- <dto-c>
- <dto-a-inner>
- <dto-a-inner-inner>
- <simple-arg>456</simple-arg>
- </dto-a-inner-inner>
- <simple-arg>44</simple-arg>
- </dto-a-inner>
- </dto-c>
- <simple-short>4</simple-short>
- <simple-BigInteger>999</simple-BigInteger>
- <simple-byte>4</simple-byte>
- <peers>
- <port>port1</port>
- <simple-int3>456</simple-int3>
- <core-size>44</core-size>
- </peers>
- <peers>
- <port>port23</port>
- <simple-int3>456</simple-int3>
- <core-size>44</core-size>
- </peers>
- <testing-dep>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep</name>
- </testing-dep>
+ </dto_d>
+ <simpleInt>44</simpleInt>
+ <simple-test>545</simple-test>
+ <simple-long>454545</simple-long>
+ <simpleBoolean>false</simpleBoolean>
+ <dto-c>
+ <dto-a-inner>
+ <dto-a-inner-inner>
+ <simple-arg>456</simple-arg>
+ </dto-a-inner-inner>
+ <simple-arg>44</simple-arg>
+ </dto-a-inner>
+ </dto-c>
+ <simple-short>4</simple-short>
+ <simple-BigInteger>999</simple-BigInteger>
+ <simple-byte>4</simple-byte>
+ <peers>
+ <port>port1</port>
+ <simple-int3>456</simple-int3>
+ <core-size>44</core-size>
+ </peers>
+ <peers>
+ <port>port23</port>
+ <simple-int3>456</simple-int3>
+ <core-size>44</core-size>
+ </peers>
+ <testing-dep>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <name>ref_dep</name>
+ </testing-dep>
+ </impl-netconf>
</module>
<module>
test-impl:impl-netconf
</type>
<name>test2</name>
- <testing-dep>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep</name>
- </testing-dep>
+ <impl-netconf xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ <testing-dep>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <name>ref_dep</name>
+ </testing-dep>
+ </impl-netconf>
</module>
</modules>
<module>
<type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
- test-impl:impl-netconf
+ test-impl:impl
</type>
<name>test1</name>
-
- <simple-long-2>44</simple-long-2>
- <binaryLeaf>8</binaryLeaf>
- <binaryLeaf xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">1</binaryLeaf>
- <binaryLeaf>0</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>
- <simple-int2>4444</simple-int2>
- <simple-int3>454</simple-int3>
- <complex-dto-bInner>
- <simple-int3>44</simple-int3>
- <deep>
- <simple-int3>4</simple-int3>
- </deep>
- <simple-list>4</simple-list>
- </complex-dto-bInner>
- <simple-list>4</simple-list>
- </dto_d>
- <simpleInt>44</simpleInt>
- <simple-test>545</simple-test>
- <simple-long>454545</simple-long>
- <simpleBoolean>false</simpleBoolean>
- <dto-c>
- <dto-a-inner>
- <dto-a-inner-inner>
- <simple-arg>456</simple-arg>
- </dto-a-inner-inner>
- <simple-arg>44</simple-arg>
- </dto-a-inner>
- </dto-c>
- <simple-short>4</simple-short>
- <simple-BigInteger>999</simple-BigInteger>
- <simple-byte>4</simple-byte>
- <peers>
- <port>port1</port>
- <simple-int3>456</simple-int3>
- <core-size>44</core-size>
- </peers>
- <peers>
- <port>port23</port>
- <simple-int3>456</simple-int3>
- <core-size>44</core-size>
- </peers>
- <testing-dep>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep</name>
- </testing-dep>
+ <allow-user>1</allow-user>
+ <allow-user xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">2</allow-user>
</module>
<module>
test-impl:impl-netconf
</type>
<name>test2</name>
- <testing-dep>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep</name>
- </testing-dep>
+ <impl-netconf xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ <testing-dep>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <name>ref_dep</name>
+ </testing-dep>
+ </impl-netconf>
</module>
</modules>
<services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
- <service>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <instance>
- <name>ref_dep</name>
- <provider>/modules/module[type='impl-dep'][name='dep']
- </provider>
- </instance>
- <instance>
- <name>ref_dep_2</name>
- <provider>/modules/module[type='impl-dep'][name='dep2']
- </provider>
- </instance>
- <instance>
- <name>ref_test1</name>
- <provider>
- /modules/module[type='impl-netconf'][name='test1']
- </provider>
- </instance>
- </service>
+
</services>
</config>
</edit-config>
</type>
<name>test1</name>
-
- <simple-long-2>44</simple-long-2>
- <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>
- <simple-int3>454</simple-int3>
- <complex-dto-bInner>
- <simple-int3>44</simple-int3>
- <deep>
- <simple-int3>4</simple-int3>
- </deep>
+ <impl-netconf xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ <simple-long-2>44</simple-long-2>
+ <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>
+ <simple-int3>454</simple-int3>
+ <complex-dto-bInner>
+ <simple-int3>44</simple-int3>
+ <deep>
+ <simple-int3>4</simple-int3>
+ </deep>
+ <simple-list>4</simple-list>
+ </complex-dto-bInner>
<simple-list>4</simple-list>
- </complex-dto-bInner>
- <simple-list>4</simple-list>
- </dto_d>
- <simpleInt>44</simpleInt>
- <simple-test>545</simple-test>
- <simple-long>454545</simple-long>
- <simpleBoolean>false</simpleBoolean>
- <dto-c>
- <dto-a-inner>
- <dto-a-inner-inner>
- <simple-arg>456</simple-arg>
- </dto-a-inner-inner>
- <simple-arg>44</simple-arg>
- </dto-a-inner>
- </dto-c>
- <simple-short>4</simple-short>
- <simple-BigInteger>999</simple-BigInteger>
- <simple-byte>4</simple-byte>
- <peers>
- <port>port1</port>
- <simple-int3>456</simple-int3>
- <core-size>44</core-size>
- </peers>
- <peers>
- <port>port23</port>
- <simple-int3>456</simple-int3>
- <core-size>44</core-size>
- </peers>
- <testing-dep>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep</name>
- </testing-dep>
+ </dto_d>
+ <simpleInt>44</simpleInt>
+ <simple-test>545</simple-test>
+ <simple-long>454545</simple-long>
+ <simpleBoolean>false</simpleBoolean>
+ <dto-c>
+ <dto-a-inner>
+ <dto-a-inner-inner>
+ <simple-arg>456</simple-arg>
+ </dto-a-inner-inner>
+ <simple-arg>44</simple-arg>
+ </dto-a-inner>
+ </dto-c>
+ <simple-short>4</simple-short>
+ <simple-BigInteger>999</simple-BigInteger>
+ <simple-byte>4</simple-byte>
+ <peers>
+ <port>port1</port>
+ <simple-int3>456</simple-int3>
+ <core-size>44</core-size>
+ </peers>
+ <peers>
+ <port>port23</port>
+ <simple-int3>456</simple-int3>
+ <core-size>44</core-size>
+ </peers>
+ <testing-dep>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <name>ref_dep</name>
+ </testing-dep>
+ </impl-netconf>
</module>
<module>
test-impl:impl-netconf
</type>
<name>test2</name>
- <testing-dep>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep</name>
- </testing-dep>
+ <impl-netconf xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ <testing-dep>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <name>ref_dep</name>
+ </testing-dep>
+ </impl-netconf>
</module>
</modules>
</type>
<name>test1</name>
-
- <simple-long-2>44</simple-long-2>
- <binaryLeaf>8545649856</binaryLeaf>
- <dto_d>
- <unknownAttribute>error</unknownAttribute>
- <simple-int1>444</simple-int1>
- <simple-int2>4444</simple-int2>
- <simple-int3>454</simple-int3>
- <complex-dto-bInner>
- <simple-int3>44</simple-int3>
- <deep>
- <simple-int3>4</simple-int3>
- </deep>
+ <impl-netconf xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ <simple-long-2>44</simple-long-2>
+ <binaryLeaf>8545649856</binaryLeaf>
+ <dto_d>
+ <unknownAttribute>error</unknownAttribute>
+ <simple-int1>444</simple-int1>
+ <simple-int2>4444</simple-int2>
+ <simple-int3>454</simple-int3>
+ <complex-dto-bInner>
+ <simple-int3>44</simple-int3>
+ <deep>
+ <simple-int3>4</simple-int3>
+ </deep>
+ <simple-list>4</simple-list>
+ </complex-dto-bInner>
<simple-list>4</simple-list>
- </complex-dto-bInner>
- <simple-list>4</simple-list>
- </dto_d>
- <simpleInt>44</simpleInt>
- <simple-test>545</simple-test>
- <simple-long>454545</simple-long>
- <simpleBoolean>false</simpleBoolean>
- <dto-c>
- <dto-a-inner>
- <dto-a-inner-inner>
- <simple-arg>456</simple-arg>
- </dto-a-inner-inner>
- <simple-arg>44</simple-arg>
- </dto-a-inner>
- </dto-c>
- <simple-short>4</simple-short>
- <simple-BigInteger>999</simple-BigInteger>
- <simple-byte>4</simple-byte>
- <peers>
- <port>port1</port>
- <simple-int3>456</simple-int3>
- <core-size>44</core-size>
- </peers>
- <peers>
- <port>port23</port>
- <simple-int3>456</simple-int3>
- <core-size>44</core-size>
- </peers>
- <testing-dep>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep</name>
- </testing-dep>
+ </dto_d>
+ <simpleInt>44</simpleInt>
+ <simple-test>545</simple-test>
+ <simple-long>454545</simple-long>
+ <simpleBoolean>false</simpleBoolean>
+ <dto-c>
+ <dto-a-inner>
+ <dto-a-inner-inner>
+ <simple-arg>456</simple-arg>
+ </dto-a-inner-inner>
+ <simple-arg>44</simple-arg>
+ </dto-a-inner>
+ </dto-c>
+ <simple-short>4</simple-short>
+ <simple-BigInteger>999</simple-BigInteger>
+ <simple-byte>4</simple-byte>
+ <peers>
+ <port>port1</port>
+ <simple-int3>456</simple-int3>
+ <core-size>44</core-size>
+ </peers>
+ <peers>
+ <port>port23</port>
+ <simple-int3>456</simple-int3>
+ <core-size>44</core-size>
+ </peers>
+ <testing-dep>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <name>ref_dep</name>
+ </testing-dep>
+ </impl-netconf>
</module>
<module>
test-impl:impl-netconf
</type>
<name>test2</name>
- <testing-dep>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep</name>
- </testing-dep>
+ <impl-netconf xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ <testing-dep>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <name>ref_dep</name>
+ </testing-dep>
+ </impl-netconf>
</module>
</modules>
</type>
<name>test1</name>
-
- <simple-long-2>44</simple-long-2>
- <binaryLeaf>8545649856</binaryLeaf>
- <dto_d>
- <simple-int1>444</simple-int1>
- <simple-int2>4444</simple-int2>
- <simple-int3>454</simple-int3>
- <complex-dto-bInner>
- <simple-int3>44</simple-int3>
- <deep>
- <simple-int3>4</simple-int3>
- </deep>
+ <impl-netconf xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ <simple-long-2>44</simple-long-2>
+ <binaryLeaf>8545649856</binaryLeaf>
+ <dto_d>
+ <simple-int1>444</simple-int1>
+ <simple-int2>4444</simple-int2>
+ <simple-int3>454</simple-int3>
+ <complex-dto-bInner>
+ <simple-int3>44</simple-int3>
+ <deep>
+ <simple-int3>4</simple-int3>
+ </deep>
+ <simple-list>4</simple-list>
+ </complex-dto-bInner>
<simple-list>4</simple-list>
- </complex-dto-bInner>
- <simple-list>4</simple-list>
- </dto_d>
- <simpleInt>44</simpleInt>
- <simple-test>545</simple-test>
- <simple-long>454545</simple-long>
- <simpleBoolean>false</simpleBoolean>
- <dto-c>
- <dto-a-inner>
- <dto-a-inner-inner>
- <simple-arg>456</simple-arg>
- </dto-a-inner-inner>
- <simple-arg>44</simple-arg>
- </dto-a-inner>
- </dto-c>
- <simple-short>4</simple-short>
- <simple-BigInteger>999</simple-BigInteger>
- <simple-byte>4</simple-byte>
- <peers>
- <port>port1</port>
- <simple-int3>456</simple-int3>
- <core-size>44</core-size>
- </peers>
- <peers>
- <port>port23</port>
- <simple-int3>456</simple-int3>
- <core-size>44</core-size>
- <unknownAttribute>error</unknownAttribute>
- </peers>
- <testing-dep>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep</name>
- </testing-dep>
+ </dto_d>
+ <simpleInt>44</simpleInt>
+ <simple-test>545</simple-test>
+ <simple-long>454545</simple-long>
+ <simpleBoolean>false</simpleBoolean>
+ <dto-c>
+ <dto-a-inner>
+ <dto-a-inner-inner>
+ <simple-arg>456</simple-arg>
+ </dto-a-inner-inner>
+ <simple-arg>44</simple-arg>
+ </dto-a-inner>
+ </dto-c>
+ <simple-short>4</simple-short>
+ <simple-BigInteger>999</simple-BigInteger>
+ <simple-byte>4</simple-byte>
+ <peers>
+ <port>port1</port>
+ <simple-int3>456</simple-int3>
+ <core-size>44</core-size>
+ </peers>
+ <peers>
+ <port>port23</port>
+ <simple-int3>456</simple-int3>
+ <core-size>44</core-size>
+ <unknownAttribute>error</unknownAttribute>
+ </peers>
+ <testing-dep>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <name>ref_dep</name>
+ </testing-dep>
+ </impl-netconf>
</module>
<module>
test-impl:impl-netconf
</type>
<name>test2</name>
- <testing-dep>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep</name>
- </testing-dep>
+ <impl-netconf xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ <testing-dep>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <name>ref_dep</name>
+ </testing-dep>
+ </impl-netconf>
</module>
</modules>
import org.opendaylight.controller.networkconfig.neutron.INeutronPortCRUD;
import org.opendaylight.controller.networkconfig.neutron.INeutronRouterCRUD;
import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronSecurityGroupCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronSecurityRuleCRUD;
import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
public class Activator extends ComponentActivatorAbstractBase {
NeutronRouterInterface.class,
NeutronPortInterface.class,
NeutronSubnetInterface.class,
- NeutronNetworkInterface.class };
+ NeutronNetworkInterface.class,
+ NeutronSecurityGroupInterface.class,
+ NeutronSecurityRuleInterface.class};
return res;
}
"setConfigurationContainerService",
"unsetConfigurationContainerService").setRequired(true));
}
+ if (imp.equals(NeutronSecurityGroupInterface.class)) {
+ // export the service
+ c.setInterface(
+ new String[] { INeutronSecurityGroupCRUD.class.getName(),
+ IConfigurationContainerAware.class.getName()}, null);
+ Dictionary<String, String> props = new Hashtable<String, String>();
+ props.put("salListenerName", "neutron");
+ c.add(createContainerServiceDependency(containerName)
+ .setService(IClusterContainerServices.class)
+ .setCallbacks("setClusterContainerService",
+ "unsetClusterContainerService").setRequired(true));
+ c.add(createContainerServiceDependency(containerName).setService(
+ IConfigurationContainerService.class).setCallbacks(
+ "setConfigurationContainerService",
+ "unsetConfigurationContainerService").setRequired(true));
+ }
+ if (imp.equals(NeutronSecurityRuleInterface.class)) {
+ // export the service
+ c.setInterface(
+ new String[] { INeutronSecurityRuleCRUD.class.getName(),
+ IConfigurationContainerAware.class.getName()}, null);
+ Dictionary<String, String> props = new Hashtable<String, String>();
+ props.put("salListenerName", "neutron");
+ c.add(createContainerServiceDependency(containerName)
+ .setService(IClusterContainerServices.class)
+ .setCallbacks("setClusterContainerService",
+ "unsetClusterContainerService").setRequired(true));
+ c.add(createContainerServiceDependency(containerName).setService(
+ IConfigurationContainerService.class).setCallbacks(
+ "setConfigurationContainerService",
+ "unsetConfigurationContainerService").setRequired(true));
+ }
}
}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron.implementation;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Map.Entry;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+import org.apache.felix.dm.Component;
+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.configuration.ConfigurationObject;
+import org.opendaylight.controller.configuration.IConfigurationContainerAware;
+import org.opendaylight.controller.configuration.IConfigurationContainerService;
+import org.opendaylight.controller.networkconfig.neutron.INeutronSecurityGroupCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronSecurityGroup;
+import org.opendaylight.controller.sal.utils.IObjectReader;
+import org.opendaylight.controller.sal.utils.Status;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class NeutronSecurityGroupInterface implements INeutronSecurityGroupCRUD, IConfigurationContainerAware, IObjectReader {
+ private static final Logger logger = LoggerFactory.getLogger(NeutronSecurityGroupInterface.class);
+ private static final String FILE_NAME ="neutron.securitygroup.conf";
+ private String containerName = null;
+
+ private IClusterContainerServices clusterContainerService = null;
+ private IConfigurationContainerService configurationService;
+ private ConcurrentMap<String, NeutronSecurityGroup> securityGroupDB;
+
+ // methods needed for creating caches
+ void setClusterContainerService(IClusterContainerServices s) {
+ logger.debug("Cluster Service set");
+ clusterContainerService = s;
+ }
+
+ void unsetClusterContainerService(IClusterContainerServices s) {
+ if (clusterContainerService == s) {
+ logger.debug("Cluster Service removed!");
+ clusterContainerService = null;
+ }
+ }
+
+ public void setConfigurationContainerService(IConfigurationContainerService service) {
+ logger.trace("Configuration service set: {}", service);
+ configurationService = service;
+ }
+
+ public void unsetConfigurationContainerService(IConfigurationContainerService service) {
+ logger.trace("Configuration service removed: {}", service);
+ configurationService = null;
+ }
+
+ private void allocateCache() {
+ if (this.clusterContainerService == null) {
+ logger.error("un-initialized clusterContainerService, can't create cache");
+ return;
+ }
+ logger.debug("Creating Cache for Neutron Security Groups");
+ try {
+ // neutron caches
+ this.clusterContainerService.createCache("neutronSecurityGroups",
+ EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+ } catch (CacheConfigException cce) {
+ logger.error("Cache couldn't be created for Neutron Security Groups - check cache mode");
+ } catch (CacheExistException cce) {
+ logger.error("Cache for Neutron Security Groups already exists, destroy and recreate");
+ }
+ logger.debug("Cache successfully created for Neutron Security Groups");
+ }
+
+ @SuppressWarnings({ "unchecked" })
+ private void retrieveCache() {
+ if (clusterContainerService == null) {
+ logger.error("un-initialized clusterContainerService, can't retrieve cache");
+ return;
+ }
+
+ logger.debug("Retrieving cache for Neutron Security Groups");
+ securityGroupDB = (ConcurrentMap<String, NeutronSecurityGroup>) clusterContainerService
+ .getCache("neutronSecurityGroups");
+ if (securityGroupDB == null) {
+ logger.error("Cache couldn't be retrieved for Neutron Security Groups");
+ }
+ logger.debug("Cache was successfully retrieved for Neutron Security Groups");
+ }
+
+ private void destroyCache() {
+ if (clusterContainerService == null) {
+ logger.error("un-initialized clusterMger, can't destroy cache");
+ return;
+ }
+ logger.debug("Destroying Cache for Neutron Security Groups");
+ clusterContainerService.destroyCache("neutronSecurityGroups");
+ }
+
+ private void startUp() {
+ allocateCache();
+ retrieveCache();
+ loadConfiguration();
+ }
+
+ /**
+ * Function called by the dependency manager when all the required
+ * dependencies are satisfied
+ *
+ */
+ void init(Component c) {
+ Dictionary<?, ?> props = c.getServiceProperties();
+ if (props != null) {
+ this.containerName = (String) props.get("containerName");
+ logger.debug("Running containerName: {}", this.containerName);
+ } else {
+ // In the Global instance case the containerName is empty
+ this.containerName = "";
+ }
+ startUp();
+ }
+
+ /**
+ * Function called by the dependency manager when at least one dependency
+ * become unsatisfied or when the component is shutting down because for
+ * example bundle is being stopped.
+ *
+ */
+ void destroy() {
+ destroyCache();
+ }
+
+ /**
+ * Function called by dependency manager after "init ()" is called and after
+ * the services provided by the class are registered in the service registry
+ *
+ */
+ void start() {
+ }
+
+ /**
+ * Function called by the dependency manager before the services exported by
+ * the component are unregistered, this will be followed by a "destroy ()"
+ * calls
+ *
+ */
+ void stop() {
+ }
+
+ // this method uses reflection to update an object from it's delta.
+
+ private boolean overwrite(Object target, Object delta) {
+ Method[] methods = target.getClass().getMethods();
+
+ for(Method toMethod: methods){
+ if(toMethod.getDeclaringClass().equals(target.getClass())
+ && toMethod.getName().startsWith("set")){
+
+ String toName = toMethod.getName();
+ String fromName = toName.replace("set", "get");
+
+ try {
+ Method fromMethod = delta.getClass().getMethod(fromName);
+ Object value = fromMethod.invoke(delta, (Object[])null);
+ if(value != null){
+ toMethod.invoke(target, value);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean neutronSecurityGroupExists(String uuid) {
+ return securityGroupDB.containsKey(uuid);
+ }
+
+ @Override
+ public NeutronSecurityGroup getNeutronSecurityGroup(String uuid) {
+ if (!neutronSecurityGroupExists(uuid)) {
+ logger.debug("No Security Groups Have Been Defined");
+ return null;
+ }
+ return securityGroupDB.get(uuid);
+ }
+
+ @Override
+ public List<NeutronSecurityGroup> getAllNeutronSecurityGroups() {
+ Set<NeutronSecurityGroup> allSecurityGroups = new HashSet<NeutronSecurityGroup>();
+ for (Entry<String, NeutronSecurityGroup> entry : securityGroupDB.entrySet()) {
+ NeutronSecurityGroup securityGroup = entry.getValue();
+ allSecurityGroups.add(securityGroup);
+ }
+ logger.debug("Exiting getSecurityGroups, Found {} OpenStackSecurityGroup", allSecurityGroups.size());
+ List<NeutronSecurityGroup> ans = new ArrayList<NeutronSecurityGroup>();
+ ans.addAll(allSecurityGroups);
+ return ans;
+ }
+
+ @Override
+ public boolean addNeutronSecurityGroup(NeutronSecurityGroup input) {
+ if (neutronSecurityGroupExists(input.getSecurityGroupUUID())) {
+ return false;
+ }
+ securityGroupDB.putIfAbsent(input.getSecurityGroupUUID(), input);
+ return true;
+ }
+
+ @Override
+ public boolean removeNeutronSecurityGroup(String uuid) {
+ if (!neutronSecurityGroupExists(uuid)) {
+ return false;
+ }
+ securityGroupDB.remove(uuid);
+ return true;
+ }
+
+ @Override
+ public boolean updateNeutronSecurityGroup(String uuid, NeutronSecurityGroup delta) {
+ if (!neutronSecurityGroupExists(uuid)) {
+ return false;
+ }
+ NeutronSecurityGroup target = securityGroupDB.get(uuid);
+ return overwrite(target, delta);
+ }
+
+ @Override
+ public boolean neutronSecurityGroupInUse(String securityGroupUUID) {
+ return !neutronSecurityGroupExists(securityGroupUUID);
+ }
+
+ private void loadConfiguration() {
+ for (ConfigurationObject conf : configurationService.retrieveConfiguration(this, FILE_NAME)) {
+ NeutronSecurityGroup nn = (NeutronSecurityGroup) conf;
+ securityGroupDB.put(nn.getSecurityGroupUUID(), nn);
+ }
+ }
+
+ @Override
+ public Status saveConfiguration() {
+ return configurationService.persistConfiguration(new ArrayList<ConfigurationObject>(securityGroupDB.values()),
+ FILE_NAME);
+ }
+
+ @Override
+ public Object readObject(ObjectInputStream ois) throws FileNotFoundException, IOException, ClassNotFoundException {
+ return ois.readObject();
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron.implementation;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Map.Entry;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.felix.dm.Component;
+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.configuration.ConfigurationObject;
+import org.opendaylight.controller.configuration.IConfigurationContainerAware;
+import org.opendaylight.controller.configuration.IConfigurationContainerService;
+import org.opendaylight.controller.networkconfig.neutron.INeutronSecurityRuleCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronSecurityRule;
+import org.opendaylight.controller.sal.utils.IObjectReader;
+import org.opendaylight.controller.sal.utils.Status;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class NeutronSecurityRuleInterface implements INeutronSecurityRuleCRUD, IConfigurationContainerAware, IObjectReader {
+ private static final Logger logger = LoggerFactory.getLogger(NeutronSecurityRuleInterface.class);
+ private static final String FILE_NAME = "neutron.securityrule.conf";
+ private String containerName = null;
+
+ private IClusterContainerServices clusterContainerService = null;
+ private IConfigurationContainerService configurationService;
+ private ConcurrentMap<String, NeutronSecurityRule> securityRuleDB;
+
+ // methods needed for creating caches
+ void setClusterContainerService(IClusterContainerServices s) {
+ logger.debug("Cluster Service set");
+ clusterContainerService = s;
+ }
+
+ void unsetClusterContainerService(IClusterContainerServices s) {
+ if (clusterContainerService == s) {
+ logger.debug("Cluster Service removed!");
+ clusterContainerService = null;
+ }
+ }
+
+ public void setConfigurationContainerService(IConfigurationContainerService service) {
+ logger.trace("Configuration service set: {}", service);
+ configurationService = service;
+ }
+
+ public void unsetConfigurationContainerService(IConfigurationContainerService service) {
+ logger.trace("Configuration service removed: {}", service);
+ configurationService = null;
+ }
+
+ private void allocateCache() {
+ if (this.clusterContainerService == null) {
+ logger.error("un-initialized clusterContainerService, can't create cache");
+ return;
+ }
+ logger.debug("Creating Cache for Neutron Security Rules");
+ try {
+ // neutron caches
+ this.clusterContainerService.createCache("neutronSecurityRules",
+ EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+ } catch (CacheConfigException cce) {
+ logger.error("Cache couldn't be created for Neutron Security Rules - check cache mode");
+ } catch (CacheExistException cce) {
+ logger.error("Cache for Neutron Security Rules already exists, destroy and recreate");
+ }
+ logger.debug("Cache successfully created for Neutron Security Rules");
+ }
+
+ @SuppressWarnings({"unchecked"})
+ private void retrieveCache() {
+ if (clusterContainerService == null) {
+ logger.error("un-initialized clusterContainerService, can't retrieve cache");
+ return;
+ }
+
+ logger.debug("Retrieving cache for Neutron Security Rules");
+ securityRuleDB = (ConcurrentMap<String, NeutronSecurityRule>) clusterContainerService
+ .getCache("neutronSecurityRules");
+ if (securityRuleDB == null) {
+ logger.error("Cache couldn't be retrieved for Neutron Security Rules");
+ }
+ logger.debug("Cache was successfully retrieved for Neutron Security Rules");
+ }
+
+ private void destroyCache() {
+ if (clusterContainerService == null) {
+ logger.error("un-initialized clusterMger, can't destroy cache");
+ return;
+ }
+ logger.debug("Destroying Cache for Neutron Security Rules");
+ clusterContainerService.destroyCache("neutronSecurityRules");
+ }
+
+ private void startUp() {
+ allocateCache();
+ retrieveCache();
+ loadConfiguration();
+ }
+
+ /**
+ * Function called by the dependency manager when all the required
+ * dependencies are satisfied
+ */
+ void init(Component c) {
+ Dictionary<?, ?> props = c.getServiceProperties();
+ if (props != null) {
+ this.containerName = (String) props.get("containerName");
+ logger.debug("Running containerName: {}", this.containerName);
+ } else {
+ // In the Global instance case the containerName is empty
+ this.containerName = "";
+ }
+ startUp();
+ }
+
+ /**
+ * Function called by the dependency manager when at least one dependency
+ * become unsatisfied or when the component is shutting down because for
+ * example bundle is being stopped.
+ */
+ void destroy() {
+ destroyCache();
+ }
+
+ /**
+ * Function called by dependency manager after "init ()" is called and after
+ * the services provided by the class are registered in the service registry
+ */
+ void start() {
+ }
+
+ /**
+ * Function called by the dependency manager before the services exported by
+ * the component are unregistered, this will be followed by a "destroy ()"
+ * calls
+ */
+ void stop() {
+ }
+
+ // this method uses reflection to update an object from it's delta.
+ private boolean overwrite(Object target, Object delta) {
+ Method[] methods = target.getClass().getMethods();
+
+ for (Method toMethod : methods) {
+ if (toMethod.getDeclaringClass().equals(target.getClass())
+ && toMethod.getName().startsWith("set")) {
+
+ String toName = toMethod.getName();
+ String fromName = toName.replace("set", "get");
+
+ try {
+ Method fromMethod = delta.getClass().getMethod(fromName);
+ Object value = fromMethod.invoke(delta, (Object[]) null);
+ if (value != null) {
+ toMethod.invoke(target, value);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean neutronSecurityRuleExists(String uuid) {
+ return securityRuleDB.containsKey(uuid);
+ }
+
+ @Override
+ public NeutronSecurityRule getNeutronSecurityRule(String uuid) {
+ if (!neutronSecurityRuleExists(uuid)) {
+ logger.debug("No Security Rules Have Been Defined");
+ return null;
+ }
+ return securityRuleDB.get(uuid);
+ }
+
+ @Override
+ public List<NeutronSecurityRule> getAllNeutronSecurityRules() {
+ Set<NeutronSecurityRule> allSecurityRules = new HashSet<NeutronSecurityRule>();
+ for (Entry<String, NeutronSecurityRule> entry : securityRuleDB.entrySet()) {
+ NeutronSecurityRule securityRule = entry.getValue();
+ allSecurityRules.add(securityRule);
+ }
+ logger.debug("Exiting getSecurityRule, Found {} OpenStackSecurityRule", allSecurityRules.size());
+ List<NeutronSecurityRule> ans = new ArrayList<NeutronSecurityRule>();
+ ans.addAll(allSecurityRules);
+ return ans;
+ }
+
+ @Override
+ public boolean addNeutronSecurityRule(NeutronSecurityRule input) {
+ if (neutronSecurityRuleExists(input.getSecurityRuleUUID())) {
+ return false;
+ }
+ securityRuleDB.putIfAbsent(input.getSecurityRuleUUID(), input);
+ return true;
+ }
+
+ @Override
+ public boolean removeNeutronSecurityRule(String uuid) {
+ if (!neutronSecurityRuleExists(uuid)) {
+ return false;
+ }
+ securityRuleDB.remove(uuid);
+ return true;
+ }
+
+ @Override
+ public boolean updateNeutronSecurityRule(String uuid, NeutronSecurityRule delta) {
+ if (!neutronSecurityRuleExists(uuid)) {
+ return false;
+ }
+ NeutronSecurityRule target = securityRuleDB.get(uuid);
+ return overwrite(target, delta);
+ }
+
+ @Override
+ public boolean neutronSecurityRuleInUse(String securityRuleUUID) {
+ return !neutronSecurityRuleExists(securityRuleUUID);
+ }
+
+ private void loadConfiguration() {
+ for (ConfigurationObject conf : configurationService.retrieveConfiguration(this, FILE_NAME)) {
+ NeutronSecurityRule nn = (NeutronSecurityRule) conf;
+ securityRuleDB.put(nn.getSecurityRuleUUID(), nn);
+ }
+ }
+
+ @Override
+ public Status saveConfiguration() {
+ return configurationService.persistConfiguration(new ArrayList<ConfigurationObject>(securityRuleDB.values()),
+ FILE_NAME);
+ }
+
+ @Override
+ public Object readObject(ObjectInputStream ois) throws FileNotFoundException, IOException, ClassNotFoundException {
+ return ois.readObject();
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Neutron Security Groups needs to implement
+ */
+
+public interface INeutronSecurityGroupAware {
+
+ /**
+ * Services provide this interface method to indicate if the specified security group can be created
+ *
+ * @param securityGroup instance of proposed new Neutron Security Group object
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the create operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ public int canCreateNeutronSecurityGroup(NeutronSecurityGroup securityGroup);
+
+ /**
+ * Services provide this interface method for taking action after a security group has been created
+ *
+ * @param securityGroup instance of new Neutron Security Group object
+ * @return void
+ */
+ public void neutronSecurityGroupCreated(NeutronSecurityGroup securityGroup);
+
+ /**
+ * Services provide this interface method to indicate if the specified security group can be changed using the specified
+ * delta
+ *
+ * @param delta updates to the security group object using patch semantics
+ * @param original instance of the Neutron Security Group object to be updated
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the update operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ public int canUpdateNeutronSecurityGroup(NeutronSecurityGroup delta, NeutronSecurityGroup original);
+
+ /**
+ * Services provide this interface method for taking action after a security group has been updated
+ *
+ * @param securityGroup instance of modified Neutron Security Group object
+ * @return void
+ */
+ public void neutronSecurityGroupUpdated(NeutronSecurityGroup securityGroup);
+
+ /**
+ * Services provide this interface method to indicate if the specified security group can be deleted
+ *
+ * @param securityGroup instance of the Neutron Security Group object to be deleted
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the delete operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ public int canDeleteNeutronSecurityGroup(NeutronSecurityGroup securityGroup);
+
+ /**
+ * Services provide this interface method for taking action after a security group has been deleted
+ *
+ * @param securityGroup instance of deleted Neutron Security Group object
+ * @return void
+ */
+ public void neutronSecurityGroupDeleted(NeutronSecurityGroup securityGroup);
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron;
+
+import java.util.List;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack Security Group objects
+ */
+
+public interface INeutronSecurityGroupCRUD {
+ /**
+ * Applications call this interface method to determine if a particular
+ * Security Group object exists
+ *
+ * @param uuid UUID of the Security Group object
+ * @return boolean
+ */
+
+ public boolean neutronSecurityGroupExists(String uuid);
+
+ /**
+ * Applications call this interface method to return if a particular
+ * Security Group object exists
+ *
+ * @param uuid UUID of the Security Group object
+ * @return {@link org.opendaylight.controller.networkconfig.neutron.NeutronSecurityGroup.OpenStackSecurity Groups}
+ * OpenStack Security Group class
+ */
+
+ public NeutronSecurityGroup getNeutronSecurityGroup(String uuid);
+
+ /**
+ * Applications call this interface method to return all Security Group objects
+ *
+ * @return List of OpenStackSecurity Groups objects
+ */
+
+ public List<NeutronSecurityGroup> getAllNeutronSecurityGroups();
+
+ /**
+ * Applications call this interface method to add a Security Group object to the
+ * concurrent map
+ *
+ * @param input OpenStackSecurity Group object
+ * @return boolean on whether the object was added or not
+ */
+
+ public boolean addNeutronSecurityGroup(NeutronSecurityGroup input);
+
+ /**
+ * Applications call this interface method to remove a Neutron Security Group object to the
+ * concurrent map
+ *
+ * @param uuid identifier for the security group object
+ * @return boolean on whether the object was removed or not
+ */
+
+ public boolean removeNeutronSecurityGroup(String uuid);
+
+ /**
+ * Applications call this interface method to edit a Security Group object
+ *
+ * @param uuid identifier of the security group object
+ * @param delta OpenStackSecurity Group object containing changes to apply
+ * @return boolean on whether the object was updated or not
+ */
+
+ public boolean updateNeutronSecurityGroup(String uuid, NeutronSecurityGroup delta);
+
+ /**
+ * Applications call this interface method to see if a MAC address is in use
+ *
+ * @param uuid identifier of the security group object
+ * @return boolean on whether the Security Groups is already in use
+ */
+
+ public boolean neutronSecurityGroupInUse(String uuid);
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron;
+
+/**
+ * This interface defines the methods required to be aware of Neutron Security Rules
+ */
+
+public interface INeutronSecurityRuleAware {
+
+ /**
+ * Services provide this interface method to indicate if the specified security rule can be created
+ *
+ * @param securityRule instance of proposed new Neutron Security Rule object
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the create operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ public int canCreateNeutronSecurityRule(NeutronSecurityRule securityRule);
+
+ /**
+ * Services provide this interface method for taking action after a security rule has been created
+ *
+ * @param securityRule instance of new Neutron Security Rule object
+ * @return void
+ */
+ public void neutronSecurityRuleCreated(NeutronSecurityRule securityRule);
+
+ /**
+ * Services provide this interface method to indicate if the specified security rule can be changed using the specified
+ * delta
+ *
+ * @param delta updates to the security rule object using patch semantics
+ * @param original instance of the Neutron Security Rule object to be updated
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the update operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ public int canUpdateNeutronSecurityRule(NeutronSecurityRule delta, NeutronSecurityRule original);
+
+ /**
+ * Services provide this interface method for taking action after a security rule has been updated
+ *
+ * @param securityRule instance of modified Neutron Security Rule object
+ * @return void
+ */
+ public void neutronSecurityRuleUpdated(NeutronSecurityRule securityRule);
+
+ /**
+ * Services provide this interface method to indicate if the specified security rule can be deleted
+ *
+ * @param securityRule instance of the Neutron Security Rule object to be deleted
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the delete operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ public int canDeleteNeutronSecurityRule(NeutronSecurityRule securityRule);
+
+ /**
+ * Services provide this interface method for taking action after a security rule has been deleted
+ *
+ * @param securityRule instance of deleted Neutron Security Rule object
+ * @return void
+ */
+ public void neutronSecurityRuleDeleted(NeutronSecurityRule securityRule);
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron;
+
+import java.util.List;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack Security Rule objects
+ */
+
+public interface INeutronSecurityRuleCRUD {
+ /**
+ * Applications call this interface method to determine if a particular
+ * Security Rule object exists
+ *
+ * @param uuid UUID of theSecurity Rule object
+ * @return boolean
+ */
+
+ public boolean neutronSecurityRuleExists(String uuid);
+
+ /**
+ * Applications call this interface method to return if a particular
+ * Security Rule object exists
+ *
+ * @param uuid UUID of the security rule object
+ * @return {@link org.opendaylight.controller.networkconfig.neutron.NeutronSecurityRule.OpenStackNetworks}
+ * OpenStackSecurity Rule class
+ */
+
+ public NeutronSecurityRule getNeutronSecurityRule(String uuid);
+
+ /**
+ * Applications call this interface method to return all Security Rule objects
+ *
+ * @return List of OpenStack SecurityRules objects
+ */
+
+ public List<NeutronSecurityRule> getAllNeutronSecurityRules();
+
+ /**
+ * Applications call this interface method to add a Security Rule object to the
+ * concurrent map
+ *
+ * @param input OpenStack security rule object
+ * @return boolean on whether the object was added or not
+ */
+
+ public boolean addNeutronSecurityRule(NeutronSecurityRule input);
+
+ /**
+ * Applications call this interface method to remove a Neutron Security Rule object to the
+ * concurrent map
+ *
+ * @param uuid identifier for the security rule object
+ * @return boolean on whether the object was removed or not
+ */
+
+ public boolean removeNeutronSecurityRule(String uuid);
+
+ /**
+ * Applications call this interface method to edit aSecurity Rule object
+ *
+ * @param uuid identifier of the security rule object
+ * @param delta OpenStackSecurity Rule object containing changes to apply
+ * @return boolean on whether the object was updated or not
+ */
+
+ public boolean updateNeutronSecurityRule(String uuid, NeutronSecurityRule delta);
+
+ /**
+ * Applications call this interface method to see if a MAC address is in use
+ *
+ * @param uuid identifier of the security rule object
+ * @return boolean on whether the macAddress is already associated with a
+ * port or not
+ */
+
+ public boolean neutronSecurityRuleInUse(String uuid);
+
+}
INeutronFloatingIPCRUD answer = (INeutronFloatingIPCRUD) ServiceHelper.getGlobalInstance(INeutronFloatingIPCRUD.class, o);
return answer;
}
-}
+
+ public static INeutronSecurityGroupCRUD getINeutronSecurityGroupCRUD(Object o) {
+ INeutronSecurityGroupCRUD answer = (INeutronSecurityGroupCRUD) ServiceHelper.getGlobalInstance(INeutronSecurityGroupCRUD.class, o);
+ return answer;
+ }
+
+ public static INeutronSecurityRuleCRUD getINeutronSecurityRuleCRUD(Object o) {
+ INeutronSecurityRuleCRUD answer = (INeutronSecurityRuleCRUD) ServiceHelper.getGlobalInstance(INeutronSecurityRuleCRUD.class, o);
+ return answer;
+ }
+}
\ No newline at end of file
@XmlElement (name="tenant_id")
String tenantID;
- // TODO: add security groups
- // @XmlElement (name="security_groups")
- // List<String> securityGroups;
+ @XmlElement (name="security_groups")
+ List<NeutronSecurityGroup> securityGroups;
/* this attribute stores the floating IP address assigned to
* each fixed IP address
this.tenantID = tenantID;
}
+ public List<NeutronSecurityGroup> getSecurityGroups() {
+ return securityGroups;
+ }
+
+ public void setSecurityGroups(List<NeutronSecurityGroup> securityGroups) {
+ this.securityGroups = securityGroups;
+ }
+
public NeutronFloatingIP getFloatingIP(String key) {
if (!floatingIPMap.containsKey(key)) {
return null;
return "NeutronPort [portUUID=" + portUUID + ", networkUUID=" + networkUUID + ", name=" + name
+ ", adminStateUp=" + adminStateUp + ", status=" + status + ", macAddress=" + macAddress
+ ", fixedIPs=" + fixedIPs + ", deviceID=" + deviceID + ", deviceOwner=" + deviceOwner + ", tenantID="
- + tenantID + ", floatingIPMap=" + floatingIPMap + "]";
+ + tenantID + ", floatingIPMap=" + floatingIPMap + ", securityGroups=" + securityGroups + "]";
}
}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron;
+
+import org.opendaylight.controller.configuration.ConfigurationObject;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Security Group bindings.
+ * See OpenStack Network API v2.0 Reference for description of
+ * annotated attributes. The current fields are as follows:
+ * <p/>
+ * id uuid-str unique ID for the security group.
+ * name String name of the security group.
+ * description String name of the security group.
+ * tenant_id uuid-str Owner of security rule..
+ * security_group_rules List<NeutronSecurityRule> nested RO in the sec group.
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronSecurityGroup extends ConfigurationObject implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ @XmlElement(name = "id")
+ String securityGroupUUID;
+
+ @XmlElement(name = "name")
+ String securityGroupName;
+
+ @XmlElement(name = "description")
+ String securityGroupDescription;
+
+ @XmlElement(name = "tenant_id")
+ String securityGroupTenantID;
+
+ @XmlElement(name = "security_group_rules")
+ List<NeutronSecurityRule> neutronSecurityRule;
+
+ List<NeutronPort> neutronPorts;
+
+ public NeutronSecurityGroup() {
+ neutronPorts = new ArrayList<NeutronPort> ();
+ List<NeutronSecurityRule> securityRules;
+
+ }
+
+ public String getSecurityGroupUUID() {
+ return securityGroupUUID;
+ }
+
+ public void setSecurityGroupUUID(String securityGroupUUID) {
+ this.securityGroupUUID = securityGroupUUID;
+ }
+
+ public String getSecurityGroupName() {
+ return securityGroupName;
+ }
+
+ public void setSecurityGroupName(String securityGroupName) {
+ this.securityGroupName = securityGroupName;
+ }
+
+ public String getSecurityGroupDescription() {
+ return securityGroupDescription;
+ }
+
+ public void setSecurityGroupDescription(String securityGroupDescription) {
+ this.securityGroupDescription = securityGroupDescription;
+ }
+
+ public String getSecurityGroupTenantID() {
+ return securityGroupTenantID;
+ }
+
+ public void setSecurityGroupTenantID(String securityGroupTenantID) {
+ this.securityGroupTenantID = securityGroupTenantID;
+ }
+
+ // Rules In Group
+ public List<NeutronSecurityRule> getSecurityRules() {
+ return neutronSecurityRule;
+ }
+
+ public void setSecurityRules(NeutronSecurityRule neutronSecurityRule) {
+ this.neutronSecurityRule = (List<NeutronSecurityRule>) neutronSecurityRule;
+ }
+
+ public NeutronSecurityGroup extractFields(List<String> fields) {
+ NeutronSecurityGroup ans = new NeutronSecurityGroup ();
+ Iterator<String> i = fields.iterator ();
+ while (i.hasNext ()) {
+ String s = i.next ();
+ if (s.equals ("id")) {
+ ans.setSecurityGroupUUID (this.getSecurityGroupUUID ());
+ }
+ if (s.equals ("name")) {
+ ans.setSecurityGroupName (this.getSecurityGroupName ());
+ }
+ if (s.equals ("description")) {
+ ans.setSecurityGroupDescription (this.getSecurityGroupDescription ());
+ }
+ if (s.equals ("tenant_id")) {
+ ans.setSecurityGroupTenantID (this.getSecurityGroupTenantID ());
+ }
+ if (s.equals ("security_group_rules")) {
+ ans.setSecurityRules ((NeutronSecurityRule) this.getSecurityRules ());
+ }
+ }
+ return ans;
+ }
+
+ @Override
+ public String toString() {
+ return "NeutronSecurityGroup{" +
+ "securityGroupUUID='" + securityGroupUUID + '\'' +
+ ", securityGroupName='" + securityGroupName + '\'' +
+ ", securityGroupDescription='" + securityGroupDescription + '\'' +
+ ", securityGroupTenantID='" + securityGroupTenantID + '\'' +
+ ", securityRules=" + neutronSecurityRule + "]";
+ }
+
+ public void initDefaults() {
+ //TODO verify no defaults values are nessecary required.
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron;
+
+import org.opendaylight.controller.configuration.ConfigurationObject;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * See OpenStack Network API v2.0 Reference for description of
+ * annotated attributes. The current fields are as follows:
+ * <p/>
+ * id uuid (String) UUID for the security group rule.
+ * security_rule_id uuid (String) The security group to associate rule.
+ * direction String Direction the VM traffic (ingress/egress).
+ * security_group_id The security group to associate rule with.
+ * protocol String IP Protocol (icmp, tcp, udp, etc).
+ * port_range_min Integer Port at start of range
+ * port_range_max Integer Port at end of range
+ * ethertype String ethertype in L2 packet (IPv4, IPv6, etc)
+ * remote_ip_prefix String (IP cidr) CIDR for address range.
+ * remote_group_id uuid-str Source security group to apply to rule.
+ * tenant_id uuid-str Owner of security rule. Admin only outside tenant.
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronSecurityRule extends ConfigurationObject implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ @XmlElement(name = "id")
+ String securityRuleUUID;
+
+ @XmlElement(name = "direction")
+ String securityRuleDirection;
+
+ @XmlElement(name = "protocol")
+ String securityRuleProtocol;
+
+ @XmlElement(name = "port_range_min")
+ Integer securityRulePortMin;
+
+ @XmlElement(name = " port_range_max")
+ Integer securityRulePortMax;
+
+ @XmlElement(name = "ethertype")
+ String securityRuleEthertype;
+
+ @XmlElement(name = "remote_ip_prefix")
+ String securityRuleRemoteIpPrefix;
+
+ @XmlElement(name = "remote_group_id")
+ String securityRemoteGroupID;
+
+ @XmlElement(name = "security_group_id")
+ String securityRuleGroupID;
+
+ @XmlElement(name = "tenant_id")
+ String securityRuleTenantID;
+
+ public NeutronSecurityRule() {
+ List<NeutronSecurityRule> securityRules;
+ }
+
+ public String getSecurityRuleUUID() {
+ return securityRuleUUID;
+ }
+
+ public void setSecurityRuleUUID(String securityRuleUUID) {
+ this.securityRuleUUID = securityRuleUUID;
+ }
+
+ public String getSecurityRuleDirection() {
+ return securityRuleDirection;
+ }
+
+ public void setSecurityRuleDirection(String securityRuleDirection) {
+ this.securityRuleDirection = securityRuleDirection;
+ }
+
+ public String getSecurityRuleProtocol() {
+ return securityRuleProtocol;
+ }
+
+ public void setSecurityRuleProtocol(String securityRuleProtocol) {
+ this.securityRuleProtocol = securityRuleProtocol;
+ }
+
+ public Integer getSecurityRulePortMin() {
+ return securityRulePortMin;
+ }
+
+ public void setSecurityRulePortMin(Integer securityRulePortMin) {
+ this.securityRulePortMin = securityRulePortMin;
+ }
+
+ public Integer getSecurityRulePortMax() {
+ return securityRulePortMax;
+ }
+
+ public void setSecurityRulePortMax(Integer securityRulePortMax) {
+ this.securityRulePortMax = securityRulePortMax;
+ }
+
+ public String getSecurityRuleEthertype() {
+ return securityRuleEthertype;
+ }
+
+ public void setSecurityRuleEthertype(String securityRuleEthertype) {
+ this.securityRuleEthertype = securityRuleEthertype;
+ }
+
+ public String getSecurityRuleRemoteIpPrefix() {
+ return securityRuleRemoteIpPrefix;
+ }
+
+ public void setSecurityRuleRemoteIpPrefix(String securityRuleRemoteIpPrefix) {
+ this.securityRuleRemoteIpPrefix = securityRuleRemoteIpPrefix;
+ }
+
+ public String getSecurityRemoteGroupID() {
+ return securityRemoteGroupID;
+ }
+
+ public void setSecurityRemoteGroupID(String securityRemoteGroupID) {
+ this.securityRemoteGroupID = securityRemoteGroupID;
+ }
+
+ public String getSecurityRuleGroupID() {
+ return securityRuleGroupID;
+ }
+
+ public void setSecurityRuleGroupID(String securityRuleGroupID) {
+ this.securityRuleGroupID = securityRuleGroupID;
+ }
+
+ public String getSecurityRuleTenantID() {
+ return securityRuleTenantID;
+ }
+
+ public void setSecurityRuleTenantID(String securityRuleTenantID) {
+ this.securityRuleTenantID = securityRuleTenantID;
+ }
+
+ public NeutronSecurityRule extractFields(List<String> fields) {
+ NeutronSecurityRule ans = new NeutronSecurityRule();
+ Iterator<String> i = fields.iterator();
+ while (i.hasNext()) {
+ String s = i.next();
+ if (s.equals("id")) {
+ ans.setSecurityRuleUUID(this.getSecurityRuleUUID());
+ }
+ if (s.equals("direction")) {
+ ans.setSecurityRuleDirection(this.getSecurityRuleDirection());
+ }
+ if (s.equals("protocol")) {
+ ans.setSecurityRuleProtocol(this.getSecurityRuleProtocol());
+ }
+ if (s.equals("port_range_min")) {
+ ans.setSecurityRulePortMin(this.getSecurityRulePortMin());
+ }
+ if (s.equals("port_range_max")) {
+ ans.setSecurityRulePortMax(this.getSecurityRulePortMax());
+ }
+ if (s.equals("ethertype")) {
+ ans.setSecurityRuleEthertype(this.getSecurityRuleEthertype());
+ }
+ if (s.equals("remote_ip_prefix")) {
+ ans.setSecurityRuleRemoteIpPrefix(this.getSecurityRuleRemoteIpPrefix());
+ }
+ if (s.equals("remote_group_id")) {
+ ans.setSecurityRemoteGroupID(this.getSecurityRemoteGroupID());
+ }
+ if (s.equals("security_group_id")) {
+ ans.setSecurityRuleGroupID(this.getSecurityRuleGroupID());
+ }
+ if (s.equals("tenant_id")) {
+ ans.setSecurityRuleTenantID(this.getSecurityRuleTenantID());
+ }
+ }
+ return ans;
+ }
+
+ @Override
+ public String toString() {
+ return "NeutronSecurityRule{" +
+ "securityRuleUUID='" + securityRuleUUID + '\'' +
+ ", securityRuleDirection='" + securityRuleDirection + '\'' +
+ ", securityRuleProtocol='" + securityRuleProtocol + '\'' +
+ ", securityRulePortMin=" + securityRulePortMin +
+ ", securityRulePortMax=" + securityRulePortMax +
+ ", securityRuleEthertype='" + securityRuleEthertype + '\'' +
+ ", securityRuleRemoteIpPrefix='" + securityRuleRemoteIpPrefix + '\'' +
+ ", securityRemoteGroupID=" + securityRemoteGroupID +
+ ", securityRuleGroupID='" + securityRuleGroupID + '\'' +
+ ", securityRuleTenantID='" + securityRuleTenantID + '\'' +
+ '}';
+ }
+
+ public void initDefaults() {
+ //TODO verify no defaults values are nessecary required.
+ }
+}
\ No newline at end of file
classes.add(NeutronPortsNorthbound.class);
classes.add(NeutronRoutersNorthbound.class);
classes.add(NeutronFloatingIPsNorthbound.class);
+ classes.add(NeutronSecurityGroupsNorthbound.class);
+ classes.add(NeutronSecurityRulesNorthbound.class);
return classes;
}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron.northbound;
+
+import org.opendaylight.controller.networkconfig.neutron.NeutronSecurityGroup;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.List;
+
+
+@XmlRootElement
+@XmlAccessorType (XmlAccessType.NONE)
+
+public class NeutronSecurityGroupRequest {
+ /**
+ * See OpenStack Network API v2.0 Reference for a
+ * description of annotated attributes and operations
+ */
+
+ @XmlElement (name = "security_group")
+ NeutronSecurityGroup singletonSecurityGroup;
+
+ @XmlElement (name = "security_groups")
+ List<NeutronSecurityGroup> bulkRequest;
+
+ NeutronSecurityGroupRequest() {
+ }
+
+ NeutronSecurityGroupRequest(List<NeutronSecurityGroup> bulk) {
+ bulkRequest = bulk;
+ singletonSecurityGroup = null;
+ }
+
+ NeutronSecurityGroupRequest(NeutronSecurityGroup group) {
+ singletonSecurityGroup = group;
+ }
+
+ public List<NeutronSecurityGroup> getBulk() {
+ return bulkRequest;
+ }
+
+ public NeutronSecurityGroup getSingleton() {
+ return singletonSecurityGroup;
+ }
+
+ public boolean isSingleton() {
+ return (singletonSecurityGroup != null);
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron.northbound;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.opendaylight.controller.networkconfig.neutron.INeutronSecurityGroupAware;
+import org.opendaylight.controller.networkconfig.neutron.INeutronSecurityGroupCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
+import org.opendaylight.controller.networkconfig.neutron.NeutronSecurityGroup;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Neutron Northbound REST APIs for Security Group.<br>
+ * This class provides REST APIs for managing neutron Security Group
+ * <p/>
+ * <br>
+ * <br>
+ * Authentication scheme : <b>HTTP Basic</b><br>
+ * Authentication realm : <b>opendaylight</b><br>
+ * Transport : <b>HTTP and HTTPS</b><br>
+ * <br>
+ * HTTPS Authentication is disabled by default. Administrator can enable it in
+ * tomcat-server.xml after adding a proper keystore / SSL certificate from a
+ * trusted authority.<br>
+ * More info :
+ * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+ */
+@Path ("/security-groups")
+public class NeutronSecurityGroupsNorthbound {
+ static final Logger logger = LoggerFactory.getLogger(NeutronSecurityGroupsNorthbound.class);
+
+ private NeutronSecurityGroup extractFields(NeutronSecurityGroup o, List<String> fields) {
+ return o.extractFields(fields);
+ }
+
+ /**
+ * Returns a list of all Security Groups
+ */
+ @GET
+ @Produces ({MediaType.APPLICATION_JSON})
+ @StatusCodes ({
+ @ResponseCode (code = 200, condition = "Operation successful"),
+ @ResponseCode (code = 401, condition = "Unauthorized"),
+ @ResponseCode (code = 501, condition = "Not Implemented")})
+
+ public Response listGroups(
+ // return fields
+ @QueryParam ("fields") List<String> fields,
+ // OpenStack security group attributes
+ @QueryParam ("id") String querySecurityGroupUUID,
+ @QueryParam ("name") String querySecurityGroupName,
+ @QueryParam ("description") String querySecurityDescription,
+ @QueryParam ("tenant_id") String querySecurityTenantID,
+ @QueryParam ("limit") String limit,
+ @QueryParam ("marker") String marker,
+ @QueryParam ("page_reverse") String pageReverse
+ ) {
+ INeutronSecurityGroupCRUD securityGroupInterface = NeutronCRUDInterfaces.getINeutronSecurityGroupCRUD(this);
+
+ if (securityGroupInterface == null) {
+ throw new ServiceUnavailableException("Security Group CRUD Interface "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+ List<NeutronSecurityGroup> allSecurityGroups = securityGroupInterface.getAllNeutronSecurityGroups();
+ List<NeutronSecurityGroup> ans = new ArrayList<NeutronSecurityGroup>();
+ Iterator<NeutronSecurityGroup> i = allSecurityGroups.iterator();
+ while (i.hasNext()) {
+ NeutronSecurityGroup nsg = i.next();
+ if ((querySecurityGroupUUID == null ||
+ querySecurityGroupUUID.equals(nsg.getSecurityGroupUUID())) &&
+ (querySecurityGroupName == null ||
+ querySecurityGroupName.equals(nsg.getSecurityGroupName())) &&
+ (querySecurityDescription == null ||
+ querySecurityDescription.equals(nsg.getSecurityGroupDescription())) &&
+ (querySecurityTenantID == null ||
+ querySecurityTenantID.equals(nsg.getSecurityGroupTenantID()))) {
+ if (fields.size() > 0) {
+ ans.add(extractFields(nsg, fields));
+ } else {
+ ans.add(nsg);
+ }
+ }
+ }
+ return Response.status(200).entity(
+ new NeutronSecurityGroupRequest(ans)).build();
+ }
+
+ /**
+ * Returns a specific Security Group
+ */
+
+ @Path ("{securityGroupUUID}")
+ @GET
+ @Produces ({MediaType.APPLICATION_JSON})
+ @StatusCodes ({
+ @ResponseCode (code = 200, condition = "Operation successful"),
+ @ResponseCode (code = 401, condition = "Unauthorized"),
+ @ResponseCode (code = 404, condition = "Not Found"),
+ @ResponseCode (code = 501, condition = "Not Implemented")})
+ public Response showSecurityGroup(@PathParam ("securityGroupUUID") String securityGroupUUID,
+ // return fields
+ @QueryParam ("fields") List<String> fields) {
+ INeutronSecurityGroupCRUD securityGroupInterface = NeutronCRUDInterfaces.getINeutronSecurityGroupCRUD(this);
+ if (securityGroupInterface == null) {
+ throw new ServiceUnavailableException("Security Group CRUD Interface "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+ if (!securityGroupInterface.neutronSecurityGroupExists(securityGroupUUID)) {
+ throw new ResourceNotFoundException("Security Group UUID does not exist.");
+ }
+ if (!fields.isEmpty()) {
+ NeutronSecurityGroup ans = securityGroupInterface.getNeutronSecurityGroup(securityGroupUUID);
+ return Response.status(200).entity(
+ new NeutronSecurityGroupRequest(extractFields(ans, fields))).build();
+ } else {
+ return Response.status(200).entity(new NeutronSecurityGroupRequest(securityGroupInterface.getNeutronSecurityGroup(securityGroupUUID))).build();
+ }
+ }
+
+ /**
+ * Creates new Security Group
+ */
+
+ @POST
+ @Produces ({MediaType.APPLICATION_JSON})
+ @Consumes ({MediaType.APPLICATION_JSON})
+ @StatusCodes ({
+ @ResponseCode (code = 201, condition = "Created"),
+ @ResponseCode (code = 400, condition = "Bad Request"),
+ @ResponseCode (code = 401, condition = "Unauthorized"),
+ @ResponseCode (code = 403, condition = "Forbidden"),
+ @ResponseCode (code = 404, condition = "Not Found"),
+ @ResponseCode (code = 409, condition = "Conflict"),
+ @ResponseCode (code = 501, condition = "Not Implemented")})
+ public Response createSecurityGroups(final NeutronSecurityGroupRequest input) {
+ INeutronSecurityGroupCRUD securityGroupInterface = NeutronCRUDInterfaces.getINeutronSecurityGroupCRUD(this);
+ if (securityGroupInterface == null) {
+ throw new ServiceUnavailableException("Security Group CRUD Interface "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ if (input.isSingleton()) {
+ NeutronSecurityGroup singleton = input.getSingleton();
+
+ /*
+ * Verify that the Security Group doesn't already exist.
+ */
+ if (securityGroupInterface.neutronSecurityGroupExists(singleton.getSecurityGroupUUID())) {
+ throw new BadRequestException("Security Group UUID already exists");
+ }
+
+ Object[] instances = ServiceHelper.getGlobalInstances(INeutronSecurityGroupAware.class, this, null);
+ if (instances != null) {
+ for (Object instance : instances) {
+ INeutronSecurityGroupAware service = (INeutronSecurityGroupAware) instance;
+ int status = service.canCreateNeutronSecurityGroup(singleton);
+ if (status < 200 || status > 299) {
+ return Response.status(status).build();
+ }
+ }
+ }
+ // Add to Neutron cache
+ securityGroupInterface.addNeutronSecurityGroup(singleton);
+ if (instances != null) {
+ for (Object instance : instances) {
+ INeutronSecurityGroupAware service = (INeutronSecurityGroupAware) instance;
+ service.neutronSecurityGroupCreated(singleton);
+ }
+ }
+ } else {
+ List<NeutronSecurityGroup> bulk = input.getBulk();
+ Iterator<NeutronSecurityGroup> i = bulk.iterator();
+ HashMap<String, NeutronSecurityGroup> testMap = new HashMap<String, NeutronSecurityGroup>();
+ Object[] instances = ServiceHelper.getGlobalInstances(INeutronSecurityGroupAware.class, this, null);
+ while (i.hasNext()) {
+ NeutronSecurityGroup test = i.next();
+
+ /*
+ * Verify that the security group doesn't already exist
+ */
+
+ if (securityGroupInterface.neutronSecurityGroupExists(test.getSecurityGroupUUID())) {
+ throw new BadRequestException("Security Group UUID already is already created");
+ }
+ if (instances != null) for (Object instance : instances) {
+ INeutronSecurityGroupAware service = (INeutronSecurityGroupAware) instance;
+ int status = service.canCreateNeutronSecurityGroup(test);
+ if ((status < 200) || (status > 299)) return Response.status(status).build();
+ }
+ }
+
+ /*
+ * now, each element of the bulk request can be added to the cache
+ */
+ i = bulk.iterator();
+ while (i.hasNext()) {
+ NeutronSecurityGroup test = i.next();
+ securityGroupInterface.addNeutronSecurityGroup(test);
+ if (instances != null) {
+ for (Object instance : instances) {
+ INeutronSecurityGroupAware service = (INeutronSecurityGroupAware) instance;
+ service.neutronSecurityGroupCreated(test);
+ }
+ }
+ }
+ }
+ return Response.status(201).entity(input).build();
+ }
+
+ /**
+ * Updates a Security Group
+ */
+
+ @Path ("{securityGroupUUID}")
+ @PUT
+ @Produces ({MediaType.APPLICATION_JSON})
+ @Consumes ({MediaType.APPLICATION_JSON})
+ @StatusCodes ({
+ @ResponseCode (code = 200, condition = "Operation successful"),
+ @ResponseCode (code = 400, condition = "Bad Request"),
+ @ResponseCode (code = 401, condition = "Unauthorized"),
+ @ResponseCode (code = 403, condition = "Forbidden"),
+ @ResponseCode (code = 404, condition = "Not Found"),
+ @ResponseCode (code = 501, condition = "Not Implemented")})
+ public Response updateSecurityGroup(
+ @PathParam ("securityGroupUUID") String securityGroupUUID, final NeutronSecurityGroupRequest input) {
+ INeutronSecurityGroupCRUD securityGroupInterface = NeutronCRUDInterfaces.getINeutronSecurityGroupCRUD(this);
+ if (securityGroupInterface == null) {
+ throw new ServiceUnavailableException("Security Group CRUD Interface "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ /*
+ * verify the Security Group exists and there is only one delta provided
+ */
+ if (!securityGroupInterface.neutronSecurityGroupExists(securityGroupUUID)) {
+ throw new ResourceNotFoundException("Security Group UUID does not exist.");
+ }
+ if (!input.isSingleton()) {
+ throw new BadRequestException("Only singleton edit supported");
+ }
+ NeutronSecurityGroup delta = input.getSingleton();
+ NeutronSecurityGroup original = securityGroupInterface.getNeutronSecurityGroup(securityGroupUUID);
+
+ if (delta.getSecurityGroupUUID() != null ||
+ delta.getSecurityGroupTenantID() != null ||
+ delta.getSecurityGroupName() != null ||
+ delta.getSecurityGroupDescription() != null) {
+ throw new BadRequestException("Attribute edit blocked by Neutron");
+ }
+
+ Object[] instances = ServiceHelper.getGlobalInstances(INeutronSecurityGroupAware.class, this, null);
+ if (instances != null) {
+ for (Object instance : instances) {
+ INeutronSecurityGroupAware service = (INeutronSecurityGroupAware) instance;
+ int status = service.canUpdateNeutronSecurityGroup(delta, original);
+ if (status < 200 || status > 299) {
+ return Response.status(status).build();
+ }
+ }
+ }
+
+ /*
+ * update the object and return it
+ */
+ securityGroupInterface.updateNeutronSecurityGroup(securityGroupUUID, delta);
+ NeutronSecurityGroup updatedSecurityGroup = securityGroupInterface.getNeutronSecurityGroup(securityGroupUUID);
+ if (instances != null) {
+ for (Object instance : instances) {
+ INeutronSecurityGroupAware service = (INeutronSecurityGroupAware) instance;
+ service.neutronSecurityGroupUpdated(updatedSecurityGroup);
+ }
+ }
+ return Response.status(200).entity(new NeutronSecurityGroupRequest(securityGroupInterface.getNeutronSecurityGroup(securityGroupUUID))).build();
+ }
+
+ /**
+ * Deletes a Security Group
+ */
+
+ @Path ("{securityGroupUUID}")
+ @DELETE
+ @StatusCodes ({
+ @ResponseCode (code = 204, condition = "No Content"),
+ @ResponseCode (code = 401, condition = "Unauthorized"),
+ @ResponseCode (code = 404, condition = "Not Found"),
+ @ResponseCode (code = 409, condition = "Conflict"),
+ @ResponseCode (code = 501, condition = "Not Implemented")})
+ public Response deleteSecurityGroup(
+ @PathParam ("securityGroupUUID") String securityGroupUUID) {
+ INeutronSecurityGroupCRUD securityGroupInterface = NeutronCRUDInterfaces.getINeutronSecurityGroupCRUD(this);
+ if (securityGroupInterface == null) {
+ throw new ServiceUnavailableException("Security Group CRUD Interface "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ /*
+ * verify the Security Group exists and it isn't currently in use
+ */
+ if (!securityGroupInterface.neutronSecurityGroupExists(securityGroupUUID)) {
+ throw new ResourceNotFoundException("Security Group UUID does not exist.");
+ }
+ if (securityGroupInterface.neutronSecurityGroupInUse(securityGroupUUID)) {
+ return Response.status(409).build();
+ }
+ NeutronSecurityGroup singleton = securityGroupInterface.getNeutronSecurityGroup(securityGroupUUID);
+ Object[] instances = ServiceHelper.getGlobalInstances(INeutronSecurityGroupAware.class, this, null);
+ if (instances != null) {
+ for (Object instance : instances) {
+ INeutronSecurityGroupAware service = (INeutronSecurityGroupAware) instance;
+ int status = service.canDeleteNeutronSecurityGroup(singleton);
+ if ((status < 200) || (status > 299)) {
+ return Response.status(status).build();
+ }
+ }
+ }
+
+ /*
+ * remove it and return 204 status
+ */
+ securityGroupInterface.removeNeutronSecurityGroup(securityGroupUUID);
+ if (instances != null) {
+ for (Object instance : instances) {
+ INeutronSecurityGroupAware service = (INeutronSecurityGroupAware) instance;
+ service.neutronSecurityGroupDeleted(singleton);
+ }
+ }
+ return Response.status(204).build();
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron.northbound;
+
+import org.opendaylight.controller.networkconfig.neutron.NeutronSecurityRule;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.List;
+
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronSecurityRuleRequest {
+ /**
+ * See OpenStack Network API v2.0 Reference for a
+ * description of annotated attributes and operations
+ */
+
+ @XmlElement(name="security_group_rule")
+ NeutronSecurityRule singletonSecurityRule;
+
+ @XmlElement(name="security_group_rules")
+ List<NeutronSecurityRule> bulkRequest;
+
+ NeutronSecurityRuleRequest() {
+ }
+
+ NeutronSecurityRuleRequest(List<NeutronSecurityRule> bulk) {
+ bulkRequest = bulk;
+ singletonSecurityRule = null;
+ }
+
+ NeutronSecurityRuleRequest(NeutronSecurityRule rule) {
+ singletonSecurityRule = rule;
+ }
+
+ public NeutronSecurityRule getSingleton() {
+ return singletonSecurityRule;
+ }
+
+ public boolean isSingleton() {
+ return (singletonSecurityRule != null);
+ }
+ public List<NeutronSecurityRule> getBulk() {
+ return bulkRequest;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron.northbound;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.opendaylight.controller.networkconfig.neutron.INeutronSecurityGroupCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronSecurityRuleAware;
+import org.opendaylight.controller.networkconfig.neutron.INeutronSecurityRuleCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
+import org.opendaylight.controller.networkconfig.neutron.NeutronSecurityRule;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Neutron Northbound REST APIs for Security Rule.<br>
+ * This class provides REST APIs for managing neutron Security Rule
+ * <p/>
+ * <br>
+ * <br>
+ * Authentication scheme : <b>HTTP Basic</b><br>
+ * Authentication realm : <b>opendaylight</b><br>
+ * Transport : <b>HTTP and HTTPS</b><br>
+ * <br>
+ * HTTPS Authentication is disabled by default. Administrator can enable it in
+ * tomcat-server.xml after adding a proper keystore / SSL certificate from a
+ * trusted authority.<br>
+ * More info :
+ * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+ */
+
+@Path ("/security-group-rules")
+public class NeutronSecurityRulesNorthbound {
+ static final Logger logger = LoggerFactory.getLogger(NeutronSecurityRulesNorthbound.class);
+
+ private NeutronSecurityRule extractFields(NeutronSecurityRule o, List<String> fields) {
+ return o.extractFields(fields);
+ }
+
+ /**
+ * Returns a list of all Security Rules
+ */
+ @GET
+ @Produces ({MediaType.APPLICATION_JSON})
+ @StatusCodes ({
+ @ResponseCode (code = 200, condition = "Operation successful"),
+ @ResponseCode (code = 401, condition = "Unauthorized"),
+ @ResponseCode (code = 501, condition = "Not Implemented")})
+ public Response listRules(
+ // return fields
+ @QueryParam ("fields") List<String> fields,
+ // OpenStack security rule attributes
+ @QueryParam ("id") String querySecurityRuleUUID,
+ @QueryParam ("direction") String querySecurityRuleDirection,
+ @QueryParam ("protocol") String querySecurityRuleProtocol,
+ @QueryParam ("port_range_min") Integer querySecurityRulePortMin,
+ @QueryParam ("port_range_max") Integer querySecurityRulePortMax,
+ @QueryParam ("ethertype") String querySecurityRuleEthertype,
+ @QueryParam ("remote_ip_prefix") String querySecurityRuleIpPrefix,
+ @QueryParam ("remote_group_id") String querySecurityRemoteGroupID,
+ @QueryParam ("security_group_id") String querySecurityRuleGroupID,
+ @QueryParam ("tenant_id") String querySecurityRuleTenantID,
+ @QueryParam ("limit") String limit,
+ @QueryParam ("marker") String marker,
+ @QueryParam ("page_reverse") String pageReverse
+ ) {
+ INeutronSecurityRuleCRUD securityRuleInterface = NeutronCRUDInterfaces.getINeutronSecurityRuleCRUD(this);
+ if (securityRuleInterface == null) {
+ throw new ServiceUnavailableException("Security Rule CRUD Interface "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+ List<NeutronSecurityRule> allSecurityRules = securityRuleInterface.getAllNeutronSecurityRules();
+ List<NeutronSecurityRule> ans = new ArrayList<NeutronSecurityRule>();
+ Iterator<NeutronSecurityRule> i = allSecurityRules.iterator();
+ while (i.hasNext()) {
+ NeutronSecurityRule nsr = i.next();
+ if ((querySecurityRuleUUID == null ||
+ querySecurityRuleUUID.equals(nsr.getSecurityRuleUUID())) &&
+ (querySecurityRuleDirection == null ||
+ querySecurityRuleDirection.equals(nsr.getSecurityRuleDirection())) &&
+ (querySecurityRuleProtocol == null ||
+ querySecurityRuleProtocol.equals(nsr.getSecurityRuleProtocol())) &&
+ (querySecurityRulePortMin == null ||
+ querySecurityRulePortMin.equals(nsr.getSecurityRulePortMin())) &&
+ (querySecurityRulePortMax == null ||
+ querySecurityRulePortMax.equals(nsr.getSecurityRulePortMax())) &&
+ (querySecurityRuleEthertype == null ||
+ querySecurityRuleEthertype.equals(nsr.getSecurityRuleEthertype())) &&
+ (querySecurityRuleIpPrefix == null ||
+ querySecurityRuleIpPrefix.equals(nsr.getSecurityRuleRemoteIpPrefix())) &&
+ (querySecurityRuleGroupID == null ||
+ querySecurityRuleGroupID.equals(nsr.getSecurityRuleGroupID())) &&
+ (querySecurityRemoteGroupID == null ||
+ querySecurityRemoteGroupID.equals(nsr.getSecurityRemoteGroupID())) &&
+ (querySecurityRuleTenantID == null ||
+ querySecurityRuleTenantID.equals(nsr.getSecurityRuleTenantID()))) {
+ if (fields.size() > 0) {
+ ans.add(extractFields(nsr, fields));
+ } else {
+ ans.add(nsr);
+ }
+ }
+ }
+ return Response.status(200).entity(
+ new NeutronSecurityRuleRequest(ans)).build();
+ }
+
+ /**
+ * Returns a specific Security Rule
+ */
+
+ @Path ("{securityRuleUUID}")
+ @GET
+ @Produces ({MediaType.APPLICATION_JSON})
+ @StatusCodes ({
+ @ResponseCode (code = 200, condition = "Operation successful"),
+ @ResponseCode (code = 401, condition = "Unauthorized"),
+ @ResponseCode (code = 404, condition = "Not Found"),
+ @ResponseCode (code = 501, condition = "Not Implemented")})
+ public Response showSecurityRule(@PathParam ("securityRuleUUID") String securityRuleUUID,
+ // return fields
+ @QueryParam ("fields") List<String> fields) {
+ INeutronSecurityRuleCRUD securityRuleInterface = NeutronCRUDInterfaces.getINeutronSecurityRuleCRUD(this);
+ if (securityRuleInterface == null) {
+ throw new ServiceUnavailableException("Security Rule CRUD Interface "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+ if (!securityRuleInterface.neutronSecurityRuleExists(securityRuleUUID)) {
+ throw new ResourceNotFoundException("Security Rule UUID does not exist.");
+ }
+ if (!fields.isEmpty()) {
+ NeutronSecurityRule ans = securityRuleInterface.getNeutronSecurityRule(securityRuleUUID);
+ return Response.status(200).entity(
+ new NeutronSecurityRuleRequest(extractFields(ans, fields))).build();
+ } else {
+ return Response.status(200).entity(new NeutronSecurityRuleRequest(securityRuleInterface.getNeutronSecurityRule(securityRuleUUID))).build();
+ }
+ }
+
+ /**
+ * Creates new Security Rule
+ */
+
+ @POST
+ @Produces ({MediaType.APPLICATION_JSON})
+ @Consumes ({MediaType.APPLICATION_JSON})
+ @StatusCodes ({
+ @ResponseCode (code = 201, condition = "Created"),
+ @ResponseCode (code = 400, condition = "Bad Request"),
+ @ResponseCode (code = 401, condition = "Unauthorized"),
+ @ResponseCode (code = 403, condition = "Forbidden"),
+ @ResponseCode (code = 404, condition = "Not Found"),
+ @ResponseCode (code = 409, condition = "Conflict"),
+ @ResponseCode (code = 501, condition = "Not Implemented")})
+ public Response createSecurityRules(final NeutronSecurityRuleRequest input) {
+ INeutronSecurityRuleCRUD securityRuleInterface = NeutronCRUDInterfaces.getINeutronSecurityRuleCRUD(this);
+ if (securityRuleInterface == null) {
+ throw new ServiceUnavailableException("Security Rule CRUD Interface "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+ INeutronSecurityGroupCRUD securityGroupInterface = NeutronCRUDInterfaces.getINeutronSecurityGroupCRUD(this);
+ if (securityGroupInterface == null) {
+ throw new ServiceUnavailableException("Security Group CRUD Interface "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ /*
+ * Existing entry checks
+ */
+
+ if (input.isSingleton()) {
+ NeutronSecurityRule singleton = input.getSingleton();
+
+ if (securityRuleInterface.neutronSecurityRuleExists(singleton.getSecurityRuleUUID())) {
+ throw new BadRequestException("Security Rule UUID already exists");
+ }
+ Object[] instances = ServiceHelper.getGlobalInstances(INeutronSecurityRuleAware.class, this, null);
+ if (instances != null) {
+ for (Object instance : instances) {
+ INeutronSecurityRuleAware service = (INeutronSecurityRuleAware) instance;
+ int status = service.canCreateNeutronSecurityRule(singleton);
+ if ((status < 200) || (status > 299)) {
+ return Response.status(status).build();
+ }
+ }
+ }
+
+ // add rule to cache
+ singleton.initDefaults();
+ securityRuleInterface.addNeutronSecurityRule(singleton);
+ if (instances != null) {
+ for (Object instance : instances) {
+ INeutronSecurityRuleAware service = (INeutronSecurityRuleAware) instance;
+ service.neutronSecurityRuleCreated(singleton);
+ }
+ }
+
+ securityRuleInterface.addNeutronSecurityRule(singleton);
+ if (instances != null) {
+ for (Object instance : instances) {
+ INeutronSecurityRuleAware service = (INeutronSecurityRuleAware) instance;
+ service.neutronSecurityRuleCreated(singleton);
+ }
+ }
+ } else {
+ List<NeutronSecurityRule> bulk = input.getBulk();
+ Iterator<NeutronSecurityRule> i = bulk.iterator();
+ HashMap<String, NeutronSecurityRule> testMap = new HashMap<String, NeutronSecurityRule>();
+ Object[] instances = ServiceHelper.getGlobalInstances(INeutronSecurityRuleAware.class, this, null);
+ while (i.hasNext()) {
+ NeutronSecurityRule test = i.next();
+
+ /*
+ * Verify that the security rule doesn't already exist
+ */
+
+ if (securityRuleInterface.neutronSecurityRuleExists(test.getSecurityRuleUUID())) {
+ throw new BadRequestException("Security Rule UUID already exists");
+ }
+ if (testMap.containsKey(test.getSecurityRuleUUID())) {
+ throw new BadRequestException("Security Rule UUID already exists");
+ }
+ if (instances != null) {
+ for (Object instance : instances) {
+ INeutronSecurityRuleAware service = (INeutronSecurityRuleAware) instance;
+ int status = service.canCreateNeutronSecurityRule(test);
+ if ((status < 200) || (status > 299)) {
+ return Response.status(status).build();
+ }
+ }
+ }
+ }
+
+ /*
+ * now, each element of the bulk request can be added to the cache
+ */
+ i = bulk.iterator();
+ while (i.hasNext()) {
+ NeutronSecurityRule test = i.next();
+ securityRuleInterface.addNeutronSecurityRule(test);
+ if (instances != null) {
+ for (Object instance : instances) {
+ INeutronSecurityRuleAware service = (INeutronSecurityRuleAware) instance;
+ service.neutronSecurityRuleCreated(test);
+ }
+ }
+ }
+ }
+ return Response.status(201).entity(input).build();
+ }
+
+ /**
+ * Updates a Security Rule
+ */
+
+ @Path ("{securityRuleUUID}")
+ @PUT
+ @Produces ({MediaType.APPLICATION_JSON})
+ @Consumes ({MediaType.APPLICATION_JSON})
+ @StatusCodes ({
+ @ResponseCode (code = 200, condition = "Operation successful"),
+ @ResponseCode (code = 400, condition = "Bad Request"),
+ @ResponseCode (code = 401, condition = "Unauthorized"),
+ @ResponseCode (code = 403, condition = "Forbidden"),
+ @ResponseCode (code = 404, condition = "Not Found"),
+ @ResponseCode (code = 501, condition = "Not Implemented")})
+ public Response updateSecurityRule(
+ @PathParam ("securityRuleUUID") String securityRuleUUID, final NeutronSecurityRuleRequest input) {
+ INeutronSecurityRuleCRUD securityRuleInterface = NeutronCRUDInterfaces.getINeutronSecurityRuleCRUD(this);
+ if (securityRuleInterface == null) {
+ throw new ServiceUnavailableException("Security Rule CRUD Interface "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ /*
+ * verify the Security Rule exists and there is only one delta provided
+ */
+ if (!securityRuleInterface.neutronSecurityRuleExists(securityRuleUUID)) {
+ throw new ResourceNotFoundException("Security Rule UUID does not exist.");
+ }
+ if (!input.isSingleton()) {
+ throw new BadRequestException("Only singleton edit supported");
+ }
+ NeutronSecurityRule delta = input.getSingleton();
+ NeutronSecurityRule original = securityRuleInterface.getNeutronSecurityRule(securityRuleUUID);
+
+ /*
+ * updates restricted by Neutron
+ *
+ */
+ if (delta.getSecurityRuleUUID() != null ||
+ delta.getSecurityRuleDirection() != null ||
+ delta.getSecurityRuleProtocol() != null ||
+ delta.getSecurityRulePortMin() != null ||
+ delta.getSecurityRulePortMax() != null ||
+ delta.getSecurityRuleEthertype() != null ||
+ delta.getSecurityRuleRemoteIpPrefix() != null ||
+ delta.getSecurityRuleGroupID() != null ||
+ delta.getSecurityRemoteGroupID() != null ||
+ delta.getSecurityRuleTenantID() != null) {
+ throw new BadRequestException("Attribute edit blocked by Neutron");
+ }
+
+ Object[] instances = ServiceHelper.getGlobalInstances(INeutronSecurityRuleAware.class, this, null);
+ if (instances != null) {
+ for (Object instance : instances) {
+ INeutronSecurityRuleAware service = (INeutronSecurityRuleAware) instance;
+ int status = service.canUpdateNeutronSecurityRule(delta, original);
+ if (status < 200 || status > 299) {
+ return Response.status(status).build();
+ }
+ }
+ }
+
+ /*
+ * update the object and return it
+ */
+ securityRuleInterface.updateNeutronSecurityRule(securityRuleUUID, delta);
+ NeutronSecurityRule updatedSecurityRule = securityRuleInterface.getNeutronSecurityRule(securityRuleUUID);
+ if (instances != null) {
+ for (Object instance : instances) {
+ INeutronSecurityRuleAware service = (INeutronSecurityRuleAware) instance;
+ service.neutronSecurityRuleUpdated(updatedSecurityRule);
+ }
+ }
+ return Response.status(200).entity(new NeutronSecurityRuleRequest(securityRuleInterface.getNeutronSecurityRule(securityRuleUUID))).build();
+ }
+
+ /**
+ * Deletes a Security Rule
+ */
+
+ @Path ("{securityRuleUUID}")
+ @DELETE
+ @StatusCodes ({
+ @ResponseCode (code = 204, condition = "No Content"),
+ @ResponseCode (code = 401, condition = "Unauthorized"),
+ @ResponseCode (code = 404, condition = "Not Found"),
+ @ResponseCode (code = 409, condition = "Conflict"),
+ @ResponseCode (code = 501, condition = "Not Implemented")})
+ public Response deleteSecurityRule(
+ @PathParam ("securityRuleUUID") String securityRuleUUID) {
+ INeutronSecurityRuleCRUD securityRuleInterface = NeutronCRUDInterfaces.getINeutronSecurityRuleCRUD(this);
+ if (securityRuleInterface == null) {
+ throw new ServiceUnavailableException("Security Rule CRUD Interface "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ /*
+ * verify the Security Rule exists and it isn't currently in use
+ */
+ if (!securityRuleInterface.neutronSecurityRuleExists(securityRuleUUID)) {
+ throw new ResourceNotFoundException("Security Rule UUID does not exist.");
+ }
+ if (securityRuleInterface.neutronSecurityRuleInUse(securityRuleUUID)) {
+ return Response.status(409).build();
+ }
+ NeutronSecurityRule singleton = securityRuleInterface.getNeutronSecurityRule(securityRuleUUID);
+ Object[] instances = ServiceHelper.getGlobalInstances(INeutronSecurityRuleAware.class, this, null);
+ if (instances != null) {
+ for (Object instance : instances) {
+ INeutronSecurityRuleAware service = (INeutronSecurityRuleAware) instance;
+ int status = service.canDeleteNeutronSecurityRule(singleton);
+ if (status < 200 || status > 299) {
+ return Response.status(status).build();
+ }
+ }
+ }
+
+ /*
+ * remove it and return 204 status
+ */
+ securityRuleInterface.removeNeutronSecurityRule(securityRuleUUID);
+ if (instances != null) {
+ for (Object instance : instances) {
+ INeutronSecurityRuleAware service = (INeutronSecurityRuleAware) instance;
+ service.neutronSecurityRuleDeleted(singleton);
+ }
+ }
+ return Response.status(204).build();
+ }
+}
\ No newline at end of file