<groupId>${project.groupId}</groupId>
<artifactId>config-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>config-manager-facade-xml</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>config-util</artifactId>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-impl</artifactId>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-mapping-api</artifactId>
<artifactId>binding-generator-impl</artifactId>
</dependency>
<dependency>
- <groupId>org.osgi</groupId>
- <artifactId>org.osgi.core</artifactId>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
+ <artifactId>slf4j-simple</artifactId>
</dependency>
<dependency>
<groupId>xmlunit</groupId>
<artifactId>config-manager</artifactId>
<scope>test</scope>
</dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>netconf-impl</artifactId>
- <scope>test</scope>
- </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<configuration>
<instructions>
<Bundle-Activator>org.opendaylight.controller.netconf.confignetconfconnector.osgi.Activator</Bundle-Activator>
- <Private-Package>org.opendaylight.controller.netconf.confignetconfconnector.mapping.*,
- org.opendaylight.controller.netconf.confignetconfconnector.operations.*,
- org.opendaylight.controller.netconf.confignetconfconnector.transactions,
- org.opendaylight.controller.netconf.confignetconfconnector.util,
- org.opendaylight.controller.netconf.confignetconfconnector.osgi,
- org.opendaylight.controller.netconf.confignetconfconnector.exception,</Private-Package>
</instructions>
</configuration>
</plugin>
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.netconf.confignetconfconnector.exception;
-
-import java.util.Collections;
-import java.util.Map;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-
-public class NetconfConfigHandlingException extends NetconfDocumentedException {
- private static final long serialVersionUID = 1L;
-
- public NetconfConfigHandlingException(final String message, final ErrorType errorType, final ErrorTag errorTag,
- final ErrorSeverity errorSeverity) {
- this(message, errorType, errorTag, errorSeverity, Collections.<String, String>emptyMap());
- }
-
- public NetconfConfigHandlingException(final String message, final ErrorType errorType, final ErrorTag errorTag,
- final ErrorSeverity errorSeverity, final Map<String, String> errorInfo){
- super(message,errorType,errorTag,errorSeverity,errorInfo);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.netconf.confignetconfconnector.exception;
-
-import java.util.Collections;
-import java.util.Map;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-
-public class NoTransactionFoundException extends NetconfDocumentedException {
- private static final long serialVersionUID = 1L;
-
- public NoTransactionFoundException(final String message, final ErrorType errorType, final ErrorTag errorTag,
- final ErrorSeverity errorSeverity) {
- this(message, errorType, errorTag, errorSeverity, Collections.<String, String> emptyMap());
- }
-
- public NoTransactionFoundException(final String message, final ErrorType errorType, final ErrorTag errorTag,
- final ErrorSeverity errorSeverity, final Map<String, String> errorInfo){
- super(message,errorType,errorTag,errorSeverity,errorInfo);
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.netconf.confignetconfconnector.exception;
-
-import java.util.Collections;
-import java.util.Map;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-
-public class OperationNotPermittedException extends NetconfDocumentedException {
- private static final long serialVersionUID = 1L;
-
- public OperationNotPermittedException(final String message, final ErrorType errorType, final ErrorTag errorTag,
- final ErrorSeverity errorSeverity) {
- this(message, errorType, errorTag, errorSeverity, Collections.<String, String> emptyMap());
- }
-
- public OperationNotPermittedException(final String message, final ErrorType errorType, final ErrorTag errorTag,
- final ErrorSeverity errorSeverity, final Map<String, String> errorInfo){
- super(message,errorType,errorTag,errorSeverity,errorInfo);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes;
-
-import javax.management.openmbean.ArrayType;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.OpenType;
-import javax.management.openmbean.SimpleType;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
-import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
-
-public abstract class AttributeIfcSwitchStatement<T> {
-
- private AttributeIfc lastAttribute;
-
- public T switchAttribute(AttributeIfc attributeIfc) {
-
- this.lastAttribute = attributeIfc;
-
- OpenType<?> openType = attributeIfc.getOpenType();
-
- if (attributeIfc instanceof JavaAttribute) {
- try {
- if(((JavaAttribute)attributeIfc).getTypeDefinition() instanceof BinaryTypeDefinition) {
- return caseJavaBinaryAttribute(openType);
- } else if(((JavaAttribute)attributeIfc).isUnion()) {
- return caseJavaUnionAttribute(openType);
- } else if(((JavaAttribute)attributeIfc).isIdentityRef()) {
- return caseJavaIdentityRefAttribute(openType);
- } else if(((JavaAttribute)attributeIfc).isEnum()) {
- return caseJavaEnumAttribute(openType);
- } else {
- return caseJavaAttribute(openType);
- }
- } catch (UnknownOpenTypeException e) {
- throw getIllegalArgumentException(attributeIfc);
- }
-
- } else if (attributeIfc instanceof DependencyAttribute) {
- return caseDependencyAttribute(((DependencyAttribute) attributeIfc).getOpenType());
- } else if (attributeIfc instanceof ListAttribute) {
- return caseListAttribute((ArrayType<?>) openType);
- } else if (attributeIfc instanceof ListDependenciesAttribute) {
- return caseListDependeciesAttribute((ArrayType<?>) openType);
- } else if (attributeIfc instanceof TOAttribute) {
- return caseTOAttribute(((TOAttribute) attributeIfc).getOpenType());
- }
-
- throw getIllegalArgumentException(attributeIfc);
- }
-
- public AttributeIfc getLastAttribute() {
- return lastAttribute;
- }
-
- protected T caseJavaIdentityRefAttribute(OpenType<?> openType) {
- return caseJavaAttribute(openType);
- }
-
- protected T caseJavaUnionAttribute(OpenType<?> openType) {
- return caseJavaAttribute(openType);
- }
-
- protected T caseJavaEnumAttribute(OpenType<?> openType) {
- return caseJavaAttribute(openType);
- }
-
- protected T caseJavaBinaryAttribute(OpenType<?> openType) {
- return caseJavaAttribute(openType);
- }
-
- private IllegalArgumentException getIllegalArgumentException(AttributeIfc attributeIfc) {
- return new IllegalArgumentException("Unknown attribute type " + attributeIfc.getClass() + ", " + attributeIfc
- + " with open type:" + attributeIfc.getOpenType());
- }
-
- public final T caseJavaAttribute(OpenType<?> openType) {
- if (openType instanceof SimpleType<?>) {
- return caseJavaSimpleAttribute((SimpleType<?>) openType);
- } else if (openType instanceof ArrayType<?>) {
- return caseJavaArrayAttribute((ArrayType<?>) openType);
- } else if (openType instanceof CompositeType) {
- return caseJavaCompositeAttribute((CompositeType) openType);
- }
-
- throw new UnknownOpenTypeException("Unknown attribute open type " + openType);
- }
-
- protected abstract T caseJavaSimpleAttribute(SimpleType<?> openType);
-
- protected abstract T caseJavaArrayAttribute(ArrayType<?> openType);
-
- protected abstract T caseJavaCompositeAttribute(CompositeType openType);
-
- protected abstract T caseDependencyAttribute(SimpleType<?> attributeIfc);
-
- protected abstract T caseTOAttribute(CompositeType openType);
-
- protected abstract T caseListAttribute(ArrayType<?> openType);
-
- protected abstract T caseListDependeciesAttribute(ArrayType<?> openType);
-
- private static class UnknownOpenTypeException extends RuntimeException {
- private static final long serialVersionUID = 1L;
-
- public UnknownOpenTypeException(String message) {
- super(message);
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml;
-
-import java.util.List;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-
-public abstract class AbstractAttributeReadingStrategy implements AttributeReadingStrategy {
-
- private final String nullableDefault;
-
- public AbstractAttributeReadingStrategy(String nullableDefault) {
- this.nullableDefault = nullableDefault;
- }
-
- public String getNullableDefault() {
- return nullableDefault;
- }
-
- @Override
- public AttributeConfigElement readElement(List<XmlElement> configNodes) throws NetconfDocumentedException {
- if (configNodes.size() == 0){
- return AttributeConfigElement.createNullValue(postprocessNullableDefault(nullableDefault));
- }
- return readElementHook(configNodes);
- }
-
- abstract AttributeConfigElement readElementHook(List<XmlElement> configNodes) throws NetconfDocumentedException;
-
- protected Object postprocessNullableDefault(String nullableDefault) {
- return nullableDefault;
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml;
-
-import com.google.common.collect.Lists;
-import java.util.List;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-
-public class ArrayAttributeReadingStrategy extends AbstractAttributeReadingStrategy {
-
- private final AttributeReadingStrategy innerStrategy;
-
- /**
- * @param attributeIfc
- * @param innerStrategy
- */
- public ArrayAttributeReadingStrategy(String nullableDefault, AttributeReadingStrategy innerStrategy) {
- super(nullableDefault);
- this.innerStrategy = innerStrategy;
- }
-
- @Override
- AttributeConfigElement readElementHook(List<XmlElement> configNodes) throws NetconfDocumentedException {
- List<Object> innerList = Lists.newArrayList();
- EditStrategyType innerEditStrategy= null;
- for (XmlElement configNode : configNodes) {
- final AttributeConfigElement attributeConfigElement = innerStrategy.readElement(Lists.newArrayList(configNode));
- if(attributeConfigElement.getEditStrategy().isPresent()) {
- // TODO this sets the last operation for the entire array
- innerEditStrategy = attributeConfigElement.getEditStrategy().get();
- }
- innerList.add(attributeConfigElement.getValue());
- }
- return innerEditStrategy == null ? AttributeConfigElement.create(getNullableDefault(), innerList) :
- AttributeConfigElement.create(getNullableDefault(), innerList, innerEditStrategy);
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml;
-
-import com.google.common.base.Optional;
-import javax.management.openmbean.OpenType;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving.AttributeResolvingStrategy;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
-
-/**
- * Parsed xml element containing configuration for one attribute of an instance
- * of some module. Contains default value extracted from yang file.
- */
-public class AttributeConfigElement {
- private final Object defaultValue;
- private final Object value;
- private final Optional<EditStrategyType> editStrategy;
-
- private Optional<?> resolvedValue;
- private Object resolvedDefaultValue;
- private String jmxName;
-
- public AttributeConfigElement(Object defaultValue, Object value, final EditStrategyType editStrategyType) {
- this.defaultValue = defaultValue;
- this.value = value;
- this.editStrategy = Optional.fromNullable(editStrategyType);
- }
-
- public void setJmxName(String jmxName) {
- this.jmxName = jmxName;
- }
-
- public String getJmxName() {
- return jmxName;
- }
-
- public void resolveValue(AttributeResolvingStrategy<?, ? extends OpenType<?>> attributeResolvingStrategy,
- String attrName) throws NetconfDocumentedException {
- resolvedValue = attributeResolvingStrategy.parseAttribute(attrName, value);
- Optional<?> resolvedDefault = attributeResolvingStrategy.parseAttribute(attrName, defaultValue);
- resolvedDefaultValue = resolvedDefault.isPresent() ? resolvedDefault.get() : null;
- }
-
- public Optional<EditStrategyType> getEditStrategy() {
- return editStrategy;
- }
-
- public static AttributeConfigElement create(Object nullableDefault, Object value) {
- return new AttributeConfigElement(nullableDefault, value, null);
- }
-
- public static AttributeConfigElement createNullValue(Object nullableDefault) {
- return new AttributeConfigElement(nullableDefault, null, null);
- }
-
- public static AttributeConfigElement create(final String nullableDefault, final Object value, final EditStrategyType editStrategyType) {
- return new AttributeConfigElement(nullableDefault, value, editStrategyType);
- }
-
- public Object getValue() {
- return value;
- }
-
- public Object getDefaultValue() {
- return defaultValue;
- }
-
- public Optional<?> getResolvedValue() {
- return resolvedValue;
- }
-
- public Object getResolvedDefaultValue() {
- return resolvedDefaultValue;
- }
-
- @Override
- public String toString() {
- return "AttributeConfigElement [defaultValue=" + defaultValue + ", value=" + value + "]";
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml;
-
-import java.util.List;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-
-public interface AttributeReadingStrategy {
-
- public abstract AttributeConfigElement readElement(List<XmlElement> element) throws NetconfDocumentedException;
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml;
-
-import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-
-public class CompositeAttributeReadingStrategy extends AbstractAttributeReadingStrategy {
-
- private final Map<String, AttributeReadingStrategy> innerStrategies;
-
- public CompositeAttributeReadingStrategy(String nullableDefault,
- Map<String, AttributeReadingStrategy> innerStrategies) {
- super(nullableDefault);
- this.innerStrategies = innerStrategies;
- }
-
- @Override
- AttributeConfigElement readElementHook(List<XmlElement> configNodes) throws NetconfDocumentedException {
-
- Preconditions.checkState(configNodes.size() == 1, "This element should be present only once %s", configNodes);
-
- XmlElement complexElement = configNodes.get(0);
-
- Map<String, Object> innerMap = Maps.newHashMap();
-
- List<XmlElement> recognisedChildren = Lists.newArrayList();
- for (Entry<String, AttributeReadingStrategy> innerAttrEntry : innerStrategies.entrySet()) {
- List<XmlElement> childItem = complexElement.getChildElementsWithSameNamespace(
- innerAttrEntry.getKey());
- recognisedChildren.addAll(childItem);
-
- AttributeConfigElement resolvedInner = innerAttrEntry.getValue().readElement(childItem);
-
- Object value = resolvedInner.getValue();
- if(value == null) {
- value = resolvedInner.getDefaultValue();
- }
-
- innerMap.put(innerAttrEntry.getKey(), value);
- }
-
- complexElement.checkUnrecognisedElements(recognisedChildren);
-
- String perInstanceEditStrategy = complexElement.getAttribute(XmlNetconfConstants.OPERATION_ATTR_KEY,
- XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
-
- return Strings.isNullOrEmpty(perInstanceEditStrategy) ? AttributeConfigElement.create(getNullableDefault(), innerMap) :
- AttributeConfigElement.create(getNullableDefault(), innerMap, EditStrategyType.valueOf(perInstanceEditStrategy));
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml;
-
-import com.google.common.base.Preconditions;
-import java.util.List;
-import java.util.Map;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.ObjectNameAttributeMappingStrategy;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-
-public class ObjectNameAttributeReadingStrategy extends AbstractAttributeReadingStrategy {
-
- private static final Object PREFIX_SEPARATOR = ":";
-
- public ObjectNameAttributeReadingStrategy(String nullableDefault) {
- super(nullableDefault);
- }
-
- @Override
- AttributeConfigElement readElementHook(List<XmlElement> configNodes) throws NetconfDocumentedException {
-
- XmlElement firstChild = configNodes.get(0);
- Preconditions.checkState(configNodes.size() == 1, "This element should be present only once " + firstChild
- + " but was " + configNodes.size());
-
- Preconditions.checkNotNull(firstChild, "Element %s should be present", firstChild);
- return AttributeConfigElement.create(getNullableDefault(), resolve(firstChild));
- }
-
- private ObjectNameAttributeMappingStrategy.MappedDependency resolve(XmlElement firstChild) throws NetconfDocumentedException{
- XmlElement typeElement = firstChild.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.TYPE_KEY);
- Map.Entry<String, String> prefixNamespace = typeElement.findNamespaceOfTextContent();
-
- String serviceName = checkPrefixAndExtractServiceName(typeElement, prefixNamespace);
-
- XmlElement nameElement = firstChild.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.NAME_KEY);
- String dependencyName = nameElement.getTextContent();
-
- return new ObjectNameAttributeMappingStrategy.MappedDependency(prefixNamespace.getValue(), serviceName,
- dependencyName);
- }
-
- public static String checkPrefixAndExtractServiceName(XmlElement typeElement, Map.Entry<String, String> prefixNamespace) throws NetconfDocumentedException {
- String serviceName = typeElement.getTextContent();
- Preconditions.checkNotNull(prefixNamespace.getKey(), "Service %s value cannot be linked to namespace",
- XmlNetconfConstants.TYPE_KEY);
- if(prefixNamespace.getKey().isEmpty()) {
- return serviceName;
- } else {
- String prefix = prefixNamespace.getKey() + PREFIX_SEPARATOR;
- Preconditions.checkState(serviceName.startsWith(prefix),
- "Service %s not correctly prefixed, expected %s, but was %s", XmlNetconfConstants.TYPE_KEY, prefix,
- serviceName);
- serviceName = serviceName.substring(prefix.length());
- return serviceName;
- }
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-import java.util.Date;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import javax.management.openmbean.ArrayType;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.OpenType;
-import javax.management.openmbean.SimpleType;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
-
-public class ObjectXmlReader extends AttributeIfcSwitchStatement<AttributeReadingStrategy> {
-
- private String key;
- private Map<String, Map<Date, EditConfig.IdentityMapping>> identityMap;
-
- public Map<String, AttributeReadingStrategy> prepareReading(Map<String, AttributeIfc> yangToAttrConfig, Map<String, Map<Date,EditConfig.IdentityMapping>> identityMap) {
- Map<String, AttributeReadingStrategy> strategies = Maps.newHashMap();
- this.identityMap = identityMap;
-
- for (Entry<String, AttributeIfc> attributeEntry : yangToAttrConfig.entrySet()) {
- AttributeReadingStrategy strat = prepareReadingStrategy(attributeEntry.getKey(), attributeEntry.getValue());
- strategies.put(attributeEntry.getKey(), strat);
- }
- return strategies;
- }
-
- private AttributeReadingStrategy prepareReadingStrategy(String key, AttributeIfc attributeIfc) {
- this.key = key;
- return switchAttribute(attributeIfc);
- }
-
- @Override
- protected AttributeReadingStrategy caseJavaBinaryAttribute(OpenType<?> openType) {
- return new SimpleBinaryAttributeReadingStrategy(getLastAttribute().getNullableDefault());
- }
-
- @Override
- protected AttributeReadingStrategy caseJavaUnionAttribute(OpenType<?> openType) {
- String mappingKey = JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION;
- return new SimpleUnionAttributeReadingStrategy(getLastAttribute().getNullableDefault(), mappingKey);
- }
-
- @Override
- public AttributeReadingStrategy caseJavaSimpleAttribute(SimpleType<?> openType) {
- return new SimpleAttributeReadingStrategy(getLastAttribute().getNullableDefault());
- }
-
- @Override
- public AttributeReadingStrategy caseJavaArrayAttribute(ArrayType<?> openType) {
- SimpleAttributeReadingStrategy innerStrategy = new SimpleAttributeReadingStrategy(getLastAttribute().getNullableDefault());
- return new ArrayAttributeReadingStrategy(getLastAttribute().getNullableDefault(), innerStrategy);
- }
-
- @Override
- public AttributeReadingStrategy caseJavaCompositeAttribute(CompositeType openType) {
- Preconditions.checkState(openType.keySet().size() == 1, "Unexpected number of elements for open type %s, should be 1", openType);
- String mappingKey = openType.keySet().iterator().next();
- return new SimpleCompositeAttributeReadingStrategy(getLastAttribute().getNullableDefault(), mappingKey);
- }
-
- @Override
- protected AttributeReadingStrategy caseJavaIdentityRefAttribute(OpenType<?> openType) {
- Preconditions.checkState(openType instanceof CompositeType);
- Set<String> keys = ((CompositeType) openType).keySet();
- Preconditions.checkState(keys.size() == 1, "Unexpected number of elements for open type %s, should be 1", openType);
- String mappingKey = keys.iterator().next();
- return new SimpleIdentityRefAttributeReadingStrategy(getLastAttribute().getNullableDefault(), mappingKey, identityMap);
- }
-
- @Override
- protected AttributeReadingStrategy caseDependencyAttribute(SimpleType<?> openType) {
- return new ObjectNameAttributeReadingStrategy(getLastAttribute().getNullableDefault());
- }
-
- @Override
- protected AttributeReadingStrategy caseTOAttribute(CompositeType openType) {
- AttributeIfc lastAttribute = getLastAttribute();
- Preconditions.checkState(lastAttribute instanceof TOAttribute);
- Map<String, AttributeIfc> inner = ((TOAttribute)lastAttribute).getYangPropertiesToTypesMap();
-
- Map<String, AttributeReadingStrategy> innerStrategies = Maps.newHashMap();
-
- for (Entry<String, AttributeIfc> innerAttrEntry : inner.entrySet()) {
- AttributeReadingStrategy innerStrat = prepareReadingStrategy(innerAttrEntry.getKey(),
- innerAttrEntry.getValue());
- innerStrategies.put(innerAttrEntry.getKey(), innerStrat);
- }
-
- return new CompositeAttributeReadingStrategy(lastAttribute.getNullableDefault(), innerStrategies);
- }
-
- @Override
- protected AttributeReadingStrategy caseListAttribute(ArrayType<?> openType) {
- AttributeIfc lastAttribute = getLastAttribute();
- Preconditions.checkState(lastAttribute instanceof ListAttribute);
- AttributeReadingStrategy innerStrategy = prepareReadingStrategy(key, ((ListAttribute) lastAttribute).getInnerAttribute());
- return new ArrayAttributeReadingStrategy(lastAttribute.getNullableDefault(), innerStrategy);
- }
-
- @Override
- protected AttributeReadingStrategy caseListDependeciesAttribute(ArrayType<?> openType) {
- AttributeIfc lastAttribute = getLastAttribute();
- Preconditions.checkState(lastAttribute instanceof ListDependenciesAttribute);
- AttributeReadingStrategy innerStrategy = caseDependencyAttribute(SimpleType.OBJECTNAME);
- return new ArrayAttributeReadingStrategy(lastAttribute.getNullableDefault(), innerStrategy);
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml;
-
-import com.google.common.base.Preconditions;
-import java.util.List;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-
-public class SimpleAttributeReadingStrategy extends AbstractAttributeReadingStrategy {
- public SimpleAttributeReadingStrategy(String nullableDefault) {
- super(nullableDefault);
- }
-
- @Override
- AttributeConfigElement readElementHook(List<XmlElement> configNodes) throws NetconfDocumentedException {
- XmlElement xmlElement = configNodes.get(0);
- Preconditions.checkState(configNodes.size() == 1, "This element should be present only once " + xmlElement
- + " but was " + configNodes.size());
-
- String textContent = readElementContent(xmlElement);
- return AttributeConfigElement.create(postprocessNullableDefault(getNullableDefault()),
- postprocessParsedValue(textContent));
- }
-
- protected String readElementContent(XmlElement xmlElement) throws NetconfDocumentedException {
- return xmlElement.getTextContent();
- }
-
- @Override
- protected Object postprocessNullableDefault(String nullableDefault) {
- return nullableDefault;
- }
-
- protected Object postprocessParsedValue(String textContent) {
- return textContent;
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml;
-
-import com.google.common.collect.Lists;
-import com.google.common.io.BaseEncoding;
-import java.util.List;
-
-public class SimpleBinaryAttributeReadingStrategy extends SimpleAttributeReadingStrategy {
-
- public SimpleBinaryAttributeReadingStrategy(String nullableDefault) {
- super(nullableDefault);
- }
-
- @Override
- protected Object postprocessParsedValue(String textContent) {
- BaseEncoding en = BaseEncoding.base64();
- byte[] decode = en.decode(textContent);
- List<String> parsed = Lists.newArrayListWithCapacity(decode.length);
- for (byte b : decode) {
- parsed.add(Byte.toString(b));
- }
- return parsed;
- }
-
- @Override
- protected Object postprocessNullableDefault(String nullableDefault) {
- return nullableDefault == null ? null : postprocessParsedValue(nullableDefault);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml;
-
-import com.google.common.collect.Maps;
-import java.util.HashMap;
-
-public class SimpleCompositeAttributeReadingStrategy extends SimpleAttributeReadingStrategy {
-
- private final String key;
-
- public SimpleCompositeAttributeReadingStrategy(String nullableDefault, String key) {
- super(nullableDefault);
- this.key = key;
- }
-
- @Override
- protected Object postprocessParsedValue(String textContent) {
- HashMap<String,String> map = Maps.newHashMap();
- map.put(key, textContent);
- return map;
- }
-
- @Override
- protected Object postprocessNullableDefault(String nullableDefault) {
- return nullableDefault == null ? null : postprocessParsedValue(nullableDefault);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-import java.net.URI;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.yangtools.yang.common.QName;
-
-
-public class SimpleIdentityRefAttributeReadingStrategy extends SimpleAttributeReadingStrategy {
-
- private final String key;
- private final Map<String, Map<Date, EditConfig.IdentityMapping>> identityMap;
-
- public SimpleIdentityRefAttributeReadingStrategy(String nullableDefault, String key, Map<String, Map<Date,EditConfig.IdentityMapping>> identityMap) {
- super(nullableDefault);
- this.key = key;
- this.identityMap = identityMap;
- }
-
- @Override
- protected String readElementContent(XmlElement xmlElement) throws NetconfDocumentedException {
- Map.Entry<String, String> namespaceOfTextContent = xmlElement.findNamespaceOfTextContent();
- String content = xmlElement.getTextContent();
-
- final String namespace;
- final String localName;
- if(namespaceOfTextContent.getKey().isEmpty()) {
- localName = content;
- namespace = xmlElement.getNamespace();
- } else {
- String prefix = namespaceOfTextContent.getKey() + ":";
- Preconditions.checkArgument(content.startsWith(prefix), "Identity ref should be prefixed with \"%s\"", prefix);
- localName = content.substring(prefix.length());
- namespace = namespaceOfTextContent.getValue();
- }
-
- Date revision = null;
- Map<Date, EditConfig.IdentityMapping> revisions = identityMap.get(namespace);
- if(revisions.keySet().size() > 1) {
- for (Map.Entry<Date, EditConfig.IdentityMapping> revisionToIdentityEntry : revisions.entrySet()) {
- if(revisionToIdentityEntry.getValue().containsIdName(localName)) {
- Preconditions.checkState(revision == null, "Duplicate identity %s, in namespace %s, with revisions: %s, %s detected. Cannot map attribute",
- localName, namespace, revision, revisionToIdentityEntry.getKey());
- revision = revisionToIdentityEntry.getKey();
- }
- }
- } else {
- revision = revisions.keySet().iterator().next();
- }
-
- return QName.create(URI.create(namespace), revision, localName).toString();
- }
-
- @Override
- protected Object postprocessParsedValue(String textContent) {
- HashMap<String,String> map = Maps.newHashMap();
- map.put(key, textContent);
- return map;
- }
-
- @Override
- protected Object postprocessNullableDefault(String nullableDefault) {
- return nullableDefault == null ? null : postprocessParsedValue(nullableDefault);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import java.util.List;
-import java.util.Map;
-
-public class SimpleUnionAttributeReadingStrategy extends SimpleAttributeReadingStrategy {
-
- private final String key;
-
- public SimpleUnionAttributeReadingStrategy(String nullableDefault, String key) {
- super(nullableDefault);
- this.key = key;
- }
-
- @Override
- protected Object postprocessParsedValue(String textContent) {
- char[] charArray = textContent.toCharArray();
- List<String> chars = Lists.newArrayListWithCapacity(charArray.length);
-
- for (char c : charArray) {
- chars.add(Character.toString(c));
- }
-
- Map<String, Object> map = Maps.newHashMap();
- map.put(key, chars);
- return map;
- }
-
- @Override
- protected Object postprocessNullableDefault(String nullableDefault) {
- return nullableDefault == null ? null : postprocessParsedValue(nullableDefault);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping;
-
-import javax.management.openmbean.OpenType;
-
-public abstract class AbstractAttributeMappingStrategy<T, O extends OpenType<?>> implements
- AttributeMappingStrategy<T, O> {
-
- private final O attrOpenType;
-
- public AbstractAttributeMappingStrategy(O attributeIfc) {
- this.attrOpenType = attributeIfc;
- }
-
- @Override
- public O getOpenType() {
- return attrOpenType;
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-import java.lang.reflect.Array;
-import java.util.List;
-import javax.management.openmbean.ArrayType;
-import javax.management.openmbean.OpenType;
-
-public class ArrayAttributeMappingStrategy extends AbstractAttributeMappingStrategy<List<Object>, ArrayType<?>> {
-
- private final AttributeMappingStrategy<?, ? extends OpenType<?>> innerElementStrategy;
-
- public ArrayAttributeMappingStrategy(ArrayType<?> arrayType,
- AttributeMappingStrategy<?, ? extends OpenType<?>> innerElementStrategy) {
- super(arrayType);
- this.innerElementStrategy = innerElementStrategy;
- }
-
- @Override
- public Optional<List<Object>> mapAttribute(Object value) {
- if (value == null){
- return Optional.absent();
- }
-
- Preconditions.checkArgument(value.getClass().isArray(), "Value has to be instanceof Array ");
-
- List<Object> retVal = Lists.newArrayList();
-
- for (int i = 0; i < Array.getLength(value); i++) {
- Object innerValue = Array.get(value, i);
- Optional<?> mapAttribute = innerElementStrategy.mapAttribute(innerValue);
-
- if (mapAttribute.isPresent()){
- retVal.add(mapAttribute.get());
- }
- }
-
- return Optional.of(retVal);
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping;
-
-import com.google.common.base.Optional;
-import javax.management.openmbean.OpenType;
-
-public interface AttributeMappingStrategy<T, O extends OpenType<?>> {
-
- O getOpenType();
-
- Optional<T> mapAttribute(Object o);
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-import java.util.Map;
-import java.util.Set;
-import javax.management.openmbean.CompositeDataSupport;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.OpenType;
-import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
-
-public class CompositeAttributeMappingStrategy extends
- AbstractAttributeMappingStrategy<Map<String, Object>, CompositeType> {
-
- private final Map<String, AttributeMappingStrategy<?, ? extends OpenType<?>>> innerStrategies;
- private final Map<String, String> jmxToJavaNameMapping;
-
- public CompositeAttributeMappingStrategy(CompositeType compositeType,
- Map<String, AttributeMappingStrategy<?, ? extends OpenType<?>>> innerStrategies,
- Map<String, String> jmxToJavaNameMapping) {
- super(compositeType);
- this.innerStrategies = innerStrategies;
- this.jmxToJavaNameMapping = jmxToJavaNameMapping;
- }
-
- @Override
- public Optional<Map<String, Object>> mapAttribute(Object value) {
- if (value == null){
- return Optional.absent();
- }
-
- Util.checkType(value, CompositeDataSupport.class);
-
- CompositeDataSupport compositeData = (CompositeDataSupport) value;
- CompositeType currentType = compositeData.getCompositeType();
- CompositeType expectedType = getOpenType();
-
- Set<String> expectedCompositeTypeKeys = expectedType.keySet();
- Set<String> currentCompositeTypeKeys = currentType.keySet();
- Preconditions.checkArgument(expectedCompositeTypeKeys.equals(currentCompositeTypeKeys),
- "Composite type mismatch, expected composite type with attributes " + expectedCompositeTypeKeys
- + " but was " + currentCompositeTypeKeys);
-
- Map<String, Object> retVal = Maps.newHashMap();
-
- for (String jmxName : jmxToJavaNameMapping.keySet()) {
- Optional<?> mapped = mapInnerAttribute(compositeData, jmxName, expectedType.getDescription(jmxName));
- if(mapped.isPresent()){
- retVal.put(jmxToJavaNameMapping.get(jmxName), mapped.get());
- }
- }
-
- return Optional.of(retVal);
- }
-
- protected Optional<?> mapInnerAttribute(CompositeDataSupport compositeData, String jmxName, String description) {
- Object innerValue = compositeData.get(jmxName);
-
- AttributeMappingStrategy<?, ? extends OpenType<?>> attributeMappingStrategy = innerStrategies
- .get(jmxName);
- return attributeMappingStrategy.mapAttribute(innerValue);
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping;
-
-import com.google.common.base.Optional;
-import javax.management.openmbean.CompositeType;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
-
-public class EnumAttributeMappingStrategy extends AbstractAttributeMappingStrategy<String, CompositeType> {
-
- private final EnumResolver enumResolver;
-
- public EnumAttributeMappingStrategy(CompositeType openType, final EnumResolver enumResolver) {
- super(openType);
- this.enumResolver = enumResolver;
- }
-
- @Override
- public Optional<String> mapAttribute(Object value) {
- if (value == null){
- return Optional.absent();
- }
-
- String expectedClass = getOpenType().getTypeName();
- return Optional.of(enumResolver.toYang(expectedClass, value.toString()));
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-import java.util.Map;
-import java.util.Map.Entry;
-import javax.management.openmbean.ArrayType;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.OpenType;
-import javax.management.openmbean.SimpleType;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
-
-public class ObjectMapper extends AttributeIfcSwitchStatement<AttributeMappingStrategy<?, ? extends OpenType<?>>> {
-
- private EnumResolver enumResolver;
-
- public Map<String, AttributeMappingStrategy<?, ? extends OpenType<?>>> prepareMapping(
- Map<String, AttributeIfc> configDefinition, EnumResolver enumResolver) {
- this.enumResolver = Preconditions.checkNotNull(enumResolver);
- Map<String, AttributeMappingStrategy<?, ? extends OpenType<?>>> strategies = Maps.newHashMap();
-
- for (Entry<String, AttributeIfc> attrEntry : configDefinition.entrySet()) {
- strategies.put(attrEntry.getKey(), prepareStrategy(attrEntry.getValue()));
- }
-
- return strategies;
- }
-
- public AttributeMappingStrategy<?, ? extends OpenType<?>> prepareStrategy(AttributeIfc attributeIfc) {
-
- if(attributeIfc instanceof DependencyAttribute) {
- namespaceOfDepAttr = ((DependencyAttribute)attributeIfc).getDependency().getSie().getQName().getNamespace().toString();
- } else if (attributeIfc instanceof ListDependenciesAttribute) {
- namespaceOfDepAttr = ((ListDependenciesAttribute)attributeIfc).getDependency().getSie().getQName().getNamespace().toString();
- }
-
- return switchAttribute(attributeIfc);
- }
-
- private Map<String, String> createJmxToYangMapping(TOAttribute attributeIfc) {
- Map<String, String> retVal = Maps.newHashMap();
- for (Entry<String, AttributeIfc> entry : attributeIfc.getJmxPropertiesToTypesMap().entrySet()) {
- retVal.put(entry.getKey(), (entry.getValue()).getAttributeYangName());
- }
- return retVal;
- }
-
- @Override
- protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseJavaSimpleAttribute(SimpleType<?> openType) {
- return new SimpleAttributeMappingStrategy(openType);
- }
-
- @Override
- protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseJavaEnumAttribute(final OpenType<?> openType) {
- return new EnumAttributeMappingStrategy(((CompositeType) openType), enumResolver);
- }
-
- @Override
- protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseJavaArrayAttribute(ArrayType<?> openType) {
-
- AttributeMappingStrategy<?, ? extends OpenType<?>> innerStrategy = new SimpleAttributeMappingStrategy(
- (SimpleType<?>) openType.getElementOpenType());
- return new ArrayAttributeMappingStrategy(openType, innerStrategy);
- }
-
- @Override
- protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseJavaCompositeAttribute(CompositeType openType) {
- Map<String, AttributeMappingStrategy<?, ? extends OpenType<?>>> innerStrategies = Maps.newHashMap();
-
- Map<String, String> attributeMapping = Maps.newHashMap();
-
- for (String innerAttributeKey : openType.keySet()) {
-
- innerStrategies.put(innerAttributeKey, caseJavaAttribute(openType.getType(innerAttributeKey)));
- attributeMapping.put(innerAttributeKey, innerAttributeKey);
- }
-
- return new CompositeAttributeMappingStrategy(openType, innerStrategies, attributeMapping);
- }
-
- @Override
- protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseJavaUnionAttribute(OpenType<?> openType) {
- Map<String, AttributeMappingStrategy<?, ? extends OpenType<?>>> innerStrategies = Maps.newHashMap();
-
- Map<String, String> attributeMapping = Maps.newHashMap();
-
- CompositeType compositeType = (CompositeType) openType;
- for (String innerAttributeKey : compositeType.keySet()) {
-
- innerStrategies.put(innerAttributeKey, caseJavaAttribute(compositeType.getType(innerAttributeKey)));
- attributeMapping.put(innerAttributeKey, innerAttributeKey);
- }
-
- return new UnionCompositeAttributeMappingStrategy(compositeType, innerStrategies, attributeMapping);
- }
-
- private String namespaceOfDepAttr;
-
- @Override
- protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseDependencyAttribute(
- SimpleType<?> openType) {
- return new ObjectNameAttributeMappingStrategy(openType, namespaceOfDepAttr);
- }
-
- @Override
- protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseTOAttribute(CompositeType openType) {
- Map<String, AttributeMappingStrategy<?, ? extends OpenType<?>>> innerStrategies = Maps.newHashMap();
-
- Preconditions.checkState(getLastAttribute() instanceof TOAttribute);
- TOAttribute lastTO = (TOAttribute) getLastAttribute();
-
- for (Entry<String, AttributeIfc> innerAttrEntry : ((TOAttribute)getLastAttribute()).getJmxPropertiesToTypesMap().entrySet()) {
- innerStrategies.put(innerAttrEntry.getKey(), prepareStrategy(innerAttrEntry.getValue()));
- }
-
- return new CompositeAttributeMappingStrategy(openType, innerStrategies,
- createJmxToYangMapping(lastTO));
- }
-
- @Override
- protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseListAttribute(ArrayType<?> openType) {
- Preconditions.checkState(getLastAttribute() instanceof ListAttribute);
- return new ArrayAttributeMappingStrategy(openType,
- prepareStrategy(((ListAttribute) getLastAttribute()).getInnerAttribute()));
- }
-
- @Override
- protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseListDependeciesAttribute(ArrayType<?> openType) {
- Preconditions.checkState(getLastAttribute() instanceof ListDependenciesAttribute);
- return new ArrayAttributeMappingStrategy(openType, caseDependencyAttribute(SimpleType.OBJECTNAME));
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import javax.management.ObjectName;
-import javax.management.openmbean.SimpleType;
-import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
-import org.opendaylight.yangtools.yang.common.QName;
-
-public class ObjectNameAttributeMappingStrategy extends
- AbstractAttributeMappingStrategy<ObjectNameAttributeMappingStrategy.MappedDependency, SimpleType<?>> {
-
- private final String namespace;
-
- public ObjectNameAttributeMappingStrategy(SimpleType<?> openType, String namespace) {
- super(openType);
- this.namespace = namespace;
- }
-
- @Override
- public Optional<MappedDependency> mapAttribute(Object value) {
- if (value == null){
- return Optional.absent();
- }
-
- String expectedClass = getOpenType().getClassName();
- String realClass = value.getClass().getName();
- Preconditions.checkArgument(realClass.equals(expectedClass), "Type mismatch, expected " + expectedClass
- + " but was " + realClass);
- Util.checkType(value, ObjectName.class);
-
- ObjectName on = (ObjectName) value;
-
- String refName = ObjectNameUtil.getReferenceName(on);
-
- //we want to use the exact service name that was configured in xml so services that are referencing it can be resolved
- return Optional.of(new MappedDependency(namespace,
- QName.create(ObjectNameUtil.getServiceQName(on)).getLocalName(), refName));
- }
-
- public static class MappedDependency {
- private final String namespace, serviceName, refName;
-
- public MappedDependency(String namespace, String serviceName, String refName) {
- this.serviceName = serviceName;
- this.refName = refName;
- this.namespace = namespace;
- }
-
- public String getServiceName() {
- return serviceName;
- }
-
- public String getRefName() {
- return refName;
- }
-
- public String getNamespace() {
- return namespace;
- }
-
- @Override
- public String toString() {
- final StringBuffer sb = new StringBuffer("MappedDependency{");
- sb.append("namespace='").append(namespace).append('\'');
- sb.append(", serviceName='").append(serviceName).append('\'');
- sb.append(", refName='").append(refName).append('\'');
- sb.append('}');
- return sb.toString();
- }
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-import java.util.Date;
-import java.util.Map;
-import javax.management.openmbean.SimpleType;
-import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
-
-public class SimpleAttributeMappingStrategy extends AbstractAttributeMappingStrategy<String, SimpleType<?>> {
-
- public SimpleAttributeMappingStrategy(SimpleType<?> openType) {
- super(openType);
- }
-
- @Override
- public Optional<String> mapAttribute(Object value) {
- if (value == null){
- return Optional.absent();
- }
-
- String expectedClass = getOpenType().getClassName();
- String realClass = value.getClass().getName();
- Preconditions.checkArgument(realClass.equals(expectedClass), "Type mismatch, expected " + expectedClass
- + " but was " + realClass);
-
- WriterPlugin prefferedPlugin = writerPlugins.get(value.getClass().getCanonicalName());
- prefferedPlugin = prefferedPlugin == null ? writerPlugins.get(DEFAULT_WRITER_PLUGIN) : prefferedPlugin;
- return Optional.of(prefferedPlugin.writeObject(value));
- }
-
- private static final String DEFAULT_WRITER_PLUGIN = "default";
- private static final Map<String, WriterPlugin> writerPlugins = Maps.newHashMap();
- static {
- writerPlugins.put(DEFAULT_WRITER_PLUGIN, new DefaultWriterPlugin());
- writerPlugins.put(Date.class.getCanonicalName(), new DatePlugin());
- }
-
- /**
- * Custom writer plugins must implement this interface.
- */
- static interface WriterPlugin {
- String writeObject(Object value);
- }
-
- static class DefaultWriterPlugin implements WriterPlugin {
-
- @Override
- public String writeObject(Object value) {
- return value.toString();
- }
- }
-
- static class DatePlugin implements WriterPlugin {
-
- @Override
- public String writeObject(Object value) {
- Preconditions.checkArgument(value instanceof Date, "Attribute must be Date");
- return Util.writeDate((Date) value);
- }
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping;
-
-import com.google.common.base.Optional;
-import java.util.Map;
-import javax.management.openmbean.CompositeDataSupport;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.OpenType;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
-
-public class UnionCompositeAttributeMappingStrategy extends
- CompositeAttributeMappingStrategy {
-
-
- public UnionCompositeAttributeMappingStrategy(CompositeType compositeType, Map<String, AttributeMappingStrategy<?, ? extends OpenType<?>>> innerStrategies, Map<String, String> jmxToJavaNameMapping) {
- super(compositeType, innerStrategies, jmxToJavaNameMapping);
- }
-
- @Override
- protected Optional<?> mapInnerAttribute(CompositeDataSupport compositeData, String jmxName, String description) {
- if(!description.equals(JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION)){
- return Optional.absent();
- }
- return super.mapInnerAttribute(compositeData, jmxName, description);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving;
-
-import javax.management.openmbean.OpenType;
-
-abstract class AbstractAttributeResolvingStrategy<T, O extends OpenType<?>> implements AttributeResolvingStrategy<T, O> {
- private O openType;
-
- public AbstractAttributeResolvingStrategy(O openType) {
- this.openType = openType;
- }
-
- @Override
- public O getOpenType() {
- return openType;
- }
-
- /**
- * Composite types might change during resolution. Use this setter to update open type
- */
- public void setOpenType(final O openType) {
- this.openType = openType;
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving;
-
-import com.google.common.base.Optional;
-import java.lang.reflect.Array;
-import java.util.List;
-import javax.management.openmbean.ArrayType;
-import javax.management.openmbean.CompositeDataSupport;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.OpenDataException;
-import javax.management.openmbean.OpenType;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-final class ArrayAttributeResolvingStrategy extends AbstractAttributeResolvingStrategy<Object, ArrayType<?>> {
-
- private final AttributeResolvingStrategy<?, ? extends OpenType<?>> innerTypeResolvingStrategy;
-
- private static final Logger LOG = LoggerFactory.getLogger(ArrayAttributeResolvingStrategy.class);
-
- public ArrayAttributeResolvingStrategy(AttributeResolvingStrategy<?, ? extends OpenType<?>> innerTypeResolved,
- ArrayType<?> openType) {
- super(openType);
- this.innerTypeResolvingStrategy = innerTypeResolved;
- }
-
- @Override
- public Optional<Object> parseAttribute(String attrName, Object value) throws NetconfDocumentedException {
- if (value == null) {
- return Optional.absent();
- }
-
- Util.checkType(value, List.class);
- List<?> valueList = (List<?>) value;
-
- Class<?> innerTypeClass = null;
-
- if (innerTypeResolvingStrategy.getOpenType() instanceof CompositeType) {
- innerTypeClass = CompositeDataSupport.class;
- } else {
- try {
- innerTypeClass = Class.forName(getOpenType().getElementOpenType().getClassName());
- } catch (ClassNotFoundException e) {
- throw new IllegalStateException("Unable to locate class for "
- + getOpenType().getElementOpenType().getClassName(), e);
- }
- }
-
- Object parsedArray = null;
-
- if (getOpenType().isPrimitiveArray()) {
- Class<?> primitiveType = getPrimitiveType(innerTypeClass);
- parsedArray = Array.newInstance(primitiveType, valueList.size());
- } else {
- parsedArray = Array.newInstance(innerTypeClass, valueList.size());
- }
-
- int i = 0;
- for (Object innerValue : valueList) {
- Optional<?> parsedElement = innerTypeResolvingStrategy.parseAttribute(attrName + "_" + i, innerValue);
- if (!parsedElement.isPresent()){
- continue;
- }
- Array.set(parsedArray, i, parsedElement.get());
- i++;
- }
-
- // Rebuild open type. Underlying composite types might have changed
- if (innerTypeResolvingStrategy.getOpenType() instanceof CompositeType) {
- try {
- final ArrayType<?> openType = new ArrayType<Object>(getOpenType().getDimension(), innerTypeResolvingStrategy.getOpenType());
- setOpenType(openType);
- } catch (OpenDataException e) {
- throw new IllegalStateException("An error occurred during restoration of array type " + this
- + " for attribute " + attrName + " from value " + value, e);
- }
- }
-
- LOG.debug("Attribute {} : {} parsed to type {} as {}", attrName, value, getOpenType(),
- toStringArray(parsedArray));
-
- return Optional.of(parsedArray);
- }
-
- private static String toStringArray(Object array) {
- StringBuilder build = new StringBuilder(array.toString());
- build.append(" [");
- for (int i = 0; i < Array.getLength(array); i++) {
- build.append(Array.get(array, i).toString());
- build.append(",");
- }
- build.append("]]");
- return build.toString();
- }
-
- private static Class<?> getPrimitiveType(Class<?> innerTypeClass) {
- try {
- return (Class<?>) innerTypeClass.getField("TYPE").get(null);
- } catch (Exception e) {
- throw new IllegalStateException("Unable to determine primitive type to " + innerTypeClass);
- }
- }
-
- @Override
- public String toString() {
- return "ResolvedArrayTypeAttributeType [innerTypeResolved=" + innerTypeResolvingStrategy + "]";
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving;
-
-import com.google.common.base.Optional;
-import javax.management.openmbean.OpenType;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-
-/**
- * Create real object from String or Map that corresponds to given opentype.
- */
-public interface AttributeResolvingStrategy<T, O extends OpenType<?>> {
- O getOpenType();
-
- Optional<T> parseAttribute(String attrName, Object value) throws NetconfDocumentedException;
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-import java.util.Map;
-import javax.management.openmbean.CompositeDataSupport;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.OpenDataException;
-import javax.management.openmbean.OpenType;
-import javax.management.openmbean.SimpleType;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-class CompositeAttributeResolvingStrategy extends
- AbstractAttributeResolvingStrategy<CompositeDataSupport, CompositeType> {
- private final Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> innerTypes;
- private final Map<String, String> yangToJavaAttrMapping;
-
- private static final Logger LOG = LoggerFactory.getLogger(CompositeAttributeResolvingStrategy.class);
-
- CompositeAttributeResolvingStrategy(Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> innerTypes,
- CompositeType openType, Map<String, String> yangToJavaAttrMapping) {
- super(openType);
- this.innerTypes = innerTypes;
- this.yangToJavaAttrMapping = yangToJavaAttrMapping;
- }
-
- @Override
- public String toString() {
- return "ResolvedCompositeAttribute [" + innerTypes + "]";
- }
-
- @Override
- public Optional<CompositeDataSupport> parseAttribute(String attrName, Object value) throws NetconfDocumentedException {
-
- if (value == null) {
- return Optional.absent();
- }
-
- Util.checkType(value, Map.class);
- Map<?, ?> valueMap = (Map<?, ?>) value;
- valueMap = preprocessValueMap(valueMap);
-
- Map<String, Object> items = Maps.newHashMap();
- Map<String, OpenType<?>> openTypes = Maps.newHashMap();
-
- final String[] names = new String[getOpenType().keySet().size()];
- final String[] descriptions = new String[getOpenType().keySet().size()];
- OpenType<?>[] itemTypes = new OpenType[names.length];
- int i = 0;
-
- for (Object innerAttrName : innerTypes.keySet()) {
- Preconditions.checkState(innerAttrName instanceof String, "Attribute name must be string");
- String innerAttrNameStr = (String) innerAttrName;
-
- AttributeResolvingStrategy<?, ? extends OpenType<?>> attributeResolvingStrategy = innerTypes
- .get(innerAttrName);
-
- Object valueToParse = valueMap.get(innerAttrName);
-
- Optional<?> parsedInnerValue = attributeResolvingStrategy.parseAttribute(innerAttrNameStr, valueToParse);
-
- if(attributeResolvingStrategy instanceof EnumAttributeResolvingStrategy) {
- // Open type for enum contain the class name necessary for its resolution, however in a DTO
- // the open type need to be just SimpleType.STRING so that JMX is happy
- // After the enum attribute is resolved, change its open type back to STRING
- openTypes.put(innerAttrNameStr, SimpleType.STRING);
- } else {
- openTypes.put(innerAttrNameStr, attributeResolvingStrategy.getOpenType());
- }
-
- items.put(yangToJavaAttrMapping.get(innerAttrNameStr),
- parsedInnerValue.isPresent() ? parsedInnerValue.get() : null);
-
- // fill names + item types in order to reconstruct the open type for current attribute
- names[i] = yangToJavaAttrMapping.get(innerAttrNameStr);
- descriptions[i] = getOpenType().getDescription(names[i]);
- itemTypes[i] = openTypes.get(innerAttrNameStr);
- i++;
- }
-
- CompositeDataSupport parsedValue;
- try {
- LOG.trace("Attribute {} with open type {}. Reconstructing open type.", attrName, getOpenType());
- setOpenType(new CompositeType(getOpenType().getTypeName(), getOpenType().getDescription(), names, descriptions, itemTypes));
- LOG.debug("Attribute {}. Open type reconstructed to {}", attrName, getOpenType(), getOpenType());
- parsedValue = new CompositeDataSupport(getOpenType(), items);
- } catch (OpenDataException e) {
- throw new IllegalStateException("An error occurred during restoration of composite type " + this
- + " for attribute " + attrName + " from value " + value, e);
- }
-
- LOG.debug("Attribute {} : {} parsed to type {} as {}", attrName, value, getOpenType(), parsedValue);
-
- return Optional.of(parsedValue);
- }
-
-
- protected Map<?, ?> preprocessValueMap(Map<?, ?> valueMap) {
- return valueMap;
- }
-
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import java.util.Map;
-import javax.management.openmbean.CompositeType;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
-import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-final class EnumAttributeResolvingStrategy extends AbstractAttributeResolvingStrategy<Object, CompositeType> {
-
- private static final Logger LOG = LoggerFactory.getLogger(EnumAttributeResolvingStrategy.class);
- private final EnumResolver enumResolver;
-
- EnumAttributeResolvingStrategy(CompositeType simpleType, final EnumResolver enumResolver) {
- super(simpleType);
- this.enumResolver = enumResolver;
- }
-
- @Override
- public String toString() {
- return "ResolvedEnumAttribute [" + getOpenType().getClassName() + "]";
- }
-
- @Override
- public Optional<Object> parseAttribute(String attrName, Object value) throws NetconfDocumentedException {
- if (value == null) {
- return Optional.absent();
- }
-
- Util.checkType(value, Map.class);
- Map<?, ?> valueMap = (Map<?, ?>) value;
- Preconditions.checkArgument(valueMap.size() == 1, "Unexpected value size " + value + " should be just 1 foe enum");
- final Object innerValue = valueMap.values().iterator().next();
- Util.checkType(innerValue, String.class);
-
- final String className = getOpenType().getTypeName();
- final Object parsedValue = enumResolver.fromYang(className, ((String) innerValue));
-
- LOG.debug("Attribute {} : {} parsed to enum type {} with value {}", attrName, innerValue, getOpenType(), parsedValue);
- return Optional.of(parsedValue);
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving;
-
-import com.google.common.base.Optional;
-import javax.management.ObjectName;
-import javax.management.openmbean.SimpleType;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.ObjectNameAttributeMappingStrategy;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ServiceRegistryWrapper;
-import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ObjectNameAttributeResolvingStrategy extends AbstractAttributeResolvingStrategy<ObjectName, SimpleType<?>> {
-
- private final ServiceRegistryWrapper serviceTracker;
- private static final Logger LOG = LoggerFactory.getLogger(ObjectNameAttributeResolvingStrategy.class);
-
- ObjectNameAttributeResolvingStrategy(ServiceRegistryWrapper serviceTracker) {
- super(SimpleType.OBJECTNAME);
- this.serviceTracker = serviceTracker;
- }
-
- @Override
- public Optional<ObjectName> parseAttribute(String attrName, Object value) {
- if (value == null) {
- return Optional.absent();
- }
-
- Util.checkType(value, ObjectNameAttributeMappingStrategy.MappedDependency.class);
-
- ObjectNameAttributeMappingStrategy.MappedDependency mappedDep = (ObjectNameAttributeMappingStrategy.MappedDependency) value;
- String serviceName = mappedDep.getServiceName();
- String refName = mappedDep.getRefName();
- String namespace = mappedDep.getNamespace();
- LOG.trace("Getting service instance by service name {} : {} and ref name {}", namespace, serviceName, refName);
-
- ObjectName on = serviceTracker.getByServiceAndRefName(namespace, serviceName, refName);
-
- LOG.debug("Attribute {} : {} parsed to type {}", attrName, value, getOpenType());
- return Optional.of(on);
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-import java.util.Map;
-import java.util.Map.Entry;
-import javax.management.openmbean.ArrayType;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.OpenType;
-import javax.management.openmbean.SimpleType;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ServiceRegistryWrapper;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
-
-public class ObjectResolver extends AttributeIfcSwitchStatement<AttributeResolvingStrategy<?, ? extends OpenType<?>>> {
-
- private final ServiceRegistryWrapper serviceTracker;
- private EnumResolver enumResolver;
-
- public ObjectResolver(ServiceRegistryWrapper serviceTracker) {
- this.serviceTracker = serviceTracker;
- }
-
- public Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> prepareResolving(
- Map<String, AttributeIfc> configDefinition, final EnumResolver enumResolver) {
- this.enumResolver = enumResolver;
-
- Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> strategies = Maps.newHashMap();
-
- for (Entry<String, AttributeIfc> attrEntry : configDefinition.entrySet()) {
- strategies.put(attrEntry.getKey(),
- prepareStrategy(attrEntry.getValue()));
- }
-
- return strategies;
- }
-
- private AttributeResolvingStrategy<?, ? extends OpenType<?>> prepareStrategy(AttributeIfc attributeIfc) {
- return switchAttribute(attributeIfc);
- }
-
- private Map<String, String> createYangToJmxMapping(TOAttribute attributeIfc) {
- Map<String, String> retVal = Maps.newHashMap();
- for (Entry<String, AttributeIfc> entry : attributeIfc.getYangPropertiesToTypesMap().entrySet()) {
- retVal.put(entry.getKey(), (entry.getValue()).getLowerCaseCammelCase());
- }
- return retVal;
- }
-
- @Override
- protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseJavaEnumAttribute(final OpenType<?> openType) {
- return new EnumAttributeResolvingStrategy((CompositeType) openType, enumResolver);
- }
-
- @Override
- protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseJavaSimpleAttribute(SimpleType<?> openType) {
- return new SimpleAttributeResolvingStrategy(openType);
- }
-
- @Override
- protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseJavaArrayAttribute(ArrayType<?> openType) {
-
- SimpleType<?> innerType = (SimpleType<?>) openType.getElementOpenType();
- AttributeResolvingStrategy<?, ? extends OpenType<?>> strat = new SimpleAttributeResolvingStrategy(innerType);
- return new ArrayAttributeResolvingStrategy(strat, openType);
- }
-
- @Override
- protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseJavaCompositeAttribute(CompositeType openType) {
- Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> innerMap = Maps.newHashMap();
- Map<String, String> yangToJmxMapping = Maps.newHashMap();
-
- fillMappingForComposite(openType, innerMap, yangToJmxMapping);
- return new CompositeAttributeResolvingStrategy(innerMap, openType, yangToJmxMapping);
- }
-
- private void fillMappingForComposite(CompositeType openType, Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> innerMap, Map<String, String> yangToJmxMapping) {
- for (String innerAttributeKey : openType.keySet()) {
- innerMap.put(innerAttributeKey, caseJavaAttribute(openType.getType(innerAttributeKey)));
- yangToJmxMapping.put(innerAttributeKey, innerAttributeKey);
- }
- }
-
- @Override
- protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseJavaUnionAttribute(OpenType<?> openType) {
-
- Preconditions.checkState(openType instanceof CompositeType, "Unexpected open type, expected %s but was %s");
- CompositeType compositeType = (CompositeType) openType;
-
- Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> innerMap = Maps.newHashMap();
- Map<String, String> yangToJmxMapping = Maps.newHashMap();
- fillMappingForComposite(compositeType, innerMap, yangToJmxMapping);
-
- return new UnionCompositeAttributeResolvingStrategy(innerMap, compositeType, yangToJmxMapping);
- }
-
- @Override
- protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseDependencyAttribute(
- SimpleType<?> openType) {
- return new ObjectNameAttributeResolvingStrategy(serviceTracker);
- }
-
- @Override
- protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseTOAttribute(CompositeType openType) {
- Preconditions.checkState(getLastAttribute() instanceof TOAttribute);
- TOAttribute toAttribute = (TOAttribute) getLastAttribute();
-
- Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> innerMap = Maps.newHashMap();
-
- for (String innerName : openType.keySet()) {
-
- AttributeIfc innerAttributeIfc = toAttribute.getJmxPropertiesToTypesMap().get(innerName);
- innerMap.put(innerAttributeIfc.getAttributeYangName(),
- prepareStrategy(innerAttributeIfc));
- }
- return new CompositeAttributeResolvingStrategy(innerMap, openType, createYangToJmxMapping(toAttribute));
- }
-
- @Override
- protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseListAttribute(ArrayType<?> openType) {
- Preconditions.checkState(getLastAttribute() instanceof ListAttribute);
- AttributeIfc innerAttribute = ((ListAttribute) getLastAttribute()).getInnerAttribute();
- return new ArrayAttributeResolvingStrategy(prepareStrategy(innerAttribute), openType);
- }
-
- @Override
- protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseListDependeciesAttribute(ArrayType<?> openType) {
- Preconditions.checkState(getLastAttribute() instanceof ListDependenciesAttribute);
- return new ArrayAttributeResolvingStrategy(caseDependencyAttribute(SimpleType.OBJECTNAME), openType);
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving;
-
-import com.google.common.base.Optional;
-import com.google.common.collect.Maps;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.text.ParseException;
-import java.util.Date;
-import java.util.Map;
-import javax.management.openmbean.SimpleType;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-final class SimpleAttributeResolvingStrategy extends AbstractAttributeResolvingStrategy<Object, SimpleType<?>> {
-
- private static final Logger LOG = LoggerFactory.getLogger(SimpleAttributeResolvingStrategy.class);
-
- SimpleAttributeResolvingStrategy(SimpleType<?> simpleType) {
- super(simpleType);
- }
-
- @Override
- public String toString() {
- return "ResolvedSimpleAttribute [" + getOpenType().getClassName() + "]";
- }
-
- @Override
- public Optional<Object> parseAttribute(String attrName, Object value) throws NetconfDocumentedException {
- if (value == null) {
- return Optional.absent();
- }
-
- Class<?> cls;
- try {
- cls = Class.forName(getOpenType().getClassName());
- } catch (ClassNotFoundException e) {
- throw new RuntimeException("Unable to locate class for " + getOpenType().getClassName(), e);
- }
-
- Util.checkType(value, String.class);
-
- Resolver prefferedPlugin = resolverPlugins.get(cls.getCanonicalName());
- prefferedPlugin = prefferedPlugin == null ? resolverPlugins.get(DEFAULT_RESOLVERS) : prefferedPlugin;
-
- Object parsedValue = prefferedPlugin.resolveObject(cls, attrName, (String) value);
- LOG.debug("Attribute {} : {} parsed to type {} with value {}", attrName, value, getOpenType(), parsedValue);
- return Optional.of(parsedValue);
- }
-
- private static final String DEFAULT_RESOLVERS = "default";
- private static final Map<String, Resolver> resolverPlugins = Maps.newHashMap();
-
- static {
- resolverPlugins.put(DEFAULT_RESOLVERS, new DefaultResolver());
- resolverPlugins.put(String.class.getCanonicalName(), new StringResolver());
- resolverPlugins.put(Date.class.getCanonicalName(), new DateResolver());
- resolverPlugins.put(Character.class.getCanonicalName(), new CharResolver());
- resolverPlugins.put(BigInteger.class.getCanonicalName(), new BigIntegerResolver());
- resolverPlugins.put(BigDecimal.class.getCanonicalName(), new BigDecimalResolver());
- }
-
- static interface Resolver {
- Object resolveObject(Class<?> type, String attrName, String value) throws NetconfDocumentedException;
- }
-
- static class DefaultResolver implements Resolver {
-
- @Override
- public Object resolveObject(Class<?> type, String attrName, String value) throws NetconfDocumentedException {
- try {
- return parseObject(type, value);
- } catch (Exception e) {
- throw new NetconfDocumentedException("Unable to resolve attribute " + attrName + " from " + value,
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_failed,
- NetconfDocumentedException.ErrorSeverity.error);
- }
- }
-
- protected Object parseObject(Class<?> type, String value) throws NetconfDocumentedException {
- Method method = null;
- try {
- method = type.getMethod("valueOf", String.class);
- return method.invoke(null, value);
- } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
- LOG.trace("Error parsing object ",e);
- throw new NetconfDocumentedException("Error parsing object.",
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_failed,
- NetconfDocumentedException.ErrorSeverity.error);
- }
- }
- }
-
- static class StringResolver extends DefaultResolver {
-
- @Override
- protected Object parseObject(Class<?> type, String value) {
- return value;
- }
- }
-
- static class BigIntegerResolver extends DefaultResolver {
-
- @Override
- protected Object parseObject(Class<?> type, String value) {
- return new BigInteger(value);
- }
- }
-
- static class BigDecimalResolver extends DefaultResolver {
-
- @Override
- protected Object parseObject(Class<?> type, String value) {
- return new BigDecimal(value);
- }
- }
-
- static class CharResolver extends DefaultResolver {
-
- @Override
- protected Object parseObject(Class<?> type, String value) {
- return value.charAt(0);
- }
- }
-
- static class DateResolver extends DefaultResolver {
- @Override
- protected Object parseObject(Class<?> type, String value) throws NetconfDocumentedException {
- try {
- return Util.readDate(value);
- } catch (ParseException e) {
- LOG.trace("Unable parse value {} due to ",value, e);
- throw new NetconfDocumentedException("Unable to parse value "+value+" as date.",
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_failed,
- NetconfDocumentedException.ErrorSeverity.error);
- }
- }
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-import java.util.Map;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.OpenType;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
-
-final class UnionCompositeAttributeResolvingStrategy extends CompositeAttributeResolvingStrategy {
-
- UnionCompositeAttributeResolvingStrategy(Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> innerTypes,
- CompositeType openType, Map<String, String> yangToJavaAttrMapping) {
- super(innerTypes, openType, yangToJavaAttrMapping);
- }
-
- protected Map<String, Object> preprocessValueMap(Map<?, ?> valueMap) {
- CompositeType openType = getOpenType();
-
- Preconditions.checkArgument(
- valueMap.size() == 1 && valueMap.containsKey(JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION),
- "Unexpected structure of incoming map, expecting one element under %s, but was %s",
- JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION, valueMap);
-
- Map<String, Object> newMap = Maps.newHashMap();
-
- for (String key : openType.keySet()) {
- if (openType.getDescription(key).equals(JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION)){
- newMap.put(key, valueMap.get(JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION));
- } else {
- newMap.put(key, null);
- }
- }
- return newMap;
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.toxml;
-
-import java.util.List;
-import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
-import org.w3c.dom.Element;
-
-public class ArrayAttributeWritingStrategy implements AttributeWritingStrategy {
-
- private final AttributeWritingStrategy innnerStrategy;
-
- public ArrayAttributeWritingStrategy(AttributeWritingStrategy innerStrategy) {
- this.innnerStrategy = innerStrategy;
- }
-
- @Override
- public void writeElement(Element parentElement, String namespace, Object value) {
- Util.checkType(value, List.class);
-
- for (Object innerObject : ((List<?>) value)) {
- innnerStrategy.writeElement(parentElement, namespace, innerObject);
- }
-
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.toxml;
-
-import org.w3c.dom.Element;
-
-public interface AttributeWritingStrategy {
-
- void writeElement(Element parentElement, String namespace, Object value);
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.toxml;
-
-import com.google.common.base.Optional;
-import java.util.Map;
-import java.util.Map.Entry;
-import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-public class CompositeAttributeWritingStrategy implements AttributeWritingStrategy {
-
- private final String key;
- private final Document document;
- private final Map<String, AttributeWritingStrategy> innerStrats;
-
- public CompositeAttributeWritingStrategy(Document document, String key,
- Map<String, AttributeWritingStrategy> innerStrats) {
- this.document = document;
- this.key = key;
- this.innerStrats = innerStrats;
- }
-
- @Override
- public void writeElement(Element parentElement, String namespace, Object value) {
- Util.checkType(value, Map.class);
-
- Element innerNode = XmlUtil.createElement(document, key, Optional.of(namespace));
-
- Map<?, ?> map = (Map<?, ?>) value;
-
- for (Entry<?, ?> innerObjectEntry : map.entrySet()) {
- Util.checkType(innerObjectEntry.getKey(), String.class);
-
- String innerKey = (String) innerObjectEntry.getKey();
- Object innerValue = innerObjectEntry.getValue();
-
- innerStrats.get(innerKey).writeElement(innerNode, namespace, innerValue);
- }
- parentElement.appendChild(innerNode);
- }
-
- public String getKey() {
- return key;
- }
-
- public Document getDocument() {
- return document;
- }
-
- public Map<String, AttributeWritingStrategy> getInnerStrats() {
- return innerStrats;
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.toxml;
-
-import com.google.common.base.Optional;
-import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.ObjectNameAttributeMappingStrategy;
-import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-public class ObjectNameAttributeWritingStrategy implements AttributeWritingStrategy {
-
- private final Document document;
- private final String key;
-
- /**
- * @param document
- * @param key
- */
- public ObjectNameAttributeWritingStrategy(Document document, String key) {
- this.document = document;
- this.key = key;
- }
-
- @Override
- public void writeElement(Element parentElement, String namespace, Object value) {
- Util.checkType(value, ObjectNameAttributeMappingStrategy.MappedDependency.class);
- Element innerNode = XmlUtil.createElement(document, key, Optional.of(namespace));
-
- String moduleName = ((ObjectNameAttributeMappingStrategy.MappedDependency) value).getServiceName();
- String refName = ((ObjectNameAttributeMappingStrategy.MappedDependency) value).getRefName();
- String namespaceForType = ((ObjectNameAttributeMappingStrategy.MappedDependency) value).getNamespace();
-
- Element typeElement = XmlUtil.createTextElementWithNamespacedContent(document, XmlNetconfConstants.TYPE_KEY, XmlNetconfConstants.PREFIX,
- namespaceForType, moduleName);
-
- innerNode.appendChild(typeElement);
-
- final Element nameElement = XmlUtil.createTextElement(document, XmlNetconfConstants.NAME_KEY, refName, Optional.<String>absent());
- innerNode.appendChild(nameElement);
-
- parentElement.appendChild(innerNode);
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.toxml;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-import java.util.Map;
-import java.util.Map.Entry;
-import javax.management.openmbean.ArrayType;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.OpenType;
-import javax.management.openmbean.SimpleType;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
-import org.w3c.dom.Document;
-
-public class ObjectXmlWriter extends AttributeIfcSwitchStatement<AttributeWritingStrategy> {
-
- private Document document;
- private String key;
-
- public Map<String, AttributeWritingStrategy> prepareWriting(Map<String, AttributeIfc> yangToAttrConfig,
- Document document) {
-
- Map<String, AttributeWritingStrategy> preparedWriting = Maps.newHashMap();
-
- for (Entry<String, AttributeIfc> mappedAttributeEntry : yangToAttrConfig.entrySet()) {
- String key = mappedAttributeEntry.getKey();
- AttributeIfc value = mappedAttributeEntry.getValue();
- AttributeWritingStrategy strat = prepareWritingStrategy(key, value, document);
- preparedWriting.put(key, strat);
- }
-
- return preparedWriting;
- }
-
- public AttributeWritingStrategy prepareWritingStrategy(String key, AttributeIfc expectedAttr, Document document) {
- Preconditions.checkNotNull(expectedAttr, "Mbean attributes mismatch, unable to find expected attribute for %s",
- key);
- this.document = document;
- this.key = key;
- return switchAttribute(expectedAttr);
- }
-
- @Override
- protected AttributeWritingStrategy caseJavaBinaryAttribute(OpenType<?> openType) {
- return new SimpleBinaryAttributeWritingStrategy(document, key);
- }
-
- @Override
- protected AttributeWritingStrategy caseJavaEnumAttribute(final OpenType<?> openType) {
- return new SimpleAttributeWritingStrategy(document, key);
- }
-
- @Override
- protected AttributeWritingStrategy caseJavaSimpleAttribute(SimpleType<?> openType) {
- return new SimpleAttributeWritingStrategy(document, key);
- }
-
- @Override
- protected AttributeWritingStrategy caseJavaArrayAttribute(ArrayType<?> openType) {
- AttributeWritingStrategy innerStrategy = new SimpleAttributeWritingStrategy(document, key);
- return new ArrayAttributeWritingStrategy(innerStrategy);
- }
-
- @Override
- protected AttributeWritingStrategy caseJavaIdentityRefAttribute(OpenType<?> openType) {
- return new SimpleIdentityRefAttributeWritingStrategy(document, key);
- }
-
- @Override
- protected AttributeWritingStrategy caseJavaCompositeAttribute(CompositeType openType) {
- return new SimpleCompositeAttributeWritingStrategy(document, key);
- }
-
- @Override
- protected AttributeWritingStrategy caseJavaUnionAttribute(OpenType<?> openType) {
- return new SimpleUnionAttributeWritingStrategy(document, key);
- }
-
- @Override
- protected AttributeWritingStrategy caseDependencyAttribute(SimpleType<?> openType) {
- return new ObjectNameAttributeWritingStrategy(document, key);
- }
-
- @Override
- protected AttributeWritingStrategy caseTOAttribute(CompositeType openType) {
- Preconditions.checkState(getLastAttribute() instanceof TOAttribute);
-
- Map<String, AttributeWritingStrategy> innerStrats = Maps.newHashMap();
- String currentKey = key;
- for (Entry<String, AttributeIfc> innerAttrEntry : ((TOAttribute) getLastAttribute()).getYangPropertiesToTypesMap().entrySet()) {
-
- AttributeWritingStrategy innerStrategy = prepareWritingStrategy(innerAttrEntry.getKey(),
- innerAttrEntry.getValue(), document);
- innerStrats.put(innerAttrEntry.getKey(), innerStrategy);
- }
-
- return new CompositeAttributeWritingStrategy(document, currentKey, innerStrats);
- }
-
- @Override
- protected AttributeWritingStrategy caseListAttribute(ArrayType<?> openType) {
- Preconditions.checkState(getLastAttribute() instanceof ListAttribute);
- AttributeIfc innerAttribute = ((ListAttribute) getLastAttribute()).getInnerAttribute();
-
- AttributeWritingStrategy innerStrategy = prepareWritingStrategy(key, innerAttribute, document);
- return new ArrayAttributeWritingStrategy(innerStrategy);
- }
-
- @Override
- protected AttributeWritingStrategy caseListDependeciesAttribute(ArrayType<?> openType) {
- Preconditions.checkState(getLastAttribute() instanceof ListDependenciesAttribute);
- AttributeWritingStrategy innerStrategy = caseDependencyAttribute(SimpleType.OBJECTNAME);
- return new ArrayAttributeWritingStrategy(innerStrategy);
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.toxml;
-
-import com.google.common.base.Optional;
-import java.util.Map;
-import java.util.Map.Entry;
-import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-public class RuntimeBeanEntryWritingStrategy extends CompositeAttributeWritingStrategy {
-
- public RuntimeBeanEntryWritingStrategy(Document document, String key,
- Map<String, AttributeWritingStrategy> innerStrats) {
- super(document, key, innerStrats);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.opendaylight.controller.config.netconf.mapping.attributes.toxml.
- * AttributeWritingStrategy#writeElement(org.w3c.dom.Element,
- * java.lang.Object)
- */
- @Override
- public void writeElement(Element parentElement, String namespace, Object value) {
- Util.checkType(value, Map.class);
-
- Element innerNode = XmlUtil.createElement(getDocument(), getKey(), Optional.<String>absent());
-
- Map<?, ?> map = (Map<?, ?>) value;
-
- for (Entry<?, ?> runtimeBeanInstanceMappingEntry : map.entrySet()) {
-
- // wrap runtime attributes with number assigned to current runtime
- // bean
- Util.checkType(runtimeBeanInstanceMappingEntry.getValue(), Map.class);
- Map<?, ?> innerMap = (Map<?, ?>) runtimeBeanInstanceMappingEntry.getValue();
- Element runtimeInstanceNode = XmlUtil.createElement(getDocument(), "_"
- + runtimeBeanInstanceMappingEntry.getKey(), Optional.<String>absent());
- innerNode.appendChild(runtimeInstanceNode);
-
- for (Entry<?, ?> innerObjectEntry : innerMap.entrySet()) {
-
- Util.checkType(innerObjectEntry.getKey(), String.class);
-
- String innerKey = (String) innerObjectEntry.getKey();
- Object innerValue = innerObjectEntry.getValue();
-
- getInnerStrats().get(innerKey).writeElement(runtimeInstanceNode, namespace, innerValue);
- }
- }
- parentElement.appendChild(innerNode);
-
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.toxml;
-
-import com.google.common.base.Optional;
-import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-public class SimpleAttributeWritingStrategy implements AttributeWritingStrategy {
-
- private final Document document;
- private final String key;
-
- /**
- * @param document
- * @param key
- */
- public SimpleAttributeWritingStrategy(Document document, String key) {
- this.document = document;
- this.key = key;
- }
-
- @Override
- public void writeElement(Element parentElement, String namespace, Object value) {
- value = preprocess(value);
- Util.checkType(value, String.class);
- Element innerNode = createElement(document, key, (String) value, Optional.of(namespace));
- parentElement.appendChild(innerNode);
- }
-
- protected Element createElement(Document document, String key, String value, Optional<String> namespace) {
- Element typeElement = XmlUtil.createElement(document, key, namespace);
-
- typeElement.appendChild(document.createTextNode(value));
- return typeElement;
- }
- protected Object preprocess(Object value) {
- return value;
- }
-
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.toxml;
-
-import com.google.common.base.Preconditions;
-import com.google.common.io.BaseEncoding;
-import java.util.List;
-import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
-import org.w3c.dom.Document;
-
-public class SimpleBinaryAttributeWritingStrategy extends SimpleAttributeWritingStrategy {
-
- /**
- * @param document
- * @param key
- */
- public SimpleBinaryAttributeWritingStrategy(Document document, String key) {
- super(document, key);
- }
-
- @Override
- protected Object preprocess(Object value) {
- Util.checkType(value, List.class);
- BaseEncoding en = BaseEncoding.base64();
-
- List<?> list = (List<?>) value;
- byte[] decoded = new byte[list.size()];
- int i = 0;
- for (Object bAsStr : list) {
- Preconditions.checkArgument(bAsStr instanceof String, "Unexpected inner value for %s, expected string", value);
- byte b = Byte.parseByte((String) bAsStr);
- decoded[i++] = b;
- }
-
- return en.encode(decoded);
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.toxml;
-
-import com.google.common.base.Preconditions;
-import java.util.Map;
-import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
-import org.w3c.dom.Document;
-
-public class SimpleCompositeAttributeWritingStrategy extends SimpleAttributeWritingStrategy {
-
- /**
- * @param document
- * @param key
- */
- public SimpleCompositeAttributeWritingStrategy(Document document, String key) {
- super(document, key);
- }
-
- protected Object preprocess(Object value) {
- Util.checkType(value, Map.class);
- Preconditions.checkArgument(((Map<?, ?>)value).size() == 1, "Unexpected number of values in %s, expected 1", value);
- return ((Map<?, ?>)value).values().iterator().next();
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.toxml;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import java.util.Map;
-import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-public class SimpleIdentityRefAttributeWritingStrategy extends SimpleAttributeWritingStrategy {
-
- private static final String PREFIX = "prefix";
-
- /**
- * @param document
- * @param key
- */
- public SimpleIdentityRefAttributeWritingStrategy(Document document, String key) {
- super(document, key);
- }
-
- protected Object preprocess(Object value) {
- Util.checkType(value, Map.class);
- Preconditions.checkArgument(((Map<?, ?>)value).size() == 1, "Unexpected number of values in %s, expected 1", value);
- Object stringValue = ((Map<?, ?>) value).values().iterator().next();
- Util.checkType(stringValue, String.class);
-
- return stringValue;
- }
-
- @Override
- protected Element createElement(Document doc, String key, String value, Optional<String> namespace) {
- QName qName = QName.create(value);
- String identityValue = qName.getLocalName();
- String identityNamespace = qName.getNamespace().toString();
- return XmlUtil.createTextElementWithNamespacedContent(doc, key, PREFIX, identityNamespace, identityValue, namespace);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.toxml;
-
-import com.google.common.base.Preconditions;
-import java.util.List;
-import java.util.Map;
-import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
-import org.w3c.dom.Document;
-
-public class SimpleUnionAttributeWritingStrategy extends SimpleAttributeWritingStrategy {
-
- /**
- * @param document
- * @param key
- */
- public SimpleUnionAttributeWritingStrategy(Document document, String key) {
- super(document, key);
- }
-
- protected Object preprocess(Object value) {
- Util.checkType(value, Map.class);
- Preconditions.checkArgument(((Map<?, ?>)value).size() == 1, "Unexpected number of values in %s, expected 1", value);
- Object listOfStrings = ((Map<?, ?>) value).values().iterator().next();
- Util.checkType(listOfStrings, List.class);
-
- StringBuilder b = new StringBuilder();
- for (Object character: (List<?>)listOfStrings) {
- Util.checkType(character, String.class);
- b.append(character);
- }
-
- return b.toString();
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config;
-
-import static com.google.common.base.Preconditions.checkState;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Multimap;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import javax.management.ObjectName;
-import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-
-public class Config {
-
- private final Map<String/* Namespace from yang file */,
- Map<String /* Name of module entry from yang file */, ModuleConfig>> moduleConfigs;
-
- private final Map<String, Map<Date, EditConfig.IdentityMapping>> identityMap;
-
- private final EnumResolver enumResolver;
-
- public Config(Map<String, Map<String, ModuleConfig>> moduleConfigs, final EnumResolver enumResolver) {
- this(moduleConfigs, Collections.<String, Map<Date, EditConfig.IdentityMapping>>emptyMap(), enumResolver);
- }
-
- public Config(Map<String, Map<String, ModuleConfig>> moduleConfigs, Map<String, Map<Date, EditConfig.IdentityMapping>> identityMap, final EnumResolver enumResolver) {
- this.moduleConfigs = moduleConfigs;
- this.identityMap = identityMap;
- this.enumResolver = enumResolver;
- }
-
- public static Map<String, Map<String, Collection<ObjectName>>> getMappedInstances(Set<ObjectName> instancesToMap,
- Map<String, Map<String, ModuleConfig>> configs) {
- Multimap<String, ObjectName> moduleToInstances = mapInstancesToModules(instancesToMap);
-
- Map<String, Map<String, Collection<ObjectName>>> retVal = Maps.newLinkedHashMap();
-
- for (Entry<String, Map<String, ModuleConfig>> namespaceToModuleToConfigEntry : configs.entrySet()) {
-
- Map<String, Collection<ObjectName>> innerRetVal = Maps.newHashMap();
-
- for (Entry<String, ModuleConfig> mbeEntry : namespaceToModuleToConfigEntry.getValue().entrySet()) {
-
- String moduleName = mbeEntry.getKey();
- Collection<ObjectName> instances = moduleToInstances.get(moduleName);
-
- // TODO, this code does not support same module names from different namespaces
- // Namespace should be present in ObjectName
-
- if (instances == null){
- continue;
- }
-
- innerRetVal.put(moduleName, instances);
-
- }
-
- retVal.put(namespaceToModuleToConfigEntry.getKey(), innerRetVal);
- }
- return retVal;
- }
-
- private static Multimap<String, ObjectName> mapInstancesToModules(Set<ObjectName> instancesToMap) {
- Multimap<String, ObjectName> retVal = HashMultimap.create();
-
- for (ObjectName objectName : instancesToMap) {
- String factoryName = ObjectNameUtil.getFactoryName(objectName);
- retVal.put(factoryName, objectName);
- }
- return retVal;
- }
-
- public Element toXml(Set<ObjectName> instancesToMap, Optional<String> maybeNamespace, Document document,
- Element dataElement, ServiceRegistryWrapper serviceTracker) {
-
- Map<String, Map<String, Collection<ObjectName>>> moduleToInstances = getMappedInstances(instancesToMap,
- moduleConfigs);
-
- if (maybeNamespace.isPresent()) {
- dataElement.setAttributeNS(maybeNamespace.get(), dataElement.getNodeName(), "xmlns");
- }
-
- Element modulesElement = XmlUtil.createElement(document, XmlNetconfConstants.MODULES_KEY, Optional.of(XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG));
- dataElement.appendChild(modulesElement);
- for (Entry<String, Map<String, Collection<ObjectName>>> moduleToInstanceEntry : moduleToInstances.entrySet()) {
- for (Entry<String, Collection<ObjectName>> moduleMappingEntry : moduleToInstanceEntry.getValue()
- .entrySet()) {
-
- ModuleConfig mapping = moduleConfigs.get(moduleToInstanceEntry.getKey()).get(moduleMappingEntry.getKey());
-
- if (moduleMappingEntry.getValue().isEmpty()) {
- continue;
- }
-
- for (ObjectName objectName : moduleMappingEntry.getValue()) {
- modulesElement.appendChild(mapping.toXml(objectName, document, moduleToInstanceEntry.getKey(), enumResolver));
- }
-
- }
- }
-
- dataElement.appendChild(Services.toXml(serviceTracker, document));
-
- return dataElement;
- }
-
- // TODO refactor, replace string representing namespace with namespace class
- // TODO refactor, replace Map->Multimap with e.g. ConfigElementResolved
- // class
-
- public Map<String, Multimap<String, ModuleElementResolved>> fromXmlModulesResolved(XmlElement xml, EditStrategyType defaultEditStrategyType, ServiceRegistryWrapper serviceTracker) throws NetconfDocumentedException {
- Optional<XmlElement> modulesElement = getModulesElement(xml);
- List<XmlElement> moduleElements = getModulesElementList(modulesElement);
-
- Map<String, Multimap<String, ModuleElementResolved>> retVal = Maps.newHashMap();
-
- for (XmlElement moduleElement : moduleElements) {
- ResolvingStrategy<ModuleElementResolved> resolvingStrategy = new ResolvingStrategy<ModuleElementResolved>() {
- @Override
- public ModuleElementResolved resolveElement(ModuleConfig moduleMapping, XmlElement moduleElement, ServiceRegistryWrapper serviceTracker, String instanceName, String moduleNamespace, EditStrategyType defaultStrategy) throws NetconfDocumentedException {
- return moduleMapping.fromXml(moduleElement, serviceTracker,
- instanceName, moduleNamespace, defaultStrategy, identityMap, enumResolver);
- }
- };
-
- resolveModule(retVal, serviceTracker, moduleElement, defaultEditStrategyType, resolvingStrategy);
- }
- return retVal;
- }
-
- /**
- * return a map containing namespace -> moduleName -> instanceName map. Attribute parsing is omitted.
- */
- public Map<String, Multimap<String, ModuleElementDefinition>> fromXmlModulesMap(XmlElement xml,
- EditStrategyType defaultEditStrategyType, ServiceRegistryWrapper serviceTracker) throws NetconfDocumentedException {
- Optional<XmlElement> modulesElement = getModulesElement(xml);
- List<XmlElement> moduleElements = getModulesElementList(modulesElement);
-
- Map<String, Multimap<String, ModuleElementDefinition>> retVal = Maps.newHashMap();
-
- for (XmlElement moduleElement : moduleElements) {
- ResolvingStrategy<ModuleElementDefinition> resolvingStrategy = new ResolvingStrategy<ModuleElementDefinition>() {
- @Override
- public ModuleElementDefinition resolveElement(ModuleConfig moduleMapping, XmlElement moduleElement,
- ServiceRegistryWrapper serviceTracker, String instanceName, String moduleNamespace,
- EditStrategyType defaultStrategy) {
- // 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);
- return new ModuleElementDefinition(instanceName, perInstanceEditStrategy, defaultStrategy);
- }
- };
-
- resolveModule(retVal, serviceTracker, moduleElement, defaultEditStrategyType, resolvingStrategy);
- }
- return retVal;
- }
-
- private static Optional<XmlElement> getModulesElement(XmlElement xml) {
- return xml.getOnlyChildElementOptionally(XmlNetconfConstants.MODULES_KEY,
- XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
- }
-
- private List<XmlElement> getModulesElementList(Optional<XmlElement> modulesElement) throws NetconfDocumentedException {
- List<XmlElement> moduleElements;
-
- if (modulesElement.isPresent()) {
- moduleElements = modulesElement.get().getChildElementsWithSameNamespace(XmlNetconfConstants.MODULE_KEY);
- modulesElement.get().checkUnrecognisedElements(moduleElements);
- } else {
- moduleElements = Lists.newArrayList();
- }
- return moduleElements;
- }
-
- private <T> void resolveModule(Map<String, Multimap<String, T>> retVal, ServiceRegistryWrapper serviceTracker,
- XmlElement moduleElement, EditStrategyType defaultStrategy, ResolvingStrategy<T> resolvingStrategy) throws NetconfDocumentedException {
- XmlElement typeElement = null;
- typeElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.TYPE_KEY);
- Entry<String, String> prefixToNamespace = typeElement.findNamespaceOfTextContent();
- String moduleNamespace = prefixToNamespace.getValue();
- XmlElement nameElement = null;
- nameElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.NAME_KEY);
- String instanceName = nameElement.getTextContent();
- String factoryNameWithPrefix = typeElement.getTextContent();
- String prefixOrEmptyString = prefixToNamespace.getKey();
- String factoryName = getFactoryName(factoryNameWithPrefix, prefixOrEmptyString);
-
- ModuleConfig moduleMapping = getModuleMapping(moduleNamespace, instanceName, factoryName);
-
- Multimap<String, T> innerMap = retVal.get(moduleNamespace);
- if (innerMap == null) {
- innerMap = HashMultimap.create();
- retVal.put(moduleNamespace, innerMap);
- }
-
- T resolvedElement = resolvingStrategy.resolveElement(moduleMapping, moduleElement, serviceTracker,
- instanceName, moduleNamespace, defaultStrategy);
-
- innerMap.put(factoryName, resolvedElement);
- }
-
- public Services fromXmlServices(XmlElement xml) throws NetconfDocumentedException {
- Optional<XmlElement> servicesElement = getServicesElement(xml);
-
- Services services;
- if (servicesElement.isPresent()) {
- services = Services.fromXml(servicesElement.get());
- } else {
- services = new Services();
- }
-
- return services;
- }
-
- private static Optional<XmlElement> getServicesElement(XmlElement xml) {
- return xml.getOnlyChildElementOptionally(XmlNetconfConstants.SERVICES_KEY,
- XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
- }
-
- public static void checkUnrecognisedChildren(XmlElement parent) throws NetconfDocumentedException {
- Optional<XmlElement> servicesOpt = getServicesElement(parent);
- Optional<XmlElement> modulesOpt = getModulesElement(parent);
-
- List<XmlElement> recognised = Lists.newArrayList();
- if(servicesOpt.isPresent()){
- recognised.add(servicesOpt.get());
- }
- if(modulesOpt.isPresent()){
- recognised.add(modulesOpt.get());
- }
-
- parent.checkUnrecognisedElements(recognised);
- }
-
- private String getFactoryName(String factoryNameWithPrefix, String prefixOrEmptyString) {
- checkState(
- factoryNameWithPrefix.startsWith(prefixOrEmptyString),
- String.format("Internal error: text " + "content '%s' of type node does not start with prefix '%s'",
- factoryNameWithPrefix, prefixOrEmptyString));
-
- int factoryNameAfterPrefixIndex;
- if (prefixOrEmptyString.isEmpty()) {
- factoryNameAfterPrefixIndex = 0;
- } else {
- factoryNameAfterPrefixIndex = prefixOrEmptyString.length() + 1;
- }
- return factoryNameWithPrefix.substring(factoryNameAfterPrefixIndex);
- }
-
- private ModuleConfig getModuleMapping(String moduleNamespace, String instanceName, String factoryName) {
- Map<String, ModuleConfig> mappingsFromNamespace = moduleConfigs.get(moduleNamespace);
-
- Preconditions.checkNotNull(mappingsFromNamespace,
- "Namespace %s, defined in: module %s of type %s not found, available namespaces: %s", moduleNamespace,
- instanceName, factoryName, moduleConfigs.keySet());
-
- ModuleConfig moduleMapping = mappingsFromNamespace.get(factoryName);
- checkState(moduleMapping != null, "Cannot find mapping for module type " + factoryName);
- return moduleMapping;
- }
-
- private interface ResolvingStrategy<T> {
- public T resolveElement(ModuleConfig moduleMapping, XmlElement moduleElement, ServiceRegistryWrapper serviceTracker,
- String instanceName, String moduleNamespace, EditStrategyType defaultStrategy) throws NetconfDocumentedException;
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config;
-
-import com.google.common.base.Optional;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import javax.management.ObjectName;
-import javax.management.openmbean.OpenType;
-import org.opendaylight.controller.config.util.BeanReader;
-import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeReadingStrategy;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.ObjectXmlReader;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.AttributeMappingStrategy;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.ObjectMapper;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving.AttributeResolvingStrategy;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving.ObjectResolver;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.toxml.AttributeWritingStrategy;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.toxml.ObjectXmlWriter;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-public final class InstanceConfig {
- private static final Logger LOG = LoggerFactory.getLogger(InstanceConfig.class);
-
- private final Map<String, AttributeIfc> yangToAttrConfig;
- private final String nullableDummyContainerName;
- private final Map<String, AttributeIfc> jmxToAttrConfig;
- private final BeanReader configRegistryClient;
-
- public InstanceConfig(BeanReader configRegistryClient, Map<String, AttributeIfc> yangNamesToAttributes,
- String nullableDummyContainerName) {
-
- this.yangToAttrConfig = yangNamesToAttributes;
- this.nullableDummyContainerName = nullableDummyContainerName;
- this.jmxToAttrConfig = reverseMap(yangNamesToAttributes);
- this.configRegistryClient = configRegistryClient;
- }
-
- private Map<String, Object> getMappedConfiguration(ObjectName on, final EnumResolver enumResolver) {
-
- // TODO make field, mappingStrategies can be instantiated only once
- Map<String, AttributeMappingStrategy<?, ? extends OpenType<?>>> mappingStrategies = new ObjectMapper()
- .prepareMapping(jmxToAttrConfig, enumResolver);
-
- Map<String, Object> toXml = Maps.newHashMap();
-
- for (Entry<String, AttributeIfc> configDefEntry : jmxToAttrConfig.entrySet()) {
- // Skip children runtime beans as they are mapped by InstanceRuntime
- if (configDefEntry.getValue() instanceof RuntimeBeanEntry){
- continue;
- }
- Object value = configRegistryClient.getAttributeCurrentValue(on, configDefEntry.getKey());
- try {
- AttributeMappingStrategy<?, ? extends OpenType<?>> attributeMappingStrategy = mappingStrategies
- .get(configDefEntry.getKey());
- Optional<?> a = attributeMappingStrategy.mapAttribute(value);
- if (!a.isPresent()){
- continue;
- }
- toXml.put(configDefEntry.getValue().getAttributeYangName(), a.get());
- } catch (Exception e) {
- throw new IllegalStateException("Unable to map value " + value + " to attribute "
- + configDefEntry.getKey(), e);
- }
- }
- return toXml;
- }
-
- public Element toXml(ObjectName on, String namespace, Document document, Element rootElement, final EnumResolver enumResolver) {
- Map<String, AttributeWritingStrategy> strats = new ObjectXmlWriter().prepareWriting(yangToAttrConfig, document);
- Map<String, Object> mappedConfig = getMappedConfiguration(on, enumResolver);
- 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(parentElement, namespace, mappingEntry.getValue());
- } catch (Exception e) {
- throw new IllegalStateException("Unable to write value " + mappingEntry.getValue() + " for attribute "
- + mappingEntry.getValue(), e);
- }
- }
- return rootElement;
- }
-
- private void resolveConfiguration(InstanceConfigElementResolved mappedConfig, ServiceRegistryWrapper depTracker, final EnumResolver enumResolver) {
-
- // TODO make field, resolvingStrategies can be instantiated only once
- Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> resolvingStrategies = new ObjectResolver(
- depTracker).prepareResolving(yangToAttrConfig, enumResolver);
-
- for (Entry<String, AttributeConfigElement> configDefEntry : mappedConfig.getConfiguration().entrySet()) {
- AttributeConfigElement value = configDefEntry.getValue();
- String attributeName = configDefEntry.getKey();
- try {
- AttributeResolvingStrategy<?, ? extends OpenType<?>> attributeResolvingStrategy = resolvingStrategies
- .get(attributeName);
- LOG.trace("Trying to set value {} of attribute {} with {}", value, attributeName, attributeResolvingStrategy);
-
- value.resolveValue(attributeResolvingStrategy, attributeName);
- value.setJmxName(
- yangToAttrConfig.get(attributeName).getUpperCaseCammelCase());
- } catch (Exception e) {
- throw new IllegalStateException("Unable to resolve value " + value
- + " to attribute " + attributeName, e);
- }
- }
- }
-
- public InstanceConfigElementResolved fromXml(XmlElement moduleElement, ServiceRegistryWrapper services, String moduleNamespace,
- EditStrategyType defaultStrategy,
- Map<String, Map<Date, EditConfig.IdentityMapping>> identityMap, final EnumResolver enumResolver) throws NetconfDocumentedException {
- Map<String, AttributeConfigElement> retVal = Maps.newHashMap();
-
- Map<String, AttributeReadingStrategy> strats = new ObjectXmlReader().prepareReading(yangToAttrConfig, identityMap);
- List<XmlElement> recognisedChildren = Lists.newArrayList();
-
- 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, typeAndNameElements);
- AttributeConfigElement readElement = readStratEntry.getValue().readElement(configNodes);
- retVal.put(readStratEntry.getKey(), readElement);
- }
-
- 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);
-
- InstanceConfigElementResolved instanceConfigElementResolved = perInstanceEditStrategy.equals("") ? new InstanceConfigElementResolved(
- retVal, defaultStrategy) : new InstanceConfigElementResolved(perInstanceEditStrategy, retVal, defaultStrategy);
-
- resolveConfiguration(instanceConfigElementResolved, services, enumResolver);
- return instanceConfigElementResolved;
- }
-
- private List<XmlElement> getConfigNodes(XmlElement moduleElement, String moduleNamespace, String name,
- List<XmlElement> recognisedChildren, List<XmlElement> typeAndName) throws NetconfDocumentedException {
- List<XmlElement> foundConfigNodes = moduleElement.getChildElementsWithinNamespace(name, moduleNamespace);
- if (foundConfigNodes.isEmpty()) {
- LOG.debug("No config nodes {}:{} found in {}", moduleNamespace, name, moduleElement);
- LOG.debug("Trying lookup of config nodes without specified namespace");
- foundConfigNodes = moduleElement.getChildElementsWithinNamespace(name,
- XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
- // In case module type or name element is not present in config it
- // would be matched with config type or name
- // We need to remove config type and name from available module
- // config elements
- foundConfigNodes.removeAll(typeAndName);
- LOG.debug("Found {} config nodes {} without specified namespace in {}", foundConfigNodes.size(), name,
- moduleElement);
- } else {
- List<XmlElement> foundWithoutNamespaceNodes = moduleElement.getChildElementsWithinNamespace(name,
- XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
- foundWithoutNamespaceNodes.removeAll(typeAndName);
- if (!foundWithoutNamespaceNodes.isEmpty()){
- throw new NetconfDocumentedException(String.format("Element %s present multiple times with different namespaces: %s, %s", name, foundConfigNodes,
- foundWithoutNamespaceNodes),
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.invalid_value,
- NetconfDocumentedException.ErrorSeverity.error);
- }
- }
-
- recognisedChildren.addAll(foundConfigNodes);
- return foundConfigNodes;
- }
-
- private static Map<String, AttributeIfc> reverseMap(Map<String, AttributeIfc> yangNameToAttr) {
- Map<String, AttributeIfc> reversednameToAtr = Maps.newHashMap();
-
- for (Entry<String, AttributeIfc> entry : yangNameToAttr.entrySet()) {
- reversednameToAtr.put(entry.getValue().getUpperCaseCammelCase(), entry.getValue());
- }
-
- return reversednameToAtr;
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config;
-
-import java.util.Map;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.confignetconfconnector.exception.OperationNotPermittedException;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigStrategy;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
-
-/**
- * Parsed xml element containing whole configuration for an instance of some
- * module. Contains preferred edit strategy type.
- */
-public class InstanceConfigElementResolved {
-
- private final EditStrategyType editStrategy;
- private final Map<String, AttributeConfigElement> configuration;
-
- public InstanceConfigElementResolved(String currentStrategy, Map<String, AttributeConfigElement> configuration,
- EditStrategyType defaultStrategy)
- throws NetconfDocumentedException {
- this.editStrategy = parseStrategy(currentStrategy, defaultStrategy);
- this.configuration = configuration;
- }
-
- public InstanceConfigElementResolved(Map<String, AttributeConfigElement> configuration, EditStrategyType defaultStrategy) {
- editStrategy = defaultStrategy;
- this.configuration = configuration;
- }
-
-
- static EditStrategyType parseStrategy(String currentStrategy, EditStrategyType defaultStrategy) throws OperationNotPermittedException {
- EditStrategyType parsedStrategy = EditStrategyType.valueOf(currentStrategy);
- EditStrategyType.compareParsedStrategyToDefaultEnforcing(parsedStrategy,defaultStrategy);
- return parsedStrategy;
- }
-
-
- public EditConfigStrategy getEditStrategy() {
- return editStrategy.getFittingStrategy();
- }
-
- public Map<String, AttributeConfigElement> getConfiguration() {
- return configuration;
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config;
-
-import com.google.common.base.Optional;
-import java.util.Date;
-import java.util.Map;
-import javax.management.ObjectName;
-import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-public class ModuleConfig {
-
- private final String moduleName;
- private final InstanceConfig instanceConfig;
-
- public ModuleConfig(String moduleName, InstanceConfig mbeanMapping) {
- this.moduleName = moduleName;
- this.instanceConfig = mbeanMapping;
- }
-
- public Element toXml(ObjectName instanceON, Document document, String namespace, final EnumResolver enumResolver) {
- Element root = XmlUtil.createElement(document, XmlNetconfConstants.MODULE_KEY, Optional.<String>absent());
-
- // type belongs to config.yang namespace, but needs to be <type prefix:moduleNS>prefix:moduleName</type>
-
- Element typeElement = XmlUtil.createTextElementWithNamespacedContent(document, XmlNetconfConstants.TYPE_KEY,
- XmlNetconfConstants.PREFIX, namespace, moduleName);
-
- root.appendChild(typeElement);
- // name belongs to config.yang namespace
- String instanceName = ObjectNameUtil.getInstanceName(instanceON);
- Element nameElement = XmlUtil.createTextElement(document, XmlNetconfConstants.NAME_KEY, instanceName, Optional.<String>absent());
-
- root.appendChild(nameElement);
-
- root = instanceConfig.toXml(instanceON, namespace, document, root, enumResolver);
-
- return root;
- }
-
- public ModuleElementResolved fromXml(XmlElement moduleElement, ServiceRegistryWrapper depTracker, String instanceName,
- String moduleNamespace, EditStrategyType defaultStrategy, Map<String, Map<Date, EditConfig.IdentityMapping>> identityMap, final EnumResolver enumResolver) throws NetconfDocumentedException {
-
- InstanceConfigElementResolved ice = instanceConfig.fromXml(moduleElement, depTracker, moduleNamespace, defaultStrategy, identityMap, enumResolver);
- return new ModuleElementResolved(instanceName, ice);
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config;
-
-import org.opendaylight.controller.netconf.confignetconfconnector.exception.OperationNotPermittedException;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigStrategy;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.MissingInstanceHandlingStrategy;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.NoneEditConfigStrategy;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ModuleElementDefinition {
-
- public static final NoneEditConfigStrategy NONE_EDIT_CONFIG_STRATEGY = new NoneEditConfigStrategy();
- public static final MissingInstanceHandlingStrategy MISSING_INSTANCE_HANDLING_STRATEGY = new MissingInstanceHandlingStrategy();
-
- private final String instanceName;
- private final EditStrategyType editStrategy;
- private static final Logger LOG = LoggerFactory.getLogger(ModuleElementDefinition.class);
-
- public ModuleElementDefinition(String instanceName, String currentStrategy, EditStrategyType defaultStrategy) {
- this.instanceName = instanceName;
- if (currentStrategy == null || currentStrategy.isEmpty()) {
- this.editStrategy = defaultStrategy;
- } else {
- EditStrategyType _edStrategy = null;
- try {
- _edStrategy = InstanceConfigElementResolved.parseStrategy(currentStrategy, defaultStrategy);
- } catch (OperationNotPermittedException e) {
- _edStrategy = defaultStrategy;
- LOG.warn("Operation not permitted on current strategy {} while default strategy is {}. Element definition strategy set to default.",
- currentStrategy,
- defaultStrategy,
- e);
- }
- this.editStrategy = _edStrategy;
- }
-
- }
-
- public String getInstanceName() {
- return instanceName;
- }
-
- public EditConfigStrategy getEditStrategy() {
- switch (editStrategy) {
- case delete :
- case remove :
- case none :
- return NONE_EDIT_CONFIG_STRATEGY;
- default :
- return MISSING_INSTANCE_HANDLING_STRATEGY;
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config;
-
-public class ModuleElementResolved {
-
- private final String instanceName;
- private final InstanceConfigElementResolved instanceConfigElementResolved;
-
- public ModuleElementResolved(String instanceName, InstanceConfigElementResolved instanceConfigElementResolved) {
- this.instanceName = instanceName;
- this.instanceConfigElementResolved = instanceConfigElementResolved;
- }
-
- public String getInstanceName() {
- return instanceName;
- }
-
- public InstanceConfigElementResolved getInstanceConfigElementResolved() {
- return instanceConfigElementResolved;
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-import java.util.Map;
-import javax.management.InstanceNotFoundException;
-import javax.management.ObjectName;
-import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
-import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.yangtools.yang.common.QName;
-
-public class ServiceRegistryWrapper {
-
- private final ServiceReferenceReadableRegistry configServiceRefRegistry;
-
- public ServiceRegistryWrapper(ServiceReferenceReadableRegistry configServiceRefRegistry) {
- this.configServiceRefRegistry = configServiceRefRegistry;
- }
-
- public ObjectName getByServiceAndRefName(String namespace, String serviceType, String refName) {
- Map<String, Map<String, Map<String, String>>> mappedServices = getMappedServices();
- Map<String, Map<String, String>> serviceNameToRefNameToInstance = mappedServices.get(namespace);
-
- Preconditions.checkArgument(serviceNameToRefNameToInstance != null,
- "No service mapped to %s:%s:%s. Wrong namespace, available namespaces: %s",
- namespace, serviceType, refName, mappedServices.keySet());
-
- Map<String, String> refNameToInstance = serviceNameToRefNameToInstance.get(serviceType);
- Preconditions.checkArgument(refNameToInstance != null,
- "No service mapped to %s:%s:%s. Wrong service type, available service types: %s"
- , namespace, serviceType, refName, serviceNameToRefNameToInstance.keySet());
-
- String instanceId = refNameToInstance.get(refName);
- Preconditions.checkArgument(instanceId != null,
- "No service mapped to %s:%s:%s. Wrong ref name, available ref names: %s"
- ,namespace, serviceType, refName, refNameToInstance.keySet());
-
- Services.ServiceInstance serviceInstance = Services.ServiceInstance.fromString(instanceId);
- Preconditions.checkArgument(serviceInstance != null,
- "No service mapped to %s:%s:%s. Wrong ref name, available ref names: %s"
- ,namespace, serviceType, refName, refNameToInstance.keySet());
-
- String qNameOfService = configServiceRefRegistry.getServiceInterfaceName(namespace, serviceType);
- try {
- /*
- Remove transaction name as this is redundant - will be stripped in DynamicWritableWrapper,
- and makes it hard to compare with service references got from MXBean attributes
- */
- return ObjectNameUtil.withoutTransactionName(
- configServiceRefRegistry.getServiceReference(qNameOfService, refName));
- } catch (InstanceNotFoundException e) {
- throw new IllegalArgumentException("No serviceInstance mapped to " + refName
- + " under service name " + serviceType + " , " + refNameToInstance.keySet(), e);
-
- }
- }
-
- public Map<String, Map<String, Map<String, String>>> getMappedServices() {
- Map<String, Map<String, Map<String, String>>> retVal = Maps.newHashMap();
-
- Map<String, Map<String, ObjectName>> serviceMapping = configServiceRefRegistry.getServiceMapping();
- for (Map.Entry<String, Map<String, ObjectName>> qNameToRefNameEntry : serviceMapping.entrySet()){
- for (String refName : qNameToRefNameEntry.getValue().keySet()) {
-
- ObjectName on = qNameToRefNameEntry.getValue().get(refName);
- Services.ServiceInstance si = Services.ServiceInstance.fromObjectName(on);
-
- QName qname = QName.create(qNameToRefNameEntry.getKey());
- String namespace = qname.getNamespace().toString();
- Map<String, Map<String, String>> serviceToRefs = retVal.get(namespace);
- if(serviceToRefs==null) {
- serviceToRefs = Maps.newHashMap();
- retVal.put(namespace, serviceToRefs);
- }
-
- String localName = qname.getLocalName();
- Map<String, String> refsToSis = serviceToRefs.get(localName);
- if(refsToSis==null) {
- refsToSis = Maps.newHashMap();
- serviceToRefs.put(localName, refsToSis);
- }
-
- Preconditions.checkState(!refsToSis.containsKey(refName),
- "Duplicate reference name %s for service %s:%s, now for instance %s", refName, namespace,
- localName, on);
- refsToSis.put(refName, si.toString());
- }
- }
-
- return retVal;
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import javax.management.ObjectName;
-import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.ObjectNameAttributeReadingStrategy;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.opendaylight.yangtools.yang.data.api.ModifyAction;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-public final class Services {
-
- private static final String EMPTY_PROVIDER = "";
- private static final String PROVIDER_KEY = "provider";
- private static final String NAME_KEY = "name";
- public static final String TYPE_KEY = "type";
- public static final String SERVICE_KEY = "service";
-
- private final Map<String /*Namespace*/, Map<String/* ServiceName */, Map<String/* refName */, ServiceInstance>>> namespaceToServiceNameToRefNameToInstance = Maps
- .newHashMap();
-
- /**
- *
- */
- public Map<String, Map<String, Map<String, ServiceInstance>>> getNamespaceToServiceNameToRefNameToInstance() {
- return namespaceToServiceNameToRefNameToInstance;
- }
-
- private static Services resolveServices(Map<String, Map<String, Map<String, String>>> mappedServices) {
- Services tracker = new Services();
-
- for (Entry<String, Map<String, Map<String, String>>> namespaceEntry : mappedServices.entrySet()) {
- String namespace = namespaceEntry.getKey();
-
- for (Entry<String, Map<String, String>> serviceEntry : namespaceEntry.getValue().entrySet()) {
-
- String serviceName = serviceEntry.getKey();
- for (Entry<String, String> refEntry : serviceEntry.getValue().entrySet()) {
-
- Map<String, Map<String, ServiceInstance>> namespaceToServices = tracker.namespaceToServiceNameToRefNameToInstance.get(namespace);
- if (namespaceToServices == null) {
- namespaceToServices = Maps.newHashMap();
- tracker.namespaceToServiceNameToRefNameToInstance.put(namespace, namespaceToServices);
- }
-
- Map<String, ServiceInstance> refNameToInstance = namespaceToServices
- .get(serviceName);
- if (refNameToInstance == null) {
- refNameToInstance = Maps.newHashMap();
- namespaceToServices.put(serviceName, refNameToInstance);
- }
-
- String refName = refEntry.getKey();
- //we want to compare reference not value of the provider
- refNameToInstance.put(refName, refEntry.getValue() == EMPTY_PROVIDER
- //provider name cannot be EMPTY_PROVIDER instance unless we are executing delete
- ? ServiceInstance.EMPTY_SERVICE_INSTANCE
- : ServiceInstance.fromString(refEntry.getValue()));
-
- }
- }
- }
- return tracker;
- }
-
- // TODO support edit strategies on services
-
- public static Services fromXml(XmlElement xml) throws NetconfDocumentedException {
- Map<String, Map<String, Map<String, String>>> retVal = Maps.newHashMap();
-
- List<XmlElement> services = xml.getChildElements(SERVICE_KEY);
- xml.checkUnrecognisedElements(services);
-
- for (XmlElement service : services) {
-
- XmlElement typeElement = service.getOnlyChildElement(TYPE_KEY);
- Entry<String, String> prefixNamespace = typeElement.findNamespaceOfTextContent();
-
- Preconditions.checkState(prefixNamespace.getKey()!=null && !prefixNamespace.getKey().equals(""), "Type attribute was not prefixed");
-
- Map<String, Map<String, String>> namespaceToServices = retVal.get(prefixNamespace.getValue());
- if(namespaceToServices == null) {
- namespaceToServices = Maps.newHashMap();
- retVal.put(prefixNamespace.getValue(), namespaceToServices);
- }
-
- String serviceName = ObjectNameAttributeReadingStrategy.checkPrefixAndExtractServiceName(typeElement, prefixNamespace);
-
- Map<String, String> innerMap = namespaceToServices.get(serviceName);
- if (innerMap == null) {
- innerMap = Maps.newHashMap();
- namespaceToServices.put(serviceName, innerMap);
- }
-
- List<XmlElement> instances = service.getChildElements(XmlNetconfConstants.INSTANCE_KEY);
- service.checkUnrecognisedElements(instances, typeElement);
-
- for (XmlElement instance : instances) {
- XmlElement nameElement = instance.getOnlyChildElement(NAME_KEY);
- String refName = nameElement.getTextContent();
-
- if (!ModifyAction.DELETE.toString().toLowerCase().equals(
- instance.getAttribute(
- XmlNetconfConstants.OPERATION_ATTR_KEY,
- XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0)))
- {
- XmlElement providerElement = instance.getOnlyChildElement(PROVIDER_KEY);
- String providerName = providerElement.getTextContent();
-
- instance.checkUnrecognisedElements(nameElement, providerElement);
-
- innerMap.put(refName, providerName);
- } else {
- //since this is a delete we dont have a provider name - we want empty service instance
- innerMap.put(refName, EMPTY_PROVIDER);
- }
- }
- }
-
- return resolveServices(retVal);
- }
-
- public static Element toXml(ServiceRegistryWrapper serviceRegistryWrapper, Document document) {
- Element root = XmlUtil.createElement(document, XmlNetconfConstants.SERVICES_KEY, Optional.of(XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG));
-
- Map<String, Map<String, Map<String, String>>> mappedServices = serviceRegistryWrapper.getMappedServices();
- for (Entry<String, Map<String, Map<String, String>>> namespaceToRefEntry : mappedServices.entrySet()) {
-
- for (Entry<String, Map<String, String>> serviceEntry : namespaceToRefEntry.getValue().entrySet()) {
- // service belongs to config.yang namespace
- Element serviceElement = XmlUtil.createElement(document, SERVICE_KEY, Optional.<String>absent());
- root.appendChild(serviceElement);
-
- // type belongs to config.yang namespace
- String serviceType = serviceEntry.getKey();
- Element typeElement = XmlUtil.createTextElementWithNamespacedContent(document, XmlNetconfConstants.TYPE_KEY,
- XmlNetconfConstants.PREFIX, namespaceToRefEntry.getKey(), serviceType);
-
- serviceElement.appendChild(typeElement);
-
- for (Entry<String, String> instanceEntry : serviceEntry.getValue().entrySet()) {
- Element instanceElement = XmlUtil.createElement(document, XmlNetconfConstants.INSTANCE_KEY, Optional.<String>absent());
- serviceElement.appendChild(instanceElement);
-
- Element nameElement = XmlUtil.createTextElement(document, NAME_KEY, instanceEntry.getKey(), Optional.<String>absent());
- instanceElement.appendChild(nameElement);
-
- Element providerElement = XmlUtil.createTextElement(document, PROVIDER_KEY, instanceEntry.getValue(), Optional.<String>absent());
- instanceElement.appendChild(providerElement);
- }
- }
-
- }
- return root;
- }
-
- public static final class ServiceInstance {
- public static final ServiceInstance EMPTY_SERVICE_INSTANCE = new ServiceInstance("", "");
-
- public ServiceInstance(String moduleName, String instanceName) {
- this.moduleName = moduleName;
- this.instanceName = instanceName;
- }
-
- public static ServiceInstance fromString(String instanceId) {
- instanceId = instanceId.trim();
- Matcher matcher = p.matcher(instanceId);
- if(!matcher.matches()) {
- matcher = pDeprecated.matcher(instanceId);
- }
-
- Preconditions.checkArgument(matcher.matches(), "Unexpected format for provider, expected " + p.toString()
- + " or " + pDeprecated.toString() + " but was " + instanceId);
-
- String factoryName = matcher.group(1);
- String instanceName = matcher.group(2);
- return new ServiceInstance(factoryName, instanceName);
- }
-
- private final String moduleName, instanceName;
- private String serviceName;
-
- public String getServiceName() {
- return serviceName;
- }
-
- public void setServiceName(String serviceName) {
- this.serviceName = serviceName;
- }
-
- public String getModuleName() {
- return moduleName;
- }
-
- public String getInstanceName() {
- return instanceName;
- }
-
- private static final String blueprint = "/"
- + XmlNetconfConstants.MODULES_KEY + "/" + XmlNetconfConstants.MODULE_KEY + "["
- + XmlNetconfConstants.TYPE_KEY + "='%s']["
- + XmlNetconfConstants.NAME_KEY + "='%s']";
-
- // TODO unify with xpath in RuntimeRpc
-
- // Previous version of xpath, needs to be supported for backwards compatibility (persisted configs by config-persister)
- private static final String blueprintRDeprecated = "/" + XmlNetconfConstants.CONFIG_KEY + "/"
- + XmlNetconfConstants.MODULES_KEY + "/" + XmlNetconfConstants.MODULE_KEY + "\\["
- + XmlNetconfConstants.NAME_KEY + "='%s'\\]/" + XmlNetconfConstants.INSTANCE_KEY + "\\["
- + XmlNetconfConstants.NAME_KEY + "='%s'\\]";
-
- private static final String blueprintR = "/"
- + XmlNetconfConstants.MODULES_KEY + "/" + XmlNetconfConstants.MODULE_KEY + "\\["
- + XmlNetconfConstants.TYPE_KEY + "='%s'\\]\\["
- + XmlNetconfConstants.NAME_KEY + "='%s'\\]";
-
- private static final Pattern pDeprecated = Pattern.compile(String.format(blueprintRDeprecated, "(.+)", "(.+)"));
- private static final Pattern p = Pattern.compile(String.format(blueprintR, "(.+)", "(.+)"));
-
- @Override
- public String toString() {
- return String.format(blueprint, moduleName, instanceName);
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((instanceName == null) ? 0 : instanceName.hashCode());
- result = prime * result + ((moduleName == null) ? 0 : moduleName.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj){
- return true;
- }
- if (obj == null){
- return false;
- }
- if (getClass() != obj.getClass()){
- return false;
- }
- ServiceInstance other = (ServiceInstance) obj;
- if (instanceName == null) {
- if (other.instanceName != null){
- return false;
- }
- } else if (!instanceName.equals(other.instanceName)){
- return false;
- }
- if (moduleName == null) {
- if (other.moduleName != null){
- return false;
- }
- } else if (!moduleName.equals(other.moduleName)){
- return false;
- }
- return true;
- }
-
- public ObjectName getObjectName(String transactionName) {
- return ObjectNameUtil.createTransactionModuleON(transactionName, moduleName, instanceName);
- }
-
- public static ServiceInstance fromObjectName(ObjectName on) {
- return new ServiceInstance(ObjectNameUtil.getFactoryName(on), ObjectNameUtil.getInstanceName(on));
- }
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.rpc;
-
-import com.google.common.collect.Maps;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import javax.management.openmbean.OpenType;
-import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry.Rpc;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeReadingStrategy;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.ObjectXmlReader;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving.AttributeResolvingStrategy;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving.ObjectResolver;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-
-public final class InstanceRuntimeRpc {
-
- private final Map<String, AttributeIfc> yangToAttrConfig;
- private final Rpc rpc;
- private final EnumResolver enumResolver;
-
- public InstanceRuntimeRpc(Rpc rpc, final EnumResolver enumResolver) {
- this.enumResolver = enumResolver;
- this.yangToAttrConfig = map(rpc.getParameters());
- this.rpc = rpc;
- }
-
- private Map<String, AttributeIfc> map(List<JavaAttribute> parameters) {
- Map<String, AttributeIfc> mapped = Maps.newHashMap();
- for (JavaAttribute javaAttribute : parameters) {
- mapped.put(javaAttribute.getAttributeYangName(), javaAttribute);
- }
- return mapped;
- }
-
- private void resolveConfiguration(Map<String, AttributeConfigElement> mappedConfig) {
-
- // TODO make field, resolvingStrategies can be instantiated only once
- Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> resolvingStrategies = new ObjectResolver(null)
- .prepareResolving(yangToAttrConfig, enumResolver);
- // TODO make constructor for object resolver without service tracker
- for (Entry<String, AttributeConfigElement> configDefEntry : mappedConfig.entrySet()) {
- try {
-
- AttributeResolvingStrategy<?, ? extends OpenType<?>> attributeResolvingStrategy = resolvingStrategies
- .get(configDefEntry.getKey());
-
- configDefEntry.getValue().resolveValue(attributeResolvingStrategy, configDefEntry.getKey());
- configDefEntry.getValue().setJmxName(
- yangToAttrConfig.get(configDefEntry.getKey()).getUpperCaseCammelCase());
- } catch (Exception e) {
- throw new IllegalStateException("Unable to resolve value " + configDefEntry.getValue()
- + " to attribute " + configDefEntry.getKey(), e);
- }
- }
- }
-
- public Map<String, AttributeConfigElement> fromXml(XmlElement configRootNode) throws NetconfDocumentedException {
- Map<String, AttributeConfigElement> retVal = Maps.newHashMap();
-
- // FIXME add identity map to runtime data
- Map<String, AttributeReadingStrategy> strats = new ObjectXmlReader().prepareReading(yangToAttrConfig,
- Collections.<String, Map<Date, EditConfig.IdentityMapping>> emptyMap());
-
- for (Entry<String, AttributeReadingStrategy> readStratEntry : strats.entrySet()) {
- List<XmlElement> configNodes = configRootNode.getChildElements(readStratEntry.getKey());
- AttributeConfigElement readElement = readStratEntry.getValue().readElement(configNodes);
- retVal.put(readStratEntry.getKey(), readElement);
- }
-
- resolveConfiguration(retVal);
- return retVal;
- }
-
- public String getName() {
- return rpc.getName();
- }
-
- public AttributeIfc getReturnType() {
- return rpc.getReturnType();
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.rpc;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-import java.util.Map;
-import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
-import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry.Rpc;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
-
-public final class ModuleRpcs {
-
- private final Map<String, String> yangToJavaNames = Maps.newHashMap();
- private final Map<String, Map<String, InstanceRuntimeRpc>> rpcMapping = Maps.newHashMap();
- private final EnumResolver enumResolver;
-
- public ModuleRpcs(final EnumResolver enumResolver) {
- this.enumResolver = enumResolver;
- }
-
- public void addNameMapping(RuntimeBeanEntry runtimeEntry) {
- String yangName = runtimeEntry.getYangName();
- Preconditions.checkState(!yangToJavaNames.containsKey(yangName),
- "RuntimeBean %s found twice in same namespace", yangName);
- yangToJavaNames.put(yangName, runtimeEntry.getJavaNamePrefix());
- }
-
- public void addRpc(RuntimeBeanEntry runtimeEntry, Rpc rpc) {
- String yangName = runtimeEntry.getYangName();
- Map<String, InstanceRuntimeRpc> map = rpcMapping.get(yangName);
- if (map == null) {
- map = Maps.newHashMap();
- rpcMapping.put(yangName, map);
- }
-
- Preconditions.checkState(!map.containsKey(rpc.getYangName()), "Rpc %s for runtime bean %s added twice",
- rpc.getYangName(), yangName);
- map.put(rpc.getYangName(), new InstanceRuntimeRpc(rpc, enumResolver));
- }
-
- public String getRbeJavaName(String yangName) {
- String javaName = yangToJavaNames.get(yangName);
- Preconditions.checkState(javaName != null,
- "No runtime bean entry found under yang name %s, available yang names %s", yangName,
- yangToJavaNames.keySet());
- return javaName;
- }
-
- public InstanceRuntimeRpc getRpc(String rbeName, String rpcName) {
- Map<String, InstanceRuntimeRpc> rpcs = rpcMapping.get(rbeName);
- Preconditions.checkState(rpcs != null, "No rpcs found for runtime bean %s", rbeName);
- InstanceRuntimeRpc rpc = rpcs.get(rpcName);
- Preconditions.checkState(rpc != null, "No rpc found for runtime bean %s with name %s", rbeName, rpcName);
- return rpc;
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.rpc;
-
-import com.google.common.base.Preconditions;
-import java.util.Map;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.runtimerpc.RuntimeRpcElementResolved;
-
-public class Rpcs {
- private final Map<String, Map<String, ModuleRpcs>> mappedRpcs;
-
- public Rpcs(Map<String, Map<String, ModuleRpcs>> mappedRpcs) {
- super();
- this.mappedRpcs = mappedRpcs;
- }
-
- public ModuleRpcs getRpcMapping(RuntimeRpcElementResolved id) {
- Map<String, ModuleRpcs> modules = mappedRpcs.get(id.getNamespace());
- Preconditions.checkState(modules != null, "No modules found for namespace %s", id.getNamespace());
- String moduleName = id.getModuleName();
- ModuleRpcs rpcMapping = modules.get(moduleName);
- Preconditions.checkState(rpcMapping != null, "No module %s found for namespace %s", moduleName,
- id.getNamespace());
-
- return rpcMapping;
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.runtime;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Predicate;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.Sets;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import javax.management.ObjectName;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfig;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-public class InstanceRuntime {
-
- /**
- *
- */
- private static final String KEY_ATTRIBUTE_KEY = "key";
-
- private final InstanceConfig instanceMapping;
- private final Map<String, InstanceRuntime> childrenMappings;
- private final Map<String, String> jmxToYangChildRbeMapping;
-
- public InstanceRuntime(InstanceConfig instanceMapping, Map<String, InstanceRuntime> childrenMappings,
- Map<String, String> jmxToYangChildRbeMapping) {
- this.instanceMapping = instanceMapping;
- this.childrenMappings = childrenMappings;
- this.jmxToYangChildRbeMapping = jmxToYangChildRbeMapping;
- }
-
- /**
- * Finds all children runtime beans, same properties and values as current
- * root + any number of additional properties
- */
- private Set<ObjectName> findChildren(ObjectName innerRootBean, Set<ObjectName> childRbeOns) {
- final Map<String, String> wantedProperties = innerRootBean.getKeyPropertyList();
-
- return Sets.newHashSet(Collections2.filter(childRbeOns, new Predicate<ObjectName>() {
-
- @Override
- public boolean apply(ObjectName on) {
- Map<String, String> localProperties = on.getKeyPropertyList();
- for (Entry<String, String> propertyEntry : wantedProperties.entrySet()) {
- if (!localProperties.containsKey(propertyEntry.getKey())){
- return false;
- }
- if (!localProperties.get(propertyEntry.getKey()).equals(propertyEntry.getValue())){
- return false;
- }
- if (localProperties.size() <= wantedProperties.size()){
- return false;
- }
- }
- return true;
- }
- }));
- }
-
- /**
- * Finds next level root runtime beans, beans that have the same properties
- * as current root + one additional
- */
- private Set<ObjectName> getRootBeans(Set<ObjectName> childRbeOns, final String string, final int keyListSize) {
- return Sets.newHashSet(Collections2.filter(childRbeOns, new Predicate<ObjectName>() {
-
- @Override
- public boolean apply(ObjectName on) {
- if (on.getKeyPropertyList().size() != keyListSize + 1){
- return false;
- }
- return on.getKeyPropertyList().containsKey(string);
- }
- }));
- }
-
- public Element toXml(ObjectName rootOn, Set<ObjectName> childRbeOns, Document document, Element parentElement, String namespace, final EnumResolver enumResolver) {
- return toXml(rootOn, childRbeOns, document, null, parentElement, namespace, enumResolver);
- }
-
- public Element toXml(ObjectName rootOn, Set<ObjectName> childRbeOns, Document document, String instanceIndex,
- Element parentElement, String namespace, final EnumResolver enumResolver) {
- Element xml = instanceMapping.toXml(rootOn, namespace, document, parentElement, enumResolver);
-
- if (instanceIndex != null) {
- xml.setAttribute(KEY_ATTRIBUTE_KEY, instanceIndex);
- }
-
- for (Entry<String, InstanceRuntime> childMappingEntry : childrenMappings.entrySet()) {
- Set<ObjectName> innerRootBeans = getRootBeans(childRbeOns, childMappingEntry.getKey(), rootOn
- .getKeyPropertyList().size());
-
- for (ObjectName objectName : innerRootBeans) {
- Set<ObjectName> innerChildRbeOns = findChildren(objectName, childRbeOns);
- String runtimeInstanceIndex = objectName.getKeyProperty(childMappingEntry.getKey());
-
- String elementName = jmxToYangChildRbeMapping.get(childMappingEntry.getKey());
-
- Element innerXml = XmlUtil.createElement(document, elementName, Optional.of(namespace));
- childMappingEntry.getValue().toXml(objectName, innerChildRbeOns, document,
- runtimeInstanceIndex, innerXml, namespace, enumResolver);
- xml.appendChild(innerXml);
- }
- }
-
- return xml;
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.runtime;
-
-import com.google.common.collect.Sets;
-import java.util.Collection;
-import java.util.Set;
-import javax.management.ObjectName;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-public class ModuleRuntime {
-
- private final InstanceRuntime instanceRuntime;
-
- public ModuleRuntime(InstanceRuntime instanceRuntime) {
- this.instanceRuntime = instanceRuntime;
- }
-
- private ObjectName findRoot(Collection<ObjectName> runtimeBeanOns) {
- for (ObjectName objectName : runtimeBeanOns) {
- if (objectName.getKeyPropertyList().size() == 3){
- return objectName;
- }
- }
- throw new IllegalStateException("Root runtime bean not found among " + runtimeBeanOns);
- }
-
- public Element toXml(String namespace, Collection<ObjectName> runtimeBeanOns,
- Document document, ModuleConfig moduleConfig, ObjectName configBeanON, final EnumResolver enumResolver) {
-
- Element moduleElement = moduleConfig.toXml(configBeanON, document, namespace, enumResolver);
-
- ObjectName rootName = findRoot(runtimeBeanOns);
-
- Set<ObjectName> childrenRuntimeBeans = Sets.newHashSet(runtimeBeanOns);
- childrenRuntimeBeans.remove(rootName);
-
- // FIXME: why is this called and not used?
- instanceRuntime.toXml(rootName, childrenRuntimeBeans, document, moduleElement, namespace, enumResolver);
-
- return moduleElement;
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.runtime;
-
-import com.google.common.base.Optional;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Multimap;
-import java.util.Collection;
-import java.util.Map;
-import java.util.Set;
-import javax.management.ObjectName;
-import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-public class Runtime {
-
- private final Map<String, Map<String, ModuleRuntime>> moduleRuntimes;
- private final Map<String, Map<String, ModuleConfig>> moduleConfigs;
-
- public Runtime(Map<String, Map<String, ModuleRuntime>> moduleRuntimes,
- Map<String, Map<String, ModuleConfig>> moduleConfigs) {
- this.moduleRuntimes = moduleRuntimes;
- this.moduleConfigs = moduleConfigs;
- }
-
- private Map<String, Multimap<String, ObjectName>> mapInstancesToModules(Set<ObjectName> instancesToMap) {
- Map<String, Multimap<String, ObjectName>> retVal = Maps.newHashMap();
-
- // TODO map to namepsace, prevent module name conflicts
- // this code does not support same module names from different namespaces
- // Namespace should be present in ObjectName
-
- for (ObjectName objectName : instancesToMap) {
- String moduleName = ObjectNameUtil.getFactoryName(objectName);
-
- Multimap<String, ObjectName> multimap = retVal.get(moduleName);
- if (multimap == null) {
- multimap = HashMultimap.create();
- retVal.put(moduleName, multimap);
- }
-
- String instanceName = ObjectNameUtil.getInstanceName(objectName);
-
- multimap.put(instanceName, objectName);
- }
-
- return retVal;
- }
-
- public Element toXml(Set<ObjectName> instancesToMap, Set<ObjectName> configBeans, Document document, final EnumResolver enumResolver) {
- Element root = XmlUtil.createElement(document, XmlNetconfConstants.DATA_KEY, Optional.<String>absent());
-
- Element modulesElement = XmlUtil.createElement(document, XmlNetconfConstants.MODULES_KEY, Optional.of(XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG));
- root.appendChild(modulesElement);
-
- Map<String, Multimap<String, ObjectName>> moduleToRuntimeInstance = mapInstancesToModules(instancesToMap);
- Map<String, Map<String, Collection<ObjectName>>> moduleToConfigInstance = Config.getMappedInstances(
- configBeans, moduleConfigs);
-
- for (String localNamespace : moduleConfigs.keySet()) {
-
- Map<String, Collection<ObjectName>> instanceToMbe = moduleToConfigInstance.get(localNamespace);
-
- for (String moduleName : moduleConfigs.get(localNamespace).keySet()) {
- Multimap<String, ObjectName> instanceToRbe = moduleToRuntimeInstance.get(moduleName);
-
- for (ObjectName instanceON : instanceToMbe.get(moduleName)) {
- String instanceName = ObjectNameUtil.getInstanceName(instanceON);
-
- Element runtimeXml;
- ModuleConfig moduleConfig = moduleConfigs.get(localNamespace).get(moduleName);
- if(instanceToRbe==null || !instanceToRbe.containsKey(instanceName)) {
- runtimeXml = moduleConfig.toXml(instanceON, document, localNamespace, enumResolver);
- } else {
- ModuleRuntime moduleRuntime = moduleRuntimes.get(localNamespace).get(moduleName);
- runtimeXml = moduleRuntime.toXml(localNamespace, instanceToRbe.get(instanceName), document,
- moduleConfig, instanceON, enumResolver);
- }
- modulesElement.appendChild(runtimeXml);
- }
-
- }
- }
-
- return root;
- }
-
-}
package org.opendaylight.controller.netconf.confignetconfconnector.operations;
-import org.opendaylight.controller.config.util.ConfigRegistryClient;
+import org.opendaylight.controller.config.facade.xml.ConfigSubsystemFacade;
import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation;
public abstract class AbstractConfigNetconfOperation extends AbstractLastNetconfOperation {
- private final ConfigRegistryClient configRegistryClient;
+ private final ConfigSubsystemFacade configSubsystemFacade;
- protected AbstractConfigNetconfOperation(ConfigRegistryClient configRegistryClient,
+ protected AbstractConfigNetconfOperation(ConfigSubsystemFacade configSubsystemFacade,
String netconfSessionIdForReporting) {
super(netconfSessionIdForReporting);
- this.configRegistryClient = configRegistryClient;
+ this.configSubsystemFacade = configSubsystemFacade;
}
- public ConfigRegistryClient getConfigRegistryClient() {
- return configRegistryClient;
+ public ConfigSubsystemFacade getConfigSubsystemFacade() {
+ return configSubsystemFacade;
}
}
import org.opendaylight.controller.config.api.ConflictingVersionException;
import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.api.jmx.CommitStatus;
-import org.opendaylight.controller.config.util.ConfigRegistryClient;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.facade.xml.ConfigSubsystemFacade;
+import org.opendaylight.controller.config.facade.xml.Datastore;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-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 LOG = LoggerFactory.getLogger(Commit.class);
- private final TransactionProvider transactionProvider;
-
- public Commit(TransactionProvider transactionProvider, ConfigRegistryClient configRegistryClient,
- String netconfSessionIdForReporting) {
- super(configRegistryClient, netconfSessionIdForReporting);
- this.transactionProvider = transactionProvider;
+ public Commit(final ConfigSubsystemFacade configSubsystemFacade, final String netconfSessionIdForReporting) {
+ super(configSubsystemFacade, netconfSessionIdForReporting);
}
- private static void checkXml(XmlElement xml) throws NetconfDocumentedException {
+ private static void checkXml(XmlElement xml) throws DocumentedException {
xml.checkName(XmlNetconfConstants.COMMIT);
xml.checkNamespace(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
}
}
@Override
- protected Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws DocumentedException {
checkXml(xml);
CommitStatus status;
try {
- status = this.transactionProvider.commitTransaction();
+ status = getConfigSubsystemFacade().commitTransaction();
LOG.trace("Datastore {} committed successfully: {}", Datastore.candidate, status);
} catch (ConflictingVersionException | ValidationException e) {
- throw NetconfDocumentedException.wrap(e);
+ throw DocumentedException.wrap(e);
}
LOG.trace("Datastore {} committed successfully: {}", Datastore.candidate, status);
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.operations;
-
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.getconfig.CandidateDatastoreQueryStrategy;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.getconfig.DatastoreQueryStrategy;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.getconfig.RunningDatastoreQueryStrategy;
-import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
-
-public enum Datastore {
-
- running, candidate;
-
- /**
- * @param source
- * @param transactionProvider
- * @return
- */
- public static DatastoreQueryStrategy getInstanceQueryStrategy(Datastore source,
- TransactionProvider transactionProvider) {
- switch (source) {
- case running:
- return new RunningDatastoreQueryStrategy(transactionProvider);
- case candidate:
- return new CandidateDatastoreQueryStrategy(transactionProvider);
- default:
- throw new UnsupportedOperationException("Unimplemented datastore query strategy for " + source);
- }
- }
-}
import com.google.common.base.Optional;
import java.util.HashMap;
import java.util.Map;
-import org.opendaylight.controller.config.util.ConfigRegistryClient;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
+import org.opendaylight.controller.config.facade.xml.ConfigSubsystemFacade;
+import org.opendaylight.controller.config.facade.xml.Datastore;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorSeverity;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorTag;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorType;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-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 LOG = LoggerFactory.getLogger(DiscardChanges.class);
- private final TransactionProvider transactionProvider;
-
- public DiscardChanges(final TransactionProvider transactionProvider, ConfigRegistryClient configRegistryClient,
- String netconfSessionIdForReporting) {
- super(configRegistryClient, netconfSessionIdForReporting);
- this.transactionProvider = transactionProvider;
+ public DiscardChanges(final ConfigSubsystemFacade configSubsystemFacade, final String netconfSessionIdForReporting) {
+ super(configSubsystemFacade, netconfSessionIdForReporting);
}
- private static void fromXml(XmlElement xml) throws NetconfDocumentedException {
+ private static void fromXml(XmlElement xml) throws DocumentedException {
xml.checkName(DISCARD);
xml.checkNamespace(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
}
}
@Override
- protected Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws DocumentedException {
fromXml(xml);
try {
- if (transactionProvider.getTransaction().isPresent()) {
- this.transactionProvider.abortTransaction();
- }
+ getConfigSubsystemFacade().abortConfiguration();
} catch (final RuntimeException e) {
LOG.warn("Abort failed: ", e);
final Map<String, String> errorInfo = new HashMap<>();
errorInfo
.put(ErrorTag.operation_failed.name(),
"Abort failed.");
- throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed,
+ throw new DocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed,
ErrorSeverity.error, errorInfo);
}
LOG.trace("Changes discarded successfully from datastore {}", Datastore.candidate);
package org.opendaylight.controller.netconf.confignetconfconnector.operations;
import com.google.common.base.Optional;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.facade.xml.Datastore;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
-import org.opendaylight.controller.netconf.util.exception.UnexpectedNamespaceException;
import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
}
@Override
- protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws DocumentedException {
final Datastore targetDatastore = extractTargetParameter(operationElement);
if(targetDatastore == Datastore.candidate) {
// Since candidate datastore instances are allocated per session and not accessible anywhere else, no need to lock
}
// Not supported running lock
- throw new NetconfDocumentedException("Unable to lock " + Datastore.running + " datastore", NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_not_supported, NetconfDocumentedException.ErrorSeverity.error);
+ throw new DocumentedException("Unable to lock " + Datastore.running + " datastore", DocumentedException.ErrorType.application,
+ DocumentedException.ErrorTag.operation_not_supported, DocumentedException.ErrorSeverity.error);
}
- static Datastore extractTargetParameter(final XmlElement operationElement) throws NetconfDocumentedException {
- final XmlElement targetChildNode;
- try {
- final XmlElement targetElement = operationElement.getOnlyChildElementWithSameNamespace(TARGET_KEY);
- targetChildNode = targetElement.getOnlyChildElementWithSameNamespace();
- } catch (final MissingNameSpaceException | UnexpectedNamespaceException e) {
- LOG.trace("Can't get only child element with same namespace", e);
- throw NetconfDocumentedException.wrap(e);
- }
+ static Datastore extractTargetParameter(final XmlElement operationElement) throws DocumentedException {
+ final XmlElement targetElement = operationElement.getOnlyChildElementWithSameNamespace(TARGET_KEY);
+ final XmlElement targetChildNode = targetElement.getOnlyChildElementWithSameNamespace();
return Datastore.valueOf(targetChildNode.getName());
}
package org.opendaylight.controller.netconf.confignetconfconnector.operations;
import com.google.common.base.Optional;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.facade.xml.Datastore;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
}
@Override
- protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws DocumentedException {
final Datastore targetDatastore = Lock.extractTargetParameter(operationElement);
if(targetDatastore == Datastore.candidate) {
// Since candidate datastore instances are allocated per session and not accessible anywhere else, no need to lock
}
// Not supported running lock
- throw new NetconfDocumentedException("Unable to unlock " + Datastore.running + " datastore", NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_not_supported, NetconfDocumentedException.ErrorSeverity.error);
+ throw new DocumentedException("Unable to unlock " + Datastore.running + " datastore", DocumentedException.ErrorType.application,
+ DocumentedException.ErrorTag.operation_not_supported, DocumentedException.ErrorSeverity.error);
}
@Override
import java.util.HashMap;
import java.util.Map;
import org.opendaylight.controller.config.api.ValidationException;
-import org.opendaylight.controller.config.util.ConfigRegistryClient;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
+import org.opendaylight.controller.config.facade.xml.ConfigSubsystemFacade;
+import org.opendaylight.controller.config.facade.xml.Datastore;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorSeverity;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorTag;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorType;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-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 LOG = LoggerFactory.getLogger(Validate.class);
- private final TransactionProvider transactionProvider;
-
- public Validate(final TransactionProvider transactionProvider, ConfigRegistryClient configRegistryClient,
- String netconfSessionIdForReporting) {
- super(configRegistryClient, netconfSessionIdForReporting);
- this.transactionProvider = transactionProvider;
+ public Validate(final ConfigSubsystemFacade configSubsystemFacade, final String netconfSessionIdForReporting) {
+ super(configSubsystemFacade, netconfSessionIdForReporting);
}
- private void checkXml(XmlElement xml) throws NetconfDocumentedException {
+ private void checkXml(XmlElement xml) throws DocumentedException {
xml.checkName(VALIDATE);
xml.checkNamespace(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
Datastore sourceDatastore = Datastore.valueOf(datastoreValue);
if (sourceDatastore != Datastore.candidate){
- throw new NetconfDocumentedException( "Only " + Datastore.candidate
- + " is supported as source for " + VALIDATE + " but was " + datastoreValue,ErrorType.application,ErrorTag.data_missing,ErrorSeverity.error);
+ throw new DocumentedException( "Only " + Datastore.candidate
+ + " is supported as source for " + VALIDATE + " but was " + datastoreValue, ErrorType.application, ErrorTag.data_missing, ErrorSeverity.error);
}
}
}
@Override
- protected Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws DocumentedException {
checkXml(xml);
try {
- transactionProvider.validateTransaction();
+ getConfigSubsystemFacade().validateConfiguration();
} catch (ValidationException e) {
LOG.warn("Validation failed", e);
- throw NetconfDocumentedException.wrap(e);
+ throw DocumentedException.wrap(e);
} catch (IllegalStateException e) {
LOG.warn("Validation failed", e);
final Map<String, String> errorInfo = new HashMap<>();
errorInfo
.put(ErrorTag.operation_failed.name(),
"Datastore is not present. Use 'get-config' or 'edit-config' before triggering 'operations' operation");
- throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed,
+ throw new DocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed,
ErrorSeverity.error, errorInfo);
}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
-
-import java.util.Map;
-import javax.management.InstanceNotFoundException;
-import javax.management.ObjectName;
-import org.opendaylight.controller.config.util.ConfigTransactionClient;
-import org.opendaylight.controller.netconf.confignetconfconnector.exception.NetconfConfigHandlingException;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ServiceRegistryWrapper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public abstract class AbstractEditConfigStrategy implements EditConfigStrategy {
-
- private static final Logger LOG = LoggerFactory.getLogger(AbstractEditConfigStrategy.class);
-
- @Override
- public void executeConfiguration(String module, String instance, Map<String, AttributeConfigElement> configuration,
- ConfigTransactionClient ta, ServiceRegistryWrapper services) throws NetconfConfigHandlingException {
-
- try {
- ObjectName on = ta.lookupConfigBean(module, instance);
- LOG.debug("ServiceInstance for {} {} located successfully under {}", module, instance, on);
- executeStrategy(configuration, ta, on, services);
- } catch (InstanceNotFoundException e) {
- handleMissingInstance(configuration, ta, module, instance, services);
- }
-
- }
-
- // TODO split missing instances handling strategies from edit config strategies in this hierarchy = REFACTOR
- // edit configs should not handle missing
-
- abstract void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
- String module, String instance, ServiceRegistryWrapper services) throws NetconfConfigHandlingException;
-
- abstract void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
- ObjectName objectName, ServiceRegistryWrapper services) throws NetconfConfigHandlingException;
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
-
-import java.util.Map;
-import javax.management.InstanceNotFoundException;
-import javax.management.ObjectName;
-import org.opendaylight.controller.config.util.ConfigTransactionClient;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.confignetconfconnector.exception.NetconfConfigHandlingException;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ServiceRegistryWrapper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class DeleteEditConfigStrategy extends AbstractEditConfigStrategy {
-
- private static final Logger LOG = LoggerFactory.getLogger(DeleteEditConfigStrategy.class);
-
-
- @Override
- void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
- String module, String instance, ServiceRegistryWrapper services) throws NetconfConfigHandlingException {
- throw new NetconfConfigHandlingException(String.format("Unable to delete %s : %s , ServiceInstance not found", module ,instance),
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_failed,
- NetconfDocumentedException.ErrorSeverity.error);
- }
-
- @Override
- void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on, ServiceRegistryWrapper services) throws NetconfConfigHandlingException {
- try {
- ta.destroyModule(on);
- LOG.debug("ServiceInstance {} deleted successfully", on);
- } catch (InstanceNotFoundException e) {
- throw new NetconfConfigHandlingException(
- String.format("Unable to delete %s because of exception %s" + on, e.getMessage()),
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_failed,
- NetconfDocumentedException.ErrorSeverity.error);
- }
- }
-}
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Multimap;
-import java.util.Date;
import java.util.HashMap;
import java.util.Map;
-import java.util.Set;
-import javax.management.InstanceNotFoundException;
-import javax.management.ObjectName;
import org.opendaylight.controller.config.api.ValidationException;
-import org.opendaylight.controller.config.util.BeanReader;
-import org.opendaylight.controller.config.util.ConfigRegistryClient;
-import org.opendaylight.controller.config.util.ConfigTransactionClient;
-import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
+import org.opendaylight.controller.config.facade.xml.ConfigExecution;
+import org.opendaylight.controller.config.facade.xml.ConfigSubsystemFacade;
+import org.opendaylight.controller.config.facade.xml.mapping.config.Config;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorSeverity;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorTag;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorType;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfig;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfigElementResolved;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementDefinition;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementResolved;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services.ServiceInstance;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigXmlParser.EditConfigExecution;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreContext;
-import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
-import org.opendaylight.yangtools.yang.model.api.Module;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
private static final Logger LOG = LoggerFactory.getLogger(EditConfig.class);
- private final YangStoreContext yangStoreSnapshot;
-
- private final TransactionProvider transactionProvider;
private EditConfigXmlParser editConfigXmlParser;
- public EditConfig(YangStoreContext yangStoreSnapshot, TransactionProvider transactionProvider,
- ConfigRegistryClient configRegistryClient, String netconfSessionIdForReporting) {
- super(configRegistryClient, netconfSessionIdForReporting);
- this.yangStoreSnapshot = yangStoreSnapshot;
- this.transactionProvider = transactionProvider;
+ public EditConfig(final ConfigSubsystemFacade configSubsystemFacade, final String netconfSessionIdForReporting) {
+ super(configSubsystemFacade, netconfSessionIdForReporting);
this.editConfigXmlParser = new EditConfigXmlParser();
}
@VisibleForTesting
Element getResponseInternal(final Document document,
- final EditConfigXmlParser.EditConfigExecution editConfigExecution) throws NetconfDocumentedException {
-
- if (editConfigExecution.shouldTest()) {
- executeTests(getConfigRegistryClient(), editConfigExecution);
- }
-
- if (editConfigExecution.shouldSet()) {
- executeSet(getConfigRegistryClient(), editConfigExecution);
- }
-
- LOG.trace("Operation {} successful", EditConfigXmlParser.EDIT_CONFIG);
-
- return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
- }
+ final ConfigExecution configExecution) throws DocumentedException {
- private void executeSet(ConfigRegistryClient configRegistryClient,
- EditConfigXmlParser.EditConfigExecution editConfigExecution) throws NetconfDocumentedException {
- set(configRegistryClient, editConfigExecution);
- LOG.debug("Set phase for {} operation successful", EditConfigXmlParser.EDIT_CONFIG);
- }
-
- private void executeTests(ConfigRegistryClient configRegistryClient,
- EditConfigExecution editConfigExecution) throws NetconfDocumentedException {
try {
- test(configRegistryClient, editConfigExecution, editConfigExecution.getDefaultStrategy());
- } catch (final ValidationException e) {
+ getConfigSubsystemFacade().executeConfigExecution(configExecution);
+ } catch (ValidationException e) {
LOG.warn("Test phase for {} failed", EditConfigXmlParser.EDIT_CONFIG, e);
final Map<String, String> errorInfo = new HashMap<>();
errorInfo.put(ErrorTag.operation_failed.name(), e.getMessage());
- throw new NetconfDocumentedException("Test phase: " + e.getMessage(), e, ErrorType.application,
+ throw new DocumentedException("Test phase: " + e.getMessage(), e, ErrorType.application,
ErrorTag.operation_failed, ErrorSeverity.error, errorInfo);
}
- LOG.debug("Test phase for {} operation successful", EditConfigXmlParser.EDIT_CONFIG);
- }
-
- private void test(ConfigRegistryClient configRegistryClient, EditConfigExecution execution,
- EditStrategyType editStrategyType) throws ValidationException, NetconfDocumentedException {
- ObjectName taON = transactionProvider.getTestTransaction();
- try {
- // default strategy = replace wipes config
- if (editStrategyType == EditStrategyType.replace) {
- transactionProvider.wipeTestTransaction(taON);
- }
-
- ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(taON);
-
- handleMisssingInstancesOnTransaction(ta, execution);
- setServicesOnTransaction(ta, execution);
- setOnTransaction(ta, execution);
- transactionProvider.validateTestTransaction(taON);
- } finally {
- transactionProvider.abortTestTransaction(taON);
- }
- }
-
- private void set(ConfigRegistryClient configRegistryClient,
- EditConfigXmlParser.EditConfigExecution editConfigExecution) throws NetconfDocumentedException {
- ObjectName taON = transactionProvider.getOrCreateTransaction();
-
- // default strategy = replace wipes config
- if (editConfigExecution.getDefaultStrategy() == EditStrategyType.replace) {
- transactionProvider.wipeTransaction();
- }
-
- ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(taON);
-
- handleMisssingInstancesOnTransaction(ta, editConfigExecution);
- setServicesOnTransaction(ta, editConfigExecution);
- setOnTransaction(ta, editConfigExecution);
- }
-
- private void setServicesOnTransaction(ConfigTransactionClient ta, EditConfigExecution execution) throws NetconfDocumentedException {
-
- Services services = execution.getServices();
-
- Map<String, Map<String, Map<String, Services.ServiceInstance>>> namespaceToServiceNameToRefNameToInstance = services
- .getNamespaceToServiceNameToRefNameToInstance();
-
- for (Map.Entry<String, Map<String, Map<String, Services.ServiceInstance>>> namespaceToServiceToRefEntry : namespaceToServiceNameToRefNameToInstance.entrySet()) {
- for (Map.Entry<String, Map<String, Services.ServiceInstance>> serviceToRefEntry : namespaceToServiceToRefEntry.getValue().entrySet()) {
-
- String qnameOfService = getQname(ta, namespaceToServiceToRefEntry.getKey(), serviceToRefEntry.getKey());
- Map<String, Services.ServiceInstance> refNameToInstance = serviceToRefEntry.getValue();
-
- for (Map.Entry<String, Services.ServiceInstance> refNameToServiceEntry : refNameToInstance.entrySet()) {
- ObjectName on = refNameToServiceEntry.getValue().getObjectName(ta.getTransactionName());
- try {
- if (ServiceInstance.EMPTY_SERVICE_INSTANCE == refNameToServiceEntry.getValue()) {
- ta.removeServiceReference(qnameOfService, refNameToServiceEntry.getKey());
- LOG.debug("Removing service {} with name {}", qnameOfService, refNameToServiceEntry.getKey());
- } else {
- ObjectName saved = ta.saveServiceReference(qnameOfService, refNameToServiceEntry.getKey(), on);
- LOG.debug("Saving service {} with on {} under name {} with service on {}", qnameOfService,
- on, refNameToServiceEntry.getKey(), saved);
- }
- } catch (InstanceNotFoundException e) {
- throw new NetconfDocumentedException(String.format("Unable to edit ref name " + refNameToServiceEntry.getKey() + " for instance " + on, e),
- ErrorType.application,
- ErrorTag.operation_failed,
- ErrorSeverity.error);
- }
- }
- }
- }
- }
-
- private String getQname(ConfigTransactionClient ta, String namespace, String serviceName) {
- return ta.getServiceInterfaceName(namespace, serviceName);
- }
-
- private void setOnTransaction(ConfigTransactionClient ta, EditConfigExecution execution) throws NetconfDocumentedException {
-
- for (Multimap<String, ModuleElementResolved> modulesToResolved : execution.getResolvedXmlElements(ta).values()) {
-
- for (Map.Entry<String, ModuleElementResolved> moduleToResolved : modulesToResolved.entries()) {
- String moduleName = moduleToResolved.getKey();
-
- ModuleElementResolved moduleElementResolved = moduleToResolved.getValue();
- String instanceName = moduleElementResolved.getInstanceName();
- InstanceConfigElementResolved ice = moduleElementResolved.getInstanceConfigElementResolved();
- EditConfigStrategy strategy = ice.getEditStrategy();
- strategy.executeConfiguration(moduleName, instanceName, ice.getConfiguration(), ta, execution.getServiceRegistryWrapper(ta));
- }
- }
- }
-
- private void handleMisssingInstancesOnTransaction(ConfigTransactionClient ta,
- EditConfigExecution execution) throws NetconfDocumentedException {
-
- for (Multimap<String,ModuleElementDefinition> modulesToResolved : execution.getModulesDefinition(ta).values()) {
- for (Map.Entry<String, ModuleElementDefinition> moduleToResolved : modulesToResolved.entries()) {
- String moduleName = moduleToResolved.getKey();
-
- ModuleElementDefinition moduleElementDefinition = moduleToResolved.getValue();
-
- EditConfigStrategy strategy = moduleElementDefinition.getEditStrategy();
- strategy.executeConfiguration(moduleName, moduleElementDefinition.getInstanceName(), null, ta, execution.getServiceRegistryWrapper(ta));
- }
- }
- }
-
- public static Config getConfigMapping(ConfigRegistryClient configRegistryClient, YangStoreContext yangStoreSnapshot) {
- Map<String, Map<String, ModuleConfig>> factories = transformMbeToModuleConfigs(configRegistryClient,
- yangStoreSnapshot.getModuleMXBeanEntryMap());
- Map<String, Map<Date, IdentityMapping>> identitiesMap = transformIdentities(yangStoreSnapshot.getModules());
- return new Config(factories, identitiesMap, yangStoreSnapshot.getEnumResolver());
- }
-
-
- public static class IdentityMapping {
- private final Map<String, IdentitySchemaNode> identityNameToSchemaNode;
-
- public IdentityMapping() {
- this.identityNameToSchemaNode = Maps.newHashMap();
- }
-
- void addIdSchemaNode(IdentitySchemaNode node) {
- String name = node.getQName().getLocalName();
- Preconditions.checkState(!identityNameToSchemaNode.containsKey(name));
- identityNameToSchemaNode.put(name, node);
- }
-
- public boolean containsIdName(String idName) {
- return identityNameToSchemaNode.containsKey(idName);
- }
-
- }
-
- private static Map<String, Map<Date, IdentityMapping>> transformIdentities(Set<Module> modules) {
- Map<String, Map<Date, IdentityMapping>> mappedIds = Maps.newHashMap();
- for (Module module : modules) {
- String namespace = module.getNamespace().toString();
- Map<Date, IdentityMapping> revisionsByNamespace= mappedIds.get(namespace);
- if(revisionsByNamespace == null) {
- revisionsByNamespace = Maps.newHashMap();
- mappedIds.put(namespace, revisionsByNamespace);
- }
-
- Date revision = module.getRevision();
-
- IdentityMapping identityMapping = revisionsByNamespace.get(revision);
- if(identityMapping == null) {
- identityMapping = new IdentityMapping();
- revisionsByNamespace.put(revision, identityMapping);
- }
-
- for (IdentitySchemaNode identitySchemaNode : module.getIdentities()) {
- identityMapping.addIdSchemaNode(identitySchemaNode);
- }
-
- }
-
- return mappedIds;
- }
-
- public static Map<String/* Namespace from yang file */,
- Map<String /* Name of module entry from yang file */, ModuleConfig>> transformMbeToModuleConfigs (
- final BeanReader configRegistryClient, Map<String/* Namespace from yang file */,
- Map<String /* Name of module entry from yang file */, ModuleMXBeanEntry>> mBeanEntries) {
-
- Map<String, Map<String, ModuleConfig>> namespaceToModuleNameToModuleConfig = Maps.newHashMap();
-
- for (Map.Entry<String, Map<String, ModuleMXBeanEntry>> namespaceToModuleToMbe : mBeanEntries.entrySet()) {
- for (Map.Entry<String, ModuleMXBeanEntry> moduleNameToMbe : namespaceToModuleToMbe.getValue().entrySet()) {
- String moduleName = moduleNameToMbe.getKey();
- ModuleMXBeanEntry moduleMXBeanEntry = moduleNameToMbe.getValue();
-
- ModuleConfig moduleConfig = new ModuleConfig(moduleName,
- new InstanceConfig(configRegistryClient,moduleMXBeanEntry.getAttributes(), moduleMXBeanEntry.getNullableDummyContainerName()));
-
- Map<String, ModuleConfig> moduleNameToModuleConfig = namespaceToModuleNameToModuleConfig.get(namespaceToModuleToMbe.getKey());
- if(moduleNameToModuleConfig == null) {
- moduleNameToModuleConfig = Maps.newHashMap();
- namespaceToModuleNameToModuleConfig.put(namespaceToModuleToMbe.getKey(), moduleNameToModuleConfig);
- }
-
- moduleNameToModuleConfig.put(moduleName, moduleConfig);
- }
- }
+ LOG.trace("Operation {} successful", EditConfigXmlParser.EDIT_CONFIG);
- return namespaceToModuleNameToModuleConfig;
+ return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
}
@Override
}
@Override
- protected Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws NetconfDocumentedException {
- EditConfigXmlParser.EditConfigExecution editConfigExecution;
- Config cfg = getConfigMapping(getConfigRegistryClient(), yangStoreSnapshot);
- editConfigExecution = editConfigXmlParser.fromXml(xml, cfg);
-
- Element responseInternal;
- responseInternal = getResponseInternal(document, editConfigExecution);
- return responseInternal;
+ protected Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws DocumentedException {
+ ConfigExecution configExecution;
+ // FIXME config mapping getter works on dynamic yang store service and so does later executeConfigExecution method
+ // They might have different view of current yangs in ODL and might cause race conditions
+ Config cfg = getConfigSubsystemFacade().getConfigMapping();
+ configExecution = editConfigXmlParser.fromXml(xml, cfg);
+
+ return getResponseInternal(document, configExecution);
}
}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
-
-import java.util.Map;
-import org.opendaylight.controller.config.util.ConfigTransactionClient;
-import org.opendaylight.controller.netconf.confignetconfconnector.exception.NetconfConfigHandlingException;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ServiceRegistryWrapper;
-
-public interface EditConfigStrategy {
-
- void executeConfiguration(String module, String instance, Map<String, AttributeConfigElement> configuration,
- ConfigTransactionClient ta, ServiceRegistryWrapper services) throws NetconfConfigHandlingException;
-
-}
package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
-import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
-import com.google.common.collect.Multimap;
-import java.util.Arrays;
-import java.util.Map;
-import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.facade.xml.ConfigExecution;
+import org.opendaylight.controller.config.facade.xml.Datastore;
+import org.opendaylight.controller.config.facade.xml.TestOption;
+import org.opendaylight.controller.config.facade.xml.mapping.config.Config;
+import org.opendaylight.controller.config.facade.xml.strategy.EditStrategyType;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementDefinition;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementResolved;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ServiceRegistryWrapper;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.Datastore;
-import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
-import org.opendaylight.controller.netconf.util.exception.UnexpectedNamespaceException;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public EditConfigXmlParser() {
}
- EditConfigXmlParser.EditConfigExecution fromXml(final XmlElement xml, final Config cfgMapping)
- throws NetconfDocumentedException {
+ ConfigExecution fromXml(final XmlElement xml, final Config cfgMapping)
+ throws DocumentedException {
//TODO remove transactionProvider and CfgRegistry from parameters, accept only service ref store
XmlElement targetElement = null;
XmlElement targetChildNode = null;
- try {
- targetElement = xml.getOnlyChildElementWithSameNamespace(EditConfigXmlParser.TARGET_KEY);
- targetChildNode = targetElement.getOnlyChildElementWithSameNamespace();
- } catch (final MissingNameSpaceException | UnexpectedNamespaceException e) {
- LOG.trace("Can't get only child element with same namespace", e);
- throw NetconfDocumentedException.wrap(e);
- }
+ targetElement = xml.getOnlyChildElementWithSameNamespace(EditConfigXmlParser.TARGET_KEY);
+ targetChildNode = targetElement.getOnlyChildElementWithSameNamespace();
+
String datastoreValue = targetChildNode.getName();
Datastore targetDatastore = Datastore.valueOf(datastoreValue);
LOG.debug("Setting {} to '{}'", EditConfigXmlParser.TARGET_KEY, targetDatastore);
// check target
if (targetDatastore != Datastore.candidate){
- throw new NetconfDocumentedException(String.format(
+ throw new DocumentedException(String.format(
"Only %s datastore supported for edit config but was: %s",
Datastore.candidate,
targetDatastore),
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.invalid_value,
- NetconfDocumentedException.ErrorSeverity.error);
+ DocumentedException.ErrorType.application,
+ DocumentedException.ErrorTag.invalid_value,
+ DocumentedException.ErrorSeverity.error);
}
// Test option
.getOnlyChildElementWithSameNamespaceOptionally(EditConfigXmlParser.TEST_OPTION_KEY);
if (testOptionElementOpt.isPresent()) {
String testOptionValue = testOptionElementOpt.get().getTextContent();
- testOption = EditConfigXmlParser.TestOption.getFromXmlName(testOptionValue);
+ testOption = TestOption.getFromXmlName(testOptionValue);
} else {
- testOption = EditConfigXmlParser.TestOption.getDefault();
+ testOption = TestOption.getDefault();
}
LOG.debug("Setting {} to '{}'", EditConfigXmlParser.TEST_OPTION_KEY, testOption);
}
XmlElement configElement = null;
- try {
- configElement = xml.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.CONFIG_KEY);
- } catch (MissingNameSpaceException e) {
- LOG.trace("Can't get only child element with same namespace due to ",e);
- throw NetconfDocumentedException.wrap(e);
- }
-
- return new EditConfigXmlParser.EditConfigExecution(cfgMapping, configElement, testOption, editStrategyType);
- }
-
- @VisibleForTesting
- static enum TestOption {
- testOnly, set, testThenSet;
-
- static TestOption getFromXmlName(String testOptionXmlName) {
- switch (testOptionXmlName) {
- case "test-only":
- return testOnly;
- case "test-then-set":
- return testThenSet;
- case "set":
- return set;
- default:
- throw new IllegalArgumentException("Unsupported test option " + testOptionXmlName + " supported: "
- + Arrays.toString(TestOption.values()));
- }
- }
-
- public static TestOption getDefault() {
- return testThenSet;
- }
-
- }
-
- @VisibleForTesting
- static class EditConfigExecution {
-
- private final TestOption testOption;
- private final EditStrategyType defaultEditStrategyType;
- private final Services services;
- private final Config configResolver;
- private final XmlElement configElement;
-
- EditConfigExecution(Config configResolver, XmlElement configElement, TestOption testOption, EditStrategyType defaultStrategy) throws NetconfDocumentedException {
- Config.checkUnrecognisedChildren(configElement);
- this.configResolver = configResolver;
- this.configElement = configElement;
- this.services = configResolver.fromXmlServices(configElement);
- this.testOption = testOption;
- this.defaultEditStrategyType = defaultStrategy;
- }
+ configElement = xml.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.CONFIG_KEY);
- boolean shouldTest() {
- return testOption == TestOption.testOnly || testOption == TestOption.testThenSet;
- }
-
- boolean shouldSet() {
- return testOption == TestOption.set || testOption == TestOption.testThenSet;
- }
-
- Map<String, Multimap<String, ModuleElementResolved>> getResolvedXmlElements(ServiceReferenceReadableRegistry serviceRegistry) throws NetconfDocumentedException {
- return configResolver.fromXmlModulesResolved(configElement, defaultEditStrategyType, getServiceRegistryWrapper(serviceRegistry));
- }
-
- ServiceRegistryWrapper getServiceRegistryWrapper(ServiceReferenceReadableRegistry serviceRegistry) {
- // TODO cache service registry
- return new ServiceRegistryWrapper(serviceRegistry);
- }
-
- Map<String, Multimap<String,ModuleElementDefinition>> getModulesDefinition(ServiceReferenceReadableRegistry serviceRegistry) throws NetconfDocumentedException {
- return configResolver.fromXmlModulesMap(configElement, defaultEditStrategyType, getServiceRegistryWrapper(serviceRegistry));
- }
-
- EditStrategyType getDefaultStrategy() {
- return defaultEditStrategyType;
- }
-
- Services getServices() {
- return services;
- }
+ return new ConfigExecution(cfgMapping, configElement, testOption, editStrategyType);
}
}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
-
-import java.util.EnumSet;
-import java.util.Set;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.confignetconfconnector.exception.OperationNotPermittedException;
-
-public enum EditStrategyType {
- // can be default
- merge, replace, none,
- // additional per element
- delete, remove;
-
- private static final Set<EditStrategyType> defaultStrats = EnumSet.of(merge, replace, none);
-
- public static EditStrategyType getDefaultStrategy() {
- return merge;
- }
-
- public boolean isEnforcing() {
- switch (this) {
- case merge:
- case none:
- case remove:
- case delete:
- return false;
- case replace:
- return true;
-
- default:
- throw new IllegalStateException("Default edit strategy can be only of value " + defaultStrats + " but was "
- + this);
- }
- }
- public static void compareParsedStrategyToDefaultEnforcing(EditStrategyType parsedStrategy,
- EditStrategyType defaultStrategy) throws OperationNotPermittedException {
- if (defaultStrategy.isEnforcing()) {
- if (parsedStrategy != defaultStrategy){
- throw new OperationNotPermittedException(String.format("With "
- + defaultStrategy
- + " as "
- + EditConfigXmlParser.DEFAULT_OPERATION_KEY
- + " operations on module elements are not permitted since the default option is restrictive"),
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_failed,
- NetconfDocumentedException.ErrorSeverity.error);
- }
- }
-
- }
- public EditConfigStrategy getFittingStrategy() {
- switch (this) {
- case merge:
- return new MergeEditConfigStrategy();
- case replace:
- return new ReplaceEditConfigStrategy();
- case delete:
- return new DeleteEditConfigStrategy();
- case remove:
- return new RemoveEditConfigStrategy();
- case none:
- return new NoneEditConfigStrategy();
- default:
- throw new UnsupportedOperationException("Unimplemented edit config strategy" + this);
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
-
-import static java.util.Arrays.asList;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import javax.management.Attribute;
-import javax.management.ObjectName;
-import org.opendaylight.controller.config.util.ConfigTransactionClient;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.confignetconfconnector.exception.NetconfConfigHandlingException;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ServiceRegistryWrapper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class MergeEditConfigStrategy extends AbstractEditConfigStrategy {
-
- private static final Logger LOG = LoggerFactory.getLogger(MergeEditConfigStrategy.class);
-
- public MergeEditConfigStrategy() {
-
- }
-
- @Override
- void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
- String module, String instance, ServiceRegistryWrapper services) throws NetconfConfigHandlingException {
- throw new NetconfConfigHandlingException(
- String.format("Unable to handle missing instance, no missing instances should appear at this point, missing: %s : %s ",
- module,
- instance),
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_failed,
- NetconfDocumentedException.ErrorSeverity.error);
- }
-
- @Override
- void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on, ServiceRegistryWrapper services) throws NetconfConfigHandlingException {
-
- for (Entry<String, AttributeConfigElement> configAttributeEntry : configuration.entrySet()) {
- try {
- AttributeConfigElement ace = configAttributeEntry.getValue();
-
- if (!ace.getResolvedValue().isPresent()) {
- LOG.debug("Skipping attribute {} for {}", configAttributeEntry.getKey(), on);
- continue;
- }
-
- Object toBeMergedIn = ace.getResolvedValue().get();
- // Get the existing values so we can merge the new values with them.
- Attribute currentAttribute = ta.getAttribute(on, ace.getJmxName());
- Object oldValue = (currentAttribute != null ? currentAttribute.getValue() : null);
- // Merge value with currentValue
- toBeMergedIn = merge(oldValue, toBeMergedIn);
- ta.setAttribute(on, ace.getJmxName(), new Attribute(ace.getJmxName(), toBeMergedIn));
- LOG.debug("Attribute {} set to {} for {}", configAttributeEntry.getKey(), toBeMergedIn, on);
- } catch (Exception e) {
- LOG.error("Error while merging objectnames of {}", on, e);
- throw new NetconfConfigHandlingException(String.format("Unable to set attributes for %s, Error with attribute %s : %s ",
- on,
- configAttributeEntry.getKey(),
- configAttributeEntry.getValue()),
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_failed,
- NetconfDocumentedException.ErrorSeverity.error);
- }
- }
- }
-
- /**
- * Merge value into current value
- * Currently, this is only implemented for arrays of ObjectNames, but that is the
- * most common case for which it is needed.
- */
- protected Object merge(Object oldValue, Object toBeMergedIn) {
- if (oldValue instanceof ObjectName[] && toBeMergedIn instanceof ObjectName[]) {
- toBeMergedIn = mergeObjectNameArrays((ObjectName[]) oldValue, (ObjectName[]) toBeMergedIn);
- }
- return toBeMergedIn;
- }
-
- /**
- * Merge value into current values
- * This implements for arrays of ObjectNames, but that is the
- * most common case for which it is needed.
- *
- * @param oldValue - the new values to be merged into existing values
- * @param toBeMergedIn - the existing values
- *
- * @return an ObjectName[] consisting the elements of currentValue with an elements from values not already present in currentValue added
- *
- */
- protected ObjectName[] mergeObjectNameArrays(ObjectName[] oldValue, ObjectName[] toBeMergedIn) {
- List<ObjectName> newValueList = new ArrayList<>();
- newValueList.addAll(asList(oldValue));
- /*
- It is guaranteed that old values do not contain transaction name.
- Since toBeMergedIn is filled using service references translated by ServiceRegistryWrapper, it
- is also guaranteed that this list will not contain transaction names.
- Run through the list of values to be merged. If we don't have them already, add them to the list.
- */
- for (ObjectName objName : toBeMergedIn) {
- if (!newValueList.contains(objName)) {
- newValueList.add(objName);
- }
- }
- return newValueList.toArray(new ObjectName[newValueList.size()]);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
-
-import java.util.Map;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.ObjectName;
-import org.opendaylight.controller.config.util.ConfigTransactionClient;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.confignetconfconnector.exception.NetconfConfigHandlingException;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ServiceRegistryWrapper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class MissingInstanceHandlingStrategy extends AbstractEditConfigStrategy {
-
- private static final Logger LOG = LoggerFactory.getLogger(MissingInstanceHandlingStrategy.class);
-
- @Override
- void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
- String module, String instance, ServiceRegistryWrapper services) throws NetconfConfigHandlingException {
- try {
- ObjectName on = ta.createModule(module, instance);
- LOG.trace("New instance for {} {} created under name {}", module, instance, on);
- } catch (InstanceAlreadyExistsException e1) {
- throw new NetconfConfigHandlingException(String.format("Unable to create instance for %s : %s.", module, instance),
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_failed,
- NetconfDocumentedException.ErrorSeverity.error);
- }
- }
-
- @Override
- void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
- ObjectName objectName, ServiceRegistryWrapper services) {
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
-
-import java.util.Collections;
-import java.util.Map;
-import org.opendaylight.controller.config.util.ConfigTransactionClient;
-import org.opendaylight.controller.netconf.confignetconfconnector.exception.NetconfConfigHandlingException;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ServiceRegistryWrapper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class NoneEditConfigStrategy implements EditConfigStrategy {
-
- private static final Logger LOG = LoggerFactory.getLogger(NoneEditConfigStrategy.class);
-
- @Override
- public void executeConfiguration(String module, String instance, Map<String, AttributeConfigElement> configuration,
- ConfigTransactionClient ta, ServiceRegistryWrapper services) throws NetconfConfigHandlingException {
- if(configuration != null && !configuration.isEmpty()) {
- for (Map.Entry<String, AttributeConfigElement> attrEntry : configuration.entrySet()) {
- if(attrEntry.getValue().getEditStrategy().isPresent()) {
- final Map<String, AttributeConfigElement> partialConfig =
- Collections.singletonMap(attrEntry.getKey(), attrEntry.getValue());
- attrEntry.getValue().getEditStrategy().get().getFittingStrategy()
- .executeConfiguration(module, instance, partialConfig, ta, services);
- } else {
- LOG.debug("Skipping configuration element for {}:{}:{}", module, instance, attrEntry.getKey());
- }
- }
- } else {
- LOG.debug("Skipping configuration element for {}:{}", module, instance);
- }
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
-
-import java.util.Map;
-import org.opendaylight.controller.config.util.ConfigTransactionClient;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ServiceRegistryWrapper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class RemoveEditConfigStrategy extends DeleteEditConfigStrategy {
-
- private static final Logger LOG = LoggerFactory.getLogger(RemoveEditConfigStrategy.class);
-
- @Override
- void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
- String module, String instance, ServiceRegistryWrapper services) {
- LOG.warn("Unable to delete {}:{}, ServiceInstance not found", module, instance);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
-
-import java.util.Map;
-import java.util.Map.Entry;
-import javax.management.Attribute;
-import javax.management.ObjectName;
-import org.opendaylight.controller.config.util.ConfigTransactionClient;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.confignetconfconnector.exception.NetconfConfigHandlingException;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ServiceRegistryWrapper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ReplaceEditConfigStrategy extends AbstractEditConfigStrategy {
-
- private static final Logger LOG = LoggerFactory.getLogger(ReplaceEditConfigStrategy.class);
-
- @Override
- void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
- String module, String instance, ServiceRegistryWrapper services) throws NetconfConfigHandlingException {
- throw new NetconfConfigHandlingException(
- String.format("Unable to handle missing instance, no missing instances should appear at this point, missing: %s : %s ",
- module,
- instance),
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_failed,
- NetconfDocumentedException.ErrorSeverity.error);
- }
-
- @Override
- void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on, ServiceRegistryWrapper services) throws NetconfConfigHandlingException {
- for (Entry<String, AttributeConfigElement> configAttributeEntry : configuration.entrySet()) {
- try {
- AttributeConfigElement ace = configAttributeEntry.getValue();
-
- if (!ace.getResolvedValue().isPresent()) {
- Object value = ace.getResolvedDefaultValue();
- ta.setAttribute(on, ace.getJmxName(), new Attribute(ace.getJmxName(), value));
- LOG.debug("Attribute {} set to default value {} for {}", configAttributeEntry.getKey(), value,
- on);
- } else {
- Object value = ace.getResolvedValue().get();
- ta.setAttribute(on, ace.getJmxName(), new Attribute(ace.getJmxName(), value));
- LOG.debug("Attribute {} set to value {} for {}", configAttributeEntry.getKey(), value, on);
- }
-
- } catch (Exception e) {
- throw new IllegalStateException("Unable to set attributes for " + on + ", Error with attribute "
- + configAttributeEntry.getKey() + ":" + configAttributeEntry.getValue(), e);
- }
- }
- }
-}
package org.opendaylight.controller.netconf.confignetconfconnector.operations.get;
-import com.google.common.collect.Maps;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import javax.management.ObjectName;
-import org.opendaylight.controller.config.util.ConfigRegistryClient;
-import org.opendaylight.controller.config.util.ConfigTransactionClient;
-import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
-import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.facade.xml.ConfigSubsystemFacade;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfig;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.runtime.InstanceRuntime;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.runtime.ModuleRuntime;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.runtime.Runtime;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.Datastore;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreContext;
-import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
-import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
-import org.opendaylight.controller.netconf.util.exception.UnexpectedElementException;
-import org.opendaylight.controller.netconf.util.exception.UnexpectedNamespaceException;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
public class Get extends AbstractConfigNetconfOperation {
- private final TransactionProvider transactionProvider;
- private final YangStoreContext yangStoreSnapshot;
private static final Logger LOG = LoggerFactory.getLogger(Get.class);
- public Get(final TransactionProvider transactionProvider, YangStoreContext yangStoreSnapshot, ConfigRegistryClient configRegistryClient,
- String netconfSessionIdForReporting) {
- super(configRegistryClient, netconfSessionIdForReporting);
- this.transactionProvider = transactionProvider;
- this.yangStoreSnapshot = yangStoreSnapshot;
+ public Get(final ConfigSubsystemFacade configSubsystemFacade, final String netconfSessionIdForReporting) {
+ super(configSubsystemFacade, netconfSessionIdForReporting);
}
- private Map<String, Map<String, ModuleRuntime>> createModuleRuntimes(ConfigRegistryClient configRegistryClient,
- Map<String, Map<String, ModuleMXBeanEntry>> mBeanEntries) {
- Map<String, Map<String, ModuleRuntime>> retVal = Maps.newHashMap();
-
- for (Map.Entry<String, Map<String, ModuleMXBeanEntry>> namespaceToModuleEntry : mBeanEntries.entrySet()) {
-
- Map<String, ModuleRuntime> innerMap = Maps.newHashMap();
- Map<String, ModuleMXBeanEntry> entriesFromNamespace = namespaceToModuleEntry.getValue();
- for (Map.Entry<String, ModuleMXBeanEntry> moduleToMXEntry : entriesFromNamespace.entrySet()) {
-
- ModuleMXBeanEntry mbe = moduleToMXEntry.getValue();
-
- Map<RuntimeBeanEntry, InstanceConfig> cache = Maps.newHashMap();
- RuntimeBeanEntry root = null;
- for (RuntimeBeanEntry rbe : mbe.getRuntimeBeans()) {
- cache.put(rbe, new InstanceConfig(configRegistryClient, rbe.getYangPropertiesToTypesMap(), mbe.getNullableDummyContainerName()));
- if (rbe.isRoot()){
- root = rbe;
- }
- }
-
- if (root == null){
- continue;
- }
-
- InstanceRuntime rootInstanceRuntime = createInstanceRuntime(root, cache);
- ModuleRuntime moduleRuntime = new ModuleRuntime(rootInstanceRuntime);
- innerMap.put(moduleToMXEntry.getKey(), moduleRuntime);
- }
-
- retVal.put(namespaceToModuleEntry.getKey(), innerMap);
- }
- return retVal;
- }
-
- private InstanceRuntime createInstanceRuntime(RuntimeBeanEntry root, Map<RuntimeBeanEntry, InstanceConfig> cache) {
- Map<String, InstanceRuntime> children = Maps.newHashMap();
- for (RuntimeBeanEntry child : root.getChildren()) {
- children.put(child.getJavaNamePrefix(), createInstanceRuntime(child, cache));
- }
-
- return new InstanceRuntime(cache.get(root), children, createJmxToYangMap(root.getChildren()));
- }
-
- private Map<String, String> createJmxToYangMap(List<RuntimeBeanEntry> children) {
- Map<String, String> jmxToYangNamesForChildRbe = Maps.newHashMap();
- for (RuntimeBeanEntry rbe : children) {
- jmxToYangNamesForChildRbe.put(rbe.getJavaNamePrefix(), rbe.getYangName());
- }
- return jmxToYangNamesForChildRbe;
- }
-
- private static void checkXml(XmlElement xml) throws UnexpectedElementException, UnexpectedNamespaceException, MissingNameSpaceException {
+ private static void checkXml(XmlElement xml) throws DocumentedException {
xml.checkName(XmlNetconfConstants.GET);
xml.checkNamespace(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
}
@Override
- protected Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws DocumentedException {
checkXml(xml);
-
- final ObjectName testTransaction = transactionProvider.getOrCreateReadTransaction();
- final ConfigTransactionClient registryClient = getConfigRegistryClient().getConfigTransactionClient(testTransaction);
-
- try {
- // Runtime beans are not parts of transactions and have to be queried against the central registry
- final Set<ObjectName> runtimeBeans = getConfigRegistryClient().lookupRuntimeBeans();
-
- final Set<ObjectName> configBeans = Datastore.getInstanceQueryStrategy(Datastore.running, transactionProvider)
- .queryInstances(getConfigRegistryClient());
-
- final Map<String, Map<String, ModuleRuntime>> moduleRuntimes = createModuleRuntimes(getConfigRegistryClient(),
- yangStoreSnapshot.getModuleMXBeanEntryMap());
- final Map<String, Map<String, ModuleConfig>> moduleConfigs = EditConfig.transformMbeToModuleConfigs(
- registryClient, yangStoreSnapshot.getModuleMXBeanEntryMap());
-
- final Runtime runtime = new Runtime(moduleRuntimes, moduleConfigs);
-
- final Element element = runtime.toXml(runtimeBeans, configBeans, document, yangStoreSnapshot.getEnumResolver());
-
- LOG.trace("{} operation successful", XmlNetconfConstants.GET);
-
- return element;
- } finally {
- transactionProvider.closeReadTransaction();
- }
+ final Element element = getConfigSubsystemFacade().get(document);
+ LOG.trace("{} operation successful", XmlNetconfConstants.GET);
+ return element;
}
}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.operations.getconfig;
-
-import java.util.Set;
-import javax.management.ObjectName;
-import org.opendaylight.controller.config.util.ConfigRegistryClient;
-import org.opendaylight.controller.config.util.ConfigTransactionClient;
-import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
-
-public class CandidateDatastoreQueryStrategy implements DatastoreQueryStrategy {
-
- private final TransactionProvider transactionProvider;
-
- public CandidateDatastoreQueryStrategy(TransactionProvider transactionProvider) {
- this.transactionProvider = transactionProvider;
- }
-
- @Override
- public Set<ObjectName> queryInstances(ConfigRegistryClient configRegistryClient) {
- ObjectName on = transactionProvider.getOrCreateTransaction();
- ConfigTransactionClient proxy = configRegistryClient.getConfigTransactionClient(on);
- return proxy.lookupConfigBeans();
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.operations.getconfig;
-
-import java.util.Set;
-import javax.management.ObjectName;
-import org.opendaylight.controller.config.util.ConfigRegistryClient;
-
-public interface DatastoreQueryStrategy {
-
- /**
- * @param configRegistryClient
- * @return
- */
- Set<ObjectName> queryInstances(ConfigRegistryClient configRegistryClient);
-
-}
package org.opendaylight.controller.netconf.confignetconfconnector.operations.getconfig;
import com.google.common.base.Optional;
-import java.util.Set;
-import javax.management.ObjectName;
-import org.opendaylight.controller.config.util.ConfigRegistryClient;
-import org.opendaylight.controller.config.util.ConfigTransactionClient;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.facade.xml.ConfigSubsystemFacade;
+import org.opendaylight.controller.config.facade.xml.Datastore;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ServiceRegistryWrapper;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.Datastore;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreContext;
-import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
-import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
-import org.opendaylight.controller.netconf.util.exception.UnexpectedElementException;
-import org.opendaylight.controller.netconf.util.exception.UnexpectedNamespaceException;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
public static final String GET_CONFIG = "get-config";
- private final YangStoreContext yangStoreSnapshot;
private final Optional<String> maybeNamespace;
- private final TransactionProvider transactionProvider;
-
private static final Logger LOG = LoggerFactory.getLogger(GetConfig.class);
- public GetConfig(YangStoreContext yangStoreSnapshot, Optional<String> maybeNamespace,
- TransactionProvider transactionProvider, ConfigRegistryClient configRegistryClient,
- String netconfSessionIdForReporting) {
- super(configRegistryClient, netconfSessionIdForReporting);
- this.yangStoreSnapshot = yangStoreSnapshot;
+ public GetConfig(final ConfigSubsystemFacade configSubsystemFacade, final Optional<String> maybeNamespace, final String netconfSessionIdForReporting) {
+ super(configSubsystemFacade, netconfSessionIdForReporting);
this.maybeNamespace = maybeNamespace;
- this.transactionProvider = transactionProvider;
}
- public static Datastore fromXml(XmlElement xml) throws UnexpectedNamespaceException, UnexpectedElementException, MissingNameSpaceException, NetconfDocumentedException {
+ public static Datastore fromXml(XmlElement xml) throws DocumentedException {
xml.checkName(GET_CONFIG);
xml.checkNamespace(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
}
- private Element getResponseInternal(final Document document, final ConfigRegistryClient configRegistryClient,
- final Datastore source) {
-
- final ConfigTransactionClient registryClient;
- // Read current state from a transaction, if running is source, then start new transaction just for reading
- // in case of candidate, get current transaction representing candidate
- if(source == Datastore.running) {
- final ObjectName readTx = transactionProvider.getOrCreateReadTransaction();
- registryClient = getConfigRegistryClient().getConfigTransactionClient(readTx);
- } else {
- registryClient = getConfigRegistryClient().getConfigTransactionClient(transactionProvider.getOrCreateTransaction());
- }
-
- try {
- Element dataElement = XmlUtil.createElement(document, XmlNetconfConstants.DATA_KEY, Optional.<String>absent());
- final Set<ObjectName> instances = Datastore.getInstanceQueryStrategy(source, this.transactionProvider)
- .queryInstances(configRegistryClient);
-
- final Config configMapping = new Config(EditConfig.transformMbeToModuleConfigs(registryClient,
- yangStoreSnapshot.getModuleMXBeanEntryMap()), yangStoreSnapshot.getEnumResolver());
-
- ServiceRegistryWrapper serviceTracker = new ServiceRegistryWrapper(registryClient);
- dataElement = configMapping.toXml(instances, this.maybeNamespace, document, dataElement, serviceTracker);
-
- LOG.trace("{} operation successful", GET_CONFIG);
-
- return dataElement;
- } finally {
- if(source == Datastore.running) {
- transactionProvider.closeReadTransaction();
- }
- }
- }
-
@Override
protected String getOperationName() {
return GET_CONFIG;
}
@Override
- public Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws NetconfDocumentedException {
- Datastore source;
- source = fromXml(xml);
- return getResponseInternal(document, getConfigRegistryClient(), source);
+ public Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws DocumentedException {
+ return getConfigSubsystemFacade().getConfiguration(document, fromXml(xml), maybeNamespace);
}
}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.operations.getconfig;
-
-import java.util.Set;
-import javax.management.ObjectName;
-import org.opendaylight.controller.config.util.ConfigRegistryClient;
-import org.opendaylight.controller.config.util.ConfigTransactionClient;
-import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
-
-public class RunningDatastoreQueryStrategy implements DatastoreQueryStrategy {
-
- private final TransactionProvider transactionProvider;
-
- public RunningDatastoreQueryStrategy(TransactionProvider transactionProvider) {
- this.transactionProvider = transactionProvider;
- }
-
- @Override
- public Set<ObjectName> queryInstances(ConfigRegistryClient configRegistryClient) {
- ObjectName on = transactionProvider.getOrCreateReadTransaction();
- ConfigTransactionClient proxy = configRegistryClient.getConfigTransactionClient(on);
- return proxy.lookupConfigBeans();
- }
-
-}
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-import java.util.Map;
-import javax.management.ObjectName;
-import javax.management.openmbean.OpenType;
-import org.opendaylight.controller.config.util.ConfigRegistryClient;
-import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
-import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
-import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry.Rpc;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.VoidAttribute;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.facade.xml.ConfigSubsystemFacade;
+import org.opendaylight.controller.config.facade.xml.RpcFacade;
+import org.opendaylight.controller.config.facade.xml.rpc.InstanceRuntimeRpc;
+import org.opendaylight.controller.config.facade.xml.rpc.ModuleRpcs;
+import org.opendaylight.controller.config.facade.xml.rpc.Rpcs;
+import org.opendaylight.controller.config.facade.xml.rpc.RuntimeRpcElementResolved;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.AttributeMappingStrategy;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.ObjectMapper;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.toxml.ObjectXmlWriter;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.rpc.InstanceRuntimeRpc;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.rpc.ModuleRpcs;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.rpc.Rpcs;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreContext;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
-import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
public class RuntimeRpc extends AbstractConfigNetconfOperation {
private static final Logger LOG = LoggerFactory.getLogger(RuntimeRpc.class);
- public static final String CONTEXT_INSTANCE = "context-instance";
- private final YangStoreContext yangStoreSnapshot;
-
- public RuntimeRpc(final YangStoreContext yangStoreSnapshot, ConfigRegistryClient configRegistryClient,
- String netconfSessionIdForReporting) {
- super(configRegistryClient, netconfSessionIdForReporting);
- this.yangStoreSnapshot = yangStoreSnapshot;
- }
-
- private Element toXml(Document doc, Object result, AttributeIfc returnType, String namespace, String elementName) throws NetconfDocumentedException {
- AttributeMappingStrategy<?, ? extends OpenType<?>> mappingStrategy = new ObjectMapper().prepareStrategy(returnType);
- Optional<?> mappedAttributeOpt = mappingStrategy.mapAttribute(result);
- Preconditions.checkState(mappedAttributeOpt.isPresent(), "Unable to map return value %s as %s", result, returnType.getOpenType());
-
- // FIXME: multiple return values defined as leaf-list and list in yang should not be wrapped in output xml element,
- // they need to be appended directly under rpc-reply element
- //
- // Either allow List of Elements to be returned from NetconfOperation or
- // pass reference to parent output xml element for netconf operations to
- // append result(s) on their own
- Element tempParent = XmlUtil.createElement(doc, "output", Optional.of(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0));
- new ObjectXmlWriter().prepareWritingStrategy(elementName, returnType, doc).writeElement(tempParent, namespace, mappedAttributeOpt.get());
-
- XmlElement xmlElement = XmlElement.fromDomElement(tempParent);
- return xmlElement.getChildElements().size() > 1 ? tempParent : xmlElement.getOnlyChildElement().getDomElement();
+ public RuntimeRpc(final ConfigSubsystemFacade configSubsystemFacade, final String netconfSessionIdForReporting) {
+ super(configSubsystemFacade, netconfSessionIdForReporting);
}
- private Object executeOperation(final ConfigRegistryClient configRegistryClient, final ObjectName on,
- final String name, final Map<String, AttributeConfigElement> attributes) {
- final Object[] params = new Object[attributes.size()];
- final String[] signature = new String[attributes.size()];
-
- int i = 0;
- for (final AttributeConfigElement attribute : attributes.values()) {
- final Optional<?> resolvedValueOpt = attribute.getResolvedValue();
-
- params[i] = resolvedValueOpt.isPresent() ? resolvedValueOpt.get() : attribute.getResolvedDefaultValue();
- signature[i] = resolvedValueOpt.isPresent() ? resolvedValueOpt.get().getClass().getName() : attribute
- .getResolvedDefaultValue().getClass().getName();
- i++;
- }
-
- return configRegistryClient.invokeMethod(on, name, params, signature);
- }
-
- public NetconfOperationExecution fromXml(final XmlElement xml) throws NetconfDocumentedException {
- final String namespace;
- try {
- namespace = xml.getNamespace();
- } catch (MissingNameSpaceException e) {
- LOG.trace("Can't get namespace from xml element due to ",e);
- throw NetconfDocumentedException.wrap(e);
- }
- final XmlElement contextInstanceElement = xml.getOnlyChildElement(CONTEXT_INSTANCE);
- final String operationName = xml.getName();
-
- final RuntimeRpcElementResolved id = RuntimeRpcElementResolved.fromXpath(
- contextInstanceElement.getTextContent(), operationName, namespace);
-
- final Rpcs rpcs = mapRpcs(yangStoreSnapshot.getModuleMXBeanEntryMap(), yangStoreSnapshot.getEnumResolver());
-
- final ModuleRpcs rpcMapping = rpcs.getRpcMapping(id);
- final InstanceRuntimeRpc instanceRuntimeRpc = rpcMapping.getRpc(id.getRuntimeBeanName(), operationName);
-
- // TODO move to Rpcs after xpath attribute is redesigned
-
- final ObjectName on = id.getObjectName(rpcMapping);
- Map<String, AttributeConfigElement> attributes = instanceRuntimeRpc.fromXml(xml);
- attributes = sortAttributes(attributes, xml);
-
- return new NetconfOperationExecution(on, instanceRuntimeRpc.getName(), attributes,
- instanceRuntimeRpc.getReturnType(), namespace);
- }
@Override
- public HandlingPriority canHandle(Document message) throws NetconfDocumentedException {
+ public HandlingPriority canHandle(Document message) throws DocumentedException {
XmlElement requestElement = null;
requestElement = getRequestElementWithCheck(message);
final String netconfOperationNamespace;
try {
netconfOperationNamespace = operationElement.getNamespace();
- } catch (MissingNameSpaceException e) {
+ } catch (DocumentedException e) {
LOG.debug("Cannot retrieve netconf operation namespace from message due to ", e);
return HandlingPriority.CANNOT_HANDLE;
}
final Optional<XmlElement> contextInstanceElement = operationElement
- .getOnlyChildElementOptionally(CONTEXT_INSTANCE);
+ .getOnlyChildElementOptionally(RpcFacade.CONTEXT_INSTANCE);
if (!contextInstanceElement.isPresent()){
return HandlingPriority.CANNOT_HANDLE;
.getTextContent(), netconfOperationName, netconfOperationNamespace);
// TODO reuse rpcs instance in fromXml method
- final Rpcs rpcs = mapRpcs(yangStoreSnapshot.getModuleMXBeanEntryMap(), yangStoreSnapshot.getEnumResolver());
+ final Rpcs rpcs = getConfigSubsystemFacade().getRpcFacade().mapRpcs();
try {
-
final ModuleRpcs rpcMapping = rpcs.getRpcMapping(id);
final InstanceRuntimeRpc instanceRuntimeRpc = rpcMapping.getRpc(id.getRuntimeBeanName(),
netconfOperationName);
Preconditions.checkState(instanceRuntimeRpc != null, "No rpc found for %s:%s", netconfOperationNamespace,
netconfOperationName);
-
} catch (IllegalStateException e) {
LOG.debug("Cannot handle runtime operation {}:{}", netconfOperationNamespace, netconfOperationName, e);
return HandlingPriority.CANNOT_HANDLE;
}
@Override
- protected Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws DocumentedException {
// TODO check for namespaces and unknown elements
- final NetconfOperationExecution execution = fromXml(xml);
+ final RpcFacade.OperationExecution execution = getConfigSubsystemFacade().getRpcFacade().fromXml(xml);
- LOG.debug("Invoking operation {} on {} with arguments {}", execution.operationName, execution.on,
- execution.attributes);
- final Object result = executeOperation(getConfigRegistryClient(), execution.on, execution.operationName,
- execution.attributes);
+ LOG.debug("Invoking operation {} on {} with arguments {}", execution.getOperationName(), execution.getOn(),
+ execution.getAttributes());
+ final Object result = getConfigSubsystemFacade().getRpcFacade().executeOperation(execution);
- LOG.trace("Operation {} called successfully on {} with arguments {} with result {}", execution.operationName,
- execution.on, execution.attributes, result);
+ LOG.trace("Operation {} called successfully on {} with arguments {} with result {}", execution.getOperationName(),
+ execution.getOn(), execution.getAttributes(), result);
if (execution.isVoid()) {
return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
} else {
- return toXml(document, result, execution.returnType, execution.namespace,
- execution.returnType.getAttributeYangName());
- }
- }
-
- private static class NetconfOperationExecution {
-
- private final ObjectName on;
- private final String operationName;
- private final Map<String, AttributeConfigElement> attributes;
- private final AttributeIfc returnType;
- private final String namespace;
-
- public NetconfOperationExecution(final ObjectName on, final String name,
- final Map<String, AttributeConfigElement> attributes, final AttributeIfc returnType, final String namespace) {
- this.on = on;
- this.operationName = name;
- this.attributes = attributes;
- this.returnType = returnType;
- this.namespace = namespace;
- }
-
- boolean isVoid() {
- return returnType == VoidAttribute.getInstance();
+ return getConfigSubsystemFacade().getRpcFacade().toXml(document, result, execution);
}
-
- }
-
- private static Map<String, AttributeConfigElement> sortAttributes(
- final Map<String, AttributeConfigElement> attributes, final XmlElement xml) {
- final Map<String, AttributeConfigElement> sorted = Maps.newLinkedHashMap();
-
- for (XmlElement xmlElement : xml.getChildElements()) {
- final String name = xmlElement.getName();
- if (!CONTEXT_INSTANCE.equals(name)) { // skip context
- // instance child node
- // because it
- // specifies
- // ObjectName
- final AttributeConfigElement value = attributes.get(name);
- if (value == null) {
- throw new IllegalArgumentException("Cannot find yang mapping for node " + xmlElement);
- }
- sorted.put(name, value);
- }
- }
-
- return sorted;
- }
-
- private static Rpcs mapRpcs(final Map<String, Map<String, ModuleMXBeanEntry>> mBeanEntries, final EnumResolver enumResolver) {
-
- final Map<String, Map<String, ModuleRpcs>> map = Maps.newHashMap();
-
- for (final Map.Entry<String, Map<String, ModuleMXBeanEntry>> namespaceToModuleEntry : mBeanEntries.entrySet()) {
-
- Map<String, ModuleRpcs> namespaceToModules = map.get(namespaceToModuleEntry.getKey());
- if (namespaceToModules == null) {
- namespaceToModules = Maps.newHashMap();
- map.put(namespaceToModuleEntry.getKey(), namespaceToModules);
- }
-
- for (final Map.Entry<String, ModuleMXBeanEntry> moduleEntry : namespaceToModuleEntry.getValue().entrySet()) {
-
- ModuleRpcs rpcMapping = namespaceToModules.get(moduleEntry.getKey());
- if (rpcMapping == null) {
- rpcMapping = new ModuleRpcs(enumResolver);
- namespaceToModules.put(moduleEntry.getKey(), rpcMapping);
- }
-
- final ModuleMXBeanEntry entry = moduleEntry.getValue();
-
- for (final RuntimeBeanEntry runtimeEntry : entry.getRuntimeBeans()) {
- rpcMapping.addNameMapping(runtimeEntry);
- for (final Rpc rpc : runtimeEntry.getRpcs()) {
- rpcMapping.addRpc(runtimeEntry, rpc);
- }
- }
- }
- }
-
- return new Rpcs(map);
}
}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.operations.runtimerpc;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
-import com.google.common.collect.Maps;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import javax.management.ObjectName;
-import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.rpc.ModuleRpcs;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.Modules;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.modules.Module;
-
-/**
- * Represents parsed xpath to runtime bean instance
- */
-public final class RuntimeRpcElementResolved {
- private final String moduleName;
- private final String instanceName;
- private final String namespace;
- private final String runtimeBeanName;
- private final Map<String, String> additionalAttributes;
-
- private RuntimeRpcElementResolved(String namespace, String moduleName, String instanceName, String runtimeBeanName,
- Map<String, String> additionalAttributes) {
- this.moduleName = Preconditions.checkNotNull(moduleName, "Module name");
- this.instanceName = Preconditions.checkNotNull(instanceName, "Instance name");
- this.additionalAttributes = additionalAttributes;
- this.namespace = Preconditions.checkNotNull(namespace, "Namespace");
- this.runtimeBeanName = Preconditions.checkNotNull(runtimeBeanName, "Runtime bean name");
- }
-
- public String getModuleName() {
- return moduleName;
- }
-
- @VisibleForTesting
- Map<String, String> getAdditionalAttributes() {
- return additionalAttributes;
- }
-
- public String getInstanceName() {
- return instanceName;
- }
-
- public String getNamespace() {
- return namespace;
- }
-
- public String getRuntimeBeanName() {
- return runtimeBeanName;
- }
-
- public ObjectName getObjectName(ModuleRpcs rpcMapping) {
- Map<String, String> additionalAttributesJavaNames = Maps
- .newHashMapWithExpectedSize(additionalAttributes.size());
- for (String attributeYangName : additionalAttributes.keySet()) {
- String attributeJavaName = rpcMapping.getRbeJavaName(attributeYangName);
- Preconditions.checkState(attributeJavaName != null,
- "Cannot find java name for runtime bean wtih yang name %s", attributeYangName);
- additionalAttributesJavaNames.put(attributeJavaName, additionalAttributes.get(attributeYangName));
- }
- return ObjectNameUtil.createRuntimeBeanName(moduleName, instanceName, additionalAttributesJavaNames);
- }
-
- /**
- * Pattern for an absolute instance identifier xpath pointing to a runtime bean instance e.g:
- * <pre>
- * /modules/module[name=instanceName][type=moduleType]
- * </pre>
- * or
- * <pre>
- * /a:modules/a:module[a:name=instanceName][a:type=moduleType]
- * </pre>
- */
- private static final String xpathPatternBlueprint =
- "/" + getRegExForPrefixedName(Modules.QNAME.getLocalName())+ "/" + getRegExForPrefixedName(Module.QNAME.getLocalName())
-
- + "\\["
- + "(?<key1>" + getRegExForPrefixedName(XmlNetconfConstants.TYPE_KEY) + "|" + getRegExForPrefixedName(XmlNetconfConstants.NAME_KEY) + ")"
- + "=('|\")?(?<value1>[^'\"\\]]+)('|\")?"
- + "( and |\\]\\[)"
- + "(?<key2>" + getRegExForPrefixedName(XmlNetconfConstants.TYPE_KEY) + "|" + getRegExForPrefixedName(XmlNetconfConstants.NAME_KEY) + ")"
- + "=('|\")?(?<value2>[^'\"\\]]+)('|\")?"
- + "\\]"
-
- + "(?<additional>.*)";
-
- /**
- * Return reg ex that matches either the name with or without a prefix
- */
- private static String getRegExForPrefixedName(final String name) {
- return "([^:]+:)?" + name;
- }
-
- private static final Pattern xpathPattern = Pattern.compile(xpathPatternBlueprint);
-
- /**
- * Pattern for additional path elements inside xpath for instance identifier pointing to an inner runtime bean e.g:
- * <pre>
- * /modules/module[name=instanceName and type=moduleType]/inner[key=b]
- * </pre>
- */
- private static final String additionalPatternBlueprint = getRegExForPrefixedName("(?<additionalKey>.+)") + "\\[(?<prefixedKey>" + getRegExForPrefixedName("(.+)") + ")=('|\")?(?<additionalValue>[^'\"\\]]+)('|\")?\\]";
- private static final Pattern additionalPattern = Pattern.compile(additionalPatternBlueprint);
-
- public static RuntimeRpcElementResolved fromXpath(String xpath, String elementName, String namespace) {
- Matcher matcher = xpathPattern.matcher(xpath);
- Preconditions.checkState(matcher.matches(),
- "Node %s with value '%s' not in required form on rpc element %s, required format is %s",
- RuntimeRpc.CONTEXT_INSTANCE, xpath, elementName, xpathPatternBlueprint);
-
- PatternGroupResolver groups = new PatternGroupResolver(matcher.group("key1"), matcher.group("value1"),
- matcher.group("value2"), matcher.group("additional"));
-
- String moduleName = groups.getModuleName();
- String instanceName = groups.getInstanceName();
-
- Map<String, String> additionalAttributes = groups.getAdditionalKeys(elementName, moduleName);
-
- return new RuntimeRpcElementResolved(namespace, moduleName, instanceName, groups.getRuntimeBeanYangName(),
- additionalAttributes);
- }
-
- private static final class PatternGroupResolver {
-
- private final String key1, value1, value2;
- private final String additional;
- private String runtimeBeanYangName;
-
- PatternGroupResolver(String key1, String value1, String value2, String additional) {
- this.key1 = Preconditions.checkNotNull(key1);
- this.value1 = Preconditions.checkNotNull(value1);
- this.value2 = Preconditions.checkNotNull(value2);
- this.additional = Preconditions.checkNotNull(additional);
- }
-
- String getModuleName() {
- return key1.contains(XmlNetconfConstants.TYPE_KEY) ? value1 : value2;
- }
-
- String getInstanceName() {
- return key1.contains(XmlNetconfConstants.NAME_KEY) ? value1 : value2;
- }
-
-
- Map<String, String> getAdditionalKeys(String elementName, String moduleName) {
- HashMap<String, String> additionalAttributes = Maps.newHashMap();
-
- runtimeBeanYangName = moduleName;
- for (String additionalKeyValue : additional.split("/")) {
- if (Strings.isNullOrEmpty(additionalKeyValue)){
- continue;
- }
- Matcher matcher = additionalPattern.matcher(additionalKeyValue);
- Preconditions
- .checkState(
- matcher.matches(),
- "Attribute %s not in required form on rpc element %s, required format for additional attributes is: %s",
- additionalKeyValue, elementName, additionalPatternBlueprint);
- String name = matcher.group("additionalKey");
- runtimeBeanYangName = name;
- additionalAttributes.put(name, matcher.group("additionalValue"));
- }
- return additionalAttributes;
- }
-
- private String getRuntimeBeanYangName() {
- Preconditions.checkState(runtimeBeanYangName!=null);
- return runtimeBeanYangName;
- }
- }
-}
package org.opendaylight.controller.netconf.confignetconfconnector.osgi;
-import static com.google.common.base.Preconditions.checkState;
-
import java.util.Dictionary;
import java.util.Hashtable;
+import org.opendaylight.controller.config.facade.xml.ConfigSubsystemFacadeFactory;
import org.opendaylight.controller.netconf.api.util.NetconfConstants;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
-import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
-import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
private static final Logger LOG = LoggerFactory.getLogger(Activator.class);
- private BundleContext context;
private ServiceRegistration<?> osgiRegistration;
- private ConfigRegistryLookupThread configRegistryLookup = null;
@Override
public void start(final BundleContext context) throws Exception {
- this.context = context;
+ ServiceTrackerCustomizer<ConfigSubsystemFacadeFactory, ConfigSubsystemFacadeFactory> schemaServiceTrackerCustomizer = new ServiceTrackerCustomizer<ConfigSubsystemFacadeFactory, ConfigSubsystemFacadeFactory>() {
- ServiceTrackerCustomizer<SchemaContextProvider, ConfigRegistryLookupThread> customizer = new ServiceTrackerCustomizer<SchemaContextProvider, ConfigRegistryLookupThread>() {
@Override
- public ConfigRegistryLookupThread addingService(ServiceReference<SchemaContextProvider> reference) {
- LOG.debug("Got addingService(SchemaContextProvider) event, starting ConfigRegistryLookupThread");
- checkState(configRegistryLookup == null, "More than one onYangStoreAdded received");
-
- SchemaContextProvider schemaContextProvider = reference.getBundle().getBundleContext().getService(reference);
-
- YangStoreService yangStoreService = new YangStoreService(schemaContextProvider, context);
- configRegistryLookup = new ConfigRegistryLookupThread(yangStoreService);
- configRegistryLookup.start();
- return configRegistryLookup;
+ public ConfigSubsystemFacadeFactory addingService(ServiceReference<ConfigSubsystemFacadeFactory> reference) {
+ LOG.debug("Got addingService(SchemaContextProvider) event");
+ // Yang store service should not be registered multiple times
+ ConfigSubsystemFacadeFactory configSubsystemFacade = reference.getBundle().getBundleContext().getService(reference);
+ osgiRegistration = startNetconfServiceFactory(configSubsystemFacade, context);
+ return configSubsystemFacade;
}
@Override
- public void modifiedService(ServiceReference<SchemaContextProvider> reference, ConfigRegistryLookupThread configRegistryLookup) {
- LOG.debug("Got modifiedService(SchemaContextProvider) event");
- final BindingRuntimeContext runtimeContext = (BindingRuntimeContext) reference.getProperty(BindingRuntimeContext.class.getName());
- LOG.debug("BindingRuntimeContext retrieved as {}", runtimeContext);
- configRegistryLookup.yangStoreService.refresh(runtimeContext);
-
+ public void modifiedService(ServiceReference<ConfigSubsystemFacadeFactory> reference, ConfigSubsystemFacadeFactory service) {
+ LOG.warn("Config manager facade was modified unexpectedly");
}
@Override
- public void removedService(ServiceReference<SchemaContextProvider> reference, ConfigRegistryLookupThread configRegistryLookup) {
- configRegistryLookup.interrupt();
- if (osgiRegistration != null) {
- osgiRegistration.unregister();
- }
- osgiRegistration = null;
- Activator.this.configRegistryLookup = null;
+ public void removedService(ServiceReference<ConfigSubsystemFacadeFactory> reference, ConfigSubsystemFacadeFactory service) {
+ LOG.warn("Config manager facade was removed unexpectedly");
}
};
- ServiceTracker<SchemaContextProvider, ConfigRegistryLookupThread> listenerTracker = new ServiceTracker<>(context, SchemaContextProvider.class, customizer);
- listenerTracker.open();
+ ServiceTracker<ConfigSubsystemFacadeFactory, ConfigSubsystemFacadeFactory> schemaContextProviderServiceTracker =
+ new ServiceTracker<>(context, ConfigSubsystemFacadeFactory.class, schemaServiceTrackerCustomizer);
+ schemaContextProviderServiceTracker.open();
}
@Override
- public void stop(BundleContext context) {
- if (configRegistryLookup != null) {
- configRegistryLookup.interrupt();
+ public void stop(final BundleContext bundleContext) throws Exception {
+ if (osgiRegistration != null) {
+ osgiRegistration.unregister();
}
}
- private class ConfigRegistryLookupThread extends Thread {
- private final YangStoreService yangStoreService;
-
- private ConfigRegistryLookupThread(YangStoreService yangStoreService) {
- super("config-registry-lookup");
- this.yangStoreService = yangStoreService;
- }
-
- @Override
- public void run() {
- NetconfOperationServiceFactoryImpl factory = new NetconfOperationServiceFactoryImpl(yangStoreService);
- LOG.debug("Registering into OSGi");
- Dictionary<String, String> properties = new Hashtable<>();
- properties.put(NetconfConstants.SERVICE_NAME, NetconfConstants.CONFIG_NETCONF_CONNECTOR);
- osgiRegistration = context.registerService(NetconfOperationServiceFactory.class, factory, properties);
- }
+ private ServiceRegistration<NetconfOperationServiceFactory> startNetconfServiceFactory(final ConfigSubsystemFacadeFactory configSubsystemFacade, final BundleContext context) {
+ final NetconfOperationServiceFactoryImpl netconfOperationServiceFactory = new NetconfOperationServiceFactoryImpl(configSubsystemFacade);
+ // Add properties to autowire with netconf-impl instance for cfg subsystem
+ final Dictionary<String, String> properties = new Hashtable<>();
+ properties.put(NetconfConstants.SERVICE_NAME, NetconfConstants.CONFIG_NETCONF_CONNECTOR);
+ return context.registerService(NetconfOperationServiceFactory.class, netconfOperationServiceFactory, properties);
}
+
}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.osgi;
-
-public interface EnumResolver {
-
- String fromYang(String enumType, String enumYangValue);
-
- String toYang(String enumType, String enumJavaValue);
-}
import com.google.common.base.Optional;
import com.google.common.collect.Sets;
import java.util.Set;
-import org.opendaylight.controller.config.util.ConfigRegistryClient;
+import org.opendaylight.controller.config.facade.xml.ConfigSubsystemFacade;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.Commit;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.DiscardChanges;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.Lock;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.get.Get;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.getconfig.GetConfig;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.runtimerpc.RuntimeRpc;
-import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
final class NetconfOperationProvider {
private final Set<NetconfOperation> operations;
- NetconfOperationProvider(YangStoreContext yangStoreSnapshot, ConfigRegistryClient configRegistryClient,
- TransactionProvider transactionProvider, String netconfSessionIdForReporting) {
+ NetconfOperationProvider(final ConfigSubsystemFacade configSubsystemFacade, final String netconfSessionIdForReporting) {
- operations = setUpOperations(yangStoreSnapshot, configRegistryClient, transactionProvider,
- netconfSessionIdForReporting);
+ operations = setUpOperations(configSubsystemFacade, netconfSessionIdForReporting);
}
Set<NetconfOperation> getOperations() {
return operations;
}
- private static Set<NetconfOperation> setUpOperations(YangStoreContext yangStoreSnapshot,
- ConfigRegistryClient configRegistryClient, TransactionProvider transactionProvider,
+ private static Set<NetconfOperation> setUpOperations(final ConfigSubsystemFacade configSubsystemFacade,
String netconfSessionIdForReporting) {
Set<NetconfOperation> ops = Sets.newHashSet();
- GetConfig getConfigOp = new GetConfig(yangStoreSnapshot, Optional.<String> absent(), transactionProvider,
- configRegistryClient, netconfSessionIdForReporting);
+ GetConfig getConfigOp = new GetConfig(configSubsystemFacade, Optional.<String> absent(), netconfSessionIdForReporting);
ops.add(getConfigOp);
- ops.add(new EditConfig(yangStoreSnapshot, transactionProvider, configRegistryClient,
- netconfSessionIdForReporting));
- ops.add(new Commit(transactionProvider, configRegistryClient, netconfSessionIdForReporting));
+ ops.add(new EditConfig(configSubsystemFacade, netconfSessionIdForReporting));
+ ops.add(new Commit(configSubsystemFacade, netconfSessionIdForReporting));
ops.add(new Lock(netconfSessionIdForReporting));
ops.add(new UnLock(netconfSessionIdForReporting));
- ops.add(new Get(transactionProvider, yangStoreSnapshot, configRegistryClient, netconfSessionIdForReporting));
- ops.add(new DiscardChanges(transactionProvider, configRegistryClient, netconfSessionIdForReporting));
- ops.add(new Validate(transactionProvider, configRegistryClient, netconfSessionIdForReporting));
- ops.add(new RuntimeRpc(yangStoreSnapshot, configRegistryClient, netconfSessionIdForReporting));
+ ops.add(new Get(configSubsystemFacade, netconfSessionIdForReporting));
+ ops.add(new DiscardChanges(configSubsystemFacade, netconfSessionIdForReporting));
+ ops.add(new Validate(configSubsystemFacade, netconfSessionIdForReporting));
+ ops.add(new RuntimeRpc(configSubsystemFacade, netconfSessionIdForReporting));
return ops;
}
package org.opendaylight.controller.netconf.confignetconfconnector.osgi;
-import java.lang.management.ManagementFactory;
-import java.util.HashSet;
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Sets;
import java.util.Set;
-import javax.management.MBeanServer;
-import org.opendaylight.controller.config.util.ConfigRegistryJMXClient;
-import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.config.facade.xml.ConfigSubsystemFacadeFactory;
+import org.opendaylight.controller.config.util.capability.Capability;
+import org.opendaylight.controller.config.util.capability.ModuleListener;
+import org.opendaylight.controller.config.util.capability.YangModuleCapability;
import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
-import org.opendaylight.controller.netconf.util.capability.BasicCapability;
-import org.opendaylight.controller.netconf.util.capability.YangModuleCapability;
import org.opendaylight.yangtools.yang.model.api.Module;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
public class NetconfOperationServiceFactoryImpl implements NetconfOperationServiceFactory {
- public static final int ATTEMPT_TIMEOUT_MS = 1000;
- private static final int SILENT_ATTEMPTS = 30;
+ private final ConfigSubsystemFacadeFactory configFacadeFactory;
- private final YangStoreService yangStoreService;
- private final ConfigRegistryJMXClient jmxClient;
-
- private static final Logger LOG = LoggerFactory.getLogger(NetconfOperationServiceFactoryImpl.class);
-
- public NetconfOperationServiceFactoryImpl(YangStoreService yangStoreService) {
- this(yangStoreService, ManagementFactory.getPlatformMBeanServer());
- }
-
- public NetconfOperationServiceFactoryImpl(YangStoreService yangStoreService, MBeanServer mBeanServer) {
- this.yangStoreService = yangStoreService;
-
- ConfigRegistryJMXClient configRegistryJMXClient;
- int i = 0;
- // Config registry might not be present yet, but will be eventually
- while(true) {
-
- try {
- configRegistryJMXClient = new ConfigRegistryJMXClient(mBeanServer);
- break;
- } catch (IllegalStateException e) {
- ++i;
- if (i > SILENT_ATTEMPTS) {
- LOG.info("JMX client not created after {} attempts, still trying", i, e);
- } else {
- LOG.debug("JMX client could not be created, reattempting, try {}", i, e);
- }
- try {
- Thread.sleep(ATTEMPT_TIMEOUT_MS);
- } catch (InterruptedException e1) {
- Thread.currentThread().interrupt();
- throw new IllegalStateException("Interrupted while reattempting connection", e1);
- }
- }
- }
-
- jmxClient = configRegistryJMXClient;
- if (i > SILENT_ATTEMPTS) {
- LOG.info("Created JMX client after {} attempts", i);
- } else {
- LOG.debug("Created JMX client after {} attempts", i);
- }
+ public NetconfOperationServiceFactoryImpl(ConfigSubsystemFacadeFactory configFacadeFactory) {
+ this.configFacadeFactory = configFacadeFactory;
}
@Override
public NetconfOperationServiceImpl createService(String netconfSessionIdForReporting) {
- return new NetconfOperationServiceImpl(yangStoreService, jmxClient, netconfSessionIdForReporting);
+ return new NetconfOperationServiceImpl(configFacadeFactory.createFacade(netconfSessionIdForReporting), netconfSessionIdForReporting);
}
-
@Override
public Set<Capability> getCapabilities() {
- return setupCapabilities(yangStoreService);
+ return configFacadeFactory.getCurrentCapabilities();
}
@Override
public AutoCloseable registerCapabilityListener(final CapabilityListener listener) {
- return yangStoreService.registerCapabilityListener(listener);
+ return configFacadeFactory.getYangStoreService().registerModuleListener(new ModuleListener() {
+ @Override
+ public void onCapabilitiesChanged(Set<Module> added, Set<Module> removed) {
+ listener.onCapabilitiesChanged(
+ transformModulesToCapabilities(added), transformModulesToCapabilities(removed));
+ }
+ });
}
- public static Set<Capability> setupCapabilities(final YangStoreContext yangStoreSnapshot) {
- Set<Capability> capabilities = new HashSet<>();
- // [RFC6241] 8.3. Candidate Configuration Capability
- capabilities.add(new BasicCapability("urn:ietf:params:netconf:capability:candidate:1.0"));
-
- // TODO rollback on error not supported EditConfigXmlParser:100
- // [RFC6241] 8.5. Rollback-on-Error Capability
- // capabilities.add(new BasicCapability("urn:ietf:params:netconf:capability:rollback-on-error:1.0"));
-
- Set<Module> modules = yangStoreSnapshot.getModules();
- for (Module module : modules) {
- capabilities.add(new YangModuleCapability(module, yangStoreSnapshot.getModuleSource(module)));
+ private static final Function<Module, Capability> MODULE_TO_CAPABILITY = new Function<Module, Capability>() {
+ @Override
+ public Capability apply(final Module module) {
+ return new YangModuleCapability(module, module.getSource());
}
+ };
- return capabilities;
+ public static Set<Capability> transformModulesToCapabilities(Set<Module> modules) {
+ return Sets.newHashSet(Collections2.transform(modules, MODULE_TO_CAPABILITY));
}
}
package org.opendaylight.controller.netconf.confignetconfconnector.osgi;
import java.util.Set;
-import org.opendaylight.controller.config.util.ConfigRegistryJMXClient;
-import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
+import org.opendaylight.controller.config.facade.xml.ConfigSubsystemFacade;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
-/**
- * Manages life cycle of {@link YangStoreContext}.
- */
public class NetconfOperationServiceImpl implements NetconfOperationService {
private final NetconfOperationProvider operationProvider;
- private final TransactionProvider transactionProvider;
+ private ConfigSubsystemFacade configSubsystemFacade;
- public NetconfOperationServiceImpl(final YangStoreService yangStoreService, final ConfigRegistryJMXClient jmxClient,
+ public NetconfOperationServiceImpl(final ConfigSubsystemFacade configSubsystemFacade,
final String netconfSessionIdForReporting) {
-
- transactionProvider = new TransactionProvider(jmxClient, netconfSessionIdForReporting);
- operationProvider = new NetconfOperationProvider(yangStoreService, jmxClient, transactionProvider,
- netconfSessionIdForReporting);
+ this.configSubsystemFacade = configSubsystemFacade;
+ operationProvider = new NetconfOperationProvider(configSubsystemFacade, netconfSessionIdForReporting);
}
@Override
@Override
public void close() {
- transactionProvider.close();
+ configSubsystemFacade.close();
}
}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.netconf.confignetconfconnector.osgi;
-
-import java.util.Map;
-import java.util.Set;
-import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
-
-public interface YangStoreContext {
-
- /**
- * @deprecated Use {@link #getQNamesToIdentitiesToModuleMXBeanEntries()} instead. This method return only one
- * module representation even if multiple revisions are available.
- */
- @Deprecated
- Map<String/* Namespace from yang file */,
- Map<String /* Name of module entry from yang file */, ModuleMXBeanEntry>> getModuleMXBeanEntryMap();
-
-
- Map<QName, Map<String /* identity local name */, ModuleMXBeanEntry>> getQNamesToIdentitiesToModuleMXBeanEntries();
-
- /**
- * Get all modules discovered when this snapshot was created.
- * @return all modules discovered. If one module exists with two different revisions, return both.
- */
- Set<Module> getModules();
-
- String getModuleSource(ModuleIdentifier moduleIdentifier);
-
- EnumResolver getEnumResolver();
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.osgi;
-
-import com.google.common.base.Function;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import java.lang.ref.SoftReference;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.atomic.AtomicReference;
-import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
-import org.opendaylight.controller.netconf.api.Capability;
-import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
-import org.opendaylight.controller.netconf.notifications.BaseNetconfNotificationListener;
-import org.opendaylight.controller.netconf.notifications.BaseNotificationPublisherRegistration;
-import org.opendaylight.controller.netconf.notifications.NetconfNotificationCollector;
-import org.opendaylight.controller.netconf.util.capability.YangModuleCapability;
-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.netconf.notifications.rev120206.NetconfCapabilityChange;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChangeBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.changed.by.parms.ChangedByBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.changed.by.parms.changed.by.server.or.user.ServerBuilder;
-import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
-import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-import org.osgi.util.tracker.ServiceTracker;
-import org.osgi.util.tracker.ServiceTrackerCustomizer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class YangStoreService implements YangStoreContext {
-
- private static final Logger LOG = LoggerFactory.getLogger(YangStoreService.class);
-
- /**
- * This is a rather interesting locking model. We need to guard against both the
- * cache expiring from GC and being invalidated by schema context change. The
- * context can change while we are doing processing, so we do not want to block
- * it, so no synchronization can happen on the methods.
- *
- * So what we are doing is the following:
- *
- * We synchronize with GC as usual, using a SoftReference.
- *
- * The atomic reference is used to synchronize with {@link #refresh(org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext)}, e.g. when
- * refresh happens, it will push a SoftReference(null), e.g. simulate the GC. Now
- * that may happen while the getter is already busy acting on the old schema context,
- * so it needs to understand that a refresh has happened and retry. To do that, it
- * attempts a CAS operation -- if it fails, in knows that the SoftReference has
- * been replaced and thus it needs to retry.
- *
- * Note that {@link #getYangStoreSnapshot()} will still use synchronize() internally
- * to stop multiple threads doing the same work.
- */
- private final AtomicReference<SoftReference<YangStoreSnapshot>> ref =
- new AtomicReference<>(new SoftReference<YangStoreSnapshot>(null));
-
- private final AtomicReference<SoftReference<BindingRuntimeContext>> refBindingContext =
- new AtomicReference<>(new SoftReference<BindingRuntimeContext>(null));
-
- private final SchemaContextProvider schemaContextProvider;
- private final BaseNetconfNotificationListener notificationPublisher;
-
- private final ExecutorService notificationExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() {
- @Override
- public Thread newThread(final Runnable r) {
- return new Thread(r, "config-netconf-connector-capability-notifications");
- }
- });
-
- private final Set<CapabilityListener> listeners = Collections.synchronizedSet(new HashSet<CapabilityListener>());
-
- public YangStoreService(final SchemaContextProvider schemaContextProvider, final BundleContext context) {
- this(schemaContextProvider, new NotificationCollectorTracker(context));
- }
-
- public YangStoreService(final SchemaContextProvider schemaContextProvider, final BaseNetconfNotificationListener notificationHandler) {
- this.schemaContextProvider = schemaContextProvider;
- this.notificationPublisher = notificationHandler;
- }
-
- private synchronized YangStoreContext getYangStoreSnapshot() {
- SoftReference<YangStoreSnapshot> r = ref.get();
- YangStoreSnapshot ret = r.get();
-
- while (ret == null) {
- // We need to be compute a new value
- ret = new YangStoreSnapshot(schemaContextProvider.getSchemaContext(), refBindingContext.get().get());
-
- if (!ref.compareAndSet(r, new SoftReference<>(ret))) {
- LOG.debug("Concurrent refresh detected, recomputing snapshot");
- r = ref.get();
- ret = null;
- }
- }
-
- return ret;
- }
-
- @Override
- public Map<String, Map<String, ModuleMXBeanEntry>> getModuleMXBeanEntryMap() {
- return getYangStoreSnapshot().getModuleMXBeanEntryMap();
- }
-
- @Override
- public Map<QName, Map<String, ModuleMXBeanEntry>> getQNamesToIdentitiesToModuleMXBeanEntries() {
- return getYangStoreSnapshot().getQNamesToIdentitiesToModuleMXBeanEntries();
- }
-
- @Override
- public Set<Module> getModules() {
- return getYangStoreSnapshot().getModules();
- }
-
- @Override
- public String getModuleSource(final ModuleIdentifier moduleIdentifier) {
- return getYangStoreSnapshot().getModuleSource(moduleIdentifier);
- }
-
- @Override
- public EnumResolver getEnumResolver() {
- return getYangStoreSnapshot().getEnumResolver();
- }
-
- public void refresh(final BindingRuntimeContext runtimeContext) {
- final YangStoreSnapshot previous = ref.get().get();
- ref.set(new SoftReference<YangStoreSnapshot>(null));
- refBindingContext.set(new SoftReference<>(runtimeContext));
- notificationExecutor.submit(new CapabilityChangeNotifier(previous));
- }
-
- public AutoCloseable registerCapabilityListener(final CapabilityListener listener) {
-
- YangStoreContext context = ref.get().get();
-
- if(context == null) {
- context = getYangStoreSnapshot();
- }
-
- this.listeners.add(listener);
- listener.onCapabilitiesAdded(NetconfOperationServiceFactoryImpl.setupCapabilities(context));
-
- return new AutoCloseable() {
- @Override
- public void close() throws Exception {
- YangStoreService.this.listeners.remove(listener);
- }
- };
- }
-
- private static final Function<Module, Capability> MODULE_TO_CAPABILITY = new Function<Module, Capability>() {
- @Override
- public Capability apply(final Module module) {
- return new YangModuleCapability(module, module.getSource());
- }
- };
-
- private final class CapabilityChangeNotifier implements Runnable {
-
- private final YangStoreSnapshot previous;
-
- public CapabilityChangeNotifier(final YangStoreSnapshot previous) {
- this.previous = previous;
- }
-
- @Override
- public void run() {
- final YangStoreContext current = getYangStoreSnapshot();
-
- if(current.equals(previous) == false) {
- final Sets.SetView<Module> removed = Sets.difference(previous.getModules(), current.getModules());
- final Sets.SetView<Module> added = Sets.difference(current.getModules(), previous.getModules());
-
- // Notify notification manager
- notificationPublisher.onCapabilityChanged(computeDiff(removed, added));
-
- // Notify direct capability listener TODO would it not be better if the capability listeners went through notification manager ?
- for (final CapabilityListener listener : listeners) {
- listener.onCapabilitiesAdded(Sets.newHashSet(Collections2.transform(added, MODULE_TO_CAPABILITY)));
- }
- for (final CapabilityListener listener : listeners) {
- listener.onCapabilitiesRemoved(Sets.newHashSet(Collections2.transform(removed, MODULE_TO_CAPABILITY)));
- }
- }
- }
- }
-
- private static final Function<Module, Uri> MODULE_TO_URI = new Function<Module, Uri>() {
- @Override
- public Uri apply(final Module input) {
- return new Uri(new YangModuleCapability(input, input.getSource()).getCapabilityUri());
- }
- };
-
- static NetconfCapabilityChange computeDiff(final Sets.SetView<Module> removed, final Sets.SetView<Module> added) {
- final NetconfCapabilityChangeBuilder netconfCapabilityChangeBuilder = new NetconfCapabilityChangeBuilder();
- netconfCapabilityChangeBuilder.setChangedBy(new ChangedByBuilder().setServerOrUser(new ServerBuilder().setServer(true).build()).build());
- netconfCapabilityChangeBuilder.setDeletedCapability(Lists.newArrayList(Collections2.transform(removed, MODULE_TO_URI)));
- netconfCapabilityChangeBuilder.setAddedCapability(Lists.newArrayList(Collections2.transform(added, MODULE_TO_URI)));
- // TODO modified should be computed ... but why ?
- netconfCapabilityChangeBuilder.setModifiedCapability(Collections.<Uri>emptyList());
- return netconfCapabilityChangeBuilder.build();
- }
-
-
- /**
- * Looks for NetconfNotificationCollector service and publishes base netconf notifications if possible
- */
- private static class NotificationCollectorTracker implements ServiceTrackerCustomizer<NetconfNotificationCollector, NetconfNotificationCollector>, BaseNetconfNotificationListener, AutoCloseable {
-
- private final BundleContext context;
- private final ServiceTracker<NetconfNotificationCollector, NetconfNotificationCollector> listenerTracker;
- private BaseNotificationPublisherRegistration publisherReg;
-
- public NotificationCollectorTracker(final BundleContext context) {
- this.context = context;
- listenerTracker = new ServiceTracker<>(context, NetconfNotificationCollector.class, this);
- listenerTracker.open();
- }
-
- @Override
- public synchronized NetconfNotificationCollector addingService(final ServiceReference<NetconfNotificationCollector> reference) {
- closePublisherRegistration();
- publisherReg = context.getService(reference).registerBaseNotificationPublisher();
- return null;
- }
-
- @Override
- public synchronized void modifiedService(final ServiceReference<NetconfNotificationCollector> reference, final NetconfNotificationCollector service) {
- closePublisherRegistration();
- publisherReg = context.getService(reference).registerBaseNotificationPublisher();
- }
-
- @Override
- public synchronized void removedService(final ServiceReference<NetconfNotificationCollector> reference, final NetconfNotificationCollector service) {
- closePublisherRegistration();
- publisherReg = null;
- }
-
- private void closePublisherRegistration() {
- if(publisherReg != null) {
- publisherReg.close();
- }
- }
-
- @Override
- public synchronized void close() {
- closePublisherRegistration();
- listenerTracker.close();
- }
-
- @Override
- public void onCapabilityChanged(final NetconfCapabilityChange capabilityChange) {
- if(publisherReg == null) {
- LOG.warn("Omitting notification due to missing notification service: {}", capabilityChange);
- return;
- }
-
- publisherReg.onCapabilityChanged(capabilityChange);
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.osgi;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Predicate;
-import com.google.common.collect.BiMap;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
-import org.opendaylight.controller.config.yangjmxgenerator.PackageTranslator;
-import org.opendaylight.controller.config.yangjmxgenerator.ServiceInterfaceEntry;
-import org.opendaylight.controller.config.yangjmxgenerator.TypeProviderWrapper;
-import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
-import org.opendaylight.yangtools.sal.binding.yang.types.TypeProviderImpl;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
-import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleIdentifierImpl;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-final class YangStoreSnapshot implements YangStoreContext, EnumResolver {
- private static final Logger LOG = LoggerFactory.getLogger(YangStoreSnapshot.class);
-
-
- private final Map<String /* Namespace from yang file */,
- Map<String /* Name of module entry from yang file */, ModuleMXBeanEntry>> moduleMXBeanEntryMap;
-
-
- private final Map<QName, Map<String, ModuleMXBeanEntry>> qNamesToIdentitiesToModuleMXBeanEntries;
-
- private final SchemaContext schemaContext;
- private final BindingRuntimeContext bindingContextProvider;
-
- public YangStoreSnapshot(final SchemaContext resolveSchemaContext, final BindingRuntimeContext bindingContextProvider) {
- this.bindingContextProvider = bindingContextProvider;
- LOG.trace("Resolved modules:{}", resolveSchemaContext.getModules());
- this.schemaContext = resolveSchemaContext;
- // JMX generator
-
- Map<String, String> namespaceToPackageMapping = Maps.newHashMap();
- PackageTranslator packageTranslator = new PackageTranslator(namespaceToPackageMapping);
- Map<QName, ServiceInterfaceEntry> qNamesToSIEs = new HashMap<>();
- Map<IdentitySchemaNode, ServiceInterfaceEntry> knownSEITracker = new HashMap<>();
- // create SIE structure qNamesToSIEs
- for (Module module : resolveSchemaContext.getModules()) {
- String packageName = packageTranslator.getPackageName(module);
- Map<QName, ServiceInterfaceEntry> namesToSIEntries = ServiceInterfaceEntry
- .create(module, packageName, knownSEITracker);
- for (Entry<QName, ServiceInterfaceEntry> sieEntry : namesToSIEntries.entrySet()) {
- // merge value into qNamesToSIEs
- if (qNamesToSIEs.containsKey(sieEntry.getKey()) == false) {
- qNamesToSIEs.put(sieEntry.getKey(), sieEntry.getValue());
- } else {
- throw new IllegalStateException("Cannot add two SIE with same qname "
- + sieEntry.getValue());
- }
- }
- }
-
- Map<String, Map<String, ModuleMXBeanEntry>> moduleMXBeanEntryMap = Maps.newHashMap();
-
- Map<QName, Map<String /* identity local name */, ModuleMXBeanEntry>> qNamesToIdentitiesToModuleMXBeanEntries = new HashMap<>();
-
-
- for (Module module : schemaContext.getModules()) {
- String packageName = packageTranslator.getPackageName(module);
- TypeProviderWrapper typeProviderWrapper = new TypeProviderWrapper(
- new TypeProviderImpl(resolveSchemaContext));
-
- QName qName = QName.create(module.getNamespace(), module.getRevision(), module.getName());
-
- Map<String /* MB identity local name */, ModuleMXBeanEntry> namesToMBEs =
- Collections.unmodifiableMap(ModuleMXBeanEntry.create(module, qNamesToSIEs, resolveSchemaContext,
- typeProviderWrapper, packageName));
- moduleMXBeanEntryMap.put(module.getNamespace().toString(), namesToMBEs);
-
- qNamesToIdentitiesToModuleMXBeanEntries.put(qName, namesToMBEs);
- }
- this.moduleMXBeanEntryMap = Collections.unmodifiableMap(moduleMXBeanEntryMap);
- this.qNamesToIdentitiesToModuleMXBeanEntries = Collections.unmodifiableMap(qNamesToIdentitiesToModuleMXBeanEntries);
-
- }
-
- @Override
- public Map<String, Map<String, ModuleMXBeanEntry>> getModuleMXBeanEntryMap() {
- return moduleMXBeanEntryMap;
- }
-
- @Override
- public Map<QName, Map<String, ModuleMXBeanEntry>> getQNamesToIdentitiesToModuleMXBeanEntries() {
- return qNamesToIdentitiesToModuleMXBeanEntries;
- }
-
- @Override
- public Set<Module> getModules() {
- final Set<Module> modules = Sets.newHashSet(schemaContext.getModules());
- for (final Module module : schemaContext.getModules()) {
- modules.addAll(module.getSubmodules());
- }
- return modules;
- }
-
- @Override
- public String getModuleSource(final org.opendaylight.yangtools.yang.model.api.ModuleIdentifier moduleIdentifier) {
- final Optional<String> moduleSource = schemaContext.getModuleSource(moduleIdentifier);
- if(moduleSource.isPresent()) {
- return moduleSource.get();
- } else {
- try {
- return Iterables.find(getModules(), new Predicate<Module>() {
- @Override
- public boolean apply(final Module input) {
- final ModuleIdentifierImpl id = new ModuleIdentifierImpl(input.getName(), Optional.fromNullable(input.getNamespace()), Optional.fromNullable(input.getRevision()));
- return id.equals(moduleIdentifier);
- }
- }).getSource();
- } catch (final NoSuchElementException e) {
- throw new IllegalArgumentException("Source for yang module " + moduleIdentifier + " not found", e);
- }
- }
- }
-
- @Override
- public EnumResolver getEnumResolver() {
- return this;
- }
-
- @Override
- public boolean equals(final Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- final YangStoreSnapshot that = (YangStoreSnapshot) o;
-
- if (schemaContext != null ? !schemaContext.equals(that.schemaContext) : that.schemaContext != null)
- return false;
-
- return true;
- }
-
- @Override
- public int hashCode() {
- return schemaContext != null ? schemaContext.hashCode() : 0;
- }
-
- @Override
- public String fromYang(final String enumClass, final String enumYangValue) {
- Preconditions.checkState(bindingContextProvider != null, "Binding context provider was not set yet");
- final BiMap<String, String> enumMapping = bindingContextProvider.getEnumMapping(enumClass);
- final String javaName = enumMapping.get(enumYangValue);
- return Preconditions.checkNotNull(javaName, "Unable to resolve enum value %s for enum class %s with assumed enum mapping: %s", enumYangValue, enumClass, enumMapping);
- }
-
- @Override
- public String toYang(final String enumClass, final String enumJavaValue) {
- Preconditions.checkState(bindingContextProvider != null, "Binding context provider was not set yet");
- final BiMap<String, String> enumMapping = bindingContextProvider.getEnumMapping(enumClass);
- final String javaName = enumMapping.inverse().get(enumJavaValue);
- return Preconditions.checkNotNull(javaName, "Unable to map enumcd .." +
- "cd value %s for enum class %s with assumed enum mapping: %s", enumJavaValue, enumClass, enumMapping.inverse());
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.transactions;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-import javax.management.InstanceNotFoundException;
-import javax.management.ObjectName;
-import org.opendaylight.controller.config.api.ConflictingVersionException;
-import org.opendaylight.controller.config.api.ValidationException;
-import org.opendaylight.controller.config.api.jmx.CommitStatus;
-import org.opendaylight.controller.config.util.ConfigRegistryClient;
-import org.opendaylight.controller.config.util.ConfigTransactionClient;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.confignetconfconnector.exception.NoTransactionFoundException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class TransactionProvider implements AutoCloseable {
- private static final Logger LOG = LoggerFactory.getLogger(TransactionProvider.class);
-
- private final ConfigRegistryClient configRegistryClient;
-
- private final String netconfSessionIdForReporting;
- private ObjectName candidateTx;
- private ObjectName readTx;
- private final List<ObjectName> allOpenedTransactions = new ArrayList<>();
- private static final String NO_TRANSACTION_FOUND_FOR_SESSION = "No transaction found for session ";
-
- public TransactionProvider(ConfigRegistryClient configRegistryClient, String netconfSessionIdForReporting) {
- this.configRegistryClient = configRegistryClient;
- this.netconfSessionIdForReporting = netconfSessionIdForReporting;
- }
-
- @Override
- public synchronized void close() {
- for (ObjectName tx : allOpenedTransactions) {
- try {
- if (isStillOpenTransaction(tx)) {
- configRegistryClient.getConfigTransactionClient(tx).abortConfig();
- }
- } catch (Exception e) {
- LOG.debug("Ignoring exception while closing transaction {}", tx, e);
- }
- }
- allOpenedTransactions.clear();
- }
-
- public synchronized Optional<ObjectName> getTransaction() {
-
- if (candidateTx == null){
- return Optional.absent();
- }
-
- // Transaction was already closed somehow
- if (!isStillOpenTransaction(candidateTx)) {
- LOG.warn("Fixing illegal state: transaction {} was closed in {}", candidateTx,
- netconfSessionIdForReporting);
- candidateTx = null;
- return Optional.absent();
- }
- return Optional.of(candidateTx);
- }
-
- public synchronized Optional<ObjectName> getReadTransaction() {
-
- if (readTx == null){
- return Optional.absent();
- }
-
- // Transaction was already closed somehow
- if (!isStillOpenTransaction(readTx)) {
- LOG.warn("Fixing illegal state: transaction {} was closed in {}", readTx,
- netconfSessionIdForReporting);
- readTx = null;
- return Optional.absent();
- }
- return Optional.of(readTx);
- }
-
- private boolean isStillOpenTransaction(ObjectName transaction) {
- return configRegistryClient.getOpenConfigs().contains(transaction);
- }
-
- public synchronized ObjectName getOrCreateTransaction() {
- Optional<ObjectName> ta = getTransaction();
-
- if (ta.isPresent()) {
- return ta.get();
- }
- candidateTx = configRegistryClient.beginConfig();
- allOpenedTransactions.add(candidateTx);
- return candidateTx;
- }
-
- public synchronized ObjectName getOrCreateReadTransaction() {
- Optional<ObjectName> ta = getReadTransaction();
-
- if (ta.isPresent()) {
- return ta.get();
- }
- readTx = configRegistryClient.beginConfig();
- allOpenedTransactions.add(readTx);
- return readTx;
- }
-
- /**
- * Used for editConfig test option
- */
- public synchronized ObjectName getTestTransaction() {
- ObjectName testTx = configRegistryClient.beginConfig();
- allOpenedTransactions.add(testTx);
- return testTx;
- }
-
- /**
- * Commit and notification send must be atomic
- */
- public synchronized CommitStatus commitTransaction() throws ValidationException, ConflictingVersionException, NoTransactionFoundException {
- if (!getTransaction().isPresent()){
- throw new NoTransactionFoundException("No transaction found for session " + netconfSessionIdForReporting,
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_failed,
- NetconfDocumentedException.ErrorSeverity.error);
- }
- final Optional<ObjectName> maybeTaON = getTransaction();
- ObjectName taON = maybeTaON.get();
- try {
- CommitStatus status = configRegistryClient.commitConfig(taON);
- // clean up
- allOpenedTransactions.remove(candidateTx);
- candidateTx = null;
- return status;
- } catch (ValidationException validationException) {
- // no clean up: user can reconfigure and recover this transaction
- LOG.warn("Transaction {} failed on {}", taON, validationException.toString());
- throw validationException;
- } catch (ConflictingVersionException e) {
- LOG.error("Exception while commit of {}, aborting transaction", taON, e);
- // clean up
- abortTransaction();
- throw e;
- }
- }
-
- public synchronized void abortTransaction() {
- LOG.debug("Aborting current transaction");
- Optional<ObjectName> taON = getTransaction();
- Preconditions.checkState(taON.isPresent(), NO_TRANSACTION_FOUND_FOR_SESSION + netconfSessionIdForReporting);
-
- ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON.get());
- transactionClient.abortConfig();
- allOpenedTransactions.remove(candidateTx);
- candidateTx = null;
- }
-
- public synchronized void closeReadTransaction() {
- LOG.debug("Closing read transaction");
- Optional<ObjectName> taON = getReadTransaction();
- Preconditions.checkState(taON.isPresent(), NO_TRANSACTION_FOUND_FOR_SESSION + netconfSessionIdForReporting);
-
- ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON.get());
- transactionClient.abortConfig();
- allOpenedTransactions.remove(readTx);
- readTx = null;
- }
-
- public synchronized void abortTestTransaction(ObjectName testTx) {
- LOG.debug("Aborting transaction {}", testTx);
- ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(testTx);
- allOpenedTransactions.remove(testTx);
- transactionClient.abortConfig();
- }
-
- public void validateTransaction() throws ValidationException {
- Optional<ObjectName> taON = getTransaction();
- Preconditions.checkState(taON.isPresent(), NO_TRANSACTION_FOUND_FOR_SESSION + netconfSessionIdForReporting);
-
- ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON.get());
- transactionClient.validateConfig();
- }
-
- public void validateTestTransaction(ObjectName taON) throws ValidationException {
- ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON);
- transactionClient.validateConfig();
- }
-
- public void wipeTestTransaction(ObjectName taON) {
- wipeInternal(taON, true);
- }
-
- /**
- * Wiping means removing all module instances keeping the transaction open + service references.
- */
- synchronized void wipeInternal(ObjectName taON, boolean isTest) {
- ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON);
-
- Set<ObjectName> lookupConfigBeans = transactionClient.lookupConfigBeans();
- int i = lookupConfigBeans.size();
- for (ObjectName instance : lookupConfigBeans) {
- try {
- transactionClient.destroyModule(instance);
- } catch (InstanceNotFoundException e) {
- if (isTest){
- LOG.debug("Unable to clean configuration in transactiom {}", taON, e);
- } else {
- LOG.warn("Unable to clean configuration in transactiom {}", taON, e);
- }
-
- throw new IllegalStateException("Unable to clean configuration in transactiom " + taON, e);
- }
- }
- LOG.debug("Transaction {} wiped clean of {} config beans", taON, i);
-
- transactionClient.removeAllServiceReferences();
- LOG.debug("Transaction {} wiped clean of all service references", taON);
- }
-
- public void wipeTransaction() {
- Optional<ObjectName> taON = getTransaction();
- Preconditions.checkState(taON.isPresent(), NO_TRANSACTION_FOUND_FOR_SESSION + netconfSessionIdForReporting);
- wipeInternal(taON.get(), false);
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.util;
-
-import static org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil.getRevisionFormat;
-
-import com.google.common.base.Preconditions;
-import java.text.ParseException;
-import java.util.Date;
-
-public final class Util {
-
- public static String writeDate(final Date date) {
- return getRevisionFormat().format(date);
- }
-
- public static Date readDate(final String s) throws ParseException {
- return getRevisionFormat().parse(s);
- }
-
- public static void checkType(final Object value, final Class<?> clazz) {
- Preconditions.checkArgument(clazz.isAssignableFrom(value.getClass()), "Unexpected type " + value.getClass()
- + " should be " + clazz + " of " + value);
- }
-
-}
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.opendaylight.controller.config.util.xml.XmlUtil.readXmlToElement;
import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElement;
import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElementWithText;
-import static org.opendaylight.controller.netconf.util.xml.XmlUtil.readXmlToElement;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
+import org.opendaylight.controller.config.facade.xml.ConfigSubsystemFacade;
+import org.opendaylight.controller.config.facade.xml.osgi.EnumResolver;
+import org.opendaylight.controller.config.facade.xml.osgi.YangStoreService;
+import org.opendaylight.controller.config.facade.xml.transactions.TransactionProvider;
import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlMappingConstants;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.config.yang.test.impl.ComplexDtoBInner;
import org.opendaylight.controller.config.yang.test.impl.ComplexList;
import org.opendaylight.controller.config.yang.test.impl.Deep;
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.api.NetconfDocumentedException.ErrorSeverity;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
-import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.Commit;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.DiscardChanges;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.Lock;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.get.Get;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.getconfig.GetConfig;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.runtimerpc.RuntimeRpc;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreContext;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreService;
-import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
import org.opendaylight.controller.netconf.impl.NetconfServerSession;
import org.opendaylight.controller.netconf.impl.NetconfServerSessionListener;
import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCloseSession;
import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
-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;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.test.types.rev131127.TestIdentity2;
import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
private TestImplModuleFactory factory4;
@Mock
- YangStoreContext yangStoreSnapshot;
+ YangStoreService yangStoreSnapshot;
@Mock
NetconfOperationRouter netconfOperationRouter;
@Mock
private TransactionProvider transactionProvider;
+ private ConfigSubsystemFacade configSubsystemFacade;
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
doNothing().when(mockedContext).addServiceListener(any(ServiceListener.class), anyString());
doReturn(new ServiceReference<?>[]{}).when(mockedContext).getServiceReferences(anyString(), anyString());
+ doReturn(yangStoreSnapshot).when(yangStoreSnapshot).getCurrentSnapshot();
doReturn(getMbes()).when(this.yangStoreSnapshot).getModuleMXBeanEntryMap();
doReturn(getModules()).when(this.yangStoreSnapshot).getModules();
doReturn(new EnumResolver() {
this.factory3, factory4));
transactionProvider = new TransactionProvider(this.configRegistryClient, NETCONF_SESSION_ID);
+
+ configSubsystemFacade = new ConfigSubsystemFacade(configRegistryClient, configRegistryClient, yangStoreSnapshot, "mapping-test");
}
private ObjectName createModule(final String instanceName) throws InstanceAlreadyExistsException, InstanceNotFoundException, URISyntaxException, ValidationException, ConflictingVersionException {
try {
edit("netconfMessages/editConfig_removeServiceNameOnTest.xml");
fail("Should've failed, non-existing service instance");
- } catch (NetconfDocumentedException e) {
- assertEquals(e.getErrorSeverity(), ErrorSeverity.error);
- assertEquals(e.getErrorTag(), ErrorTag.operation_failed);
- assertEquals(e.getErrorType(), ErrorType.application);
+ } catch (DocumentedException e) {
+ assertEquals(e.getErrorSeverity(), DocumentedException.ErrorSeverity.error);
+ assertEquals(e.getErrorTag(), DocumentedException.ErrorTag.operation_failed);
+ assertEquals(e.getErrorType(), DocumentedException.ErrorType.application);
}
edit("netconfMessages/editConfig_replace_default.xml");
}
- private void closeSession() throws NetconfDocumentedException, ParserConfigurationException, SAXException,
- IOException {
+ private void closeSession() throws ParserConfigurationException, SAXException,
+ IOException, DocumentedException {
final Channel channel = mock(Channel.class);
doReturn("channel").when(channel).toString();
final NetconfServerSessionListener listener = mock(NetconfServerSessionListener.class);
}
private void edit(String resource) throws ParserConfigurationException, SAXException, IOException,
- NetconfDocumentedException {
- EditConfig editOp = new EditConfig(yangStoreSnapshot, transactionProvider, configRegistryClient,
- NETCONF_SESSION_ID);
+ DocumentedException {
+ EditConfig editOp = new EditConfig(configSubsystemFacade, NETCONF_SESSION_ID);
executeOp(editOp, resource);
}
- private void commit() throws ParserConfigurationException, SAXException, IOException, NetconfDocumentedException {
- Commit commitOp = new Commit(transactionProvider, configRegistryClient, NETCONF_SESSION_ID);
+ private void commit() throws ParserConfigurationException, SAXException, IOException, DocumentedException {
+ Commit commitOp = new Commit(configSubsystemFacade, NETCONF_SESSION_ID);
executeOp(commitOp, "netconfMessages/commit.xml");
}
- private Document lockCandidate() throws ParserConfigurationException, SAXException, IOException, NetconfDocumentedException {
+ private Document lockCandidate() throws ParserConfigurationException, SAXException, IOException, DocumentedException {
Lock commitOp = new Lock(NETCONF_SESSION_ID);
return executeOp(commitOp, "netconfMessages/lock.xml");
}
- private Document unlockCandidate() throws ParserConfigurationException, SAXException, IOException, NetconfDocumentedException {
+ private Document unlockCandidate() throws ParserConfigurationException, SAXException, IOException, DocumentedException {
UnLock commitOp = new UnLock(NETCONF_SESSION_ID);
return executeOp(commitOp, "netconfMessages/unlock.xml");
}
private Document getConfigCandidate() throws ParserConfigurationException, SAXException, IOException,
- NetconfDocumentedException {
- GetConfig getConfigOp = new GetConfig(yangStoreSnapshot, Optional.<String> absent(), transactionProvider,
- configRegistryClient, NETCONF_SESSION_ID);
+ DocumentedException {
+ GetConfig getConfigOp = new GetConfig(configSubsystemFacade, Optional.<String> absent(), NETCONF_SESSION_ID);
return executeOp(getConfigOp, "netconfMessages/getConfig_candidate.xml");
}
private Document getConfigRunning() throws ParserConfigurationException, SAXException, IOException,
- NetconfDocumentedException {
- GetConfig getConfigOp = new GetConfig(yangStoreSnapshot, Optional.<String> absent(), transactionProvider,
- configRegistryClient, NETCONF_SESSION_ID);
+ DocumentedException {
+ GetConfig getConfigOp = new GetConfig(configSubsystemFacade, Optional.<String> absent(), NETCONF_SESSION_ID);
return executeOp(getConfigOp, "netconfMessages/getConfig.xml");
}
@Ignore("second edit message corrupted")
- @Test(expected = NetconfDocumentedException.class)
+ @Test(expected = DocumentedException.class)
public void testConfigNetconfReplaceDefaultEx() throws Exception {
createModule(INSTANCE_NAME);
try {
edit("netconfMessages/namespaces/editConfig_sameAttrDifferentNamespaces.xml");
fail();
- } catch (NetconfDocumentedException e) {
+ } catch (DocumentedException e) {
String message = e.getMessage();
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);
+ assertContainsString(message, XmlMappingConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
}
}
try {
edit("netconfMessages/namespaces/editConfig_differentNamespaceTO.xml");
fail();
- } catch (NetconfDocumentedException e) {
+ } catch (DocumentedException e) {
String message = e.getMessage();
assertContainsString(message, "Unrecognised elements");
assertContainsString(message, "simple-int2");
try {
edit("netconfMessages/namespaces/editConfig_sameAttrDifferentNamespacesList.xml");
fail();
- } catch (NetconfDocumentedException e) {
+ } catch (DocumentedException e) {
String message = e.getMessage();
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);
+ assertContainsString(message, XmlMappingConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
}
}
}
// TODO add <modules operation="replace"> functionality
- @Test(expected = NetconfDocumentedException.class)
+ @Test(expected = DocumentedException.class)
public void testConfigNetconfReplaceModuleEx() throws Exception {
createModule(INSTANCE_NAME);
LOG.info("Reading {}", file);
try {
edit(file);
- } catch (NetconfDocumentedException e) {
+ } catch (DocumentedException e) {
assertContainsString(e.getMessage(), "Unrecognised elements");
assertContainsString(e.getMessage(), "unknownAttribute");
continue;
assertEquals(3 + 3, afterReplace);
}
- @Test(expected = NetconfDocumentedException.class)
+ @Test(expected = DocumentedException.class)
public void testEx() throws Exception {
commit();
@Test
public void testFailedDiscardChangesAbort() throws Exception {
+ final ConfigSubsystemFacade facade = mock(ConfigSubsystemFacade.class);
+ doThrow(new RuntimeException("Mocked runtime exception, Abort has to fail")).when(facade).abortConfiguration();
- TransactionProvider mockedTxProvider = mock(TransactionProvider.class);
- doThrow(new RuntimeException("Mocked runtime exception, Abort has to fail")).when(mockedTxProvider).abortTransaction();
- doReturn(Optional.of(ObjectName.getInstance("dummyDomain", "DummyKey", "DummyValue"))).when(mockedTxProvider).getTransaction();
-
- DiscardChanges discardOp = new DiscardChanges(mockedTxProvider, configRegistryClient, NETCONF_SESSION_ID);
+ DiscardChanges discardOp = new DiscardChanges(facade, NETCONF_SESSION_ID);
try {
executeOp(discardOp, "netconfMessages/discardChanges.xml");
fail("Should've failed, abort on mocked is supposed to throw RuntimeException");
- } catch (NetconfDocumentedException e) {
- assertTrue(e.getErrorTag() == ErrorTag.operation_failed);
- assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
- assertTrue(e.getErrorType() == ErrorType.application);
+ } catch (DocumentedException e) {
+ assertTrue(e.getErrorTag() == DocumentedException.ErrorTag.operation_failed);
+ assertTrue(e.getErrorSeverity() == DocumentedException.ErrorSeverity.error);
+ assertTrue(e.getErrorType() == DocumentedException.ErrorType.application);
}
-
}
- private Document discard() throws ParserConfigurationException, SAXException, IOException, NetconfDocumentedException {
- DiscardChanges discardOp = new DiscardChanges(transactionProvider, configRegistryClient, NETCONF_SESSION_ID);
+ private Document discard() throws ParserConfigurationException, SAXException, IOException, DocumentedException {
+ DiscardChanges discardOp = new DiscardChanges(configSubsystemFacade, NETCONF_SESSION_ID);
return executeOp(discardOp, "netconfMessages/discardChanges.xml");
}
public SchemaContext getSchemaContext() {
return schemaContext ;
}
- }, mockedContext);
+ });
final BindingRuntimeContext bindingRuntimeContext = mock(BindingRuntimeContext.class);
doReturn(getEnumMapping()).when(bindingRuntimeContext).getEnumMapping(any(Class.class));
yangStoreService.refresh(bindingRuntimeContext);
assertEquals(8, getElementsSize(response, "deep4"));
// TODO assert keys
- RuntimeRpc netconf = new RuntimeRpc(yangStoreSnapshot, configRegistryClient, NETCONF_SESSION_ID);
+ RuntimeRpc netconf = new RuntimeRpc(configSubsystemFacade, NETCONF_SESSION_ID);
response = executeOp(netconf, "netconfMessages/rpc.xml");
assertContainsElementWithText(response, "testarg1");
assertContainsElementWithText(response, "2");
}
- private Document get() throws NetconfDocumentedException, ParserConfigurationException, SAXException, IOException {
- Get getOp = new Get(transactionProvider, yangStoreSnapshot, configRegistryClient, NETCONF_SESSION_ID);
+ private Document get() throws ParserConfigurationException, SAXException, IOException, DocumentedException {
+ Get getOp = new Get(configSubsystemFacade, NETCONF_SESSION_ID);
return executeOp(getOp, "netconfMessages/get.xml");
}
}
private Document executeOp(final NetconfOperation op, final String filename) throws ParserConfigurationException,
- SAXException, IOException, NetconfDocumentedException {
+ SAXException, IOException, DocumentedException {
final Document request = XmlFileLoader.xmlFileToDocument(filename);
import static org.junit.Assert.assertEquals;
import org.junit.Test;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services.ServiceInstance;
+import org.opendaylight.controller.config.facade.xml.mapping.config.Services;
+import org.opendaylight.controller.config.facade.xml.mapping.config.Services.ServiceInstance;
public class ServiceTrackerTest {
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml;
-
-import static org.junit.Assert.assertEquals;
-
-import com.google.common.collect.Maps;
-import java.net.URI;
-import java.util.Collections;
-import java.util.Date;
-import java.util.Map;
-import org.junit.Test;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-
-public class SimpleIdentityRefAttributeReadingStrategyTest {
-
- @Test
- public void testReadIdRef() throws Exception {
- final Map<String, Map<Date, EditConfig.IdentityMapping>> identityMapping = Maps.newHashMap();
- final EditConfig.IdentityMapping value = new EditConfig.IdentityMapping();
- final Date rev = new Date();
- identityMapping.put("namespace", Collections.singletonMap(rev, value));
- identityMapping.put("inner", Collections.singletonMap(rev, value));
- final SimpleIdentityRefAttributeReadingStrategy key = new SimpleIdentityRefAttributeReadingStrategy(null, "key", identityMapping);
-
- String read = key.readElementContent(XmlElement.fromString("<el xmlns=\"namespace\">local</el>"));
- assertEquals(org.opendaylight.yangtools.yang.common.QName.create(URI.create("namespace"), rev, "local").toString(), read);
-
- read = key.readElementContent(XmlElement.fromString("<el xmlns:a=\"inner\" xmlns=\"namespace\">a:local</el>"));
- assertEquals(org.opendaylight.yangtools.yang.common.QName.create(URI.create("inner"), rev, "local").toString(), read);
-
- read = key.readElementContent(XmlElement.fromString("<top xmlns=\"namespace\"><el>local</el></top>").getOnlyChildElement());
- assertEquals(org.opendaylight.yangtools.yang.common.QName.create(URI.create("namespace"), rev, "local").toString(), read);
- }
-}
import org.junit.Test;
import org.opendaylight.controller.config.api.ValidationException;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.facade.xml.ConfigSubsystemFacade;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Element;
public class ValidateTest {
public static final String NETCONF_SESSION_ID_FOR_REPORTING = "foo";
- @Test(expected = NetconfDocumentedException.class)
+ @Test(expected = DocumentedException.class)
public void test() throws Exception {
final XmlElement xml = XmlElement.fromString("<abc></abc>");
- final Validate validate = new Validate(null, null, NETCONF_SESSION_ID_FOR_REPORTING);
+ final Validate validate = new Validate(null, NETCONF_SESSION_ID_FOR_REPORTING);
validate.handleWithNoSubsequentOperations(null, xml);
}
- @Test(expected = NetconfDocumentedException.class)
+ @Test(expected = DocumentedException.class)
public void testNoSource() throws Exception {
final XmlElement xml = XmlElement.fromString("<validate xmlns=\""
+ XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0 + "\"/>");
- final Validate validate = new Validate(null, null, NETCONF_SESSION_ID_FOR_REPORTING);
+ final Validate validate = new Validate(null, NETCONF_SESSION_ID_FOR_REPORTING);
validate.handleWithNoSubsequentOperations(null, xml);
}
- @Test(expected = NetconfDocumentedException.class)
+ @Test(expected = DocumentedException.class)
public void testNoNamespace() throws Exception {
final XmlElement xml = XmlElement.fromString("<validate/>");
- final Validate validate = new Validate(null, null, NETCONF_SESSION_ID_FOR_REPORTING);
+ final Validate validate = new Validate(null, NETCONF_SESSION_ID_FOR_REPORTING);
validate.handleWithNoSubsequentOperations(null, xml);
}
- @Test(expected = NetconfDocumentedException.class)
+ @Test(expected = DocumentedException.class)
public void testRunningSource() throws Exception {
final XmlElement xml = XmlElement.fromString("<validate xmlns=\""
+ XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0
+ "\"><source><running></running></source></validate>");
- final Validate validate = new Validate(null, null, NETCONF_SESSION_ID_FOR_REPORTING);
+ final Validate validate = new Validate(null, NETCONF_SESSION_ID_FOR_REPORTING);
validate.handleWithNoSubsequentOperations(null, xml);
}
- @Test(expected = NetconfDocumentedException.class)
+ @Test(expected = DocumentedException.class)
public void testNoTransaction() throws Exception {
final XmlElement xml = XmlElement.fromString("<validate xmlns=\""
+ XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0
+ "\"><source><candidate/></source></validate>");
- final TransactionProvider transactionProvider = mock(TransactionProvider.class);
- doThrow(IllegalStateException.class).when(transactionProvider).validateTransaction();
- final Validate validate = new Validate(transactionProvider, null, NETCONF_SESSION_ID_FOR_REPORTING);
+ final ConfigSubsystemFacade facade = mock(ConfigSubsystemFacade.class);
+ doThrow(IllegalStateException.class).when(facade).validateConfiguration();
+ final Validate validate = new Validate(facade, NETCONF_SESSION_ID_FOR_REPORTING);
validate.handleWithNoSubsequentOperations(null, xml);
}
- @Test(expected = NetconfDocumentedException.class)
+ @Test(expected = DocumentedException.class)
public void testValidationException() throws Exception {
final XmlElement xml = XmlElement.fromString("<validate xmlns=\""
+ XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0
+ "\">><source><candidate/></source></validate>");
- final TransactionProvider transactionProvider = mock(TransactionProvider.class);
- doThrow(ValidationException.class).when(transactionProvider).validateTransaction();
- final Validate validate = new Validate(transactionProvider, null, NETCONF_SESSION_ID_FOR_REPORTING);
+ final ConfigSubsystemFacade facade = mock(ConfigSubsystemFacade.class);
+ doThrow(ValidationException.class).when(facade).validateConfiguration();
+ final Validate validate = new Validate(facade, NETCONF_SESSION_ID_FOR_REPORTING);
validate.handleWithNoSubsequentOperations(null, xml);
}
final XmlElement xml = XmlElement.fromString("<validate xmlns=\""
+ XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0
+ "\"><source><candidate/></source></validate>");
- final TransactionProvider transactionProvider = mock(TransactionProvider.class);
final Element okElement = XmlUtil.readXmlToElement("<ok/>");
- doNothing().when(transactionProvider).validateTransaction();
- final Validate validate = new Validate(transactionProvider, null, NETCONF_SESSION_ID_FOR_REPORTING);
+ final ConfigSubsystemFacade facade = mock(ConfigSubsystemFacade.class);
+ doNothing().when(facade).validateConfiguration();
+ final Validate validate = new Validate(facade, NETCONF_SESSION_ID_FOR_REPORTING);
Element ok = validate.handleWithNoSubsequentOperations(XmlUtil.newDocument(), xml);
assertEquals(XmlUtil.toString(okElement), XmlUtil.toString(ok));
}
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
-import org.opendaylight.controller.config.api.ValidationException;
+import org.opendaylight.controller.config.facade.xml.ConfigExecution;
+import org.opendaylight.controller.config.facade.xml.ConfigSubsystemFacade;
+import org.opendaylight.controller.config.facade.xml.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.config.facade.xml.mapping.config.InstanceConfigElementResolved;
+import org.opendaylight.controller.config.facade.xml.mapping.config.ModuleElementDefinition;
+import org.opendaylight.controller.config.facade.xml.mapping.config.ModuleElementResolved;
+import org.opendaylight.controller.config.facade.xml.mapping.config.ServiceRegistryWrapper;
+import org.opendaylight.controller.config.facade.xml.mapping.config.Services;
+import org.opendaylight.controller.config.facade.xml.osgi.YangStoreService;
+import org.opendaylight.controller.config.facade.xml.strategy.EditConfigStrategy;
+import org.opendaylight.controller.config.facade.xml.strategy.EditStrategyType;
+import org.opendaylight.controller.config.facade.xml.transactions.TransactionProvider;
import org.opendaylight.controller.config.util.ConfigRegistryClient;
import org.opendaylight.controller.config.util.ConfigTransactionClient;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfigElementResolved;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementDefinition;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementResolved;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ServiceRegistryWrapper;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.ValidateTest;
-import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigXmlParser.EditConfigExecution;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreContext;
-import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
public class EditConfigTest {
@Mock
- private YangStoreContext yangStoreSnapshot;
+ private YangStoreService yangStoreSnapshot;
@Mock
private TransactionProvider provider;
@Mock
@Mock
private ObjectName mockOn;
+ private ConfigSubsystemFacade cfgFacade;
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
doReturn("mockConfigTransactionClient").when(configTransactionClient).toString();
doReturn(mockOn).when(configTransactionClient).lookupConfigBean(anyString(), anyString());
+
+ cfgFacade = new ConfigSubsystemFacade(configRegistry, configRegistry, yangStoreSnapshot, provider);
}
@Test
- public void test() throws NetconfDocumentedException, ValidationException {
- EditConfig edit = new EditConfig(yangStoreSnapshot, provider, configRegistry,
- ValidateTest.NETCONF_SESSION_ID_FOR_REPORTING);
+ public void test() throws Exception {
+ EditConfig edit = new EditConfig(cfgFacade, ValidateTest.NETCONF_SESSION_ID_FOR_REPORTING);
EditConfigStrategy editStrat = mock(EditConfigStrategy.class);
doNothing().when(editStrat).executeConfiguration(anyString(), anyString(), anyMapOf(String.class, AttributeConfigElement.class),
any(ConfigTransactionClient.class), any(ServiceRegistryWrapper.class));
- EditConfigExecution editConfigExecution = mockExecution(editStrat);
+ ConfigExecution editConfigExecution = mockExecution(editStrat);
edit.getResponseInternal(XmlUtil.newDocument(), editConfigExecution);
any(ConfigTransactionClient.class), any(ServiceRegistryWrapper.class));
}
- private EditConfigExecution mockExecution(EditConfigStrategy editStrat) throws NetconfDocumentedException {
- EditConfigExecution mock = mock(EditConfigExecution.class);
+ private ConfigExecution mockExecution(EditConfigStrategy editStrat) throws Exception {
+ ConfigExecution mock = mock(ConfigExecution.class);
doReturn(getMapping(editStrat)).when(mock).getResolvedXmlElements(any(ConfigTransactionClient.class));
doReturn(getMappingDefinition(editStrat)).when(mock).getModulesDefinition(any(ConfigTransactionClient.class));
doReturn(EditStrategyType.merge).when(mock).getDefaultStrategy();
doReturn(true).when(mock).shouldTest();
doReturn(mockServices()).when(mock).getServiceRegistryWrapper(any(ConfigTransactionClient.class));
doReturn(new Services()).when(mock).getServices();
+ doReturn(XmlElement.fromDomElement(XmlUtil.readXmlToElement("<abc/>"))).when(mock).getConfigElement();
return mock;
}
import javax.management.ObjectName;
import org.junit.Before;
import org.junit.Test;
+import org.opendaylight.controller.config.facade.xml.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.config.facade.xml.mapping.config.ServiceRegistryWrapper;
+import org.opendaylight.controller.config.facade.xml.strategy.MergeEditConfigStrategy;
import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
import org.opendaylight.controller.config.yang.test.impl.MultipleDependenciesModule;
import org.opendaylight.controller.config.yang.test.impl.MultipleDependenciesModuleFactory;
import org.opendaylight.controller.config.yang.test.impl.MultipleDependenciesModuleMXBean;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ServiceRegistryWrapper;
public class MergeEditConfigStrategyTest extends AbstractConfigTest {
private static final MultipleDependenciesModuleFactory factory = new MultipleDependenciesModuleFactory();
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.config.facade.xml.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.config.facade.xml.strategy.ReplaceEditConfigStrategy;
import org.opendaylight.controller.config.util.ConfigTransactionClient;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
public class ReplaceEditConfigStrategyTest {
+++ /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.netconf.confignetconfconnector.operations.runtimerpc;
-
-import static org.junit.Assert.assertEquals;
-import com.google.common.collect.ImmutableMap;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-@RunWith(Parameterized.class)
-public class RuntimeRpcElementResolvedTest {
-
- private static final String MODULE_TYPE = "moduleType";
- private static final String INSTANCE_NAME = "instanceName";
- @Parameterized.Parameter(0)
- public String xpath;
- @Parameterized.Parameter(1)
- public Map<String, String> additional;
-
- @Parameterized.Parameters(name = "{index}: parsed({0}) contains moduleName:{1} and instanceName:{2}")
- public static Collection<Object[]> data() {
- return Arrays.asList(new Object[][] {
- // With namespaces
- { "/a:modules/a:module[a:name='instanceName'][a:type='moduleType']/b:listener-state[b:peer-id='127.0.0.1']",
- new HashMap<>(ImmutableMap.of("listener-state", "127.0.0.1"))},
- { "/a:modules/a:module[a:name='instanceName'][a:type='moduleType']",
- null},
-
- // Without namespaces
- { "/modules/module[name=instanceName][type=moduleType]", null},
- { "/modules/module[type=moduleType][name='instanceName']", null},
- { "/modules/module[name=\'instanceName\'][type=\"moduleType\"]", null},
- { "/modules/module[type=moduleType and name=instanceName]", null},
- { "/modules/module[name=\"instanceName\" and type=moduleType]", null},
- { "/modules/module[type=\"moduleType\" and name=instanceName]", null},
- { "/modules/module[name=\'instanceName\' and type=\"moduleType\"]", null},
-
- // With inner beans
- { "/modules/module[name=instanceName and type=\"moduleType\"]/inner[key=b]", Collections.singletonMap("inner", "b")},
- { "/modules/module[name=instanceName and type=moduleType]/inner[key=b]", Collections.singletonMap("inner", "b")},
- { "/modules/module[name=instanceName and type=moduleType]/inner[key=\'b\']", Collections.singletonMap("inner", "b")},
- { "/modules/module[name=instanceName and type=moduleType]/inner[key=\"b\"]", Collections.singletonMap("inner", "b")},
-
- { "/modules/module[name=instanceName and type=\"moduleType\"]/inner[key2=a]/inner2[key=b]",
- new HashMap<>(ImmutableMap.of("inner", "a", "inner2", "b"))
- },
- });
- }
-
- @Test
- public void testFromXpath() throws Exception {
- final RuntimeRpcElementResolved resolved = RuntimeRpcElementResolved.fromXpath(xpath, "element", "namespace");
- assertEquals(MODULE_TYPE, resolved.getModuleName());
- assertEquals(INSTANCE_NAME, resolved.getInstanceName());
- if (additional != null) {
- assertEquals(additional, resolved.getAdditionalAttributes());
- }
- }
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <parent>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>netconf-subsystem</artifactId>
- <version>0.4.0-SNAPSHOT</version>
- <relativePath>../</relativePath>
- </parent>
- <artifactId>config-persister-impl</artifactId>
- <packaging>bundle</packaging>
- <name>${project.artifactId}</name>
-
- <dependencies>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>netconf-api</artifactId>
- </dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>netconf-util</artifactId>
- </dependency>
- <dependency>
- <groupId>com.google.guava</groupId>
- <artifactId>guava</artifactId>
- </dependency>
- <!-- compile dependencies -->
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>config-persister-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.osgi</groupId>
- <artifactId>org.osgi.core</artifactId>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- </dependency>
-
- <!-- test dependencies -->
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>netconf-impl</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>netconf-util</artifactId>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>config-persister-directory-xml-adapter</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>config-persister-file-xml-adapter</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>mockito-configuration</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <configuration>
- <instructions>
- <Bundle-Activator>org.opendaylight.controller.netconf.persist.impl.osgi.ConfigPersisterActivator</Bundle-Activator>
- <Require-Capability>org.opendaylight.controller.config.persister.storage.adapter</Require-Capability>
- <Export-Package></Export-Package>
- </instructions>
- </configuration>
- </plugin>
- </plugins>
- </build>
-</project>
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.persist.impl;
-
-import com.google.common.annotations.VisibleForTesting;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
-import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-
-/**
- * Inspects snapshot xml to be stored, remove all capabilities that are not referenced by it.
- * Useful when persisting current configuration.
- */
-public class CapabilityStrippingConfigSnapshotHolder implements ConfigSnapshotHolder {
- private static final Logger LOG = LoggerFactory.getLogger(CapabilityStrippingConfigSnapshotHolder.class);
-
- private final String configSnapshot;
- private final StripCapabilitiesResult stripCapabilitiesResult;
-
- public CapabilityStrippingConfigSnapshotHolder(Element snapshot, Set<String> capabilities) {
- final XmlElement configElement = XmlElement.fromDomElement(snapshot);
- configSnapshot = XmlUtil.toString(configElement.getDomElement());
- stripCapabilitiesResult = stripCapabilities(configElement, capabilities);
- }
-
- private static class StripCapabilitiesResult {
- private final SortedSet<String> requiredCapabilities, obsoleteCapabilities;
-
- private StripCapabilitiesResult(SortedSet<String> requiredCapabilities, SortedSet<String> obsoleteCapabilities) {
- this.requiredCapabilities = Collections.unmodifiableSortedSet(requiredCapabilities);
- this.obsoleteCapabilities = Collections.unmodifiableSortedSet(obsoleteCapabilities);
- }
- }
-
-
- @VisibleForTesting
- static StripCapabilitiesResult stripCapabilities(XmlElement configElement, Set<String> allCapabilitiesFromHello) {
- // collect all namespaces
- Set<String> foundNamespacesInXML = getNamespaces(configElement);
- LOG.trace("All capabilities {}\nFound namespaces in XML {}", allCapabilitiesFromHello, foundNamespacesInXML);
- // required are referenced both in xml and hello
- SortedSet<String> requiredCapabilities = new TreeSet<>();
- // can be removed
- SortedSet<String> obsoleteCapabilities = new TreeSet<>();
- for (String capability : allCapabilitiesFromHello) {
- String namespace = capability.replaceAll("\\?.*","");
- if (foundNamespacesInXML.contains(namespace)) {
- requiredCapabilities.add(capability);
- } else {
- obsoleteCapabilities.add(capability);
- }
- }
-
- LOG.trace("Required capabilities {}, \nObsolete capabilities {}",
- requiredCapabilities, obsoleteCapabilities);
-
- return new StripCapabilitiesResult(requiredCapabilities, obsoleteCapabilities);
- }
-
- static Set<String> getNamespaces(XmlElement element){
- Set<String> result = new HashSet<>();
- for (Entry<String,Attr> attribute : element.getAttributes().entrySet()) {
- if (attribute.getKey().startsWith("xmlns")){
- result.add(attribute.getValue().getValue());
- }
- }
- for(XmlElement child: element.getChildElements()) {
- result.addAll(getNamespaces(child));
- }
- return result;
- }
-
- @Override
- public SortedSet<String> getCapabilities() {
- return stripCapabilitiesResult.requiredCapabilities;
- }
-
- @VisibleForTesting
- Set<String> getObsoleteCapabilities(){
- return stripCapabilitiesResult.obsoleteCapabilities;
- }
-
- @Override
- public String getConfigSnapshot() {
- return configSnapshot;
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.persist.impl;
-
-import java.io.Closeable;
-import java.io.IOException;
-import javax.annotation.concurrent.ThreadSafe;
-import javax.management.InstanceNotFoundException;
-import javax.management.MBeanServerConnection;
-import javax.management.Notification;
-import javax.management.NotificationListener;
-import javax.management.ObjectName;
-import org.opendaylight.controller.config.persist.api.Persister;
-import org.opendaylight.controller.netconf.api.jmx.CommitJMXNotification;
-import org.opendaylight.controller.netconf.api.jmx.DefaultCommitOperationMXBean;
-import org.opendaylight.controller.netconf.api.jmx.NetconfJMXNotification;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Responsible for listening for notifications from netconf (via JMX) containing latest
- * committed configuration that should be persisted, and also for loading last
- * configuration.
- */
-@ThreadSafe
-public class ConfigPersisterNotificationHandler implements Closeable {
-
- private static final Logger LOG = LoggerFactory.getLogger(ConfigPersisterNotificationHandler.class);
- private final MBeanServerConnection mBeanServerConnection;
- private final NotificationListener listener;
-
-
- public ConfigPersisterNotificationHandler(final MBeanServerConnection mBeanServerConnection, final Persister persisterAggregator) {
- this(mBeanServerConnection, new ConfigPersisterNotificationListener(persisterAggregator));
- }
-
- public ConfigPersisterNotificationHandler(final MBeanServerConnection mBeanServerConnection, final NotificationListener notificationListener) {
- this.mBeanServerConnection = mBeanServerConnection;
- this.listener = notificationListener;
- registerAsJMXListener(mBeanServerConnection, listener);
- }
-
- private static void registerAsJMXListener(final MBeanServerConnection mBeanServerConnection, final NotificationListener listener) {
- LOG.trace("Called registerAsJMXListener");
- try {
- mBeanServerConnection.addNotificationListener(DefaultCommitOperationMXBean.OBJECT_NAME, listener, null, null);
- } catch (InstanceNotFoundException | IOException e) {
- throw new IllegalStateException("Cannot register as JMX listener to netconf", e);
- }
- }
-
- @Override
- public synchronized void close() {
- // unregister from JMX
- final ObjectName on = DefaultCommitOperationMXBean.OBJECT_NAME;
- try {
- if (mBeanServerConnection.isRegistered(on)) {
- mBeanServerConnection.removeNotificationListener(on, listener);
- }
- } catch (final Exception e) {
- LOG.warn("Unable to unregister {} as listener for {}", listener, on, e);
- }
- }
-}
-
-class ConfigPersisterNotificationListener implements NotificationListener {
- private static final Logger LOG = LoggerFactory.getLogger(ConfigPersisterNotificationListener.class);
-
- private final Persister persisterAggregator;
-
- ConfigPersisterNotificationListener(final Persister persisterAggregator) {
- this.persisterAggregator = persisterAggregator;
- }
-
- @Override
- public void handleNotification(final Notification notification, final Object handback) {
- if (!(notification instanceof NetconfJMXNotification)) {
- return;
- }
-
- // Socket should not be closed at this point
- // Activator unregisters this as JMX listener before close is called
-
- LOG.trace("Received notification {}", notification);
- if (notification instanceof CommitJMXNotification) {
- try {
- handleAfterCommitNotification((CommitJMXNotification) notification);
- } catch (final Exception e) {
- // log exceptions from notification Handler here since
- // notificationBroadcastSupport logs only DEBUG level
- LOG.warn("Failed to handle notification {}", notification, e);
- throw e;
- }
- } else {
- throw new IllegalStateException("Unknown config registry notification type " + notification);
- }
- }
-
- private void handleAfterCommitNotification(final CommitJMXNotification notification) {
- try {
- persisterAggregator.persistConfig(new CapabilityStrippingConfigSnapshotHolder(notification.getConfigSnapshot(),
- notification.getCapabilities()));
- LOG.trace("Configuration persisted successfully");
- } catch (final IOException e) {
- throw new RuntimeException("Unable to persist configuration snapshot", e);
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.persist.impl;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.base.Function;
-import com.google.common.base.Stopwatch;
-import com.google.common.collect.Collections2;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeMap;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-import javax.annotation.Nonnull;
-import javax.annotation.concurrent.Immutable;
-import javax.management.MBeanServerConnection;
-import org.opendaylight.controller.config.api.ConflictingVersionException;
-import org.opendaylight.controller.config.persist.api.ConfigPusher;
-import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
-import org.opendaylight.controller.config.persist.api.Persister;
-import org.opendaylight.controller.netconf.api.Capability;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
-import org.opendaylight.controller.netconf.util.NetconfUtil;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.xml.sax.SAXException;
-
-@Immutable
-public class ConfigPusherImpl implements ConfigPusher {
- private static final Logger LOG = LoggerFactory.getLogger(ConfigPusherImpl.class);
-
- private final long maxWaitForCapabilitiesMillis;
- private final long conflictingVersionTimeoutMillis;
- private final NetconfOperationServiceFactory configNetconfConnector;
- private static final int QUEUE_SIZE = 100;
- private BlockingQueue<List<? extends ConfigSnapshotHolder>> queue = new LinkedBlockingQueue<List<? extends ConfigSnapshotHolder>>(QUEUE_SIZE);
-
- public ConfigPusherImpl(NetconfOperationServiceFactory configNetconfConnector, long maxWaitForCapabilitiesMillis,
- long conflictingVersionTimeoutMillis) {
- this.configNetconfConnector = configNetconfConnector;
- this.maxWaitForCapabilitiesMillis = maxWaitForCapabilitiesMillis;
- this.conflictingVersionTimeoutMillis = conflictingVersionTimeoutMillis;
- }
-
- public void process(List<AutoCloseable> autoCloseables, MBeanServerConnection platformMBeanServer, Persister persisterAggregator) throws InterruptedException {
- List<? extends ConfigSnapshotHolder> configs;
- while(true) {
- configs = queue.take();
- try {
- internalPushConfigs(configs);
- ConfigPersisterNotificationHandler jmxNotificationHandler = new ConfigPersisterNotificationHandler(platformMBeanServer, persisterAggregator);
- synchronized (autoCloseables) {
- autoCloseables.add(jmxNotificationHandler);
- }
-
- LOG.debug("ConfigPusher has pushed configs {}", configs);
- } catch (NetconfDocumentedException e) {
- LOG.error("Error pushing configs {}",configs);
- throw new IllegalStateException(e);
- }
- }
- }
-
- public void pushConfigs(List<? extends ConfigSnapshotHolder> configs) throws InterruptedException {
- LOG.debug("Requested to push configs {}", configs);
- this.queue.put(configs);
- }
-
- private LinkedHashMap<? extends ConfigSnapshotHolder, EditAndCommitResponse> internalPushConfigs(List<? extends ConfigSnapshotHolder> configs) throws NetconfDocumentedException {
- LOG.debug("Last config snapshots to be pushed to netconf: {}", configs);
- LinkedHashMap<ConfigSnapshotHolder, EditAndCommitResponse> result = new LinkedHashMap<>();
- // start pushing snapshots:
- for (ConfigSnapshotHolder configSnapshotHolder : configs) {
- if(configSnapshotHolder != null) {
- EditAndCommitResponse editAndCommitResponseWithRetries = null;
- try {
- editAndCommitResponseWithRetries = pushConfigWithConflictingVersionRetries(configSnapshotHolder);
- } catch (ConfigSnapshotFailureException e) {
- LOG.warn("Failed to apply configuration snapshot: {}. Config snapshot is not semantically correct and will be IGNORED. " +
- "for detailed information see enclosed exception.", e.getConfigIdForReporting(), e);
- throw new IllegalStateException("Failed to apply configuration snapshot " + e.getConfigIdForReporting(), e);
- }
- LOG.debug("Config snapshot pushed successfully: {}, result: {}", configSnapshotHolder, result);
- result.put(configSnapshotHolder, editAndCommitResponseWithRetries);
- }
- }
- LOG.debug("All configuration snapshots have been pushed successfully.");
- return result;
- }
-
- /**
- * First calls {@link #getOperationServiceWithRetries(java.util.Set, String)} in order to wait until
- * expected capabilities are present, then tries to push configuration. If {@link ConflictingVersionException}
- * is caught, whole process is retried - new service instance need to be obtained from the factory. Closes
- * {@link NetconfOperationService} after each use.
- */
- private synchronized EditAndCommitResponse pushConfigWithConflictingVersionRetries(ConfigSnapshotHolder configSnapshotHolder) throws ConfigSnapshotFailureException {
- ConflictingVersionException lastException;
- Stopwatch stopwatch = Stopwatch.createUnstarted();
- do {
- String idForReporting = configSnapshotHolder.toString();
- SortedSet<String> expectedCapabilities = checkNotNull(configSnapshotHolder.getCapabilities(),
- "Expected capabilities must not be null - %s, check %s", idForReporting,
- configSnapshotHolder.getClass().getName());
- try (NetconfOperationService operationService = getOperationServiceWithRetries(expectedCapabilities, idForReporting)) {
- if(!stopwatch.isRunning()) {
- stopwatch.start();
- }
- return pushConfig(configSnapshotHolder, operationService);
- } catch (ConflictingVersionException e) {
- lastException = e;
- LOG.info("Conflicting version detected, will retry after timeout");
- sleep();
- }
- } while (stopwatch.elapsed(TimeUnit.MILLISECONDS) < conflictingVersionTimeoutMillis);
- throw new IllegalStateException("Max wait for conflicting version stabilization timeout after " + stopwatch.elapsed(TimeUnit.MILLISECONDS) + " ms",
- lastException);
- }
-
- private NetconfOperationService getOperationServiceWithRetries(Set<String> expectedCapabilities, String idForReporting) {
- Stopwatch stopwatch = Stopwatch.createStarted();
- ConfigPusherException lastException;
- do {
- try {
- return getOperationService(expectedCapabilities, idForReporting);
- } catch (ConfigPusherException e) {
- LOG.debug("Not enough capabilities: {}", e.toString());
- lastException = e;
- sleep();
- }
- } while (stopwatch.elapsed(TimeUnit.MILLISECONDS) < maxWaitForCapabilitiesMillis);
-
- if(lastException instanceof NotEnoughCapabilitiesException) {
- LOG.error("Unable to push configuration due to missing yang models." +
- " Yang models that are missing, but required by the configuration: {}." +
- " For each mentioned model check: " +
- " 1. that the mentioned yang model namespace/name/revision is identical to those in the yang model itself" +
- " 2. the yang file is present in the system" +
- " 3. the bundle with that yang file is present in the system and active" +
- " 4. the yang parser did not fail while attempting to parse that model",
- ((NotEnoughCapabilitiesException) lastException).getMissingCaps());
- throw new IllegalStateException("Unable to push configuration due to missing yang models." +
- " Required yang models that are missing: "
- + ((NotEnoughCapabilitiesException) lastException).getMissingCaps(), lastException);
- } else {
- final String msg = "Unable to push configuration due to missing netconf service";
- LOG.error(msg, lastException);
- throw new IllegalStateException(msg, lastException);
- }
- }
-
- private static class ConfigPusherException extends Exception {
-
- public ConfigPusherException(final String message) {
- super(message);
- }
-
- public ConfigPusherException(final String message, final Throwable cause) {
- super(message, cause);
- }
- }
-
- private static class NotEnoughCapabilitiesException extends ConfigPusherException {
- private static final long serialVersionUID = 1L;
- private Set<String> missingCaps;
-
- private NotEnoughCapabilitiesException(String message, Set<String> missingCaps) {
- super(message);
- this.missingCaps = missingCaps;
- }
-
- public Set<String> getMissingCaps() {
- return missingCaps;
- }
- }
-
- private static final class NetconfServiceNotAvailableException extends ConfigPusherException {
-
- public NetconfServiceNotAvailableException(final String s, final RuntimeException e) {
- super(s, e);
- }
- }
-
- private static final class ConfigSnapshotFailureException extends ConfigPusherException {
-
- private final String configIdForReporting;
-
- public ConfigSnapshotFailureException(final String configIdForReporting, final String operationNameForReporting, final Exception e) {
- super(String.format("Failed to apply config snapshot: %s during phase: %s", configIdForReporting, operationNameForReporting), e);
- this.configIdForReporting = configIdForReporting;
- }
-
- public String getConfigIdForReporting() {
- return configIdForReporting;
- }
- }
-
- /**
- * Get NetconfOperationService iif all required capabilities are present.
- *
- * @param expectedCapabilities that must be provided by configNetconfConnector
- * @param idForReporting
- * @return service if capabilities are present, otherwise absent value
- */
- private NetconfOperationService getOperationService(Set<String> expectedCapabilities, String idForReporting) throws ConfigPusherException {
- NetconfOperationService serviceCandidate;
- try {
- serviceCandidate = configNetconfConnector.createService(idForReporting);
- } catch(RuntimeException e) {
- throw new NetconfServiceNotAvailableException("Netconf service not stable for config pusher." +
- " Cannot push any configuration", e);
- }
- Set<String> notFoundDiff = computeNotFoundCapabilities(expectedCapabilities, configNetconfConnector);
- if (notFoundDiff.isEmpty()) {
- return serviceCandidate;
- } else {
- serviceCandidate.close();
- LOG.debug("Netconf server did not provide required capabilities for {} ", idForReporting,
- "Expected but not found: {}, all expected {}, current {}",
- notFoundDiff, expectedCapabilities, configNetconfConnector.getCapabilities()
- );
- throw new NotEnoughCapabilitiesException("Not enough capabilities for " + idForReporting + ". Expected but not found: " + notFoundDiff, notFoundDiff);
- }
- }
-
- private static Set<String> computeNotFoundCapabilities(Set<String> expectedCapabilities, NetconfOperationServiceFactory serviceCandidate) {
- Collection<String> actual = Collections2.transform(serviceCandidate.getCapabilities(), new Function<Capability, String>() {
- @Override
- public String apply(@Nonnull final Capability input) {
- return input.getCapabilityUri();
- }
- });
- Set<String> allNotFound = new HashSet<>(expectedCapabilities);
- allNotFound.removeAll(actual);
- return allNotFound;
- }
-
- private void sleep() {
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- throw new IllegalStateException(e);
- }
- }
-
- /**
- * Sends two RPCs to the netconf server: edit-config and commit.
- *
- * @param configSnapshotHolder
- * @throws ConflictingVersionException if commit fails on optimistic lock failure inside of config-manager
- * @throws java.lang.RuntimeException if edit-config or commit fails otherwise
- */
- private synchronized EditAndCommitResponse pushConfig(ConfigSnapshotHolder configSnapshotHolder, NetconfOperationService operationService)
- throws ConflictingVersionException, ConfigSnapshotFailureException {
-
- Element xmlToBePersisted;
- try {
- xmlToBePersisted = XmlUtil.readXmlToElement(configSnapshotHolder.getConfigSnapshot());
- } catch (SAXException | IOException e) {
- throw new IllegalStateException("Cannot parse " + configSnapshotHolder);
- }
- LOG.trace("Pushing last configuration to netconf: {}", configSnapshotHolder);
- Stopwatch stopwatch = Stopwatch.createStarted();
- NetconfMessage editConfigMessage = createEditConfigMessage(xmlToBePersisted);
-
- Document editResponseMessage = sendRequestGetResponseCheckIsOK(editConfigMessage, operationService,
- "edit-config", configSnapshotHolder.toString());
-
- Document commitResponseMessage = sendRequestGetResponseCheckIsOK(getCommitMessage(), operationService,
- "commit", configSnapshotHolder.toString());
-
- if (LOG.isTraceEnabled()) {
- StringBuilder response = new StringBuilder("editConfig response = {");
- response.append(XmlUtil.toString(editResponseMessage));
- response.append("}");
- response.append("commit response = {");
- response.append(XmlUtil.toString(commitResponseMessage));
- response.append("}");
- LOG.trace("Last configuration loaded successfully");
- LOG.trace("Detailed message {}", response);
- LOG.trace("Total time spent {} ms", stopwatch.elapsed(TimeUnit.MILLISECONDS));
- }
- return new EditAndCommitResponse(editResponseMessage, commitResponseMessage);
- }
-
- private NetconfOperation findOperation(NetconfMessage request, NetconfOperationService operationService) {
- TreeMap<HandlingPriority, NetconfOperation> allOperations = new TreeMap<>();
- Set<NetconfOperation> netconfOperations = operationService.getNetconfOperations();
- if (netconfOperations.isEmpty()) {
- throw new IllegalStateException("Possible code error: no config operations");
- }
- for (NetconfOperation netconfOperation : netconfOperations) {
- HandlingPriority handlingPriority = null;
- try {
- handlingPriority = netconfOperation.canHandle(request.getDocument());
- } catch (NetconfDocumentedException e) {
- throw new IllegalStateException("Possible code error: canHandle threw exception", e);
- }
- allOperations.put(handlingPriority, netconfOperation);
- }
- Entry<HandlingPriority, NetconfOperation> highestEntry = allOperations.lastEntry();
- if (highestEntry.getKey().isCannotHandle()) {
- throw new IllegalStateException("Possible code error: operation with highest priority is CANNOT_HANDLE");
- }
- return highestEntry.getValue();
- }
-
- private Document sendRequestGetResponseCheckIsOK(NetconfMessage request, NetconfOperationService operationService,
- String operationNameForReporting, String configIdForReporting)
- throws ConflictingVersionException, ConfigSnapshotFailureException {
-
- NetconfOperation operation = findOperation(request, operationService);
- Document response;
- try {
- response = operation.handle(request.getDocument(), NetconfOperationChainedExecution.EXECUTION_TERMINATION_POINT);
- return NetconfUtil.checkIsMessageOk(response);
- } catch (NetconfDocumentedException e) {
- if (e.getCause() instanceof ConflictingVersionException) {
- throw (ConflictingVersionException) e.getCause();
- }
- throw new ConfigSnapshotFailureException(configIdForReporting, operationNameForReporting, e);
- }
- }
-
- // load editConfig.xml template, populate /rpc/edit-config/config with parameter
- private static NetconfMessage createEditConfigMessage(Element dataElement) {
- String editConfigResourcePath = "/netconfOp/editConfig.xml";
- try (InputStream stream = ConfigPersisterNotificationHandler.class.getResourceAsStream(editConfigResourcePath)) {
- checkNotNull(stream, "Unable to load resource " + editConfigResourcePath);
-
- Document doc = XmlUtil.readXmlToDocument(stream);
-
- XmlElement editConfigElement = XmlElement.fromDomDocument(doc).getOnlyChildElement();
- XmlElement configWrapper = editConfigElement.getOnlyChildElement(XmlNetconfConstants.CONFIG_KEY);
- editConfigElement.getDomElement().removeChild(configWrapper.getDomElement());
- for (XmlElement el : XmlElement.fromDomElement(dataElement).getChildElements()) {
- boolean deep = true;
- configWrapper.appendChild((Element) doc.importNode(el.getDomElement(), deep));
- }
- editConfigElement.appendChild(configWrapper.getDomElement());
- return new NetconfMessage(doc);
- } catch (IOException | SAXException | NetconfDocumentedException e) {
- // error reading the xml file bundled into the jar
- throw new IllegalStateException("Error while opening local resource " + editConfigResourcePath, e);
- }
- }
-
- private static NetconfMessage getCommitMessage() {
- String resource = "/netconfOp/commit.xml";
- try (InputStream stream = ConfigPusherImpl.class.getResourceAsStream(resource)) {
- checkNotNull(stream, "Unable to load resource " + resource);
- return new NetconfMessage(XmlUtil.readXmlToDocument(stream));
- } catch (SAXException | IOException e) {
- // error reading the xml file bundled into the jar
- throw new IllegalStateException("Error while opening local resource " + resource, e);
- }
- }
-
- static class EditAndCommitResponse {
- private final Document editResponse, commitResponse;
-
- EditAndCommitResponse(Document editResponse, Document commitResponse) {
- this.editResponse = editResponse;
- this.commitResponse = commitResponse;
- }
-
- public Document getEditResponse() {
- return editResponse;
- }
-
- public Document getCommitResponse() {
- return commitResponse;
- }
-
- @Override
- public String toString() {
- return "EditAndCommitResponse{" +
- "editResponse=" + editResponse +
- ", commitResponse=" + commitResponse +
- '}';
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.persist.impl;
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.List;
-import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
-import org.opendaylight.controller.config.persist.api.Persister;
-import org.opendaylight.controller.config.persist.api.PropertiesProvider;
-import org.opendaylight.controller.config.persist.api.StorageAdapter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class NoOpStorageAdapter implements StorageAdapter, Persister {
- private static final Logger LOG = LoggerFactory.getLogger(NoOpStorageAdapter.class);
-
- @Override
- public Persister instantiate(PropertiesProvider propertiesProvider) {
- LOG.debug("instantiate called with {}", propertiesProvider);
- return this;
- }
-
- @Override
- public void persistConfig(ConfigSnapshotHolder holder) throws IOException {
- LOG.debug("persistConfig called with {}", holder);
- }
-
- @Override
- public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
- LOG.debug("loadLastConfig called");
- return Collections.emptyList();
- }
-
- @Override
- public void close() {
- LOG.debug("close called");
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.persist.impl;
-
-import com.google.common.annotations.VisibleForTesting;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.ListIterator;
-import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
-import org.opendaylight.controller.config.persist.api.Persister;
-import org.opendaylight.controller.config.persist.api.PropertiesProvider;
-import org.opendaylight.controller.config.persist.api.StorageAdapter;
-import org.opendaylight.controller.netconf.persist.impl.osgi.ConfigPersisterActivator;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * {@link Persister} implementation that delegates persisting functionality to
- * underlying {@link Persister} storages. Each storage has unique id, class, readonly value.
- *
- * Storage adapters are low level persisters that do the heavy lifting for this
- * class. Instances of storage adapters can be injected directly via constructor
- * or instantiated from a full name of its class provided in a properties file.
- *
- * Example configuration:<pre>
- netconf.config.persister.active=2,3
- # read startup configuration
- netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter
- netconf.config.persister.1.properties.fileStorage=configuration/initial/
-
- netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter
- netconf.config.persister.2.readonly=true
- netconf.config.persister.2.properties.fileStorage=configuration/current/controller.config.1.xml
-
- netconf.config.persister.3.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter
- netconf.config.persister.3.properties.fileStorage=configuration/current/controller.config.2.xml
- netconf.config.persister.3.properties.numberOfBackups=3
-
- </pre>
- * During server startup {@link ConfigPersisterNotificationHandler} requests last snapshot from underlying storages.
- * Each storage can respond by giving snapshot or absent response.
- * The {@link #loadLastConfigs()} will search for first non-absent response from storages ordered backwards as user
- * specified (first '3', then '2').
- *
- * When a commit notification is received, '2' will be omitted because readonly flag is set to true, so
- * only '3' will have a chance to persist new configuration. If readonly was false or not specified, both storage adapters
- * would be called in order specified by 'netconf.config.persister' property.
- *
- */
-public final class PersisterAggregator implements Persister {
- private static final Logger LOG = LoggerFactory.getLogger(PersisterAggregator.class);
-
- public static class PersisterWithConfiguration {
-
- private final Persister storage;
- private final boolean readOnly;
-
- public PersisterWithConfiguration(Persister storage, boolean readOnly) {
- this.storage = storage;
- this.readOnly = readOnly;
- }
-
- @VisibleForTesting
- public Persister getStorage() {
- return storage;
- }
-
- @VisibleForTesting
- public boolean isReadOnly() {
- return readOnly;
- }
-
- @Override
- public String toString() {
- return "PersisterWithConfiguration{" +
- "storage=" + storage +
- ", readOnly=" + readOnly +
- '}';
- }
- }
-
- private static PersisterWithConfiguration loadConfiguration(final String index, final PropertiesProvider propertiesProvider) {
-
- String classKey = index + "." + ConfigPersisterActivator.STORAGE_ADAPTER_CLASS_PROP_SUFFIX;
- String storageAdapterClass = propertiesProvider.getProperty(classKey);
- StorageAdapter storageAdapter;
- if (storageAdapterClass == null || storageAdapterClass.equals("")) {
- throw new IllegalStateException("No persister is defined in " +
- propertiesProvider.getFullKeyForReporting(classKey)
- + " property. Persister is not operational");
- }
-
- try {
- Class<?> clazz = Class.forName(storageAdapterClass);
- boolean implementsCorrectIfc = StorageAdapter.class.isAssignableFrom(clazz);
- if (!implementsCorrectIfc) {
- throw new IllegalArgumentException("Storage adapter " + clazz + " does not implement " + StorageAdapter.class);
- }
- storageAdapter = StorageAdapter.class.cast(clazz.newInstance());
-
- boolean readOnly = false;
- String readOnlyProperty = propertiesProvider.getProperty(index + "." + "readonly");
- if (readOnlyProperty != null && readOnlyProperty.equals("true")) {
- readOnly = true;
- }
-
- PropertiesProviderAdapterImpl innerProvider = new PropertiesProviderAdapterImpl(propertiesProvider, index);
- Persister storage = storageAdapter.instantiate(innerProvider);
- return new PersisterWithConfiguration(storage, readOnly);
- } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
- throw new IllegalArgumentException("Unable to instantiate storage adapter from " + storageAdapterClass, e);
- }
- }
-
- /**
- * Persisters ordered by 'netconf.config.persister' property.
- */
- private final List<PersisterWithConfiguration> persisterWithConfigurations;
-
- public PersisterAggregator(List<PersisterWithConfiguration> persisterWithConfigurations) {
- this.persisterWithConfigurations = persisterWithConfigurations;
-
- }
-
- public static PersisterAggregator createFromProperties(PropertiesProvider propertiesProvider) {
- List<PersisterWithConfiguration> persisterWithConfigurations = new ArrayList<>();
- String prefixes = propertiesProvider.getProperty("active");
- if (prefixes!=null && !prefixes.isEmpty()) {
- String [] keys = prefixes.split(",");
- for (String index: keys) {
- persisterWithConfigurations.add(PersisterAggregator.loadConfiguration(index, propertiesProvider));
- }
- }
- LOG.debug("Initialized persister with following adapters {}", persisterWithConfigurations);
- return new PersisterAggregator(persisterWithConfigurations);
- }
-
- @Override
- public void persistConfig(ConfigSnapshotHolder holder) throws IOException {
- for (PersisterWithConfiguration persisterWithConfiguration: persisterWithConfigurations){
- if (!persisterWithConfiguration.readOnly){
- LOG.debug("Calling {}.persistConfig", persisterWithConfiguration.getStorage());
- persisterWithConfiguration.getStorage().persistConfig(holder);
- }
- }
- }
-
- /**
- * @return last non-empty result from input persisters
- */
- @Override
- public List<ConfigSnapshotHolder> loadLastConfigs() {
- // iterate in reverse order
- ListIterator<PersisterWithConfiguration> li = persisterWithConfigurations.listIterator(persisterWithConfigurations.size());
- while(li.hasPrevious()) {
- PersisterWithConfiguration persisterWithConfiguration = li.previous();
- List<ConfigSnapshotHolder> configs = null;
- try {
- configs = persisterWithConfiguration.storage.loadLastConfigs();
- } catch (IOException e) {
- throw new RuntimeException("Error while calling loadLastConfig on " + persisterWithConfiguration, e);
- }
- if (!configs.isEmpty()) {
- LOG.debug("Found non empty configs using {}:{}", persisterWithConfiguration, configs);
- return configs;
- }
- }
- // no storage had an answer
- LOG.debug("No non-empty list of configuration snapshots found");
- return Collections.emptyList();
- }
-
- @VisibleForTesting
- List<PersisterWithConfiguration> getPersisterWithConfigurations() {
- return persisterWithConfigurations;
- }
-
- @Override
- public void close() {
- RuntimeException lastException = null;
- for (PersisterWithConfiguration persisterWithConfiguration: persisterWithConfigurations){
- try{
- persisterWithConfiguration.storage.close();
- }catch(RuntimeException e) {
- LOG.error("Error while closing {}", persisterWithConfiguration.storage, e);
- if (lastException == null){
- lastException = e;
- } else {
- lastException.addSuppressed(e);
- }
- }
- }
- if (lastException != null){
- throw lastException;
- }
- }
-
- @Override
- public String toString() {
- return "PersisterAggregator{" +
- "persisterWithConfigurations=" + persisterWithConfigurations +
- '}';
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.netconf.persist.impl;
-
-import org.opendaylight.controller.config.persist.api.PropertiesProvider;
-
-public class PropertiesProviderAdapterImpl implements PropertiesProvider {
- private final PropertiesProvider inner;
- private final String index;
-
- public PropertiesProviderAdapterImpl(PropertiesProvider inner, String index) {
- this.inner = inner;
- this.index = index;
- }
-
- @Override
- public String getProperty(String key) {
- String fullKey = getFullKeyForReporting(key);
- return inner.getPropertyWithoutPrefix(fullKey);
- }
-
- public String getPrefix() {
- return inner.getPrefix() + "." + index + ".properties";
- }
-
- @Override
- public String getPropertyWithoutPrefix(String fullKey) {
- return inner.getPropertyWithoutPrefix(fullKey);
- }
-
-
- @Override
- public String getFullKeyForReporting(String key) {
- return getPrefix() + "." + key;
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.persist.impl.osgi;
-
-import com.google.common.annotations.VisibleForTesting;
-import java.lang.management.ManagementFactory;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import javax.management.MBeanServer;
-import org.opendaylight.controller.config.persist.api.ConfigPusher;
-import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
-import org.opendaylight.controller.netconf.persist.impl.ConfigPusherImpl;
-import org.opendaylight.controller.netconf.persist.impl.PersisterAggregator;
-import org.opendaylight.controller.netconf.util.CloseableUtil;
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.Filter;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.util.tracker.ServiceTracker;
-import org.osgi.util.tracker.ServiceTrackerCustomizer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ConfigPersisterActivator implements BundleActivator {
-
- private static final Logger LOG = LoggerFactory.getLogger(ConfigPersisterActivator.class);
- private static final MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
-
- public static final String MAX_WAIT_FOR_CAPABILITIES_MILLIS_PROPERTY = "maxWaitForCapabilitiesMillis";
- private static final long MAX_WAIT_FOR_CAPABILITIES_MILLIS_DEFAULT = TimeUnit.MINUTES.toMillis(2);
- public static final String CONFLICTING_VERSION_TIMEOUT_MILLIS_PROPERTY = "conflictingVersionTimeoutMillis";
- private static final long CONFLICTING_VERSION_TIMEOUT_MILLIS_DEFAULT = TimeUnit.MINUTES.toMillis(1);
-
- public static final String NETCONF_CONFIG_PERSISTER = "netconf.config.persister";
-
- public static final String STORAGE_ADAPTER_CLASS_PROP_SUFFIX = "storageAdapterClass";
-
- private List<AutoCloseable> autoCloseables;
- private volatile BundleContext context;
-
- ServiceRegistration<?> registration;
-
- @Override
- public void start(final BundleContext context) throws Exception {
- LOG.debug("ConfigPersister starting");
- this.context = context;
-
- autoCloseables = new ArrayList<>();
- PropertiesProviderBaseImpl propertiesProvider = new PropertiesProviderBaseImpl(context);
-
- final PersisterAggregator persisterAggregator = PersisterAggregator.createFromProperties(propertiesProvider);
- autoCloseables.add(persisterAggregator);
- long maxWaitForCapabilitiesMillis = getMaxWaitForCapabilitiesMillis(propertiesProvider);
- List<ConfigSnapshotHolder> configs = persisterAggregator.loadLastConfigs();
- long conflictingVersionTimeoutMillis = getConflictingVersionTimeoutMillis(propertiesProvider);
- LOG.debug("Following configs will be pushed: {}", configs);
-
- InnerCustomizer innerCustomizer = new InnerCustomizer(configs, maxWaitForCapabilitiesMillis,
- conflictingVersionTimeoutMillis, persisterAggregator);
- OuterCustomizer outerCustomizer = new OuterCustomizer(context, innerCustomizer);
- new ServiceTracker<>(context, NetconfOperationServiceFactory.class, outerCustomizer).open();
- }
-
- private long getConflictingVersionTimeoutMillis(PropertiesProviderBaseImpl propertiesProvider) {
- String timeoutProperty = propertiesProvider.getProperty(CONFLICTING_VERSION_TIMEOUT_MILLIS_PROPERTY);
- return timeoutProperty == null ? CONFLICTING_VERSION_TIMEOUT_MILLIS_DEFAULT : Long.valueOf(timeoutProperty);
- }
-
- private long getMaxWaitForCapabilitiesMillis(PropertiesProviderBaseImpl propertiesProvider) {
- String timeoutProperty = propertiesProvider.getProperty(MAX_WAIT_FOR_CAPABILITIES_MILLIS_PROPERTY);
- return timeoutProperty == null ? MAX_WAIT_FOR_CAPABILITIES_MILLIS_DEFAULT : Long.valueOf(timeoutProperty);
- }
-
- @Override
- public void stop(BundleContext context) throws Exception {
- synchronized(autoCloseables) {
- CloseableUtil.closeAll(autoCloseables);
- if (registration != null) {
- registration.unregister();
- }
- this.context = null;
- }
- }
-
-
- @VisibleForTesting
- public static String getFilterString() {
- return "(&" +
- "(" + Constants.OBJECTCLASS + "=" + NetconfOperationServiceFactory.class.getName() + ")" +
- "(name" + "=" + "config-netconf-connector" + ")" +
- ")";
- }
-
- class OuterCustomizer implements ServiceTrackerCustomizer<NetconfOperationServiceFactory, NetconfOperationServiceFactory> {
- private final BundleContext context;
- private final InnerCustomizer innerCustomizer;
-
- OuterCustomizer(BundleContext context, InnerCustomizer innerCustomizer) {
- this.context = context;
- this.innerCustomizer = innerCustomizer;
- }
-
- @Override
- public NetconfOperationServiceFactory addingService(ServiceReference<NetconfOperationServiceFactory> reference) {
- LOG.trace("Got OuterCustomizer.addingService {}", reference);
- // JMX was registered, track config-netconf-connector
- Filter filter;
- try {
- filter = context.createFilter(getFilterString());
- } catch (InvalidSyntaxException e) {
- throw new IllegalStateException(e);
- }
- new ServiceTracker<>(context, filter, innerCustomizer).open();
- return null;
- }
-
- @Override
- public void modifiedService(ServiceReference<NetconfOperationServiceFactory> reference, NetconfOperationServiceFactory service) {
-
- }
-
- @Override
- public void removedService(ServiceReference<NetconfOperationServiceFactory> reference, NetconfOperationServiceFactory service) {
-
- }
- }
-
- class InnerCustomizer implements ServiceTrackerCustomizer<NetconfOperationServiceFactory, NetconfOperationServiceFactory> {
- private final List<ConfigSnapshotHolder> configs;
- private final PersisterAggregator persisterAggregator;
- private final long maxWaitForCapabilitiesMillis, conflictingVersionTimeoutMillis;
- // This inner customizer has its filter to find the right operation service, but it gets triggered after any
- // operation service appears. This means that it could start pushing thread up to N times (N = number of operation services spawned in OSGi)
- private final AtomicBoolean alreadyStarted = new AtomicBoolean(false);
-
- InnerCustomizer(List<ConfigSnapshotHolder> configs, long maxWaitForCapabilitiesMillis, long conflictingVersionTimeoutMillis,
- PersisterAggregator persisterAggregator) {
- this.configs = configs;
- this.maxWaitForCapabilitiesMillis = maxWaitForCapabilitiesMillis;
- this.conflictingVersionTimeoutMillis = conflictingVersionTimeoutMillis;
- this.persisterAggregator = persisterAggregator;
- }
-
- @Override
- public NetconfOperationServiceFactory addingService(ServiceReference<NetconfOperationServiceFactory> reference) {
- if(alreadyStarted.compareAndSet(false, true) == false) {
- //Prevents multiple calls to this method spawning multiple pushing threads
- return reference.getBundle().getBundleContext().getService(reference);
- }
- LOG.trace("Got InnerCustomizer.addingService {}", reference);
- NetconfOperationServiceFactory service = reference.getBundle().getBundleContext().getService(reference);
-
- LOG.debug("Creating new job queue");
-
- final ConfigPusherImpl configPusher = new ConfigPusherImpl(service, maxWaitForCapabilitiesMillis, conflictingVersionTimeoutMillis);
- LOG.debug("Configuration Persister got {}", service);
- LOG.debug("Context was {}", context);
- LOG.debug("Registration was {}", registration);
-
- final Thread pushingThread = new Thread(new Runnable() {
- @Override
- public void run() {
- try {
- if(configs != null && !configs.isEmpty()) {
- configPusher.pushConfigs(configs);
- }
- if(context != null) {
- registration = context.registerService(ConfigPusher.class.getName(), configPusher, null);
- configPusher.process(autoCloseables, platformMBeanServer, persisterAggregator);
- } else {
- LOG.warn("Unable to process configs as BundleContext is null");
- }
- } catch (InterruptedException e) {
- LOG.info("ConfigPusher thread stopped",e);
- }
- LOG.info("Configuration Persister initialization completed.");
- }
- }, "config-pusher");
- synchronized (autoCloseables) {
- autoCloseables.add(new AutoCloseable() {
- @Override
- public void close() {
- pushingThread.interrupt();
- }
- });
- }
- pushingThread.start();
- return service;
- }
-
- @Override
- public void modifiedService(ServiceReference<NetconfOperationServiceFactory> reference, NetconfOperationServiceFactory service) {
- LOG.trace("Got InnerCustomizer.modifiedService {}", reference);
- }
-
- @Override
- public void removedService(ServiceReference<NetconfOperationServiceFactory> reference, NetconfOperationServiceFactory service) {
- LOG.trace("Got InnerCustomizer.removedService {}", reference);
- }
-
- }
-}
-
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.netconf.persist.impl.osgi;
-
-import org.opendaylight.controller.config.persist.api.PropertiesProvider;
-import org.osgi.framework.BundleContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class PropertiesProviderBaseImpl implements PropertiesProvider {
-
- private static final Logger LOG = LoggerFactory.getLogger(PropertiesProviderBaseImpl.class);
- private final BundleContext bundleContext;
-
- public PropertiesProviderBaseImpl(BundleContext bundleContext) {
- this.bundleContext = bundleContext;
- }
-
- @Override
- public String getProperty(String key) {
- String fullKey = getFullKeyForReporting(key);
- return getPropertyWithoutPrefix(fullKey);
- }
-
- public String getPropertyWithoutPrefix(String fullKey){
- LOG.trace("Full key {}", fullKey);
- return bundleContext.getProperty(fullKey);
- }
-
- public String getPrefix(){
- return ConfigPersisterActivator.NETCONF_CONFIG_PERSISTER;
- }
-
- @Override
- public String getFullKeyForReporting(String key) {
- return getPrefix() + "." + key;
- }
-}
+++ /dev/null
- <hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
- <capabilities>
- <capability>urn:ietf:params:netconf:base:1.0</capability>
- </capabilities>
- </hello>
+++ /dev/null
-<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="persister_commit" notify="false">
- <commit></commit>
-</rpc>
\ No newline at end of file
+++ /dev/null
-<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="persister_edit">
- <edit-config>
- <target>
- <candidate/>
- </target>
- <default-operation>merge</default-operation>
-
- <config>
- </config>
-
- </edit-config>
-</rpc>
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.netconf.persist.impl;
-
-import static org.junit.Assert.assertEquals;
-import com.google.common.base.Charsets;
-import com.google.common.collect.Sets;
-import com.google.common.io.Resources;
-import java.io.IOException;
-import java.util.HashSet;
-import java.util.Set;
-import org.junit.Test;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.w3c.dom.Element;
-
-public class CapabilityStrippingConfigSnapshotHolderTest {
-
- @Test
- public void testCapabilityStripping() throws Exception {
- Set<String> allCapabilities = readLines("/capabilities-all.txt");
- Set<String> expectedCapabilities = readLines("/capabilities-stripped.txt");
- String snapshotAsString = readToString("/snapshot.xml");
- Element element = XmlUtil.readXmlToElement(snapshotAsString);
- CapabilityStrippingConfigSnapshotHolder tested = new CapabilityStrippingConfigSnapshotHolder(
- element, allCapabilities);
- assertEquals(expectedCapabilities, tested.getCapabilities());
-
- Set<String> obsoleteCapabilities = Sets.difference(allCapabilities, expectedCapabilities);
-
- assertEquals(obsoleteCapabilities, tested.getObsoleteCapabilities());
- }
-
- private Set<String> readLines(String fileName) throws IOException {
- return new HashSet<>(Resources.readLines(getClass().getResource(fileName), Charsets.UTF_8));
- }
-
- private String readToString(String fileName) throws IOException {
- return Resources.toString(getClass().getResource(fileName), Charsets.UTF_8);
- }
-
-}
+++ /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.netconf.persist.impl;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import javax.management.MBeanServerConnection;
-import javax.management.NotificationFilter;
-import javax.management.NotificationListener;
-import javax.management.ObjectName;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.opendaylight.controller.config.persist.api.Persister;
-
-public class ConfigPersisterNotificationHandlerTest {
-
- @Mock
- private MBeanServerConnection mBeanServer;
- @Mock
- private Persister notificationListener;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- doNothing().when(mBeanServer).addNotificationListener(any(ObjectName.class), any(NotificationListener.class),
- any(NotificationFilter.class), anyObject());
- }
-
- @Test
- public void testNotificationHandler() throws Exception {
- doReturn(true).when(mBeanServer).isRegistered(any(ObjectName.class));
- doThrow(Exception.class).when(mBeanServer).removeNotificationListener(any(ObjectName.class), any(NotificationListener.class));
-
- final ConfigPersisterNotificationHandler testedHandler = new ConfigPersisterNotificationHandler(mBeanServer, notificationListener);
- verify(mBeanServer).addNotificationListener(any(ObjectName.class), any(NotificationListener.class),
- any(NotificationFilter.class), anyObject());
-
- testedHandler.close();
- verify(mBeanServer).removeNotificationListener(any(ObjectName.class), any(NotificationListener.class));
- }
-
- @Test
- public void testNotificationHandlerCloseNotRegistered() throws Exception {
- doReturn(false).when(mBeanServer).isRegistered(any(ObjectName.class));
-
- final ConfigPersisterNotificationHandler testedHandler = new ConfigPersisterNotificationHandler(mBeanServer, notificationListener);
-
- testedHandler.close();
- verify(mBeanServer, times(0)).removeNotificationListener(any(ObjectName.class), any(NotificationListener.class));
- }
-}
+++ /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.netconf.persist.impl;
-
-import com.google.common.collect.Lists;
-import java.util.Collections;
-import javax.management.Notification;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Matchers;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
-import org.opendaylight.controller.config.persist.api.Persister;
-import org.opendaylight.controller.netconf.api.jmx.CommitJMXNotification;
-import org.opendaylight.controller.netconf.api.jmx.NetconfJMXNotification;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-
-public class ConfigPersisterNotificationListenerTest {
-
- @Mock
- private Persister mockPersister;
- private PersisterAggregator persisterAggregator;
-
- @Mock
- private NetconfJMXNotification unknownNetconfNotif;
- @Mock
- private CommitJMXNotification commitNetconfNotif;
- @Mock
- private Notification unknownNotif;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- Mockito.doNothing().when(mockPersister).persistConfig(Matchers.any(ConfigSnapshotHolder.class));
- Mockito.doReturn("persister").when(mockPersister).toString();
- final PersisterAggregator.PersisterWithConfiguration withCfg = new PersisterAggregator.PersisterWithConfiguration(mockPersister, false);
- persisterAggregator = new PersisterAggregator(Lists.newArrayList(withCfg));
-
- Mockito.doReturn("netconfUnknownNotification").when(unknownNetconfNotif).toString();
- Mockito.doReturn("netconfCommitNotification").when(commitNetconfNotif).toString();
-
- Mockito.doReturn(XmlUtil.readXmlToElement("<config-snapshot/>")).when(commitNetconfNotif).getConfigSnapshot();
- Mockito.doReturn(Collections.emptySet()).when(commitNetconfNotif).getCapabilities();
-
- }
-
- @Test
- public void testNotificationListenerUnknownNotification() throws Exception {
- final ConfigPersisterNotificationListener testeListener = new ConfigPersisterNotificationListener(persisterAggregator);
- testeListener.handleNotification(unknownNotif, null);
- Mockito.verifyZeroInteractions(mockPersister);
- }
-
- @Test
- public void testNotificationListenerUnknownNetconfNotification() throws Exception {
- final ConfigPersisterNotificationListener testeListener = new ConfigPersisterNotificationListener(persisterAggregator);
- try {
- testeListener.handleNotification(unknownNetconfNotif, null);
- Assert.fail("Unknown netconf notification should fail");
- } catch (final IllegalStateException e) {
- Mockito.verifyZeroInteractions(mockPersister);
- }
- }
-
- @Test
- public void testNotificationListenerCommitNetconfNotification() throws Exception {
- final ConfigPersisterNotificationListener testeListener = new ConfigPersisterNotificationListener(persisterAggregator);
- testeListener.handleNotification(commitNetconfNotif, null);
- Mockito.verify(mockPersister).persistConfig(Matchers.any(ConfigSnapshotHolder.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.netconf.persist.impl;
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.List;
-import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
-import org.opendaylight.controller.config.persist.api.Persister;
-import org.opendaylight.controller.config.persist.api.PropertiesProvider;
-import org.opendaylight.controller.config.persist.api.StorageAdapter;
-
-public class DummyAdapter implements StorageAdapter, Persister {
-
- static int persist = 0;
-
- @Override
- public void persistConfig(ConfigSnapshotHolder holder) throws IOException {
- persist++;
- }
-
- static int load = 0;
-
- @Override
- public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
- load++;
- return Collections.emptyList();
- }
-
- static int props = 0;
-
- @Override
- public Persister instantiate(PropertiesProvider propertiesProvider) {
- props++;
- return this;
- }
-
- @Override
- public void close() {
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.persist.impl;
-
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.opendaylight.controller.netconf.persist.impl.PersisterAggregator.PersisterWithConfiguration;
-
-import com.google.common.collect.Lists;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Properties;
-import org.junit.Before;
-import org.junit.Test;
-import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
-import org.opendaylight.controller.config.persist.api.Persister;
-import org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter;
-import org.opendaylight.controller.netconf.persist.impl.osgi.ConfigPersisterActivator;
-import org.opendaylight.controller.netconf.persist.impl.osgi.PropertiesProviderBaseImpl;
-
-public class PersisterAggregatorTest {
-
- static class TestingPropertiesProvider extends PropertiesProviderBaseImpl {
-
- private final Properties prop;
-
- public TestingPropertiesProvider(Properties prop) {
- super(null);
- this.prop = prop;
- }
-
- public static TestingPropertiesProvider loadFile(String fileName) {
- Properties prop = new Properties();
- try {
- prop.load(TestingPropertiesProvider.class.getClassLoader().getResourceAsStream(fileName));
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- return new TestingPropertiesProvider(prop);
- }
-
- @Override
- public String getFullKeyForReporting(String key) {
- return ConfigPersisterActivator.NETCONF_CONFIG_PERSISTER + "." + key;
- }
-
- @Override
- public String getProperty(String key) {
- return prop.getProperty(getFullKeyForReporting(key));
- }
-
- @Override
- public String getPropertyWithoutPrefix(String fullKey){
- return prop.getProperty(fullKey);
- }
- }
-
- @Before
- public void setUp() throws Exception {
- if(XmlFileStorageAdapter.getInstance().isPresent()) {
- XmlFileStorageAdapter.getInstance().get().reset();
- }
- }
-
- @Test
- public void testDummyAdapter() throws Exception {
- PersisterAggregator persisterAggregator = PersisterAggregator.createFromProperties(TestingPropertiesProvider.loadFile("test1.properties"));
- List<PersisterWithConfiguration> persisters = persisterAggregator.getPersisterWithConfigurations();
- assertEquals(1, persisters.size());
- PersisterWithConfiguration persister = persisters.get(0);
- assertEquals(DummyAdapter.class.getName(), persister.getStorage().getClass().getName());
- assertFalse(persister.isReadOnly());
-
- persisterAggregator.persistConfig(null);
- persisterAggregator.loadLastConfigs();
- persisterAggregator.persistConfig(null);
- persisterAggregator.loadLastConfigs();
-
- assertEquals(2, DummyAdapter.persist);
- assertEquals(2, DummyAdapter.load);
- assertEquals(1, DummyAdapter.props);
- }
-
- @Test
- public void testNoopAdapter() throws Exception {
- final NoOpStorageAdapter noOpStorageAdapter = new NoOpStorageAdapter();
- final PersisterAggregator persisterAggregator =
- new PersisterAggregator(Lists.newArrayList(new PersisterWithConfiguration(noOpStorageAdapter, false)));
-
- noOpStorageAdapter.instantiate(null);
-
- persisterAggregator.persistConfig(null);
- persisterAggregator.loadLastConfigs();
- persisterAggregator.persistConfig(null);
- persisterAggregator.loadLastConfigs();
-
- noOpStorageAdapter.close();
- }
-
- @Test
- public void testLoadFromPropertyFile() throws Exception {
- PersisterAggregator persisterAggregator = PersisterAggregator.createFromProperties(TestingPropertiesProvider.loadFile("test2.properties"));
- List<PersisterWithConfiguration> persisters = persisterAggregator.getPersisterWithConfigurations();
- assertEquals(1, persisters.size());
- PersisterWithConfiguration persister = persisters.get(0);
- assertEquals(XmlFileStorageAdapter.class.getName() ,persister.getStorage().getClass().getName());
- assertFalse(persister.isReadOnly());
- }
-
- @Test
- public void testFileStorageNumberOfBackups() throws Exception {
- try {
- PersisterAggregator.createFromProperties(TestingPropertiesProvider.loadFile("test3.properties"));
- fail();
- } catch (RuntimeException e) {
- assertThat(
- e.getMessage(),
- containsString("numberOfBackups property should be either set to positive value, or ommited. Can not be set to 0."));
- }
- }
-
- private ConfigSnapshotHolder mockHolder(String name){
- ConfigSnapshotHolder result = mock(ConfigSnapshotHolder.class);
- doReturn("mock:" + name).when(result).toString();
- return result;
- }
-
- private Persister mockPersister(String name){
- Persister result = mock(Persister.class);
- doReturn("mock:" + name).when(result).toString();
- return result;
- }
-
- @Test
- public void loadLastConfig() throws Exception {
- List<PersisterWithConfiguration> persisterWithConfigurations = new ArrayList<>();
- PersisterWithConfiguration first = new PersisterWithConfiguration(mock(Persister.class), false);
-
- ConfigSnapshotHolder ignored = mockHolder("ignored");
- doReturn(Arrays.asList(ignored)).when(first.getStorage()).loadLastConfigs(); // should be ignored
-
-
- ConfigSnapshotHolder used = mockHolder("used");
- PersisterWithConfiguration second = new PersisterWithConfiguration(mockPersister("p1"), false);
- doReturn(Arrays.asList(used)).when(second.getStorage()).loadLastConfigs(); // should be used
-
- PersisterWithConfiguration third = new PersisterWithConfiguration(mockPersister("p2"), false);
- doReturn(Arrays.asList()).when(third.getStorage()).loadLastConfigs();
-
- persisterWithConfigurations.add(first);
- persisterWithConfigurations.add(second);
- persisterWithConfigurations.add(third);
-
- PersisterAggregator persisterAggregator = new PersisterAggregator(persisterWithConfigurations);
- List<ConfigSnapshotHolder> configSnapshotHolderOptional = persisterAggregator.loadLastConfigs();
- assertEquals(1, configSnapshotHolderOptional.size());
- assertEquals(used, configSnapshotHolderOptional.get(0));
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.netconf.persist.impl.osgi;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import com.google.common.collect.Sets;
-import java.io.IOException;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.opendaylight.controller.config.api.ConflictingVersionException;
-import org.opendaylight.controller.netconf.api.Capability;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
-import org.opendaylight.controller.netconf.persist.impl.osgi.MockedBundleContext.DummyAdapterWithInitialSnapshot;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
-
-public class ConfigPersisterTest {
- private static final Logger LOG = LoggerFactory.getLogger(ConfigPersisterTest.class);
-
- private MockedBundleContext ctx;
- private ConfigPersisterActivator configPersisterActivator;
- private TestingExceptionHandler handler;
-
- private void setUpContext(String requiredCapability) throws Exception {
- DummyAdapterWithInitialSnapshot.expectedCapability = requiredCapability;
- ctx = new MockedBundleContext(1000, 1000);
- configPersisterActivator = new ConfigPersisterActivator();
- }
-
- private void setUpContextAndStartPersister(String requiredCapability, final NetconfOperationService conflictingService) throws Exception {
- setUpContext(requiredCapability);
- doReturn(conflictingService).when(ctx.serviceFactory).createService(anyString());
- configPersisterActivator.start(ctx.getBundleContext());
- }
-
- @Before
- public void setUp() {
- handler = new TestingExceptionHandler();
- Thread.setDefaultUncaughtExceptionHandler(handler);
- }
-
- @After
- public void tearDown() throws Exception {
- Thread.setDefaultUncaughtExceptionHandler(null);
- configPersisterActivator.stop(ctx.getBundleContext());
- }
-
- @Test
- public void testPersisterNotAllCapabilitiesProvided() throws Exception {
- setUpContextAndStartPersister("required-cap", getConflictingService());
- Thread.sleep(2000);
- handler.assertException(IllegalStateException.class, "Required yang models that are missing: [required-cap]");
-
- }
-
- @Test
- public void testPersisterSuccessfulPush() throws Exception {
- setUpContextAndStartPersister("cap1", getWorkingService(getOKDocument()));
- Thread.sleep(2000);
- assertCannotRegisterAsJMXListener_pushWasSuccessful();
- }
-
- // this means pushing of config was successful
- public void assertCannotRegisterAsJMXListener_pushWasSuccessful() {
- handler.assertException(IllegalStateException.class, "Cannot register as JMX listener to netconf");
- }
-
- public NetconfOperationService getWorkingService(Document document) throws SAXException, IOException, NetconfDocumentedException {
- NetconfOperationService service = mock(NetconfOperationService.class);
- Capability capability = mock(Capability.class);
-// doReturn(Sets.newHashSet(capability)).when(service).getCapabilities();
- doReturn("cap1").when(capability).getCapabilityUri();
-
-
- NetconfOperation mockedOperation = mock(NetconfOperation.class);
- doReturn(Sets.newHashSet(mockedOperation)).when(service).getNetconfOperations();
- doReturn(HandlingPriority.getHandlingPriority(1)).when(mockedOperation).canHandle(any(Document.class));
- doReturn(document).when(mockedOperation).handle(any(Document.class), any(NetconfOperationChainedExecution.class));
- doNothing().when(service).close();
- return service;
- }
-
- private Document getOKDocument() throws SAXException, IOException {
- return XmlUtil.readXmlToDocument(
- "<rpc-reply message-id=\"1\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" +
- "<ok/>\n" +
- "</rpc-reply>"
- );
- }
-
-
- @Test
- public void testPersisterConflictingVersionException() throws Exception {
- setUpContextAndStartPersister("cap1", getConflictingService());
-
- Thread.sleep(2000);
- handler.assertException(IllegalStateException.class, "Max wait for conflicting version stabilization timeout");
- }
-
- private NetconfOperationService getConflictingService() throws Exception {
- NetconfOperationService service = getWorkingService(getOKDocument());
- ConflictingVersionException cve = new ConflictingVersionException("");
- try {
- NetconfDocumentedException.wrap(cve);
- throw new AssertionError("Should throw an exception");
- }catch(NetconfDocumentedException e) {
- NetconfOperation mockedOperation = service.getNetconfOperations().iterator().next();
- doThrow(e).when(mockedOperation).handle(any(Document.class), any(NetconfOperationChainedExecution.class));
- return service;
- }
- }
-
- @Test
- public void testSuccessConflictingVersionException() throws Exception {
- LOG.info("testSuccessConflictingVersionException starting");
-
- setUpContext("cap1");
-
- NetconfOperationService conflictingService = getConflictingService();
- NetconfOperationService workingService = getWorkingService(getOKDocument());
-
- doReturn(conflictingService).doReturn(conflictingService).doReturn(conflictingService).
- doReturn(workingService).when(ctx.serviceFactory).createService(anyString());
-
- configPersisterActivator.start(ctx.getBundleContext());
-
- Thread.sleep(1000);
- assertCannotRegisterAsJMXListener_pushWasSuccessful();
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.netconf.persist.impl.osgi;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import java.io.Closeable;
-import java.io.IOException;
-import java.util.Collections;
-import java.util.Dictionary;
-import java.util.List;
-import java.util.SortedSet;
-import java.util.TreeSet;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.opendaylight.controller.config.persist.api.ConfigPusher;
-import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
-import org.opendaylight.controller.config.persist.api.Persister;
-import org.opendaylight.controller.config.persist.api.PropertiesProvider;
-import org.opendaylight.controller.netconf.api.Capability;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
-import org.opendaylight.controller.netconf.persist.impl.DummyAdapter;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Filter;
-import org.osgi.framework.ServiceListener;
-import org.osgi.framework.ServiceReference;
-import org.osgi.framework.ServiceRegistration;
-
-final class MockedBundleContext {
- @Mock
- private BundleContext context;
- @Mock
- private Filter outerFilter, innerFilter;
- @Mock
- private ServiceReference<?> serviceReference;
- @Mock
- private Bundle bundle;
- @Mock
- NetconfOperationServiceFactory serviceFactory;
- @Mock
- private NetconfOperationService service;
- @Mock
- private ServiceRegistration<?> registration;
-
- MockedBundleContext(long maxWaitForCapabilitiesMillis, long conflictingVersionTimeoutMillis) throws Exception {
- MockitoAnnotations.initMocks(this);
- doReturn(null).when(context).getProperty(anyString());
- initContext(maxWaitForCapabilitiesMillis, conflictingVersionTimeoutMillis);
-
- String outerFilterString = "(objectClass=org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory)";
- doReturn(outerFilter).when(context).createFilter(outerFilterString);
- doNothing().when(context).addServiceListener(any(ServiceListener.class), eq(outerFilterString));
- ServiceReference<?>[] toBeReturned = {serviceReference};
- doReturn(toBeReturned).when(context).getServiceReferences(NetconfOperationServiceFactory.class.getName(), null);
-
- String innerFilterString = "innerfilter";
- doReturn(innerFilterString).when(outerFilter).toString();
-
- doReturn(innerFilter).when(context).createFilter(ConfigPersisterActivator.getFilterString());
- doReturn(innerFilterString).when(innerFilter).toString();
- doNothing().when(context).addServiceListener(any(ServiceListener.class), eq(innerFilterString));
-
- doReturn(toBeReturned).when(context).getServiceReferences((String) null, innerFilterString);
- doReturn(bundle).when(serviceReference).getBundle();
- doReturn(context).when(bundle).getBundleContext();
- doReturn("").when(serviceReference).toString();
- doReturn("context").when(context).toString();
- doReturn(serviceFactory).when(context).getService(any(ServiceReference.class));
- doReturn(service).when(serviceFactory).createService(anyString());
- final Capability cap = mock(Capability.class);
- doReturn("cap1").when(cap).getCapabilityUri();
- doReturn(Collections.singleton(cap)).when(serviceFactory).getCapabilities();
- doNothing().when(service).close();
- doReturn("serviceFactoryMock").when(serviceFactory).toString();
-
- doNothing().when(registration).unregister();
- doReturn(registration).when(context).registerService(
- eq(ConfigPusher.class.getName()), any(Closeable.class),
- any(Dictionary.class));
- }
-
- public BundleContext getBundleContext() {
- return context;
- }
-
- private void initContext(long maxWaitForCapabilitiesMillis, long conflictingVersionTimeoutMillis) {
- initProp(context, "active", "1");
- initProp(context, "1." + ConfigPersisterActivator.STORAGE_ADAPTER_CLASS_PROP_SUFFIX, DummyAdapterWithInitialSnapshot.class.getName());
- initProp(context, "1." + "readonly", "false");
- initProp(context, "1." + ".properties.fileStorage", "target/configuration-persister-test/initial/");
- initProp(context, ConfigPersisterActivator.MAX_WAIT_FOR_CAPABILITIES_MILLIS_PROPERTY, String.valueOf(maxWaitForCapabilitiesMillis));
- initProp(context, ConfigPersisterActivator.CONFLICTING_VERSION_TIMEOUT_MILLIS_PROPERTY, String.valueOf(conflictingVersionTimeoutMillis));
- }
-
- private void initProp(BundleContext context, String key, String value) {
- initPropNoPrefix(context, ConfigPersisterActivator.NETCONF_CONFIG_PERSISTER + "." + key, value);
- }
-
- private void initPropNoPrefix(BundleContext context, String key, String value) {
- doReturn(value).when(context).getProperty(key);
- }
-
- public static class DummyAdapterWithInitialSnapshot extends DummyAdapter {
-
- public static final String CONFIG_SNAPSHOT = "config-snapshot";
- public static String expectedCapability = "cap2";
-
- @Override
- public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
- return Lists.newArrayList(getConfigSnapshot());
- }
-
- @Override
- public Persister instantiate(PropertiesProvider propertiesProvider) {
- return this;
- }
-
- public ConfigSnapshotHolder getConfigSnapshot() {
- return new ConfigSnapshotHolder() {
- @Override
- public String getConfigSnapshot() {
- return "<data><" + CONFIG_SNAPSHOT + "/></data>";
- }
-
- @Override
- public SortedSet<String> getCapabilities() {
- TreeSet<String> strings = Sets.newTreeSet();
- strings.add(expectedCapability);
- return strings;
- }
-
- @Override
- public String toString() {
- return getConfigSnapshot();
- }
- };
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.netconf.persist.impl.osgi;
-
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.fail;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-final class TestingExceptionHandler implements Thread.UncaughtExceptionHandler {
-
- private static final Logger LOG = LoggerFactory.getLogger(TestingExceptionHandler.class);
-
- private Throwable t;
-
- @Override
- public void uncaughtException(Thread t, Throwable e) {
- LOG.debug("Uncaught exception in thread {}", t, e);
- this.t = e;
- }
-
- public void assertException(Class<? extends Exception> exType, String exMessageToContain) {
- assertException(exMessageToContain, exType, exMessageToContain);
- }
-
- public void assertException(String failMessageSuffix, Class<? extends Exception> exType, String exMessageToContain) {
- if(t == null) {
- fail("Should fail to " + failMessageSuffix);
- }
- else {
- assertException(t, exType, exMessageToContain);
- }
- }
-
- public void assertNoException() {
- assertNull("No exception expected but was " + t, t);
- }
-
- private void assertException(Throwable t, Class<? extends Exception> exType, String exMessageToContain) {
- assertEquals("Expected exception of type " + exType + " but was " + t, exType, t.getClass());
- if(exMessageToContain!=null) {
- assertThat(t.getMessage(), containsString(exMessageToContain));
- }
- }
-
- public void assertException(String failMessageSuffix, Class<? extends Exception> exType,
- String exMessageToContain, Class<? extends Exception> nestedExType, String nestedExMessageToContain,
- int nestedExDepth) {
- assertException(failMessageSuffix, exType, exMessageToContain);
- assertNotNull("Expected nested exception in " + t, t.getCause());
- assertException(getNestedException(t, nestedExDepth), nestedExType, nestedExMessageToContain);
- }
-
- private Throwable getNestedException(Throwable t, int nestedExDepth) {
-
- int depth = 0;
- while(t.getCause() != null) {
- t = t.getCause();
- depth++;
- if(nestedExDepth == depth)
- return t;
- }
- throw new IllegalArgumentException("Unable to get nested exception from " + t + " from depth " + nestedExDepth);
- }
-}
+++ /dev/null
-urn:opendaylight:l2:types?module=opendaylight-l2-types&revision=2013-08-27
-urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28
-urn:opendaylight:params:xml:ns:yang:controller:threadpool?module=threadpool&revision=2013-04-09
-urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&revision=2013-10-28
-urn:opendaylight:params:xml:ns:yang:controller:config?module=config&revision=2013-04-05
-urn:ietf:params:netconf:capability:candidate:1.0
-urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04
-urn:opendaylight:params:xml:ns:yang:controller:netty:eventexecutor?module=netty-event-executor&revision=2013-11-12
-urn:ietf:params:xml:ns:yang:rpc-context?module=rpc-context&revision=2013-06-17
-urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&revision=2013-10-28
-urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&revision=2010-09-24
-urn:ietf:params:netconf:capability:rollback-on-error:1.0
-urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&revision=2010-09-24
-urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl?module=threadpool-impl&revision=2013-04-05
-urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&revision=2013-10-28
-urn:opendaylight:params:xml:ns:yang:controller:logback:config?module=config-logging&revision=2013-07-16
-urn:opendaylight:yang:extension:yang-ext?module=yang-ext&revision=2013-07-09
-urn:opendaylight:params:xml:ns:yang:iana?module=iana&revision=2013-08-16
-urn:opendaylight:params:xml:ns:yang:controller:md:sal:common?module=opendaylight-md-sal-common&revision=2013-10-28
-urn:opendaylight:params:xml:ns:yang:ieee754?module=ieee754&revision=2013-08-19
+++ /dev/null
-urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28
-urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&revision=2013-10-28
-urn:opendaylight:params:xml:ns:yang:controller:config?module=config&revision=2013-04-05
-urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&revision=2013-10-28
-urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&revision=2013-10-28
+++ /dev/null
-<configuration scan="true">
-
- <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
- <encoder>
- <pattern>%date{"yyyy-MM-dd HH:mm:ss.SSS z"} [%thread] %-5level %logger{36} - %msg%n</pattern>
- </encoder>
- </appender>
-
- <root level="error">
- <appender-ref ref="STDOUT" />
- </root>
- <logger name="org.opendaylight.controller.netconf.persist.impl" level="TRACE"/>
-</configuration>
+++ /dev/null
-<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
- <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:schema-service-singleton</type>
- <name>yang-schema-service</name>
- </module>
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:hash-map-data-store</type>
- <name>hash-map-data-store</name>
- </module>
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-broker-impl</type>
- <name>dom-broker</name>
- <data-store xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
- <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
- <name>ref_hash-map-data-store</name>
- </data-store>
- </module>
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-broker-impl</type>
- <name>binding-broker-impl</name>
- <notification-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
- <name>ref_binding-notification-broker</name>
- </notification-service>
- <data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
- <name>ref_binding-data-broker</name>
- </data-broker>
- </module>
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:runtime-generated-mapping</type>
- <name>runtime-mapping-singleton</name>
- </module>
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-notification-broker</type>
- <name>binding-notification-broker</name>
- </module>
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-data-broker</type>
- <name>binding-data-broker</name>
- <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
- <name>ref_dom-broker</name>
- </dom-broker>
- <mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
- <name>ref_runtime-mapping-singleton</name>
- </mapping-service>
- </module>
- </modules>
- <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
- <service>
- <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
- <instance>
- <name>ref_yang-schema-service</name>
- <provider>/config/modules/module[name='schema-service-singleton']/instance[name='yang-schema-service']</provider>
- </instance>
- </service>
- <service>
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
- <instance>
- <name>ref_binding-notification-broker</name>
- <provider>/config/modules/module[name='binding-notification-broker']/instance[name='binding-notification-broker']</provider>
- </instance>
- </service>
- <service>
- <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
- <instance>
- <name>ref_hash-map-data-store</name>
- <provider>/config/modules/module[name='hash-map-data-store']/instance[name='hash-map-data-store']</provider>
- </instance>
- </service>
- <service>
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
- <instance>
- <name>ref_binding-broker-impl</name>
- <provider>/config/modules/module[name='binding-broker-impl']/instance[name='binding-broker-impl']</provider>
- </instance>
- </service>
- <service>
- <type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding-impl:binding-dom-mapping-service</type>
- <instance>
- <name>ref_runtime-mapping-singleton</name>
- <provider>/config/modules/module[name='runtime-generated-mapping']/instance[name='runtime-mapping-singleton']</provider>
- </instance>
- </service>
- <service>
- <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
- <instance>
- <name>ref_dom-broker</name>
- <provider>/config/modules/module[name='dom-broker-impl']/instance[name='dom-broker']</provider>
- </instance>
- </service>
- <service>
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
- <instance>
- <name>ref_binding-data-broker</name>
- <provider>/config/modules/module[name='binding-data-broker']/instance[name='binding-data-broker']</provider>
- </instance>
- </service>
- </services>
-</data>
+++ /dev/null
-netconf.config.persister.active=1
-netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.netconf.persist.impl.DummyAdapter
-netconf.config.persister.1.properties.fileStorage=target/configuration/initial/
+++ /dev/null
-netconf.config.persister.active=2
-# read startup configuration
-netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter
-netconf.config.persister.1.properties.directoryStorage=target/configuration/initial/
-netconf.config.persister.1.readonly=true
-
-netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter
-netconf.config.persister.2.properties.fileStorage=target/configuration/current/controller.config.2.txt
-netconf.config.persister.2.properties.numberOfBackups=3
+++ /dev/null
-netconf.config.persister.active=3
-netconf.config.persister.3.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter
-netconf.config.persister.3.properties.fileStorage=target/configuration/current/controller.config.2.txt
-netconf.config.persister.3.properties.numberOfBackups=0
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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
+--><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>netconf-subsystem</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ <relativePath>../../</relativePath>
+ </parent>
+ <artifactId>features-netconf-connector</artifactId>
+
+ <!-- Preserve mdsal version-->
+ <version>${mdsal.version}</version>
+ <packaging>jar</packaging>
+ <properties>
+ <features.file>features.xml</features.file>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>features-yangtools</artifactId>
+ <version>${yangtools.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>features-mdsal</artifactId>
+ <version>${mdsal.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>features-netconf</artifactId>
+ <classifier>features</classifier>
+ <type>xml</type>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.aaa</groupId>
+ <artifactId>features-aaa</artifactId>
+ <version>${aaa.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-netconf-connector</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller.model</groupId>
+ <artifactId>model-inventory</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-config-dispatcher</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-tcp</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-ssh</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcpkix-jdk15on</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk15on</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-connector-config</artifactId>
+ <version>${netconf.version}</version>
+ <type>xml</type>
+ <classifier>config</classifier>
+ </dependency>
+
+ <!--
+ Optional TODO: Remove TODO comments.
+ -->
+ <!-- test to validate features.xml -->
+ <!--FIXME BUG-2195 When running single feature tests for netconf connector, features including ssh proxy server always fail (this behavior does not appear when running karaf distro directly)-->
+ <dependency>
+ <groupId>org.opendaylight.odlparent</groupId>
+ <artifactId>features-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <!-- dependency for opendaylight-karaf-empty for use by testing -->
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>opendaylight-karaf-empty</artifactId>
+ <version>${commons.opendaylight.version}</version>
+ <type>zip</type>
+ </dependency>
+ <!-- Uncomment this if you get an error : java.lang.NoSuchMethodError: org.slf4j.helpers.MessageFormatter.format(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Lorg/slf4j/helpers/FormattingTuple;
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <version>1.7.2</version>
+ </dependency>
+ -->
+
+ </dependencies>
+ <build>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ <filtering>true</filtering>
+ </resource>
+ </resources>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>filter</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>resources</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-artifacts</id>
+ <phase>package</phase>
+ <goals>
+ <goal>attach-artifact</goal>
+ </goals>
+ <configuration>
+ <artifacts>
+ <artifact>
+ <file>${project.build.directory}/classes/${features.file}</file>
+ <type>xml</type>
+ <classifier>features</classifier>
+ </artifact>
+ </artifacts>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <systemPropertyVariables>
+ <karaf.distro.groupId>org.opendaylight.controller</karaf.distro.groupId>
+ <karaf.distro.artifactId>opendaylight-karaf-empty</karaf.distro.artifactId>
+ <karaf.distro.version>${commons.opendaylight.version}</karaf.distro.version>
+ </systemPropertyVariables>
+ <dependenciesToScan>
+ <dependency>org.opendaylight.odlparent:features-test</dependency>
+ </dependenciesToScan>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <scm>
+ <connection>scm:git:http://git.opendaylight.org/gerrit/controller.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+ <tag>HEAD</tag>
+ <url>https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=summary</url>
+ </scm>
+</project>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ 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
+-->
+<features name="odl-controller-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
+ <repository>mvn:org.opendaylight.controller/features-mdsal/${mdsal.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.yangtools/features-yangtools/${yangtools.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.controller/features-netconf/${netconf.version}/xml/features</repository>
+
+ <feature name='odl-netconf-connector-all' version='${project.version}' description='OpenDaylight :: Netconf Connector :: All'>
+ <feature version='${project.version}'>odl-netconf-connector</feature>
+ <feature version='${project.version}'>odl-netconf-connector-ssh</feature>
+ </feature>
+
+ <feature name='odl-netconf-connector' version='${project.version}' description="OpenDaylight :: Netconf Connector :: Netconf Connector">
+ <feature version='${mdsal.version}'>odl-mdsal-broker</feature>
+ <feature version='${netconf.version}'>odl-netconf-client</feature>
+ <feature version='${yangtools.version}'>odl-yangtools-models</feature>
+ <bundle>mvn:org.opendaylight.controller/sal-netconf-connector/${project.version}</bundle>
+ <bundle>mvn:org.opendaylight.controller.model/model-inventory/${mdsal.version}</bundle>
+ </feature>
+
+ <feature name='odl-netconf-connector-ssh' version='${project.version}' description="OpenDaylight :: Netconf Connector :: Netconf Connector + Netconf SSH Server + loopback connection configuration">
+ <feature version='${netconf.version}'>odl-netconf-ssh</feature>
+ <feature version='${project.version}'>odl-netconf-connector</feature>
+ <configfile finalname="${config.configfile.directory}/${config.netconf.connector.configfile}">mvn:org.opendaylight.controller/netconf-connector-config/${netconf.version}/xml/config</configfile>
+ </feature>
+
+</features>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-subsystem</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ <relativePath>../../</relativePath>
+ </parent>
+ <artifactId>features-netconf</artifactId>
+
+ <packaging>jar</packaging>
+
+ <properties>
+ <features.file>features.xml</features.file>
+ </properties>
+
+ <dependencies>
+ <!-- FIXME AAA netconf dependency loop-->
+ <dependency>
+ <groupId>org.opendaylight.aaa</groupId>
+ <artifactId>features-aaa</artifactId>
+ <version>${aaa.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>features-config</artifactId>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>features-protocol-framework</artifactId>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>features-config-persister</artifactId>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-config</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-auth</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-notifications-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-notifications-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>ietf-netconf</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>ietf-netconf-monitoring</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>ietf-netconf-monitoring-extension</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>ietf-netconf-notifications</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>ietf-inet-types</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>ietf-yang-types</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-model-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-mapping-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-manager-facade-xml</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-netconf-connector</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-netty-util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sshd</groupId>
+ <artifactId>sshd-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>openexi</groupId>
+ <artifactId>nagasena</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-codec</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-handler</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-buffer</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-transport</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-client</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-config</artifactId>
+ <version>${config.version}</version>
+ <type>xml</type>
+ <classifier>config</classifier>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-connector-config</artifactId>
+ <version>${netconf.version}</version>
+ <type>xml</type>
+ <classifier>config</classifier>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-monitoring</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>mdsal-netconf-monitoring</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>mdsal-netconf-connector</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-mdsal-config</artifactId>
+ <classifier>config</classifier>
+ <type>xml</type>
+ </dependency>
+ <!-- test to validate features.xml -->
+ <dependency>
+ <groupId>org.opendaylight.odlparent</groupId>
+ <artifactId>features-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <!-- dependency for opendaylight-karaf-empty for use by testing -->
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>opendaylight-karaf-empty</artifactId>
+ <version>${commons.opendaylight.version}</version>
+ <type>zip</type>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <resources>
+ <resource>
+ <filtering>true</filtering>
+ <directory>src/main/resources</directory>
+ </resource>
+ </resources>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>filter</id>
+ <goals>
+ <goal>resources</goal>
+ </goals>
+ <phase>generate-resources</phase>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-artifacts</id>
+ <goals>
+ <goal>attach-artifact</goal>
+ </goals>
+ <phase>package</phase>
+ <configuration>
+ <artifacts>
+ <artifact>
+ <file>${project.build.directory}/classes/${features.file}</file>
+ <type>xml</type>
+ <classifier>features</classifier>
+ </artifact>
+ </artifacts>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <!-- FIXME uncomment after merge -->
+ <!--<plugin>-->
+ <!--<groupId>org.apache.maven.plugins</groupId>-->
+ <!--<artifactId>maven-surefire-plugin</artifactId>-->
+ <!--<version>${surefire.version}</version>-->
+ <!--<configuration>-->
+ <!--<systemPropertyVariables>-->
+ <!--<karaf.distro.groupId>org.opendaylight.controller</karaf.distro.groupId>-->
+ <!--<karaf.distro.artifactId>opendaylight-karaf-empty</karaf.distro.artifactId>-->
+ <!--<karaf.distro.version>${commons.opendaylight.version}</karaf.distro.version>-->
+ <!--</systemPropertyVariables>-->
+ <!--<dependenciesToScan>-->
+ <!--<dependency>org.opendaylight.odlparent:features-test</dependency>-->
+ <!--</dependenciesToScan>-->
+ <!--</configuration>-->
+ <!--</plugin>-->
+ </plugins>
+ </build>
+ <scm>
+ <connection>scm:git:http://git.opendaylight.org/gerrit/controller.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+ <tag>HEAD</tag>
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
+ </scm>
+</project>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<features name="odl-netconf-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
+ <repository>mvn:org.opendaylight.controller/features-protocol-framework/${protocol-framework.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.controller/features-config/${config.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.controller/features-config-persister/${config.version}/xml/features</repository>
+ <!-- FIXME: This introduces cycle between projects, which makes version updates
+ harder. Should be moved to different.
+ -->
+ <repository>mvn:org.opendaylight.aaa/features-aaa/${aaa.version}/xml/features</repository>
+
+ <feature name='odl-netconf-all' version='${project.version}' description="OpenDaylight :: Netconf :: All">
+ <feature version='${project.version}'>odl-netconf-api</feature>
+ <feature version='${project.version}'>odl-netconf-mapping-api</feature>
+ <feature version='${project.version}'>odl-netconf-util</feature>
+ <feature version='${project.version}'>odl-netconf-impl</feature>
+ <feature version='${project.version}'>odl-config-netconf-connector</feature>
+ <feature version='${project.version}'>odl-netconf-netty-util</feature>
+ <feature version='${project.version}'>odl-netconf-client</feature>
+ <feature version='${project.version}'>odl-netconf-monitoring</feature>
+ </feature>
+
+ <feature name='odl-netconf-api' version='${project.version}' description="OpenDaylight :: Netconf :: API">
+ <feature version='${protocol-framework.version}'>odl-protocol-framework</feature>
+ <bundle>mvn:org.opendaylight.yangtools/yang-model-api/${yangtools.version}</bundle>
+ <bundle>mvn:org.opendaylight.controller/config-util/${config.version}</bundle>
+ <bundle>mvn:org.opendaylight.controller/netconf-api/${project.version}</bundle>
+ <bundle>mvn:org.opendaylight.controller/netconf-auth/${project.version}</bundle>
+ <bundle>mvn:org.opendaylight.controller/ietf-netconf-monitoring/${project.version}</bundle>
+ <bundle>mvn:org.opendaylight.controller/ietf-netconf/${project.version}</bundle>
+ <bundle>mvn:org.opendaylight.controller/ietf-netconf-notifications/${project.version}</bundle>
+ <bundle>mvn:org.opendaylight.controller/ietf-netconf-monitoring-extension/${project.version}</bundle>
+ <bundle>mvn:org.opendaylight.yangtools.model/ietf-inet-types/${ietf-inet-types.version}</bundle>
+ <bundle>mvn:org.opendaylight.yangtools.model/ietf-yang-types/${ietf-yang-types.version}</bundle>
+ <bundle>mvn:org.opendaylight.yangtools.model/ietf-yang-types-20130715/2013.07.15.8-SNAPSHOT</bundle>
+ </feature>
+
+ <feature name='odl-netconf-mapping-api' version='${project.version}' description="OpenDaylight :: Netconf :: Mapping API">
+ <feature version='${project.version}'>odl-netconf-api</feature>
+ <bundle>mvn:org.opendaylight.controller/netconf-mapping-api/${project.version}</bundle>
+ </feature>
+
+ <feature name='odl-netconf-util' version='${project.version}'>
+ <feature version='${project.version}'>odl-netconf-mapping-api</feature>
+ <bundle>mvn:org.opendaylight.yangtools/yang-model-api/${yangtools.version}</bundle>
+ <bundle>mvn:org.opendaylight.yangtools/yang-data-api/${yangtools.version}</bundle>
+ <bundle>mvn:org.opendaylight.controller/netconf-util/${project.version}</bundle>
+ </feature>
+
+ <feature name='odl-netconf-impl' version='${project.version}' description="OpenDaylight :: Netconf :: Impl">
+ <bundle>mvn:org.opendaylight.controller/yang-jmx-generator/${project.version}</bundle>
+ <feature version='${project.version}'>odl-netconf-api</feature>
+ <feature version='${project.version}'>odl-netconf-mapping-api</feature>
+ <feature version='${project.version}'>odl-netconf-util</feature>
+ <feature version='${project.version}'>odl-netconf-netty-util</feature>
+ <!-- Netconf server without config connector is just an empty shell -->
+ <feature version='${project.version}'>odl-config-netconf-connector</feature>
+ <!-- Netconf will not provide schemas without monitoring -->
+ <bundle>mvn:org.opendaylight.controller/config-manager-facade-xml/${project.version}</bundle>
+ <feature version='${project.version}'>odl-netconf-monitoring</feature>
+ <feature version='${project.version}'>odl-netconf-notifications-impl</feature>
+ <bundle>mvn:org.opendaylight.controller/netconf-impl/${project.version}</bundle>
+ </feature>
+
+ <feature name='odl-config-netconf-connector' version='${project.version}' description="OpenDaylight :: Netconf :: Connector">
+ <bundle>mvn:org.opendaylight.controller/yang-jmx-generator/${project.version}</bundle>
+ <bundle>mvn:org.opendaylight.controller/config-manager-facade-xml/${project.version}</bundle>
+ <feature version='${config.version}'>odl-config-manager</feature>
+ <feature version='${project.version}'>odl-netconf-netty-util</feature>
+ <bundle>mvn:org.opendaylight.controller/netconf-impl/${project.version}</bundle>
+ <feature version='${project.version}'>odl-netconf-notifications-api</feature>
+ <bundle>mvn:org.opendaylight.controller/netconf-notifications-impl/${project.version}</bundle>
+ <bundle>mvn:org.opendaylight.controller/config-netconf-connector/${project.version}</bundle>
+ </feature>
+
+ <feature name='odl-netconf-netty-util' version='${project.version}' description="OpenDaylight :: Netconf :: Netty Util">
+ <feature version='${project.version}'>odl-netconf-api</feature>
+ <feature version='${project.version}'>odl-netconf-mapping-api</feature>
+ <feature version='${project.version}'>odl-netconf-util</feature>
+ <bundle>mvn:org.opendaylight.controller/netconf-netty-util/${project.version}</bundle>
+ <bundle>mvn:org.bouncycastle/bcpkix-jdk15on/${bouncycastle.version}</bundle>
+ <bundle>mvn:org.bouncycastle/bcprov-jdk15on/${bouncycastle.version}</bundle>
+ <bundle>mvn:org.apache.sshd/sshd-core/${sshd-core.version}</bundle>
+ <bundle>mvn:openexi/nagasena/${exi.nagasena.version}</bundle>
+ <bundle>mvn:io.netty/netty-codec/${netty.version}</bundle>
+ <bundle>mvn:io.netty/netty-handler/${netty.version}</bundle>
+ <bundle>mvn:io.netty/netty-common/${netty.version}</bundle>
+ <bundle>mvn:io.netty/netty-buffer/${netty.version}</bundle>
+ <bundle>mvn:io.netty/netty-transport/${netty.version}</bundle>
+ </feature>
+
+ <feature name='odl-netconf-client' version='${project.version}' description="OpenDaylight :: Netconf :: Client">
+ <feature version='${config.version}'>odl-config-all</feature>
+ <feature version='${project.version}'>odl-netconf-netty-util</feature>
+ <bundle>mvn:org.opendaylight.controller/netconf-client/${project.version}</bundle>
+ <bundle>mvn:org.opendaylight.controller/netconf-config-dispatcher/${config.version}</bundle>
+ <configfile finalname='${config.configfile.directory}/${config.netconf.client.configfile}'>mvn:org.opendaylight.controller/netconf-config/${project.version}/xml/config</configfile>
+ </feature>
+
+ <feature name='odl-netconf-monitoring' version='${project.version}' description="OpenDaylight :: Netconf :: Monitoring">
+ <feature version='${project.version}'>odl-netconf-util</feature>
+ <bundle>mvn:org.opendaylight.controller/netconf-monitoring/${project.version}</bundle>
+ </feature>
+
+ <feature name='odl-netconf-notifications-api' version='${project.version}' description="OpenDaylight :: Netconf :: Notification :: Api">
+ <feature version='${project.version}'>odl-config-manager-facade-xml</feature>
+ <feature version='${project.version}'>odl-netconf-api</feature>
+ <bundle>mvn:org.opendaylight.controller/netconf-notifications-api/${project.version}</bundle>
+ </feature>
+
+ <feature name='odl-netconf-notifications-impl' version='${project.version}' description="OpenDaylight :: Netconf :: Monitoring :: Impl">
+ <feature version='${project.version}'>odl-netconf-notifications-api</feature>
+ <feature version='${project.version}'>odl-netconf-util</feature>
+ <bundle>mvn:org.opendaylight.controller/netconf-notifications-impl/${project.version}</bundle>
+ </feature>
+
+ <feature name='odl-netconf-ssh' version='${project.version}' description="OpenDaylight :: Netconf Connector :: SSH">
+ <feature version='${project.version}'>odl-netconf-tcp</feature>
+ <!-- FIXME: This introduces cycle between projects, which makes version updates
+ harder. Should be moved to different.
+ -->
+ <feature version='${aaa.version}'>odl-aaa-netconf-plugin</feature>
+ <bundle>mvn:org.opendaylight.controller/netconf-ssh/${project.version}</bundle>
+ </feature>
+
+ <feature name='odl-netconf-tcp' version='${project.version}' description="OpenDaylight :: Netconf Connector :: TCP">
+ <feature version='${project.version}'>odl-netconf-impl</feature>
+ <feature version='${config.version}'>odl-config-netty</feature>
+ <bundle>mvn:org.opendaylight.controller/netconf-tcp/${project.version}</bundle>
+ </feature>
+
+ <feature name='odl-netconf-mdsal' version='${mdsal.version}' description="OpenDaylight :: Netconf :: Mdsal">
+ <feature version='${config.version}'>odl-config-all</feature>
+ <feature version='${project.version}'>odl-netconf-all</feature>
+ <feature version='${project.version}'>odl-netconf-tcp</feature>
+ <feature version='${project.version}'>odl-netconf-ssh</feature>
+ <feature version='${project.version}'>odl-netconf-client</feature>
+ <feature version='${mdsal.version}'>odl-mdsal-broker</feature>
+ <bundle>mvn:org.opendaylight.controller/mdsal-netconf-connector/${project.version}</bundle>
+ <bundle>mvn:org.opendaylight.controller/mdsal-netconf-monitoring/${project.version}</bundle>
+ <configfile finalname='${config.configfile.directory}/${config.netconf.mdsal.configfile}'>mvn:org.opendaylight.controller/netconf-mdsal-config/${project.version}/xml/config</configfile>
+ </feature>
+</features>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-subsystem</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ <relativePath>../</relativePath>
+ </parent>
+ <artifactId>features-netconf-parent</artifactId>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>netconf</module>
+ <module>netconf-connector</module>
+ </modules>
+</project>
</instructions>
</configuration>
</plugin>
- <!--FIXME extract yang plugin definition into parent-->
<plugin>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-maven-plugin</artifactId>
- <executions>
- <execution>
- <id>config</id>
- <goals>
- <goal>generate-sources</goal>
- </goals>
- <configuration>
- <codeGenerators>
- <generator>
- <codeGeneratorClass>org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator</codeGeneratorClass>
- <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
- <additionalConfiguration>
- <namespaceToPackage1>urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang</namespaceToPackage1>
- </additionalConfiguration>
- </generator>
- <generator>
- <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
- <outputBaseDir>${salGeneratorPath}</outputBaseDir>
- </generator>
- </codeGenerators>
- <inspectDependencies>true</inspectDependencies>
- </configuration>
- </execution>
- </executions>
- <dependencies>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>yang-jmx-generator-plugin</artifactId>
- <version>${config.version}</version>
- </dependency>
- </dependencies>
</plugin>
</plugins>
</build>
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
-import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.config.util.capability.Capability;
import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
import org.opendaylight.controller.sal.core.api.model.SchemaService;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
public class CurrentSchemaContext implements SchemaContextListener, AutoCloseable {
final AtomicReference<SchemaContext> currentContext = new AtomicReference<SchemaContext>();
private final ListenerRegistration<SchemaContextListener> schemaContextListenerListenerRegistration;
- private final Set<CapabilityListener> listeners = Collections.synchronizedSet(Sets.<CapabilityListener>newHashSet());
+ private final Set<CapabilityListener> listeners1 = Collections.synchronizedSet(Sets.<CapabilityListener>newHashSet());
public SchemaContext getCurrentContext() {
Preconditions.checkState(currentContext.get() != null, "Current context not received");
currentContext.set(schemaContext);
// FIXME is notifying all the listeners from this callback wise ?
final Set<Capability> addedCaps = MdsalNetconfOperationServiceFactory.transformCapabilities(currentContext.get());
- for (final CapabilityListener listener : listeners) {
- listener.onCapabilitiesAdded(addedCaps);
+ for (final CapabilityListener listener : listeners1) {
+ listener.onCapabilitiesChanged(addedCaps, Collections.<Capability>emptySet());
}
}
@Override
public void close() throws Exception {
- listeners.clear();
+ listeners1.clear();
schemaContextListenerListenerRegistration.close();
currentContext.set(null);
}
public AutoCloseable registerCapabilityListener(final CapabilityListener listener) {
- listener.onCapabilitiesAdded(MdsalNetconfOperationServiceFactory.transformCapabilities(currentContext.get()));
- listeners.add(listener);
+ listener.onCapabilitiesChanged(MdsalNetconfOperationServiceFactory.transformCapabilities(currentContext.get()), Collections.<Capability>emptySet());
+ listeners1.add(listener);
return new AutoCloseable() {
@Override
public void close() throws Exception {
- listeners.remove(listener);
+ listeners1.remove(listener);
}
};
}
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
+import org.opendaylight.controller.config.util.capability.Capability;
+import org.opendaylight.controller.config.util.capability.YangModuleCapability;
import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
-import org.opendaylight.controller.netconf.api.Capability;
import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
-import org.opendaylight.controller.netconf.util.capability.BasicCapability;
-import org.opendaylight.controller.netconf.util.capability.YangModuleCapability;
import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
import org.opendaylight.controller.sal.core.api.Consumer;
import org.opendaylight.controller.sal.core.api.model.SchemaService;
static Set<Capability> transformCapabilities(final SchemaContext currentContext) {
final Set<Capability> capabilities = new HashSet<>();
- // [RFC6241] 8.3. Candidate Configuration Capability
- capabilities.add(new BasicCapability("urn:ietf:params:netconf:capability:candidate:1.0"));
+
+ // Added by netconf-impl by default
+// capabilities.add(new BasicCapability("urn:ietf:params:netconf:capability:candidate:1.0"));
final Set<Module> modules = currentContext.getModules();
for (final Module module : modules) {
import com.google.common.util.concurrent.CheckedFuture;
import java.util.ArrayList;
import java.util.List;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorSeverity;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorTag;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorType;
import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
return candidateTransaction;
}
- public synchronized boolean commitTransaction() throws NetconfDocumentedException {
+ public synchronized boolean commitTransaction() throws DocumentedException {
if (!getCandidateTransaction().isPresent()) {
- throw new NetconfDocumentedException(NO_TRANSACTION_FOUND_FOR_SESSION + netconfSessionIdForReporting,
+ throw new DocumentedException(NO_TRANSACTION_FOUND_FOR_SESSION + netconfSessionIdForReporting,
ErrorType.application, ErrorTag.operation_failed, ErrorSeverity.error);
}
future.checkedGet();
} catch (TransactionCommitFailedException e) {
LOG.debug("Transaction {} failed on", candidateTransaction, e);
- throw new NetconfDocumentedException("Transaction commit failed on " + e.getMessage() + " " + netconfSessionIdForReporting,
+ throw new DocumentedException("Transaction commit failed on " + e.getMessage() + " " + netconfSessionIdForReporting,
ErrorType.application, ErrorTag.operation_failed, ErrorSeverity.error);
}
allOpenReadWriteTransactions.remove(candidateTransaction);
return runningTransaction;
}
- public synchronized boolean commitRunningTransaction(DOMDataReadWriteTransaction tx) throws NetconfDocumentedException {
+ public synchronized boolean commitRunningTransaction(DOMDataReadWriteTransaction tx) throws DocumentedException {
allOpenReadWriteTransactions.remove(tx);
CheckedFuture<Void, TransactionCommitFailedException> future = tx.submit();
future.checkedGet();
} catch (TransactionCommitFailedException e) {
LOG.debug("Transaction {} failed on", tx, e);
- throw new NetconfDocumentedException("Transaction commit failed on " + e.getMessage() + " " + netconfSessionIdForReporting,
+ throw new DocumentedException("Transaction commit failed on " + e.getMessage() + " " + netconfSessionIdForReporting,
ErrorType.application, ErrorTag.operation_failed, ErrorSeverity.error);
}
package org.opendaylight.controller.netconf.mdsal.connector.ops;
import com.google.common.base.Optional;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.mdsal.connector.TransactionProvider;
import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
}
@Override
- protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws DocumentedException {
boolean commitStatus = transactionProvider.commitTransaction();
LOG.trace("Transaction commited succesfuly {}", commitStatus);
import com.google.common.base.Optional;
import java.util.HashMap;
import java.util.Map;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorSeverity;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorTag;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorType;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.mdsal.connector.TransactionProvider;
import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
}
@Override
- protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws DocumentedException {
try {
transactionProvider.abortTransaction();
errorInfo
.put(ErrorTag.operation_failed.name(),
"Operation failed. Use 'get-config' or 'edit-config' before triggering 'discard-changes' operation");
- throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed,
+ throw new DocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed,
ErrorSeverity.error, errorInfo);
}
return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorSeverity;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorTag;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorType;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.mdsal.connector.CurrentSchemaContext;
import org.opendaylight.controller.netconf.mdsal.connector.TransactionProvider;
import org.opendaylight.controller.netconf.mdsal.connector.ops.DataTreeChangeTracker.DataTreeChange;
import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.yangtools.yang.data.api.ModifyAction;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
}
@Override
- protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws DocumentedException {
final Datastore targetDatastore = extractTargetParameter(operationElement);
if (targetDatastore == Datastore.running) {
- throw new NetconfDocumentedException("edit-config on running datastore is not supported",
+ throw new DocumentedException("edit-config on running datastore is not supported",
ErrorType.protocol,
ErrorTag.operation_not_supported,
ErrorSeverity.error);
return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
}
- private void executeOperations(final DataTreeChangeTracker changeTracker) throws NetconfDocumentedException {
+ private void executeOperations(final DataTreeChangeTracker changeTracker) throws DocumentedException {
final DOMDataReadWriteTransaction rwTx = transactionProvider.getOrCreateTransaction();
final List<DataTreeChange> aa = changeTracker.getDataTreeChanges();
final ListIterator<DataTreeChange> iterator = aa.listIterator(aa.size());
}
}
- private void executeChange(final DOMDataReadWriteTransaction rwtx, final DataTreeChange change) throws NetconfDocumentedException {
+ private void executeChange(final DOMDataReadWriteTransaction rwtx, final DataTreeChange change) throws DocumentedException {
switch (change.getAction()) {
case NONE:
return;
try {
final Optional<NormalizedNode<?, ?>> readResult = rwtx.read(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create(change.getPath())).checkedGet();
if (readResult.isPresent()) {
- throw new NetconfDocumentedException("Data already exists, cannot execute CREATE operation", ErrorType.protocol, ErrorTag.data_exists, ErrorSeverity.error);
+ throw new DocumentedException("Data already exists, cannot execute CREATE operation", ErrorType.protocol, ErrorTag.data_exists, ErrorSeverity.error);
}
rwtx.put(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create(change.getPath()), change.getChangeRoot());
} catch (ReadFailedException e) {
try {
final Optional<NormalizedNode<?, ?>> readResult = rwtx.read(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create(change.getPath())).checkedGet();
if (!readResult.isPresent()) {
- throw new NetconfDocumentedException("Data is missing, cannot execute DELETE operation", ErrorType.protocol, ErrorTag.data_missing, ErrorSeverity.error);
+ throw new DocumentedException("Data is missing, cannot execute DELETE operation", ErrorType.protocol, ErrorTag.data_missing, ErrorSeverity.error);
}
rwtx.delete(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create(change.getPath()));
} catch (ReadFailedException e) {
throw new UnsupportedOperationException("implement exception if parse fails");
}
- private Optional<DataSchemaNode> getSchemaNodeFromNamespace(final String namespace, final XmlElement element) throws NetconfDocumentedException{
+ private Optional<DataSchemaNode> getSchemaNodeFromNamespace(final String namespace, final XmlElement element) throws DocumentedException{
Optional<DataSchemaNode> dataSchemaNode = Optional.absent();
try {
//returns module with newest revision since findModuleByNamespace returns a set of modules and we only need the newest one
if (schemaNode != null) {
dataSchemaNode = Optional.of(module.getDataChildByName(element.getName()));
} else {
- throw new NetconfDocumentedException("Unable to find node with namespace: " + namespace + "in module: " + module.toString(),
+ throw new DocumentedException("Unable to find node with namespace: " + namespace + "in module: " + module.toString(),
ErrorType.application,
ErrorTag.unknown_namespace,
ErrorSeverity.error);
return dataSchemaNode;
}
- private Datastore extractTargetParameter(final XmlElement operationElement) throws NetconfDocumentedException {
+ private Datastore extractTargetParameter(final XmlElement operationElement) throws DocumentedException {
final NodeList elementsByTagName = operationElement.getDomElement().getElementsByTagName(TARGET_KEY);
// Direct lookup instead of using XmlElement class due to performance
if (elementsByTagName.getLength() == 0) {
- throw new NetconfDocumentedException("Missing target element", ErrorType.rpc, ErrorTag.missing_attribute, ErrorSeverity.error);
+ throw new DocumentedException("Missing target element", ErrorType.rpc, ErrorTag.missing_attribute, ErrorSeverity.error);
} else if (elementsByTagName.getLength() > 1) {
- throw new NetconfDocumentedException("Multiple target elements", ErrorType.rpc, ErrorTag.unknown_attribute, ErrorSeverity.error);
+ throw new DocumentedException("Multiple target elements", ErrorType.rpc, ErrorTag.unknown_attribute, ErrorSeverity.error);
} else {
final XmlElement targetChildNode = XmlElement.fromDomElement((Element) elementsByTagName.item(0)).getOnlyChildElement();
return Datastore.valueOf(targetChildNode.getName());
}
}
- private ModifyAction getDefaultOperation(final XmlElement operationElement) throws NetconfDocumentedException {
+ private ModifyAction getDefaultOperation(final XmlElement operationElement) throws DocumentedException {
final NodeList elementsByTagName = operationElement.getDomElement().getElementsByTagName(DEFAULT_OPERATION_KEY);
if(elementsByTagName.getLength() == 0) {
return ModifyAction.MERGE;
} else if(elementsByTagName.getLength() > 1) {
- throw new NetconfDocumentedException("Multiple " + DEFAULT_OPERATION_KEY + " elements",
+ throw new DocumentedException("Multiple " + DEFAULT_OPERATION_KEY + " elements",
ErrorType.rpc, ErrorTag.unknown_attribute, ErrorSeverity.error);
} else {
return ModifyAction.fromXmlValue(elementsByTagName.item(0).getTextContent());
}
- private XmlElement getElement(final XmlElement operationElement, String elementName) throws NetconfDocumentedException {
+ private XmlElement getElement(final XmlElement operationElement, String elementName) throws DocumentedException {
final Optional<XmlElement> childNode = operationElement.getOnlyChildElementOptionally(elementName);
if (!childNode.isPresent()) {
- throw new NetconfDocumentedException(elementName + " element is missing",
+ throw new DocumentedException(elementName + " element is missing",
ErrorType.protocol,
ErrorTag.missing_element,
ErrorSeverity.error);
package org.opendaylight.controller.netconf.mdsal.connector.ops;
import com.google.common.base.Optional;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
}
@Override
- protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws DocumentedException {
final Datastore targetDatastore = extractTargetParameter(operationElement);
if (targetDatastore == Datastore.candidate) {
LOG.debug("Locking candidate datastore on session: {}", getNetconfSessionIdForReporting());
return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
}
- throw new NetconfDocumentedException("Unable to lock " + targetDatastore + " datastore", NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_not_supported, NetconfDocumentedException.ErrorSeverity.error);
+ throw new DocumentedException("Unable to lock " + targetDatastore + " datastore", DocumentedException.ErrorType.application,
+ DocumentedException.ErrorTag.operation_not_supported, DocumentedException.ErrorSeverity.error);
}
- static Datastore extractTargetParameter(final XmlElement operationElement) throws NetconfDocumentedException {
+ static Datastore extractTargetParameter(final XmlElement operationElement) throws DocumentedException {
final XmlElement targetElement = operationElement.getOnlyChildElementWithSameNamespace(TARGET_KEY);
final XmlElement targetChildNode = targetElement.getOnlyChildElementWithSameNamespace();
return Datastore.valueOf(targetChildNode.getName());
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.dom.DOMResult;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorSeverity;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorTag;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorType;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlMappingConstants;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
import org.opendaylight.controller.netconf.mdsal.connector.CurrentSchemaContext;
import org.opendaylight.controller.netconf.util.OrderedNormalizedNodeWriter;
-import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
}
@Override
- protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws DocumentedException {
final String netconfOperationName = operationElement.getName();
final String netconfOperationNamespace;
try {
netconfOperationNamespace = operationElement.getNamespace();
- } catch (MissingNameSpaceException e) {
+ } catch (DocumentedException e) {
LOG.debug("Cannot retrieve netconf operation namespace from message due to ", e);
- throw new NetconfDocumentedException("Cannot retrieve netconf operation namespace from message",
+ throw new DocumentedException("Cannot retrieve netconf operation namespace from message",
ErrorType.protocol, ErrorTag.unknown_namespace, ErrorSeverity.error);
}
final Optional<Module> moduleOptional = getModule(namespaceURI);
if (!moduleOptional.isPresent()) {
- throw new NetconfDocumentedException("Unable to find module in Schema Context with namespace and name : " +
+ throw new DocumentedException("Unable to find module in Schema Context with namespace and name : " +
namespaceURI + " " + netconfOperationName + schemaContext.getCurrentContext(),
ErrorType.application, ErrorTag.bad_element, ErrorSeverity.error);
}
final Optional<RpcDefinition> rpcDefinitionOptional = getRpcDefinitionFromModule(moduleOptional.get(), namespaceURI, netconfOperationName);
if (!rpcDefinitionOptional.isPresent()) {
- throw new NetconfDocumentedException("Unable to find RpcDefinition with namespace and name : " + namespaceURI + " " + netconfOperationName,
+ throw new DocumentedException("Unable to find RpcDefinition with namespace and name : " + namespaceURI + " " + netconfOperationName,
ErrorType.application, ErrorTag.bad_element, ErrorSeverity.error);
}
}
return (Element) transformNormalizedNode(document, result.getResult(), rpcDefinition.getOutput().getPath());
} catch (DOMRpcException e) {
- throw NetconfDocumentedException.wrap(e);
+ throw DocumentedException.wrap(e);
}
}
@Override
public Document handle(final Document requestMessage,
- final NetconfOperationChainedExecution subsequentOperation) throws NetconfDocumentedException {
+ final NetconfOperationChainedExecution subsequentOperation) throws DocumentedException {
final XmlElement requestElement = getRequestElementWithCheck(requestMessage);
final Map<String, Attr> attributes = requestElement.getAttributes();
final Element response = handle(document, operationElement, subsequentOperation);
- final Element rpcReply = XmlUtil.createElement(document, XmlNetconfConstants.RPC_REPLY_KEY, Optional.of(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0));
+ final Element rpcReply = XmlUtil.createElement(document, XmlMappingConstants.RPC_REPLY_KEY, Optional.of(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0));
if(XmlElement.fromDomElement(response).hasNamespace()) {
rpcReply.appendChild(response);
//TODO move all occurences of this method in mdsal netconf(and xml factories) to a utility class
private Node transformNormalizedNode(final Document document, final NormalizedNode<?, ?> data, final SchemaPath rpcOutputPath) {
- final DOMResult result = new DOMResult(document.createElement(XmlNetconfConstants.RPC_REPLY_KEY));
+ final DOMResult result = new DOMResult(document.createElement(XmlMappingConstants.RPC_REPLY_KEY));
final XMLStreamWriter xmlWriter = getXmlStreamWriter(result);
package org.opendaylight.controller.netconf.mdsal.connector.ops;
import com.google.common.base.Optional;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
}
@Override
- protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws DocumentedException {
final Datastore targetDatastore = Lock.extractTargetParameter(operationElement);
if (targetDatastore == Datastore.candidate) {
LOG.debug("Unlocking candidate datastore on session: {}", getNetconfSessionIdForReporting());
return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
}
- throw new NetconfDocumentedException("Unable to unlock " + targetDatastore + " datastore", NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_not_supported, NetconfDocumentedException.ErrorSeverity.error);
+ throw new DocumentedException("Unable to unlock " + targetDatastore + " datastore", DocumentedException.ErrorType.application,
+ DocumentedException.ErrorTag.operation_not_supported, DocumentedException.ErrorSeverity.error);
}
@Override
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.dom.DOMResult;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorSeverity;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorTag;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorType;
+import org.opendaylight.controller.config.util.xml.XmlElement;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.mdsal.connector.CurrentSchemaContext;
import org.opendaylight.controller.netconf.mdsal.connector.ops.Datastore;
import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
}
}
- private DataSchemaNode getSchemaNodeFromNamespace(final XmlElement element) throws NetconfDocumentedException {
+ private DataSchemaNode getSchemaNodeFromNamespace(final XmlElement element) throws DocumentedException {
try {
final Module module = schemaContext.getCurrentContext().findModuleByNamespaceAndRevision(new URI(element.getNamespace()), null);
throw new IllegalArgumentException("Unable to parse element namespace, this should not happen since " +
"namespace of an xml element is valid and if the xml was parsed then the URI should be as well");
}
- throw new NetconfDocumentedException("Unable to find node with namespace: " + element.getNamespace() + "in schema context: " + schemaContext.getCurrentContext().toString(),
+ throw new DocumentedException("Unable to find node with namespace: " + element.getNamespace() + "in schema context: " + schemaContext.getCurrentContext().toString(),
ErrorType.application,
ErrorTag.unknown_namespace,
ErrorSeverity.error);
* @return if Filter is present and not empty returns Optional of the InstanceIdentifier to the read location in datastore.
* empty filter returns Optional.absent() which should equal an empty <data/> container in the response.
* if filter is not present we want to read the entire datastore - return ROOT.
- * @throws NetconfDocumentedException
+ * @throws DocumentedException
*/
- protected Optional<YangInstanceIdentifier> getDataRootFromFilter(XmlElement operationElement) throws NetconfDocumentedException {
+ protected Optional<YangInstanceIdentifier> getDataRootFromFilter(XmlElement operationElement) throws DocumentedException {
Optional<XmlElement> filterElement = operationElement.getOnlyChildElementOptionally(FILTER);
if (filterElement.isPresent()) {
if (filterElement.get().getChildElements().size() == 0) {
}
@VisibleForTesting
- protected YangInstanceIdentifier getInstanceIdentifierFromFilter(XmlElement filterElement) throws NetconfDocumentedException {
+ protected YangInstanceIdentifier getInstanceIdentifierFromFilter(XmlElement filterElement) throws DocumentedException {
if (filterElement.getChildElements().size() != 1) {
- throw new NetconfDocumentedException("Multiple filter roots not supported yet",
+ throw new DocumentedException("Multiple filter roots not supported yet",
ErrorType.application, ErrorTag.operation_not_supported, ErrorSeverity.error);
}
return path;
}
- private NormalizedNode filterToNormalizedNode(XmlElement element, DataSchemaNode schemaNode) throws NetconfDocumentedException {
+ private NormalizedNode filterToNormalizedNode(XmlElement element, DataSchemaNode schemaNode) throws DocumentedException {
DomToNormalizedNodeParserFactory parserFactory = DomToNormalizedNodeParserFactory
.getInstance(DomUtils.defaultValueCodecProvider(), schemaContext.getCurrentContext());
} else if (schemaNode instanceof ListSchemaNode) {
parsedNode = parserFactory.getMapNodeParser().parse(Collections.singletonList(element.getDomElement()), (ListSchemaNode) schemaNode);
} else {
- throw new NetconfDocumentedException("Schema node of the top level element is not an instance of container or list",
+ throw new DocumentedException("Schema node of the top level element is not an instance of container or list",
ErrorType.application, ErrorTag.unknown_element, ErrorSeverity.error);
}
return parsedNode;
return datastore;
}
- static GetConfigExecution fromXml(final XmlElement xml, final String operationName) throws NetconfDocumentedException {
+ static GetConfigExecution fromXml(final XmlElement xml, final String operationName) throws DocumentedException {
try {
validateInputRpc(xml, operationName);
- } catch (final NetconfDocumentedException e) {
- throw new NetconfDocumentedException("Incorrect RPC: " + e.getMessage(), e.getErrorType(), e.getErrorTag(), e.getErrorSeverity(), e.getErrorInfo());
+ } catch (final DocumentedException e) {
+ throw new DocumentedException("Incorrect RPC: " + e.getMessage(), e.getErrorType(), e.getErrorTag(), e.getErrorSeverity(), e.getErrorInfo());
}
final Optional<Datastore> sourceDatastore;
try {
sourceDatastore = parseSource(xml);
- } catch (final NetconfDocumentedException e) {
- throw new NetconfDocumentedException("Get-config source attribute error: " + e.getMessage(), e.getErrorType(), e.getErrorTag(), e.getErrorSeverity(), e.getErrorInfo());
+ } catch (final DocumentedException e) {
+ throw new DocumentedException("Get-config source attribute error: " + e.getMessage(), e.getErrorType(), e.getErrorTag(), e.getErrorSeverity(), e.getErrorInfo());
}
return new GetConfigExecution(sourceDatastore);
}
- private static Optional<Datastore> parseSource(final XmlElement xml) throws NetconfDocumentedException {
+ private static Optional<Datastore> parseSource(final XmlElement xml) throws DocumentedException {
final Optional<XmlElement> sourceElement = xml.getOnlyChildElementOptionally(XmlNetconfConstants.SOURCE_KEY,
XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
Optional.of(Datastore.valueOf(sourceElement.get().getOnlyChildElement().getName())) : Optional.<Datastore>absent();
}
- private static void validateInputRpc(final XmlElement xml, String operationName) throws NetconfDocumentedException{
+ private static void validateInputRpc(final XmlElement xml, String operationName) throws DocumentedException{
xml.checkName(operationName);
xml.checkNamespace(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
}
package org.opendaylight.controller.netconf.mdsal.connector.ops.get;
import com.google.common.base.Optional;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorSeverity;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorTag;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorType;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.mdsal.connector.CurrentSchemaContext;
import org.opendaylight.controller.netconf.mdsal.connector.TransactionProvider;
import org.opendaylight.controller.netconf.mdsal.connector.ops.Datastore;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.slf4j.Logger;
}
@Override
- protected Element handleWithNoSubsequentOperations(Document document, XmlElement operationElement) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(Document document, XmlElement operationElement) throws DocumentedException {
final Optional<YangInstanceIdentifier> dataRootOptional = getDataRootFromFilter(operationElement);
if (!dataRootOptional.isPresent()) {
}
}
- private DOMDataReadWriteTransaction getTransaction(Datastore datastore) throws NetconfDocumentedException{
+ private DOMDataReadWriteTransaction getTransaction(Datastore datastore) throws DocumentedException{
if (datastore == Datastore.candidate) {
return transactionProvider.getOrCreateTransaction();
} else if (datastore == Datastore.running) {
return transactionProvider.createRunningTransaction();
}
- throw new NetconfDocumentedException("Incorrect Datastore: ", ErrorType.protocol, ErrorTag.bad_element, ErrorSeverity.error);
+ throw new DocumentedException("Incorrect Datastore: ", ErrorType.protocol, ErrorTag.bad_element, ErrorSeverity.error);
}
@Override
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorSeverity;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorTag;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorType;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.mdsal.connector.CurrentSchemaContext;
import org.opendaylight.controller.netconf.mdsal.connector.TransactionProvider;
import org.opendaylight.controller.netconf.mdsal.connector.ops.Datastore;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.slf4j.Logger;
}
@Override
- protected Element handleWithNoSubsequentOperations(Document document, XmlElement operationElement) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(Document document, XmlElement operationElement) throws DocumentedException {
GetConfigExecution getConfigExecution = null;
try {
getConfigExecution = GetConfigExecution.fromXml(operationElement, OPERATION_NAME);
- } catch (final NetconfDocumentedException e) {
+ } catch (final DocumentedException e) {
LOG.warn("Get request processing failed on session: {}", getNetconfSessionIdForReporting(), e);
throw e;
}
}
}
- private DOMDataReadWriteTransaction getTransaction(Datastore datastore) throws NetconfDocumentedException{
+ private DOMDataReadWriteTransaction getTransaction(Datastore datastore) throws DocumentedException{
if (datastore == Datastore.candidate) {
return transactionProvider.getOrCreateTransaction();
} else if (datastore == Datastore.running) {
return transactionProvider.createRunningTransaction();
}
- throw new NetconfDocumentedException("Incorrect Datastore: ", ErrorType.protocol, ErrorTag.bad_element, ErrorSeverity.error);
+ throw new DocumentedException("Incorrect Datastore: ", ErrorType.protocol, ErrorTag.bad_element, ErrorSeverity.error);
}
@Override
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.cluster.datastore.ConcurrentDOMDataBroker;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorSeverity;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorTag;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorType;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStoreFactory;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
import org.opendaylight.controller.netconf.mdsal.connector.CurrentSchemaContext;
import org.opendaylight.controller.netconf.mdsal.connector.ops.get.GetConfig;
import org.opendaylight.controller.netconf.util.test.NetconfXmlUnitRecursiveQualifier;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.controller.sal.core.api.model.SchemaService;
import org.opendaylight.controller.sal.core.spi.data.DOMStore;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
try {
discardChanges();
fail("Should have failed, need to execute an edit before discard");
- } catch (NetconfDocumentedException e) {
+ } catch (DocumentedException e) {
assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
assertTrue(e.getErrorTag() == ErrorTag.operation_failed);
assertTrue(e.getErrorType() == ErrorType.application);
try {
executeOperation(new GetConfig(sessionIdForReporting, currentSchemaContext, transactionProvider), "messages/mapping/bad_getConfig.xml");
fail("Should have failed, this is an incorrect request");
- } catch (NetconfDocumentedException e) {
+ } catch (DocumentedException e) {
assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
assertTrue(e.getErrorTag() == ErrorTag.operation_failed);
assertTrue(e.getErrorType() == ErrorType.application);
try {
executeOperation(new GetConfig(sessionIdForReporting, currentSchemaContext, transactionProvider), "messages/mapping/bad_namespace_getConfig.xml");
fail("Should have failed, this is an incorrect request");
- } catch (NetconfDocumentedException e) {
+ } catch (DocumentedException e) {
assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
assertTrue(e.getErrorTag() == ErrorTag.operation_failed);
assertTrue(e.getErrorType() == ErrorType.application);
try {
edit("messages/mapping/editConfigs/editConfig_running.xml");
fail("Should have failed - edit config on running datastore is not supported");
- } catch (NetconfDocumentedException e) {
+ } catch (DocumentedException e) {
assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
assertTrue(e.getErrorTag() == ErrorTag.operation_not_supported);
assertTrue(e.getErrorType() == ErrorType.protocol);
try {
lock();
fail("Should have failed - locking of running datastore is not supported");
- } catch (NetconfDocumentedException e) {
+ } catch (DocumentedException e) {
assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
assertTrue(e.getErrorTag() == ErrorTag.operation_not_supported);
assertTrue(e.getErrorType() == ErrorType.application);
try {
lockWithoutTarget();
fail("Should have failed, target is missing");
- } catch (NetconfDocumentedException e) {
+ } catch (DocumentedException e) {
assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
assertTrue(e.getErrorTag() == ErrorTag.invalid_value);
assertTrue(e.getErrorType() == ErrorType.application);
try {
unlock();
fail("Should have failed - unlocking of running datastore is not supported");
- } catch (NetconfDocumentedException e) {
+ } catch (DocumentedException e) {
assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
assertTrue(e.getErrorTag() == ErrorTag.operation_not_supported);
assertTrue(e.getErrorType() == ErrorType.application);
try {
unlockWithoutTarget();
fail("Should have failed, target is missing");
- } catch (NetconfDocumentedException e) {
+ } catch (DocumentedException e) {
assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
assertTrue(e.getErrorTag() == ErrorTag.invalid_value);
assertTrue(e.getErrorType() == ErrorType.application);
try {
edit("messages/mapping/editConfigs/editConfig_create.xml");
fail("Create should have failed - data already exists");
- } catch (NetconfDocumentedException e) {
+ } catch (DocumentedException e) {
assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
assertTrue(e.getErrorTag() == ErrorTag.data_exists);
assertTrue(e.getErrorType() == ErrorType.protocol);
try {
edit("messages/mapping/editConfigs/editConfig_delete-top.xml");
fail("Delete should have failed - data is missing");
- } catch (NetconfDocumentedException e) {
+ } catch (DocumentedException e) {
assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
assertTrue(e.getErrorTag() == ErrorTag.data_missing);
assertTrue(e.getErrorType() == ErrorType.protocol);
try {
edit("messages/mapping/editConfigs/editConfig_merge_multiple_operations_4_create_existing.xml");
fail();
- } catch (NetconfDocumentedException e) {
+ } catch (DocumentedException e) {
assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
assertTrue(e.getErrorTag() == ErrorTag.data_exists);
assertTrue(e.getErrorType() == ErrorType.protocol);
try {
edit("messages/mapping/editConfigs/editConfig_merge_multiple_operations_4_delete-non-existing.xml");
fail();
- } catch (NetconfDocumentedException e) {
+ } catch (DocumentedException e) {
assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
assertTrue(e.getErrorTag() == ErrorTag.data_missing);
assertTrue(e.getErrorType() == ErrorType.protocol);
super(sessionId, schemaContext, transactionProvider);
}
- public YangInstanceIdentifier getInstanceIdentifierFromDocument(Document request) throws NetconfDocumentedException {
+ public YangInstanceIdentifier getInstanceIdentifierFromDocument(Document request) throws DocumentedException {
XmlElement filterElement = XmlElement.fromDomDocument(request).getOnlyChildElement(GET_CONFIG).getOnlyChildElement(FILTER_NODE);
return getInstanceIdentifierFromFilter(filterElement);
}
}
- private Document commit() throws NetconfDocumentedException, ParserConfigurationException, SAXException, IOException {
+ private Document commit() throws DocumentedException, ParserConfigurationException, SAXException, IOException {
Commit commit = new Commit(sessionIdForReporting, transactionProvider);
return executeOperation(commit, "messages/mapping/commit.xml");
}
- private Document discardChanges() throws NetconfDocumentedException, ParserConfigurationException, SAXException, IOException {
+ private Document discardChanges() throws DocumentedException, ParserConfigurationException, SAXException, IOException {
DiscardChanges discardOp = new DiscardChanges(sessionIdForReporting, transactionProvider);
return executeOperation(discardOp, "messages/mapping/discardChanges.xml");
}
- private Document edit(String resource) throws NetconfDocumentedException, ParserConfigurationException, SAXException, IOException {
+ private Document edit(String resource) throws DocumentedException, ParserConfigurationException, SAXException, IOException {
EditConfig editConfig = new EditConfig(sessionIdForReporting, currentSchemaContext, transactionProvider);
return executeOperation(editConfig, resource);
}
- private Document get() throws NetconfDocumentedException, ParserConfigurationException, SAXException, IOException {
+ private Document get() throws DocumentedException, ParserConfigurationException, SAXException, IOException {
Get get = new Get(sessionIdForReporting, currentSchemaContext, transactionProvider);
return executeOperation(get, "messages/mapping/get.xml");
}
- private Document getWithFilter(String resource) throws NetconfDocumentedException, ParserConfigurationException, SAXException, IOException {
+ private Document getWithFilter(String resource) throws DocumentedException, ParserConfigurationException, SAXException, IOException {
Get get = new Get(sessionIdForReporting, currentSchemaContext, transactionProvider);
return executeOperation(get, resource);
}
- private Document getConfigRunning() throws NetconfDocumentedException, ParserConfigurationException, SAXException, IOException {
+ private Document getConfigRunning() throws DocumentedException, ParserConfigurationException, SAXException, IOException {
GetConfig getConfig = new GetConfig(sessionIdForReporting, currentSchemaContext, transactionProvider);
return executeOperation(getConfig, "messages/mapping/getConfig.xml");
}
- private Document getConfigCandidate() throws NetconfDocumentedException, ParserConfigurationException, SAXException, IOException {
+ private Document getConfigCandidate() throws DocumentedException, ParserConfigurationException, SAXException, IOException {
GetConfig getConfig = new GetConfig(sessionIdForReporting, currentSchemaContext, transactionProvider);
return executeOperation(getConfig, "messages/mapping/getConfig_candidate.xml");
}
- private Document getConfigWithFilter(String resource) throws NetconfDocumentedException, ParserConfigurationException, SAXException, IOException {
+ private Document getConfigWithFilter(String resource) throws DocumentedException, ParserConfigurationException, SAXException, IOException {
GetConfig getConfig = new GetConfig(sessionIdForReporting, currentSchemaContext, transactionProvider);
return executeOperation(getConfig, resource);
}
- private Document lock() throws NetconfDocumentedException, ParserConfigurationException, SAXException, IOException {
+ private Document lock() throws DocumentedException, ParserConfigurationException, SAXException, IOException {
Lock lock = new Lock(sessionIdForReporting);
return executeOperation(lock, "messages/mapping/lock.xml");
}
- private Document unlock() throws NetconfDocumentedException, ParserConfigurationException, SAXException, IOException {
+ private Document unlock() throws DocumentedException, ParserConfigurationException, SAXException, IOException {
Unlock unlock = new Unlock(sessionIdForReporting);
return executeOperation(unlock, "messages/mapping/unlock.xml");
}
- private Document lockWithoutTarget() throws NetconfDocumentedException, ParserConfigurationException, SAXException, IOException {
+ private Document lockWithoutTarget() throws DocumentedException, ParserConfigurationException, SAXException, IOException {
Lock lock = new Lock(sessionIdForReporting);
return executeOperation(lock, "messages/mapping/lock_notarget.xml");
}
- private Document unlockWithoutTarget() throws NetconfDocumentedException, ParserConfigurationException, SAXException, IOException {
+ private Document unlockWithoutTarget() throws DocumentedException, ParserConfigurationException, SAXException, IOException {
Unlock unlock = new Unlock(sessionIdForReporting);
return executeOperation(unlock, "messages/mapping/unlock_notarget.xml");
}
- private Document lockCandidate() throws NetconfDocumentedException, ParserConfigurationException, SAXException, IOException {
+ private Document lockCandidate() throws DocumentedException, ParserConfigurationException, SAXException, IOException {
Lock lock = new Lock(sessionIdForReporting);
return executeOperation(lock, "messages/mapping/lock_candidate.xml");
}
- private Document unlockCandidate() throws NetconfDocumentedException, ParserConfigurationException, SAXException, IOException {
+ private Document unlockCandidate() throws DocumentedException, ParserConfigurationException, SAXException, IOException {
Unlock unlock = new Unlock(sessionIdForReporting);
return executeOperation(unlock, "messages/mapping/unlock_candidate.xml");
}
- private Document executeOperation(NetconfOperation op, String filename) throws ParserConfigurationException, SAXException, IOException, NetconfDocumentedException {
+ private Document executeOperation(NetconfOperation op, String filename) throws ParserConfigurationException, SAXException, IOException, DocumentedException {
final Document request = XmlFileLoader.xmlFileToDocument(filename);
final Document response = op.handle(request, NetconfOperationChainedExecution.EXECUTION_TERMINATION_POINT);
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorSeverity;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorTag;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorType;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.md.sal.dom.api.DOMRpcAvailabilityListener;
import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
import org.opendaylight.controller.md.sal.dom.spi.DefaultDOMRpcResult;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
import org.opendaylight.controller.netconf.mdsal.connector.CurrentSchemaContext;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.controller.sal.core.api.model.SchemaService;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.common.RpcError;
try {
rpc.handle(rpcDocument, NetconfOperationChainedExecution.EXECUTION_TERMINATION_POINT);
fail("should have failed with rpc invocation not implemented yet");
- } catch (NetconfDocumentedException e) {
+ } catch (DocumentedException e) {
assertTrue(e.getErrorType() == ErrorType.application);
assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
assertTrue(e.getErrorTag() == ErrorTag.operation_failed);
try {
rpc.handle(rpcDocument, NetconfOperationChainedExecution.EXECUTION_TERMINATION_POINT);
fail("Should have failed, rpc has bad namespace");
- } catch (NetconfDocumentedException e) {
+ } catch (DocumentedException e) {
assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
assertTrue(e.getErrorTag() == ErrorTag.bad_element);
assertTrue(e.getErrorType() == ErrorType.application);
<plugin>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-maven-plugin</artifactId>
- <executions>
- <execution>
- <id>config</id>
- <goals>
- <goal>generate-sources</goal>
- </goals>
- <configuration>
- <codeGenerators>
- <generator>
- <codeGeneratorClass>org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator</codeGeneratorClass>
- <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
- <additionalConfiguration>
- <namespaceToPackage1>urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang</namespaceToPackage1>
- </additionalConfiguration>
- </generator>
- <generator>
- <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
- <outputBaseDir>${salGeneratorPath}</outputBaseDir>
- </generator>
- </codeGenerators>
- <inspectDependencies>true</inspectDependencies>
- </configuration>
- </execution>
- </executions>
- <dependencies>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>yang-jmx-generator-plugin</artifactId>
- <version>${config.version}</version>
- </dependency>
- </dependencies>
</plugin>
</plugins>
</build>
import java.util.Collections;
import java.util.Set;
-import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.config.util.capability.Capability;
import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
import java.util.Collections;
import java.util.Set;
-import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.config.util.capability.Capability;
import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.opendaylight.controller</groupId>
- <artifactId>netconf-subsystem</artifactId>
+ <artifactId>netconf-models</artifactId>
<version>0.4.0-SNAPSHOT</version>
</parent>
<artifactId>ietf-netconf-monitoring-extension</artifactId>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.opendaylight.controller</groupId>
- <artifactId>netconf-subsystem</artifactId>
+ <artifactId>netconf-models</artifactId>
<version>0.4.0-SNAPSHOT</version>
</parent>
<artifactId>ietf-netconf-monitoring</artifactId>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.opendaylight.controller</groupId>
- <artifactId>netconf-subsystem</artifactId>
+ <artifactId>netconf-models</artifactId>
<version>0.4.0-SNAPSHOT</version>
</parent>
<artifactId>ietf-netconf-notifications</artifactId>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.opendaylight.controller</groupId>
- <artifactId>netconf-subsystem</artifactId>
+ <artifactId>netconf-models</artifactId>
<version>0.4.0-SNAPSHOT</version>
</parent>
<artifactId>ietf-netconf</artifactId>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-subsystem</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>netconf-models</artifactId>
+
+ <version>0.4.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+ <name>${project.artifactId}</name>
+
+ <modules>
+ <module>ietf-netconf</module>
+ <module>ietf-netconf-monitoring</module>
+ <module>ietf-netconf-notifications</module>
+ <module>ietf-netconf-monitoring-extension</module>
+ </modules>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-maven-plugin</artifactId>
+ </plugin>
+ </plugins>
+
+ </pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <configuration>
+ <failsOnError>false</failsOnError>
+ <failOnViolation>true</failOnViolation>
+ <configLocation>checkstyle-logging.xml</configLocation>
+ <consoleOutput>true</consoleOutput>
+ <includeTestSourceDirectory>true</includeTestSourceDirectory>
+ <sourceDirectory>${project.basedir}</sourceDirectory>
+ <includes>**\/*.java,**\/*.xml,**\/*.ini,**\/*.sh,**\/*.bat,**\/*.yang</includes>
+ <excludes>**\/target\/,**\/bin\/,**\/target-ide\/,**\/${jmxGeneratorPath}\/,**\/${salGeneratorPath}\/,**\/netconf\/test\/tool\/Main.java, **\/netconf\/test\/tool\/client\/stress\/StressClient.java</excludes>
+ </configuration>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>checkstyle-logging</artifactId>
+ <version>${yangtools.version}</version>
+ </dependency>
+ </dependencies>
+ <executions>
+ <execution>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+</project>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-manager-facade-xml</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>protocol-framework</artifactId>
<plugin>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-maven-plugin</artifactId>
- <executions>
- <execution>
- <id>config</id>
- <goals>
- <goal>generate-sources</goal>
- </goals>
- <configuration>
- <codeGenerators>
- <generator>
- <codeGeneratorClass>org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator</codeGeneratorClass>
- <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
- <additionalConfiguration>
- <namespaceToPackage1>urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang</namespaceToPackage1>
- </additionalConfiguration>
- </generator>
- <generator>
- <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
- <outputBaseDir>${salGeneratorPath}</outputBaseDir>
- </generator>
- </codeGenerators>
- <inspectDependencies>true</inspectDependencies>
- </configuration>
- </execution>
- </executions>
- <dependencies>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>yang-jmx-generator-plugin</artifactId>
- <version>${config.version}</version>
- </dependency>
- </dependencies>
</plugin>
</plugins>
</build>
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.api;
-
-import com.google.common.base.Optional;
-import java.util.Collection;
-
-/**
- * Contains capability URI announced by server hello message and optionally its
- * corresponding yang schema that can be retrieved by get-schema rpc.
- */
-public interface Capability {
-
- public String getCapabilityUri();
-
- public Optional<String> getModuleNamespace();
-
- public Optional<String> getModuleName();
-
- public Optional<String> getRevision();
-
- public Optional<String> getCapabilitySchema();
-
- public Collection<String> getLocation();
-}
package org.opendaylight.controller.netconf.api;
-import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.ERROR_INFO;
-import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.ERROR_MESSAGE;
-import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.ERROR_SEVERITY;
-import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.ERROR_TAG;
-import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.ERROR_TYPE;
-import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.RPC_ERROR;
-import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.RPC_REPLY_KEY;
-import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0;
-
-import java.util.Collections;
-import java.util.HashMap;
import java.util.Map;
-import java.util.Map.Entry;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import org.opendaylight.controller.config.api.ConflictingVersionException;
-import org.opendaylight.controller.config.api.ValidationException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
/**
* Checked exception to communicate an error that needs to be sent to the
* netconf client.
*/
-public class NetconfDocumentedException extends Exception {
-
- private static final long serialVersionUID = 1L;
-
- private final static Logger LOG = LoggerFactory.getLogger( NetconfDocumentedException.class );
-
- private static final DocumentBuilderFactory BUILDER_FACTORY;
-
- static {
- BUILDER_FACTORY = DocumentBuilderFactory.newInstance();
- try {
- BUILDER_FACTORY.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
- BUILDER_FACTORY.setFeature("http://xml.org/sax/features/external-general-entities", false);
- BUILDER_FACTORY.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
- BUILDER_FACTORY.setXIncludeAware(false);
- BUILDER_FACTORY.setExpandEntityReferences(false);
- } catch (ParserConfigurationException e) {
- throw new ExceptionInInitializerError(e);
- }
- BUILDER_FACTORY.setNamespaceAware(true);
- BUILDER_FACTORY.setCoalescing(true);
- BUILDER_FACTORY.setIgnoringElementContentWhitespace(true);
- BUILDER_FACTORY.setIgnoringComments(true);
- }
-
- public enum ErrorType {
- transport, rpc, protocol, application;
-
- public String getTagValue() {
- return name();
- }
-
- public static ErrorType from( String text ) {
- try {
- return valueOf( text );
- }
- catch( Exception e ) {
- return application;
- }
- }
- }
-
- public enum ErrorTag {
- access_denied("access-denied"),
- bad_attribute("bad-attribute"),
- bad_element("bad-element"),
- data_exists("data-exists"),
- data_missing("data-missing"),
- in_use("in-use"),
- invalid_value("invalid-value"),
- lock_denied("lock-denied"),
- malformed_message("malformed-message"),
- missing_attribute("missing-attribute"),
- missing_element("missing-element"),
- operation_failed("operation-failed"),
- operation_not_supported("operation-not-supported"),
- resource_denied("resource-denied"),
- rollback_failed("rollback-failed"),
- too_big("too-big"),
- unknown_attribute("unknown-attribute"),
- unknown_element("unknown-element"),
- unknown_namespace("unknown-namespace");
-
- private final String tagValue;
-
- ErrorTag(final String tagValue) {
- this.tagValue = tagValue;
- }
-
- public String getTagValue() {
- return this.tagValue;
- }
+public class NetconfDocumentedException extends DocumentedException {
- public static ErrorTag from( String text ) {
- for( ErrorTag e: values() )
- {
- if( e.getTagValue().equals( text ) ) {
- return e;
- }
- }
-
- return operation_failed;
- }
- }
-
- public enum ErrorSeverity {
- error, warning;
-
- public String getTagValue() {
- return name();
- }
-
- public static ErrorSeverity from( String text ) {
- try {
- return valueOf( text );
- }
- catch( Exception e ) {
- return error;
- }
- }
- }
-
- private final ErrorType errorType;
- private final ErrorTag errorTag;
- 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());
- }
-
- public NetconfDocumentedException(final String message, final ErrorType errorType, final ErrorTag errorTag,
- final ErrorSeverity errorSeverity, final Map<String, String> errorInfo) {
+ public NetconfDocumentedException(final String message) {
super(message);
- this.errorType = errorType;
- this.errorTag = errorTag;
- this.errorSeverity = errorSeverity;
- this.errorInfo = errorInfo;
}
- public NetconfDocumentedException(final String message, final Exception cause, final ErrorType errorType,
- final ErrorTag errorTag, final ErrorSeverity errorSeverity) {
- this(message, cause, errorType, errorTag, errorSeverity, Collections.<String, String> emptyMap());
+ public NetconfDocumentedException(final String message, final ErrorType errorType, final ErrorTag errorTag, final ErrorSeverity errorSeverity) {
+ super(message, errorType, errorTag, errorSeverity);
}
- public NetconfDocumentedException(final String message, final Exception cause, final ErrorType errorType,
- final ErrorTag errorTag, final ErrorSeverity errorSeverity, final Map<String, String> errorInfo) {
- super(message, cause);
- this.errorType = errorType;
- this.errorTag = errorTag;
- this.errorSeverity = errorSeverity;
- this.errorInfo = errorInfo;
+ public NetconfDocumentedException(final String message, final ErrorType errorType, final ErrorTag errorTag, final ErrorSeverity errorSeverity, final Map<String, String> errorInfo) {
+ super(message, errorType, errorTag, errorSeverity, errorInfo);
}
- public static <E extends Exception> NetconfDocumentedException wrap(E exception) throws NetconfDocumentedException {
- final Map<String, String> errorInfo = new HashMap<>();
- errorInfo.put(ErrorTag.operation_failed.name(), "Exception thrown");
- throw new NetconfDocumentedException(exception.getMessage(), exception, ErrorType.application, ErrorTag.operation_failed,
- ErrorSeverity.error, errorInfo);
- }
- public static NetconfDocumentedException wrap(ValidationException e) throws NetconfDocumentedException {
- final Map<String, String> errorInfo = new HashMap<>();
- errorInfo.put(ErrorTag.operation_failed.name(), "Validation failed");
- throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed,
- ErrorSeverity.error, errorInfo);
+ public NetconfDocumentedException(final String message, final Exception cause, final ErrorType errorType, final ErrorTag errorTag, final ErrorSeverity errorSeverity) {
+ super(message, cause, errorType, errorTag, errorSeverity);
}
- public static NetconfDocumentedException wrap(ConflictingVersionException e) throws NetconfDocumentedException {
- final Map<String, String> errorInfo = new HashMap<>();
- errorInfo.put(ErrorTag.operation_failed.name(), "Optimistic lock failed");
- throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed,
- ErrorSeverity.error, errorInfo);
- }
-
- public static NetconfDocumentedException fromXMLDocument( Document fromDoc ) {
-
- ErrorType errorType = ErrorType.application;
- ErrorTag errorTag = ErrorTag.operation_failed;
- ErrorSeverity errorSeverity = ErrorSeverity.error;
- Map<String, String> errorInfo = null;
- String errorMessage = "";
-
- Node rpcReply = fromDoc.getDocumentElement();
-
- // FIXME: BUG? - we only handle one rpc-error.
-
- NodeList replyChildren = rpcReply.getChildNodes();
- for( int i = 0; i < replyChildren.getLength(); i++ ) {
- Node replyChild = replyChildren.item( i );
- if( RPC_ERROR.equals( replyChild.getNodeName() ) )
- {
- NodeList rpcErrorChildren = replyChild.getChildNodes();
- for( int j = 0; j < rpcErrorChildren.getLength(); j++ )
- {
- Node rpcErrorChild = rpcErrorChildren.item( j );
- if( ERROR_TYPE.equals( rpcErrorChild.getNodeName() ) ) {
- errorType = ErrorType.from( rpcErrorChild.getTextContent() );
- }
- else if( ERROR_TAG.equals( rpcErrorChild.getNodeName() ) ) {
- errorTag = ErrorTag.from( rpcErrorChild.getTextContent() );
- }
- else if( ERROR_SEVERITY.equals( rpcErrorChild.getNodeName() ) ) {
- errorSeverity = ErrorSeverity.from( rpcErrorChild.getTextContent() );
- }
- else if( ERROR_MESSAGE.equals( rpcErrorChild.getNodeName() ) ) {
- errorMessage = rpcErrorChild.getTextContent();
- }
- else if( ERROR_INFO.equals( rpcErrorChild.getNodeName() ) ) {
- errorInfo = parseErrorInfo( rpcErrorChild );
- }
- }
-
- break;
- }
- }
-
- return new NetconfDocumentedException( errorMessage, errorType, errorTag, errorSeverity, errorInfo );
- }
-
- private static Map<String, String> parseErrorInfo( Node node ) {
- Map<String, String> infoMap = new HashMap<>();
- NodeList children = node.getChildNodes();
- for( int i = 0; i < children.getLength(); i++ ) {
- Node child = children.item( i );
- if( child.getNodeType() == Node.ELEMENT_NODE ) {
- infoMap.put( child.getNodeName(), child.getTextContent() );
- }
- }
-
- return infoMap;
- }
-
- public ErrorType getErrorType() {
- return this.errorType;
- }
-
- public ErrorTag getErrorTag() {
- return this.errorTag;
- }
-
- public ErrorSeverity getErrorSeverity() {
- return this.errorSeverity;
- }
-
- public Map<String, String> getErrorInfo() {
- return this.errorInfo;
- }
-
- public Document toXMLDocument() {
- Document doc = null;
- try {
- doc = BUILDER_FACTORY.newDocumentBuilder().newDocument();
-
- Node rpcReply = doc.createElementNS( URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, RPC_REPLY_KEY );
- doc.appendChild( rpcReply );
-
- Node rpcError = doc.createElementNS( URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, RPC_ERROR );
- rpcReply.appendChild( rpcError );
-
- rpcError.appendChild( createTextNode( doc, ERROR_TYPE, getErrorType().getTagValue() ) );
- rpcError.appendChild( createTextNode( doc, ERROR_TAG, getErrorTag().getTagValue() ) );
- rpcError.appendChild( createTextNode( doc, ERROR_SEVERITY, getErrorSeverity().getTagValue() ) );
- rpcError.appendChild( createTextNode( doc, ERROR_MESSAGE, getLocalizedMessage() ) );
-
- Map<String, String> errorInfoMap = getErrorInfo();
- if( errorInfoMap != null && !errorInfoMap.isEmpty() ) {
- /*
- * <error-info>
- * <bad-attribute>message-id</bad-attribute>
- * <bad-element>rpc</bad-element>
- * </error-info>
- */
-
- Node errorInfoNode = doc.createElementNS( URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, ERROR_INFO );
- errorInfoNode.setPrefix( rpcReply.getPrefix() );
- rpcError.appendChild( errorInfoNode );
-
- for ( Entry<String, String> entry : errorInfoMap.entrySet() ) {
- errorInfoNode.appendChild( createTextNode( doc, entry.getKey(), entry.getValue() ) );
- }
- }
- }
- catch( ParserConfigurationException e ) {
- LOG.error( "Error outputting to XML document", e ); // this shouldn't happen
- }
-
- return doc;
+ public NetconfDocumentedException(final String message, final Exception cause, final ErrorType errorType, final ErrorTag errorTag, final ErrorSeverity errorSeverity, final Map<String, String> errorInfo) {
+ super(message, cause, errorType, errorTag, errorSeverity, errorInfo);
}
- private Node createTextNode( Document doc, String tag, String textContent ) {
- Node node = doc.createElementNS( URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, tag );
- node.setTextContent( textContent );
- return node;
+ public NetconfDocumentedException(DocumentedException e) {
+ super(e.getMessage(), e.getErrorType(), e.getErrorTag(), e.getErrorSeverity(), e.getErrorInfo());
}
- @Override
- public String toString() {
- return "NetconfDocumentedException{" + "message=" + getMessage() + ", errorType=" + this.errorType
- + ", errorTag=" + this.errorTag + ", errorSeverity=" + this.errorSeverity + ", errorInfo="
- + this.errorInfo + '}';
+ public static NetconfDocumentedException fromXMLDocument( Document fromDoc) {
+ return new NetconfDocumentedException(DocumentedException.fromXMLDocument(fromDoc));
}
}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.api.jmx;
-
-import java.util.Set;
-import javax.management.NotificationBroadcasterSupport;
-import org.w3c.dom.Element;
-
-public class CommitJMXNotification extends NetconfJMXNotification {
-
- private final Element configSnapshot;
-
- private static final String AFTER_COMMIT_MESSAGE_TEMPLATE = "Commit successful: %s";
- private final Set<String> capabilities;
-
- CommitJMXNotification(NotificationBroadcasterSupport source, String message, Element cfgSnapshot,
- Set<String> capabilities) {
- super(TransactionProviderJMXNotificationType.commit, source, String.format(AFTER_COMMIT_MESSAGE_TEMPLATE, message));
- this.configSnapshot = cfgSnapshot;
- this.capabilities = capabilities;
- }
-
- public Element getConfigSnapshot() {
- return configSnapshot;
- }
-
- public Set<String> getCapabilities() {
- return capabilities;
- }
-
- @Override
- public String toString() {
- final StringBuffer sb = new StringBuffer("CommitJMXNotification{");
- sb.append("configSnapshot=").append(configSnapshot);
- sb.append(", capabilities=").append(getCapabilities());
- sb.append('}');
- return sb.toString();
- }
-
- /**
- *
- */
- private static final long serialVersionUID = -8587623362011695514L;
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.api.jmx;
-
-import javax.management.ObjectName;
-import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-
-public interface DefaultCommitOperationMXBean {
-
- String TYPE_NAME = "NetconfNotificationProvider";
- ObjectName OBJECT_NAME = ObjectNameUtil.createONWithDomainAndType(TYPE_NAME);
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.api.jmx;
-
-import java.util.Set;
-import javax.management.Notification;
-import javax.management.NotificationBroadcasterSupport;
-import org.w3c.dom.Element;
-
-public abstract class NetconfJMXNotification extends Notification {
-
- /**
- *
- */
- private static final long serialVersionUID = 6754474563863772845L;
-
- private static long sequenceNumber = 1;
-
- private final TransactionProviderJMXNotificationType type;
-
- protected NetconfJMXNotification(TransactionProviderJMXNotificationType type,
- NotificationBroadcasterSupport source, String message) {
- super(type.toString(), source, sequenceNumber++, System.nanoTime(), message);
- this.type = type;
- }
-
- @Override
- public String toString() {
- return "TransactionProviderJMXNotification [type=" + type + "]";
- }
-
- /**
- * Sends this notification using source that created it
- */
- public void send() {
- ((NotificationBroadcasterSupport) getSource()).sendNotification(this);
- }
-
- /**
- * Creates notification about successful commit execution.
- *
- * Intended for config-persister.
- *
- * @param transactionName
- * @param cfgSnapshot
- */
- public static CommitJMXNotification afterCommit(NotificationBroadcasterSupport source, String message,
- Element cfgSnapshot, Set<String> capabilities) {
- return new CommitJMXNotification(source, message, cfgSnapshot, capabilities);
- }
-
- static enum TransactionProviderJMXNotificationType {
- commit;
- }
-
-}
package org.opendaylight.controller.netconf.api.monitoring;
import java.util.Set;
-import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.config.util.capability.Capability;
public interface CapabilityListener {
- void onCapabilitiesAdded(Set<Capability> addedCaps);
+ void onCapabilitiesChanged(Set<Capability> added, Set<Capability> removed);
- void onCapabilitiesRemoved(Set<Capability> removedCaps);
}
package org.opendaylight.controller.netconf.api.util;
+/**
+ * These constants mark operation service factories that are auto wired with netconf endpoint
+ * for config subsystem
+ */
public final class NetconfConstants {
/*
* TODO define marker interface in mapping-api that the serviceFactories in cofing subsystem
*/
package org.opendaylight.controller.netconf.api.xml;
-public final class XmlNetconfConstants {
-
+import org.opendaylight.controller.config.util.xml.XmlMappingConstants;
+public final class XmlNetconfConstants {
private XmlNetconfConstants() {}
- public static final String MOUNTPOINTS = "mountpoints";
- public static final String MOUNTPOINT = "mountpoint";
- public static final String ID = "id";
public static final String CAPABILITY = "capability";
public static final String CAPABILITIES = "capabilities";
public static final String COMMIT = "commit";
- public static final String TYPE_KEY = "type";
- public static final String MODULE_KEY = "module";
- public static final String INSTANCE_KEY = "instance";
public static final String OPERATION_ATTR_KEY = "operation";
- public static final String SERVICES_KEY = "services";
public static final String CONFIG_KEY = "config";
- public static final String MODULES_KEY = "modules";
- public static final String CONFIGURATION_KEY = "configuration";
public static final String DATA_KEY = "data";
public static final String OK = "ok";
public static final String FILTER = "filter";
public static final String SOURCE_KEY = "source";
public static final String RPC_KEY = "rpc";
- public static final String RPC_REPLY_KEY = "rpc-reply";
- public static final String RPC_ERROR = "rpc-error";
- public static final String ERROR_TYPE = "error-type";
- public static final String ERROR_TAG = "error-tag";
- public static final String ERROR_SEVERITY = "error-severity";
- public static final String ERROR_APP_TAG = "error-app-tag";
- public static final String ERROR_PATH = "error-path";
- public static final String ERROR_MESSAGE = "error-message";
- public static final String ERROR_INFO = "error-info";
- public static final String NAME_KEY = "name";
public static final String NOTIFICATION_ELEMENT_NAME = "notification";
- public static final String PREFIX = "prefix";
-
public static final String MESSAGE_ID = "message-id";
public static final String SESSION_ID = "session-id";
- //
- // TODO duplicate
- public static final String RFC4741_TARGET_NAMESPACE = "urn:ietf:params:xml:ns:netconf:base:1.0";
- public static final String URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0 = "urn:ietf:params:xml:ns:netconf:base:1.0";
-// public static final String URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_1 = "urn:ietf:params:xml:ns:netconf:base:1.1";
+ public static final String GET = "get";
+ public static final String GET_CONFIG = "get-config";
+
+ public static final String URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0 = XmlMappingConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0;
public static final String URN_IETF_PARAMS_NETCONF_BASE_1_0 = "urn:ietf:params:netconf:base:1.0";
public static final String URN_IETF_PARAMS_NETCONF_BASE_1_1 = "urn:ietf:params:netconf:base:1.1";
public static final String URN_IETF_PARAMS_XML_NS_NETCONF_EXI_1_0 = "urn:ietf:params:xml:ns:netconf:exi:1.0";
public static final String URN_IETF_PARAMS_NETCONF_CAPABILITY_EXI_1_0 = "urn:ietf:params:netconf:capability:exi:1.0";
public static final String URN_IETF_PARAMS_XML_NS_YANG_IETF_NETCONF_MONITORING = "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring";
- // TODO where to store namespace of config ?
- public static final String URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG = "urn:opendaylight:params:xml:ns:yang:controller:config";
- public static final String GET = "get";
- public static final String GET_CONFIG = "get-config";
}
import javax.xml.xpath.XPathFactory;
import org.junit.Before;
import org.junit.Test;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
@Test
public void testToAndFromXMLDocument() throws XPathExpressionException {
String errorMessage = "mock error message";
- NetconfDocumentedException ex = new NetconfDocumentedException( errorMessage, null,
- ErrorType.protocol,
- ErrorTag.data_exists,
- ErrorSeverity.warning,
+ DocumentedException ex = new NetconfDocumentedException( errorMessage, null,
+ DocumentedException.ErrorType.protocol,
+ DocumentedException.ErrorTag.data_exists,
+ DocumentedException.ErrorSeverity.warning,
ImmutableMap.of( "foo", "bar" ) );
Document doc = ex.toXMLDocument();
Node errorTypeNode = getNode( "netconf:error-type", rpcErrorNode );
assertNotNull( "error-type not found", errorTypeNode );
- assertEquals( "error-type", ErrorType.protocol.getTagValue(),
+ assertEquals( "error-type", DocumentedException.ErrorType.protocol.getTagValue(),
errorTypeNode.getTextContent() );
Node errorTagNode = getNode( "netconf:error-tag", rpcErrorNode );
assertNotNull( "error-tag not found", errorTagNode );
- assertEquals( "error-tag", ErrorTag.data_exists.getTagValue(),
+ assertEquals( "error-tag", DocumentedException.ErrorTag.data_exists.getTagValue(),
errorTagNode.getTextContent() );
Node errorSeverityNode = getNode( "netconf:error-severity", rpcErrorNode );
assertNotNull( "error-severity not found", errorSeverityNode );
- assertEquals( "error-severity", ErrorSeverity.warning.getTagValue(),
+ assertEquals( "error-severity", DocumentedException.ErrorSeverity.warning.getTagValue(),
errorSeverityNode.getTextContent() );
Node errorInfoNode = getNode( "netconf:error-info/netconf:foo", rpcErrorNode );
// Test fromXMLDocument
- ex = NetconfDocumentedException.fromXMLDocument( doc );
+ ex = DocumentedException.fromXMLDocument( doc );
assertNotNull( "NetconfDocumentedException is null", ex );
- assertEquals( "getErrorSeverity", ErrorSeverity.warning, ex.getErrorSeverity() );
- assertEquals( "getErrorTag", ErrorTag.data_exists, ex.getErrorTag() );
- assertEquals( "getErrorType", ErrorType.protocol, ex.getErrorType() );
+ assertEquals( "getErrorSeverity", DocumentedException.ErrorSeverity.warning, ex.getErrorSeverity() );
+ assertEquals( "getErrorTag", DocumentedException.ErrorTag.data_exists, ex.getErrorTag() );
+ assertEquals( "getErrorType", DocumentedException.ErrorType.protocol, ex.getErrorType() );
assertEquals( "getLocalizedMessage", errorMessage, ex.getLocalizedMessage() );
assertEquals( "getErrorInfo", ImmutableMap.of( "foo", "bar" ), ex.getErrorInfo() );
}
<version>0.4.0-SNAPSHOT</version>
<packaging>pom</packaging>
+ <properties>
+ <mdsal.version>1.3.0-SNAPSHOT</mdsal.version>
+ </properties>
+
<dependencyManagement>
<dependencies>
<dependency>
<artifactId>mdsal-netconf-monitoring</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mdsal-netconf-monitoring</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-netty-util</artifactId>
<artifactId>netconf-util</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-mdsal-config</artifactId>
+ <version>${project.version}</version>
+ <classifier>config</classifier>
+ <type>xml</type>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>sal-netconf-connector</artifactId>
+ <version>${mdsal.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>features-netconf-connector</artifactId>
+ <version>${mdsal.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
import java.util.Collection;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.NetconfClientSessionPreferences;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil;
import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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
+-->
+<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/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-subsystem</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>netconf-config-dispatcher</artifactId>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>config-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-client</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>config-manager</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>config-manager</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>config-util</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netty-threadgroup-config</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netty-timer-config</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>mockito-configuration</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-maven-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+</project>
--- /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.config.yang.config.netconf.client.dispatcher;
+
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
+
+/**
+*
+*/
+public final class NetconfClientDispatcherModule extends org.opendaylight.controller.config.yang.config.netconf.client.dispatcher.AbstractNetconfClientDispatcherModule {
+
+ public NetconfClientDispatcherModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public NetconfClientDispatcherModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+ NetconfClientDispatcherModule oldModule, java.lang.AutoCloseable oldInstance) {
+
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ protected void customValidation(){
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ return new NetconfClientDispatcherImpl(getBossThreadGroupDependency(), getWorkerThreadGroupDependency(), getTimerDependency());
+ }
+}
--- /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.config.yang.config.netconf.client.dispatcher;
+
+/**
+*
+*/
+public class NetconfClientDispatcherModuleFactory extends org.opendaylight.controller.config.yang.config.netconf.client.dispatcher.AbstractNetconfClientDispatcherModuleFactory
+{
+
+
+}
--- /dev/null
+// vi: set smarttab et sw=4 tabstop=4:
+module odl-netconf-cfg {
+
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:config:netconf";
+ prefix "cfg-net";
+
+ import config { prefix config; revision-date 2013-04-05; }
+
+ description
+ "This module contains the base YANG definitions for
+ netconf related services.
+
+ Copyright (c)2013 Cisco Systems, Inc. All rights reserved.;
+
+ This program and the accompanying materials are made available
+ under the terms of the Eclipse Public License v1.0 which
+ accompanies this distribution, and is available at
+ http://www.eclipse.org/legal/epl-v10.html";
+
+ revision "2014-04-08" {
+ description
+ "Initial revision.";
+ }
+
+ identity netconf-client-dispatcher {
+
+ base "config:service-type";
+ config:java-class "org.opendaylight.controller.netconf.client.NetconfClientDispatcher";
+ }
+}
\ No newline at end of file
--- /dev/null
+// vi: set smarttab et sw=4 tabstop=4:
+module odl-netconfig-client-cfg {
+
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:config:netconf:client:dispatcher";
+ prefix "cfg-net-client";
+
+ import config { prefix config; revision-date 2013-04-05; }
+ import odl-netconf-cfg { prefix cfg-net; revision-date 2014-04-08; }
+ import netty {prefix netty; }
+
+ description
+ "This module contains the base YANG definitions for
+ netconf-client-dispatcher implementation.
+
+ Copyright (c)2013 Cisco Systems, Inc. All rights reserved.;
+
+ This program and the accompanying materials are made available
+ under the terms of the Eclipse Public License v1.0 which
+ accompanies this distribution, and is available at
+ http://www.eclipse.org/legal/epl-v10.html";
+
+ revision "2014-04-08" {
+ description
+ "Initial revision.";
+ }
+
+ identity netconf-client-dispatcher {
+ base config:module-type;
+ config:provided-service cfg-net:netconf-client-dispatcher;
+ config:java-name-prefix NetconfClientDispatcher;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case netconf-client-dispatcher {
+ when "/config:modules/config:module/config:type = 'netconf-client-dispatcher'";
+
+ container boss-thread-group {
+ uses config:service-ref {
+ refine type {
+ config:required-identity netty:netty-threadgroup;
+ }
+ }
+ }
+
+ container worker-thread-group {
+ uses config:service-ref {
+ refine type {
+ config:required-identity netty:netty-threadgroup;
+ }
+ }
+ }
+
+ container timer {
+ uses config:service-ref {
+ refine type {
+ config:required-identity netty:netty-timer;
+ }
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
--- /dev/null
+package org.opendaylight.controller.config.yang.config.netconf.client.dispatcher;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ValidationException;
+import org.opendaylight.controller.config.api.jmx.CommitStatus;
+import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
+import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
+import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
+import org.opendaylight.controller.config.yang.netty.threadgroup.NettyThreadgroupModuleFactory;
+import org.opendaylight.controller.config.yang.netty.threadgroup.NettyThreadgroupModuleMXBean;
+import org.opendaylight.controller.config.yang.netty.timer.HashedWheelTimerModuleFactory;
+
+public class NetconfClientDispatcherModuleTest extends AbstractConfigTest{
+
+ private NetconfClientDispatcherModuleFactory factory;
+ private final String instanceName = "dispatch";
+
+ @Before
+ public void setUp() {
+ factory = new NetconfClientDispatcherModuleFactory();
+ super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,factory,
+ new NettyThreadgroupModuleFactory(),
+ new HashedWheelTimerModuleFactory()));
+ }
+
+ @Test
+ public void testCreateBean() throws InstanceAlreadyExistsException, ValidationException, ConflictingVersionException {
+ ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+
+ createInstance(transaction, instanceName, "timer", "thGroup");
+ createInstance(transaction, instanceName + 2, "timer2", "thGroup2");
+ transaction.validateConfig();
+ CommitStatus status = transaction.commit();
+
+ assertBeanCount(2, factory.getImplementationName());
+ assertStatus(status, 2 + 4, 0, 0);
+ }
+
+ @Test
+ public void testReusingOldInstance() throws InstanceAlreadyExistsException, ConflictingVersionException, ValidationException {
+
+ ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+ createInstance(transaction, instanceName, "timer", "thGroup");
+
+ transaction.commit();
+
+ transaction = configRegistryClient.createTransaction();
+ assertBeanCount(1, factory.getImplementationName());
+ CommitStatus status = transaction.commit();
+
+ assertBeanCount(1, factory.getImplementationName());
+ assertStatus(status, 0, 0, 3);
+ }
+
+ @Test
+ public void testReconfigure() throws InstanceAlreadyExistsException, ConflictingVersionException,
+ ValidationException, InstanceNotFoundException {
+
+ ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+ createInstance(transaction, instanceName, "timer", "thGroup");
+
+ transaction.commit();
+
+ transaction = configRegistryClient.createTransaction();
+ assertBeanCount(1, factory.getImplementationName());
+ NetconfClientDispatcherModuleMXBean mxBean = transaction.newMBeanProxy(
+ transaction.lookupConfigBean(NetconfClientDispatcherModuleFactory.NAME, instanceName),
+ NetconfClientDispatcherModuleMXBean.class);
+ mxBean.setBossThreadGroup(getThreadGroup(transaction, "group2"));
+ CommitStatus status = transaction.commit();
+
+ assertBeanCount(1, factory.getImplementationName());
+ assertStatus(status, 1, 1, 2);
+ }
+
+ private ObjectName createInstance(ConfigTransactionJMXClient transaction, String instanceName, String timerName, String threadGroupName)
+ throws InstanceAlreadyExistsException {
+ ObjectName nameCreated = transaction.createModule(factory.getImplementationName(), instanceName);
+ NetconfClientDispatcherModuleMXBean mxBean = transaction.newMBeanProxy(nameCreated, NetconfClientDispatcherModuleMXBean.class);
+ ObjectName thGroup = getThreadGroup(transaction, threadGroupName);
+ mxBean.setBossThreadGroup(thGroup);
+ mxBean.setWorkerThreadGroup(thGroup);
+ mxBean.setTimer(getTimer(transaction, timerName));
+ return nameCreated;
+ }
+
+ private ObjectName getTimer(ConfigTransactionJMXClient transaction, String name) throws InstanceAlreadyExistsException {
+ return transaction.createModule(HashedWheelTimerModuleFactory.NAME, name);
+ }
+
+ private ObjectName getThreadGroup(ConfigTransactionJMXClient transaction, String name) throws InstanceAlreadyExistsException {
+ ObjectName nameCreated = transaction.createModule(NettyThreadgroupModuleFactory.NAME, name);
+ NettyThreadgroupModuleMXBean mxBean = transaction.newMXBeanProxy(nameCreated, NettyThreadgroupModuleMXBean.class);
+ mxBean.setThreadCount(1);
+ return nameCreated;
+ }
+}
<groupId>${project.groupId}</groupId>
<artifactId>netconf-mapping-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-notifications-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-notifications-impl</artifactId>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-netty-util</artifactId>
<artifactId>ietf-inet-types</artifactId>
</dependency>
- <dependency>
- <groupId>org.osgi</groupId>
- <artifactId>org.osgi.core</artifactId>
- </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<plugin>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-maven-plugin</artifactId>
- <executions>
- <execution>
- <id>config</id>
- <goals>
- <goal>generate-sources</goal>
- </goals>
- <configuration>
- <codeGenerators>
- <generator>
- <codeGeneratorClass>org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator</codeGeneratorClass>
- <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
- <additionalConfiguration>
- <namespaceToPackage1>urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang</namespaceToPackage1>
- </additionalConfiguration>
- </generator>
- <generator>
- <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
- <outputBaseDir>${salGeneratorPath}</outputBaseDir>
- </generator>
- </codeGenerators>
- <inspectDependencies>true</inspectDependencies>
- </configuration>
- </execution>
- </executions>
- <dependencies>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>yang-jmx-generator-plugin</artifactId>
- <version>${config.version}</version>
- </dependency>
- </dependencies>
</plugin>
</plugins>
</build>
import org.opendaylight.controller.config.api.JmxAttributeValidationException;
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
-import org.opendaylight.controller.netconf.impl.CommitNotifier;
import org.opendaylight.controller.netconf.impl.NetconfServerDispatcherImpl;
import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
import org.opendaylight.controller.netconf.impl.SessionIdProvider;
final AggregatedNetconfOperationServiceFactory aggregatedOpProvider = getAggregatedOpProvider();
final NetconfMonitoringService monitoringService = getServerMonitorDependency();
final NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
- getTimerDependency(), aggregatedOpProvider, new SessionIdProvider(), getConnectionTimeoutMillis(), CommitNotifier.NoopCommitNotifier.getInstance(), monitoringService);
+ getTimerDependency(), aggregatedOpProvider, new SessionIdProvider(), getConnectionTimeoutMillis(), monitoringService);
final NetconfServerDispatcherImpl.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcherImpl.ServerChannelInitializer(
serverNegotiatorFactory);
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.impl;
-
-import java.util.Set;
-import org.w3c.dom.Element;
-
-public interface CommitNotifier {
- void sendCommitNotification(String message, Element cfgSnapshot, Set<String> capabilities);
-
- public static final class NoopCommitNotifier implements CommitNotifier {
-
- private static final CommitNotifier INSTANCE = new NoopCommitNotifier();
-
- private NoopCommitNotifier() {}
-
- public static CommitNotifier getInstance() {
- return INSTANCE;
- }
-
- @Override
- public void sendCommitNotification(final String message, final Element cfgSnapshot, final Set<String> capabilities) {
- // NOOP
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.impl;
-
-import java.util.Set;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InstanceNotFoundException;
-import javax.management.MBeanRegistrationException;
-import javax.management.MBeanServer;
-import javax.management.NotCompliantMBeanException;
-import javax.management.NotificationBroadcasterSupport;
-import javax.management.ObjectName;
-import org.opendaylight.controller.netconf.api.jmx.CommitJMXNotification;
-import org.opendaylight.controller.netconf.api.jmx.DefaultCommitOperationMXBean;
-import org.opendaylight.controller.netconf.api.jmx.NetconfJMXNotification;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.w3c.dom.Element;
-
-public class DefaultCommitNotificationProducer extends NotificationBroadcasterSupport implements
- DefaultCommitOperationMXBean, AutoCloseable, CommitNotifier {
-
- private static final Logger LOG = LoggerFactory.getLogger(DefaultCommitNotificationProducer.class);
-
- private final MBeanServer mbeanServer;
-
- private final ObjectName on = DefaultCommitOperationMXBean.OBJECT_NAME;
-
- public DefaultCommitNotificationProducer(MBeanServer mBeanServer) {
- this.mbeanServer = mBeanServer;
- LOG.debug("Registering to JMX under {}", on);
- registerMBean(this, mbeanServer, on);
- }
-
- private static void registerMBean(final Object instance, final MBeanServer mbs, final ObjectName on) {
- try {
- mbs.registerMBean(instance, on);
- } catch (InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException e) {
- throw new IllegalStateException("Unable to register " + instance + " as " + on, e);
- }
- }
-
- @Override
- public void sendCommitNotification(String message, Element cfgSnapshot, Set<String> capabilities) {
- CommitJMXNotification notif = NetconfJMXNotification.afterCommit(this, message, cfgSnapshot, capabilities);
- LOG.debug("Notification about commit {} sent", notif);
- sendNotification(notif);
- }
-
- @Override
- public void close() {
- try {
- mbeanServer.unregisterMBean(on);
- } catch (InstanceNotFoundException | MBeanRegistrationException e) {
- LOG.warn("Ignoring exception while unregistering {} as {}", this, on, e);
- }
- }
-}
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.NetconfSessionListener;
import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouter;
import org.opendaylight.controller.netconf.util.messages.SendErrorExceptionUtil;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
LOG.error("Unexpected exception", e);
session.onIncommingRpcFail();
throw new IllegalStateException("Unable to process incoming message " + netconfMessage, e);
- } catch (NetconfDocumentedException e) {
+ } catch (DocumentedException e) {
LOG.trace("Error occurred while processing message",e);
session.onOutgoingRpcError();
session.onIncommingRpcFail();
}
private NetconfMessage processDocument(final NetconfMessage netconfMessage, final NetconfServerSession session)
- throws NetconfDocumentedException {
+ throws DocumentedException {
final Document incomingDocument = netconfMessage.getDocument();
final Node rootNode = incomingDocument.getDocumentElement();
* unexpected element Description: An unexpected element is present.
*/
// TODO add message to error info
- throw new NetconfDocumentedException("Unknown tag " + rootNode.getNodeName(),
- NetconfDocumentedException.ErrorType.protocol, NetconfDocumentedException.ErrorTag.unknown_element,
- NetconfDocumentedException.ErrorSeverity.error, ImmutableMap.of("bad-element",
+ throw new DocumentedException("Unknown tag " + rootNode.getNodeName(),
+ DocumentedException.ErrorType.protocol, DocumentedException.ErrorTag.unknown_element,
+ DocumentedException.ErrorSeverity.error, ImmutableMap.of("bad-element",
rootNode.getNodeName()));
}
}
- private static void checkMessageId(final Node rootNode) throws NetconfDocumentedException {
+ private static void checkMessageId(final Node rootNode) throws DocumentedException {
NamedNodeMap attributes = rootNode.getAttributes();
return;
}
- throw new NetconfDocumentedException("Missing attribute" + rootNode.getNodeName(),
- NetconfDocumentedException.ErrorType.protocol, NetconfDocumentedException.ErrorTag.missing_attribute,
- NetconfDocumentedException.ErrorSeverity.error,
- ImmutableMap.of(NetconfDocumentedException.ErrorTag.missing_attribute.toString(),
+ throw new DocumentedException("Missing attribute" + rootNode.getNodeName(),
+ DocumentedException.ErrorType.protocol, DocumentedException.ErrorTag.missing_attribute,
+ DocumentedException.ErrorSeverity.error,
+ ImmutableMap.of(DocumentedException.ErrorTag.missing_attribute.toString(),
XmlNetconfConstants.MESSAGE_ID));
}
}
package org.opendaylight.controller.netconf.impl;
+import com.google.common.base.Function;
import com.google.common.base.Preconditions;
+import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import io.netty.channel.Channel;
import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences;
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCommit;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouter;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouterImpl;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import org.opendaylight.protocol.framework.SessionListenerFactory;
import org.opendaylight.protocol.framework.SessionNegotiator;
import org.opendaylight.protocol.framework.SessionNegotiatorFactory;
+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.netconf.monitoring.rev101004.netconf.state.Capabilities;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private final SessionIdProvider idProvider;
private final NetconfOperationServiceFactory aggregatedOpService;
private final long connectionTimeoutMillis;
- private final CommitNotifier commitNotificationProducer;
private final NetconfMonitoringService monitoringService;
private static final Logger LOG = LoggerFactory.getLogger(NetconfServerSessionNegotiatorFactory.class);
private final Set<String> baseCapabilities;
// TODO too many params, refactor
public NetconfServerSessionNegotiatorFactory(final Timer timer, final NetconfOperationServiceFactory netconfOperationProvider,
final SessionIdProvider idProvider, final long connectionTimeoutMillis,
- final CommitNotifier commitNot,
final NetconfMonitoringService monitoringService) {
- this(timer, netconfOperationProvider, idProvider, connectionTimeoutMillis, commitNot, monitoringService, DEFAULT_BASE_CAPABILITIES);
+ this(timer, netconfOperationProvider, idProvider, connectionTimeoutMillis, monitoringService, DEFAULT_BASE_CAPABILITIES);
}
// TODO too many params, refactor
public NetconfServerSessionNegotiatorFactory(final Timer timer, final NetconfOperationServiceFactory netconfOperationProvider,
final SessionIdProvider idProvider, final long connectionTimeoutMillis,
- final CommitNotifier commitNot,
final NetconfMonitoringService monitoringService, final Set<String> baseCapabilities) {
this.timer = timer;
this.aggregatedOpService = netconfOperationProvider;
this.idProvider = idProvider;
this.connectionTimeoutMillis = connectionTimeoutMillis;
- this.commitNotificationProducer = commitNot;
this.monitoringService = monitoringService;
this.baseCapabilities = validateBaseCapabilities(baseCapabilities);
}
final NetconfOperationService service =
this.aggregatedOpService.createService(netconfSessionIdForReporting);
final NetconfOperationRouter operationRouter =
- new NetconfOperationRouterImpl(service, commitNotificationProducer, monitoringService, netconfSessionIdForReporting);
+ new NetconfOperationRouterImpl(service, monitoringService, netconfSessionIdForReporting);
return new NetconfServerSessionListener(operationRouter, monitoringService, service);
}
private NetconfHelloMessage createHelloMessage(final long sessionId, final NetconfMonitoringService capabilityProvider) throws NetconfDocumentedException {
- return NetconfHelloMessage.createServerHello(Sets.union(DefaultCommit.transformCapabilities(capabilityProvider.getCapabilities()), baseCapabilities), sessionId);
+ return NetconfHelloMessage.createServerHello(Sets.union(transformCapabilities(capabilityProvider.getCapabilities()), baseCapabilities), sessionId);
+ }
+
+ public static Set<String> transformCapabilities(final Capabilities capabilities) {
+ return Sets.newHashSet(Collections2.transform(capabilities.getCapability(), new Function<Uri, String>() {
+ @Override
+ public String apply(final Uri uri) {
+ return uri.getValue();
+ }
+ }));
}
}
import com.google.common.base.Optional;
import java.io.IOException;
import java.util.Map;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation.OperationNameAndNamespace;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Attr;
public class SubtreeFilter {
private static final Logger LOG = LoggerFactory.getLogger(SubtreeFilter.class);
- static Document applySubtreeFilter(Document requestDocument, Document rpcReply) throws NetconfDocumentedException {
+ static Document applySubtreeFilter(Document requestDocument, Document rpcReply) throws DocumentedException {
OperationNameAndNamespace operationNameAndNamespace = new OperationNameAndNamespace(requestDocument);
if (XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0.equals(operationNameAndNamespace.getNamespace()) &&
XmlNetconfConstants.GET.equals(operationNameAndNamespace.getOperationName()) ||
rpcReply = XmlUtil.readXmlToDocument(XmlUtil.toString(rpcReply, true));
} catch (SAXException | IOException e) {
LOG.error("Cannot transform document", e);
- throw new NetconfDocumentedException("Cannot transform document" + e);
+ throw new DocumentedException("Cannot transform document" + e);
}
XmlElement filter = maybeFilter.get();
if ("subtree".equals(filter.getAttribute("type"))||
return rpcReply; // return identical document
}
- private static Document filtered(XmlElement filter, Document originalReplyDocument) throws NetconfDocumentedException {
+ private static Document filtered(XmlElement filter, Document originalReplyDocument) throws DocumentedException {
Document result = XmlUtil.newDocument();
// even if filter is empty, copy /rpc/data
Element rpcReply = originalReplyDocument.getDocumentElement();
Node rpcReplyDst = result.importNode(rpcReply, false);
result.appendChild(rpcReplyDst);
- XmlElement dataSrc = XmlElement.fromDomElement(rpcReply).getOnlyChildElement("data", XmlNetconfConstants.RFC4741_TARGET_NAMESPACE);
+ XmlElement dataSrc = XmlElement.fromDomElement(rpcReply).getOnlyChildElement("data", XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
Element dataDst = (Element) result.importNode(dataSrc.getDomElement(), false);
rpcReplyDst.appendChild(dataDst);
addSubtree(filter, dataSrc, XmlElement.fromDomElement(dataDst));
return result;
}
- private static void addSubtree(XmlElement filter, XmlElement src, XmlElement dst) throws NetconfDocumentedException {
+ private static void addSubtree(XmlElement filter, XmlElement src, XmlElement dst) throws DocumentedException {
for (XmlElement srcChild : src.getChildElements()) {
for (XmlElement filterChild : filter.getChildElements()) {
addSubtree2(filterChild, srcChild, dst);
}
}
- private static MatchingResult addSubtree2(XmlElement filter, XmlElement src, XmlElement dstParent) throws NetconfDocumentedException {
+ private static MatchingResult addSubtree2(XmlElement filter, XmlElement src, XmlElement dstParent) throws DocumentedException {
Document document = dstParent.getDomElement().getOwnerDocument();
MatchingResult matches = matches(src, filter);
if (matches != MatchingResult.NO_MATCH && matches != MatchingResult.CONTENT_MISMATCH) {
* Shallow compare src node to filter: tag name and namespace must match.
* If filter node has no children and has text content, it also must match.
*/
- private static MatchingResult matches(XmlElement src, XmlElement filter) throws NetconfDocumentedException {
+ private static MatchingResult matches(XmlElement src, XmlElement filter) throws DocumentedException {
boolean tagMatch = src.getName().equals(filter.getName()) &&
src.getNamespaceOptionally().equals(filter.getNamespaceOptionally());
MatchingResult result = null;
return result;
}
- private static boolean prefixedContentMatches(final XmlElement filter, final XmlElement src) throws NetconfDocumentedException {
+ private static boolean prefixedContentMatches(final XmlElement filter, final XmlElement src) throws DocumentedException {
final Map.Entry<String, String> prefixToNamespaceOfFilter;
final Map.Entry<String, String> prefixToNamespaceOfSrc;
try {
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import java.util.Collections;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.impl.NetconfServerSession;
import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
*/
@Override
protected Element handleWithNoSubsequentOperations(Document document, XmlElement operationElement)
- throws NetconfDocumentedException {
+ throws DocumentedException {
try {
sessionResources.close();
Preconditions.checkNotNull(session, "Session was not set").delayedClose();
LOG.info("Session {} closing", session.getSessionId());
} catch (Exception e) {
- throw new NetconfDocumentedException("Unable to properly close session "
- + getNetconfSessionIdForReporting(), NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_failed,
- NetconfDocumentedException.ErrorSeverity.error, Collections.singletonMap(
- NetconfDocumentedException.ErrorSeverity.error.toString(), e.getMessage()));
+ throw new DocumentedException("Unable to properly close session "
+ + getNetconfSessionIdForReporting(), DocumentedException.ErrorType.application,
+ DocumentedException.ErrorTag.operation_failed,
+ DocumentedException.ErrorSeverity.error, Collections.singletonMap(
+ DocumentedException.ErrorSeverity.error.toString(), e.getMessage()));
}
return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.impl.mapping.operations;
-
-import com.google.common.base.Function;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.Sets;
-import java.io.InputStream;
-import java.util.Set;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
-import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.impl.CommitNotifier;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouter;
-import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
-import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-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.netconf.monitoring.rev101004.netconf.state.Capabilities;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-public class DefaultCommit extends AbstractNetconfOperation {
-
- private static final Logger LOG = LoggerFactory.getLogger(DefaultCommit.class);
-
- private static final String NOTIFY_ATTR = "notify";
-
- //TODO make commit notification optional
- private final CommitNotifier notificationProducer;
- private final NetconfMonitoringService cap;
- private final NetconfOperationRouter operationRouter;
-
- public DefaultCommit(final CommitNotifier notifier, final NetconfMonitoringService cap,
- final String netconfSessionIdForReporting, final NetconfOperationRouter netconfOperationRouter) {
- super(netconfSessionIdForReporting);
- this.notificationProducer = notifier;
- this.cap = cap;
- this.operationRouter = netconfOperationRouter;
- this.getConfigMessage = loadGetConfigMessage();
- }
-
- private final Document getConfigMessage;
- public static final String GET_CONFIG_CANDIDATE_XML_LOCATION = "/getConfig_candidate.xml";
-
- private static Document loadGetConfigMessage() {
- try (InputStream asStream = DefaultCommit.class.getResourceAsStream(GET_CONFIG_CANDIDATE_XML_LOCATION)) {
- return XmlUtil.readXmlToDocument(asStream);
- } catch (Exception e) {
- throw new IllegalStateException("Unable to load getConfig message for notifications from "
- + GET_CONFIG_CANDIDATE_XML_LOCATION);
- }
- }
-
- @Override
- protected String getOperationName() {
- return XmlNetconfConstants.COMMIT;
- }
-
- @Override
- public Document handle(final Document requestMessage, final NetconfOperationChainedExecution subsequentOperation) throws NetconfDocumentedException {
- Preconditions.checkArgument(!subsequentOperation.isExecutionTermination(),
- "Subsequent netconf operation expected by %s", this);
-
- if (isCommitWithoutNotification(requestMessage)) {
- LOG.debug("Skipping commit notification");
- } else {
- // Send commit notification if commit was not issued by persister
- removePersisterAttributes(requestMessage);
- Element cfgSnapshot = getConfigSnapshot(operationRouter);
- LOG.debug("Config snapshot retrieved successfully {}", cfgSnapshot);
- notificationProducer.sendCommitNotification("ok", cfgSnapshot, transformCapabilities(cap.getCapabilities()));
- }
-
- return subsequentOperation.execute(requestMessage);
- }
-
- // FIXME move somewhere to util since this is required also by negotiatiorFactory
- public static Set<String> transformCapabilities(final Capabilities capabilities) {
- return Sets.newHashSet(Collections2.transform(capabilities.getCapability(), new Function<Uri, String>() {
- @Override
- public String apply(final Uri uri) {
- return uri.getValue();
- }
- }));
- }
-
- @Override
- protected Element handle(final Document document, final XmlElement message, final NetconfOperationChainedExecution subsequentOperation) throws NetconfDocumentedException {
- throw new UnsupportedOperationException("Never gets called");
- }
-
- @Override
- protected HandlingPriority getHandlingPriority() {
- return HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY.increasePriority(1);
- }
-
- private static void removePersisterAttributes(final Document message) {
- message.getDocumentElement().removeAttribute(NOTIFY_ATTR);
- }
-
- private static boolean isCommitWithoutNotification(final Document message) {
- XmlElement xmlElement = null;
- try {
- xmlElement = XmlElement.fromDomElementWithExpected(message.getDocumentElement(),
- XmlNetconfConstants.RPC_KEY, XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
- } catch (NetconfDocumentedException e) {
- LOG.trace("Commit operation is not valid due to ",e);
- return false;
- }
-
- String attr = xmlElement.getAttribute(NOTIFY_ATTR);
-
- if (attr == null || attr.equals("")){
- return false;
- } else if (attr.equals(Boolean.toString(false))) {
- LOG.debug("Commit operation received with notify=false attribute {}", message);
- return true;
- } else {
- return false;
- }
- }
-
- private Element getConfigSnapshot(final NetconfOperationRouter opRouter) throws NetconfDocumentedException {
- final Document responseDocument = opRouter.onNetconfMessage(
- getConfigMessage, null);
-
- XmlElement dataElement;
- XmlElement xmlElement = XmlElement.fromDomElementWithExpected(responseDocument.getDocumentElement(),
- XmlNetconfConstants.RPC_REPLY_KEY, XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
- dataElement = xmlElement.getOnlyChildElement(XmlNetconfConstants.DATA_KEY);
- return dataElement.getDomElement();
- }
-
-}
*/
package org.opendaylight.controller.netconf.impl.mapping.operations;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorSeverity;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorTag;
+import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorType;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.impl.NetconfServerSession;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
+
public class DefaultStartExi extends AbstractSingletonNetconfOperation implements DefaultNetconfOperation {
public static final String START_EXI = "start-exi";
@Override
public Document handle(final Document message,
- final NetconfOperationChainedExecution subsequentOperation) throws NetconfDocumentedException {
+ final NetconfOperationChainedExecution subsequentOperation) throws DocumentedException {
if (LOG.isDebugEnabled()) {
LOG.debug("Received start-exi message {} ", XmlUtil.toString(message));
}
try {
netconfSession.startExiCommunication(new NetconfMessage(message));
} catch (IllegalArgumentException e) {
- throw new NetconfDocumentedException("Failed to parse EXI parameters", ErrorType.protocol,
+ throw new DocumentedException("Failed to parse EXI parameters", ErrorType.protocol,
ErrorTag.operation_failed, ErrorSeverity.error);
}
}
@Override
- protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws DocumentedException {
Element getSchemaResult = document.createElementNS( XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, XmlNetconfConstants.OK);
LOG.trace("{} operation successful", START_EXI);
return getSchemaResult;
*/
package org.opendaylight.controller.netconf.impl.mapping.operations;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.impl.NetconfServerSession;
import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
}
@Override
- protected Element handleWithNoSubsequentOperations(Document document, XmlElement operationElement) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(Document document, XmlElement operationElement) throws DocumentedException {
LOG.debug("Received stop-exi message {} ", XmlUtil.toString(operationElement));
netconfSession.stopExiCommunication();
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
-import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.config.util.capability.Capability;
import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactoryListener;
import org.opendaylight.controller.netconf.util.CloseableUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* NetconfOperationService aggregator. Makes a collection of operation services accessible as one.
*/
public class AggregatedNetconfOperationServiceFactory implements NetconfOperationServiceFactory, NetconfOperationServiceFactoryListener, AutoCloseable {
+ private static final Logger LOG = LoggerFactory.getLogger(AggregatedNetconfOperationServiceFactory.class);
+
private final Set<NetconfOperationServiceFactory> factories = new HashSet<>();
private final Multimap<NetconfOperationServiceFactory, AutoCloseable> registrations = HashMultimap.create();
private final Set<CapabilityListener> listeners = Sets.newHashSet();
try {
autoCloseable.close();
} catch (Exception e) {
- // FIXME Issue warning
+ LOG.warn("Unable to close listener registration", e);
}
}
import io.netty.channel.local.LocalAddress;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.HashedWheelTimer;
-import java.lang.management.ManagementFactory;
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.NetconfServerDispatcherImpl;
import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
import org.opendaylight.controller.netconf.impl.SessionIdProvider;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactoryListener;
+import org.opendaylight.controller.netconf.notifications.BaseNotificationPublisherRegistration;
+import org.opendaylight.controller.netconf.notifications.NetconfNotificationCollector;
import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger LOG = LoggerFactory.getLogger(NetconfImplActivator.class);
private NetconfOperationServiceFactoryTracker factoriesTracker;
- private DefaultCommitNotificationProducer commitNot;
private NioEventLoopGroup eventLoopGroup;
private HashedWheelTimer timer;
private ServiceRegistration<NetconfMonitoringService> regMonitoring;
+ private BaseNotificationPublisherRegistration listenerReg;
+
@Override
public void start(final BundleContext context) {
-
- AggregatedNetconfOperationServiceFactory factoriesListener = new AggregatedNetconfOperationServiceFactory();
- startOperationServiceFactoryTracker(context, factoriesListener);
-
- SessionIdProvider idProvider = new SessionIdProvider();
- timer = new HashedWheelTimer();
- long connectionTimeoutMillis = NetconfConfigUtil.extractTimeoutMillis(context);
-
-
- commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
-
- NetconfMonitoringService monitoringService = startMonitoringService(context, factoriesListener);
-
- NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
- timer, factoriesListener, idProvider, connectionTimeoutMillis, commitNot, monitoringService);
-
- eventLoopGroup = new NioEventLoopGroup();
-
- NetconfServerDispatcherImpl.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcherImpl.ServerChannelInitializer(
- serverNegotiatorFactory);
- NetconfServerDispatcherImpl dispatch = new NetconfServerDispatcherImpl(serverChannelInitializer, eventLoopGroup, eventLoopGroup);
-
- LocalAddress address = NetconfConfigUtil.getNetconfLocalAddress();
- LOG.trace("Starting local netconf server at {}", address);
- dispatch.createLocalServer(address);
+ try {
+ AggregatedNetconfOperationServiceFactory factoriesListener = new AggregatedNetconfOperationServiceFactory();
+ startOperationServiceFactoryTracker(context, factoriesListener);
+
+ SessionIdProvider idProvider = new SessionIdProvider();
+ timer = new HashedWheelTimer();
+ long connectionTimeoutMillis = NetconfConfigUtil.extractTimeoutMillis(context);
+
+ final NetconfMonitoringServiceImpl monitoringService = startMonitoringService(context, factoriesListener);
+
+ NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
+ timer, factoriesListener, idProvider, connectionTimeoutMillis, monitoringService);
+
+ eventLoopGroup = new NioEventLoopGroup();
+
+ NetconfServerDispatcherImpl.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcherImpl.ServerChannelInitializer(
+ serverNegotiatorFactory);
+ NetconfServerDispatcherImpl dispatch = new NetconfServerDispatcherImpl(serverChannelInitializer, eventLoopGroup, eventLoopGroup);
+
+ LocalAddress address = NetconfConfigUtil.getNetconfLocalAddress();
+ LOG.trace("Starting local netconf server at {}", address);
+ dispatch.createLocalServer(address);
+
+ final ServiceTracker<NetconfNotificationCollector, NetconfNotificationCollector> notificationServiceTracker =
+ new ServiceTracker<>(context, NetconfNotificationCollector.class, new ServiceTrackerCustomizer<NetconfNotificationCollector, NetconfNotificationCollector>() {
+ @Override
+ public NetconfNotificationCollector addingService(ServiceReference<NetconfNotificationCollector> reference) {
+ listenerReg = context.getService(reference).registerBaseNotificationPublisher();
+ monitoringService.setNotificationPublisher(listenerReg);
+ return null;
+ }
+
+ @Override
+ public void modifiedService(ServiceReference<NetconfNotificationCollector> reference, NetconfNotificationCollector service) {
+
+ }
+
+ @Override
+ public void removedService(ServiceReference<NetconfNotificationCollector> reference, NetconfNotificationCollector service) {
+ listenerReg.close();
+ listenerReg = null;
+ monitoringService.setNotificationPublisher(listenerReg);
+ }
+ });
+ notificationServiceTracker.open();
+ } catch (Exception e) {
+ LOG.warn("Unable to start NetconfImplActivator", e);
+ }
}
private void startOperationServiceFactoryTracker(BundleContext context, NetconfOperationServiceFactoryListener factoriesListener) {
public void stop(final BundleContext context) {
LOG.info("Shutting down netconf because YangStoreService service was removed");
- commitNot.close();
eventLoopGroup.shutdownGracefully(0, 1, TimeUnit.SECONDS);
timer.stop();
import io.netty.util.internal.ConcurrentSet;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.Nonnull;
-import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.config.util.capability.BasicCapability;
+import org.opendaylight.controller.config.util.capability.Capability;
import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+import org.opendaylight.controller.netconf.notifications.BaseNotificationPublisherRegistration;
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.netconf.monitoring.rev101004.NetconfState;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfStateBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.SchemaBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.SchemaKey;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChange;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChangeBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.changed.by.parms.ChangedByBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.changed.by.parms.changed.by.server.or.user.ServerBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private final Map<Uri, Capability> capabilities = new ConcurrentHashMap<>();
private final Set<MonitoringListener> listeners = Sets.newHashSet();
+ private volatile BaseNotificationPublisherRegistration notificationPublisher;
public NetconfMonitoringServiceImpl(final NetconfOperationServiceFactory netconfOperationProvider) {
this.netconfOperationProvider = netconfOperationProvider;
return b.build();
}
+ public static Set<Capability> setupCapabilities(final Set<Capability> caps) {
+ Set<Capability> capabilities = new HashSet<>(caps);
+ capabilities.add(new BasicCapability("urn:ietf:params:netconf:capability:candidate:1.0"));
+ // TODO rollback on error not supported EditConfigXmlParser:100
+ // [RFC6241] 8.5. Rollback-on-Error Capability
+ // capabilities.add(new BasicCapability("urn:ietf:params:netconf:capability:rollback-on-error:1.0"));
+ return capabilities;
+ }
+
@Override
- public synchronized void onCapabilitiesAdded(final Set<Capability> addedCaps) {
- // FIXME howto check for duplicates
- this.capabilities.putAll(Maps.uniqueIndex(addedCaps, CAPABILITY_TO_URI));
+ public synchronized void close() throws Exception {
+ listeners.clear();
+ sessions.clear();
+ capabilities.clear();
+ }
+
+ @Override
+ public void onCapabilitiesChanged(Set<Capability> added, Set<Capability> removed) {
+ onCapabilitiesAdded(added);
+ onCapabilitiesRemoved(removed);
notifyListeners();
+
+ // publish notification to notification collector about changed capabilities
+ if (notificationPublisher != null) {
+ notificationPublisher.onCapabilityChanged(computeDiff(added, removed));
+ }
+ }
+
+ static NetconfCapabilityChange computeDiff(final Set<Capability> removed, final Set<Capability> added) {
+ final NetconfCapabilityChangeBuilder netconfCapabilityChangeBuilder = new NetconfCapabilityChangeBuilder();
+ netconfCapabilityChangeBuilder.setChangedBy(new ChangedByBuilder().setServerOrUser(new ServerBuilder().setServer(true).build()).build());
+ netconfCapabilityChangeBuilder.setDeletedCapability(Lists.newArrayList(Collections2.transform(removed, CAPABILITY_TO_URI)));
+ netconfCapabilityChangeBuilder.setAddedCapability(Lists.newArrayList(Collections2.transform(added, CAPABILITY_TO_URI)));
+ // TODO modified should be computed ... but why ?
+ netconfCapabilityChangeBuilder.setModifiedCapability(Collections.<Uri>emptyList());
+ return netconfCapabilityChangeBuilder.build();
+ }
+
+
+ private synchronized void onCapabilitiesAdded(final Set<Capability> addedCaps) {
+ // FIXME howto check for duplicates
+ this.capabilities.putAll(Maps.uniqueIndex(setupCapabilities(addedCaps), CAPABILITY_TO_URI));
}
private void notifyListeners() {
}
}
- @Override
- public synchronized void onCapabilitiesRemoved(final Set<Capability> addedCaps) {
+ private synchronized void onCapabilitiesRemoved(final Set<Capability> addedCaps) {
for (final Capability addedCap : addedCaps) {
- capabilities.remove(addedCap.getCapabilityUri());
+ capabilities.remove(CAPABILITY_TO_URI.apply(addedCap));
}
- notifyListeners();
}
- @Override
- public synchronized void close() throws Exception {
- listeners.clear();
- sessions.clear();
- capabilities.clear();
+ public void setNotificationPublisher(final BaseNotificationPublisherRegistration notificationPublisher) {
+ this.notificationPublisher = notificationPublisher;
}
}
package org.opendaylight.controller.netconf.impl.osgi;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
import org.opendaylight.controller.netconf.impl.NetconfServerSession;
import org.w3c.dom.Document;
public interface NetconfOperationRouter extends AutoCloseable {
Document onNetconfMessage(Document message, NetconfServerSession session)
- throws NetconfDocumentedException;
+ throws DocumentedException;
}
import java.util.NavigableMap;
import java.util.Set;
import java.util.TreeMap;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
-import org.opendaylight.controller.netconf.impl.CommitNotifier;
import org.opendaylight.controller.netconf.impl.NetconfServerSession;
import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCloseSession;
-import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCommit;
import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultNetconfOperation;
import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultStartExi;
import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultStopExi;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import org.opendaylight.controller.netconf.mapping.api.SessionAwareNetconfOperation;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
private final Collection<NetconfOperation> allNetconfOperations;
public NetconfOperationRouterImpl(final NetconfOperationService netconfOperationServiceSnapshot,
- final CommitNotifier commitNotifier, final NetconfMonitoringService netconfMonitoringService, final String sessionId) {
+ final NetconfMonitoringService netconfMonitoringService, final String sessionId) {
this.netconfOperationServiceSnapshot = Preconditions.checkNotNull(netconfOperationServiceSnapshot);
final Set<NetconfOperation> ops = new HashSet<>();
ops.add(new DefaultCloseSession(sessionId, this));
ops.add(new DefaultStartExi(sessionId));
ops.add(new DefaultStopExi(sessionId));
- ops.add(new DefaultCommit(commitNotifier, netconfMonitoringService, sessionId, this));
ops.addAll(netconfOperationServiceSnapshot.getNetconfOperations());
}
@Override
- public Document onNetconfMessage(final Document message, final NetconfServerSession session) throws NetconfDocumentedException {
+ public Document onNetconfMessage(final Document message, final NetconfServerSession session) throws DocumentedException {
Preconditions.checkNotNull(allNetconfOperations, "Operation router was not initialized properly");
final NetconfOperationExecution netconfOperationExecution;
final String messageAsString = XmlUtil.toString(message);
LOG.warn("Unable to handle rpc {} on session {}", messageAsString, session, e);
- final NetconfDocumentedException.ErrorTag tag;
+ final DocumentedException.ErrorTag tag;
if (e instanceof IllegalArgumentException) {
- tag = NetconfDocumentedException.ErrorTag.operation_not_supported;
+ tag = DocumentedException.ErrorTag.operation_not_supported;
} else {
- tag = NetconfDocumentedException.ErrorTag.operation_failed;
+ tag = DocumentedException.ErrorTag.operation_failed;
}
- throw new NetconfDocumentedException(
+ throw new DocumentedException(
String.format("Unable to handle rpc %s on session %s", messageAsString, session),
- e, NetconfDocumentedException.ErrorType.application,
- tag, NetconfDocumentedException.ErrorSeverity.error,
+ e, DocumentedException.ErrorType.application,
+ tag, DocumentedException.ErrorSeverity.error,
Collections.singletonMap(tag.toString(), e.getMessage()));
} catch (RuntimeException e) {
throw handleUnexpectedEx("Unexpected exception during netconf operation sort", e);
netconfOperationServiceSnapshot.close();
}
- private static NetconfDocumentedException handleUnexpectedEx(final String s, final Exception e) throws NetconfDocumentedException {
+ private static DocumentedException handleUnexpectedEx(final String s, final Exception e) throws DocumentedException {
LOG.error("{}", s, e);
- return new NetconfDocumentedException("Unexpected error",
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_failed,
- NetconfDocumentedException.ErrorSeverity.error,
- Collections.singletonMap(NetconfDocumentedException.ErrorSeverity.error.toString(), e.toString()));
+ return new DocumentedException("Unexpected error",
+ DocumentedException.ErrorType.application,
+ DocumentedException.ErrorTag.operation_failed,
+ DocumentedException.ErrorSeverity.error,
+ Collections.singletonMap(DocumentedException.ErrorSeverity.error.toString(), e.toString()));
}
private Document executeOperationWithHighestPriority(final Document message,
final NetconfOperationExecution netconfOperationExecution)
- throws NetconfDocumentedException {
+ throws DocumentedException {
if (LOG.isDebugEnabled()) {
LOG.debug("Forwarding netconf message {} to {}", XmlUtil.toString(message), netconfOperationExecution.netconfOperation);
}
}
private NetconfOperationExecution getNetconfOperationWithHighestPriority(
- final Document message, final NetconfServerSession session) throws NetconfDocumentedException {
+ final Document message, final NetconfServerSession session) throws DocumentedException {
NavigableMap<HandlingPriority, NetconfOperation> sortedByPriority = getSortedNetconfOperationsWithCanHandle(
message, session);
}
private TreeMap<HandlingPriority, NetconfOperation> getSortedNetconfOperationsWithCanHandle(final Document message,
- final NetconfServerSession session) throws NetconfDocumentedException {
+ final NetconfServerSession session) throws DocumentedException {
TreeMap<HandlingPriority, NetconfOperation> sortedPriority = Maps.newTreeMap();
for (NetconfOperation netconfOperation : allNetconfOperations) {
}
@Override
- public Document execute(final Document requestMessage) throws NetconfDocumentedException {
- throw new NetconfDocumentedException("This execution represents the termination point in operation execution and cannot be executed itself",
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_failed,
- NetconfDocumentedException.ErrorSeverity.error);
+ public Document execute(final Document requestMessage) throws DocumentedException {
+ throw new DocumentedException("This execution represents the termination point in operation execution and cannot be executed itself",
+ DocumentedException.ErrorType.application,
+ DocumentedException.ErrorTag.operation_failed,
+ DocumentedException.ErrorSeverity.error);
}
};
}
@Override
- public Document execute(final Document message) throws NetconfDocumentedException {
+ public Document execute(final Document message) throws DocumentedException {
return netconfOperation.handle(message, subsequentExecution);
}
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import java.util.Map;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
import org.opendaylight.controller.netconf.util.messages.SendErrorExceptionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Map<String, String> info = Maps.newHashMap();
info.put("cause", cause.getMessage());
- NetconfDocumentedException ex = new NetconfDocumentedException(cause.getMessage(),
- NetconfDocumentedException.ErrorType.rpc, NetconfDocumentedException.ErrorTag.malformed_message,
- NetconfDocumentedException.ErrorSeverity.error, info);
+ DocumentedException ex = new DocumentedException(cause.getMessage(),
+ DocumentedException.ErrorType.rpc, DocumentedException.ErrorTag.malformed_message,
+ DocumentedException.ErrorSeverity.error, info);
SendErrorExceptionUtil.sendErrorMessage(ctx.channel(), ex);
}
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
-import java.lang.management.ManagementFactory;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Arrays;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
-import org.opendaylight.controller.netconf.api.Capability;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.capability.Capability;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.protocol.framework.NeverReconnectStrategy;
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.netconf.monitoring.rev101004.netconf.state.CapabilitiesBuilder;
private EventLoopGroup nettyGroup;
private NetconfClientDispatcher netconfClientDispatcher;
- private DefaultCommitNotificationProducer commitNot;
-
HashedWheelTimer hashedWheelTimer;
private TestingNetconfOperation testingNetconfOperation;
}
}).when(monitoring).registerListener(any(NetconfMonitoringService.MonitoringListener.class));
- doNothing().when(monitoring).onCapabilitiesAdded(anySetOf(Capability.class));
- doNothing().when(monitoring).onCapabilitiesRemoved(anySetOf(Capability.class));
+ doNothing().when(monitoring).onCapabilitiesChanged(anySetOf(Capability.class), anySetOf(Capability.class));
doReturn(new CapabilitiesBuilder().setCapability(Collections.<Uri>emptyList()).build()).when(monitoring).getCapabilities();
return monitoring;
}
SessionIdProvider idProvider = new SessionIdProvider();
NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
- hashedWheelTimer, factoriesListener, idProvider, 5000, commitNot, createMockedMonitoringService(), serverCaps);
-
- commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
+ hashedWheelTimer, factoriesListener, idProvider, 5000, createMockedMonitoringService(), serverCaps);
NetconfServerDispatcherImpl.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcherImpl.ServerChannelInitializer(serverNegotiatorFactory);
final NetconfServerDispatcherImpl dispatch = new NetconfServerDispatcherImpl(serverChannelInitializer, nettyGroup, nettyGroup);
@After
public void tearDown(){
- commitNot.close();
hashedWheelTimer.stop();
try {
nettyGroup.shutdownGracefully().get();
}
@Override
- public Document handle(Document requestMessage, NetconfOperationChainedExecution subsequentOperation) throws NetconfDocumentedException {
+ public Document handle(Document requestMessage, NetconfOperationChainedExecution subsequentOperation) throws DocumentedException {
try {
LOG.info("Handling netconf message from test {}", XmlUtil.toString(requestMessage));
counter.getAndIncrement();
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.HashedWheelTimer;
-import java.lang.management.ManagementFactory;
import java.net.InetSocketAddress;
import org.junit.After;
import org.junit.Before;
private EventLoopGroup nettyGroup;
private NetconfServerDispatcherImpl dispatch;
- private DefaultCommitNotificationProducer commitNot;
private HashedWheelTimer hashedWheelTimer;
public void setUp() throws Exception {
nettyGroup = new NioEventLoopGroup();
- commitNot = new DefaultCommitNotificationProducer(
- ManagementFactory.getPlatformMBeanServer());
AggregatedNetconfOperationServiceFactory factoriesListener = new AggregatedNetconfOperationServiceFactory();
SessionIdProvider idProvider = new SessionIdProvider();
hashedWheelTimer = new HashedWheelTimer();
NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
- hashedWheelTimer, factoriesListener, idProvider, 5000, commitNot, ConcurrentClientsTest.createMockedMonitoringService());
+ hashedWheelTimer, factoriesListener, idProvider, 5000, ConcurrentClientsTest.createMockedMonitoringService());
NetconfServerDispatcherImpl.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcherImpl.ServerChannelInitializer(serverNegotiatorFactory);
@After
public void tearDown() throws Exception {
hashedWheelTimer.stop();
- commitNot.close();
nettyGroup.shutdownGracefully();
}
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
+
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.util.concurrent.GenericFutureListener;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
import org.opendaylight.controller.netconf.impl.NetconfServerSession;
import org.opendaylight.controller.netconf.impl.NetconfServerSessionListener;
import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
public class DefaultCloseSessionTest {
verify(listener).onSessionTerminated(any(NetconfServerSession.class), any(NetconfTerminationReason.class));
}
- @Test(expected = NetconfDocumentedException.class)
+ @Test(expected = DocumentedException.class)
public void testDefaultCloseSession2() throws Exception {
AutoCloseable res = mock(AutoCloseable.class);
doThrow(NetconfDocumentedException.class).when(res).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.netconf.impl.mapping.operations;
-
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anySetOf;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import java.util.Collections;
-import org.junit.Before;
-import org.junit.Test;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
-import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
-import org.opendaylight.controller.netconf.impl.NetconfServerSession;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouter;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
-import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-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.netconf.monitoring.rev101004.netconf.state.CapabilitiesBuilder;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-public class DefaultCommitTest {
-
- private NetconfOperationChainedExecution operation;
- private Document requestMessage;
- private NetconfOperationRouter router;
- private DefaultCommitNotificationProducer notifier;
- private NetconfMonitoringService cap;
- private DefaultCommit commit;
-
- @Before
- public void setUp() throws Exception {
- operation = mock(NetconfOperationChainedExecution.class);
- doReturn(XmlUtil.newDocument()).when(operation).execute(any(Document.class));
- router = mock(NetconfOperationRouter.class);
- doReturn(false).when(operation).isExecutionTermination();
- notifier = mock(DefaultCommitNotificationProducer.class);
- doNothing().when(notifier).sendCommitNotification(anyString(), any(Element.class), anySetOf(String.class));
- cap = mock(NetconfMonitoringService.class);
- doReturn(new CapabilitiesBuilder().setCapability(Collections.<Uri>emptyList()).build()).when(cap).getCapabilities();
- Document rpcData = XmlFileLoader.xmlFileToDocument("netconfMessages/editConfig_expectedResult.xml");
- doReturn(rpcData).when(router).onNetconfMessage(any(Document.class), any(NetconfServerSession.class));
- commit = new DefaultCommit(notifier, cap, "", router);
- }
-
- @Test
- public void testHandleWithNotification() throws Exception {
- requestMessage = XmlFileLoader.xmlFileToDocument("netconfMessages/commit.xml");
- commit.handle(requestMessage, operation);
- verify(operation, times(1)).execute(requestMessage);
- verify(notifier, times(1)).sendCommitNotification(anyString(), any(Element.class), anySetOf(String.class));
- }
-
- @Test
- public void testHandleWithoutNotification() throws Exception {
- requestMessage = XmlFileLoader.xmlFileToDocument("netconfMessages/commit.xml");
- Element elem = requestMessage.getDocumentElement();
- elem.setAttribute("notify", "false");
- commit.handle(requestMessage, operation);
- verify(operation, times(1)).execute(requestMessage);
- verify(notifier, never()).sendCommitNotification(anyString(), any(Element.class), anySetOf(String.class));
- }
-
- @Test(expected = NetconfDocumentedException.class)
- public void testHandle() throws Exception {
- Document rpcData = XmlFileLoader.xmlFileToDocument("netconfMessages/get.xml");
- doReturn(rpcData).when(router).onNetconfMessage(any(Document.class), any(NetconfServerSession.class));
- requestMessage = XmlFileLoader.xmlFileToDocument("netconfMessages/commit.xml");
- commit.handle(requestMessage, operation);
- }
-}
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelPipeline;
import org.junit.Test;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.impl.NetconfServerSession;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
public class DefaultStopExiTest {
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>object-cache-guava</artifactId>
</dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>mockito-configuration</artifactId>
- </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anySetOf;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.mock;
+
import com.google.common.io.ByteStreams;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import java.util.concurrent.TimeUnit;
import org.junit.After;
import org.junit.Before;
+import org.opendaylight.controller.config.facade.xml.ConfigSubsystemFacadeFactory;
+import org.opendaylight.controller.config.facade.xml.osgi.EnumResolver;
+import org.opendaylight.controller.config.facade.xml.osgi.YangStoreService;
import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.opendaylight.controller.netconf.client.SimpleNetconfClientSessionListener;
import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
import org.opendaylight.controller.netconf.client.conf.NetconfClientConfigurationBuilder;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreService;
-import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
import org.opendaylight.controller.netconf.impl.NetconfServerDispatcherImpl;
import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
import org.opendaylight.controller.netconf.impl.SessionIdProvider;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringActivator;
import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringOperationService;
-import org.opendaylight.controller.netconf.notifications.BaseNetconfNotificationListener;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
import org.opendaylight.protocol.framework.NeverReconnectStrategy;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChange;
+import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
import org.opendaylight.yangtools.yang.binding.BindingMapping;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
-import org.w3c.dom.Element;
public abstract class AbstractNetconfConfigTest extends AbstractConfigTest {
new IdentityTestModuleFactory(),
new MultipleDependenciesModuleFactory() };
+ protected ConfigSubsystemFacadeFactory configSubsystemFacadeFactory;
private EventLoopGroup nettyThreadgroup;
private HashedWheelTimer hashedWheelTimer;
final AggregatedNetconfOperationServiceFactory factoriesListener = new AggregatedNetconfOperationServiceFactory();
final NetconfMonitoringService netconfMonitoringService = getNetconfMonitoringService(factoriesListener);
- factoriesListener.onAddNetconfOperationServiceFactory(new NetconfOperationServiceFactoryImpl(getYangStore()));
+ configSubsystemFacadeFactory = new ConfigSubsystemFacadeFactory(configRegistryClient, configRegistryClient, getYangStore());
+ factoriesListener.onAddNetconfOperationServiceFactory(new NetconfOperationServiceFactoryImpl(configSubsystemFacadeFactory));
factoriesListener.onAddNetconfOperationServiceFactory(new NetconfMonitoringActivator.NetconfMonitoringOperationServiceFactory(new NetconfMonitoringOperationService(netconfMonitoringService)));
for (final NetconfOperationServiceFactory netconfOperationServiceFactory : getAdditionalServiceFactories(factoriesListener)) {
}
private Channel startNetconfTcpServer(final AggregatedNetconfOperationServiceFactory listener, final NetconfMonitoringService monitoring) throws Exception {
- final NetconfServerDispatcherImpl dispatch = createDispatcher(listener, monitoring, getNotificationProducer());
+ final NetconfServerDispatcherImpl dispatch = createDispatcher(listener, monitoring);
final ChannelFuture s;
if(getTcpServerAddress() instanceof LocalAddress) {
return s.channel();
}
- protected DefaultCommitNotificationProducer getNotificationProducer() {
- final DefaultCommitNotificationProducer notificationProducer = mock(DefaultCommitNotificationProducer.class);
- doNothing().when(notificationProducer).close();
- doNothing().when(notificationProducer).sendCommitNotification(anyString(), any(Element.class), anySetOf(String.class));
- return notificationProducer;
- }
-
protected Iterable<NetconfOperationServiceFactory> getAdditionalServiceFactories(final AggregatedNetconfOperationServiceFactory factoriesListener) throws Exception {
return Collections.emptySet();
}
private HardcodedYangStoreService getYangStore() throws IOException {
final Collection<InputStream> yangDependencies = getBasicYangs();
- return new HardcodedYangStoreService(yangDependencies);
+ return new HardcodedYangStoreService(yangDependencies, getBindingRuntimeContext());
}
static Collection<InputStream> getBasicYangs() throws IOException {
}
protected NetconfServerDispatcherImpl createDispatcher(
- final AggregatedNetconfOperationServiceFactory factoriesListener, final NetconfMonitoringService sessionMonitoringService,
- final DefaultCommitNotificationProducer commitNotifier) {
+ final AggregatedNetconfOperationServiceFactory factoriesListener, final NetconfMonitoringService sessionMonitoringService) {
final SessionIdProvider idProvider = new SessionIdProvider();
final NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
- hashedWheelTimer, factoriesListener, idProvider, SERVER_CONNECTION_TIMEOUT_MILLIS, commitNotifier, sessionMonitoringService);
+ hashedWheelTimer, factoriesListener, idProvider, SERVER_CONNECTION_TIMEOUT_MILLIS, sessionMonitoringService);
final NetconfServerDispatcherImpl.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcherImpl.ServerChannelInitializer(
serverNegotiatorFactory);
}
public static final class HardcodedYangStoreService extends YangStoreService {
- public HardcodedYangStoreService(final Collection<? extends InputStream> inputStreams) throws IOException {
+ public HardcodedYangStoreService(final Collection<? extends InputStream> inputStreams, final BindingRuntimeContext bindingRuntimeContext) throws IOException {
super(new SchemaContextProvider() {
@Override
public SchemaContext getSchemaContext() {
return getSchema(inputStreams);
}
- }, new BaseNetconfNotificationListener() {
- @Override
- public void onCapabilityChanged(final NetconfCapabilityChange capabilityChange) {
- // NOOP
- }
});
+
+ refresh(bindingRuntimeContext);
}
private static SchemaContext getSchema(final Collection<? extends InputStream> inputStreams) {
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.opendaylight.controller.config.util.xml.XmlUtil.readXmlToDocument;
import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElementWithName;
import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertElementsCount;
-import static org.opendaylight.controller.netconf.util.xml.XmlUtil.readXmlToDocument;
+import com.google.common.collect.HashBiMap;
import com.google.common.collect.Lists;
import java.io.IOException;
-import java.lang.management.ManagementFactory;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.List;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
+import org.opendaylight.controller.config.api.jmx.notifications.CommitJMXNotification;
+import org.opendaylight.controller.config.api.jmx.notifications.ConfigJMXNotification;
import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
import org.opendaylight.controller.config.persist.api.Persister;
+import org.opendaylight.controller.config.persist.impl.ConfigPersisterNotificationHandler;
import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.api.jmx.CommitJMXNotification;
import org.opendaylight.controller.netconf.client.TestingNetconfClient;
-import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
-import org.opendaylight.controller.netconf.persist.impl.ConfigPersisterNotificationHandler;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.test.types.rev131127.TestIdentity1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.test.types.rev131127.TestIdentity2;
+import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
import org.w3c.dom.Document;
-import org.w3c.dom.Element;
import org.xml.sax.SAXException;
public class NetconfConfigPersisterITTest extends AbstractNetconfConfigTest {
public static final int PORT = 12026;
private static final InetSocketAddress TCP_ADDRESS = new InetSocketAddress(LOOPBACK_ADDRESS, PORT);
-
@Override
protected SocketAddress getTcpServerAddress() {
return TCP_ADDRESS;
}
- @Override
- protected DefaultCommitNotificationProducer getNotificationProducer() {
- return new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
- }
-
@Test
public void testNetconfCommitNotifications() throws Exception {
final VerifyingNotificationListener notificationVerifier = createCommitNotificationListener();
try (TestingNetconfClient persisterClient = new TestingNetconfClient("persister", getClientDispatcher(), getClientConfiguration(TCP_ADDRESS, 4000))) {
try (ConfigPersisterNotificationHandler configPersisterNotificationHandler = new ConfigPersisterNotificationHandler(
- platformMBeanServer, mockedAggregator)) {
+ platformMBeanServer, mockedAggregator, configSubsystemFacadeFactory)) {
try (TestingNetconfClient netconfClient = new TestingNetconfClient("client", getClientDispatcher(), getClientConfiguration(TCP_ADDRESS, 4000))) {
- NetconfMessage response = netconfClient.sendMessage(loadGetConfigMessage());
- assertContainsElementWithName(response.getDocument(), "modules");
- assertContainsElementWithName(response.getDocument(), "services");
- response = netconfClient.sendMessage(loadCommitMessage());
- assertContainsElementWithName(response.getDocument(), "ok");
-
- response = netconfClient.sendMessage(loadEditConfigMessage());
+ NetconfMessage response = netconfClient.sendMessage(loadEditConfigMessage());
assertContainsElementWithName(response.getDocument(), "ok");
response = netconfClient.sendMessage(loadCommitMessage());
assertContainsElementWithName(response.getDocument(), "ok");
+
+ response = netconfClient.sendMessage(loadGetConfigMessage());
+ assertContainsElementWithName(response.getDocument(), "modules");
+ assertContainsElementWithName(response.getDocument(), "services");
}
}
}
- notificationVerifier.assertNotificationCount(2);
- notificationVerifier.assertNotificationContent(0, 0, 0, 8);
- notificationVerifier.assertNotificationContent(1, 4, 3, 8);
+ notificationVerifier.assertNotificationCount(1);
- mockedAggregator.assertSnapshotCount(2);
+ mockedAggregator.assertSnapshotCount(1);
// Capabilities are stripped for persister
- mockedAggregator.assertSnapshotContent(0, 0, 0, 1);
- mockedAggregator.assertSnapshotContent(1, 4, 3, 3);
+ mockedAggregator.assertSnapshotContent(0, 4, 3, 3);
+ }
+
+ @Override
+ protected BindingRuntimeContext getBindingRuntimeContext() {
+ final BindingRuntimeContext ret = super.getBindingRuntimeContext();
+ doReturn(TestIdentity1.class).when(ret).getIdentityClass(TestIdentity1.QNAME);
+ doReturn(TestIdentity2.class).when(ret).getIdentityClass(TestIdentity2.QNAME);
+ final HashBiMap<String, String> toBeReturned = HashBiMap.create();
+ toBeReturned.put("two", "Two");
+ toBeReturned.put("one", "One");
+ toBeReturned.put("version1", "Version1");
+ doReturn(toBeReturned).when(ret).getEnumMapping(anyString());
+ return ret;
}
private VerifyingPersister mockAggregator() throws IOException {
private VerifyingNotificationListener createCommitNotificationListener() throws InstanceNotFoundException {
final VerifyingNotificationListener listener = new VerifyingNotificationListener();
- platformMBeanServer.addNotificationListener(DefaultCommitNotificationProducer.OBJECT_NAME, listener, null, null);
+ platformMBeanServer.addNotificationListener(ConfigJMXNotification.OBJECT_NAME, listener, null, null);
return listener;
}
assertEquals(size, notifications.size());
}
- void assertNotificationContent(final int notificationIndex, final int expectedModulesSize, final int expectedServicesSize, final int expectedCapsSize) {
+ void assertNotificationContent(final int notificationIndex) {
final Notification notification = notifications.get(notificationIndex);
assertEquals(CommitJMXNotification.class, notification.getClass());
- final int capsSize = ((CommitJMXNotification) notification).getCapabilities().size();
- assertEquals("Expected capabilities count", expectedCapsSize, capsSize);
- final Element configSnapshot = ((CommitJMXNotification) notification).getConfigSnapshot();
- final int modulesSize = configSnapshot.getElementsByTagName("module").getLength();
- assertEquals("Expected modules count", expectedModulesSize, modulesSize);
- final int servicesSize = configSnapshot.getElementsByTagName("instance").getLength();
- assertEquals("Expected services count", expectedServicesSize, servicesSize);
}
}
throws SAXException, IOException {
final ConfigSnapshotHolder snapshot = snapshots.get(notificationIndex);
final int capsSize = snapshot.getCapabilities().size();
- assertEquals("Expected capabilities count", expectedCapsSize, capsSize);
+ assertEquals("Expected capabilities count should be " + expectedCapsSize + " but was " + snapshot.getCapabilities(), expectedCapsSize, capsSize);
final Document configSnapshot = readXmlToDocument(snapshot.getConfigSnapshot());
assertElementsCount(configSnapshot, "module", expectedModulesSize);
assertElementsCount(configSnapshot, "instance", expectedServicesSize);
import java.util.List;
import java.util.Set;
import org.junit.Test;
-import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.config.util.capability.Capability;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
import org.opendaylight.controller.netconf.client.TestingNetconfClient;
import org.opendaylight.controller.netconf.impl.osgi.AggregatedNetconfOperationServiceFactory;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
public class NetconfITMonitoringTest extends AbstractNetconfConfigTest {
}
}
-
@Test(timeout = 13 * 10000)
public void testClientHelloWithAuth() throws Exception {
String fileName = "netconfMessages/client_hello_with_auth.xml";
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.auth.AuthProvider;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
import org.opendaylight.controller.netconf.ssh.SshProxyServerConfigurationBuilder;
import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil;
import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.controller.sal.connect.api.RemoteDevice;
import org.opendaylight.controller.sal.connect.netconf.listener.NetconfDeviceCommunicator;
import org.opendaylight.controller.sal.connect.netconf.listener.NetconfSessionPreferences;
import org.junit.Test;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.config.yang.test.impl.DepTestImplModuleFactory;
import org.opendaylight.controller.config.yang.test.impl.MultipleDependenciesModuleFactory;
import org.opendaylight.controller.config.yang.test.impl.MultipleDependenciesModuleMXBean;
import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleFactory;
import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleMXBean;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
import org.opendaylight.controller.netconf.client.TestingNetconfClient;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-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;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.test.types.rev131127.TestIdentity2;
import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
}
}
- private void assertIsOK(final Document rpcReply) throws NetconfDocumentedException {
+ private void assertIsOK(final Document rpcReply) throws DocumentedException {
assertEquals("rpc-reply", rpcReply.getDocumentElement().getLocalName());
assertEquals("ok", XmlElement.fromDomDocument(rpcReply).getOnlyChildElement().getName());
}
- private Document assertGetConfigWorks(final TestingNetconfClient netconfClient) throws InterruptedException, ExecutionException, TimeoutException, NetconfDocumentedException {
+ private Document assertGetConfigWorks(final TestingNetconfClient netconfClient) throws InterruptedException, ExecutionException, TimeoutException, DocumentedException {
return assertGetConfigWorks(netconfClient, getGetConfig());
}
private Document assertGetConfigWorks(final TestingNetconfClient netconfClient, final NetconfMessage getConfigMessage)
- throws InterruptedException, ExecutionException, TimeoutException, NetconfDocumentedException {
+ throws InterruptedException, ExecutionException, TimeoutException, DocumentedException {
final NetconfMessage rpcReply = netconfClient.sendMessage(getConfigMessage);
assertNotNull(rpcReply);
assertEquals("data", XmlElement.fromDomDocument(rpcReply.getDocument()).getOnlyChildElement().getName());
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.netconf.it;
-
-import com.google.common.base.Preconditions;
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.KeyManagementException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateException;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManagerFactory;
-
-public final class SSLUtil {
-
- private SSLUtil() {}
-
- public static SSLContext initializeSecureContext(final String pass, final InputStream ksKeysFile, final InputStream ksTrustFile,
- final String algorithm) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException,
- UnrecoverableKeyException, KeyManagementException {
-
- Preconditions.checkNotNull(ksTrustFile, "ksTrustFile cannot be null");
- Preconditions.checkNotNull(ksKeysFile, "ksKeysFile cannot be null");
-
- final char[] passphrase = pass.toCharArray();
-
- // First initialize the key and trust material.
- final KeyStore ksKeys = KeyStore.getInstance("JKS");
- ksKeys.load(ksKeysFile, passphrase);
- final KeyStore ksTrust = KeyStore.getInstance("JKS");
- ksTrust.load(ksTrustFile, passphrase);
-
- // KeyManager's decide which key material to use.
- final KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
- kmf.init(ksKeys, passphrase);
-
- // TrustManager's decide whether to allow connections.
- final TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
- tmf.init(ksTrust);
-
- final SSLContext sslContext = SSLContext.getInstance("TLS");
-
- // Create/initialize the SSLContext with key material
- sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
- return sslContext;
- }
-
-}
<groupId>${project.groupId}</groupId>
<artifactId>netconf-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-manager-facade-xml</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>com.google.guava</groupId>
<plugin>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-maven-plugin</artifactId>
- <executions>
- <execution>
- <id>config</id>
- <goals>
- <goal>generate-sources</goal>
- </goals>
- <configuration>
- <codeGenerators>
- <generator>
- <codeGeneratorClass>org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator</codeGeneratorClass>
- <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
- <additionalConfiguration>
- <namespaceToPackage1>urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang</namespaceToPackage1>
- </additionalConfiguration>
- </generator>
- <generator>
- <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
- <outputBaseDir>${salGeneratorPath}</outputBaseDir>
- </generator>
- </codeGenerators>
- <inspectDependencies>true</inspectDependencies>
- </configuration>
- </execution>
- </executions>
- <dependencies>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>yang-jmx-generator-plugin</artifactId>
- <version>${config.version}</version>
- </dependency>
- </dependencies>
</plugin>
</plugins>
</build>
package org.opendaylight.controller.netconf.mapping.api;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
import org.w3c.dom.Document;
/**
* @param requestMessage
* @return
*/
- HandlingPriority canHandle(Document message) throws NetconfDocumentedException;
+ HandlingPriority canHandle(Document message) throws DocumentedException;
/**
* Execute current netconf operation and trigger execution of subsequent
* @param subsequentOperation
* execution of subsequent netconf operation
* @return
- * @throws NetconfDocumentedException
+ * @throws DocumentedException
*/
Document handle(Document requestMessage, NetconfOperationChainedExecution subsequentOperation)
- throws NetconfDocumentedException;
+ throws DocumentedException;
}
*/
package org.opendaylight.controller.netconf.mapping.api;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
import org.w3c.dom.Document;
/**
/**
* Do not execute if this is termination point
*/
- Document execute(Document requestMessage) throws NetconfDocumentedException;
+ Document execute(Document requestMessage) throws DocumentedException;
public static final NetconfOperationChainedExecution EXECUTION_TERMINATION_POINT = new NetconfOperationChainedExecution() {
@Override
}
@Override
- public Document execute(Document requestMessage) throws NetconfDocumentedException {
+ public Document execute(Document requestMessage) throws DocumentedException {
throw new IllegalStateException("This execution represents the termination point in operation execution and cannot be executed itself");
}
};
package org.opendaylight.controller.netconf.mapping.api;
import java.util.Set;
-import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.config.util.capability.Capability;
import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
/**
public class HandlingPriorityTest {
- @Test
- public void testHandlingPriority() throws Exception {
-
-
- assertTrue(HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY.compareTo(HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY) == 0);
+ @Test public void testHandlingPriority() throws Exception {
+ assertTrue(
+ HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY.compareTo(HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY)
+ == 0);
assertTrue(HandlingPriority.CANNOT_HANDLE.compareTo(HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY) == -1);
assertTrue(HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY.compareTo(HandlingPriority.CANNOT_HANDLE) == 1);
- assertTrue(HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY.compareTo(HandlingPriority.HANDLE_WITH_MAX_PRIORITY) == -1);
- assertTrue(HandlingPriority.HANDLE_WITH_MAX_PRIORITY.compareTo(HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY) == 1);
- assertTrue(HandlingPriority.getHandlingPriority(Integer.MIN_VALUE).compareTo(HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY) == 0);
+ assertTrue(
+ HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY.compareTo(HandlingPriority.HANDLE_WITH_MAX_PRIORITY) == -1);
+ assertTrue(
+ HandlingPriority.HANDLE_WITH_MAX_PRIORITY.compareTo(HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY) == 1);
+ assertTrue(HandlingPriority.getHandlingPriority(Integer.MIN_VALUE)
+ .compareTo(HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY) == 0);
HandlingPriority prio = HandlingPriority.getHandlingPriority(10);
assertTrue(prio.increasePriority(1).compareTo(HandlingPriority.getHandlingPriority(11)) == 0);
assertFalse(HandlingPriority.CANNOT_HANDLE.getPriority().isPresent());
assertFalse(HandlingPriority.HANDLE_WITH_MAX_PRIORITY.equals(new Object()));
- assertEquals(HandlingPriority.HANDLE_WITH_MAX_PRIORITY, HandlingPriority.getHandlingPriority(Integer.MAX_VALUE));
- assertEquals(HandlingPriority.HANDLE_WITH_MAX_PRIORITY.hashCode(), HandlingPriority.getHandlingPriority(Integer.MAX_VALUE).hashCode());
+ assertEquals(HandlingPriority.HANDLE_WITH_MAX_PRIORITY,
+ HandlingPriority.getHandlingPriority(Integer.MAX_VALUE));
+ assertEquals(HandlingPriority.HANDLE_WITH_MAX_PRIORITY.hashCode(),
+ HandlingPriority.getHandlingPriority(Integer.MAX_VALUE).hashCode());
}
}
package org.opendaylight.controller.netconf.monitoring;
import java.util.Collections;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlMappingConstants;
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.opendaylight.controller.netconf.monitoring.xml.JaxBSerializer;
import org.opendaylight.controller.netconf.monitoring.xml.model.NetconfState;
import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
}
private Element getPlaceholder(final Document innerResult)
- throws NetconfDocumentedException {
+ throws DocumentedException {
final XmlElement rootElement = XmlElement.fromDomElementWithExpected(
- innerResult.getDocumentElement(), XmlNetconfConstants.RPC_REPLY_KEY, XmlNetconfConstants.RFC4741_TARGET_NAMESPACE);
+ innerResult.getDocumentElement(), XmlMappingConstants.RPC_REPLY_KEY, XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
return rootElement.getOnlyChildElement(XmlNetconfConstants.DATA_KEY).getDomElement();
}
@Override
public Document handle(final Document requestMessage, final NetconfOperationChainedExecution subsequentOperation)
- throws NetconfDocumentedException {
+ throws DocumentedException {
if (subsequentOperation.isExecutionTermination()){
- throw new NetconfDocumentedException(String.format("Subsequent netconf operation expected by %s", this),
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_failed,
- NetconfDocumentedException.ErrorSeverity.error);
+ throw new DocumentedException(String.format("Subsequent netconf operation expected by %s", this),
+ DocumentedException.ErrorType.application,
+ DocumentedException.ErrorTag.operation_failed,
+ DocumentedException.ErrorSeverity.error);
}
try {
final String errorMessage = "Get operation for netconf-state subtree failed";
LOG.warn(errorMessage, e);
- throw new NetconfDocumentedException(errorMessage, NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_failed,
- NetconfDocumentedException.ErrorSeverity.error,
- Collections.singletonMap(NetconfDocumentedException.ErrorSeverity.error.toString(), e.getMessage()));
+ throw new DocumentedException(errorMessage, DocumentedException.ErrorType.application,
+ DocumentedException.ErrorTag.operation_failed,
+ DocumentedException.ErrorSeverity.error,
+ Collections.singletonMap(DocumentedException.ErrorSeverity.error.toString(), e.getMessage()));
}
}
@Override
protected Element handle(final Document document, final XmlElement message, final NetconfOperationChainedExecution subsequentOperation)
- throws NetconfDocumentedException {
+ throws DocumentedException {
throw new UnsupportedOperationException("Never gets called");
}
}
import com.google.common.base.Optional;
import com.google.common.collect.Maps;
import java.util.Map;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
}
@Override
- protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement xml) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement xml) throws DocumentedException {
final GetSchemaEntry entry;
entry = new GetSchemaEntry(xml);
} catch (final IllegalStateException e) {
final Map<String, String> errorInfo = Maps.newHashMap();
errorInfo.put(entry.identifier, e.getMessage());
- LOG.warn("Rpc error: {}", NetconfDocumentedException.ErrorTag.operation_failed, e);
- throw new NetconfDocumentedException(e.getMessage(), NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_failed,
- NetconfDocumentedException.ErrorSeverity.error, errorInfo);
+ LOG.warn("Rpc error: {}", DocumentedException.ErrorTag.operation_failed, e);
+ throw new DocumentedException(e.getMessage(), DocumentedException.ErrorType.application,
+ DocumentedException.ErrorTag.operation_failed,
+ DocumentedException.ErrorSeverity.error, errorInfo);
}
final Element getSchemaResult;
private final String identifier;
private final Optional<String> version;
- GetSchemaEntry(final XmlElement getSchemaElement) throws NetconfDocumentedException {
+ GetSchemaEntry(final XmlElement getSchemaElement) throws DocumentedException {
getSchemaElement.checkName(GET_SCHEMA);
getSchemaElement.checkNamespace(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_YANG_IETF_NETCONF_MONITORING);
XmlElement identifierElement = null;
try {
identifierElement = getSchemaElement.getOnlyChildElementWithSameNamespace(IDENTIFIER);
- } catch (final MissingNameSpaceException e) {
+ } catch (final DocumentedException e) {
LOG.trace("Can't get identifier element as only child element with same namespace due to ",e);
- throw NetconfDocumentedException.wrap(e);
+ throw DocumentedException.wrap(e);
}
identifier = identifierElement.getTextContent();
final Optional<XmlElement> versionElement = getSchemaElement
import java.util.Collections;
import java.util.Set;
-import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.config.util.capability.Capability;
import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
import com.google.common.base.Optional;
import org.junit.Before;
import org.junit.Test;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
public class GetSchemaTest {
" </get-schema>";
}
- @Test(expected = NetconfDocumentedException.class)
+ @Test(expected = DocumentedException.class)
public void testDefaultGetSchema() throws Exception {
GetSchema schema = new GetSchema(cap);
doThrow(IllegalStateException.class).when(cap).getSchemaForCapability(anyString(), any(Optional.class));
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
+
import java.util.Collections;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.SchemasBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.SessionsBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.Schema;
public void testHandleNoSubsequent() throws Exception {
try {
get.handle(null, NetconfOperationChainedExecution.EXECUTION_TERMINATION_POINT);
- } catch (final NetconfDocumentedException e) {
- assertNetconfDocumentedEx(e, NetconfDocumentedException.ErrorSeverity.error, NetconfDocumentedException.ErrorTag.operation_failed, NetconfDocumentedException.ErrorType.application);
+ } catch (final DocumentedException e) {
+ assertNetconfDocumentedEx(e, DocumentedException.ErrorSeverity.error, DocumentedException.ErrorTag.operation_failed, DocumentedException.ErrorType.application);
return;
}
doReturn(incorrectSubsequentResult).when(subsequentOperation).execute(request);
try {
get.handle(request, subsequentOperation);
- } catch (final NetconfDocumentedException e) {
- assertNetconfDocumentedEx(e, NetconfDocumentedException.ErrorSeverity.error, NetconfDocumentedException.ErrorTag.invalid_value, NetconfDocumentedException.ErrorType.application);
+ } catch (final DocumentedException e) {
+ assertNetconfDocumentedEx(e, DocumentedException.ErrorSeverity.error, DocumentedException.ErrorTag.invalid_value, DocumentedException.ErrorType.application);
return;
}
doThrow(RuntimeException.class).when(subsequentOperation).execute(request);
try {
get.handle(request, subsequentOperation);
- } catch (final NetconfDocumentedException e) {
- assertNetconfDocumentedEx(e, NetconfDocumentedException.ErrorSeverity.error, NetconfDocumentedException.ErrorTag.operation_failed, NetconfDocumentedException.ErrorType.application);
+ } catch (final DocumentedException e) {
+ assertNetconfDocumentedEx(e, DocumentedException.ErrorSeverity.error, DocumentedException.ErrorTag.operation_failed, DocumentedException.ErrorType.application);
assertEquals(1, e.getErrorInfo().size());
return;
}
}
- private void assertNetconfDocumentedEx(final NetconfDocumentedException e, final NetconfDocumentedException.ErrorSeverity severity, final NetconfDocumentedException.ErrorTag errorTag, final NetconfDocumentedException.ErrorType type) {
+ private void assertNetconfDocumentedEx(final DocumentedException e, final DocumentedException.ErrorSeverity severity, final DocumentedException.ErrorTag errorTag, final DocumentedException.ErrorType type) {
assertEquals(severity, e.getErrorSeverity());
assertEquals(errorTag, e.getErrorTag());
assertEquals(type, e.getErrorType());
import java.util.Set;
import org.hamcrest.CoreMatchers;
import org.junit.Test;
-import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.config.util.capability.Capability;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
import org.opendaylight.controller.netconf.monitoring.xml.model.NetconfState;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.DomainName;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
final NetconfMonitoringService service = new NetconfMonitoringService() {
@Override
- public void onSessionUp(final NetconfManagementSession session) {
-
- }
-
- @Override
- public void onSessionDown(final NetconfManagementSession session) {
+ public void onCapabilitiesChanged(Set<Capability> added, Set<Capability> removed) {
}
@Override
- public void onCapabilitiesAdded(final Set<Capability> addedCaps) {
+ public void onSessionUp(final NetconfManagementSession session) {
}
@Override
- public void onCapabilitiesRemoved(final Set<Capability> addedCaps) {
+ public void onSessionDown(final NetconfManagementSession session) {
}
<groupId>openexi</groupId>
<artifactId>nagasena-rta</artifactId>
</dependency>
- <dependency>
- <groupId>org.osgi</groupId>
- <artifactId>org.osgi.core</artifactId>
- </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
- <Export-Package>org.opendaylight.controller.netconf.nettyutil,
- org.opendaylight.controller.netconf.nettyutil.handler,
- org.opendaylight.controller.netconf.nettyutil.handler.exi,
- org.opendaylight.controller.netconf.nettyutil.handler.ssh,
- org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication,
- org.opendaylight.controller.netconf.nettyutil.handler.ssh.client</Export-Package>
+ <Export-Package>org.opendaylight.controller.netconf.nettyutil.*</Export-Package>
</instructions>
</configuration>
</plugin>
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import java.io.IOException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
import org.opendaylight.controller.netconf.api.NetconfExiSession;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.nettyutil.handler.NetconfEXIToMessageDecoder;
import org.opendaylight.controller.netconf.nettyutil.handler.NetconfMessageToEXIEncoder;
import org.opendaylight.controller.netconf.nettyutil.handler.exi.EXIParameters;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.opendaylight.protocol.framework.AbstractProtocolSession;
import org.openexi.proc.common.EXIOptionsException;
import org.openexi.sax.TransmogrifierException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.List;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import io.netty.handler.codec.ByteToMessageDecoder;
import java.io.IOException;
import java.util.List;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;
package org.opendaylight.controller.netconf.nettyutil.handler.exi;
import com.google.common.base.Preconditions;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlElement;
import org.openexi.proc.common.AlignmentType;
import org.openexi.proc.common.EXIOptions;
import org.openexi.proc.common.EXIOptionsException;
import com.google.common.collect.Lists;
import java.util.List;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.openexi.proc.common.EXIOptions;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+
import com.google.common.collect.Lists;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.custommonkey.xmlunit.XMLUnit;
import org.junit.Before;
import org.junit.Test;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.openexi.proc.common.EXIOptions;
import org.openexi.proc.common.EXIOptionsException;
import org.openexi.sax.Transmogrifier;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
public class NetconfHelloMessageToXMLEncoderTest {
import java.util.List;
import org.hamcrest.CoreMatchers;
import org.junit.Test;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
public class NetconfXMLToHelloMessageDecoderTest {
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.openexi.proc.common.AlignmentType;
import org.openexi.proc.common.EXIOptions;
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-manager-facade-xml</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>ietf-netconf-notifications</artifactId>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
- <configuration>
- <instructions>
- <Export-Package>org.opendaylight.controller.netconf.notifications.*</Export-Package>
- </instructions>
- </configuration>
</plugin>
</plugins>
</build>
/**
* Callback used to notify about a change in used capabilities
*/
- void onCapabilityChanged(NetconfCapabilityChange capabilityChange);
+ void onCapabilityChanged(final NetconfCapabilityChange capabilityChange);
// TODO add other base notifications
/**
* Collector of all notifications. Base or generic
*/
-public interface NetconfNotificationCollector {
+public interface NetconfNotificationCollector {
/**
* Add notification publisher for a particular stream
<configuration>
<instructions>
<Bundle-Activator>org.opendaylight.controller.netconf.notifications.impl.osgi.Activator</Bundle-Activator>
+ <Export-Package>org.opendaylight.controller.netconf.notifications.impl.*</Export-Package>
</instructions>
</configuration>
</plugin>
@Override
public synchronized void onNotification(final StreamNameType stream, final NetconfNotification notification) {
LOG.debug("Notification of type {} detected", stream);
- if(LOG.isTraceEnabled()) {
+ if (LOG.isTraceEnabled()) {
LOG.debug("Notification of type {} detected: {}", stream, notification);
}
return new NotificationRegistration() {
@Override
public void close() {
- synchronized(NetconfNotificationManager.this) {
+ synchronized (NetconfNotificationManager.this) {
streamListeners.remove(listener);
}
}
final StreamNameType streamName = stream.getName();
LOG.debug("Notification publisher registered for stream: {}", streamName);
- if(LOG.isTraceEnabled()) {
+ if (LOG.isTraceEnabled()) {
LOG.trace("Notification publisher registered for stream: {}", stream);
}
- if(streamMetadata.containsKey(streamName)) {
+ if (streamMetadata.containsKey(streamName)) {
LOG.warn("Notification stream {} already registered as: {}. Will be reused", streamName, streamMetadata.get(streamName));
} else {
streamMetadata.put(streamName, stream);
streamListener.onStreamRegistered(stream);
}
}
+
private synchronized void notifyStreamRemoved(final StreamNameType stream) {
for (final NetconfNotificationStreamListener streamListener : streamListeners) {
streamListener.onStreamUnregistered(stream);
baseRegistration.close();
}
+ private static NetconfNotification serializeNotification(final NetconfCapabilityChange capabilityChange) {
+ return NotificationsTransformUtil.transform(capabilityChange);
+ }
+
@Override
public void onCapabilityChanged(final NetconfCapabilityChange capabilityChange) {
baseRegistration.onNotification(BASE_STREAM_NAME, serializeNotification(capabilityChange));
- }
-
- private static NetconfNotification serializeNotification(final NetconfCapabilityChange capabilityChange) {
- return NotificationsTransformUtil.transform(capabilityChange);
+// baseRegistration.onNotification(BASE_STREAM_NAME, serializeNotification(computeDiff(removed, added)));
}
}
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import java.util.List;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.mapping.api.SessionAwareNetconfOperation;
import org.opendaylight.controller.netconf.notifications.NotificationListenerRegistration;
import org.opendaylight.controller.netconf.notifications.impl.NetconfNotificationManager;
import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.CreateSubscriptionInput;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.StreamNameType;
import org.slf4j.Logger;
}
@Override
- protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws DocumentedException {
operationElement.checkName(CREATE_SUBSCRIPTION);
operationElement.checkNamespace(CreateSubscriptionInput.QNAME.getNamespace().toString());
// FIXME reimplement using CODEC_REGISTRY and parse everything into generated class instance
return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
}
- private static StreamNameType parseStreamIfPresent(final XmlElement operationElement) throws NetconfDocumentedException {
+ private static StreamNameType parseStreamIfPresent(final XmlElement operationElement) throws DocumentedException {
final Optional<XmlElement> stream = operationElement.getOnlyChildElementWithSameNamespaceOptionally("stream");
return stream.isPresent() ? new StreamNameType(stream.get().getTextContent()) : NetconfNotificationManager.BASE_STREAM_NAME;
}
import java.io.IOException;
import javax.xml.stream.XMLStreamException;
import javax.xml.transform.dom.DOMResult;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlMappingConstants;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
import org.opendaylight.controller.netconf.notifications.NetconfNotificationRegistry;
import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.Netconf;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.NetconfBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.netconf.Streams;
}
@Override
- public Document handle(final Document requestMessage, final NetconfOperationChainedExecution subsequentOperation) throws NetconfDocumentedException {
+ public Document handle(final Document requestMessage, final NetconfOperationChainedExecution subsequentOperation) throws DocumentedException {
final Document partialResponse = subsequentOperation.execute(requestMessage);
final Streams availableStreams = notificationRegistry.getNotificationPublishers();
if(availableStreams.getStream().isEmpty() == false) {
return partialResponse;
}
- static void serializeStreamsSubtree(final Document partialResponse, final Streams availableStreams) throws NetconfDocumentedException {
+ static void serializeStreamsSubtree(final Document partialResponse, final Streams availableStreams) throws DocumentedException {
final Netconf netconfSubtree = new NetconfBuilder().setStreams(availableStreams).build();
final NormalizedNode<?, ?> normalized = toNormalized(netconfSubtree);
}
private static Element getPlaceholder(final Document innerResult)
- throws NetconfDocumentedException {
+ throws DocumentedException {
final XmlElement rootElement = XmlElement.fromDomElementWithExpected(
- innerResult.getDocumentElement(), XmlNetconfConstants.RPC_REPLY_KEY, XmlNetconfConstants.RFC4741_TARGET_NAMESPACE);
+ innerResult.getDocumentElement(), XmlMappingConstants.RPC_REPLY_KEY, XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
return rootElement.getOnlyChildElement(XmlNetconfConstants.DATA_KEY).getDomElement();
}
@Override
protected Element handle(final Document document, final XmlElement message, final NetconfOperationChainedExecution subsequentOperation)
- throws NetconfDocumentedException {
+ throws DocumentedException {
throw new UnsupportedOperationException("Never gets called");
}
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.dom.DOMResult;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.notifications.NetconfNotification;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.$YangModuleInfoImpl;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChange;
import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.Set;
-import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.config.util.capability.BasicCapability;
+import org.opendaylight.controller.config.util.capability.Capability;
import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
import org.opendaylight.controller.netconf.api.util.NetconfConstants;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
import org.opendaylight.controller.netconf.notifications.impl.NetconfNotificationManager;
import org.opendaylight.controller.netconf.notifications.impl.ops.CreateSubscription;
import org.opendaylight.controller.netconf.notifications.impl.ops.Get;
-import org.opendaylight.controller.netconf.util.capability.BasicCapability;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class Activator implements BundleActivator {
+ private static final Logger LOG = LoggerFactory.getLogger(Activator.class);
+
private ServiceRegistration<NetconfNotificationCollector> netconfNotificationCollectorServiceRegistration;
private ServiceRegistration<NetconfOperationServiceFactory> operationaServiceRegistration;
private NetconfNotificationManager netconfNotificationManager;
@Override
public AutoCloseable registerCapabilityListener(final CapabilityListener listener) {
- listener.onCapabilitiesAdded(capabilities);
+ listener.onCapabilitiesChanged(capabilities, Collections.<Capability>emptySet());
return new AutoCloseable() {
@Override
public void close() {
- listener.onCapabilitiesRemoved(capabilities);
+ listener.onCapabilitiesChanged(Collections.<Capability>emptySet(), capabilities);
}
};
}
private final CreateSubscription createSubscription = new CreateSubscription(netconfSessionIdForReporting, netconfNotificationManager);
-
@Override
public Set<NetconfOperation> getNetconfOperations() {
return Sets.<NetconfOperation>newHashSet(
final Dictionary<String, String> properties = new Hashtable<>();
properties.put(NetconfConstants.SERVICE_NAME, NetconfConstants.NETCONF_MONITORING);
operationaServiceRegistration = context.registerService(NetconfOperationServiceFactory.class, netconfOperationServiceFactory, properties);
-
}
@Override
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.notifications.NetconfNotificationListener;
import org.opendaylight.controller.netconf.notifications.NetconfNotificationRegistry;
import org.opendaylight.controller.netconf.notifications.NotificationListenerRegistration;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.StreamNameType;
import org.w3c.dom.Element;
import com.google.common.collect.Lists;
import java.io.IOException;
import org.junit.Test;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.StreamNameType;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.netconf.Streams;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.netconf.StreamsBuilder;
import org.custommonkey.xmlunit.XMLUnit;
import org.custommonkey.xmlunit.examples.RecursiveElementNameAndTextQualifier;
import org.junit.Test;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.notifications.NetconfNotification;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
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.netconf.notifications.rev120206.NetconfCapabilityChange;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChangeBuilder;
<plugin>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-maven-plugin</artifactId>
- <executions>
- <execution>
- <id>config</id>
- <goals>
- <goal>generate-sources</goal>
- </goals>
- <configuration>
- <codeGenerators>
- <generator>
- <codeGeneratorClass>org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator</codeGeneratorClass>
- <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
- <additionalConfiguration>
- <namespaceToPackage1>urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang</namespaceToPackage1>
- </additionalConfiguration>
- </generator>
- <generator>
- <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
- <outputBaseDir>${salGeneratorPath}</outputBaseDir>
- </generator>
- </codeGenerators>
- <inspectDependencies>true</inspectDependencies>
- </configuration>
- </execution>
- </executions>
- <dependencies>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>yang-jmx-generator-plugin</artifactId>
- <version>${config.version}</version>
- </dependency>
- </dependencies>
</plugin>
</plugins>
</build>
<plugin>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-maven-plugin</artifactId>
- <executions>
- <execution>
- <id>config</id>
- <goals>
- <goal>generate-sources</goal>
- </goals>
- <configuration>
- <codeGenerators>
- <generator>
- <codeGeneratorClass>org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator</codeGeneratorClass>
- <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
- <additionalConfiguration>
- <namespaceToPackage1>urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang</namespaceToPackage1>
- </additionalConfiguration>
- </generator>
- <generator>
- <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
- <outputBaseDir>${salGeneratorPath}</outputBaseDir>
- </generator>
- </codeGenerators>
- <inspectDependencies>true</inspectDependencies>
- </configuration>
- </execution>
- </executions>
- <dependencies>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>yang-jmx-generator-plugin</artifactId>
- <version>${config.version}</version>
- </dependency>
- </dependencies>
</plugin>
</plugins>
</build>
<dependencies>
<!-- compile dependencies -->
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-manager-facade-xml</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-api</artifactId>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-api</artifactId>
</dependency>
- <dependency>
- <groupId>org.osgi</groupId>
- <artifactId>org.osgi.core</artifactId>
- </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
package org.opendaylight.controller.netconf.util;
import com.google.common.base.Preconditions;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlMappingConstants;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
private NetconfUtil() {}
- public static Document checkIsMessageOk(Document response) throws NetconfDocumentedException {
+ public static Document checkIsMessageOk(Document response) throws DocumentedException {
XmlElement element = XmlElement.fromDomDocument(response);
- Preconditions.checkState(element.getName().equals(XmlNetconfConstants.RPC_REPLY_KEY));
+ Preconditions.checkState(element.getName().equals(XmlMappingConstants.RPC_REPLY_KEY));
element = element.getOnlyChildElement();
if (element.getName().equals(XmlNetconfConstants.OK)) {
return response;
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.util.capability;
-
-import com.google.common.base.Optional;
-import java.util.Collection;
-import java.util.Collections;
-import org.opendaylight.controller.netconf.api.Capability;
-
-/**
- * Capability representing a basic, one-line, string based capability
- */
-public class BasicCapability implements Capability {
-
- private final String capability;
-
- public BasicCapability(final String capability) {
- this.capability = capability;
- }
-
- @Override
- public String getCapabilityUri() {
- return capability;
- }
-
- @Override
- public Optional<String> getModuleNamespace() {
- return Optional.absent();
- }
-
- @Override
- public Optional<String> getModuleName() {
- return Optional.absent();
- }
-
- @Override
- public Optional<String> getRevision() {
- return Optional.absent();
- }
-
- @Override
- public Optional<String> getCapabilitySchema() {
- return Optional.absent();
- }
-
- @Override
- public Collection<String> getLocation() {
- return Collections.emptyList();
- }
-
- @Override
- public String toString() {
- return capability;
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.util.capability;
-
-import com.google.common.base.Optional;
-import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
-import org.opendaylight.yangtools.yang.model.api.Module;
-
-/**
- * Yang model representing capability.
- */
-public final class YangModuleCapability extends BasicCapability {
-
- private final String content;
- private final String revision;
- private final String moduleName;
- private final String moduleNamespace;
-
- public YangModuleCapability(final Module module, final String moduleContent) {
- super(toCapabilityURI(module));
- this.content = moduleContent;
- this.moduleName = module.getName();
- this.moduleNamespace = module.getNamespace().toString();
- this.revision = SimpleDateFormatUtil.getRevisionFormat().format(module.getRevision());
- }
-
- @Override
- public Optional<String> getCapabilitySchema() {
- return Optional.of(content);
- }
-
- private static String toCapabilityURI(final Module module) {
- return String.valueOf(module.getNamespace()) + "?module="
- + module.getName() + "&revision=" + SimpleDateFormatUtil.getRevisionFormat().format(module.getRevision());
- }
-
- @Override
- public Optional<String> getModuleName() {
- return Optional.of(moduleName);
- }
-
- @Override
- public Optional<String> getModuleNamespace() {
- return Optional.of(moduleNamespace);
- }
-
- @Override
- public Optional<String> getRevision() {
- return Optional.of(revision);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.netconf.util.exception;
-
-import java.util.Collections;
-import java.util.Map;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-
-public class MissingNameSpaceException extends NetconfDocumentedException {
- private static final long serialVersionUID = 1L;
-
- public MissingNameSpaceException(final String message, final ErrorType errorType, final ErrorTag errorTag,
- final ErrorSeverity errorSeverity) {
- this(message, errorType, errorTag, errorSeverity, Collections.<String, String> emptyMap());
- }
-
- public MissingNameSpaceException(final String message, final ErrorType errorType, final ErrorTag errorTag,
- final ErrorSeverity errorSeverity, final Map<String, String> errorInfo){
- super(message,errorType,errorTag,errorSeverity,errorInfo);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.netconf.util.exception;
-
-import java.util.Collections;
-import java.util.Map;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-
-public class UnexpectedElementException extends NetconfDocumentedException {
- private static final long serialVersionUID = 1L;
-
- public UnexpectedElementException(final String message, final ErrorType errorType, final ErrorTag errorTag,
- final ErrorSeverity errorSeverity) {
- this(message, errorType, errorTag, errorSeverity, Collections.<String, String> emptyMap());
- }
-
- public UnexpectedElementException(final String message, final ErrorType errorType, final ErrorTag errorTag,
- final ErrorSeverity errorSeverity, final Map<String, String> errorInfo) {
- super(message,errorType,errorTag,errorSeverity,errorInfo);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.netconf.util.exception;
-
-import java.util.Collections;
-import java.util.Map;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-
-public class UnexpectedNamespaceException extends NetconfDocumentedException {
- private static final long serialVersionUID = 1L;
-
- public UnexpectedNamespaceException(final String message, final ErrorType errorType, final ErrorTag errorTag,
- final ErrorSeverity errorSeverity) {
- this(message, errorType, errorTag, errorSeverity, Collections.<String, String> emptyMap());
- }
-
- public UnexpectedNamespaceException(final String message, final ErrorType errorType, final ErrorTag errorTag,
- final ErrorSeverity errorSeverity, final Map<String, String> errorInfo){
- super(message,errorType,errorTag,errorSeverity,errorInfo);
- }
-}
*/
package org.opendaylight.controller.netconf.util.mapping;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@Override
protected Element handle(Document document, XmlElement operationElement,
- NetconfOperationChainedExecution subsequentOperation) throws NetconfDocumentedException {
+ NetconfOperationChainedExecution subsequentOperation) throws DocumentedException {
if (!subsequentOperation.isExecutionTermination()){
- throw new NetconfDocumentedException(String.format("No netconf operation expected to be subsequent to %s, but is %s", this, subsequentOperation),
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.malformed_message,
- NetconfDocumentedException.ErrorSeverity.error);
+ throw new DocumentedException(String.format("No netconf operation expected to be subsequent to %s, but is %s", this, subsequentOperation),
+ DocumentedException.ErrorType.application,
+ DocumentedException.ErrorTag.malformed_message,
+ DocumentedException.ErrorSeverity.error);
}
return handleWithNoSubsequentOperations(document, operationElement);
return HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY;
}
- protected abstract Element handleWithNoSubsequentOperations(Document document, XmlElement operationElement) throws NetconfDocumentedException;
+ protected abstract Element handleWithNoSubsequentOperations(Document document, XmlElement operationElement) throws DocumentedException;
}
import com.google.common.base.Optional;
import java.util.Map;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlMappingConstants;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
}
@Override
- public HandlingPriority canHandle(final Document message) throws NetconfDocumentedException {
+ public HandlingPriority canHandle(final Document message) throws DocumentedException {
OperationNameAndNamespace operationNameAndNamespace = null;
operationNameAndNamespace = new OperationNameAndNamespace(message);
return canHandle(operationNameAndNamespace.getOperationName(), operationNameAndNamespace.getNamespace());
private final String operationName, namespace;
private final XmlElement operationElement;
- public OperationNameAndNamespace(final Document message) throws NetconfDocumentedException {
+ public OperationNameAndNamespace(final Document message) throws DocumentedException {
XmlElement requestElement = null;
requestElement = getRequestElementWithCheck(message);
operationElement = requestElement.getOnlyChildElement();
}
}
- protected static XmlElement getRequestElementWithCheck(final Document message) throws NetconfDocumentedException {
+ protected static XmlElement getRequestElementWithCheck(final Document message) throws DocumentedException {
return XmlElement.fromDomElementWithExpected(message.getDocumentElement(), XmlNetconfConstants.RPC_KEY,
XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
}
@Override
public Document handle(final Document requestMessage,
- final NetconfOperationChainedExecution subsequentOperation) throws NetconfDocumentedException {
+ final NetconfOperationChainedExecution subsequentOperation) throws DocumentedException {
XmlElement requestElement = getRequestElementWithCheck(requestMessage);
Map<String, Attr> attributes = requestElement.getAttributes();
Element response = handle(document, operationElement, subsequentOperation);
- Element rpcReply = XmlUtil.createElement(document, XmlNetconfConstants.RPC_REPLY_KEY, Optional.of(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0));
+ Element rpcReply = XmlUtil.createElement(document, XmlMappingConstants.RPC_REPLY_KEY, Optional.of(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0));
if(XmlElement.fromDomElement(response).hasNamespace()) {
rpcReply.appendChild(response);
}
protected abstract Element handle(Document document, XmlElement message, NetconfOperationChainedExecution subsequentOperation)
- throws NetconfDocumentedException;
+ throws DocumentedException;
@Override
public String toString() {
*/
package org.opendaylight.controller.netconf.util.mapping;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@Override
protected Element handle(Document document, XmlElement operationElement,
- NetconfOperationChainedExecution subsequentOperation) throws NetconfDocumentedException {
+ NetconfOperationChainedExecution subsequentOperation) throws DocumentedException {
return handleWithNoSubsequentOperations(document, operationElement);
}
import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
import java.util.Set;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
// accept even if hello has no namespace
return element.getName().equals(HELLO_TAG) &&
(!element.hasNamespace() || element.getNamespace().equals(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0));
- } catch (MissingNameSpaceException e) {
+ } catch (DocumentedException e) {
// Cannot happen, since we check for hasNamespace
throw new IllegalStateException(e);
}
import java.util.Collection;
import java.util.List;
import javax.annotation.Nonnull;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
if(xmlElement.getChildElements().size() != 1) {
return false;
}
- return xmlElement.getOnlyChildElement().getName().equals(XmlNetconfConstants.OK);
+ try {
+ return xmlElement.getOnlyChildElement().getName().equals(XmlNetconfConstants.OK);
+ } catch (DocumentedException e) {
+ throw new NetconfDocumentedException(e);
+ }
}
public static boolean isErrorMessage(NetconfMessage message) throws NetconfDocumentedException {
if(xmlElement.getChildElements().size() != 1) {
return false;
}
- return xmlElement.getOnlyChildElement().getName().equals(XmlNetconfConstants.RPC_ERROR);
+ try {
+ return xmlElement.getOnlyChildElement().getName().equals(DocumentedException.RPC_ERROR);
+ } catch (DocumentedException e) {
+ throw new NetconfDocumentedException(e);
+ }
}
public static Collection<String> extractCapabilitiesFromHello(Document doc) throws NetconfDocumentedException {
// Trim possible leading/tailing whitespace
try {
return input.getTextContent().trim();
- } catch (NetconfDocumentedException e) {
+ } catch (DocumentedException e) {
LOG.trace("Error fetching input text content",e);
return null;
}
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlMappingConstants;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Attr;
private SendErrorExceptionUtil() {}
public static void sendErrorMessage(final NetconfSession session,
- final NetconfDocumentedException sendErrorException) {
+ final DocumentedException sendErrorException) {
LOG.trace("Sending error {}", sendErrorException.getMessage(), sendErrorException);
final Document errorDocument = createDocument(sendErrorException);
ChannelFuture f = session.sendMessage(new NetconfMessage(errorDocument));
f.addListener(new SendErrorVerifyingListener(sendErrorException));
}
- public static void sendErrorMessage(final Channel channel, final NetconfDocumentedException sendErrorException) {
+ public static void sendErrorMessage(final Channel channel, final DocumentedException sendErrorException) {
LOG.trace("Sending error {}", sendErrorException.getMessage(), sendErrorException);
final Document errorDocument = createDocument(sendErrorException);
ChannelFuture f = channel.writeAndFlush(new NetconfMessage(errorDocument));
f.addListener(new SendErrorVerifyingListener(sendErrorException));
}
- public static void sendErrorMessage(final NetconfSession session, final NetconfDocumentedException sendErrorException,
+ public static void sendErrorMessage(final NetconfSession session, final DocumentedException sendErrorException,
final NetconfMessage incommingMessage) {
final Document errorDocument = createDocument(sendErrorException);
if (LOG.isTraceEnabled()) {
}
private static void tryToCopyAttributes(final Document incommingDocument, final Document errorDocument,
- final NetconfDocumentedException sendErrorException) {
+ final DocumentedException sendErrorException) {
try {
final Element incommingRpc = incommingDocument.getDocumentElement();
Preconditions.checkState(incommingRpc.getTagName().equals(XmlNetconfConstants.RPC_KEY), "Missing %s element",
XmlNetconfConstants.RPC_KEY);
final Element rpcReply = errorDocument.getDocumentElement();
- Preconditions.checkState(rpcReply.getTagName().equals(XmlNetconfConstants.RPC_REPLY_KEY), "Missing %s element",
- XmlNetconfConstants.RPC_REPLY_KEY);
+ Preconditions.checkState(rpcReply.getTagName().equals(XmlMappingConstants.RPC_REPLY_KEY), "Missing %s element",
+ XmlMappingConstants.RPC_REPLY_KEY);
final NamedNodeMap incomingAttributes = incommingRpc.getAttributes();
for (int i = 0; i < incomingAttributes.getLength(); i++) {
}
}
- private static Document createDocument(final NetconfDocumentedException sendErrorException) {
+ private static Document createDocument(final DocumentedException sendErrorException) {
return sendErrorException.toXMLDocument();
}
* Checks if netconf error was sent successfully.
*/
private static final class SendErrorVerifyingListener implements ChannelFutureListener {
- private final NetconfDocumentedException sendErrorException;
+ private final DocumentedException sendErrorException;
- public SendErrorVerifyingListener(final NetconfDocumentedException sendErrorException) {
+ public SendErrorVerifyingListener(final DocumentedException sendErrorException) {
this.sendErrorException = sendErrorException;
}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.util.xml;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Predicate;
-import com.google.common.base.Strings;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
-import org.opendaylight.controller.netconf.util.exception.UnexpectedElementException;
-import org.opendaylight.controller.netconf.util.exception.UnexpectedNamespaceException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.w3c.dom.Attr;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.w3c.dom.Text;
-import org.xml.sax.SAXException;
-
-public final class XmlElement {
-
- public static final String DEFAULT_NAMESPACE_PREFIX = "";
-
- private final Element element;
- private static final Logger LOG = LoggerFactory.getLogger(XmlElement.class);
-
- private XmlElement(Element element) {
- this.element = element;
- }
-
- public static XmlElement fromDomElement(Element e) {
- return new XmlElement(e);
- }
-
- public static XmlElement fromDomDocument(Document xml) {
- return new XmlElement(xml.getDocumentElement());
- }
-
- public static XmlElement fromString(String s) throws NetconfDocumentedException {
- try {
- return new XmlElement(XmlUtil.readXmlToElement(s));
- } catch (IOException | SAXException e) {
- throw NetconfDocumentedException.wrap(e);
- }
- }
-
- public static XmlElement fromDomElementWithExpected(Element element, String expectedName) throws NetconfDocumentedException {
- XmlElement xmlElement = XmlElement.fromDomElement(element);
- xmlElement.checkName(expectedName);
- return xmlElement;
- }
-
- public static XmlElement fromDomElementWithExpected(Element element, String expectedName, String expectedNamespace) throws NetconfDocumentedException {
- XmlElement xmlElement = XmlElement.fromDomElementWithExpected(element, expectedName);
- xmlElement.checkNamespace(expectedNamespace);
- return xmlElement;
- }
-
- private Map<String, String> extractNamespaces() throws NetconfDocumentedException {
- Map<String, String> namespaces = new HashMap<>();
- NamedNodeMap attributes = element.getAttributes();
- for (int i = 0; i < attributes.getLength(); i++) {
- Node attribute = attributes.item(i);
- String attribKey = attribute.getNodeName();
- if (attribKey.startsWith(XmlUtil.XMLNS_ATTRIBUTE_KEY)) {
- String prefix;
- if (attribKey.equals(XmlUtil.XMLNS_ATTRIBUTE_KEY)) {
- prefix = DEFAULT_NAMESPACE_PREFIX;
- } else {
- if (!attribKey.startsWith(XmlUtil.XMLNS_ATTRIBUTE_KEY + ":")){
- throw new NetconfDocumentedException("Attribute doesn't start with :",
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.invalid_value,
- NetconfDocumentedException.ErrorSeverity.error);
- }
- prefix = attribKey.substring(XmlUtil.XMLNS_ATTRIBUTE_KEY.length() + 1);
- }
- namespaces.put(prefix, attribute.getNodeValue());
- }
- }
-
- // namespace does not have to be defined on this element but inherited
- if(!namespaces.containsKey(DEFAULT_NAMESPACE_PREFIX)) {
- Optional<String> namespaceOptionally = getNamespaceOptionally();
- if(namespaceOptionally.isPresent()) {
- namespaces.put(DEFAULT_NAMESPACE_PREFIX, namespaceOptionally.get());
- }
- }
-
- return namespaces;
- }
-
- public void checkName(String expectedName) throws UnexpectedElementException {
- if (!getName().equals(expectedName)){
- throw new UnexpectedElementException(String.format("Expected %s xml element but was %s", expectedName,
- getName()),
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_failed,
- NetconfDocumentedException.ErrorSeverity.error);
- }
- }
-
- public void checkNamespaceAttribute(String expectedNamespace) throws UnexpectedNamespaceException, MissingNameSpaceException {
- if (!getNamespaceAttribute().equals(expectedNamespace))
- {
- throw new UnexpectedNamespaceException(String.format("Unexpected namespace %s should be %s",
- getNamespaceAttribute(),
- expectedNamespace),
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_failed,
- NetconfDocumentedException.ErrorSeverity.error);
- }
- }
-
- public void checkNamespace(String expectedNamespace) throws UnexpectedNamespaceException, MissingNameSpaceException {
- if (!getNamespace().equals(expectedNamespace))
- {
- throw new UnexpectedNamespaceException(String.format("Unexpected namespace %s should be %s",
- getNamespace(),
- expectedNamespace),
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_failed,
- NetconfDocumentedException.ErrorSeverity.error);
- }
- }
-
- public String getName() {
- final String localName = element.getLocalName();
- if (!Strings.isNullOrEmpty(localName)){
- return localName;
- }
- return element.getTagName();
- }
-
- public String getAttribute(String attributeName) {
- return element.getAttribute(attributeName);
- }
-
- public String getAttribute(String attributeName, String namespace) {
- return element.getAttributeNS(namespace, attributeName);
- }
-
- public NodeList getElementsByTagName(String name) {
- return element.getElementsByTagName(name);
- }
-
- public void appendChild(Element element) {
- this.element.appendChild(element);
- }
-
- public Element getDomElement() {
- return element;
- }
-
- public Map<String, Attr> getAttributes() {
-
- Map<String, Attr> mappedAttributes = Maps.newHashMap();
-
- NamedNodeMap attributes = element.getAttributes();
- for (int i = 0; i < attributes.getLength(); i++) {
- Attr attr = (Attr) attributes.item(i);
- mappedAttributes.put(attr.getNodeName(), attr);
- }
-
- return mappedAttributes;
- }
-
- /**
- * Non recursive
- */
- private List<XmlElement> getChildElementsInternal(ElementFilteringStrategy strat) {
- NodeList childNodes = element.getChildNodes();
- final List<XmlElement> result = new ArrayList<>();
- for (int i = 0; i < childNodes.getLength(); i++) {
- Node item = childNodes.item(i);
- if (!(item instanceof Element)) {
- continue;
- }
- if (strat.accept((Element) item)) {
- result.add(new XmlElement((Element) item));
- }
- }
-
- return result;
- }
-
- public List<XmlElement> getChildElements() {
- return getChildElementsInternal(new ElementFilteringStrategy() {
- @Override
- public boolean accept(Element e) {
- return true;
- }
- });
- }
-
- public List<XmlElement> getChildElementsWithinNamespace(final String childName, String namespace) {
- return Lists.newArrayList(Collections2.filter(getChildElementsWithinNamespace(namespace),
- new Predicate<XmlElement>() {
- @Override
- public boolean apply(XmlElement xmlElement) {
- return xmlElement.getName().equals(childName);
- }
- }));
- }
-
- public List<XmlElement> getChildElementsWithinNamespace(final String namespace) {
- return getChildElementsInternal(new ElementFilteringStrategy() {
- @Override
- public boolean accept(Element e) {
- try {
- return XmlElement.fromDomElement(e).getNamespace().equals(namespace);
- } catch (MissingNameSpaceException e1) {
- return false;
- }
- }
-
- });
- }
-
- /**
- *
- * @param tagName tag name without prefix
- * @return List of child elements
- */
- public List<XmlElement> getChildElements(final String tagName) {
- return getChildElementsInternal(new ElementFilteringStrategy() {
- @Override
- public boolean accept(Element e) {
- // localName returns pure localName without prefix
- return e.getLocalName().equals(tagName);
- }
- });
- }
-
- public XmlElement getOnlyChildElement(String childName) throws NetconfDocumentedException {
- List<XmlElement> nameElements = getChildElements(childName);
- if (nameElements.size() != 1){
- throw new NetconfDocumentedException("One element " + childName + " expected in " + toString(),
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.invalid_value,
- NetconfDocumentedException.ErrorSeverity.error);
- }
- return nameElements.get(0);
- }
-
- public Optional<XmlElement> getOnlyChildElementOptionally(String childName) {
- List<XmlElement> nameElements = getChildElements(childName);
- if (nameElements.size() != 1) {
- return Optional.absent();
- }
- return Optional.of(nameElements.get(0));
- }
-
- public Optional<XmlElement> getOnlyChildElementOptionally(final String childName, final String namespace) {
- List<XmlElement> children = getChildElementsWithinNamespace(namespace);
- children = Lists.newArrayList(Collections2.filter(children, new Predicate<XmlElement>() {
- @Override
- public boolean apply(XmlElement xmlElement) {
- return xmlElement.getName().equals(childName);
- }
- }));
- if (children.size() != 1){
- return Optional.absent();
- }
- return Optional.of(children.get(0));
- }
-
- public XmlElement getOnlyChildElementWithSameNamespace(String childName) throws NetconfDocumentedException {
- return getOnlyChildElement(childName, getNamespace());
- }
-
- public Optional<XmlElement> getOnlyChildElementWithSameNamespaceOptionally(final String childName) {
- Optional<String> namespace = getNamespaceOptionally();
- if (namespace.isPresent()) {
- List<XmlElement> children = getChildElementsWithinNamespace(namespace.get());
- children = Lists.newArrayList(Collections2.filter(children, new Predicate<XmlElement>() {
- @Override
- public boolean apply(XmlElement xmlElement) {
- return xmlElement.getName().equals(childName);
- }
- }));
- if (children.size() != 1){
- return Optional.absent();
- }
- return Optional.of(children.get(0));
- }
- return Optional.absent();
- }
-
- public XmlElement getOnlyChildElementWithSameNamespace() throws NetconfDocumentedException {
- XmlElement childElement = getOnlyChildElement();
- childElement.checkNamespace(getNamespace());
- return childElement;
- }
-
- public Optional<XmlElement> getOnlyChildElementWithSameNamespaceOptionally() {
- Optional<XmlElement> child = getOnlyChildElementOptionally();
- if (child.isPresent()
- && child.get().getNamespaceOptionally().isPresent()
- && getNamespaceOptionally().isPresent()
- && getNamespaceOptionally().get().equals(child.get().getNamespaceOptionally().get())) {
- return child;
- }
- return Optional.absent();
- }
-
- public XmlElement getOnlyChildElement(final String childName, String namespace) throws NetconfDocumentedException {
- List<XmlElement> children = getChildElementsWithinNamespace(namespace);
- children = Lists.newArrayList(Collections2.filter(children, new Predicate<XmlElement>() {
- @Override
- public boolean apply(XmlElement xmlElement) {
- return xmlElement.getName().equals(childName);
- }
- }));
- if (children.size() != 1){
- throw new NetconfDocumentedException(String.format("One element %s:%s expected in %s but was %s", namespace,
- childName, toString(), children.size()),
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.invalid_value,
- NetconfDocumentedException.ErrorSeverity.error);
- }
-
- return children.get(0);
- }
-
- public XmlElement getOnlyChildElement() throws NetconfDocumentedException {
- List<XmlElement> children = getChildElements();
- if (children.size() != 1){
- throw new NetconfDocumentedException(String.format( "One element expected in %s but was %s", toString(),
- children.size()),
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.invalid_value,
- NetconfDocumentedException.ErrorSeverity.error);
- }
- return children.get(0);
- }
-
- public Optional<XmlElement> getOnlyChildElementOptionally() {
- List<XmlElement> children = getChildElements();
- if (children.size() != 1) {
- return Optional.absent();
- }
- return Optional.of(children.get(0));
- }
-
- public String getTextContent() throws NetconfDocumentedException {
- NodeList childNodes = element.getChildNodes();
- if (childNodes.getLength() == 0) {
- return DEFAULT_NAMESPACE_PREFIX;
- }
- for(int i = 0; i < childNodes.getLength(); i++) {
- Node textChild = childNodes.item(i);
- if (textChild instanceof Text) {
- String content = textChild.getTextContent();
- return content.trim();
- }
- }
- throw new NetconfDocumentedException(getName() + " should contain text.",
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.invalid_value,
- NetconfDocumentedException.ErrorSeverity.error
- );
- }
-
- public Optional<String> getOnlyTextContentOptionally() {
- // only return text content if this node has exactly one Text child node
- if (element.getChildNodes().getLength() == 1) {
- Node item = element.getChildNodes().item(0);
- if (item instanceof Text) {
- return Optional.of(((Text) item).getWholeText());
- }
- }
- return Optional.absent();
- }
-
- public String getNamespaceAttribute() throws MissingNameSpaceException {
- String attribute = element.getAttribute(XmlUtil.XMLNS_ATTRIBUTE_KEY);
- if (attribute == null || attribute.equals(DEFAULT_NAMESPACE_PREFIX)){
- throw new MissingNameSpaceException(String.format("Element %s must specify namespace",
- toString()),
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_failed,
- NetconfDocumentedException.ErrorSeverity.error);
- }
- return attribute;
- }
-
- public Optional<String> getNamespaceAttributeOptionally(){
- String attribute = element.getAttribute(XmlUtil.XMLNS_ATTRIBUTE_KEY);
- if (attribute == null || attribute.equals(DEFAULT_NAMESPACE_PREFIX)){
- return Optional.absent();
- }
- return Optional.of(attribute);
- }
-
- public Optional<String> getNamespaceOptionally() {
- String namespaceURI = element.getNamespaceURI();
- if (Strings.isNullOrEmpty(namespaceURI)) {
- return Optional.absent();
- } else {
- return Optional.of(namespaceURI);
- }
- }
-
- public String getNamespace() throws MissingNameSpaceException {
- Optional<String> namespaceURI = getNamespaceOptionally();
- if (!namespaceURI.isPresent()){
- throw new MissingNameSpaceException(String.format("No namespace defined for %s", this),
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.operation_failed,
- NetconfDocumentedException.ErrorSeverity.error);
- }
- return namespaceURI.get();
- }
-
- @Override
- public String toString() {
- final StringBuilder sb = new StringBuilder("XmlElement{");
- sb.append("name='").append(getName()).append('\'');
- if (element.getNamespaceURI() != null) {
- try {
- sb.append(", namespace='").append(getNamespace()).append('\'');
- } catch (MissingNameSpaceException e) {
- LOG.trace("Missing namespace for element.");
- }
- }
- sb.append('}');
- return sb.toString();
- }
-
- /**
- * Search for element's attributes defining namespaces. Look for the one
- * namespace that matches prefix of element's text content. E.g.
- *
- * <pre>
- * <type
- * xmlns:th-java="urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl">th-java:threadfactory-naming</type>
- * </pre>
- *
- * returns {"th-java","urn:.."}. If no prefix is matched, then default
- * namespace is returned with empty string as key. If no default namespace
- * is found value will be null.
- */
- public Map.Entry<String/* prefix */, String/* namespace */> findNamespaceOfTextContent() throws NetconfDocumentedException {
- Map<String, String> namespaces = extractNamespaces();
- String textContent = getTextContent();
- int indexOfColon = textContent.indexOf(':');
- String prefix;
- if (indexOfColon > -1) {
- prefix = textContent.substring(0, indexOfColon);
- } else {
- prefix = DEFAULT_NAMESPACE_PREFIX;
- }
- if (!namespaces.containsKey(prefix)) {
- throw new IllegalArgumentException("Cannot find namespace for " + XmlUtil.toString(element) + ". Prefix from content is "
- + prefix + ". Found namespaces " + namespaces);
- }
- return Maps.immutableEntry(prefix, namespaces.get(prefix));
- }
-
- public List<XmlElement> getChildElementsWithSameNamespace(final String childName) throws MissingNameSpaceException {
- List<XmlElement> children = getChildElementsWithinNamespace(getNamespace());
- return Lists.newArrayList(Collections2.filter(children, new Predicate<XmlElement>() {
- @Override
- public boolean apply(XmlElement xmlElement) {
- return xmlElement.getName().equals(childName);
- }
- }));
- }
-
- public void checkUnrecognisedElements(List<XmlElement> recognisedElements,
- XmlElement... additionalRecognisedElements) throws NetconfDocumentedException {
- List<XmlElement> childElements = getChildElements();
- childElements.removeAll(recognisedElements);
- for (XmlElement additionalRecognisedElement : additionalRecognisedElements) {
- childElements.remove(additionalRecognisedElement);
- }
- if (!childElements.isEmpty()){
- throw new NetconfDocumentedException(String.format("Unrecognised elements %s in %s", childElements, this),
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.invalid_value,
- NetconfDocumentedException.ErrorSeverity.error);
- }
- }
-
- public void checkUnrecognisedElements(XmlElement... additionalRecognisedElements) throws NetconfDocumentedException {
- checkUnrecognisedElements(Collections.<XmlElement>emptyList(), additionalRecognisedElements);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- XmlElement that = (XmlElement) o;
-
- return element.isEqualNode(that.element);
-
- }
-
- @Override
- public int hashCode() {
- return element.hashCode();
- }
-
- public boolean hasNamespace() {
- if (!getNamespaceAttributeOptionally().isPresent()) {
- if (!getNamespaceOptionally().isPresent()) {
- return false;
- }
- }
- return true;
- }
-
- private interface ElementFilteringStrategy {
- boolean accept(Element e);
- }
-}
import javax.xml.transform.dom.DOMSource;
import javax.xml.validation.Schema;
import javax.xml.validation.Validator;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.util.xml;
-
-import com.google.common.base.Charsets;
-import com.google.common.base.Optional;
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.StringWriter;
-import javax.xml.XMLConstants;
-import javax.xml.namespace.QName;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Source;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.TransformerFactoryConfigurationError;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-import javax.xml.transform.stream.StreamSource;
-import javax.xml.validation.Schema;
-import javax.xml.validation.SchemaFactory;
-import javax.xml.xpath.XPathExpression;
-import javax.xml.xpath.XPathExpressionException;
-import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.xml.sax.SAXException;
-
-public final class XmlUtil {
-
- public static final String XMLNS_ATTRIBUTE_KEY = "xmlns";
- public static final String XMLNS_URI = "http://www.w3.org/2000/xmlns/";
- private static final DocumentBuilderFactory BUILDER_FACTORY;
- private static final TransformerFactory TRANSFORMER_FACTORY = TransformerFactory.newInstance();
- private static final SchemaFactory SCHEMA_FACTORY = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
-
- static {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- try {
- factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
- factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
- factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
- factory.setXIncludeAware(false);
- factory.setExpandEntityReferences(false);
- // Performance improvement for messages with size <10k according to
- // https://xerces.apache.org/xerces2-j/faq-performance.html
- factory.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", false);
- } catch (ParserConfigurationException e) {
- throw new ExceptionInInitializerError(e);
- }
- factory.setNamespaceAware(true);
- factory.setCoalescing(true);
- factory.setIgnoringElementContentWhitespace(true);
- factory.setIgnoringComments(true);
- BUILDER_FACTORY = factory;
- }
-
- private static final ThreadLocal<DocumentBuilder> DEFAULT_DOM_BUILDER = new ThreadLocal<DocumentBuilder>(){
- @Override
- protected DocumentBuilder initialValue() {
- try {
- return BUILDER_FACTORY.newDocumentBuilder();
- } catch (ParserConfigurationException e) {
- throw new IllegalStateException("Failed to create threadLocal dom builder", e);
- }
- }
-
- @Override
- public void set(DocumentBuilder value) {
- throw new UnsupportedOperationException();
- }
- };
-
- private XmlUtil() {
- throw new UnsupportedOperationException("Utility class");
- }
-
- public static Element readXmlToElement(final String xmlContent) throws SAXException, IOException {
- Document doc = readXmlToDocument(xmlContent);
- return doc.getDocumentElement();
- }
-
- public static Element readXmlToElement(final InputStream xmlContent) throws SAXException, IOException {
- Document doc = readXmlToDocument(xmlContent);
- return doc.getDocumentElement();
- }
-
- public static Document readXmlToDocument(final String xmlContent) throws SAXException, IOException {
- return readXmlToDocument(new ByteArrayInputStream(xmlContent.getBytes(Charsets.UTF_8)));
- }
-
- // TODO improve exceptions throwing
- // along with XmlElement
-
- public static Document readXmlToDocument(final InputStream xmlContent) throws SAXException, IOException {
- Document doc = DEFAULT_DOM_BUILDER.get().parse(xmlContent);
-
- doc.getDocumentElement().normalize();
- return doc;
- }
-
- public static Element readXmlToElement(final File xmlFile) throws SAXException, IOException {
- return readXmlToDocument(new FileInputStream(xmlFile)).getDocumentElement();
- }
-
- public static Document newDocument() {
- return DEFAULT_DOM_BUILDER.get().newDocument();
- }
-
- public static Element createElement(final Document document, final String qName, final Optional<String> namespaceURI) {
- if(namespaceURI.isPresent()) {
- final Element element = document.createElementNS(namespaceURI.get(), qName);
- String name = XMLNS_ATTRIBUTE_KEY;
- if(element.getPrefix() != null) {
- name += ":" + element.getPrefix();
- }
- element.setAttributeNS(XMLNS_URI, name, namespaceURI.get());
- return element;
- }
- return document.createElement(qName);
- }
-
- public static Element createTextElement(final Document document, final String qName, final String content, final Optional<String> namespaceURI) {
- Element typeElement = createElement(document, qName, namespaceURI);
- typeElement.appendChild(document.createTextNode(content));
- return typeElement;
- }
-
- public static Element createTextElementWithNamespacedContent(final Document document, final String qName, final String prefix,
- final String namespace, final String contentWithoutPrefix) {
-
- return createTextElementWithNamespacedContent(document, qName, prefix, namespace, contentWithoutPrefix, Optional.<String>absent());
- }
-
- public static Element createTextElementWithNamespacedContent(final Document document, final String qName, final String prefix,
- final String namespace, final String contentWithoutPrefix, final Optional<String> namespaceURI) {
-
- String content = createPrefixedValue(XmlNetconfConstants.PREFIX, contentWithoutPrefix);
- Element element = createTextElement(document, qName, content, namespaceURI);
- String prefixedNamespaceAttr = createPrefixedValue(XMLNS_ATTRIBUTE_KEY, prefix);
- element.setAttributeNS(XMLNS_URI, prefixedNamespaceAttr, namespace);
- return element;
- }
-
- public static String createPrefixedValue(final String prefix, final String value) {
- return prefix + ":" + value;
- }
-
- public static String toString(final Document document) {
- return toString(document.getDocumentElement());
- }
-
- public static String toString(final Element xml) {
- return toString(xml, false);
- }
-
- public static String toString(final XmlElement xmlElement) {
- return toString(xmlElement.getDomElement(), false);
- }
-
- public static String toString(final Element xml, final boolean addXmlDeclaration) {
- try {
- Transformer transformer = TRANSFORMER_FACTORY.newTransformer();
- transformer.setOutputProperty(OutputKeys.INDENT, "yes");
- transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, addXmlDeclaration ? "no" : "yes");
-
- StreamResult result = new StreamResult(new StringWriter());
- DOMSource source = new DOMSource(xml);
- transformer.transform(source, result);
-
- return result.getWriter().toString();
- } catch (Exception | TransformerFactoryConfigurationError e) {
- throw new IllegalStateException("Unable to serialize xml element " + xml, e);
- }
- }
-
- public static String toString(final Document doc, final boolean addXmlDeclaration) {
- return toString(doc.getDocumentElement(), addXmlDeclaration);
- }
-
- public static Schema loadSchema(final InputStream... fromStreams) {
- Source[] sources = new Source[fromStreams.length];
- int i = 0;
- for (InputStream stream : fromStreams) {
- sources[i++] = new StreamSource(stream);
- }
-
- try {
- return SCHEMA_FACTORY.newSchema(sources);
- } catch (SAXException e) {
- throw new IllegalStateException("Failed to instantiate XML schema", e);
- }
- }
-
- public static Object evaluateXPath(final XPathExpression expr, final Object rootNode, final QName returnType) {
- try {
- return expr.evaluate(rootNode, returnType);
- } catch (XPathExpressionException e) {
- throw new IllegalStateException("Error while evaluating xpath expression " + expr, e);
- }
- }
-
- public static Document createDocumentCopy(final Document original) {
- final Document copiedDocument = newDocument();
- final Node copiedRoot = copiedDocument.importNode(original.getDocumentElement(), true);
- copiedDocument.appendChild(copiedRoot);
- return copiedDocument;
- }
-}
import static org.junit.Assert.fail;
import org.junit.Test;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.w3c.dom.Document;
public class NetconfUtilTest {
import org.junit.Before;
import org.junit.Test;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
}
@Override
- protected Element handleWithNoSubsequentOperations(Document document, XmlElement operationElement) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(Document document, XmlElement operationElement) throws DocumentedException{
handleWithNoSubsequentOperationsRun = true;
return null;
}
assertEquals(HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY, netconfOperation.getHandlingPriority());
}
- @Test(expected = NetconfDocumentedException.class)
+ @Test(expected = DocumentedException.class)
public void testHandle() throws Exception {
NetconfOperationChainedExecution operation = mock(NetconfOperationChainedExecution.class);
doReturn("").when(operation).toString();
import java.io.IOException;
import org.junit.Before;
import org.junit.Test;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
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.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
}
@Override
- protected Element handle(Document document, XmlElement message, NetconfOperationChainedExecution subsequentOperation) throws NetconfDocumentedException {
+ protected Element handle(Document document, XmlElement message, NetconfOperationChainedExecution subsequentOperation) throws DocumentedException{
this.handleRun = true;
try {
return XmlUtil.readXmlToElement("<element/>");
import static org.junit.Assert.assertEquals;
import org.junit.Test;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
}
@Override
- protected Element handleWithNoSubsequentOperations(Document document, XmlElement operationElement) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(Document document, XmlElement operationElement) throws DocumentedException{
return null;
}
import io.netty.util.concurrent.GenericFutureListener;
import org.junit.Before;
import org.junit.Test;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
NetconfSession netconfSession;
ChannelFuture channelFuture;
Channel channel;
- private NetconfDocumentedException exception;
+ private DocumentedException exception;
@Before
public void setUp() throws Exception {
doReturn(channelFuture).when(netconfSession).sendMessage(any(NetconfMessage.class));
doReturn(channelFuture).when(channelFuture).addListener(any(GenericFutureListener.class));
doReturn(channelFuture).when(channel).writeAndFlush(any(NetconfMessage.class));
- exception = new NetconfDocumentedException("err");
+ exception = new DocumentedException("err");
}
@Test
import java.io.IOException;
import java.io.InputStream;
import javax.xml.parsers.ParserConfigurationException;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
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.opendaylight.controller.config.util.xml.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
--- /dev/null
+package org.opendaylight.controller.netconf.util.xml;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import org.junit.Test;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.w3c.dom.Element;
+
+public class XMLNetconfUtilTest {
+
+ @Test
+ public void testXPath() throws Exception {
+ final XPathExpression correctXPath = XMLNetconfUtil.compileXPath("/top/innerText");
+ try {
+ XMLNetconfUtil.compileXPath("!@(*&$!");
+ fail("Incorrect xpath should fail");
+ } catch (IllegalStateException e) {}
+ final Object value = XmlUtil.evaluateXPath(correctXPath, XmlUtil.readXmlToDocument("<top><innerText>value</innerText></top>"), XPathConstants.NODE);
+ assertEquals("value", ((Element) value).getTextContent());
+ }
+
+}
\ 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.netconf.util.xml;
-
-import static org.hamcrest.CoreMatchers.both;
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.google.common.base.Optional;
-import java.util.Map;
-import org.junit.Before;
-import org.junit.Test;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-public class XmlElementTest {
-
- private final String elementAsString = "<top xmlns=\"namespace\" xmlns:a=\"attrNamespace\" a:attr1=\"value1\" attr2=\"value2\">" +
- "<inner>" +
- "<deepInner>deepValue</deepInner>" +
- "</inner>" +
- "<innerNamespace xmlns=\"innerNamespace\">innerNamespaceValue</innerNamespace>" +
- "<innerPrefixed xmlns:b=\"prefixedValueNamespace\">b:valueWithPrefix</innerPrefixed>" +
- "</top>";
- private Document document;
- private Element element;
- private XmlElement xmlElement;
-
- @Before
- public void setUp() throws Exception {
- document = XmlUtil.readXmlToDocument(elementAsString);
- element = document.getDocumentElement();
- xmlElement = XmlElement.fromDomElement(element);
- }
-
- @Test
- public void testConstruct() throws Exception {
- final XmlElement fromString = XmlElement.fromString(elementAsString);
- assertEquals(fromString, xmlElement);
- XmlElement.fromDomDocument(document);
- XmlElement.fromDomElement(element);
- XmlElement.fromDomElementWithExpected(element, "top");
- XmlElement.fromDomElementWithExpected(element, "top", "namespace");
-
- try {
- XmlElement.fromString("notXml");
- fail();
- } catch (final NetconfDocumentedException e) {}
-
- try {
- XmlElement.fromDomElementWithExpected(element, "notTop");
- fail();
- } catch (final NetconfDocumentedException e) {}
-
- try {
- XmlElement.fromDomElementWithExpected(element, "top", "notNamespace");
- fail();
- } catch (final NetconfDocumentedException e) {}
- }
-
- @Test
- public void testGetters() throws Exception {
- assertEquals(element, xmlElement.getDomElement());
- assertEquals(element.getElementsByTagName("inner").getLength(), xmlElement.getElementsByTagName("inner").getLength());
-
- assertEquals("top", xmlElement.getName());
- assertTrue(xmlElement.hasNamespace());
- assertEquals("namespace", xmlElement.getNamespace());
- assertEquals("namespace", xmlElement.getNamespaceAttribute());
- assertEquals(Optional.of("namespace"), xmlElement.getNamespaceOptionally());
-
- assertEquals("value1", xmlElement.getAttribute("attr1", "attrNamespace"));
- assertEquals("value2", xmlElement.getAttribute("attr2"));
- assertEquals(2 + 2/*Namespace definition*/, xmlElement.getAttributes().size());
-
- assertEquals(3, xmlElement.getChildElements().size());
- assertEquals(1, xmlElement.getChildElements("inner").size());
- assertTrue(xmlElement.getOnlyChildElementOptionally("inner").isPresent());
- assertTrue(xmlElement.getOnlyChildElementWithSameNamespaceOptionally("inner").isPresent());
- assertEquals(0, xmlElement.getChildElements("unknown").size());
- assertFalse(xmlElement.getOnlyChildElementOptionally("unknown").isPresent());
- assertEquals(1, xmlElement.getChildElementsWithSameNamespace("inner").size());
- assertEquals(0, xmlElement.getChildElementsWithSameNamespace("innerNamespace").size());
- assertEquals(1, xmlElement.getChildElementsWithinNamespace("innerNamespace", "innerNamespace").size());
- assertTrue(xmlElement.getOnlyChildElementOptionally("innerNamespace", "innerNamespace").isPresent());
- assertFalse(xmlElement.getOnlyChildElementOptionally("innerNamespace", "unknownNamespace").isPresent());
-
- final XmlElement noNamespaceElement = XmlElement.fromString("<noNamespace/>");
- assertFalse(noNamespaceElement.hasNamespace());
- try {
- noNamespaceElement.getNamespace();
- fail();
- } catch (final MissingNameSpaceException e) {}
-
- final XmlElement inner = xmlElement.getOnlyChildElement("inner");
- final XmlElement deepInner = inner.getOnlyChildElementWithSameNamespaceOptionally().get();
- assertEquals(deepInner, inner.getOnlyChildElementWithSameNamespace());
- assertEquals(Optional.<XmlElement>absent(), xmlElement.getOnlyChildElementOptionally("unknown"));
- assertEquals("deepValue", deepInner.getTextContent());
- assertEquals("deepValue", deepInner.getOnlyTextContentOptionally().get());
- assertEquals("deepValue", deepInner.getOnlyTextContentOptionally().get());
- }
-
- @Test
- public void testExtractNamespaces() throws Exception {
- final XmlElement innerPrefixed = xmlElement.getOnlyChildElement("innerPrefixed");
- Map.Entry<String, String> namespaceOfTextContent = innerPrefixed.findNamespaceOfTextContent();
-
- assertNotNull(namespaceOfTextContent);
- assertEquals("b", namespaceOfTextContent.getKey());
- assertEquals("prefixedValueNamespace", namespaceOfTextContent.getValue());
- final XmlElement innerNamespace = xmlElement.getOnlyChildElement("innerNamespace");
- namespaceOfTextContent = innerNamespace.findNamespaceOfTextContent();
-
- assertEquals("", namespaceOfTextContent.getKey());
- assertEquals("innerNamespace", namespaceOfTextContent.getValue());
- }
-
- @Test
- public void testUnrecognisedElements() throws Exception {
- xmlElement.checkUnrecognisedElements(xmlElement.getOnlyChildElement("inner"), xmlElement.getOnlyChildElement("innerPrefixed"), xmlElement.getOnlyChildElement("innerNamespace"));
-
- try {
- xmlElement.checkUnrecognisedElements(xmlElement.getOnlyChildElement("inner"));
- fail();
- } catch (final NetconfDocumentedException e) {
- assertThat(e.getMessage(), both(containsString("innerNamespace")).and(containsString("innerNamespace")));
- }
- }
-}
+++ /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.netconf.util.xml;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.google.common.base.Optional;
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathExpression;
-import org.custommonkey.xmlunit.Diff;
-import org.custommonkey.xmlunit.XMLUnit;
-import org.junit.Test;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.xml.sax.SAXParseException;
-
-public class XmlUtilTest {
-
- private final String xml = "<top xmlns=\"namespace\">\n" +
- "<innerText>value</innerText>\n" +
- "<innerPrefixedText xmlns:pref=\"prefixNamespace\">prefix:value</innerPrefixedText>\n" +
- "<innerPrefixedText xmlns=\"randomNamespace\" xmlns:pref=\"prefixNamespace\">prefix:value</innerPrefixedText>\n" +
- "</top>";
-
- @Test
- public void testCreateElement() throws Exception {
- final Document document = XmlUtil.newDocument();
- final Element top = XmlUtil.createElement(document, "top", Optional.of("namespace"));
-
- top.appendChild(XmlUtil.createTextElement(document, "innerText", "value", Optional.of("namespace")));
- top.appendChild(XmlUtil.createTextElementWithNamespacedContent(document, "innerPrefixedText", "pref", "prefixNamespace", "value", Optional.of("namespace")));
- top.appendChild(XmlUtil.createTextElementWithNamespacedContent(document, "innerPrefixedText", "pref", "prefixNamespace", "value", Optional.of("randomNamespace")));
-
- document.appendChild(top);
- assertEquals("top", XmlUtil.createDocumentCopy(document).getDocumentElement().getTagName());
-
- XMLUnit.setIgnoreAttributeOrder(true);
- XMLUnit.setIgnoreWhitespace(true);
-
- final Diff diff = XMLUnit.compareXML(XMLUnit.buildControlDocument(xml), document);
- assertTrue(diff.toString(), diff.similar());
- }
-
- @Test
- public void testLoadSchema() throws Exception {
- XmlUtil.loadSchema();
- try {
- XmlUtil.loadSchema(getClass().getResourceAsStream("/netconfMessages/commit.xml"));
- fail("Input stream does not contain xsd");
- } catch (final IllegalStateException e) {
- assertTrue(e.getCause() instanceof SAXParseException);
- }
-
- }
-
- @Test(expected = SAXParseException.class)
- public void testXXEFlaw() throws Exception {
- XmlUtil.readXmlToDocument("<!DOCTYPE foo [ \n" +
- "<!ELEMENT foo ANY >\n" +
- "<!ENTITY xxe SYSTEM \"file:///etc/passwd\" >]>\n" +
- "<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" +
- " <capabilities>\n" +
- " <capability>urn:ietf:params:netconf:base:1.0 &xxe;</capability>\n" +
- " </capabilities>\n" +
- " </hello>]]>]]>");
- }
-
- @Test
- public void testXPath() throws Exception {
- final XPathExpression correctXPath = XMLNetconfUtil.compileXPath("/top/innerText");
- try {
- XMLNetconfUtil.compileXPath("!@(*&$!");
- fail("Incorrect xpath should fail");
- } catch (IllegalStateException e) {}
- final Object value = XmlUtil.evaluateXPath(correctXPath, XmlUtil.readXmlToDocument("<top><innerText>value</innerText></top>"), XPathConstants.NODE);
- assertEquals("value", ((Element) value).getTextContent());
- }
-}
\ No newline at end of file
<modules>
<module>netconf-api</module>
- <module>netconf-cli</module>
<module>netconf-config</module>
<module>netconf-impl</module>
<module>config-netconf-connector</module>
<module>mdsal-netconf-monitoring</module>
<module>netconf-util</module>
<module>netconf-netty-util</module>
- <module>config-persister-impl</module>
<module>netconf-mapping-api</module>
<module>netconf-client</module>
+ <module>netconf-config-dispatcher</module>
<module>netconf-ssh</module>
<module>netconf-tcp</module>
<module>netconf-monitoring</module>
- <module>ietf-netconf</module>
- <module>ietf-netconf-monitoring</module>
- <module>ietf-netconf-notifications</module>
- <module>ietf-netconf-monitoring-extension</module>
<module>netconf-connector-config</module>
<module>netconf-mdsal-config</module>
<module>netconf-auth</module>
- <module>netconf-testtool</module>
<module>netconf-notifications-impl</module>
<module>netconf-notifications-api</module>
+ <module>sal-netconf-connector</module>
+ <module>features</module>
+ <module>models</module>
+ <module>tools</module>
<module>netconf-artifacts</module>
</modules>
<plugin>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-maven-plugin</artifactId>
- <version>${yangtools.version}</version>
- <dependencies>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>maven-sal-api-gen-plugin</artifactId>
- <version>${yangtools.version}</version>
- </dependency>
- </dependencies>
<executions>
<execution>
+ <id>config</id>
<goals>
<goal>generate-sources</goal>
</goals>
<configuration>
- <yangFilesRootDir>src/main/yang</yangFilesRootDir>
<codeGenerators>
<generator>
- <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
- <outputBaseDir>${salGeneratorPath}</outputBaseDir>
+ <codeGeneratorClass>org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator</codeGeneratorClass>
+ <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
+ <additionalConfiguration>
+ <namespaceToPackage1>urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang</namespaceToPackage1>
+ </additionalConfiguration>
</generator>
<generator>
- <codeGeneratorClass>org.opendaylight.yangtools.yang.unified.doc.generator.maven.DocumentationGeneratorImpl</codeGeneratorClass>
- <outputBaseDir>${project.build.directory}/site/models</outputBaseDir>
+ <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
+ <outputBaseDir>${salGeneratorPath}</outputBaseDir>
</generator>
</codeGenerators>
<inspectDependencies>true</inspectDependencies>
</configuration>
</execution>
</executions>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>yang-jmx-generator-plugin</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ </dependencies>
</plugin>
</plugins>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-subsystem</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>sal-netconf-connector</artifactId>
+
+ <packaging>bundle</packaging>
+
+ <!-- Preserve version from mdsal -->
+ <version>${mdsal.version}</version>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-config-dispatcher</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>sal-common-util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>sal-connector-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>ietf-netconf-monitoring</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>ietf-netconf-notifications</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-client</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-notifications-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netty-config-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netty-threadgroup-config</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-generator-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-config</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>threadpool-config-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller.model</groupId>
+ <artifactId>model-inventory</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>ietf-topology</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-broker-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-parser-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>ietf-inet-types</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>xmlunit</groupId>
+ <artifactId>xmlunit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>config-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>config-manager</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>config-manager</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>config-netconf-connector</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>config-persister-impl</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>config-util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-impl</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-mapping-api</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-util</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>yang-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>logback-config</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-broker-impl</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>mockito-configuration</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-maven-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+ <scm>
+ <connection>scm:git:http://git.opendaylight.org/gerrit/controller.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+ <tag>HEAD</tag>
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
+ </scm>
+</project>
--- /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.config.yang.md.sal.connector.netconf;
+
+import static org.opendaylight.controller.config.api.JmxAttributeValidationException.checkCondition;
+import static org.opendaylight.controller.config.api.JmxAttributeValidationException.checkNotNull;
+
+import com.google.common.base.Optional;
+import io.netty.util.concurrent.EventExecutor;
+import java.math.BigDecimal;
+import java.net.InetSocketAddress;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadFactory;
+import org.opendaylight.controller.config.api.JmxAttributeValidationException;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
+import org.opendaylight.controller.netconf.client.conf.NetconfReconnectingClientConfiguration;
+import org.opendaylight.controller.netconf.client.conf.NetconfReconnectingClientConfigurationBuilder;
+import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication.LoginPassword;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.controller.sal.connect.netconf.NetconfDevice;
+import org.opendaylight.controller.sal.connect.netconf.NetconfStateSchemas;
+import org.opendaylight.controller.sal.connect.netconf.listener.NetconfDeviceCommunicator;
+import org.opendaylight.controller.sal.connect.netconf.listener.NetconfSessionPreferences;
+import org.opendaylight.controller.sal.connect.netconf.sal.KeepaliveSalFacade;
+import org.opendaylight.controller.sal.connect.netconf.sal.NetconfDeviceSalFacade;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.protocol.framework.ReconnectStrategy;
+import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
+import org.opendaylight.protocol.framework.TimedReconnectStrategy;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ */
+public final class NetconfConnectorModule extends org.opendaylight.controller.config.yang.md.sal.connector.netconf.AbstractNetconfConnectorModule
+{
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfConnectorModule.class);
+
+ private BundleContext bundleContext;
+ private Optional<NetconfSessionPreferences> userCapabilities;
+ private SchemaSourceRegistry schemaRegistry;
+ private SchemaContextFactory schemaContextFactory;
+
+ public NetconfConnectorModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public NetconfConnectorModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, final NetconfConnectorModule oldModule, final java.lang.AutoCloseable oldInstance) {
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ protected void customValidation() {
+ checkNotNull(getAddress(), addressJmxAttribute);
+ checkCondition(isHostAddressPresent(getAddress()), "Host address not present in " + getAddress(), addressJmxAttribute);
+ checkNotNull(getPort(), portJmxAttribute);
+ checkNotNull(getDomRegistry(), portJmxAttribute);
+ checkNotNull(getDomRegistry(), domRegistryJmxAttribute);
+
+ checkNotNull(getConnectionTimeoutMillis(), connectionTimeoutMillisJmxAttribute);
+ checkCondition(getConnectionTimeoutMillis() > 0, "must be > 0", connectionTimeoutMillisJmxAttribute);
+
+ checkNotNull(getConnectionTimeoutMillis(), defaultRequestTimeoutMillisJmxAttribute);
+ checkCondition(getConnectionTimeoutMillis() > 0, "must be > 0", defaultRequestTimeoutMillisJmxAttribute);
+
+ checkNotNull(getBetweenAttemptsTimeoutMillis(), betweenAttemptsTimeoutMillisJmxAttribute);
+ checkCondition(getBetweenAttemptsTimeoutMillis() > 0, "must be > 0", betweenAttemptsTimeoutMillisJmxAttribute);
+
+ checkNotNull(getClientDispatcher(), clientDispatcherJmxAttribute);
+ checkNotNull(getBindingRegistry(), bindingRegistryJmxAttribute);
+ checkNotNull(getProcessingExecutor(), processingExecutorJmxAttribute);
+
+ // Check username + password in case of ssh
+ if(getTcpOnly() == false) {
+ checkNotNull(getUsername(), usernameJmxAttribute);
+ checkNotNull(getPassword(), passwordJmxAttribute);
+ }
+
+ userCapabilities = getUserCapabilities();
+
+ if(getKeepaliveExecutor() == null) {
+ LOG.warn("Keepalive executor missing. Using default instance for now, the configuration needs to be updated");
+
+ // Instantiate the default executor, now we know its necessary
+ if(DEFAULT_KEEPALIVE_EXECUTOR == null) {
+ DEFAULT_KEEPALIVE_EXECUTOR = Executors.newScheduledThreadPool(2, new ThreadFactory() {
+ @Override
+ public Thread newThread(final Runnable r) {
+ final Thread thread = new Thread(r);
+ thread.setName("netconf-southound-keepalives-" + thread.getId());
+ thread.setDaemon(true);
+ return thread;
+ }
+ });
+ }
+ }
+ }
+
+ private boolean isHostAddressPresent(final Host address) {
+ return address.getDomainName() != null ||
+ address.getIpAddress() != null && (address.getIpAddress().getIpv4Address() != null || address.getIpAddress().getIpv6Address() != null);
+ }
+
+ @Deprecated
+ private static ScheduledExecutorService DEFAULT_KEEPALIVE_EXECUTOR;
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ final RemoteDeviceId id = new RemoteDeviceId(getIdentifier(), getSocketAddress());
+
+ final ExecutorService globalProcessingExecutor = getProcessingExecutorDependency().getExecutor();
+
+ final Broker domBroker = getDomRegistryDependency();
+ final BindingAwareBroker bindingBroker = getBindingRegistryDependency();
+
+ RemoteDeviceHandler<NetconfSessionPreferences> salFacade
+ = new NetconfDeviceSalFacade(id, domBroker, bindingBroker, getDefaultRequestTimeoutMillis());
+
+ final Long keepaliveDelay = getKeepaliveDelay();
+ if(shouldSendKeepalive()) {
+ // Keepalive executor is optional for now and a default instance is supported
+ final ScheduledExecutorService executor = getKeepaliveExecutor() == null ?
+ DEFAULT_KEEPALIVE_EXECUTOR : getKeepaliveExecutorDependency().getExecutor();
+ salFacade = new KeepaliveSalFacade(id, salFacade, executor, keepaliveDelay);
+ }
+
+ final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO =
+ new NetconfDevice.SchemaResourcesDTO(schemaRegistry, schemaContextFactory, new NetconfStateSchemas.NetconfStateSchemasResolverImpl());
+
+ final NetconfDevice device =
+ new NetconfDevice(schemaResourcesDTO, id, salFacade, globalProcessingExecutor, getReconnectOnChangedSchema());
+
+ final NetconfDeviceCommunicator listener = userCapabilities.isPresent() ?
+ new NetconfDeviceCommunicator(id, device, userCapabilities.get()) : new NetconfDeviceCommunicator(id, device);
+
+ if(shouldSendKeepalive()) {
+ ((KeepaliveSalFacade) salFacade).setListener(listener);
+ }
+
+ final NetconfReconnectingClientConfiguration clientConfig = getClientConfig(listener);
+ final NetconfClientDispatcher dispatcher = getClientDispatcherDependency();
+
+ listener.initializeRemoteConnection(dispatcher, clientConfig);
+
+ return new SalConnectorCloseable(listener, salFacade);
+ }
+
+ private boolean shouldSendKeepalive() {
+ return getKeepaliveDelay() > 0;
+ }
+
+ private Optional<NetconfSessionPreferences> getUserCapabilities() {
+ if(getYangModuleCapabilities() == null) {
+ return Optional.absent();
+ }
+
+ final List<String> capabilities = getYangModuleCapabilities().getCapability();
+ if(capabilities == null || capabilities.isEmpty()) {
+ return Optional.absent();
+ }
+
+ final NetconfSessionPreferences parsedOverrideCapabilities = NetconfSessionPreferences.fromStrings(capabilities);
+ JmxAttributeValidationException.checkCondition(
+ parsedOverrideCapabilities.getNonModuleCaps().isEmpty(),
+ "Capabilities to override can only contain module based capabilities, non-module capabilities will be retrieved from the device," +
+ " configured non-module capabilities: " + parsedOverrideCapabilities.getNonModuleCaps(),
+ yangModuleCapabilitiesJmxAttribute);
+
+ return Optional.of(parsedOverrideCapabilities);
+ }
+
+ public NetconfReconnectingClientConfiguration getClientConfig(final NetconfDeviceCommunicator listener) {
+ final InetSocketAddress socketAddress = getSocketAddress();
+ final long clientConnectionTimeoutMillis = getConnectionTimeoutMillis();
+
+ final ReconnectStrategyFactory sf = new TimedReconnectStrategyFactory(
+ getEventExecutorDependency(), getMaxConnectionAttempts(), getBetweenAttemptsTimeoutMillis(), getSleepFactor());
+ final ReconnectStrategy strategy = sf.createReconnectStrategy();
+
+ return NetconfReconnectingClientConfigurationBuilder.create()
+ .withAddress(socketAddress)
+ .withConnectionTimeoutMillis(clientConnectionTimeoutMillis)
+ .withReconnectStrategy(strategy)
+ .withAuthHandler(new LoginPassword(getUsername(), getPassword()))
+ .withProtocol(getTcpOnly() ?
+ NetconfClientConfiguration.NetconfClientProtocol.TCP :
+ NetconfClientConfiguration.NetconfClientProtocol.SSH)
+ .withConnectStrategyFactory(sf)
+ .withSessionListener(listener)
+ .build();
+ }
+
+ private static final class SalConnectorCloseable implements AutoCloseable {
+ private final RemoteDeviceHandler<NetconfSessionPreferences> salFacade;
+ private final NetconfDeviceCommunicator listener;
+
+ public SalConnectorCloseable(final NetconfDeviceCommunicator listener,
+ final RemoteDeviceHandler<NetconfSessionPreferences> salFacade) {
+ this.listener = listener;
+ this.salFacade = salFacade;
+ }
+
+ @Override
+ public void close() {
+ listener.close();
+ salFacade.close();
+ }
+ }
+
+ private static final class TimedReconnectStrategyFactory implements ReconnectStrategyFactory {
+ private final Long connectionAttempts;
+ private final EventExecutor executor;
+ private final double sleepFactor;
+ private final int minSleep;
+
+ TimedReconnectStrategyFactory(final EventExecutor executor, final Long maxConnectionAttempts, final int minSleep, final BigDecimal sleepFactor) {
+ if (maxConnectionAttempts != null && maxConnectionAttempts > 0) {
+ connectionAttempts = maxConnectionAttempts;
+ } else {
+ LOG.trace("Setting {} on {} to infinity", maxConnectionAttemptsJmxAttribute, this);
+ connectionAttempts = null;
+ }
+
+ this.sleepFactor = sleepFactor.doubleValue();
+ this.executor = executor;
+ this.minSleep = minSleep;
+ }
+
+ @Override
+ public ReconnectStrategy createReconnectStrategy() {
+ final Long maxSleep = null;
+ final Long deadline = null;
+
+ return new TimedReconnectStrategy(executor, minSleep,
+ minSleep, sleepFactor, maxSleep, connectionAttempts, deadline);
+ }
+ }
+
+ private InetSocketAddress getSocketAddress() {
+ if(getAddress().getDomainName() != null) {
+ return new InetSocketAddress(getAddress().getDomainName().getValue(), getPort().getValue());
+ } else {
+ final IpAddress ipAddress = getAddress().getIpAddress();
+ final String ip = ipAddress.getIpv4Address() != null ? ipAddress.getIpv4Address().getValue() : ipAddress.getIpv6Address().getValue();
+ return new InetSocketAddress(ip, getPort().getValue());
+ }
+ }
+
+ public void setSchemaRegistry(final SchemaSourceRegistry schemaRegistry) {
+ this.schemaRegistry = schemaRegistry;
+ }
+
+ public void setSchemaContextFactory(final SchemaContextFactory schemaContextFactory) {
+ this.schemaContextFactory = schemaContextFactory;
+ }
+}
--- /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.config.yang.md.sal.connector.netconf;
+
+import java.io.File;
+
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.DynamicMBeanWithInstance;
+import org.opendaylight.controller.config.spi.Module;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.util.FilesystemSchemaSourceCache;
+import org.opendaylight.yangtools.yang.parser.repo.SharedSchemaRepository;
+import org.opendaylight.yangtools.yang.parser.util.TextToASTTransformer;
+import org.osgi.framework.BundleContext;
+
+/**
+*
+*/
+public class NetconfConnectorModuleFactory extends
+ org.opendaylight.controller.config.yang.md.sal.connector.netconf.AbstractNetconfConnectorModuleFactory {
+
+ // TODO this should be injected
+ // Netconf devices have separated schema registry + factory from controller
+ private final SharedSchemaRepository repository = new SharedSchemaRepository(NAME);
+ private final SchemaContextFactory schemaContextFactory
+ = repository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
+
+ public NetconfConnectorModuleFactory() {
+ // Start cache and Text to AST transformer
+ final FilesystemSchemaSourceCache<YangTextSchemaSource> cache = new FilesystemSchemaSourceCache<>(repository, YangTextSchemaSource.class, new File("cache/schema"));
+ repository.registerSchemaSourceListener(cache);
+ repository.registerSchemaSourceListener(TextToASTTransformer.create(repository, repository));
+ }
+
+ @Override
+ public Module createModule(final String instanceName, final DependencyResolver dependencyResolver,
+ final DynamicMBeanWithInstance old, final BundleContext bundleContext) throws Exception {
+ final NetconfConnectorModule module = (NetconfConnectorModule) super.createModule(instanceName, dependencyResolver,
+ old, bundleContext);
+
+ module.setSchemaRegistry(repository);
+ module.setSchemaContextFactory(schemaContextFactory);
+ return module;
+ }
+
+ @Override
+ public Module createModule(final String instanceName, final DependencyResolver dependencyResolver, final BundleContext bundleContext) {
+ final NetconfConnectorModule module = (NetconfConnectorModule) super.createModule(instanceName, dependencyResolver,
+ bundleContext);
+ module.setSchemaRegistry(repository);
+ module.setSchemaContextFactory(schemaContextFactory);
+ return module;
+ }
+}
--- /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.connect.api;
+
+import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+public interface MessageTransformer<M> {
+
+ DOMNotification toNotification(M message);
+
+ M toRpcRequest(SchemaPath rpc, NormalizedNode<?, ?> node);
+
+ DOMRpcResult toRpcResult(M message, SchemaPath rpc);
+
+}
--- /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.connect.api;
+
+/**
+ *
+ */
+public interface RemoteDevice<PREF, M, LISTENER extends RemoteDeviceCommunicator<M>> {
+
+ void onRemoteSessionUp(PREF remoteSessionCapabilities, LISTENER listener);
+
+ void onRemoteSessionDown();
+
+ void onRemoteSessionFailed(Throwable throwable);
+
+ void onNotification(M notification);
+}
--- /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.connect.api;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+public interface RemoteDeviceCommunicator<M> extends AutoCloseable {
+
+ ListenableFuture<RpcResult<M>> sendRequest(M message, QName rpc);
+
+ void 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.connect.api;
+
+import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public interface RemoteDeviceHandler<PREF> extends AutoCloseable {
+
+ void onDeviceConnected(SchemaContext remoteSchemaContext,
+ PREF netconfSessionPreferences, DOMRpcService deviceRpc);
+
+ void onDeviceDisconnected();
+
+ void onDeviceFailed(Throwable throwable);
+
+ void onNotification(DOMNotification domNotification);
+
+ void 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.connect.api;
+
+import java.io.InputStream;
+import java.util.Collection;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
+import org.opendaylight.yangtools.yang.model.util.repo.SchemaSourceProvider;
+
+public interface SchemaContextProviderFactory {
+
+ SchemaContextProvider createContextProvider(Collection<QName> capabilities, SchemaSourceProvider<InputStream> sourceProvider);
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015 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
+ */
+
+/**
+ * General API for remote connectors e.g. netconf connector
+ *
+ * TODO extract into separate bundle when another connector is implemented e.g. restconf connector
+ */
+package org.opendaylight.controller.sal.connect.api;
--- /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.connect.netconf;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.sal.connect.api.MessageTransformer;
+import org.opendaylight.controller.sal.connect.api.RemoteDevice;
+import org.opendaylight.controller.sal.connect.api.RemoteDeviceCommunicator;
+import org.opendaylight.controller.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.controller.sal.connect.netconf.listener.NetconfDeviceCapabilities;
+import org.opendaylight.controller.sal.connect.netconf.listener.NetconfDeviceCommunicator;
+import org.opendaylight.controller.sal.connect.netconf.listener.NetconfSessionPreferences;
+import org.opendaylight.controller.sal.connect.netconf.sal.NetconfDeviceRpc;
+import org.opendaylight.controller.sal.connect.netconf.schema.NetconfRemoteSchemaYangSourceProvider;
+import org.opendaylight.controller.sal.connect.netconf.schema.mapping.NetconfMessageTransformer;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.$YangModuleInfoImpl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChange;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.fields.unavailable.capabilities.UnavailableCapability;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.repo.api.MissingSchemaSourceException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaResolutionException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This is a mediator between NetconfDeviceCommunicator and NetconfDeviceSalFacade
+ */
+public final class NetconfDevice implements RemoteDevice<NetconfSessionPreferences, NetconfMessage, NetconfDeviceCommunicator> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfDevice.class);
+
+ /**
+ * Initial schema context contains schemas for netconf monitoring and netconf notifications
+ */
+ public static final SchemaContext INIT_SCHEMA_CTX;
+
+ static {
+ try {
+ final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create();
+ moduleInfoBackedContext.addModuleInfos(
+ Lists.newArrayList(
+ $YangModuleInfoImpl.getInstance(),
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.$YangModuleInfoImpl.getInstance(),
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.$YangModuleInfoImpl.getInstance()));
+ INIT_SCHEMA_CTX = moduleInfoBackedContext.tryToCreateSchemaContext().get();
+ } catch (final RuntimeException e) {
+ LOG.error("Unable to prepare schema context for netconf initialization", e);
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ public static final Function<QName, SourceIdentifier> QNAME_TO_SOURCE_ID_FUNCTION = new Function<QName, SourceIdentifier>() {
+ @Override
+ public SourceIdentifier apply(final QName input) {
+ return new SourceIdentifier(input.getLocalName(), Optional.fromNullable(input.getFormattedRevision()));
+ }
+ };
+
+ private final RemoteDeviceId id;
+ private final boolean reconnectOnSchemasChange;
+
+ private final SchemaContextFactory schemaContextFactory;
+ private final RemoteDeviceHandler<NetconfSessionPreferences> salFacade;
+ private final ListeningExecutorService processingExecutor;
+ private final SchemaSourceRegistry schemaRegistry;
+ private final NetconfStateSchemas.NetconfStateSchemasResolver stateSchemasResolver;
+ private final NotificationHandler notificationHandler;
+ private final List<SchemaSourceRegistration<? extends SchemaSourceRepresentation>> sourceRegistrations = Lists.newArrayList();
+
+ // Message transformer is constructed once the schemas are available
+ private MessageTransformer<NetconfMessage> messageTransformer;
+
+ public NetconfDevice(final SchemaResourcesDTO schemaResourcesDTO, final RemoteDeviceId id, final RemoteDeviceHandler<NetconfSessionPreferences> salFacade,
+ final ExecutorService globalProcessingExecutor) {
+ this(schemaResourcesDTO, id, salFacade, globalProcessingExecutor, false);
+ }
+
+ /**
+ * Create rpc implementation capable of handling RPC for monitoring and notifications even before the schemas of remote device are downloaded
+ */
+ static NetconfDeviceRpc getRpcForInitialization(final NetconfDeviceCommunicator listener) {
+ return new NetconfDeviceRpc(INIT_SCHEMA_CTX, listener, new NetconfMessageTransformer(INIT_SCHEMA_CTX, false));
+ }
+
+
+ // FIXME reduce parameters
+ public NetconfDevice(final SchemaResourcesDTO schemaResourcesDTO, final RemoteDeviceId id, final RemoteDeviceHandler<NetconfSessionPreferences> salFacade,
+ final ExecutorService globalProcessingExecutor, final boolean reconnectOnSchemasChange) {
+ this.id = id;
+ this.reconnectOnSchemasChange = reconnectOnSchemasChange;
+ this.schemaRegistry = schemaResourcesDTO.getSchemaRegistry();
+ this.schemaContextFactory = schemaResourcesDTO.getSchemaContextFactory();
+ this.salFacade = salFacade;
+ this.stateSchemasResolver = schemaResourcesDTO.getStateSchemasResolver();
+ this.processingExecutor = MoreExecutors.listeningDecorator(globalProcessingExecutor);
+ this.notificationHandler = new NotificationHandler(salFacade, id);
+ }
+
+ @Override
+ public void onRemoteSessionUp(final NetconfSessionPreferences remoteSessionCapabilities,
+ final NetconfDeviceCommunicator listener) {
+ // SchemaContext setup has to be performed in a dedicated thread since
+ // we are in a netty thread in this method
+ // Yang models are being downloaded in this method and it would cause a
+ // deadlock if we used the netty thread
+ // http://netty.io/wiki/thread-model.html
+ LOG.debug("{}: Session to remote device established with {}", id, remoteSessionCapabilities);
+
+ final NetconfDeviceRpc initRpc = getRpcForInitialization(listener);
+ final DeviceSourcesResolver task = new DeviceSourcesResolver(remoteSessionCapabilities, id, stateSchemasResolver, initRpc);
+ final ListenableFuture<DeviceSources> sourceResolverFuture = processingExecutor.submit(task);
+
+ if (shouldListenOnSchemaChange(remoteSessionCapabilities)) {
+ registerToBaseNetconfStream(initRpc, listener);
+ }
+
+ final FutureCallback<DeviceSources> resolvedSourceCallback = new FutureCallback<DeviceSources>() {
+ @Override
+ public void onSuccess(final DeviceSources result) {
+ addProvidedSourcesToSchemaRegistry(initRpc, result);
+ setUpSchema(result);
+ }
+
+ private void setUpSchema(final DeviceSources result) {
+ processingExecutor.submit(new RecursiveSchemaSetup(result, remoteSessionCapabilities, listener));
+ }
+
+ @Override
+ public void onFailure(final Throwable t) {
+ LOG.warn("{}: Unexpected error resolving device sources: {}", id, t);
+ handleSalInitializationFailure(t, listener);
+ }
+ };
+
+ Futures.addCallback(sourceResolverFuture, resolvedSourceCallback);
+ }
+
+ private void registerToBaseNetconfStream(final NetconfDeviceRpc deviceRpc, final NetconfDeviceCommunicator listener) {
+ // TODO check whether the model describing create subscription is present in schema
+ // Perhaps add a default schema context to support create-subscription if the model was not provided (same as what we do for base netconf operations in transformer)
+ final CheckedFuture<DOMRpcResult, DOMRpcException> rpcResultListenableFuture =
+ deviceRpc.invokeRpc(NetconfMessageTransformUtil.toPath(NetconfMessageTransformUtil.CREATE_SUBSCRIPTION_RPC_QNAME), NetconfMessageTransformUtil.CREATE_SUBSCRIPTION_RPC_CONTENT);
+
+ final NotificationHandler.NotificationFilter filter = new NotificationHandler.NotificationFilter() {
+ @Override
+ public Optional<DOMNotification> filterNotification(final DOMNotification notification) {
+ if (isCapabilityChanged(notification)) {
+ LOG.info("{}: Schemas change detected, reconnecting", id);
+ // Only disconnect is enough, the reconnecting nature of the connector will take care of reconnecting
+ listener.disconnect();
+ return Optional.absent();
+ }
+ return Optional.of(notification);
+ }
+
+ private boolean isCapabilityChanged(final DOMNotification notification) {
+ return notification.getBody().getNodeType().equals(NetconfCapabilityChange.QNAME);
+ }
+ };
+
+ Futures.addCallback(rpcResultListenableFuture, new FutureCallback<DOMRpcResult>() {
+ @Override
+ public void onSuccess(final DOMRpcResult domRpcResult) {
+ notificationHandler.addNotificationFilter(filter);
+ }
+
+ @Override
+ public void onFailure(final Throwable t) {
+ LOG.warn("Unable to subscribe to base notification stream. Schemas will not be reloaded on the fly", t);
+ }
+ });
+ }
+
+ private boolean shouldListenOnSchemaChange(final NetconfSessionPreferences remoteSessionCapabilities) {
+ return remoteSessionCapabilities.isNotificationsSupported() && reconnectOnSchemasChange;
+ }
+
+ @VisibleForTesting
+ void handleSalInitializationSuccess(final SchemaContext result, final NetconfSessionPreferences remoteSessionCapabilities, final DOMRpcService deviceRpc) {
+ messageTransformer = new NetconfMessageTransformer(result, true);
+
+ updateTransformer(messageTransformer);
+ // salFacade.onDeviceConnected has to be called before the notification handler is initialized
+ salFacade.onDeviceConnected(result, remoteSessionCapabilities, deviceRpc);
+ notificationHandler.onRemoteSchemaUp(messageTransformer);
+
+ LOG.info("{}: Netconf connector initialized successfully", id);
+ }
+
+ private void handleSalInitializationFailure(final Throwable t, final RemoteDeviceCommunicator<NetconfMessage> listener) {
+ LOG.error("{}: Initialization in sal failed, disconnecting from device", id, t);
+ listener.close();
+ onRemoteSessionDown();
+ resetMessageTransformer();
+ }
+
+ /**
+ * Set the transformer to null as is in initial state
+ */
+ private void resetMessageTransformer() {
+ updateTransformer(null);
+ }
+
+ private void updateTransformer(final MessageTransformer<NetconfMessage> transformer) {
+ messageTransformer = transformer;
+ }
+
+ private void addProvidedSourcesToSchemaRegistry(final NetconfDeviceRpc deviceRpc, final DeviceSources deviceSources) {
+ final NetconfRemoteSchemaYangSourceProvider yangProvider = new NetconfRemoteSchemaYangSourceProvider(id, deviceRpc);
+ for (final SourceIdentifier sourceId : deviceSources.getProvidedSources()) {
+ sourceRegistrations.add(schemaRegistry.registerSchemaSource(yangProvider,
+ PotentialSchemaSource.create(sourceId, YangTextSchemaSource.class, PotentialSchemaSource.Costs.REMOTE_IO.getValue())));
+ }
+ }
+
+ @Override
+ public void onRemoteSessionDown() {
+ notificationHandler.onRemoteSchemaDown();
+
+ salFacade.onDeviceDisconnected();
+ for (final SchemaSourceRegistration<? extends SchemaSourceRepresentation> sourceRegistration : sourceRegistrations) {
+ sourceRegistration.close();
+ }
+ resetMessageTransformer();
+ }
+
+ @Override
+ public void onRemoteSessionFailed(final Throwable throwable) {
+ salFacade.onDeviceFailed(throwable);
+ }
+
+ @Override
+ public void onNotification(final NetconfMessage notification) {
+ notificationHandler.handleNotification(notification);
+ }
+
+ /**
+ * Just a transfer object containing schema related dependencies. Injected in constructor.
+ */
+ public static class SchemaResourcesDTO {
+ private final SchemaSourceRegistry schemaRegistry;
+ private final SchemaContextFactory schemaContextFactory;
+ private final NetconfStateSchemas.NetconfStateSchemasResolver stateSchemasResolver;
+
+ public SchemaResourcesDTO(final SchemaSourceRegistry schemaRegistry, final SchemaContextFactory schemaContextFactory, final NetconfStateSchemas.NetconfStateSchemasResolver stateSchemasResolver) {
+ this.schemaRegistry = Preconditions.checkNotNull(schemaRegistry);
+ this.schemaContextFactory = Preconditions.checkNotNull(schemaContextFactory);
+ this.stateSchemasResolver = Preconditions.checkNotNull(stateSchemasResolver);
+ }
+
+ public SchemaSourceRegistry getSchemaRegistry() {
+ return schemaRegistry;
+ }
+
+ public SchemaContextFactory getSchemaContextFactory() {
+ return schemaContextFactory;
+ }
+
+ public NetconfStateSchemas.NetconfStateSchemasResolver getStateSchemasResolver() {
+ return stateSchemasResolver;
+ }
+ }
+
+ /**
+ * Schema building callable.
+ */
+ private static class DeviceSourcesResolver implements Callable<DeviceSources> {
+
+ private final NetconfDeviceRpc deviceRpc;
+ private final NetconfSessionPreferences remoteSessionCapabilities;
+ private final RemoteDeviceId id;
+ private final NetconfStateSchemas.NetconfStateSchemasResolver stateSchemasResolver;
+
+ DeviceSourcesResolver(final NetconfDeviceRpc deviceRpc, final NetconfSessionPreferences remoteSessionCapabilities,
+ final RemoteDeviceId id, final NetconfStateSchemas.NetconfStateSchemasResolver stateSchemasResolver) {
+ this.deviceRpc = deviceRpc;
+ this.remoteSessionCapabilities = remoteSessionCapabilities;
+ this.id = id;
+ this.stateSchemasResolver = stateSchemasResolver;
+ }
+
+ public DeviceSourcesResolver(final NetconfSessionPreferences remoteSessionCapabilities, final RemoteDeviceId id, final NetconfStateSchemas.NetconfStateSchemasResolver stateSchemasResolver, final NetconfDeviceRpc rpcForMonitoring) {
+ this(rpcForMonitoring, remoteSessionCapabilities, id, stateSchemasResolver);
+ }
+
+ @Override
+ public DeviceSources call() throws Exception {
+ final NetconfStateSchemas availableSchemas = stateSchemasResolver.resolve(deviceRpc, remoteSessionCapabilities, id);
+ LOG.debug("{}: Schemas exposed by ietf-netconf-monitoring: {}", id, availableSchemas.getAvailableYangSchemasQNames());
+
+ final Set<QName> requiredSources = Sets.newHashSet(remoteSessionCapabilities.getModuleBasedCaps());
+ final Set<QName> providedSources = availableSchemas.getAvailableYangSchemasQNames();
+
+ final Set<QName> requiredSourcesNotProvided = Sets.difference(requiredSources, providedSources);
+ if (!requiredSourcesNotProvided.isEmpty()) {
+ LOG.warn("{}: Netconf device does not provide all yang models reported in hello message capabilities, required but not provided: {}",
+ id, requiredSourcesNotProvided);
+ LOG.warn("{}: Attempting to build schema context from required sources", id);
+ }
+
+ // Here all the sources reported in netconf monitoring are merged with those reported in hello.
+ // It is necessary to perform this since submodules are not mentioned in hello but still required.
+ // This clashes with the option of a user to specify supported yang models manually in configuration for netconf-connector
+ // and as a result one is not able to fully override yang models of a device. It is only possible to add additional models.
+ final Set<QName> providedSourcesNotRequired = Sets.difference(providedSources, requiredSources);
+ if (!providedSourcesNotRequired.isEmpty()) {
+ LOG.warn("{}: Netconf device provides additional yang models not reported in hello message capabilities: {}",
+ id, providedSourcesNotRequired);
+ LOG.warn("{}: Adding provided but not required sources as required to prevent failures", id);
+ LOG.debug("{}: Netconf device reported in hello: {}", id, requiredSources);
+ requiredSources.addAll(providedSourcesNotRequired);
+ }
+
+ return new DeviceSources(requiredSources, providedSources);
+ }
+ }
+
+ /**
+ * Contains RequiredSources - sources from capabilities.
+ */
+ private static final class DeviceSources {
+ private final Set<QName> requiredSources;
+ private final Set<QName> providedSources;
+
+ public DeviceSources(final Set<QName> requiredSources, final Set<QName> providedSources) {
+ this.requiredSources = requiredSources;
+ this.providedSources = providedSources;
+ }
+
+ public Set<QName> getRequiredSourcesQName() {
+ return requiredSources;
+ }
+
+ public Set<QName> getProvidedSourcesQName() {
+ return providedSources;
+ }
+
+ public Collection<SourceIdentifier> getRequiredSources() {
+ return Collections2.transform(requiredSources, QNAME_TO_SOURCE_ID_FUNCTION);
+ }
+
+ public Collection<SourceIdentifier> getProvidedSources() {
+ return Collections2.transform(providedSources, QNAME_TO_SOURCE_ID_FUNCTION);
+ }
+
+ }
+
+ /**
+ * Schema builder that tries to build schema context from provided sources or biggest subset of it.
+ */
+ private final class RecursiveSchemaSetup implements Runnable {
+ private final DeviceSources deviceSources;
+ private final NetconfSessionPreferences remoteSessionCapabilities;
+ private final RemoteDeviceCommunicator<NetconfMessage> listener;
+ private final NetconfDeviceCapabilities capabilities;
+
+ public RecursiveSchemaSetup(final DeviceSources deviceSources, final NetconfSessionPreferences remoteSessionCapabilities, final RemoteDeviceCommunicator<NetconfMessage> listener) {
+ this.deviceSources = deviceSources;
+ this.remoteSessionCapabilities = remoteSessionCapabilities;
+ this.listener = listener;
+ this.capabilities = remoteSessionCapabilities.getNetconfDeviceCapabilities();
+ }
+
+ @Override
+ public void run() {
+ setUpSchema(deviceSources.getRequiredSources());
+ }
+
+ /**
+ * Recursively build schema context, in case of success or final failure notify device
+ */
+ // FIXME reimplement without recursion
+ private void setUpSchema(final Collection<SourceIdentifier> requiredSources) {
+ LOG.trace("{}: Trying to build schema context from {}", id, requiredSources);
+
+ // If no more sources, fail
+ if(requiredSources.isEmpty()) {
+ final IllegalStateException cause = new IllegalStateException(id + ": No more sources for schema context");
+ handleSalInitializationFailure(cause, listener);
+ salFacade.onDeviceFailed(cause);
+ return;
+ }
+
+ final CheckedFuture<SchemaContext, SchemaResolutionException> schemaBuilderFuture = schemaContextFactory.createSchemaContext(requiredSources);
+
+ final FutureCallback<SchemaContext> RecursiveSchemaBuilderCallback = new FutureCallback<SchemaContext>() {
+
+ @Override
+ public void onSuccess(final SchemaContext result) {
+ LOG.debug("{}: Schema context built successfully from {}", id, requiredSources);
+ final Collection<QName> filteredQNames = Sets.difference(deviceSources.getProvidedSourcesQName(), capabilities.getUnresolvedCapabilites().keySet());
+ capabilities.addCapabilities(filteredQNames);
+ capabilities.addNonModuleBasedCapabilities(remoteSessionCapabilities.getNonModuleCaps());
+ handleSalInitializationSuccess(result, remoteSessionCapabilities, getDeviceSpecificRpc(result));
+ }
+
+ @Override
+ public void onFailure(final Throwable t) {
+ // In case source missing, try without it
+ if (t instanceof MissingSchemaSourceException) {
+ final SourceIdentifier missingSource = ((MissingSchemaSourceException) t).getSourceId();
+ LOG.warn("{}: Unable to build schema context, missing source {}, will reattempt without it", id, missingSource);
+ capabilities.addUnresolvedCapabilities(getQNameFromSourceIdentifiers(Sets.newHashSet(missingSource)), UnavailableCapability.FailureReason.MissingSource);
+ setUpSchema(stripMissingSource(requiredSources, missingSource));
+
+ // In case resolution error, try only with resolved sources
+ } else if (t instanceof SchemaResolutionException) {
+ // TODO check for infinite loop
+ final SchemaResolutionException resolutionException = (SchemaResolutionException) t;
+ final Set<SourceIdentifier> unresolvedSources = resolutionException.getUnsatisfiedImports().keySet();
+ capabilities.addUnresolvedCapabilities(getQNameFromSourceIdentifiers(unresolvedSources), UnavailableCapability.FailureReason.UnableToResolve);
+ LOG.warn("{}: Unable to build schema context, unsatisfied imports {}, will reattempt with resolved only", id, resolutionException.getUnsatisfiedImports());
+ setUpSchema(resolutionException.getResolvedSources());
+ // unknown error, fail
+ } else {
+ handleSalInitializationFailure(t, listener);
+ }
+ }
+ };
+
+ Futures.addCallback(schemaBuilderFuture, RecursiveSchemaBuilderCallback);
+ }
+
+ private NetconfDeviceRpc getDeviceSpecificRpc(final SchemaContext result) {
+ return new NetconfDeviceRpc(result, listener, new NetconfMessageTransformer(result, true));
+ }
+
+ private Collection<SourceIdentifier> stripMissingSource(final Collection<SourceIdentifier> requiredSources, final SourceIdentifier sIdToRemove) {
+ final LinkedList<SourceIdentifier> sourceIdentifiers = Lists.newLinkedList(requiredSources);
+ final boolean removed = sourceIdentifiers.remove(sIdToRemove);
+ Preconditions.checkState(removed, "{}: Trying to remove {} from {} failed", id, sIdToRemove, requiredSources);
+ return sourceIdentifiers;
+ }
+
+ private Collection<QName> getQNameFromSourceIdentifiers(final Collection<SourceIdentifier> identifiers) {
+ final Collection<QName> qNames = Collections2.transform(identifiers, new Function<SourceIdentifier, QName>() {
+ @Override
+ public QName apply(final SourceIdentifier sourceIdentifier) {
+ return getQNameFromSourceIdentifier(sourceIdentifier);
+ }
+ });
+
+ if (qNames.isEmpty()) {
+ LOG.debug("{}: Unable to map any source identfiers to a capability reported by device : {}", id, identifiers);
+ }
+ return qNames;
+ }
+
+ private QName getQNameFromSourceIdentifier(final SourceIdentifier identifier) {
+ // Required sources are all required and provided merged in DeviceSourcesResolver
+ for (final QName qname : deviceSources.getRequiredSourcesQName()) {
+ if(qname.getLocalName().equals(identifier.getName()) == false) {
+ continue;
+ }
+
+ if(identifier.getRevision().equals(SourceIdentifier.NOT_PRESENT_FORMATTED_REVISION) &&
+ qname.getRevision() == null) {
+ return qname;
+ }
+
+ if (qname.getFormattedRevision().equals(identifier.getRevision())) {
+ return qname;
+ }
+ }
+ throw new IllegalArgumentException("Unable to map identifier to a devices reported capability: " + identifier + " Available: " + deviceSources.getRequiredSourcesQName());
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015 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.connect.netconf;
+
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_DATA_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_GET_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.toId;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.toPath;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Sets;
+import java.net.URI;
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.controller.sal.connect.netconf.listener.NetconfSessionPreferences;
+import org.opendaylight.controller.sal.connect.netconf.sal.NetconfDeviceRpc;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.Yang;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.Schema;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Holds QNames for all yang modules reported by ietf-netconf-monitoring/state/schemas
+ */
+public final class NetconfStateSchemas {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfStateSchemas.class);
+
+ /**
+ * Factory for NetconfStateSchemas
+ */
+ public interface NetconfStateSchemasResolver {
+ NetconfStateSchemas resolve(final NetconfDeviceRpc deviceRpc, final NetconfSessionPreferences remoteSessionCapabilities, final RemoteDeviceId id);
+ }
+
+ /**
+ * Default implementation resolving schemas QNames from netconf-state
+ */
+ public static final class NetconfStateSchemasResolverImpl implements NetconfStateSchemasResolver {
+
+ @Override
+ public NetconfStateSchemas resolve(final NetconfDeviceRpc deviceRpc, final NetconfSessionPreferences remoteSessionCapabilities, final RemoteDeviceId id) {
+ return NetconfStateSchemas.create(deviceRpc, remoteSessionCapabilities, id);
+ }
+ }
+
+ public static final NetconfStateSchemas EMPTY = new NetconfStateSchemas(Collections.<RemoteYangSchema>emptySet());
+
+ private static final YangInstanceIdentifier STATE_SCHEMAS_IDENTIFIER =
+ YangInstanceIdentifier.builder().node(NetconfState.QNAME).node(Schemas.QNAME).build();
+
+ private static final ContainerNode GET_SCHEMAS_RPC;
+ static {
+ final DataContainerChild<?, ?> filter = NetconfMessageTransformUtil.toFilterStructure(STATE_SCHEMAS_IDENTIFIER, NetconfDevice.INIT_SCHEMA_CTX);
+ GET_SCHEMAS_RPC
+ = Builders.containerBuilder().withNodeIdentifier(toId(NETCONF_GET_QNAME)).withChild(filter).build();
+ }
+
+ private final Set<RemoteYangSchema> availableYangSchemas;
+
+ public NetconfStateSchemas(final Set<RemoteYangSchema> availableYangSchemas) {
+ this.availableYangSchemas = availableYangSchemas;
+ }
+
+ public Set<RemoteYangSchema> getAvailableYangSchemas() {
+ return availableYangSchemas;
+ }
+
+ public Set<QName> getAvailableYangSchemasQNames() {
+ return Sets.newHashSet(Collections2.transform(getAvailableYangSchemas(), new Function<RemoteYangSchema, QName>() {
+ @Override
+ public QName apply(final RemoteYangSchema input) {
+ return input.getQName();
+ }
+ }));
+ }
+
+ /**
+ * Issue get request to remote device and parse response to find all schemas under netconf-state/schemas
+ */
+ private static NetconfStateSchemas create(final NetconfDeviceRpc deviceRpc, final NetconfSessionPreferences remoteSessionCapabilities, final RemoteDeviceId id) {
+ if(remoteSessionCapabilities.isMonitoringSupported() == false) {
+ LOG.warn("{}: Netconf monitoring not supported on device, cannot detect provided schemas", id);
+ return EMPTY;
+ }
+
+ final DOMRpcResult schemasNodeResult;
+ try {
+ schemasNodeResult = deviceRpc.invokeRpc(toPath(NETCONF_GET_QNAME), GET_SCHEMAS_RPC).get();
+ } catch (final InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new RuntimeException(id + ": Interrupted while waiting for response to " + STATE_SCHEMAS_IDENTIFIER, e);
+ } catch (final ExecutionException e) {
+ LOG.warn("{}: Unable to detect available schemas, get to {} failed", id, STATE_SCHEMAS_IDENTIFIER, e);
+ return EMPTY;
+ }
+
+ if(schemasNodeResult.getErrors().isEmpty() == false) {
+ LOG.warn("{}: Unable to detect available schemas, get to {} failed, {}", id, STATE_SCHEMAS_IDENTIFIER, schemasNodeResult.getErrors());
+ return EMPTY;
+ }
+
+ final Optional<? extends NormalizedNode<?, ?>> schemasNode = findSchemasNode(schemasNodeResult.getResult());
+
+ if(schemasNode.isPresent()) {
+ Preconditions.checkState(schemasNode.get() instanceof ContainerNode,
+ "Expecting container containing schemas, but was %s", schemasNode.get());
+ return create(id, ((ContainerNode) schemasNode.get()));
+ } else {
+ LOG.warn("{}: Unable to detect available schemas, get to {} was empty", id, STATE_SCHEMAS_IDENTIFIER);
+ return EMPTY;
+ }
+ }
+
+ private static Optional<? extends NormalizedNode<?, ?>> findSchemasNode(final NormalizedNode<?, ?> result) {
+ if(result == null) {
+ return Optional.absent();
+ }
+ final Optional<DataContainerChild<?, ?>> dataNode = ((DataContainerNode<?>) result).getChild(toId(NETCONF_DATA_QNAME));
+ if(dataNode.isPresent() == false) {
+ return Optional.absent();
+ }
+
+ final Optional<DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?>> nStateNode =
+ ((DataContainerNode<?>) dataNode.get()).getChild(toId(NetconfState.QNAME));
+ if(nStateNode.isPresent() == false) {
+ return Optional.absent();
+ }
+
+ return ((DataContainerNode<?>) nStateNode.get()).getChild(toId(Schemas.QNAME));
+ }
+
+ /**
+ * Parse response of get(netconf-state/schemas) to find all schemas under netconf-state/schemas
+ */
+ @VisibleForTesting
+ protected static NetconfStateSchemas create(final RemoteDeviceId id, final ContainerNode schemasNode) {
+ final Set<RemoteYangSchema> availableYangSchemas = Sets.newHashSet();
+
+ final Optional<DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?>> child = schemasNode.getChild(toId(Schema.QNAME));
+ Preconditions.checkState(child.isPresent(), "Unable to find list: %s in response: %s", Schema.QNAME.withoutRevision(), schemasNode);
+ Preconditions.checkState(child.get() instanceof MapNode, "Unexpected structure for container: %s in response: %s. Expecting a list", Schema.QNAME.withoutRevision(), schemasNode);
+
+ for (final MapEntryNode schemaNode : ((MapNode) child.get()).getValue()) {
+ final Optional<RemoteYangSchema> fromCompositeNode = RemoteYangSchema.createFromNormalizedNode(id, schemaNode);
+ if(fromCompositeNode.isPresent()) {
+ availableYangSchemas.add(fromCompositeNode.get());
+ }
+ }
+
+ return new NetconfStateSchemas(availableYangSchemas);
+ }
+
+ public final static class RemoteYangSchema {
+ private final QName qname;
+
+ RemoteYangSchema(final QName qname) {
+ this.qname = qname;
+ }
+
+ public QName getQName() {
+ return qname;
+ }
+
+ static Optional<RemoteYangSchema> createFromNormalizedNode(final RemoteDeviceId id, final MapEntryNode schemaNode) {
+ Preconditions.checkArgument(schemaNode.getNodeType().equals(Schema.QNAME), "Wrong QName %s", schemaNode.getNodeType());
+
+ QName childNode = NetconfMessageTransformUtil.IETF_NETCONF_MONITORING_SCHEMA_FORMAT;
+
+ String formatAsString = getSingleChildNodeValue(schemaNode, childNode).get();
+
+ if(formatAsString.equals(Yang.QNAME.toString()) == false) {
+ LOG.debug("{}: Ignoring schema due to unsupported format: {}", id, formatAsString);
+ return Optional.absent();
+ }
+
+ childNode = NetconfMessageTransformUtil.IETF_NETCONF_MONITORING_SCHEMA_LOCATION;
+ final Set<String> locationsAsString = getAllChildNodeValues(schemaNode, childNode);
+ if(locationsAsString.contains(Schema.Location.Enumeration.NETCONF.toString()) == false) {
+ LOG.debug("{}: Ignoring schema due to unsupported location: {}", id, locationsAsString);
+ return Optional.absent();
+ }
+
+ childNode = NetconfMessageTransformUtil.IETF_NETCONF_MONITORING_SCHEMA_NAMESPACE;
+ final String namespaceAsString = getSingleChildNodeValue(schemaNode, childNode).get();
+
+ childNode = NetconfMessageTransformUtil.IETF_NETCONF_MONITORING_SCHEMA_VERSION;
+ // Revision does not have to be filled
+ final Optional<String> revisionAsString = getSingleChildNodeValue(schemaNode, childNode);
+
+ childNode = NetconfMessageTransformUtil.IETF_NETCONF_MONITORING_SCHEMA_IDENTIFIER;
+ final String moduleNameAsString = getSingleChildNodeValue(schemaNode, childNode).get();
+
+ final QName moduleQName = revisionAsString.isPresent()
+ ? QName.create(namespaceAsString, revisionAsString.get(), moduleNameAsString)
+ : QName.create(URI.create(namespaceAsString), null, moduleNameAsString);
+
+ return Optional.of(new RemoteYangSchema(moduleQName));
+ }
+
+ /**
+ * Extracts all values of a leaf-list node as a set of strings
+ */
+ private static Set<String> getAllChildNodeValues(final DataContainerNode<?> schemaNode, final QName childNodeQName) {
+ final Set<String> extractedValues = Sets.newHashSet();
+ final Optional<DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?>> child = schemaNode.getChild(toId(childNodeQName));
+ Preconditions.checkArgument(child.isPresent(), "Child nodes %s not present", childNodeQName);
+ Preconditions.checkArgument(child.get() instanceof LeafSetNode<?>, "Child nodes %s not present", childNodeQName);
+ for (final LeafSetEntryNode<?> childNode : ((LeafSetNode<?>) child.get()).getValue()) {
+ extractedValues.add(getValueOfSimpleNode(childNode).get());
+ }
+ return extractedValues;
+ }
+
+ private static Optional<String> getSingleChildNodeValue(final DataContainerNode<?> schemaNode, final QName childNode) {
+ final Optional<DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?>> node = schemaNode.getChild(toId(childNode));
+ Preconditions.checkArgument(node.isPresent(), "Child node %s not present", childNode);
+ return getValueOfSimpleNode(node.get());
+ }
+
+ private static Optional<String> getValueOfSimpleNode(final NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?> node) {
+ final Object value = node.getValue();
+ return value == null || Strings.isNullOrEmpty(value.toString()) ? Optional.<String>absent() : Optional.of(value.toString().trim());
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ final RemoteYangSchema that = (RemoteYangSchema) o;
+
+ if (!qname.equals(that.qname)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return qname.hashCode();
+ }
+ }
+}
--- /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.connect.netconf;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import java.util.LinkedList;
+import java.util.List;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.sal.connect.api.MessageTransformer;
+import org.opendaylight.controller.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Handles incoming notifications. Either caches them(until onRemoteSchemaUp is called) or passes to sal Facade.
+ */
+final class NotificationHandler {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NotificationHandler.class);
+
+ private final RemoteDeviceHandler<?> salFacade;
+ private final List<NetconfMessage> queue = new LinkedList<>();
+ private final RemoteDeviceId id;
+ private boolean passNotifications = false;
+
+ private NotificationFilter filter;
+ private MessageTransformer<NetconfMessage> messageTransformer;
+
+ NotificationHandler(final RemoteDeviceHandler<?> salFacade, final RemoteDeviceId id) {
+ this.salFacade = Preconditions.checkNotNull(salFacade);
+ this.id = Preconditions.checkNotNull(id);
+ }
+
+ synchronized void handleNotification(final NetconfMessage notification) {
+ if(passNotifications) {
+ passNotification(transformNotification(notification));
+ } else {
+ queueNotification(notification);
+ }
+ }
+
+ /**
+ * Forward all cached notifications and pass all notifications from this point directly to sal facade.
+ * @param messageTransformer
+ */
+ synchronized void onRemoteSchemaUp(final MessageTransformer<NetconfMessage> messageTransformer) {
+ this.messageTransformer = Preconditions.checkNotNull(messageTransformer);
+
+ passNotifications = true;
+
+ for (final NetconfMessage cachedNotification : queue) {
+ passNotification(transformNotification(cachedNotification));
+ }
+
+ queue.clear();
+ }
+
+ private DOMNotification transformNotification(final NetconfMessage cachedNotification) {
+ final DOMNotification parsedNotification = messageTransformer.toNotification(cachedNotification);
+ Preconditions.checkNotNull(parsedNotification, "%s: Unable to parse received notification: %s", id, cachedNotification);
+ return parsedNotification;
+ }
+
+ private void queueNotification(final NetconfMessage notification) {
+ Preconditions.checkState(passNotifications == false);
+
+ LOG.debug("{}: Caching notification {}, remote schema not yet fully built", id, notification);
+ if(LOG.isTraceEnabled()) {
+ LOG.trace("{}: Caching notification {}", id, XmlUtil.toString(notification.getDocument()));
+ }
+
+ queue.add(notification);
+ }
+
+ private synchronized void passNotification(final DOMNotification parsedNotification) {
+ LOG.debug("{}: Forwarding notification {}", id, parsedNotification);
+
+ if(filter == null || filter.filterNotification(parsedNotification).isPresent()) {
+ salFacade.onNotification(parsedNotification);
+ }
+ }
+
+ synchronized void addNotificationFilter(final NotificationFilter filter) {
+ this.filter = filter;
+ }
+
+ synchronized void onRemoteSchemaDown() {
+ queue.clear();
+ passNotifications = false;
+ messageTransformer = null;
+ }
+
+ static interface NotificationFilter {
+
+ Optional<DOMNotification> filterNotification(DOMNotification notification);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.connect.netconf.listener;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.fields.unavailable.capabilities.UnavailableCapability.FailureReason;
+import org.opendaylight.yangtools.yang.common.QName;
+
+public final class NetconfDeviceCapabilities {
+ private final Map<QName, FailureReason> unresolvedCapabilites;
+ private final Set<QName> resolvedCapabilities;
+
+ private final Set<String> nonModuleBasedCapabilities;
+
+ public NetconfDeviceCapabilities() {
+ this.unresolvedCapabilites = new HashMap<>();
+ this.resolvedCapabilities = new HashSet<>();
+ this.nonModuleBasedCapabilities = new HashSet<>();
+ }
+
+ public void addUnresolvedCapability(QName source, FailureReason reason) {
+ unresolvedCapabilites.put(source, reason);
+ }
+
+ public void addUnresolvedCapabilities(Collection<QName> capabilities, FailureReason reason) {
+ for (QName s : capabilities) {
+ unresolvedCapabilites.put(s, reason);
+ }
+ }
+
+ public void addCapabilities(Collection<QName> availableSchemas) {
+ resolvedCapabilities.addAll(availableSchemas);
+ }
+
+ public void addNonModuleBasedCapabilities(Collection<String> nonModuleCapabilities) {
+ this.nonModuleBasedCapabilities.addAll(nonModuleCapabilities);
+ }
+
+ public Set<String> getNonModuleBasedCapabilities() {
+ return nonModuleBasedCapabilities;
+ }
+
+ public Map<QName, FailureReason> getUnresolvedCapabilites() {
+ return unresolvedCapabilites;
+ }
+
+ public Set<QName> getResolvedCapabilities() {
+ return resolvedCapabilities;
+ }
+
+}
--- /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.connect.netconf.listener;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import io.netty.util.concurrent.Future;
+import io.netty.util.concurrent.FutureListener;
+import io.netty.util.concurrent.GenericFutureListener;
+import java.util.ArrayDeque;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.client.NetconfClientSession;
+import org.opendaylight.controller.netconf.client.NetconfClientSessionListener;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
+import org.opendaylight.controller.netconf.client.conf.NetconfReconnectingClientConfiguration;
+import org.opendaylight.controller.sal.connect.api.RemoteDevice;
+import org.opendaylight.controller.sal.connect.api.RemoteDeviceCommunicator;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+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.common.RpcResultBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetconfDeviceCommunicator implements NetconfClientSessionListener, RemoteDeviceCommunicator<NetconfMessage> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfDeviceCommunicator.class);
+
+ private final RemoteDevice<NetconfSessionPreferences, NetconfMessage, NetconfDeviceCommunicator> remoteDevice;
+ private final Optional<NetconfSessionPreferences> overrideNetconfCapabilities;
+ private final RemoteDeviceId id;
+ private final Lock sessionLock = new ReentrantLock();
+
+ // TODO implement concurrent message limit
+ private final Queue<Request> requests = new ArrayDeque<>();
+ private NetconfClientSession session;
+ private Future<?> initFuture;
+
+ public NetconfDeviceCommunicator(final RemoteDeviceId id, final RemoteDevice<NetconfSessionPreferences, NetconfMessage, NetconfDeviceCommunicator> remoteDevice,
+ final NetconfSessionPreferences NetconfSessionPreferences) {
+ this(id, remoteDevice, Optional.of(NetconfSessionPreferences));
+ }
+
+ public NetconfDeviceCommunicator(final RemoteDeviceId id,
+ final RemoteDevice<NetconfSessionPreferences, NetconfMessage, NetconfDeviceCommunicator> remoteDevice) {
+ this(id, remoteDevice, Optional.<NetconfSessionPreferences>absent());
+ }
+
+ private NetconfDeviceCommunicator(final RemoteDeviceId id, final RemoteDevice<NetconfSessionPreferences, NetconfMessage, NetconfDeviceCommunicator> remoteDevice,
+ final Optional<NetconfSessionPreferences> overrideNetconfCapabilities) {
+ this.id = id;
+ this.remoteDevice = remoteDevice;
+ this.overrideNetconfCapabilities = overrideNetconfCapabilities;
+ }
+
+ @Override
+ public void onSessionUp(final NetconfClientSession session) {
+ sessionLock.lock();
+ try {
+ LOG.debug("{}: Session established", id);
+ this.session = session;
+
+ NetconfSessionPreferences netconfSessionPreferences =
+ NetconfSessionPreferences.fromNetconfSession(session);
+ LOG.trace("{}: Session advertised capabilities: {}", id,
+ netconfSessionPreferences);
+
+ if(overrideNetconfCapabilities.isPresent()) {
+ netconfSessionPreferences = netconfSessionPreferences.addModuleCaps(overrideNetconfCapabilities.get());
+ LOG.debug(
+ "{}: Session capabilities overridden, capabilities that will be used: {}",
+ id, netconfSessionPreferences);
+ }
+
+ remoteDevice.onRemoteSessionUp(netconfSessionPreferences, this);
+ }
+ finally {
+ sessionLock.unlock();
+ }
+ }
+
+ public void initializeRemoteConnection(final NetconfClientDispatcher dispatcher, final NetconfClientConfiguration config) {
+ // TODO 2313 extract listener from configuration
+ if(config instanceof NetconfReconnectingClientConfiguration) {
+ initFuture = dispatcher.createReconnectingClient((NetconfReconnectingClientConfiguration) config);
+ } else {
+ initFuture = dispatcher.createClient(config);
+ }
+
+
+ initFuture.addListener(new GenericFutureListener<Future<Object>>(){
+
+ @Override
+ public void operationComplete(Future<Object> future) throws Exception {
+ if (!future.isSuccess() && !future.isCancelled()) {
+ LOG.debug("{}: Connection failed", id, future.cause());
+ NetconfDeviceCommunicator.this.remoteDevice.onRemoteSessionFailed(future.cause());
+ }
+ }
+ });
+
+ }
+
+ public void disconnect() {
+ if(session != null) {
+ session.close();
+ }
+ }
+
+ private void tearDown( String reason ) {
+ List<UncancellableFuture<RpcResult<NetconfMessage>>> futuresToCancel = Lists.newArrayList();
+ sessionLock.lock();
+ try {
+ if( session != null ) {
+ session = null;
+
+ /*
+ * Walk all requests, check if they have been executing
+ * or cancelled and remove them from the queue.
+ */
+ final Iterator<Request> it = requests.iterator();
+ while (it.hasNext()) {
+ final Request r = it.next();
+ if (r.future.isUncancellable()) {
+ futuresToCancel.add( r.future );
+ it.remove();
+ } else if (r.future.isCancelled()) {
+ // This just does some house-cleaning
+ it.remove();
+ }
+ }
+
+ remoteDevice.onRemoteSessionDown();
+ }
+ }
+ finally {
+ sessionLock.unlock();
+ }
+
+ // Notify pending request futures outside of the sessionLock to avoid unnecessarily
+ // blocking the caller.
+ for( UncancellableFuture<RpcResult<NetconfMessage>> future: futuresToCancel ) {
+ if( Strings.isNullOrEmpty( reason ) ) {
+ future.set( createSessionDownRpcResult() );
+ } else {
+ future.set( createErrorRpcResult( RpcError.ErrorType.TRANSPORT, reason ) );
+ }
+ }
+ }
+
+ private RpcResult<NetconfMessage> createSessionDownRpcResult() {
+ return createErrorRpcResult( RpcError.ErrorType.TRANSPORT,
+ String.format( "The netconf session to %1$s is disconnected", id.getName() ) );
+ }
+
+ private RpcResult<NetconfMessage> createErrorRpcResult( RpcError.ErrorType errorType, String message ) {
+ return RpcResultBuilder.<NetconfMessage>failed()
+ .withError(errorType, NetconfDocumentedException.ErrorTag.operation_failed.getTagValue(), message).build();
+ }
+
+ @Override
+ public void onSessionDown(final NetconfClientSession session, final Exception e) {
+ LOG.warn("{}: Session went down", id, e);
+ tearDown( null );
+ }
+
+ @Override
+ public void onSessionTerminated(final NetconfClientSession session, final NetconfTerminationReason reason) {
+ LOG.warn("{}: Session terminated {}", id, reason);
+ tearDown( reason.getErrorMessage() );
+ }
+
+ @Override
+ public void close() {
+ // Cancel reconnect if in progress
+ if(initFuture != null) {
+ initFuture.cancel(false);
+ }
+ // Disconnect from device
+ if(session != null) {
+ session.close();
+ // tear down not necessary, called indirectly by above close
+ }
+ }
+
+ @Override
+ public void onMessage(final NetconfClientSession session, final NetconfMessage message) {
+ /*
+ * Dispatch between notifications and messages. Messages need to be processed
+ * with lock held, notifications do not.
+ */
+ if (isNotification(message)) {
+ processNotification(message);
+ } else {
+ processMessage(message);
+ }
+ }
+
+ private void processMessage(final NetconfMessage message) {
+ Request request = null;
+ sessionLock.lock();
+
+ try {
+ request = requests.peek();
+ if (request != null && request.future.isUncancellable()) {
+ requests.poll();
+ } else {
+ request = null;
+ LOG.warn("{}: Ignoring unsolicited message {}", id,
+ msgToS(message));
+ }
+ }
+ finally {
+ sessionLock.unlock();
+ }
+
+ if( request != null ) {
+
+ LOG.debug("{}: Message received {}", id, message);
+
+ if(LOG.isTraceEnabled()) {
+ LOG.trace( "{}: Matched request: {} to response: {}", id, msgToS( request.request ), msgToS( message ) );
+ }
+
+ try {
+ NetconfMessageTransformUtil.checkValidReply( request.request, message );
+ } catch (final NetconfDocumentedException e) {
+ LOG.warn(
+ "{}: Invalid request-reply match, reply message contains different message-id, request: {}, response: {}",
+ id, msgToS(request.request), msgToS(message), e);
+
+ request.future.set( RpcResultBuilder.<NetconfMessage>failed()
+ .withRpcError( NetconfMessageTransformUtil.toRpcError( e ) ).build() );
+
+ //recursively processing message to eventually find matching request
+ processMessage(message);
+
+ return;
+ }
+
+ try {
+ NetconfMessageTransformUtil.checkSuccessReply(message);
+ } catch(final NetconfDocumentedException e) {
+ LOG.warn(
+ "{}: Error reply from remote device, request: {}, response: {}",
+ id, msgToS(request.request), msgToS(message), e);
+
+ request.future.set( RpcResultBuilder.<NetconfMessage>failed()
+ .withRpcError( NetconfMessageTransformUtil.toRpcError( e ) ).build() );
+ return;
+ }
+
+ request.future.set( RpcResultBuilder.success( message ).build() );
+ }
+ }
+
+ private static String msgToS(final NetconfMessage msg) {
+ return XmlUtil.toString(msg.getDocument());
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<NetconfMessage>> sendRequest(final NetconfMessage message, final QName rpc) {
+ sessionLock.lock();
+ try {
+ return sendRequestWithLock( message, rpc );
+ } finally {
+ sessionLock.unlock();
+ }
+ }
+
+ private ListenableFuture<RpcResult<NetconfMessage>> sendRequestWithLock(
+ final NetconfMessage message, final QName rpc) {
+ if(LOG.isTraceEnabled()) {
+ LOG.trace("{}: Sending message {}", id, msgToS(message));
+ }
+
+ if (session == null) {
+ LOG.warn("{}: Session is disconnected, failing RPC request {}",
+ id, message);
+ return Futures.immediateFuture( createSessionDownRpcResult() );
+ }
+
+ final Request req = new Request( new UncancellableFuture<RpcResult<NetconfMessage>>(true),
+ message );
+ requests.add(req);
+
+ session.sendMessage(req.request).addListener(new FutureListener<Void>() {
+ @Override
+ public void operationComplete(final Future<Void> future) throws Exception {
+ if( !future.isSuccess() ) {
+ // We expect that a session down will occur at this point
+ LOG.debug("{}: Failed to send request {}", id,
+ XmlUtil.toString(req.request.getDocument()),
+ future.cause());
+
+ if( future.cause() != null ) {
+ req.future.set( createErrorRpcResult( RpcError.ErrorType.TRANSPORT,
+ future.cause().getLocalizedMessage() ) );
+ } else {
+ req.future.set( createSessionDownRpcResult() ); // assume session is down
+ }
+ req.future.setException( future.cause() );
+ }
+ else {
+ LOG.trace("Finished sending request {}", req.request);
+ }
+ }
+ });
+
+ return req.future;
+ }
+
+ private void processNotification(final NetconfMessage notification) {
+ if(LOG.isTraceEnabled()) {
+ LOG.trace("{}: Notification received: {}", id, notification);
+ }
+
+ remoteDevice.onNotification(notification);
+ }
+
+ private static boolean isNotification(final NetconfMessage message) {
+ final XmlElement xmle = XmlElement.fromDomDocument(message.getDocument());
+ return XmlNetconfConstants.NOTIFICATION_ELEMENT_NAME.equals(xmle.getName()) ;
+ }
+
+ private static final class Request {
+ final UncancellableFuture<RpcResult<NetconfMessage>> future;
+ final NetconfMessage request;
+
+ private Request(final UncancellableFuture<RpcResult<NetconfMessage>> future,
+ final NetconfMessage request) {
+ this.future = future;
+ this.request = request;
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.connect.netconf.listener;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+import java.net.URI;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import org.opendaylight.controller.netconf.client.NetconfClientSession;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class NetconfSessionPreferences {
+
+ private static final class ParameterMatcher {
+ private final Predicate<String> predicate;
+ private final int skipLength;
+
+ ParameterMatcher(final String name) {
+ predicate = new Predicate<String>() {
+ @Override
+ public boolean apply(final String input) {
+ return input.startsWith(name);
+ }
+ };
+
+ this.skipLength = name.length();
+ }
+
+ private String from(final Iterable<String> params) {
+ final Optional<String> o = Iterables.tryFind(params, predicate);
+ if (!o.isPresent()) {
+ return null;
+ }
+
+ return o.get().substring(skipLength);
+ }
+ }
+
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfSessionPreferences.class);
+ private static final ParameterMatcher MODULE_PARAM = new ParameterMatcher("module=");
+ private static final ParameterMatcher REVISION_PARAM = new ParameterMatcher("revision=");
+ private static final ParameterMatcher BROKEN_REVISON_PARAM = new ParameterMatcher("amp;revision=");
+ private static final Splitter AMP_SPLITTER = Splitter.on('&');
+ private static final Predicate<String> CONTAINS_REVISION = new Predicate<String>() {
+ @Override
+ public boolean apply(final String input) {
+ return input.contains("revision=");
+ }
+ };
+
+ private final Set<QName> moduleBasedCaps;
+ private final Set<String> nonModuleCaps;
+
+ private NetconfSessionPreferences(final Set<String> nonModuleCaps, final Set<QName> moduleBasedCaps) {
+ this.nonModuleCaps = Preconditions.checkNotNull(nonModuleCaps);
+ this.moduleBasedCaps = Preconditions.checkNotNull(moduleBasedCaps);
+ }
+
+ public Set<QName> getModuleBasedCaps() {
+ return moduleBasedCaps;
+ }
+
+ public Set<String> getNonModuleCaps() {
+ return nonModuleCaps;
+ }
+
+ public boolean containsNonModuleCapability(final String capability) {
+ return nonModuleCaps.contains(capability);
+ }
+
+ public boolean containsModuleCapability(final QName capability) {
+ return moduleBasedCaps.contains(capability);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("capabilities", nonModuleCaps)
+ .add("moduleBasedCapabilities", moduleBasedCaps)
+ .add("rollback", isRollbackSupported())
+ .add("monitoring", isMonitoringSupported())
+ .add("candidate", isCandidateSupported())
+ .add("writableRunning", isRunningWritable())
+ .toString();
+ }
+
+ public boolean isRollbackSupported() {
+ return containsNonModuleCapability(NetconfMessageTransformUtil.NETCONF_ROLLBACK_ON_ERROR_URI.toString());
+ }
+
+ public boolean isCandidateSupported() {
+ return containsNonModuleCapability(NetconfMessageTransformUtil.NETCONF_CANDIDATE_URI.toString());
+ }
+
+ public boolean isRunningWritable() {
+ return containsNonModuleCapability(NetconfMessageTransformUtil.NETCONF_RUNNING_WRITABLE_URI.toString());
+ }
+
+ public boolean isNotificationsSupported() {
+ return containsNonModuleCapability(NetconfMessageTransformUtil.NETCONF_NOTIFICATONS_URI.toString())
+ || containsModuleCapability(NetconfMessageTransformUtil.IETF_NETCONF_NOTIFICATIONS);
+ }
+
+ public boolean isMonitoringSupported() {
+ return containsModuleCapability(NetconfMessageTransformUtil.IETF_NETCONF_MONITORING)
+ || containsNonModuleCapability(NetconfMessageTransformUtil.IETF_NETCONF_MONITORING.getNamespace().toString());
+ }
+
+ public NetconfSessionPreferences addModuleCaps(final NetconfSessionPreferences netconfSessionModuleCapabilities) {
+ final HashSet<QName> mergedCaps = Sets.newHashSetWithExpectedSize(moduleBasedCaps.size() + netconfSessionModuleCapabilities.getModuleBasedCaps().size());
+ mergedCaps.addAll(moduleBasedCaps);
+ mergedCaps.addAll(netconfSessionModuleCapabilities.getModuleBasedCaps());
+ return new NetconfSessionPreferences(getNonModuleCaps(), mergedCaps);
+ }
+
+ public static NetconfSessionPreferences fromNetconfSession(final NetconfClientSession session) {
+ return fromStrings(session.getServerCapabilities());
+ }
+
+ private static QName cachedQName(final String namespace, final String revision, final String moduleName) {
+ return QName.cachedReference(QName.create(namespace, revision, moduleName));
+ }
+
+ private static QName cachedQName(final String namespace, final String moduleName) {
+ return QName.cachedReference(QName.create(URI.create(namespace), null, moduleName).withoutRevision());
+ }
+
+ public static NetconfSessionPreferences fromStrings(final Collection<String> capabilities) {
+ final Set<QName> moduleBasedCaps = new HashSet<>();
+ final Set<String> nonModuleCaps = Sets.newHashSet(capabilities);
+
+ for (final String capability : capabilities) {
+ final int qmark = capability.indexOf('?');
+ if (qmark == -1) {
+ continue;
+ }
+
+ final String namespace = capability.substring(0, qmark);
+ final Iterable<String> queryParams = AMP_SPLITTER.split(capability.substring(qmark + 1));
+ final String moduleName = MODULE_PARAM.from(queryParams);
+ if (moduleName == null) {
+ continue;
+ }
+
+ String revision = REVISION_PARAM.from(queryParams);
+ if (revision != null) {
+ addModuleQName(moduleBasedCaps, nonModuleCaps, capability, cachedQName(namespace, revision, moduleName));
+ continue;
+ }
+
+ /*
+ * We have seen devices which mis-escape revision, but the revision may not
+ * even be there. First check if there is a substring that matches revision.
+ */
+ if (Iterables.any(queryParams, CONTAINS_REVISION)) {
+
+ LOG.debug("Netconf device was not reporting revision correctly, trying to get amp;revision=");
+ revision = BROKEN_REVISON_PARAM.from(queryParams);
+ if (revision == null) {
+ LOG.warn("Netconf device returned revision incorrectly escaped for {}, ignoring it", capability);
+ addModuleQName(moduleBasedCaps, nonModuleCaps, capability, cachedQName(namespace, moduleName));
+ } else {
+ addModuleQName(moduleBasedCaps, nonModuleCaps, capability, cachedQName(namespace, revision, moduleName));
+ }
+ continue;
+ }
+
+ // Fallback, no revision provided for module
+ addModuleQName(moduleBasedCaps, nonModuleCaps, capability, cachedQName(namespace, moduleName));
+ }
+
+ return new NetconfSessionPreferences(ImmutableSet.copyOf(nonModuleCaps), ImmutableSet.copyOf(moduleBasedCaps));
+ }
+
+
+ private static void addModuleQName(final Set<QName> moduleBasedCaps, final Set<String> nonModuleCaps, final String capability, final QName qName) {
+ moduleBasedCaps.add(qName);
+ nonModuleCaps.remove(capability);
+ }
+
+ private NetconfDeviceCapabilities capabilities = new NetconfDeviceCapabilities();
+
+ public NetconfDeviceCapabilities getNetconfDeviceCapabilities() {
+ return capabilities;
+ }
+
+
+}
--- /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.connect.netconf.listener;
+
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.AbstractFuture;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.GuardedBy;
+
+final class UncancellableFuture<V> extends AbstractFuture<V> {
+ @GuardedBy("this")
+ private boolean uncancellable = false;
+
+ public UncancellableFuture(final boolean uncancellable) {
+ this.uncancellable = uncancellable;
+ }
+
+ public synchronized boolean setUncancellable() {
+ if (isCancelled()) {
+ return false;
+ }
+
+ uncancellable = true;
+ return true;
+ }
+
+ public synchronized boolean isUncancellable() {
+ return uncancellable;
+ }
+
+ @Override
+ public synchronized boolean cancel(final boolean mayInterruptIfRunning) {
+ return uncancellable ? false : super.cancel(mayInterruptIfRunning);
+ }
+
+ @Override
+ public synchronized boolean set(@Nullable final V value) {
+ Preconditions.checkState(uncancellable);
+ return super.set(value);
+ }
+
+ @Override
+ protected boolean setException(final Throwable throwable) {
+ Preconditions.checkState(uncancellable);
+ return super.setException(throwable);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015 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
+ */
+
+ /**
+ * Implementation of netconf southbound connector
+ */
+package org.opendaylight.controller.sal.connect.netconf;
--- /dev/null
+/*
+ * Copyright (c) 2015 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.connect.netconf.sal;
+
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfBaseOps.getSourceNode;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_RUNNING_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.toPath;
+
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcAvailabilityListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.controller.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.controller.sal.connect.netconf.listener.NetconfDeviceCommunicator;
+import org.opendaylight.controller.sal.connect.netconf.listener.NetconfSessionPreferences;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * SalFacade proxy that invokes keepalive RPCs to prevent session shutdown from remote device
+ * and to detect incorrect session drops (netconf session is inactive, but TCP/SSH connection is still present).
+ * The keepalive RPC is a get-config with empty filter.
+ */
+public final class KeepaliveSalFacade implements RemoteDeviceHandler<NetconfSessionPreferences> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(KeepaliveSalFacade.class);
+
+ // 2 minutes keepalive delay by default
+ private static final long DEFAULT_DELAY = TimeUnit.MINUTES.toSeconds(2);
+
+ private final RemoteDeviceId id;
+ private final RemoteDeviceHandler<NetconfSessionPreferences> salFacade;
+ private final ScheduledExecutorService executor;
+ private final long keepaliveDelaySeconds;
+ private final ResetKeepalive resetKeepaliveTask;
+
+ private volatile NetconfDeviceCommunicator listener;
+ private volatile ScheduledFuture<?> currentKeepalive;
+ private volatile DOMRpcService currentDeviceRpc;
+
+ public KeepaliveSalFacade(final RemoteDeviceId id, final RemoteDeviceHandler<NetconfSessionPreferences> salFacade,
+ final ScheduledExecutorService executor, final long keepaliveDelaySeconds) {
+ this.id = id;
+ this.salFacade = salFacade;
+ this.executor = executor;
+ this.keepaliveDelaySeconds = keepaliveDelaySeconds;
+ this.resetKeepaliveTask = new ResetKeepalive();
+ }
+
+ public KeepaliveSalFacade(final RemoteDeviceId id, final RemoteDeviceHandler<NetconfSessionPreferences> salFacade,
+ final ScheduledExecutorService executor) {
+ this(id, salFacade, executor, DEFAULT_DELAY);
+ }
+
+ /**
+ * Set the netconf session listener whenever ready
+ *
+ * @param listener netconf session listener
+ */
+ public void setListener(final NetconfDeviceCommunicator listener) {
+ this.listener = listener;
+ }
+
+ /**
+ * Just cancel current keepalive task.
+ * If its already started, let it finish ... not such a big deal.
+ *
+ * Then schedule next keepalive.
+ */
+ private void resetKeepalive() {
+ LOG.trace("{}: Resetting netconf keepalive timer", id);
+ if(currentKeepalive != null) {
+ currentKeepalive.cancel(false);
+ }
+ scheduleKeepalive();
+ }
+
+ /**
+ * Cancel current keepalive and also reset current deviceRpc
+ */
+ private void stopKeepalives() {
+ if(currentKeepalive != null) {
+ currentKeepalive.cancel(false);
+ }
+ currentDeviceRpc = null;
+ }
+
+ private void reconnect() {
+ Preconditions.checkState(listener != null, "%s: Unable to reconnect, session listener is missing", id);
+ stopKeepalives();
+ LOG.info("{}: Reconnecting inactive netconf session", id);
+ listener.disconnect();
+ }
+
+ @Override
+ public void onDeviceConnected(final SchemaContext remoteSchemaContext, final NetconfSessionPreferences netconfSessionPreferences, final DOMRpcService deviceRpc) {
+ this.currentDeviceRpc = deviceRpc;
+ final DOMRpcService deviceRpc1 = new KeepaliveDOMRpcService(deviceRpc, resetKeepaliveTask);
+ salFacade.onDeviceConnected(remoteSchemaContext, netconfSessionPreferences, deviceRpc1);
+
+ LOG.debug("{}: Netconf session initiated, starting keepalives", id);
+ scheduleKeepalive();
+ }
+
+ private void scheduleKeepalive() {
+ Preconditions.checkState(currentDeviceRpc != null);
+ LOG.trace("{}: Scheduling next keepalive in {} {}", id, keepaliveDelaySeconds, TimeUnit.SECONDS);
+ currentKeepalive = executor.schedule(new Keepalive(), keepaliveDelaySeconds, TimeUnit.SECONDS);
+ }
+
+ @Override
+ public void onDeviceDisconnected() {
+ stopKeepalives();
+ salFacade.onDeviceDisconnected();
+ }
+
+ @Override
+ public void onDeviceFailed(final Throwable throwable) {
+ stopKeepalives();
+ salFacade.onDeviceFailed(throwable);
+ }
+
+ @Override
+ public void onNotification(final DOMNotification domNotification) {
+ resetKeepalive();
+ salFacade.onNotification(domNotification);
+ }
+
+ @Override
+ public void close() {
+ stopKeepalives();
+ salFacade.close();
+ }
+
+ // Keepalive RPC static resources
+ private static final SchemaPath PATH = toPath(NETCONF_GET_CONFIG_QNAME);
+ private static final ContainerNode KEEPALIVE_PAYLOAD =
+ NetconfMessageTransformUtil.wrap(NETCONF_GET_CONFIG_QNAME, getSourceNode(NETCONF_RUNNING_QNAME), NetconfMessageTransformUtil.EMPTY_FILTER);
+
+ /**
+ * Invoke keepalive RPC and check the response. In case of any received response the keepalive
+ * is considered successful and schedules next keepalive with a fixed delay. If the response is unsuccessful (no
+ * response received, or the rcp could not even be sent) immediate reconnect is triggered as netconf session
+ * is considered inactive/failed.
+ */
+ private class Keepalive implements Runnable, FutureCallback<DOMRpcResult> {
+
+ @Override
+ public void run() {
+ LOG.trace("{}: Invoking keepalive RPC", id);
+
+ try {
+ Futures.addCallback(currentDeviceRpc.invokeRpc(PATH, KEEPALIVE_PAYLOAD), this);
+ } catch (NullPointerException e) {
+ LOG.debug("{}: Skipping keepalive while reconnecting", id);
+ // Empty catch block intentional
+ // Do nothing. The currentDeviceRpc was null and it means we hit the reconnect window and
+ // attempted to send keepalive while we were reconnecting. Next keepalive will be scheduled
+ // after reconnect so no action necessary here.
+ }
+ }
+
+ @Override
+ public void onSuccess(final DOMRpcResult result) {
+ LOG.debug("{}: Keepalive RPC successful with response: {}", id, result.getResult());
+ scheduleKeepalive();
+ }
+
+ @Override
+ public void onFailure(@Nonnull final Throwable t) {
+ LOG.warn("{}: Keepalive RPC failed. Reconnecting netconf session.", id, t);
+ reconnect();
+ }
+ }
+
+ /**
+ * Reset keepalive after each RPC response received
+ */
+ private class ResetKeepalive implements com.google.common.util.concurrent.FutureCallback<DOMRpcResult> {
+ @Override
+ public void onSuccess(@Nullable final DOMRpcResult result) {
+ // No matter what response we got, rpc-reply or rpc-error, we got it from device so the netconf session is OK
+ resetKeepalive();
+ }
+
+ @Override
+ public void onFailure(@Nonnull final Throwable t) {
+ // User/Application RPC failed (The RPC did not reach the remote device or .. TODO what other reasons could cause this ?)
+ // There is no point in keeping this session. Reconnect.
+ LOG.warn("{}: Rpc failure detected. Reconnecting netconf session", id, t);
+ reconnect();
+ }
+ }
+
+ /**
+ * DOMRpcService proxy that attaches reset-keepalive-task to each RPC invocation.
+ */
+ private static final class KeepaliveDOMRpcService implements DOMRpcService {
+
+ private final DOMRpcService deviceRpc;
+ private ResetKeepalive resetKeepaliveTask;
+
+ public KeepaliveDOMRpcService(final DOMRpcService deviceRpc, final ResetKeepalive resetKeepaliveTask) {
+ this.deviceRpc = deviceRpc;
+ this.resetKeepaliveTask = resetKeepaliveTask;
+ }
+
+ @Nonnull
+ @Override
+ public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(@Nonnull final SchemaPath type, final NormalizedNode<?, ?> input) {
+ final CheckedFuture<DOMRpcResult, DOMRpcException> domRpcResultDOMRpcExceptionCheckedFuture = deviceRpc.invokeRpc(type, input);
+ Futures.addCallback(domRpcResultDOMRpcExceptionCheckedFuture, resetKeepaliveTask);
+ return domRpcResultDOMRpcExceptionCheckedFuture;
+ }
+
+ @Override
+ public <T extends DOMRpcAvailabilityListener> ListenerRegistration<T> registerRpcListener(@Nonnull final T listener) {
+ // There is no real communication with the device (yet), no reset here
+ return deviceRpc.registerRpcListener(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.connect.netconf.sal;
+
+import java.util.Collections;
+import java.util.Map;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
+import org.opendaylight.controller.sal.connect.netconf.listener.NetconfSessionPreferences;
+import org.opendaylight.controller.sal.connect.netconf.sal.tx.ReadOnlyTx;
+import org.opendaylight.controller.sal.connect.netconf.sal.tx.ReadWriteTx;
+import org.opendaylight.controller.sal.connect.netconf.sal.tx.WriteCandidateRunningTx;
+import org.opendaylight.controller.sal.connect.netconf.sal.tx.WriteCandidateTx;
+import org.opendaylight.controller.sal.connect.netconf.sal.tx.WriteRunningTx;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfBaseOps;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+final class NetconfDeviceDataBroker implements DOMDataBroker {
+ private final RemoteDeviceId id;
+ private final NetconfBaseOps netconfOps;
+ private final long requestTimeoutMillis;
+
+ private final boolean rollbackSupport;
+ private boolean candidateSupported;
+ private boolean runningWritable;
+
+ public NetconfDeviceDataBroker(final RemoteDeviceId id, final SchemaContext schemaContext, final DOMRpcService rpc, final NetconfSessionPreferences netconfSessionPreferences, long requestTimeoutMillis) {
+ this.id = id;
+ this.netconfOps = new NetconfBaseOps(rpc, schemaContext);
+ this.requestTimeoutMillis = requestTimeoutMillis;
+ // get specific attributes from netconf preferences and get rid of it
+ // no need to keep the entire preferences object, its quite big with all the capability QNames
+ candidateSupported = netconfSessionPreferences.isCandidateSupported();
+ runningWritable = netconfSessionPreferences.isRunningWritable();
+ rollbackSupport = netconfSessionPreferences.isRollbackSupported();
+ }
+
+ @Override
+ public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
+ return new ReadOnlyTx(netconfOps, id);
+ }
+
+ @Override
+ public DOMDataReadWriteTransaction newReadWriteTransaction() {
+ return new ReadWriteTx(newReadOnlyTransaction(), newWriteOnlyTransaction());
+ }
+
+ @Override
+ public DOMDataWriteTransaction newWriteOnlyTransaction() {
+ if(candidateSupported) {
+ if(runningWritable) {
+ return new WriteCandidateRunningTx(id, netconfOps, rollbackSupport, requestTimeoutMillis);
+ } else {
+ return new WriteCandidateTx(id, netconfOps, rollbackSupport, requestTimeoutMillis);
+ }
+ } else {
+ return new WriteRunningTx(id, netconfOps, rollbackSupport, requestTimeoutMillis);
+ }
+ }
+
+ @Override
+ public ListenerRegistration<DOMDataChangeListener> registerDataChangeListener(final LogicalDatastoreType store, final YangInstanceIdentifier path, final DOMDataChangeListener listener, final DataChangeScope triggeringScope) {
+ throw new UnsupportedOperationException(id + ": Data change listeners not supported for netconf mount point");
+ }
+
+ @Override
+ public DOMTransactionChain createTransactionChain(final TransactionChainListener listener) {
+ throw new UnsupportedOperationException(id + ": Transaction chains not supported for netconf mount point");
+ }
+
+ @Override
+ public Map<Class<? extends DOMDataBrokerExtension>, DOMDataBrokerExtension> getSupportedExtensions() {
+ return Collections.emptyMap();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.connect.netconf.sal;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+import java.util.Collection;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+class NetconfDeviceNotificationService implements DOMNotificationService {
+
+ private final Multimap<SchemaPath, DOMNotificationListener> listeners = HashMultimap.create();
+
+ // Notification publish is very simple and hijacks the thread of the caller
+ // TODO shouldnt we reuse the implementation for notification router from sal-broker-impl ?
+ public synchronized void publishNotification(final DOMNotification notification) {
+ for (final DOMNotificationListener domNotificationListener : listeners.get(notification.getType())) {
+ domNotificationListener.onNotification(notification);
+ }
+ }
+
+ @Override
+ public synchronized <T extends DOMNotificationListener> ListenerRegistration<T> registerNotificationListener(@Nonnull final T listener, @Nonnull final Collection<SchemaPath> types) {
+ for (final SchemaPath type : types) {
+ listeners.put(type, listener);
+ }
+
+ // FIXME this should invoke create-subscription rpc on the remote device for a given notification
+
+ return new ListenerRegistration<T>() {
+ @Override
+ public void close() {
+ for (final SchemaPath type : types) {
+ listeners.remove(type, listener);
+ }
+ }
+
+ @Override
+ public T getInstance() {
+ return listener;
+ }
+ };
+ }
+
+ @Override
+ public synchronized <T extends DOMNotificationListener> ListenerRegistration<T> registerNotificationListener(@Nonnull final T listener, final SchemaPath... types) {
+ return registerNotificationListener(listener, Lists.newArrayList(types));
+ }
+}
--- /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.connect.netconf.sal;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.Collection;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcAvailabilityListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcIdentifier;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementationNotAvailableException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.controller.md.sal.dom.spi.DefaultDOMRpcResult;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.sal.connect.api.MessageTransformer;
+import org.opendaylight.controller.sal.connect.api.RemoteDeviceCommunicator;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+/**
+ * Invokes RPC by sending netconf message via listener. Also transforms result from NetconfMessage to CompositeNode.
+ */
+public final class NetconfDeviceRpc implements DOMRpcService {
+
+ private static final Function<RpcDefinition, DOMRpcIdentifier> RPC_TO_RPC_IDENTIFIER = new Function<RpcDefinition, DOMRpcIdentifier>() {
+ @Override
+ public DOMRpcIdentifier apply(final RpcDefinition input) {
+ // TODO add support for routed rpcs ... is it necessary in this case ?
+ return DOMRpcIdentifier.create(input.getPath());
+ }
+ };
+
+ private final RemoteDeviceCommunicator<NetconfMessage> listener;
+ private final MessageTransformer<NetconfMessage> transformer;
+ private final Collection<DOMRpcIdentifier> availableRpcs;
+
+ public NetconfDeviceRpc(final SchemaContext schemaContext, final RemoteDeviceCommunicator<NetconfMessage> listener, final MessageTransformer<NetconfMessage> transformer) {
+ this.listener = listener;
+ this.transformer = transformer;
+
+ availableRpcs = Collections2.transform(schemaContext.getOperations(), RPC_TO_RPC_IDENTIFIER);
+ }
+
+ @Nonnull
+ @Override
+ public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(@Nonnull final SchemaPath type, @Nullable final NormalizedNode<?, ?> input) {
+ final NetconfMessage message = transformer.toRpcRequest(type, input);
+ final ListenableFuture<RpcResult<NetconfMessage>> delegateFutureWithPureResult = listener.sendRequest(message, type.getLastComponent());
+
+ final ListenableFuture<DOMRpcResult> transformed = Futures.transform(delegateFutureWithPureResult, new Function<RpcResult<NetconfMessage>, DOMRpcResult>() {
+ @Override
+ public DOMRpcResult apply(final RpcResult<NetconfMessage> input) {
+ if (input.isSuccessful()) {
+ return transformer.toRpcResult(input.getResult(), type);
+ } else {
+ // TODO check whether the listener sets errors properly
+ return new DefaultDOMRpcResult(input.getErrors());
+ }
+ }
+ });
+
+ return Futures.makeChecked(transformed, new Function<Exception, DOMRpcException>() {
+ @Nullable
+ @Override
+ public DOMRpcException apply(@Nullable final Exception e) {
+ // FIXME what other possible exceptions are there ?
+ return new DOMRpcImplementationNotAvailableException(e, "Unable to invoke rpc %s", type);
+ }
+ });
+ }
+
+ @Nonnull
+ @Override
+ public <T extends DOMRpcAvailabilityListener> ListenerRegistration<T> registerRpcListener(@Nonnull final T listener) {
+
+ listener.onRpcAvailable(availableRpcs);
+
+ return new ListenerRegistration<T>() {
+ @Override
+ public void close() {
+ // NOOP, no rpcs appear and disappear in this implementation
+ }
+
+ @Override
+ public T getInstance() {
+ return 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.connect.netconf.sal;
+
+import com.google.common.collect.Lists;
+import java.util.List;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.controller.sal.connect.netconf.listener.NetconfDeviceCapabilities;
+import org.opendaylight.controller.sal.connect.netconf.listener.NetconfSessionPreferences;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class NetconfDeviceSalFacade implements AutoCloseable, RemoteDeviceHandler<NetconfSessionPreferences> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfDeviceSalFacade.class);
+
+ private final RemoteDeviceId id;
+ private final NetconfDeviceSalProvider salProvider;
+ private final long defaultRequestTimeoutMillis;
+
+ private final List<AutoCloseable> salRegistrations = Lists.newArrayList();
+
+ public NetconfDeviceSalFacade(final RemoteDeviceId id, final Broker domBroker, final BindingAwareBroker bindingBroker, long defaultRequestTimeoutMillis) {
+ this.id = id;
+ this.salProvider = new NetconfDeviceSalProvider(id);
+ this.defaultRequestTimeoutMillis = defaultRequestTimeoutMillis;
+ registerToSal(domBroker, bindingBroker);
+ }
+
+ public void registerToSal(final Broker domRegistryDependency, final BindingAwareBroker bindingBroker) {
+ domRegistryDependency.registerProvider(salProvider);
+ bindingBroker.registerProvider(salProvider);
+ }
+
+ @Override
+ public synchronized void onNotification(final DOMNotification domNotification) {
+ salProvider.getMountInstance().publish(domNotification);
+ }
+
+ @Override
+ public synchronized void onDeviceConnected(final SchemaContext schemaContext,
+ final NetconfSessionPreferences netconfSessionPreferences, final DOMRpcService deviceRpc) {
+
+ final DOMDataBroker domBroker = new NetconfDeviceDataBroker(id, schemaContext, deviceRpc, netconfSessionPreferences, defaultRequestTimeoutMillis);
+
+ final NetconfDeviceNotificationService notificationService = new NetconfDeviceNotificationService();
+
+ salProvider.getMountInstance().onTopologyDeviceConnected(schemaContext, domBroker, deviceRpc, notificationService);
+ salProvider.getTopologyDatastoreAdapter().updateDeviceData(true, netconfSessionPreferences.getNetconfDeviceCapabilities());
+ }
+
+ @Override
+ public synchronized void onDeviceDisconnected() {
+ salProvider.getTopologyDatastoreAdapter().updateDeviceData(false,
+ new NetconfDeviceCapabilities());
+ salProvider.getMountInstance().onTopologyDeviceDisconnected();
+ }
+
+ @Override
+ public synchronized void onDeviceFailed(final Throwable throwable) {
+ salProvider.getTopologyDatastoreAdapter().setDeviceAsFailed(throwable);
+ salProvider.getMountInstance().onTopologyDeviceDisconnected();
+ }
+
+ @Override
+ public synchronized void close() {
+ for (final AutoCloseable reg : Lists.reverse(salRegistrations)) {
+ closeGracefully(reg);
+ }
+ closeGracefully(salProvider);
+ }
+
+ private void closeGracefully(final AutoCloseable resource) {
+ if (resource != null) {
+ try {
+ resource.close();
+ } catch (final Exception e) {
+ LOG.warn("{}: Ignoring exception while closing {}", id,
+ resource, 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.connect.netconf.sal;
+
+import com.google.common.base.Preconditions;
+import java.util.Collection;
+import java.util.Collections;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.controller.sal.core.api.Provider;
+import org.opendaylight.yangtools.concepts.ObjectRegistration;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class NetconfDeviceSalProvider implements AutoCloseable, Provider, BindingAwareProvider {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfDeviceSalProvider.class);
+
+ private final RemoteDeviceId id;
+ private MountInstance mountInstance;
+
+ private volatile NetconfDeviceTopologyAdapter topologyDatastoreAdapter;
+
+ public NetconfDeviceSalProvider(final RemoteDeviceId deviceId) {
+ this.id = deviceId;
+ }
+
+ public MountInstance getMountInstance() {
+ Preconditions.checkState(mountInstance != null,
+ "%s: Mount instance was not initialized by sal. Cannot get mount instance", id);
+ return mountInstance;
+ }
+
+ public NetconfDeviceTopologyAdapter getTopologyDatastoreAdapter() {
+ Preconditions.checkState(topologyDatastoreAdapter != null,
+ "%s: Sal provider %s was not initialized by sal. Cannot get topology datastore adapter", id);
+ return topologyDatastoreAdapter;
+ }
+
+ @Override
+ public void onSessionInitiated(final Broker.ProviderSession session) {
+ LOG.debug("{}: (BI)Session with sal established {}", id, session);
+
+ final DOMMountPointService mountService = session.getService(DOMMountPointService.class);
+ if (mountService != null) {
+ mountInstance = new MountInstance(mountService, id);
+ }
+ }
+
+ @Override
+ public Collection<Provider.ProviderFunctionality> getProviderFunctionality() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public void onSessionInitiated(final BindingAwareBroker.ProviderContext session) {
+ LOG.debug("{}: Session with sal established {}", id, session);
+
+ final DataBroker dataBroker = session.getSALService(DataBroker.class);
+
+ topologyDatastoreAdapter = new NetconfDeviceTopologyAdapter(id, dataBroker);
+ }
+
+ public void close() throws Exception {
+ mountInstance.close();
+ topologyDatastoreAdapter.close();
+ topologyDatastoreAdapter = null;
+ }
+
+ static final class MountInstance implements AutoCloseable {
+
+ private DOMMountPointService mountService;
+ private final RemoteDeviceId id;
+ private NetconfDeviceNotificationService notificationService;
+
+ private ObjectRegistration<DOMMountPoint> topologyRegistration;
+
+ MountInstance(final DOMMountPointService mountService, final RemoteDeviceId id) {
+ this.mountService = Preconditions.checkNotNull(mountService);
+ this.id = Preconditions.checkNotNull(id);
+ }
+
+ synchronized void onTopologyDeviceConnected(final SchemaContext initialCtx,
+ final DOMDataBroker broker, final DOMRpcService rpc,
+ final NetconfDeviceNotificationService notificationService) {
+
+ Preconditions.checkNotNull(mountService, "Closed");
+ Preconditions.checkState(topologyRegistration == null, "Already initialized");
+
+ final DOMMountPointService.DOMMountPointBuilder mountBuilder = mountService.createMountPoint(id.getTopologyPath());
+ mountBuilder.addInitialSchemaContext(initialCtx);
+
+ mountBuilder.addService(DOMDataBroker.class, broker);
+ mountBuilder.addService(DOMRpcService.class, rpc);
+ mountBuilder.addService(DOMNotificationService.class, notificationService);
+ this.notificationService = notificationService;
+
+ topologyRegistration = mountBuilder.register();
+ LOG.debug("{}: TOPOLOGY Mountpoint exposed into MD-SAL {}", id,
+ topologyRegistration);
+
+ }
+
+ synchronized void onTopologyDeviceDisconnected() {
+ if(topologyRegistration == null) {
+ LOG.trace(
+ "{}: Not removing TOPOLOGY mountpoint from MD-SAL, mountpoint was not registered yet",
+ id);
+ return;
+ }
+
+ try {
+ topologyRegistration.close();
+ } catch (final Exception e) {
+ // Only log and ignore
+ LOG.warn(
+ "Unable to unregister mount instance for {}. Ignoring exception",
+ id.getTopologyPath(), e);
+ } finally {
+ LOG.debug("{}: TOPOLOGY Mountpoint removed from MD-SAL {}",
+ id, topologyRegistration);
+ topologyRegistration = null;
+ }
+ }
+
+ @Override
+ synchronized public void close() throws Exception {
+ onTopologyDeviceDisconnected();
+ mountService = null;
+ }
+
+ public synchronized void publish(final DOMNotification domNotification) {
+ Preconditions.checkNotNull(notificationService, "Device not set up yet, cannot handle notification {}", domNotification);
+ notificationService.publishNotification(domNotification);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.connect.netconf.sal;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.FluentIterable;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.sal.connect.netconf.listener.NetconfDeviceCapabilities;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeFields.ConnectionStatus;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.fields.AvailableCapabilitiesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.fields.UnavailableCapabilities;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.fields.UnavailableCapabilitiesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.fields.unavailable.capabilities.UnavailableCapability;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.fields.unavailable.capabilities.UnavailableCapability.FailureReason;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.fields.unavailable.capabilities.UnavailableCapabilityBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.network.topology.topology.topology.types.TopologyNetconf;
+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.NetworkTopologyBuilder;
+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.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.TopologyBuilder;
+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.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class NetconfDeviceTopologyAdapter implements AutoCloseable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfDeviceTopologyAdapter.class);
+ public static final Function<Entry<QName, FailureReason>, UnavailableCapability> UNAVAILABLE_CAPABILITY_TRANSFORMER = new Function<Entry<QName, FailureReason>, UnavailableCapability>() {
+ @Override
+ public UnavailableCapability apply(final Entry<QName, FailureReason> input) {
+ return new UnavailableCapabilityBuilder()
+ .setCapability(input.getKey().toString())
+ .setFailureReason(input.getValue()).build();
+ }
+ };
+ public static final Function<QName, String> AVAILABLE_CAPABILITY_TRANSFORMER = new Function<QName, String>() {
+ @Override
+ public String apply(QName qName) {
+ // intern string representation of a capability to avoid duplicates
+ return qName.toString().intern();
+ }
+ };
+
+ private final RemoteDeviceId id;
+ private final BindingTransactionChain txChain;
+
+ private final InstanceIdentifier<NetworkTopology> networkTopologyPath;
+ private final KeyedInstanceIdentifier<Topology, TopologyKey> topologyListPath;
+ private static final String UNKNOWN_REASON = "Unknown reason";
+
+ NetconfDeviceTopologyAdapter(final RemoteDeviceId id, final DataBroker dataService) {
+ this.id = id;
+ this.txChain = Preconditions.checkNotNull(dataService).createTransactionChain(new TransactionChainListener() {
+ @Override
+ public void onTransactionChainFailed(TransactionChain<?, ?> chain, AsyncTransaction<?, ?> transaction, Throwable cause) {
+ LOG.error("{}: TransactionChain({}) {} FAILED!", id, chain,
+ transaction.getIdentifier(), cause);
+ throw new IllegalStateException(id + " TransactionChain(" + chain + ") not committed correctly", cause);
+ }
+
+ @Override
+ public void onTransactionChainSuccessful(TransactionChain<?, ?> chain) {
+ LOG.trace("{}: TransactionChain({}) SUCCESSFUL", id, chain);
+ }
+ });
+
+ this.networkTopologyPath = InstanceIdentifier.builder(NetworkTopology.class).build();
+ this.topologyListPath = networkTopologyPath.child(Topology.class, new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName())));
+
+ initDeviceData();
+ }
+
+ private void initDeviceData() {
+ final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
+
+ createNetworkTopologyIfNotPresent(writeTx);
+
+ final InstanceIdentifier<Node> path = id.getTopologyBindingPath();
+ NodeBuilder nodeBuilder = getNodeIdBuilder(id);
+ NetconfNodeBuilder netconfNodeBuilder = new NetconfNodeBuilder();
+ netconfNodeBuilder.setConnectionStatus(ConnectionStatus.Connecting);
+ netconfNodeBuilder.setHost(id.getHost());
+ netconfNodeBuilder.setPort(new PortNumber(id.getAddress().getPort()));
+ nodeBuilder.addAugmentation(NetconfNode.class, netconfNodeBuilder.build());
+ Node node = nodeBuilder.build();
+
+ LOG.trace(
+ "{}: Init device state transaction {} putting if absent operational data started.",
+ id, writeTx.getIdentifier());
+ writeTx.put(LogicalDatastoreType.OPERATIONAL, path, node);
+ LOG.trace(
+ "{}: Init device state transaction {} putting operational data ended.",
+ id, writeTx.getIdentifier());
+
+ LOG.trace(
+ "{}: Init device state transaction {} putting if absent config data started.",
+ id, writeTx.getIdentifier());
+ writeTx.put(LogicalDatastoreType.CONFIGURATION, path, getNodeWithId(id));
+ LOG.trace(
+ "{}: Init device state transaction {} putting config data ended.",
+ id, writeTx.getIdentifier());
+
+ commitTransaction(writeTx, "init");
+ }
+
+ public void updateDeviceData(boolean up, NetconfDeviceCapabilities capabilities) {
+ final Node data = buildDataForNetconfNode(up, capabilities);
+
+ final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
+ LOG.trace(
+ "{}: Update device state transaction {} merging operational data started.",
+ id, writeTx.getIdentifier());
+ writeTx.put(LogicalDatastoreType.OPERATIONAL, id.getTopologyBindingPath(), data);
+ LOG.trace(
+ "{}: Update device state transaction {} merging operational data ended.",
+ id, writeTx.getIdentifier());
+
+ commitTransaction(writeTx, "update");
+ }
+
+ public void setDeviceAsFailed(Throwable throwable) {
+ String reason = (throwable != null && throwable.getMessage() != null) ? throwable.getMessage() : UNKNOWN_REASON;
+
+ final NetconfNode netconfNode = new NetconfNodeBuilder().setConnectionStatus(ConnectionStatus.UnableToConnect).setConnectedMessage(reason).build();
+ final Node data = getNodeIdBuilder(id).addAugmentation(NetconfNode.class, netconfNode).build();
+
+ final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
+ LOG.trace(
+ "{}: Setting device state as failed {} putting operational data started.",
+ id, writeTx.getIdentifier());
+ writeTx.put(LogicalDatastoreType.OPERATIONAL, id.getTopologyBindingPath(), data);
+ LOG.trace(
+ "{}: Setting device state as failed {} putting operational data ended.",
+ id, writeTx.getIdentifier());
+
+ commitTransaction(writeTx, "update-failed-device");
+ }
+
+ private Node buildDataForNetconfNode(boolean up, NetconfDeviceCapabilities capabilities) {
+ List<String> capabilityList = new ArrayList<>();
+ capabilityList.addAll(capabilities.getNonModuleBasedCapabilities());
+ capabilityList.addAll(FluentIterable.from(capabilities.getResolvedCapabilities()).transform(AVAILABLE_CAPABILITY_TRANSFORMER).toList());
+ final AvailableCapabilitiesBuilder avCapabalitiesBuilder = new AvailableCapabilitiesBuilder();
+ avCapabalitiesBuilder.setAvailableCapability(capabilityList);
+
+ final UnavailableCapabilities unavailableCapabilities =
+ new UnavailableCapabilitiesBuilder().setUnavailableCapability(FluentIterable.from(capabilities.getUnresolvedCapabilites().entrySet())
+ .transform(UNAVAILABLE_CAPABILITY_TRANSFORMER).toList()).build();
+
+ final NetconfNodeBuilder netconfNodeBuilder = new NetconfNodeBuilder()
+ .setHost(id.getHost())
+ .setPort(new PortNumber(id.getAddress().getPort()))
+ .setConnectionStatus(up ? ConnectionStatus.Connected : ConnectionStatus.Connecting)
+ .setAvailableCapabilities(avCapabalitiesBuilder.build())
+ .setUnavailableCapabilities(unavailableCapabilities);
+
+ final NodeBuilder nodeBuilder = getNodeIdBuilder(id);
+
+ return nodeBuilder.addAugmentation(NetconfNode.class, netconfNodeBuilder.build()).build();
+ }
+
+ public void removeDeviceConfiguration() {
+ final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
+
+ LOG.trace(
+ "{}: Close device state transaction {} removing all data started.",
+ id, writeTx.getIdentifier());
+ writeTx.delete(LogicalDatastoreType.CONFIGURATION, id.getTopologyBindingPath());
+ writeTx.delete(LogicalDatastoreType.OPERATIONAL, id.getTopologyBindingPath());
+ LOG.trace(
+ "{}: Close device state transaction {} removing all data ended.",
+ id, writeTx.getIdentifier());
+
+ commitTransaction(writeTx, "close");
+ }
+
+ private void createNetworkTopologyIfNotPresent(final WriteTransaction writeTx) {
+
+ final NetworkTopology networkTopology = new NetworkTopologyBuilder().build();
+ LOG.trace("{}: Merging {} container to ensure its presence", id,
+ networkTopology.QNAME, writeTx.getIdentifier());
+ writeTx.merge(LogicalDatastoreType.CONFIGURATION, networkTopologyPath, networkTopology);
+ writeTx.merge(LogicalDatastoreType.OPERATIONAL, networkTopologyPath, networkTopology);
+
+ final Topology topology = new TopologyBuilder().setTopologyId(new TopologyId(TopologyNetconf.QNAME.getLocalName())).build();
+ LOG.trace("{}: Merging {} container to ensure its presence", id,
+ topology.QNAME, writeTx.getIdentifier());
+ writeTx.merge(LogicalDatastoreType.CONFIGURATION, topologyListPath, topology);
+ writeTx.merge(LogicalDatastoreType.OPERATIONAL, topologyListPath, topology);
+ }
+
+ private void commitTransaction(final WriteTransaction transaction, final String txType) {
+ LOG.trace("{}: Committing Transaction {}:{}", id, txType,
+ transaction.getIdentifier());
+ final CheckedFuture<Void, TransactionCommitFailedException> result = transaction.submit();
+
+ Futures.addCallback(result, new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(final Void result) {
+ LOG.trace("{}: Transaction({}) {} SUCCESSFUL", id, txType,
+ transaction.getIdentifier());
+ }
+
+ @Override
+ public void onFailure(final Throwable t) {
+ LOG.error("{}: Transaction({}) {} FAILED!", id, txType,
+ transaction.getIdentifier(), t);
+ throw new IllegalStateException(id + " Transaction(" + txType + ") not committed correctly", t);
+ }
+ });
+
+ }
+
+ private static Node getNodeWithId(final RemoteDeviceId id) {
+ final NodeBuilder builder = getNodeIdBuilder(id);
+ return builder.build();
+ }
+
+ private static NodeBuilder getNodeIdBuilder(final RemoteDeviceId id) {
+ final NodeBuilder nodeBuilder = new NodeBuilder();
+ nodeBuilder.setKey(new NodeKey(new NodeId(id.getName())));
+ return nodeBuilder;
+ }
+
+ @Override
+ public void close() throws Exception {
+ removeDeviceConfiguration();
+ txChain.close();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015 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.connect.netconf.sal.tx;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfBaseOps;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.ModifyAction;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.MixinNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractWriteTx implements DOMDataWriteTransaction {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractWriteTx.class);
+
+ private final long defaultRequestTimeoutMillis;
+ protected final RemoteDeviceId id;
+ protected final NetconfBaseOps netOps;
+ protected final boolean rollbackSupport;
+ // Allow commit to be called only once
+ protected boolean finished = false;
+
+ public AbstractWriteTx(final long requestTimeoutMillis, final NetconfBaseOps netOps, final RemoteDeviceId id, final boolean rollbackSupport) {
+ this.defaultRequestTimeoutMillis = requestTimeoutMillis;
+ this.netOps = netOps;
+ this.id = id;
+ this.rollbackSupport = rollbackSupport;
+ init();
+ }
+
+ static boolean isSuccess(final DOMRpcResult result) {
+ return result.getErrors().isEmpty();
+ }
+
+ protected void checkNotFinished() {
+ Preconditions.checkState(!isFinished(), "%s: Transaction %s already finished", id, getIdentifier());
+ }
+
+ protected boolean isFinished() {
+ return finished;
+ }
+
+ protected void invokeBlocking(final String msg, final Function<NetconfBaseOps, ListenableFuture<DOMRpcResult>> op) throws NetconfDocumentedException {
+ try {
+ final DOMRpcResult compositeNodeRpcResult = op.apply(netOps).get(defaultRequestTimeoutMillis, TimeUnit.MILLISECONDS);
+ if(isSuccess(compositeNodeRpcResult) == false) {
+ throw new NetconfDocumentedException(id + ": " + msg + " failed: " + compositeNodeRpcResult.getErrors(), NetconfDocumentedException.ErrorType.application,
+ NetconfDocumentedException.ErrorTag.operation_failed, NetconfDocumentedException.ErrorSeverity.warning);
+ }
+ } catch (final InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new RuntimeException(e);
+ } catch (final ExecutionException | TimeoutException e) {
+ throw new NetconfDocumentedException(id + ": " + msg + " failed: " + e.getMessage(), e, NetconfDocumentedException.ErrorType.application,
+ NetconfDocumentedException.ErrorTag.operation_failed, NetconfDocumentedException.ErrorSeverity.warning);
+ }
+ }
+
+ @Override
+ public synchronized boolean cancel() {
+ if(isFinished()) {
+ return false;
+ }
+
+ finished = true;
+ cleanup();
+ return true;
+ }
+
+ protected abstract void init();
+
+ protected abstract void cleanup();
+
+ @Override
+ public Object getIdentifier() {
+ return this;
+ }
+
+ @Override
+ public synchronized void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
+ checkEditable(store);
+
+ // trying to write only mixin nodes (not visible when serialized). Ignoring. Some devices cannot handle empty edit-config rpc
+ if(containsOnlyNonVisibleData(path, data)) {
+ LOG.debug("Ignoring put for {} and data {}. Resulting data structure is empty.", path, data);
+ return;
+ }
+
+ try {
+ editConfig(
+ netOps.createEditConfigStrcture(Optional.<NormalizedNode<?, ?>>fromNullable(data), Optional.of(ModifyAction.REPLACE), path), Optional.of(ModifyAction.NONE));
+ } catch (final NetconfDocumentedException e) {
+ handleEditException(path, data, e, "putting");
+ }
+ }
+
+ protected abstract void handleEditException(YangInstanceIdentifier path, NormalizedNode<?, ?> data, NetconfDocumentedException e, String editType);
+ protected abstract void handleDeleteException(YangInstanceIdentifier path, NetconfDocumentedException e);
+
+ @Override
+ public synchronized void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
+ checkEditable(store);
+
+ // trying to write only mixin nodes (not visible when serialized). Ignoring. Some devices cannot handle empty edit-config rpc
+ if (containsOnlyNonVisibleData(path, data)) {
+ LOG.debug("Ignoring merge for {} and data {}. Resulting data structure is empty.", path, data);
+ return;
+ }
+
+ try {
+ editConfig(
+ netOps.createEditConfigStrcture(Optional.<NormalizedNode<?, ?>>fromNullable(data), Optional.<ModifyAction>absent(), path), Optional.<ModifyAction>absent());
+ } catch (final NetconfDocumentedException e) {
+ handleEditException(path, data, e, "merge");
+ }
+ }
+
+ /**
+ * Check whether the data to be written consists only from mixins
+ */
+ private static boolean containsOnlyNonVisibleData(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
+ // There's only one such case:top level list (pathArguments == 1 && data is Mixin)
+ // any other mixin nodes are contained by a "regular" node thus visible when serialized
+ return path.getPathArguments().size() == 1 && data instanceof MixinNode;
+ }
+
+ @Override
+ public synchronized void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ checkEditable(store);
+
+ try {
+ editConfig(
+ netOps.createEditConfigStrcture(Optional.<NormalizedNode<?, ?>>absent(), Optional.of(ModifyAction.DELETE), path), Optional.of(ModifyAction.NONE));
+ } catch (final NetconfDocumentedException e) {
+ handleDeleteException(path, e);
+ }
+ }
+
+ @Override
+ public final ListenableFuture<RpcResult<TransactionStatus>> commit() {
+ checkNotFinished();
+ finished = true;
+
+ return performCommit();
+ }
+
+ protected abstract ListenableFuture<RpcResult<TransactionStatus>> performCommit();
+
+ private void checkEditable(final LogicalDatastoreType store) {
+ checkNotFinished();
+ Preconditions.checkArgument(store == LogicalDatastoreType.CONFIGURATION, "Can edit only configuration data, not %s", store);
+ }
+
+ protected abstract void editConfig(DataContainerChild<?, ?> editStructure, Optional<ModifyAction> defaultOperation) throws NetconfDocumentedException;
+}
--- /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.connect.netconf.sal.tx;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.concurrent.ExecutionException;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfBaseOps;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yangtools.util.concurrent.MappingCheckedFuture;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public final class ReadOnlyTx implements DOMDataReadOnlyTransaction {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ReadOnlyTx.class);
+
+ private final NetconfBaseOps netconfOps;
+ private final RemoteDeviceId id;
+ private final FutureCallback<DOMRpcResult> loggingCallback;
+
+ public ReadOnlyTx(final NetconfBaseOps netconfOps, final RemoteDeviceId id) {
+ this.netconfOps = netconfOps;
+ this.id = id;
+
+ // Simple logging callback to log result of read operation
+ loggingCallback = new FutureCallback<DOMRpcResult>() {
+ @Override
+ public void onSuccess(final DOMRpcResult result) {
+ if(AbstractWriteTx.isSuccess(result)) {
+ LOG.trace("{}: Reading data successful", id);
+ } else {
+ LOG.warn("{}: Reading data unsuccessful: {}", id, result.getErrors());
+ }
+
+ }
+
+ @Override
+ public void onFailure(final Throwable t) {
+ LOG.warn("{}: Reading data failed", id, t);
+ }
+ };
+ }
+
+ private CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> readConfigurationData(
+ final YangInstanceIdentifier path) {
+ final ListenableFuture<DOMRpcResult> configRunning = netconfOps.getConfigRunning(loggingCallback, Optional.fromNullable(path));
+
+ final ListenableFuture<Optional<NormalizedNode<?, ?>>> transformedFuture = Futures.transform(configRunning, new Function<DOMRpcResult, Optional<NormalizedNode<?, ?>>>() {
+ @Override
+ public Optional<NormalizedNode<?, ?>> apply(final DOMRpcResult result) {
+ checkReadSuccess(result, path);
+
+ final DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> dataNode = findDataNode(result);
+ return NormalizedNodes.findNode(dataNode, path.getPathArguments());
+ }
+ });
+
+ return MappingCheckedFuture.create(transformedFuture, ReadFailedException.MAPPER);
+ }
+
+ private DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> findDataNode(final DOMRpcResult result) {
+ return ((ContainerNode) result.getResult()).getChild(NetconfMessageTransformUtil.toId(NetconfMessageTransformUtil.NETCONF_DATA_QNAME)).get();
+ }
+
+ private void checkReadSuccess(final DOMRpcResult result, final YangInstanceIdentifier path) {
+ try {
+ Preconditions.checkArgument(AbstractWriteTx.isSuccess(result), "%s: Unable to read data: %s, errors: %s", id, path, result.getErrors());
+ } catch (final IllegalArgumentException e) {
+ LOG.warn("{}: Unable to read data: {}, errors: {}", id, path, result.getErrors());
+ throw e;
+ }
+ }
+
+ private CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> readOperationalData(
+ final YangInstanceIdentifier path) {
+ final ListenableFuture<DOMRpcResult> configCandidate = netconfOps.get(loggingCallback, Optional.fromNullable(path));
+
+ // Find data node and normalize its content
+ final ListenableFuture<Optional<NormalizedNode<?, ?>>> transformedFuture = Futures.transform(configCandidate, new Function<DOMRpcResult, Optional<NormalizedNode<?, ?>>>() {
+ @Override
+ public Optional<NormalizedNode<?, ?>> apply(final DOMRpcResult result) {
+ checkReadSuccess(result, path);
+
+ final DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> dataNode = findDataNode(result);
+ return NormalizedNodes.findNode(dataNode, path.getPathArguments());
+ }
+ });
+
+ return MappingCheckedFuture.create(transformedFuture, ReadFailedException.MAPPER);
+ }
+
+ @Override
+ public void close() {
+ // NOOP
+ }
+
+ @Override
+ public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(
+ final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ switch (store) {
+ case CONFIGURATION: {
+ return readConfigurationData(path);
+ }
+ case OPERATIONAL: {
+ return readOperationalData(path);
+ }
+ }
+
+ throw new IllegalArgumentException(String.format("%s, Cannot read data %s for %s datastore, unknown datastore type", id, path, store));
+ }
+
+ @Override
+ public CheckedFuture<Boolean, ReadFailedException> exists(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> data = read(store, path);
+
+ try {
+ return Futures.immediateCheckedFuture(data.get().isPresent());
+ } catch (InterruptedException | ExecutionException e) {
+ return Futures.immediateFailedCheckedFuture(new ReadFailedException("Exists failed",e));
+ }
+ }
+
+ @Override
+ public Object getIdentifier() {
+ return 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.connect.netconf.sal.tx;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.concurrent.ExecutionException;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public class ReadWriteTx implements DOMDataReadWriteTransaction {
+
+ private final DOMDataReadTransaction delegateReadTx;
+ private final DOMDataWriteTransaction delegateWriteTx;
+
+ public ReadWriteTx(final DOMDataReadTransaction delegateReadTx, final DOMDataWriteTransaction delegateWriteTx) {
+ this.delegateReadTx = delegateReadTx;
+ this.delegateWriteTx = delegateWriteTx;
+ }
+
+ @Override
+ public boolean cancel() {
+ return delegateWriteTx.cancel();
+ }
+
+ @Override
+ public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
+ delegateWriteTx.put(store, path, data);
+ }
+
+ @Override
+ public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
+ delegateWriteTx.merge(store, path, data);
+ }
+
+ @Override
+ public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ delegateWriteTx.delete(store, path);
+ }
+
+ @Override
+ public CheckedFuture<Void, TransactionCommitFailedException> submit() {
+ return delegateWriteTx.submit();
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<TransactionStatus>> commit() {
+ return delegateWriteTx.commit();
+ }
+
+ @Override
+ public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(
+ final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ return delegateReadTx.read(store, path);
+ }
+
+ @Override public CheckedFuture<Boolean, ReadFailedException> exists(
+ final LogicalDatastoreType store,
+ final YangInstanceIdentifier path) {
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException>
+ data = read(store, path);
+
+ try {
+ return Futures.immediateCheckedFuture(data.get().isPresent());
+ } catch (InterruptedException | ExecutionException e) {
+ return Futures.immediateFailedCheckedFuture(new ReadFailedException("Exists failed",e));
+ }
+ }
+
+ @Override
+ public Object getIdentifier() {
+ return 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.connect.netconf.sal.tx;
+
+import com.google.common.base.Function;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfBaseOps;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfRpcFutureCallback;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Tx implementation for netconf devices that support only candidate datastore and writable running
+ * The sequence goes exactly as with only candidate supported, with one addition:
+ * <ul>
+ * <li>Running datastore is locked as the first thing and this lock has to succeed</li>
+ * </ul>
+ */
+public class WriteCandidateRunningTx extends WriteCandidateTx {
+
+ private static final Logger LOG = LoggerFactory.getLogger(WriteCandidateRunningTx.class);
+
+ public WriteCandidateRunningTx(final RemoteDeviceId id, final NetconfBaseOps netOps, final boolean rollbackSupport, long requestTimeoutMillis) {
+ super(id, netOps, rollbackSupport, requestTimeoutMillis);
+ }
+
+ @Override
+ protected synchronized void init() {
+ lockRunning();
+ super.init();
+ }
+
+ @Override
+ protected void cleanupOnSuccess() {
+ super.cleanupOnSuccess();
+ unlockRunning();
+ }
+
+ private void lockRunning() {
+ try {
+ invokeBlocking("Lock running", new Function<NetconfBaseOps, ListenableFuture<DOMRpcResult>>() {
+ @Override
+ public ListenableFuture<DOMRpcResult> apply(final NetconfBaseOps input) {
+ return input.lockRunning(new NetconfRpcFutureCallback("Lock running", id));
+ }
+ });
+ } catch (final NetconfDocumentedException e) {
+ LOG.warn("{}: Failed to lock running. Failed to initialize transaction", id, e);
+ finished = true;
+ throw new RuntimeException(id + ": Failed to lock running. Failed to initialize transaction", e);
+ }
+ }
+
+ /**
+ * This has to be non blocking since it is called from a callback on commit and its netty threadpool that is really sensitive to blocking calls
+ */
+ private void unlockRunning() {
+ netOps.unlockRunning(new NetconfRpcFutureCallback("Unlock running", id));
+ }
+}
--- /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.connect.netconf.sal.tx;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfBaseOps;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfRpcFutureCallback;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.opendaylight.yangtools.yang.data.api.ModifyAction;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Tx implementation for netconf devices that support only candidate datastore and no writable running
+ * The sequence goes as:
+ * <ol>
+ * <li/> Lock candidate datastore on tx construction
+ * <ul>
+ * <li/> Lock has to succeed, if it does not, an attempt to discard changes is made
+ * <li/> Discard changes has to succeed
+ * <li/> If discard is successful, lock is reattempted
+ * <li/> Second lock attempt has to succeed
+ * </ul>
+ * <li/> Edit-config in candidate N times
+ * <ul>
+ * <li/> If any issue occurs during edit, datastore is discarded using discard-changes rpc, unlocked and an exception is thrown async
+ * </ul>
+ * <li/> Commit and Unlock candidate datastore async
+ * </ol>
+ */
+public class WriteCandidateTx extends AbstractWriteTx {
+
+ private static final Logger LOG = LoggerFactory.getLogger(WriteCandidateTx.class);
+
+ private static final Function<DOMRpcResult, RpcResult<TransactionStatus>> RPC_RESULT_TO_TX_STATUS = new Function<DOMRpcResult, RpcResult<TransactionStatus>>() {
+ @Override
+ public RpcResult<TransactionStatus> apply(final DOMRpcResult input) {
+ if (isSuccess(input)) {
+ return RpcResultBuilder.success(TransactionStatus.COMMITED).build();
+ } else {
+ final RpcResultBuilder<TransactionStatus> failed = RpcResultBuilder.failed();
+ for (final RpcError rpcError : input.getErrors()) {
+ failed.withError(rpcError.getErrorType(), rpcError.getTag(), rpcError.getMessage(),
+ rpcError.getApplicationTag(), rpcError.getInfo(), rpcError.getCause());
+ }
+ return failed.build();
+ }
+ }
+ };
+
+ public WriteCandidateTx(final RemoteDeviceId id, final NetconfBaseOps rpc, final boolean rollbackSupport, long requestTimeoutMillis) {
+ super(requestTimeoutMillis, rpc, id, rollbackSupport);
+ }
+
+ @Override
+ protected synchronized void init() {
+ LOG.trace("{}: Initializing {} transaction", id, getClass().getSimpleName());
+
+ try {
+ lock();
+ } catch (final NetconfDocumentedException e) {
+ try {
+ LOG.warn("{}: Failed to lock candidate, attempting discard changes", id);
+ discardChanges();
+ LOG.warn("{}: Changes discarded successfully, attempting lock", id);
+ lock();
+ } catch (final NetconfDocumentedException secondE) {
+ LOG.error("{}: Failed to prepare candidate. Failed to initialize transaction", id, secondE);
+ throw new RuntimeException(id + ": Failed to prepare candidate. Failed to initialize transaction", secondE);
+ }
+ }
+ }
+
+ private void lock() throws NetconfDocumentedException {
+ try {
+ invokeBlocking("Lock candidate", new Function<NetconfBaseOps, ListenableFuture<DOMRpcResult>>() {
+ @Override
+ public ListenableFuture<DOMRpcResult> apply(final NetconfBaseOps input) {
+ return input.lockCandidate(new NetconfRpcFutureCallback("Lock candidate", id));
+ }
+ });
+ } catch (final NetconfDocumentedException e) {
+ LOG.warn("{}: Failed to lock candidate", id, e);
+ throw e;
+ }
+ }
+
+ @Override
+ protected void cleanup() {
+ discardChanges();
+ cleanupOnSuccess();
+ }
+
+ @Override
+ protected void handleEditException(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data, final NetconfDocumentedException e, final String editType) {
+ LOG.warn("{}: Error {} data to (candidate){}, data: {}, canceling", id, editType, path, data, e);
+ cancel();
+ throw new RuntimeException(id + ": Error while " + editType + ": (candidate)" + path, e);
+ }
+
+ @Override
+ protected void handleDeleteException(final YangInstanceIdentifier path, final NetconfDocumentedException e) {
+ LOG.warn("{}: Error deleting data (candidate){}, canceling", id, path, e);
+ cancel();
+ throw new RuntimeException(id + ": Error while deleting (candidate)" + path, e);
+ }
+
+ @Override
+ public synchronized CheckedFuture<Void, TransactionCommitFailedException> submit() {
+ final ListenableFuture<Void> commitFutureAsVoid = Futures.transform(commit(), new Function<RpcResult<TransactionStatus>, Void>() {
+ @Override
+ public Void apply(final RpcResult<TransactionStatus> input) {
+ Preconditions.checkArgument(input.isSuccessful() && input.getErrors().isEmpty(), "Submit failed with errors: %s", input.getErrors());
+ return null;
+ }
+ });
+
+ return Futures.makeChecked(commitFutureAsVoid, new Function<Exception, TransactionCommitFailedException>() {
+ @Override
+ public TransactionCommitFailedException apply(final Exception input) {
+ return new TransactionCommitFailedException("Submit of transaction " + getIdentifier() + " failed", input);
+ }
+ });
+ }
+
+ /**
+ * This has to be non blocking since it is called from a callback on commit and its netty threadpool that is really sensitive to blocking calls
+ */
+ private void discardChanges() {
+ netOps.discardChanges(new NetconfRpcFutureCallback("Discarding candidate", id));
+ }
+
+ @Override
+ public synchronized ListenableFuture<RpcResult<TransactionStatus>> performCommit() {
+ final ListenableFuture<DOMRpcResult> rpcResult = netOps.commit(new NetconfRpcFutureCallback("Commit", id) {
+ @Override
+ public void onSuccess(final DOMRpcResult result) {
+ super.onSuccess(result);
+ LOG.debug("{}: Write successful, transaction: {}. Unlocking", id, getIdentifier());
+ cleanupOnSuccess();
+ }
+
+ @Override
+ protected void onUnsuccess(final DOMRpcResult result) {
+ LOG.error("{}: Write failed, transaction {}, discarding changes, unlocking: {}", id, getIdentifier(), result.getErrors());
+ cleanup();
+ }
+
+ @Override
+ public void onFailure(final Throwable t) {
+ LOG.error("{}: Write failed, transaction {}, discarding changes, unlocking", id, getIdentifier(), t);
+ cleanup();
+ }
+ });
+
+ return Futures.transform(rpcResult, RPC_RESULT_TO_TX_STATUS);
+ }
+
+ protected void cleanupOnSuccess() {
+ unlock();
+ }
+
+ @Override
+ protected void editConfig(final DataContainerChild<?, ?> editStructure, final Optional<ModifyAction> defaultOperation) throws NetconfDocumentedException {
+ invokeBlocking("Edit candidate", new Function<NetconfBaseOps, ListenableFuture<DOMRpcResult>>() {
+ @Override
+ public ListenableFuture<DOMRpcResult> apply(final NetconfBaseOps input) {
+ return defaultOperation.isPresent()
+ ? input.editConfigCandidate(new NetconfRpcFutureCallback("Edit candidate", id), editStructure, defaultOperation.get(),
+ rollbackSupport)
+ : input.editConfigCandidate(new NetconfRpcFutureCallback("Edit candidate", id), editStructure,
+ rollbackSupport);
+ }
+ });
+ }
+
+ /**
+ * This has to be non blocking since it is called from a callback on commit and its netty threadpool that is really sensitive to blocking calls
+ */
+ private void unlock() {
+ netOps.unlockCandidate(new NetconfRpcFutureCallback("Unlock candidate", id));
+ }
+
+}
--- /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.connect.netconf.sal.tx;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfBaseOps;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfRpcFutureCallback;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.opendaylight.yangtools.yang.data.api.ModifyAction;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Tx implementation for netconf devices that support only writable-running with no candidate
+ * The sequence goes as:
+ * <ol>
+ * <li/> Lock running datastore on tx construction
+ * <ul>
+ * <li/> Lock has to succeed, if it does not, transaction is failed
+ * </ul>
+ * <li/> Edit-config in running N times
+ * <ul>
+ * <li/> If any issue occurs during edit, datastore is unlocked and an exception is thrown
+ * </ul>
+ * <li/> Unlock running datastore on tx commit
+ * </ol>
+ */
+public class WriteRunningTx extends AbstractWriteTx {
+
+ private static final Logger LOG = LoggerFactory.getLogger(WriteRunningTx.class);
+
+ public WriteRunningTx(final RemoteDeviceId id, final NetconfBaseOps netOps,
+ final boolean rollbackSupport, long requestTimeoutMillis) {
+ super(requestTimeoutMillis, netOps, id, rollbackSupport);
+ }
+
+ @Override
+ protected synchronized void init() {
+ lock();
+ }
+
+ private void lock() {
+ try {
+ invokeBlocking("Lock running", new Function<NetconfBaseOps, ListenableFuture<DOMRpcResult>>() {
+ @Override
+ public ListenableFuture<DOMRpcResult> apply(final NetconfBaseOps input) {
+ return input.lockRunning(new NetconfRpcFutureCallback("Lock running", id));
+ }
+ });
+ } catch (final NetconfDocumentedException e) {
+ LOG.warn("{}: Failed to initialize netconf transaction (lock running)", id, e);
+ finished = true;
+ throw new RuntimeException(id + ": Failed to initialize netconf transaction (lock running)", e);
+ }
+ }
+
+ @Override
+ protected void cleanup() {
+ unlock();
+ }
+
+ @Override
+ protected void handleEditException(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data, final NetconfDocumentedException e, final String editType) {
+ LOG.warn("{}: Error {} data to (running){}, data: {}, canceling", id, editType, path, data, e);
+ cancel();
+ throw new RuntimeException(id + ": Error while " + editType + ": (running)" + path, e);
+ }
+
+ @Override
+ protected void handleDeleteException(final YangInstanceIdentifier path, final NetconfDocumentedException e) {
+ LOG.warn("{}: Error deleting data (running){}, canceling", id, path, e);
+ cancel();
+ throw new RuntimeException(id + ": Error while deleting (running)" + path, e);
+ }
+
+ @Override
+ public synchronized CheckedFuture<Void, TransactionCommitFailedException> submit() {
+ final ListenableFuture<Void> commmitFutureAsVoid = Futures.transform(commit(), new Function<RpcResult<TransactionStatus>, Void>() {
+ @Override
+ public Void apply(final RpcResult<TransactionStatus> input) {
+ return null;
+ }
+ });
+
+ return Futures.makeChecked(commmitFutureAsVoid, new Function<Exception, TransactionCommitFailedException>() {
+ @Override
+ public TransactionCommitFailedException apply(final Exception input) {
+ return new TransactionCommitFailedException("Submit of transaction " + getIdentifier() + " failed", input);
+ }
+ });
+ }
+
+ @Override
+ public synchronized ListenableFuture<RpcResult<TransactionStatus>> performCommit() {
+ unlock();
+ return Futures.immediateFuture(RpcResultBuilder.success(TransactionStatus.COMMITED).build());
+ }
+
+ @Override
+ protected void editConfig(final DataContainerChild<?, ?> editStructure, final Optional<ModifyAction> defaultOperation) throws NetconfDocumentedException {
+ invokeBlocking("Edit running", new Function<NetconfBaseOps, ListenableFuture<DOMRpcResult>>() {
+ @Override
+ public ListenableFuture<DOMRpcResult> apply(final NetconfBaseOps input) {
+ return defaultOperation.isPresent()
+ ? input.editConfigRunning(new NetconfRpcFutureCallback("Edit running", id), editStructure, defaultOperation.get(),
+ rollbackSupport)
+ : input.editConfigRunning(new NetconfRpcFutureCallback("Edit running", id), editStructure,
+ rollbackSupport);
+ }
+ });
+ }
+
+ private void unlock() {
+ try {
+ invokeBlocking("Unlocking running", new Function<NetconfBaseOps, ListenableFuture<DOMRpcResult>>() {
+ @Override
+ public ListenableFuture<DOMRpcResult> apply(final NetconfBaseOps input) {
+ return input.unlockRunning(new NetconfRpcFutureCallback("Unlock running", id));
+ }
+ });
+ } catch (final NetconfDocumentedException e) {
+ LOG.warn("{}: Failed to unlock running datastore", id, e);
+ throw new RuntimeException(id + ": Failed to unlock running datastore", 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.connect.netconf.schema;
+
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.GET_SCHEMA_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_DATA_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.toId;
+import com.google.common.base.Charsets;
+import com.google.common.base.Function;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import javax.xml.transform.dom.DOMSource;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.Yang;
+import org.opendaylight.yangtools.util.concurrent.ExceptionMapper;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Element;
+
+public final class NetconfRemoteSchemaYangSourceProvider implements SchemaSourceProvider<YangTextSchemaSource> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfRemoteSchemaYangSourceProvider.class);
+
+ private static final ExceptionMapper<SchemaSourceException> MAPPER = new ExceptionMapper<SchemaSourceException>(
+ "schemaDownload", SchemaSourceException.class) {
+ @Override
+ protected SchemaSourceException newWithCause(final String s, final Throwable throwable) {
+ return new SchemaSourceException(s, throwable);
+ }
+ };
+
+ private final DOMRpcService rpc;
+ private final RemoteDeviceId id;
+
+ public NetconfRemoteSchemaYangSourceProvider(final RemoteDeviceId id, final DOMRpcService rpc) {
+ this.id = id;
+ this.rpc = Preconditions.checkNotNull(rpc);
+ }
+
+ public static ContainerNode createGetSchemaRequest(final String moduleName, final Optional<String> revision) {
+ final QName identifierQName = QName.cachedReference(QName.create(NetconfMessageTransformUtil.GET_SCHEMA_QNAME, "identifier"));
+ final YangInstanceIdentifier.NodeIdentifier identifierId = new YangInstanceIdentifier.NodeIdentifier(identifierQName);
+ final LeafNode<String> identifier = Builders.<String>leafBuilder().withNodeIdentifier(identifierId).withValue(moduleName).build();
+
+ final QName formatQName = QName.cachedReference(QName.create(NetconfMessageTransformUtil.GET_SCHEMA_QNAME, "format"));
+ final YangInstanceIdentifier.NodeIdentifier formatId = new YangInstanceIdentifier.NodeIdentifier(formatQName);
+ final LeafNode<QName> format = Builders.<QName>leafBuilder().withNodeIdentifier(formatId).withValue(Yang.QNAME).build();
+
+ final DataContainerNodeAttrBuilder<YangInstanceIdentifier.NodeIdentifier, ContainerNode> builder = Builders.containerBuilder();
+
+ builder.withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(NetconfMessageTransformUtil.GET_SCHEMA_QNAME))
+ .withChild(identifier).withChild(format);
+
+ if(revision.isPresent()) {
+ final QName revisionQName = QName.cachedReference(QName.create(NetconfMessageTransformUtil.GET_SCHEMA_QNAME, "version"));
+ final YangInstanceIdentifier.NodeIdentifier revisionId = new YangInstanceIdentifier.NodeIdentifier(revisionQName);
+ final LeafNode<String> revisionNode = Builders.<String>leafBuilder().withNodeIdentifier(revisionId).withValue(revision.get()).build();
+
+ builder.withChild(revisionNode);
+ }
+
+ return builder.build();
+ }
+
+ private static Optional<String> getSchemaFromRpc(final RemoteDeviceId id, final NormalizedNode<?, ?> result) {
+ if (result == null) {
+ return Optional.absent();
+ }
+
+ final QName schemaWrapperNode = QName.cachedReference(QName.create(GET_SCHEMA_QNAME, NETCONF_DATA_QNAME.getLocalName()));
+ final Optional<DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?>> child = ((ContainerNode) result).getChild(toId(schemaWrapperNode));
+
+ Preconditions.checkState(child.isPresent() && child.get() instanceof AnyXmlNode,
+ "%s Unexpected response to get-schema, expected response with one child %s, but was %s", id,
+ schemaWrapperNode, result);
+
+ final DOMSource wrappedNode = ((AnyXmlNode) child.get()).getValue();
+ Preconditions.checkNotNull(wrappedNode.getNode());
+ final Element dataNode = (Element) wrappedNode.getNode();
+
+ return Optional.of(dataNode.getTextContent().trim());
+ }
+
+ @Override
+ public CheckedFuture<YangTextSchemaSource, SchemaSourceException> getSource(final SourceIdentifier sourceIdentifier) {
+ final String moduleName = sourceIdentifier.getName();
+
+ // If formatted revision is SourceIdentifier.NOT_PRESENT_FORMATTED_REVISION, we have to omit it from request
+ final String formattedRevision = sourceIdentifier.getRevision().equals(SourceIdentifier.NOT_PRESENT_FORMATTED_REVISION) ? null : sourceIdentifier.getRevision();
+ final Optional<String> revision = Optional.fromNullable(formattedRevision);
+ final NormalizedNode<?, ?> getSchemaRequest = createGetSchemaRequest(moduleName, revision);
+
+ LOG.trace("{}: Loading YANG schema source for {}:{}", id, moduleName,
+ revision);
+
+ final ListenableFuture<YangTextSchemaSource> transformed = Futures.transform(
+ rpc.invokeRpc(SchemaPath.create(true, NetconfMessageTransformUtil.GET_SCHEMA_QNAME), getSchemaRequest),
+ new ResultToYangSourceTransformer(id, sourceIdentifier, moduleName, revision));
+
+ final CheckedFuture<YangTextSchemaSource, SchemaSourceException> checked = Futures.makeChecked(transformed, MAPPER);
+
+ // / FIXME remove this get, it is only present to wait until source is retrieved
+ // (goal is to limit concurrent schema download, since NetconfDevice listener does not handle concurrent messages properly)
+ // TODO retest this
+ try {
+ LOG.trace("{}: Blocking for {}", id, sourceIdentifier);
+ checked.checkedGet();
+ } catch (final SchemaSourceException e) {
+ return Futures.immediateFailedCheckedFuture(e);
+ }
+
+ return checked;
+ }
+
+ /**
+ * Transform composite node to string schema representation and then to ASTSchemaSource
+ */
+ private static final class ResultToYangSourceTransformer implements
+ Function<DOMRpcResult, YangTextSchemaSource> {
+
+ private final RemoteDeviceId id;
+ private final SourceIdentifier sourceIdentifier;
+ private final String moduleName;
+ private final Optional<String> revision;
+
+ public ResultToYangSourceTransformer(final RemoteDeviceId id, final SourceIdentifier sourceIdentifier,
+ final String moduleName, final Optional<String> revision) {
+ this.id = id;
+ this.sourceIdentifier = sourceIdentifier;
+ this.moduleName = moduleName;
+ this.revision = revision;
+ }
+
+ @Override
+ public YangTextSchemaSource apply(final DOMRpcResult input) {
+
+ if (input.getErrors().isEmpty()) {
+
+ final Optional<String> schemaString = getSchemaFromRpc(id, input.getResult());
+
+ Preconditions.checkState(schemaString.isPresent(),
+ "%s: Unexpected response to get-schema, schema not present in message for: %s", id, sourceIdentifier);
+
+ LOG.debug("{}: YANG Schema successfully retrieved for {}:{}",
+ id, moduleName, revision);
+ return new NetconfYangTextSchemaSource(id, sourceIdentifier, schemaString);
+ }
+
+ LOG.warn(
+ "{}: YANG schema was not successfully retrieved for {}. Errors: {}",
+ id, sourceIdentifier, input.getErrors());
+
+ throw new IllegalStateException(String.format(
+ "%s: YANG schema was not successfully retrieved for %s. Errors: %s", id, sourceIdentifier,
+ input.getErrors()));
+ }
+
+ }
+
+ private static class NetconfYangTextSchemaSource extends YangTextSchemaSource {
+ private final RemoteDeviceId id;
+ private final Optional<String> schemaString;
+
+ public NetconfYangTextSchemaSource(final RemoteDeviceId id, final SourceIdentifier sId, final Optional<String> schemaString) {
+ super(sId);
+ this.id = id;
+ this.schemaString = schemaString;
+ }
+
+ @Override
+ protected MoreObjects.ToStringHelper addToStringAttributes(final MoreObjects.ToStringHelper toStringHelper) {
+ return toStringHelper.add("device", id);
+ }
+
+ @Override
+ public InputStream openStream() throws IOException {
+ return new ByteArrayInputStream(schemaString.get().getBytes(Charsets.UTF_8));
+ }
+ }
+}
--- /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.connect.netconf.schema.mapping;
+
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.EVENT_TIME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_RPC_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_URI;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.toPath;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+import java.io.IOException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.AbstractMap;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import javax.xml.transform.dom.DOMResult;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.MissingNameSpaceException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.opendaylight.controller.md.sal.dom.api.DOMEvent;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.controller.md.sal.dom.spi.DefaultDOMRpcResult;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.notifications.NetconfNotification;
+import org.opendaylight.controller.netconf.util.OrderedNormalizedNodeWriter;
+import org.opendaylight.controller.sal.connect.api.MessageTransformer;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil;
+import org.opendaylight.controller.sal.connect.util.MessageCounter;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XMLStreamNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlUtils;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class NetconfMessageTransformer implements MessageTransformer<NetconfMessage> {
+
+ public static final String MESSAGE_ID_PREFIX = "m";
+
+ private static final Logger LOG= LoggerFactory.getLogger(NetconfMessageTransformer.class);
+
+
+ private static final Function<SchemaNode, QName> QNAME_FUNCTION = new Function<SchemaNode, QName>() {
+ @Override
+ public QName apply(final SchemaNode rpcDefinition) {
+ return rpcDefinition.getQName();
+ }
+ };
+
+ private static final Function<SchemaNode, QName> QNAME_NOREV_FUNCTION = new Function<SchemaNode, QName>() {
+ @Override
+ public QName apply(final SchemaNode notification) {
+ return QNAME_FUNCTION.apply(notification).withoutRevision();
+ }
+ };
+ private static final SchemaContext BASE_NETCONF_CTX;
+
+ static {
+ try {
+ final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create();
+ moduleInfoBackedContext.addModuleInfos(
+ Lists.newArrayList(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.$YangModuleInfoImpl.getInstance()));
+ BASE_NETCONF_CTX = moduleInfoBackedContext.tryToCreateSchemaContext().get();
+ } catch (final RuntimeException e) {
+ LOG.error("Unable to prepare schema context for base netconf ops", e);
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+ private static final Map<QName, RpcDefinition> MAPPED_BASE_RPCS = Maps.uniqueIndex(BASE_NETCONF_CTX.getOperations(), QNAME_FUNCTION);
+
+ private final SchemaContext schemaContext;
+ private final MessageCounter counter;
+ private final Map<QName, RpcDefinition> mappedRpcs;
+ private final Multimap<QName, NotificationDefinition> mappedNotifications;
+ private final DomToNormalizedNodeParserFactory parserFactory;
+
+ public NetconfMessageTransformer(final SchemaContext schemaContext, final boolean strictParsing) {
+ this.counter = new MessageCounter();
+ this.schemaContext = schemaContext;
+ parserFactory = DomToNormalizedNodeParserFactory.getInstance(XmlUtils.DEFAULT_XML_CODEC_PROVIDER, schemaContext, strictParsing);
+
+ mappedRpcs = Maps.uniqueIndex(schemaContext.getOperations(), QNAME_FUNCTION);
+ mappedNotifications = Multimaps.index(schemaContext.getNotifications(), QNAME_NOREV_FUNCTION);
+ }
+
+ @Override
+ public synchronized DOMNotification toNotification(final NetconfMessage message) {
+ final Map.Entry<Date, XmlElement> stripped = stripNotification(message);
+ final QName notificationNoRev;
+ try {
+ notificationNoRev = QName.create(stripped.getValue().getNamespace(), stripped.getValue().getName()).withoutRevision();
+ } catch (final MissingNameSpaceException e) {
+ throw new IllegalArgumentException("Unable to parse notification " + message + ", cannot find namespace", e);
+ }
+
+ final Collection<NotificationDefinition> notificationDefinitions = mappedNotifications.get(notificationNoRev);
+ Preconditions.checkArgument(notificationDefinitions.size() > 0,
+ "Unable to parse notification %s, unknown notification. Available notifications: %s", notificationDefinitions, mappedNotifications.keySet());
+
+ // FIXME if multiple revisions for same notifications are present, we should pick the most recent. Or ?
+ // We should probably just put the most recent notification versions into our map. We can expect that the device sends the data according to the latest available revision of a model.
+ final NotificationDefinition next = notificationDefinitions.iterator().next();
+
+ // We wrap the notification as a container node in order to reuse the parsers and builders for container node
+ final ContainerSchemaNode notificationAsContainerSchemaNode = NetconfMessageTransformUtil.createSchemaForNotification(next);
+ final ContainerNode content = parserFactory.getContainerNodeParser().parse(Collections.singleton(stripped.getValue().getDomElement()),
+ notificationAsContainerSchemaNode);
+ return new NetconfDeviceNotification(content, stripped.getKey());
+ }
+
+ private static final ThreadLocal<SimpleDateFormat> EVENT_TIME_FORMAT = new ThreadLocal<SimpleDateFormat>() {
+ protected SimpleDateFormat initialValue() {
+ return new SimpleDateFormat(NetconfNotification.RFC3339_DATE_FORMAT_BLUEPRINT);
+ }
+
+ public void set(SimpleDateFormat value) {
+ throw new UnsupportedOperationException();
+ }
+ };
+
+ // FIXME move somewhere to util
+ private static Map.Entry<Date, XmlElement> stripNotification(final NetconfMessage message) {
+ final XmlElement xmlElement = XmlElement.fromDomDocument(message.getDocument());
+ final List<XmlElement> childElements = xmlElement.getChildElements();
+ Preconditions.checkArgument(childElements.size() == 2, "Unable to parse notification %s, unexpected format", message);
+
+ final XmlElement eventTimeElement;
+ final XmlElement notificationElement;
+
+ if (childElements.get(0).getName().equals(EVENT_TIME)) {
+ eventTimeElement = childElements.get(0);
+ notificationElement = childElements.get(1);
+ }
+ else if(childElements.get(1).getName().equals(EVENT_TIME)) {
+ eventTimeElement = childElements.get(1);
+ notificationElement = childElements.get(0);
+ } else {
+ throw new IllegalArgumentException("Notification payload does not contain " + EVENT_TIME + " " + message);
+ }
+
+ try {
+ return new AbstractMap.SimpleEntry<>(EVENT_TIME_FORMAT.get().parse(eventTimeElement.getTextContent()), notificationElement);
+ } catch (DocumentedException e) {
+ throw new IllegalArgumentException("Notification payload does not contain " + EVENT_TIME + " " + message);
+ } catch (ParseException e) {
+ throw new IllegalArgumentException("Unable to parse event time from " + eventTimeElement, e);
+ }
+ }
+
+ @Override
+ public NetconfMessage toRpcRequest(SchemaPath rpc, final NormalizedNode<?, ?> payload) {
+ // In case no input for rpc is defined, we can simply construct the payload here
+ final QName rpcQName = rpc.getLastComponent();
+ Map<QName, RpcDefinition> currentMappedRpcs = mappedRpcs;
+
+ // Determine whether a base netconf operation is being invoked and also check if the device exposed model for base netconf
+ // If no, use pre built base netconf operations model
+ final boolean needToUseBaseCtx = mappedRpcs.get(rpcQName) == null && isBaseRpc(rpcQName);
+ if(needToUseBaseCtx) {
+ currentMappedRpcs = MAPPED_BASE_RPCS;
+ }
+
+ Preconditions.checkNotNull(currentMappedRpcs.get(rpcQName), "Unknown rpc %s, available rpcs: %s", rpcQName, currentMappedRpcs.keySet());
+ if(currentMappedRpcs.get(rpcQName).getInput() == null) {
+ return new NetconfMessage(prepareDomResultForRpcRequest(rpcQName).getNode().getOwnerDocument());
+ }
+
+ Preconditions.checkNotNull(payload, "Transforming an rpc with input: %s, payload cannot be null", rpcQName);
+ Preconditions.checkArgument(payload instanceof ContainerNode,
+ "Transforming an rpc with input: %s, payload has to be a container, but was: %s", rpcQName, payload);
+
+ // Set the path to the input of rpc for the node stream writer
+ rpc = rpc.createChild(QName.cachedReference(QName.create(rpcQName, "input")));
+ final DOMResult result = prepareDomResultForRpcRequest(rpcQName);
+
+ try {
+ // If the schema context for netconf device does not contain model for base netconf operations, use default pre build context with just the base model
+ // This way operations like lock/unlock are supported even if the source for base model was not provided
+ writeNormalizedRpc(((ContainerNode) payload), result, rpc, needToUseBaseCtx ? BASE_NETCONF_CTX : schemaContext);
+ } catch (final XMLStreamException | IOException | IllegalStateException e) {
+ throw new IllegalStateException("Unable to serialize " + rpc, e);
+ }
+
+ final Document node = result.getNode().getOwnerDocument();
+
+ return new NetconfMessage(node);
+ }
+
+ private static boolean isBaseRpc(final QName rpc) {
+ return rpc.getNamespace().equals(NETCONF_URI);
+ }
+
+ private DOMResult prepareDomResultForRpcRequest(final QName rpcQName) {
+ final Document document = XmlUtil.newDocument();
+ final Element rpcNS = document.createElementNS(NETCONF_RPC_QNAME.getNamespace().toString(), NETCONF_RPC_QNAME.getLocalName());
+ // set msg id
+ rpcNS.setAttribute(NetconfMessageTransformUtil.MESSAGE_ID_ATTR, counter.getNewMessageId(MESSAGE_ID_PREFIX));
+ final Element elementNS = document.createElementNS(rpcQName.getNamespace().toString(), rpcQName.getLocalName());
+ rpcNS.appendChild(elementNS);
+ document.appendChild(rpcNS);
+ return new DOMResult(elementNS);
+ }
+
+ private void writeNormalizedRpc(final ContainerNode normalized, final DOMResult result, final SchemaPath schemaPath, final SchemaContext baseNetconfCtx) throws IOException, XMLStreamException {
+ final OrderedNormalizedNodeWriter normalizedNodeWriter;
+ NormalizedNodeStreamWriter normalizedNodeStreamWriter = null;
+ XMLStreamWriter writer = null;
+ try {
+ writer = NetconfMessageTransformUtil.XML_FACTORY.createXMLStreamWriter(result);
+ normalizedNodeStreamWriter = XMLStreamNormalizedNodeStreamWriter.create(writer, baseNetconfCtx, schemaPath);
+ normalizedNodeWriter = new OrderedNormalizedNodeWriter(normalizedNodeStreamWriter, baseNetconfCtx, schemaPath);
+ Collection<DataContainerChild<?, ?>> value = (Collection) normalized.getValue();
+ normalizedNodeWriter.write(value);
+ normalizedNodeWriter.flush();
+ } finally {
+ try {
+ if(normalizedNodeStreamWriter != null) {
+ normalizedNodeStreamWriter.close();
+ }
+ if(writer != null) {
+ writer.close();
+ }
+ } catch (final Exception e) {
+ LOG.warn("Unable to close resource properly", e);
+ }
+ }
+ }
+
+ @Override
+ public synchronized DOMRpcResult toRpcResult(final NetconfMessage message, final SchemaPath rpc) {
+ final NormalizedNode<?, ?> normalizedNode;
+ final QName rpcQName = rpc.getLastComponent();
+ if (NetconfMessageTransformUtil.isDataRetrievalOperation(rpcQName)) {
+ final Element xmlData = NetconfMessageTransformUtil.getDataSubtree(message.getDocument());
+ final ContainerSchemaNode schemaForDataRead = NetconfMessageTransformUtil.createSchemaForDataRead(schemaContext);
+ final ContainerNode dataNode = parserFactory.getContainerNodeParser().parse(Collections.singleton(xmlData), schemaForDataRead);
+
+ normalizedNode = Builders.containerBuilder().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(NetconfMessageTransformUtil.NETCONF_RPC_REPLY_QNAME))
+ .withChild(dataNode).build();
+ } else {
+ final Set<Element> documentElement = Collections.singleton(message.getDocument().getDocumentElement());
+
+ Map<QName, RpcDefinition> currentMappedRpcs = mappedRpcs;
+
+ // Determine whether a base netconf operation is being invoked and also check if the device exposed model for base netconf
+ // If no, use pre built base netconf operations model
+ final boolean needToUseBaseCtx = mappedRpcs.get(rpcQName) == null && isBaseRpc(rpcQName);
+ if(needToUseBaseCtx) {
+ currentMappedRpcs = MAPPED_BASE_RPCS;
+ }
+
+ final RpcDefinition rpcDefinition = currentMappedRpcs.get(rpcQName);
+ Preconditions.checkArgument(rpcDefinition != null, "Unable to parse response of %s, the rpc is unknown", rpcQName);
+
+ // In case no input for rpc is defined, we can simply construct the payload here
+ if (rpcDefinition.getOutput() == null) {
+ Preconditions.checkArgument(XmlElement.fromDomDocument(message.getDocument()).getOnlyChildElementWithSameNamespaceOptionally("ok").isPresent(),
+ "Unexpected content in response of rpc: %s, %s", rpcDefinition.getQName(), message);
+ normalizedNode = null;
+ } else {
+ normalizedNode = parserFactory.getContainerNodeParser().parse(documentElement, rpcDefinition.getOutput());
+ }
+ }
+ return new DefaultDOMRpcResult(normalizedNode);
+ }
+
+ private static class NetconfDeviceNotification implements DOMNotification, DOMEvent {
+ private final ContainerNode content;
+ private final SchemaPath schemaPath;
+ private final Date eventTime;
+
+ NetconfDeviceNotification(final ContainerNode content, final Date eventTime) {
+ this.content = content;
+ this.eventTime = eventTime;
+ this.schemaPath = toPath(content.getNodeType());
+ }
+
+ @Nonnull
+ @Override
+ public SchemaPath getType() {
+ return schemaPath;
+
+ }
+
+ @Nonnull
+ @Override
+ public ContainerNode getBody() {
+ return content;
+ }
+
+ @Override
+ public Date getEventTime() {
+ return eventTime;
+ }
+ }
+}
--- /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.connect.netconf.util;
+
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_CANDIDATE_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_COPY_CONFIG_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_DEFAULT_OPERATION_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_DISCARD_CHANGES_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_ERROR_OPTION_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_GET_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_LOCK_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_RUNNING_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_SOURCE_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_TARGET_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_UNLOCK_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_VALIDATE_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.ROLLBACK_ON_ERROR_OPTION;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.toFilterStructure;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.toId;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.toPath;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.copy.config.input.target.ConfigTarget;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.get.config.input.source.ConfigSource;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.ModifyAction;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+/**
+ * Provides base operations for netconf e.g. get, get-config, edit-config, (un)lock, commit etc.
+ * According to RFC-6241
+ */
+public final class NetconfBaseOps {
+
+ private final DOMRpcService rpc;
+ private final SchemaContext schemaContext;
+
+ public NetconfBaseOps(final DOMRpcService rpc, final SchemaContext schemaContext) {
+ this.rpc = rpc;
+ this.schemaContext = schemaContext;
+ }
+
+ public ListenableFuture<DOMRpcResult> lock(final FutureCallback<DOMRpcResult> callback, final QName datastore) {
+ Preconditions.checkNotNull(callback);
+ Preconditions.checkNotNull(datastore);
+
+ final ListenableFuture<DOMRpcResult> future = rpc.invokeRpc(toPath(NETCONF_LOCK_QNAME), getLockContent(datastore));
+ Futures.addCallback(future, callback);
+ return future;
+ }
+
+ public ListenableFuture<DOMRpcResult> lockCandidate(final FutureCallback<DOMRpcResult> callback) {
+ final ListenableFuture<DOMRpcResult> future = rpc.invokeRpc(toPath(NETCONF_LOCK_QNAME), getLockContent(NETCONF_CANDIDATE_QNAME));
+ Futures.addCallback(future, callback);
+ return future;
+ }
+
+
+ public ListenableFuture<DOMRpcResult> lockRunning(final FutureCallback<DOMRpcResult> callback) {
+ final ListenableFuture<DOMRpcResult> future = rpc.invokeRpc(toPath(NETCONF_LOCK_QNAME), getLockContent(NETCONF_RUNNING_QNAME));
+ Futures.addCallback(future, callback);
+ return future;
+ }
+
+ public ListenableFuture<DOMRpcResult> unlock(final FutureCallback<DOMRpcResult> callback, final QName datastore) {
+ Preconditions.checkNotNull(callback);
+ Preconditions.checkNotNull(datastore);
+
+ final ListenableFuture<DOMRpcResult> future = rpc.invokeRpc(toPath(NETCONF_UNLOCK_QNAME), getUnLockContent(datastore));
+ Futures.addCallback(future, callback);
+ return future;
+ }
+
+ public ListenableFuture<DOMRpcResult> unlockRunning(final FutureCallback<DOMRpcResult> callback) {
+ final ListenableFuture<DOMRpcResult> future = rpc.invokeRpc(toPath(NETCONF_UNLOCK_QNAME), getUnLockContent(NETCONF_RUNNING_QNAME));
+ Futures.addCallback(future, callback);
+ return future;
+ }
+
+ public ListenableFuture<DOMRpcResult> unlockCandidate(final FutureCallback<DOMRpcResult> callback) {
+ final ListenableFuture<DOMRpcResult> future = rpc.invokeRpc(toPath(NETCONF_UNLOCK_QNAME), getUnLockContent(NETCONF_CANDIDATE_QNAME));
+ Futures.addCallback(future, callback);
+ return future;
+ }
+
+ public ListenableFuture<DOMRpcResult> discardChanges(final FutureCallback<DOMRpcResult> callback) {
+ Preconditions.checkNotNull(callback);
+
+ final ListenableFuture<DOMRpcResult> future = rpc.invokeRpc(toPath(NETCONF_DISCARD_CHANGES_QNAME), null);
+ Futures.addCallback(future, callback);
+ return future;
+ }
+
+ public ListenableFuture<DOMRpcResult> commit(final FutureCallback<DOMRpcResult> callback) {
+ Preconditions.checkNotNull(callback);
+
+ final ListenableFuture<DOMRpcResult> future = rpc.invokeRpc(toPath(NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME), NetconfMessageTransformUtil.COMMIT_RPC_CONTENT);
+ Futures.addCallback(future, callback);
+ return future;
+ }
+
+ public ListenableFuture<DOMRpcResult> validate(final FutureCallback<DOMRpcResult> callback, final QName datastore) {
+ Preconditions.checkNotNull(callback);
+ Preconditions.checkNotNull(datastore);
+
+ final ListenableFuture<DOMRpcResult> future = rpc.invokeRpc(toPath(NetconfMessageTransformUtil.NETCONF_VALIDATE_QNAME), getValidateContent(datastore));
+ Futures.addCallback(future, callback);
+ return future;
+ }
+
+ public ListenableFuture<DOMRpcResult> validateCandidate(final FutureCallback<DOMRpcResult> callback) {
+ return validate(callback, NETCONF_CANDIDATE_QNAME);
+ }
+
+
+ public ListenableFuture<DOMRpcResult> validateRunning(final FutureCallback<DOMRpcResult> callback) {
+ return validate(callback, NETCONF_RUNNING_QNAME);
+ }
+
+ public ListenableFuture<DOMRpcResult> copyConfig(final FutureCallback<DOMRpcResult> callback, final QName source, final QName target) {
+ Preconditions.checkNotNull(callback);
+ Preconditions.checkNotNull(source);
+ Preconditions.checkNotNull(target);
+
+ final ListenableFuture<DOMRpcResult> future = rpc.invokeRpc(toPath(NetconfMessageTransformUtil.NETCONF_COPY_CONFIG_QNAME), getCopyConfigContent(source, target));
+ Futures.addCallback(future, callback);
+ return future;
+ }
+
+ public ListenableFuture<DOMRpcResult> copyRunningToCandidate(final FutureCallback<DOMRpcResult> callback) {
+ return copyConfig(callback, NETCONF_RUNNING_QNAME, NETCONF_CANDIDATE_QNAME);
+ }
+
+ public ListenableFuture<DOMRpcResult> getConfig(final FutureCallback<DOMRpcResult> callback, final QName datastore, final Optional<YangInstanceIdentifier> filterPath) {
+ Preconditions.checkNotNull(callback);
+ Preconditions.checkNotNull(datastore);
+
+ final ListenableFuture<DOMRpcResult> future;
+ if (isFilterPresent(filterPath)) {
+ // FIXME the source node has to be wrapped in a choice
+ final DataContainerChild<?, ?> node = toFilterStructure(filterPath.get(), schemaContext);
+ future = rpc.invokeRpc(toPath(NETCONF_GET_CONFIG_QNAME),
+ NetconfMessageTransformUtil.wrap(NETCONF_GET_CONFIG_QNAME, getSourceNode(datastore), node));
+ } else {
+ future = rpc.invokeRpc(toPath(NETCONF_GET_CONFIG_QNAME),
+ NetconfMessageTransformUtil.wrap(NETCONF_GET_CONFIG_QNAME, getSourceNode(datastore)));
+ }
+
+ Futures.addCallback(future, callback);
+ return future;
+ }
+
+ public ListenableFuture<DOMRpcResult> getConfigRunning(final FutureCallback<DOMRpcResult> callback, final Optional<YangInstanceIdentifier> filterPath) {
+ return getConfig(callback, NETCONF_RUNNING_QNAME, filterPath);
+ }
+
+ public ListenableFuture<DOMRpcResult> getConfigCandidate(final FutureCallback<DOMRpcResult> callback, final Optional<YangInstanceIdentifier> filterPath) {
+ return getConfig(callback, NETCONF_CANDIDATE_QNAME, filterPath);
+ }
+
+ public ListenableFuture<DOMRpcResult> get(final FutureCallback<DOMRpcResult> callback, final Optional<YangInstanceIdentifier> filterPath) {
+ Preconditions.checkNotNull(callback);
+
+ final ListenableFuture<DOMRpcResult> future;
+
+ future = isFilterPresent(filterPath) ?
+ rpc.invokeRpc(toPath(NETCONF_GET_QNAME), NetconfMessageTransformUtil.wrap(NETCONF_GET_QNAME, toFilterStructure(filterPath.get(), schemaContext))) :
+ rpc.invokeRpc(toPath(NETCONF_GET_QNAME), NetconfMessageTransformUtil.GET_RPC_CONTENT);
+
+ Futures.addCallback(future, callback);
+ return future;
+ }
+
+ private boolean isFilterPresent(final Optional<YangInstanceIdentifier> filterPath) {
+ return filterPath.isPresent() && !filterPath.get().isEmpty();
+ }
+
+ public ListenableFuture<DOMRpcResult> editConfigCandidate(final FutureCallback<? super DOMRpcResult> callback, final DataContainerChild<?, ?> editStructure, final ModifyAction modifyAction, final boolean rollback) {
+ return editConfig(callback, NETCONF_CANDIDATE_QNAME, editStructure, Optional.of(modifyAction), rollback);
+ }
+
+ public ListenableFuture<DOMRpcResult> editConfigCandidate(final FutureCallback<? super DOMRpcResult> callback, final DataContainerChild<?, ?> editStructure, final boolean rollback) {
+ return editConfig(callback, NETCONF_CANDIDATE_QNAME, editStructure, Optional.<ModifyAction>absent(), rollback);
+ }
+
+ public ListenableFuture<DOMRpcResult> editConfigRunning(final FutureCallback<? super DOMRpcResult> callback, final DataContainerChild<?, ?> editStructure, final ModifyAction modifyAction, final boolean rollback) {
+ return editConfig(callback, NETCONF_RUNNING_QNAME, editStructure, Optional.of(modifyAction), rollback);
+ }
+
+ public ListenableFuture<DOMRpcResult> editConfigRunning(final FutureCallback<? super DOMRpcResult> callback, final DataContainerChild<?, ?> editStructure, final boolean rollback) {
+ return editConfig(callback, NETCONF_RUNNING_QNAME, editStructure, Optional.<ModifyAction>absent(), rollback);
+ }
+
+ public ListenableFuture<DOMRpcResult> editConfig(final FutureCallback<? super DOMRpcResult> callback, final QName datastore, final DataContainerChild<?, ?> editStructure, final Optional<ModifyAction> modifyAction, final boolean rollback) {
+ Preconditions.checkNotNull(editStructure);
+ Preconditions.checkNotNull(callback);
+ Preconditions.checkNotNull(datastore);
+
+ final ListenableFuture<DOMRpcResult> future = rpc.invokeRpc(toPath(NETCONF_EDIT_CONFIG_QNAME), getEditConfigContent(datastore, editStructure, modifyAction, rollback));
+
+ Futures.addCallback(future, callback);
+ return future;
+ }
+
+ public DataContainerChild<?, ?> createEditConfigStrcture(final Optional<NormalizedNode<?, ?>> lastChild, final Optional<ModifyAction> operation, final YangInstanceIdentifier dataPath) {
+ return NetconfMessageTransformUtil.createEditConfigStructure(schemaContext, dataPath, operation, lastChild);
+ }
+
+ private ContainerNode getEditConfigContent(final QName datastore, final DataContainerChild<?, ?> editStructure, final Optional<ModifyAction> defaultOperation, final boolean rollback) {
+ final DataContainerNodeAttrBuilder<YangInstanceIdentifier.NodeIdentifier, ContainerNode> editBuilder = Builders.containerBuilder().withNodeIdentifier(toId(NETCONF_EDIT_CONFIG_QNAME));
+
+ // Target
+ editBuilder.withChild(getTargetNode(datastore));
+
+ // Default operation
+ if(defaultOperation.isPresent()) {
+ final String opString = defaultOperation.get().name().toLowerCase();
+ editBuilder.withChild(Builders.leafBuilder().withNodeIdentifier(toId(NETCONF_DEFAULT_OPERATION_QNAME)).withValue(opString).build());
+ }
+
+ // Error option
+ if(rollback) {
+ editBuilder.withChild(Builders.leafBuilder().withNodeIdentifier(toId(NETCONF_ERROR_OPTION_QNAME)).withValue(ROLLBACK_ON_ERROR_OPTION).build());
+ }
+
+ // Edit content
+ editBuilder.withChild(editStructure);
+ return editBuilder.build();
+ }
+
+ public static DataContainerChild<?, ?> getSourceNode(final QName datastore) {
+ return Builders.containerBuilder().withNodeIdentifier(toId(NETCONF_SOURCE_QNAME))
+ .withChild(
+ Builders.choiceBuilder().withNodeIdentifier(toId(ConfigSource.QNAME)).withChild(
+ Builders.leafBuilder().withNodeIdentifier(toId(datastore)).build()).build()
+ ).build();
+ }
+
+ public static ContainerNode getLockContent(final QName datastore) {
+ return Builders.containerBuilder().withNodeIdentifier(toId(NETCONF_LOCK_QNAME))
+ .withChild(getTargetNode(datastore)).build();
+ }
+
+ public static DataContainerChild<?, ?> getTargetNode(final QName datastore) {
+ return Builders.containerBuilder().withNodeIdentifier(toId(NETCONF_TARGET_QNAME))
+ .withChild(
+ Builders.choiceBuilder().withNodeIdentifier(toId(ConfigTarget.QNAME)).withChild(
+ Builders.leafBuilder().withNodeIdentifier(toId(datastore)).build()).build()
+ ).build();
+ }
+
+ public static NormalizedNode<?, ?> getCopyConfigContent(final QName source, final QName target) {
+ return Builders.containerBuilder().withNodeIdentifier(toId(NETCONF_COPY_CONFIG_QNAME))
+ .withChild(getTargetNode(target)).withChild(getSourceNode(source)).build();
+ }
+
+ public static NormalizedNode<?, ?> getValidateContent(final QName source) {
+ return Builders.containerBuilder().withNodeIdentifier(toId(NETCONF_VALIDATE_QNAME))
+ .withChild(getSourceNode(source)).build();
+ }
+
+ public static NormalizedNode<?, ?> getUnLockContent(final QName datastore) {
+ return Builders.containerBuilder().withNodeIdentifier(toId(NETCONF_UNLOCK_QNAME))
+ .withChild(getTargetNode(datastore)).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.connect.netconf.util;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import java.io.IOException;
+import java.net.URI;
+import java.util.AbstractMap;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Map.Entry;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.dom.DOMSource;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.edit.config.input.EditContent;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.CreateSubscriptionInput;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChange;
+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.RpcResultBuilder;
+import org.opendaylight.yangtools.yang.data.api.ModifyAction;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XMLStreamNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class NetconfMessageTransformUtil {
+
+ private static final Logger LOG= LoggerFactory.getLogger(NetconfMessageTransformUtil.class);
+
+ public static final String MESSAGE_ID_ATTR = "message-id";
+ public static final XMLOutputFactory XML_FACTORY;
+
+ static {
+ XML_FACTORY = XMLOutputFactory.newFactory();
+ XML_FACTORY.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, false);
+ }
+
+ public static final QName CREATE_SUBSCRIPTION_RPC_QNAME = QName.cachedReference(QName.create(CreateSubscriptionInput.QNAME, "create-subscription"));
+ private static final String SUBTREE = "subtree";
+
+ // Blank document used for creation of new DOM nodes
+ private static final Document BLANK_DOCUMENT = XmlUtil.newDocument();
+ public static final String EVENT_TIME = "eventTime";
+
+ private NetconfMessageTransformUtil() {}
+
+ public static final QName IETF_NETCONF_MONITORING = QName.create(NetconfState.QNAME, "ietf-netconf-monitoring");
+ public static final QName GET_DATA_QNAME = QName.create(IETF_NETCONF_MONITORING, "data");
+ public static final QName GET_SCHEMA_QNAME = QName.create(IETF_NETCONF_MONITORING, "get-schema");
+ public static final QName IETF_NETCONF_MONITORING_SCHEMA_FORMAT = QName.create(IETF_NETCONF_MONITORING, "format");
+ public static final QName IETF_NETCONF_MONITORING_SCHEMA_LOCATION = QName.create(IETF_NETCONF_MONITORING, "location");
+ public static final QName IETF_NETCONF_MONITORING_SCHEMA_IDENTIFIER = QName.create(IETF_NETCONF_MONITORING, "identifier");
+ public static final QName IETF_NETCONF_MONITORING_SCHEMA_VERSION = QName.create(IETF_NETCONF_MONITORING, "version");
+ public static final QName IETF_NETCONF_MONITORING_SCHEMA_NAMESPACE = QName.create(IETF_NETCONF_MONITORING, "namespace");
+
+ public static final QName IETF_NETCONF_NOTIFICATIONS = QName.create(NetconfCapabilityChange.QNAME, "ietf-netconf-notifications");
+
+ public static final QName NETCONF_QNAME = QName.cachedReference(QName.create("urn:ietf:params:xml:ns:netconf:base:1.0", "2011-06-01", "netconf"));
+ public static final URI NETCONF_URI = NETCONF_QNAME.getNamespace();
+
+ public static final QName NETCONF_DATA_QNAME = QName.create(NETCONF_QNAME, "data");
+ public static final QName NETCONF_RPC_REPLY_QNAME = QName.create(NETCONF_QNAME, "rpc-reply");
+ public static final QName NETCONF_OK_QNAME = QName.create(NETCONF_QNAME, "ok");
+ public static final QName NETCONF_ERROR_OPTION_QNAME = QName.create(NETCONF_QNAME, "error-option");
+ public static final QName NETCONF_RUNNING_QNAME = QName.create(NETCONF_QNAME, "running");
+ public static final QName NETCONF_SOURCE_QNAME = QName.create(NETCONF_QNAME, "source");
+ public static final QName NETCONF_CANDIDATE_QNAME = QName.create(NETCONF_QNAME, "candidate");
+ public static final QName NETCONF_TARGET_QNAME = QName.create(NETCONF_QNAME, "target");
+ public static final QName NETCONF_CONFIG_QNAME = QName.create(NETCONF_QNAME, "config");
+ public static final QName NETCONF_COMMIT_QNAME = QName.create(NETCONF_QNAME, "commit");
+ public static final QName NETCONF_VALIDATE_QNAME = QName.create(NETCONF_QNAME, "validate");
+ public static final QName NETCONF_COPY_CONFIG_QNAME = QName.create(NETCONF_QNAME, "copy-config");
+ public static final QName NETCONF_OPERATION_QNAME = QName.create(NETCONF_QNAME, "operation");
+ public static final QName NETCONF_DEFAULT_OPERATION_QNAME = QName.create(NETCONF_OPERATION_QNAME, "default-operation");
+ public static final QName NETCONF_EDIT_CONFIG_QNAME = QName.create(NETCONF_QNAME, "edit-config");
+ public static final QName NETCONF_GET_CONFIG_QNAME = QName.create(NETCONF_QNAME, "get-config");
+ public static final QName NETCONF_DISCARD_CHANGES_QNAME = QName.create(NETCONF_QNAME, "discard-changes");
+ public static final QName NETCONF_TYPE_QNAME = QName.create(NETCONF_QNAME, "type");
+ public static final QName NETCONF_FILTER_QNAME = QName.create(NETCONF_QNAME, "filter");
+ public static final QName NETCONF_GET_QNAME = QName.create(NETCONF_QNAME, "get");
+ public static final QName NETCONF_RPC_QNAME = QName.create(NETCONF_QNAME, "rpc");
+
+ public static final URI NETCONF_ROLLBACK_ON_ERROR_URI = URI
+ .create("urn:ietf:params:netconf:capability:rollback-on-error:1.0");
+ public static final String ROLLBACK_ON_ERROR_OPTION = "rollback-on-error";
+
+ public static final URI NETCONF_CANDIDATE_URI = URI
+ .create("urn:ietf:params:netconf:capability:candidate:1.0");
+
+ public static final URI NETCONF_NOTIFICATONS_URI = URI
+ .create("urn:ietf:params:netconf:capability:notification:1.0");
+
+ public static final URI NETCONF_RUNNING_WRITABLE_URI = URI
+ .create("urn:ietf:params:netconf:capability:writable-running:1.0");
+
+ public static final QName NETCONF_LOCK_QNAME = QName.create(NETCONF_QNAME, "lock");
+ public static final QName NETCONF_UNLOCK_QNAME = QName.create(NETCONF_QNAME, "unlock");
+
+ // Discard changes message
+ public static final ContainerNode DISCARD_CHANGES_RPC_CONTENT =
+ Builders.containerBuilder().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(NETCONF_DISCARD_CHANGES_QNAME)).build();
+
+ // Commit changes message
+ public static final ContainerNode COMMIT_RPC_CONTENT =
+ Builders.containerBuilder().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(NETCONF_COMMIT_QNAME)).build();
+
+ // Get message
+ public static final ContainerNode GET_RPC_CONTENT =
+ Builders.containerBuilder().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(NETCONF_GET_QNAME)).build();
+
+ // Create-subscription changes message
+ public static final ContainerNode CREATE_SUBSCRIPTION_RPC_CONTENT =
+ Builders.containerBuilder().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(CREATE_SUBSCRIPTION_RPC_QNAME)).build();
+
+ public static final DataContainerChild<?, ?> EMPTY_FILTER;
+
+ static {
+ final NormalizedNodeAttrBuilder<YangInstanceIdentifier.NodeIdentifier, DOMSource, AnyXmlNode> anyXmlBuilder = Builders.anyXmlBuilder().withNodeIdentifier(toId(NETCONF_FILTER_QNAME));
+ anyXmlBuilder.withAttributes(Collections.singletonMap(NETCONF_TYPE_QNAME, SUBTREE));
+
+ final Element element = XmlUtil.createElement(BLANK_DOCUMENT, NETCONF_FILTER_QNAME.getLocalName(), Optional.of(NETCONF_FILTER_QNAME.getNamespace().toString()));
+ element.setAttributeNS(NETCONF_FILTER_QNAME.getNamespace().toString(), NETCONF_TYPE_QNAME.getLocalName(), "subtree");
+
+ anyXmlBuilder.withValue(new DOMSource(element));
+
+ EMPTY_FILTER = anyXmlBuilder.build();
+ }
+
+ public static DataContainerChild<?, ?> toFilterStructure(final YangInstanceIdentifier identifier, final SchemaContext ctx) {
+ final NormalizedNodeAttrBuilder<YangInstanceIdentifier.NodeIdentifier, DOMSource, AnyXmlNode> anyXmlBuilder = Builders.anyXmlBuilder().withNodeIdentifier(toId(NETCONF_FILTER_QNAME));
+ anyXmlBuilder.withAttributes(Collections.singletonMap(NETCONF_TYPE_QNAME, SUBTREE));
+
+ final NormalizedNode<?, ?> filterContent = ImmutableNodes.fromInstanceId(ctx, identifier);
+
+ final Element element = XmlUtil.createElement(BLANK_DOCUMENT, NETCONF_FILTER_QNAME.getLocalName(), Optional.of(NETCONF_FILTER_QNAME.getNamespace().toString()));
+ element.setAttributeNS(NETCONF_FILTER_QNAME.getNamespace().toString(), NETCONF_TYPE_QNAME.getLocalName(), "subtree");
+
+ try {
+ writeNormalizedNode(filterContent, new DOMResult(element), SchemaPath.ROOT, ctx);
+ } catch (IOException | XMLStreamException e) {
+ throw new IllegalStateException("Unable to serialize filter element for path " + identifier, e);
+ }
+ anyXmlBuilder.withValue(new DOMSource(element));
+
+ return anyXmlBuilder.build();
+ }
+
+ public static void checkValidReply(final NetconfMessage input, final NetconfMessage output)
+ throws NetconfDocumentedException {
+ final String inputMsgId = input.getDocument().getDocumentElement().getAttribute(MESSAGE_ID_ATTR);
+ final String outputMsgId = output.getDocument().getDocumentElement().getAttribute(MESSAGE_ID_ATTR);
+
+ if(inputMsgId.equals(outputMsgId) == false) {
+ final Map<String,String> errorInfo = ImmutableMap.<String,String>builder()
+ .put( "actual-message-id", outputMsgId )
+ .put( "expected-message-id", inputMsgId )
+ .build();
+
+ throw new NetconfDocumentedException( "Response message contained unknown \"message-id\"",
+ null, NetconfDocumentedException.ErrorType.protocol,
+ NetconfDocumentedException.ErrorTag.bad_attribute,
+ NetconfDocumentedException.ErrorSeverity.error, errorInfo );
+ }
+ }
+
+ public static void checkSuccessReply(final NetconfMessage output) throws NetconfDocumentedException {
+ if(NetconfMessageUtil.isErrorMessage(output)) {
+ throw NetconfDocumentedException.fromXMLDocument(output.getDocument());
+ }
+ }
+
+ public static RpcError toRpcError( final NetconfDocumentedException ex ) {
+ final StringBuilder infoBuilder = new StringBuilder();
+ final Map<String, String> errorInfo = ex.getErrorInfo();
+ if(errorInfo != null) {
+ for( final Entry<String,String> e: errorInfo.entrySet() ) {
+ infoBuilder.append( '<' ).append( e.getKey() ).append( '>' ).append( e.getValue() )
+ .append( "</" ).append( e.getKey() ).append( '>' );
+
+ }
+ }
+
+ final ErrorSeverity severity = toRpcErrorSeverity( ex.getErrorSeverity() );
+ return severity == ErrorSeverity.ERROR ?
+ RpcResultBuilder.newError(
+ toRpcErrorType( ex.getErrorType() ), ex.getErrorTag().getTagValue(),
+ ex.getLocalizedMessage(), null, infoBuilder.toString(), ex.getCause() ) :
+ RpcResultBuilder.newWarning(
+ toRpcErrorType( ex.getErrorType() ), ex.getErrorTag().getTagValue(),
+ ex.getLocalizedMessage(), null, infoBuilder.toString(), ex.getCause() );
+ }
+
+ private static ErrorSeverity toRpcErrorSeverity( final NetconfDocumentedException.ErrorSeverity severity ) {
+ switch (severity) {
+ case warning:
+ return RpcError.ErrorSeverity.WARNING;
+ default:
+ return RpcError.ErrorSeverity.ERROR;
+ }
+ }
+
+ private static RpcError.ErrorType toRpcErrorType(final NetconfDocumentedException.ErrorType type) {
+ switch (type) {
+ case protocol:
+ return RpcError.ErrorType.PROTOCOL;
+ case rpc:
+ return RpcError.ErrorType.RPC;
+ case transport:
+ return RpcError.ErrorType.TRANSPORT;
+ default:
+ return RpcError.ErrorType.APPLICATION;
+ }
+ }
+
+ public static YangInstanceIdentifier.NodeIdentifier toId(final YangInstanceIdentifier.PathArgument qname) {
+ return toId(qname.getNodeType());
+ }
+
+ public static YangInstanceIdentifier.NodeIdentifier toId(final QName nodeType) {
+ return new YangInstanceIdentifier.NodeIdentifier(nodeType);
+ }
+
+ public static Element getDataSubtree(final Document doc) {
+ return (Element) doc.getElementsByTagNameNS(NETCONF_URI.toString(), "data").item(0);
+ }
+
+ public static boolean isDataRetrievalOperation(final QName rpc) {
+ return NETCONF_URI.equals(rpc.getNamespace())
+ && (NETCONF_GET_CONFIG_QNAME.getLocalName().equals(rpc.getLocalName())
+ || NETCONF_GET_QNAME.getLocalName().equals(rpc.getLocalName()));
+ }
+
+ public static ContainerSchemaNode createSchemaForDataRead(final SchemaContext schemaContext) {
+ return new NodeContainerProxy(NETCONF_DATA_QNAME, schemaContext.getChildNodes());
+ }
+
+ public static ContainerSchemaNode createSchemaForNotification(final NotificationDefinition next) {
+ return new NodeContainerProxy(next.getQName(), next.getChildNodes(), next.getAvailableAugmentations());
+ }
+
+ public static ContainerNode wrap(final QName name, final DataContainerChild<?, ?>... node) {
+ return Builders.containerBuilder().withNodeIdentifier(toId(name)).withValue(ImmutableList.copyOf(node)).build();
+ }
+
+ public static DataContainerChild<?, ?> createEditConfigStructure(final SchemaContext ctx, final YangInstanceIdentifier dataPath,
+ final Optional<ModifyAction> operation, final Optional<NormalizedNode<?, ?>> lastChildOverride) {
+ final NormalizedNode<?, ?> configContent;
+
+ if (dataPath.isEmpty()) {
+ Preconditions.checkArgument(lastChildOverride.isPresent(), "Data has to be present when creating structure for top level element");
+ Preconditions.checkArgument(lastChildOverride.get() instanceof DataContainerChild<?, ?>,
+ "Data has to be either container or a list node when creating structure for top level element, but was: %s", lastChildOverride.get());
+ configContent = lastChildOverride.get();
+ } else {
+ final Entry<QName, ModifyAction> modifyOperation =
+ operation.isPresent() ? new AbstractMap.SimpleEntry<>(NETCONF_OPERATION_QNAME, operation.get()) : null;
+ configContent = ImmutableNodes.fromInstanceId(ctx, dataPath, lastChildOverride, Optional.fromNullable(modifyOperation));
+ }
+
+ final Element element = XmlUtil.createElement(BLANK_DOCUMENT, NETCONF_CONFIG_QNAME.getLocalName(), Optional.of(NETCONF_CONFIG_QNAME.getNamespace().toString()));
+ try {
+ writeNormalizedNode(configContent, new DOMResult(element), SchemaPath.ROOT, ctx);
+ } catch (IOException | XMLStreamException e) {
+ throw new IllegalStateException("Unable to serialize edit config content element for path " + dataPath, e);
+ }
+ final DOMSource value = new DOMSource(element);
+
+ return Builders.choiceBuilder().withNodeIdentifier(toId(EditContent.QNAME)).withChild(
+ Builders.anyXmlBuilder().withNodeIdentifier(toId(NETCONF_CONFIG_QNAME)).withValue(value).build()).build();
+ }
+
+ public static SchemaPath toPath(final QName rpc) {
+ return SchemaPath.create(true, rpc);
+ }
+
+ // FIXME similar code is in netconf-notifications-impl , DRY
+ public static void writeNormalizedNode(final NormalizedNode<?, ?> normalized, final DOMResult result, final SchemaPath schemaPath, final SchemaContext context)
+ throws IOException, XMLStreamException {
+ NormalizedNodeWriter normalizedNodeWriter = null;
+ NormalizedNodeStreamWriter normalizedNodeStreamWriter = null;
+ XMLStreamWriter writer = null;
+ try {
+ writer = XML_FACTORY.createXMLStreamWriter(result);
+ normalizedNodeStreamWriter = XMLStreamNormalizedNodeStreamWriter.create(writer, context, schemaPath);
+ normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(normalizedNodeStreamWriter);
+
+ normalizedNodeWriter.write(normalized);
+
+ normalizedNodeWriter.flush();
+ } finally {
+ try {
+ if(normalizedNodeWriter != null) {
+ normalizedNodeWriter.close();
+ }
+ if(normalizedNodeStreamWriter != null) {
+ normalizedNodeStreamWriter.close();
+ }
+ if(writer != null) {
+ writer.close();
+ }
+ } catch (final Exception e) {
+ LOG.warn("Unable to close resource properly", 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.connect.netconf.util;
+
+import com.google.common.util.concurrent.FutureCallback;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Simple Netconf rpc logging callback
+ */
+public class NetconfRpcFutureCallback implements FutureCallback<DOMRpcResult> {
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfRpcFutureCallback.class);
+
+ private final String type;
+ private final RemoteDeviceId id;
+
+ public NetconfRpcFutureCallback(final String prefix, final RemoteDeviceId id) {
+ this.type = prefix;
+ this.id = id;
+ }
+
+ @Override
+ public void onSuccess(final DOMRpcResult result) {
+ if(result.getErrors().isEmpty()) {
+ LOG.trace("{}: {} invoked successfully", id, type);
+ } else {
+ onUnsuccess(result);
+ }
+ }
+
+ protected void onUnsuccess(final DOMRpcResult result) {
+ LOG.warn("{}: {} invoked unsuccessfully: {}", id, type, result.getErrors());
+ }
+
+ @Override
+ public void onFailure(final Throwable t) {
+ LOG.warn("{}: {} failed.", id, type, t);
+ }
+}
--- /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.connect.netconf.util;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.Status;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.UsesNode;
+
+/**
+ * Simple proxy for container like schema nodes, where user provides a collection of children schema nodes
+ */
+public final class NodeContainerProxy implements ContainerSchemaNode {
+
+ private final Map<QName, DataSchemaNode> childNodes;
+ private final QName qName;
+ private final Set<AugmentationSchema> availableAugmentations;
+
+ public NodeContainerProxy(final QName qName, final Map<QName, DataSchemaNode> childNodes, final Set<AugmentationSchema> availableAugmentations) {
+ this.availableAugmentations = availableAugmentations;
+ this.childNodes = Preconditions.checkNotNull(childNodes, "childNodes");
+ this.qName = qName;
+ }
+
+ public NodeContainerProxy(final QName qName, final Collection<DataSchemaNode> childNodes) {
+ this(qName, asMap(childNodes), Collections.<AugmentationSchema>emptySet());
+ }
+
+ public NodeContainerProxy(final QName qName, final Collection<DataSchemaNode> childNodes, final Set<AugmentationSchema> availableAugmentations) {
+ this(qName, asMap(childNodes), availableAugmentations);
+ }
+
+ private static Map<QName, DataSchemaNode> asMap(final Collection<DataSchemaNode> childNodes) {
+ return Maps.uniqueIndex(childNodes, new Function<DataSchemaNode, QName>() {
+ @Override
+ public QName apply(final DataSchemaNode input) {
+ return input.getQName();
+ }
+ });
+ }
+
+ @Override
+ public Set<TypeDefinition<?>> getTypeDefinitions() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public Set<DataSchemaNode> getChildNodes() {
+ return Sets.newHashSet(childNodes.values());
+ }
+
+ @Override
+ public Set<GroupingDefinition> getGroupings() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public DataSchemaNode getDataChildByName(final QName qName) {
+ return childNodes.get(qName);
+ }
+
+ @Override
+ public DataSchemaNode getDataChildByName(final String s) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<UsesNode> getUses() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public boolean isPresenceContainer() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<AugmentationSchema> getAvailableAugmentations() {
+ return availableAugmentations;
+ }
+
+ @Override
+ public boolean isAugmenting() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isAddedByUses() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isConfiguration() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ConstraintDefinition getConstraints() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public QName getQName() {
+ return qName;
+ }
+
+ @Override
+ public SchemaPath getPath() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getDescription() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getReference() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Status getStatus() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+ return Collections.emptyList();
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015 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.connect.util;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class MessageCounter {
+ final AtomicInteger messageId = new AtomicInteger(0);
+
+ private static final String messageIdBlueprint = "%s-%s";
+
+ public String getNewMessageId(final String prefix) {
+ Preconditions.checkArgument(Strings.isNullOrEmpty(prefix) == false, "Null or empty prefix");
+ return String.format(messageIdBlueprint, prefix, getNewMessageId());
+ }
+
+ public String getNewMessageId() {
+ return Integer.toString(messageId.getAndIncrement());
+ }
+}
--- /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.connect.util;
+
+import com.google.common.base.Preconditions;
+import java.net.InetSocketAddress;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.HostBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.network.topology.topology.topology.types.TopologyNetconf;
+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 org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+
+public final class RemoteDeviceId {
+
+ private final String name;
+ private final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier path;
+ private final InstanceIdentifier<Node> bindingPath;
+ private final NodeKey key;
+ private final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier topologyPath;
+ private final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node> topologyBindingPath;
+ private InetSocketAddress address;
+ private Host host;
+
+ public RemoteDeviceId(final ModuleIdentifier identifier, InetSocketAddress address) {
+ this(Preconditions.checkNotNull(identifier).getInstanceName());
+ this.address = address;
+ this.host = buildHost();
+ }
+
+ private RemoteDeviceId(final String name) {
+ this.name = Preconditions.checkNotNull(name);
+ this.key = new NodeKey(new NodeId(name));
+ this.path = createBIPath(name);
+ this.bindingPath = createBindingPath(key);
+ this.topologyPath = createBIPathForTopology(name);
+ this.topologyBindingPath = createBindingPathForTopology(key);
+ }
+
+ public RemoteDeviceId(final String name, InetSocketAddress address) {
+ this(name);
+ this.address = address;
+ this.host = buildHost();
+ }
+
+ private static InstanceIdentifier<Node> createBindingPath(final NodeKey key) {
+ return InstanceIdentifier.builder(Nodes.class).child(Node.class, key).build();
+ }
+
+ private static org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier createBIPath(final String name) {
+ final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder builder =
+ org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.builder();
+ builder.node(Nodes.QNAME).node(Node.QNAME).nodeWithKey(Node.QNAME, QName.create(Node.QNAME.getNamespace(), Node.QNAME.getRevision(), "id"), name);
+
+ return builder.build();
+ }
+
+ private static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node> createBindingPathForTopology(final NodeKey key) {
+ final InstanceIdentifier<NetworkTopology> networkTopology = InstanceIdentifier.builder(NetworkTopology.class).build();
+ final KeyedInstanceIdentifier<Topology, TopologyKey> topology = networkTopology.child(Topology.class, new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName())));
+ return topology
+ .child(org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node.class,
+ new org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey(
+ new org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId(key.getId().getValue())));
+ }
+
+ private static org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier createBIPathForTopology(final String name) {
+ final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder builder =
+ org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.builder();
+ builder
+ .node(NetworkTopology.QNAME)
+ .node(Topology.QNAME)
+ .nodeWithKey(Topology.QNAME, QName.create(Topology.QNAME, "topology-id"), TopologyNetconf.QNAME.getLocalName())
+ .node(org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node.QNAME)
+ .nodeWithKey(org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node.QNAME,
+ QName.create(org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node.QNAME, "node-id"), name);
+ return builder.build();
+ }
+
+ private Host buildHost() {
+ return HostBuilder.getDefaultInstance(address.getHostString());
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public InstanceIdentifier<Node> getBindingPath() {
+ return bindingPath;
+ }
+
+ public org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier getPath() {
+ return path;
+ }
+
+ public NodeKey getBindingKey() {
+ return key;
+ }
+
+ public InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node> getTopologyBindingPath() {
+ return topologyBindingPath;
+ }
+
+ public YangInstanceIdentifier getTopologyPath() {
+ return topologyPath;
+ }
+
+ public InetSocketAddress getAddress() {
+ return address;
+ }
+
+ public Host getHost() {
+ return host;
+ }
+
+ @Override
+ public String toString() {
+ return "RemoteDevice{" + name +'}';
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof RemoteDeviceId)) {
+ return false;
+ }
+
+ final RemoteDeviceId that = (RemoteDeviceId) o;
+
+ if (!name.equals(that.name)) {
+ return false;
+ }
+ if (!bindingPath.equals(that.bindingPath)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = name.hashCode();
+ result = 31 * result + bindingPath.hashCode();
+ return result;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015 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
+ */
+
+ /**
+ * Utility classes for remote connectors e.g. netconf connector
+ *
+ * TODO extract into separate bundle when another connector is implemented e.g. restconf connector
+ */
+package org.opendaylight.controller.sal.connect.util;
--- /dev/null
+module netconf-node-topology {
+ namespace "urn:opendaylight:netconf-node-topology";
+ prefix "nettop";
+
+ import network-topology { prefix nt; revision-date 2013-10-21; }
+ import yang-ext { prefix ext; revision-date "2013-07-09";}
+ import ietf-inet-types { prefix inet; revision-date "2010-09-24"; }
+
+ revision "2015-01-14" {
+ description "Initial revision of Topology model";
+ }
+
+ augment "/nt:network-topology/nt:topology/nt:topology-types" {
+ container topology-netconf {
+ }
+ }
+
+ grouping netconf-node-fields {
+ leaf connection-status {
+ type enumeration {
+ enum connecting;
+ enum connected;
+ enum unable-to-connect;
+ }
+ }
+
+ leaf host {
+ type inet:host;
+ }
+
+ leaf port {
+ type inet:port-number;
+ }
+
+ leaf connected-message {
+ type string;
+ }
+
+ container available-capabilities {
+ leaf-list available-capability {
+ type string;
+ }
+ }
+
+ container unavailable-capabilities {
+ list unavailable-capability {
+ leaf capability {
+ type string;
+ }
+
+ leaf failure-reason {
+ type enumeration {
+ enum missing-source;
+ enum unable-to-resolve;
+ }
+ }
+ }
+ }
+
+ container pass-through {
+ when "../connection-status = connected";
+ description
+ "When the underlying node is connected, its NETCONF context
+ is available verbatim under this container through the
+ mount extension.";
+ }
+ }
+
+ augment "/nt:network-topology/nt:topology/nt:node" {
+ when "../../nt:topology-types/topology-netconf";
+ ext:augment-identifier "netconf-node";
+
+ uses netconf-node-fields;
+ }
+}
--- /dev/null
+module odl-sal-netconf-connector-cfg {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf";
+ prefix "sal-netconf";
+
+ import config { prefix config; revision-date 2013-04-05; }
+ import threadpool {prefix th;}
+ import netty {prefix netty;}
+ import opendaylight-md-sal-dom {prefix dom;}
+ import opendaylight-md-sal-binding {prefix md-sal-binding; revision-date 2013-10-28;}
+ import odl-netconf-cfg { prefix cfg-net; revision-date 2014-04-08; }
+ import ietf-inet-types {prefix inet; revision-date "2010-09-24";}
+
+ description
+ "Service definition for Binding Aware MD-SAL.";
+
+ revision "2013-10-28" {
+ description
+ "Initial revision";
+ }
+
+ identity sal-netconf-connector {
+ base config:module-type;
+ config:java-name-prefix NetconfConnector;
+ }
+
+ grouping server {
+ leaf address {
+ type string;
+ }
+
+ leaf port {
+ type uint32;
+ }
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case sal-netconf-connector {
+ when "/config:modules/config:module/config:type = 'sal-netconf-connector'";
+
+ leaf address {
+ type inet:host;
+ }
+
+ leaf port {
+ type inet:port-number;
+ }
+
+ leaf tcp-only {
+ type boolean;
+ }
+
+ leaf username {
+ type string;
+ }
+
+ leaf password {
+ type string;
+ }
+
+ container yang-module-capabilities {
+ leaf-list capability {
+ type string;
+ description "Set a list of capabilities to override capabilities provided in device's hello message.
+ Can be used for devices that do not report any yang modules in their hello message";
+ }
+ }
+
+ leaf reconnect-on-changed-schema {
+ type boolean;
+ default false;
+ description "If true, the connector would auto disconnect/reconnect when schemas are changed in the remote device.
+ The connector subscribes (right after connect) to base netconf notifications and listens for netconf-capability-change notification";
+ }
+
+ container dom-registry {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity dom:dom-broker-osgi-registry;
+ }
+ }
+ }
+
+ container binding-registry {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity md-sal-binding:binding-broker-osgi-registry;
+ }
+ }
+ }
+
+ container event-executor {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity netty:netty-event-executor;
+ }
+ }
+ }
+
+ container processing-executor {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity th:threadpool;
+ }
+ }
+
+ description "Makes up for flaws in netty threading design";
+ }
+
+ container client-dispatcher {
+ uses config:service-ref {
+ refine type {
+ mandatory false;
+ config:required-identity cfg-net:netconf-client-dispatcher;
+ }
+ }
+ }
+
+ leaf connection-timeout-millis {
+ description "Specifies timeout in milliseconds after which connection must be established.";
+ type uint32;
+ default 20000;
+ }
+
+ leaf default-request-timeout-millis {
+ description "Timeout for blocking operations within transactions.";
+ type uint32;
+ default 60000;
+ }
+
+ leaf max-connection-attempts {
+ description "Maximum number of connection retries. Non positive value or null is interpreted as infinity.";
+ type uint32;
+ default 0; // retry forever
+ }
+
+ leaf between-attempts-timeout-millis {
+ description "Initial timeout in milliseconds to wait between connection attempts. Will be multiplied by sleep-factor with every additional attempt";
+ type uint16;
+ default 2000;
+ }
+
+ leaf sleep-factor {
+ type decimal64 {
+ fraction-digits 1;
+ }
+ default 1.5;
+ }
+
+ // Keepalive configuration
+ leaf keepalive-delay {
+ type uint32;
+ default 120;
+ description "Netconf connector sends keepalive RPCs while the session is idle, this delay specifies the delay between keepalive RPC in seconds
+ If a value <1 is provided, no keepalives will be sent";
+ }
+
+ container keepalive-executor {
+ uses config:service-ref {
+ refine type {
+ mandatory false;
+ config:required-identity th:scheduled-threadpool;
+ }
+ }
+
+ description "Dedicated solely to keepalive execution";
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015 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.connect.netconf;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyCollectionOf;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.Futures;
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.controller.md.sal.dom.spi.DefaultDOMRpcResult;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
+import org.opendaylight.controller.sal.connect.api.MessageTransformer;
+import org.opendaylight.controller.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.controller.sal.connect.netconf.listener.NetconfDeviceCommunicator;
+import org.opendaylight.controller.sal.connect.netconf.listener.NetconfSessionPreferences;
+import org.opendaylight.controller.sal.connect.netconf.sal.NetconfDeviceRpc;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.ModuleImport;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.repo.api.MissingSchemaSourceException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaResolutionException;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+
+public class NetconfDeviceTest {
+
+ private static final NetconfMessage notification;
+
+ private static final ContainerNode compositeNode;
+
+ static {
+ try {
+ compositeNode = mockClass(ContainerNode.class);
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ try {
+ notification = new NetconfMessage(XmlUtil.readXmlToDocument(NetconfDeviceTest.class.getResourceAsStream("/notification-payload.xml")));
+ } catch (Exception e) {
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ private static final DOMRpcResult rpcResultC = new DefaultDOMRpcResult(compositeNode);
+
+ public static final String TEST_NAMESPACE = "test:namespace";
+ public static final String TEST_MODULE = "test-module";
+ public static final String TEST_REVISION = "2013-07-22";
+ public static final SourceIdentifier TEST_SID = new SourceIdentifier(TEST_MODULE, Optional.of(TEST_REVISION));
+ public static final String TEST_CAPABILITY = TEST_NAMESPACE + "?module=" + TEST_MODULE + "&revision=" + TEST_REVISION;
+
+ public static final SourceIdentifier TEST_SID2 = new SourceIdentifier(TEST_MODULE + "2", Optional.of(TEST_REVISION));
+ public static final String TEST_CAPABILITY2 = TEST_NAMESPACE + "?module=" + TEST_MODULE + "2" + "&revision=" + TEST_REVISION;
+
+ private static final NetconfStateSchemas.NetconfStateSchemasResolver stateSchemasResolver = new NetconfStateSchemas.NetconfStateSchemasResolver() {
+
+ @Override
+ public NetconfStateSchemas resolve(final NetconfDeviceRpc deviceRpc, final NetconfSessionPreferences remoteSessionCapabilities, final RemoteDeviceId id) {
+ return NetconfStateSchemas.EMPTY;
+ }
+ };
+
+ @Test
+ public void testNetconfDeviceFailFirstSchemaFailSecondEmpty() throws Exception {
+ final ArrayList<String> capList = Lists.newArrayList(TEST_CAPABILITY);
+
+ final RemoteDeviceHandler<NetconfSessionPreferences> facade = getFacade();
+ final NetconfDeviceCommunicator listener = getListener();
+
+ final SchemaContextFactory schemaFactory = getSchemaFactory();
+
+ // Make fallback attempt to fail due to empty resolved sources
+ final SchemaResolutionException schemaResolutionException
+ = new SchemaResolutionException("fail first",
+ Collections.<SourceIdentifier>emptyList(), HashMultimap.<SourceIdentifier, ModuleImport>create());
+ doReturn(Futures.immediateFailedCheckedFuture(
+ schemaResolutionException))
+ .when(schemaFactory).createSchemaContext(anyCollectionOf(SourceIdentifier.class));
+
+ final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO
+ = new NetconfDevice.SchemaResourcesDTO(getSchemaRegistry(), schemaFactory, stateSchemasResolver);
+ final NetconfDevice device = new NetconfDevice(schemaResourcesDTO, getId(), facade, getExecutor(),true);
+ // Monitoring not supported
+ final NetconfSessionPreferences sessionCaps = getSessionCaps(false, capList);
+ device.onRemoteSessionUp(sessionCaps, listener);
+
+ Mockito.verify(facade, Mockito.timeout(5000)).onDeviceDisconnected();
+ Mockito.verify(listener, Mockito.timeout(5000)).close();
+ Mockito.verify(schemaFactory, times(1)).createSchemaContext(anyCollectionOf(SourceIdentifier.class));
+ }
+
+ @Test
+ public void testNetconfDeviceMissingSource() throws Exception {
+ final RemoteDeviceHandler<NetconfSessionPreferences> facade = getFacade();
+ final NetconfDeviceCommunicator listener = getListener();
+ final SchemaContext schema = getSchema();
+
+ final SchemaContextFactory schemaFactory = getSchemaFactory();
+
+ // Make fallback attempt to fail due to empty resolved sources
+ final MissingSchemaSourceException schemaResolutionException = new MissingSchemaSourceException("fail first", TEST_SID);
+ doAnswer(new Answer<Object>() {
+ @Override
+ public Object answer(final InvocationOnMock invocation) throws Throwable {
+ if(((Collection<?>) invocation.getArguments()[0]).size() == 2) {
+ return Futures.immediateFailedCheckedFuture(schemaResolutionException);
+ } else {
+ return Futures.immediateCheckedFuture(schema);
+ }
+ }
+ }).when(schemaFactory).createSchemaContext(anyCollectionOf(SourceIdentifier.class));
+
+ final NetconfStateSchemas.NetconfStateSchemasResolver stateSchemasResolver = new NetconfStateSchemas.NetconfStateSchemasResolver() {
+ @Override
+ public NetconfStateSchemas resolve(final NetconfDeviceRpc deviceRpc, final NetconfSessionPreferences remoteSessionCapabilities, final RemoteDeviceId id) {
+ final Module first = Iterables.getFirst(schema.getModules(), null);
+ final QName qName = QName.create(first.getQNameModule(), first.getName());
+ final NetconfStateSchemas.RemoteYangSchema source1 = new NetconfStateSchemas.RemoteYangSchema(qName);
+ final NetconfStateSchemas.RemoteYangSchema source2 = new NetconfStateSchemas.RemoteYangSchema(QName.create(first.getQNameModule(), "test-module2"));
+ return new NetconfStateSchemas(Sets.newHashSet(source1, source2));
+ }
+ };
+
+ final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO
+ = new NetconfDevice.SchemaResourcesDTO(getSchemaRegistry(), schemaFactory, stateSchemasResolver);
+
+ final NetconfDevice device = new NetconfDevice(schemaResourcesDTO, getId(), facade, getExecutor(), true);
+ // Monitoring supported
+ final NetconfSessionPreferences sessionCaps = getSessionCaps(true, Lists.newArrayList(TEST_CAPABILITY, TEST_CAPABILITY2));
+ device.onRemoteSessionUp(sessionCaps, listener);
+
+ Mockito.verify(facade, Mockito.timeout(5000)).onDeviceConnected(any(SchemaContext.class), any(NetconfSessionPreferences.class), any(NetconfDeviceRpc.class));
+ Mockito.verify(schemaFactory, times(2)).createSchemaContext(anyCollectionOf(SourceIdentifier.class));
+ }
+
+ private SchemaSourceRegistry getSchemaRegistry() {
+ final SchemaSourceRegistry mock = mock(SchemaSourceRegistry.class);
+ final SchemaSourceRegistration<?> mockReg = mock(SchemaSourceRegistration.class);
+ doNothing().when(mockReg).close();
+ doReturn(mockReg).when(mock).registerSchemaSource(any(org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider.class), any(PotentialSchemaSource.class));
+ return mock;
+ }
+
+ @Test
+ public void testNotificationBeforeSchema() throws Exception {
+ final RemoteDeviceHandler<NetconfSessionPreferences> facade = getFacade();
+ final NetconfDeviceCommunicator listener = getListener();
+
+ final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO
+ = new NetconfDevice.SchemaResourcesDTO(getSchemaRegistry(), getSchemaFactory(), stateSchemasResolver);
+ final NetconfDevice device = new NetconfDevice(schemaResourcesDTO, getId(), facade, getExecutor(), true);
+
+ device.onNotification(notification);
+ device.onNotification(notification);
+
+ verify(facade, times(0)).onNotification(any(DOMNotification.class));
+
+ final NetconfSessionPreferences sessionCaps = getSessionCaps(true,
+ Lists.newArrayList(TEST_CAPABILITY));
+
+ final DOMRpcService deviceRpc = mock(DOMRpcService.class);
+
+ device.handleSalInitializationSuccess(NetconfToNotificationTest.getNotificationSchemaContext(getClass()), sessionCaps, deviceRpc);
+
+ verify(facade, timeout(10000).times(2)).onNotification(any(DOMNotification.class));
+
+ device.onNotification(notification);
+ verify(facade, timeout(10000).times(3)).onNotification(any(DOMNotification.class));
+ }
+
+ @Test
+ public void testNetconfDeviceReconnect() throws Exception {
+ final RemoteDeviceHandler<NetconfSessionPreferences> facade = getFacade();
+ final NetconfDeviceCommunicator listener = getListener();
+
+ final SchemaContextFactory schemaContextProviderFactory = getSchemaFactory();
+
+ final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO
+ = new NetconfDevice.SchemaResourcesDTO(getSchemaRegistry(), schemaContextProviderFactory, stateSchemasResolver);
+ final NetconfDevice device = new NetconfDevice(schemaResourcesDTO, getId(), facade, getExecutor(), true);
+ final NetconfSessionPreferences sessionCaps = getSessionCaps(true,
+ Lists.newArrayList(TEST_NAMESPACE + "?module=" + TEST_MODULE + "&revision=" + TEST_REVISION));
+ device.onRemoteSessionUp(sessionCaps, listener);
+
+ verify(schemaContextProviderFactory, timeout(5000)).createSchemaContext(any(Collection.class));
+ verify(facade, timeout(5000)).onDeviceConnected(any(SchemaContext.class), any(NetconfSessionPreferences.class), any(DOMRpcService.class));
+
+ device.onRemoteSessionDown();
+ verify(facade, timeout(5000)).onDeviceDisconnected();
+
+ device.onRemoteSessionUp(sessionCaps, listener);
+
+ verify(schemaContextProviderFactory, timeout(5000).times(2)).createSchemaContext(any(Collection.class));
+ verify(facade, timeout(5000).times(2)).onDeviceConnected(any(SchemaContext.class), any(NetconfSessionPreferences.class), any(DOMRpcService.class));
+ }
+
+ private SchemaContextFactory getSchemaFactory() {
+ final SchemaContextFactory schemaFactory = mockClass(SchemaContextFactory.class);
+ doReturn(Futures.immediateCheckedFuture(getSchema())).when(schemaFactory).createSchemaContext(any(Collection.class));
+ return schemaFactory;
+ }
+
+ public static SchemaContext getSchema() {
+ final YangParserImpl parser = new YangParserImpl();
+ final List<InputStream> modelsToParse = Lists.newArrayList(
+ NetconfDeviceTest.class.getResourceAsStream("/schemas/test-module.yang")
+ );
+ final Set<Module> models = parser.parseYangModelsFromStreams(modelsToParse);
+ return parser.resolveSchemaContext(models);
+ }
+
+ private RemoteDeviceHandler<NetconfSessionPreferences> getFacade() throws Exception {
+ final RemoteDeviceHandler<NetconfSessionPreferences> remoteDeviceHandler = mockCloseableClass(RemoteDeviceHandler.class);
+ doNothing().when(remoteDeviceHandler).onDeviceConnected(any(SchemaContext.class), any(NetconfSessionPreferences.class), any(NetconfDeviceRpc.class));
+ doNothing().when(remoteDeviceHandler).onDeviceDisconnected();
+ doNothing().when(remoteDeviceHandler).onNotification(any(DOMNotification.class));
+ return remoteDeviceHandler;
+ }
+
+ private <T extends AutoCloseable> T mockCloseableClass(final Class<T> remoteDeviceHandlerClass) throws Exception {
+ final T mock = mockClass(remoteDeviceHandlerClass);
+ doNothing().when(mock).close();
+ return mock;
+ }
+
+ private static <T> T mockClass(final Class<T> remoteDeviceHandlerClass) {
+ final T mock = mock(remoteDeviceHandlerClass);
+ Mockito.doReturn(remoteDeviceHandlerClass.getSimpleName()).when(mock).toString();
+ return mock;
+ }
+
+ public RemoteDeviceId getId() {
+ return new RemoteDeviceId("test-D", InetSocketAddress.createUnresolved("localhost", 22));
+ }
+
+ public ExecutorService getExecutor() {
+ return Executors.newSingleThreadExecutor();
+ }
+
+ public MessageTransformer<NetconfMessage> getMessageTransformer() throws Exception {
+ final MessageTransformer<NetconfMessage> messageTransformer = mockClass(MessageTransformer.class);
+ doReturn(notification).when(messageTransformer).toRpcRequest(any(SchemaPath.class), any(NormalizedNode.class));
+ doReturn(rpcResultC).when(messageTransformer).toRpcResult(any(NetconfMessage.class), any(SchemaPath.class));
+ doReturn(compositeNode).when(messageTransformer).toNotification(any(NetconfMessage.class));
+ return messageTransformer;
+ }
+
+ public NetconfSessionPreferences getSessionCaps(final boolean addMonitor, final Collection<String> additionalCapabilities) {
+ final ArrayList<String> capabilities = Lists.newArrayList(
+ XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0,
+ XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_1);
+
+ if(addMonitor) {
+ capabilities.add(NetconfMessageTransformUtil.IETF_NETCONF_MONITORING.getNamespace().toString());
+ }
+
+ capabilities.addAll(additionalCapabilities);
+
+ return NetconfSessionPreferences.fromStrings(
+ capabilities);
+ }
+
+ public NetconfDeviceCommunicator getListener() throws Exception {
+ final NetconfDeviceCommunicator remoteDeviceCommunicator = mockCloseableClass(NetconfDeviceCommunicator.class);
+// doReturn(Futures.immediateFuture(rpcResult)).when(remoteDeviceCommunicator).sendRequest(any(NetconfMessage.class), any(QName.class));
+ return remoteDeviceCommunicator;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015 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.connect.netconf;
+
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import java.net.InetSocketAddress;
+import java.util.Collections;
+import java.util.Set;
+import org.junit.Test;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlUtils;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNodeParser;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class NetconfStateSchemasTest {
+
+ @Test
+ public void testCreate() throws Exception {
+ final DataSchemaNode schemasNode = ((ContainerSchemaNode) NetconfDevice.INIT_SCHEMA_CTX.getDataChildByName("netconf-state")).getDataChildByName("schemas");
+
+ final Document schemasXml = XmlUtil.readXmlToDocument(getClass().getResourceAsStream("/netconf-state.schemas.payload.xml"));
+ final ToNormalizedNodeParser<Element, ContainerNode, ContainerSchemaNode> containerNodeParser = DomToNormalizedNodeParserFactory.getInstance(XmlUtils.DEFAULT_XML_CODEC_PROVIDER, NetconfDevice.INIT_SCHEMA_CTX, false).getContainerNodeParser();
+ final ContainerNode compositeNodeSchemas = containerNodeParser.parse(Collections.singleton(schemasXml.getDocumentElement()), (ContainerSchemaNode) schemasNode);
+ final NetconfStateSchemas schemas = NetconfStateSchemas.create(new RemoteDeviceId("device", new InetSocketAddress(99)), compositeNodeSchemas);
+
+ final Set<QName> availableYangSchemasQNames = schemas.getAvailableYangSchemasQNames();
+ assertEquals(73, availableYangSchemasQNames.size());
+
+ assertThat(availableYangSchemasQNames,
+ hasItem(QName.create("urn:TBD:params:xml:ns:yang:network-topology", "2013-07-12", "network-topology")));
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015 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.connect.netconf;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.collect.Iterables;
+import java.io.InputStream;
+import java.text.SimpleDateFormat;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import javax.xml.parsers.DocumentBuilderFactory;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.opendaylight.controller.md.sal.dom.api.DOMEvent;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.notifications.NetconfNotification;
+import org.opendaylight.controller.sal.connect.netconf.schema.mapping.NetconfMessageTransformer;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.parser.api.YangContextParser;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+import org.w3c.dom.Document;
+
+public class NetconfToNotificationTest {
+
+ NetconfMessageTransformer messageTransformer;
+
+ NetconfMessage userNotification;
+
+ @SuppressWarnings("deprecation")
+ @Before
+ public void setup() throws Exception {
+ final SchemaContext schemaContext = getNotificationSchemaContext(getClass());
+
+ messageTransformer = new NetconfMessageTransformer(schemaContext, true);
+
+ final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ InputStream notifyPayloadStream = getClass().getResourceAsStream("/notification-payload.xml");
+ assertNotNull(notifyPayloadStream);
+
+ final Document doc = XmlUtil.readXmlToDocument(notifyPayloadStream);
+ assertNotNull(doc);
+ userNotification = new NetconfMessage(doc);
+ }
+
+ static SchemaContext getNotificationSchemaContext(Class<?> loadClass) {
+ final List<InputStream> modelsToParse = Collections.singletonList(loadClass.getResourceAsStream("/schemas/user-notification.yang"));
+ final YangContextParser parser = new YangParserImpl();
+ final Set<Module> modules = parser.parseYangModelsFromStreams(modelsToParse);
+ assertTrue(!modules.isEmpty());
+ final SchemaContext schemaContext = parser.resolveSchemaContext(modules);
+ assertNotNull(schemaContext);
+ return schemaContext;
+ }
+
+ @Test
+ public void test() throws Exception {
+ final DOMNotification domNotification = messageTransformer.toNotification(userNotification);
+ final ContainerNode root = domNotification.getBody();
+ assertNotNull(root);
+ assertEquals(6, Iterables.size(root.getValue()));
+ assertEquals("user-visited-page", root.getNodeType().getLocalName());
+ assertEquals(new SimpleDateFormat(NetconfNotification.RFC3339_DATE_FORMAT_BLUEPRINT).parse("2007-07-08T00:01:00Z"),
+ ((DOMEvent) domNotification).getEventTime());
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015 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.connect.netconf;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.toId;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.toPath;
+
+import com.google.common.collect.Sets;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.sal.connect.netconf.schema.mapping.NetconfMessageTransformer;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.parser.api.YangContextParser;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+import org.w3c.dom.Document;
+
+public class NetconfToRpcRequestTest {
+
+ private final static String TEST_MODEL_NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:rpc-test";
+ private final static String REVISION = "2014-07-14";
+ private final static QName INPUT_QNAME = QName.create(TEST_MODEL_NAMESPACE, REVISION, "input");
+ private final static QName STREAM_NAME = QName.create(TEST_MODEL_NAMESPACE, REVISION, "stream-name");
+ private final static QName SUBSCRIBE_RPC_NAME = QName.create(TEST_MODEL_NAMESPACE, REVISION, "subscribe");
+
+ private final static String CONFIG_TEST_NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:test:rpc:config:defs";
+ private final static String CONFIG_TEST_REVISION = "2014-07-21";
+ private final static QName EDIT_CONFIG_QNAME = QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "edit-config");
+ private final static QName GET_QNAME = QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "get");
+ private final static QName GET_CONFIG_QNAME = QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "get-config");
+
+ static SchemaContext cfgCtx;
+ static NetconfMessageTransformer messageTransformer;
+
+ @SuppressWarnings("deprecation")
+ @BeforeClass
+ public static void setup() throws Exception {
+ List<InputStream> modelsToParse = Collections
+ .singletonList(NetconfToRpcRequestTest.class.getResourceAsStream("/schemas/rpc-notification-subscription.yang"));
+ YangContextParser parser = new YangParserImpl();
+ final Set<Module> notifModules = parser.parseYangModelsFromStreams(modelsToParse);
+ assertTrue(!notifModules.isEmpty());
+
+ modelsToParse = Collections
+ .singletonList(NetconfToRpcRequestTest.class.getResourceAsStream("/schemas/config-test-rpc.yang"));
+ parser = new YangParserImpl();
+ final Set<Module> configModules = parser.parseYangModelsFromStreams(modelsToParse);
+ cfgCtx = parser.resolveSchemaContext(Sets.union(configModules, notifModules));
+ assertNotNull(cfgCtx);
+
+ messageTransformer = new NetconfMessageTransformer(cfgCtx, true);
+ }
+
+ private LeafNode<Object> buildLeaf(final QName running, final Object value) {
+ return Builders.leafBuilder().withNodeIdentifier(toId(running)).withValue(value).build();
+ }
+
+ @Test
+ public void testUserDefinedRpcCall() throws Exception {
+ final DataContainerNodeAttrBuilder<YangInstanceIdentifier.NodeIdentifier, ContainerNode> rootBuilder = Builders.containerBuilder();
+ rootBuilder.withNodeIdentifier(toId(SUBSCRIBE_RPC_NAME));
+
+ rootBuilder.withChild(buildLeaf(STREAM_NAME, "NETCONF"));
+ final ContainerNode root = rootBuilder.build();
+
+ final NetconfMessage message = messageTransformer.toRpcRequest(toPath(SUBSCRIBE_RPC_NAME), root);
+ assertNotNull(message);
+
+ final Document xmlDoc = message.getDocument();
+ final org.w3c.dom.Node rpcChild = xmlDoc.getFirstChild();
+ assertEquals(rpcChild.getLocalName(), "rpc");
+
+ final org.w3c.dom.Node subscribeName = rpcChild.getFirstChild();
+ assertEquals(subscribeName.getLocalName(), "subscribe");
+
+ final org.w3c.dom.Node streamName = subscribeName.getFirstChild();
+ assertEquals(streamName.getLocalName(), "stream-name");
+
+ }
+
+ // The edit config defined in yang has no output
+ @Test(expected = IllegalArgumentException.class)
+ public void testRpcResponse() throws Exception {
+ final NetconfMessage response = new NetconfMessage(XmlUtil.readXmlToDocument(
+ "<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\"m-5\">\n" +
+ "<data xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">" +
+ "module schema" +
+ "</data>\n" +
+ "</rpc-reply>\n"
+ ));
+
+ messageTransformer.toRpcResult(response, toPath(EDIT_CONFIG_QNAME));
+ }
+
+}
--- /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.connect.netconf.listener;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.ListenableFuture;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.util.HashedWheelTimer;
+import io.netty.util.Timer;
+import io.netty.util.concurrent.Future;
+import io.netty.util.concurrent.GenericFutureListener;
+import io.netty.util.concurrent.GlobalEventExecutor;
+import java.io.ByteArrayInputStream;
+import java.net.InetSocketAddress;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import org.apache.commons.lang3.StringUtils;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.config.util.xml.XmlMappingConstants;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
+import org.opendaylight.controller.netconf.client.NetconfClientSession;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
+import org.opendaylight.controller.netconf.client.conf.NetconfReconnectingClientConfiguration;
+import org.opendaylight.controller.netconf.client.conf.NetconfReconnectingClientConfigurationBuilder;
+import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication.LoginPassword;
+import org.opendaylight.controller.sal.connect.api.RemoteDevice;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.protocol.framework.ReconnectStrategy;
+import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
+import org.opendaylight.protocol.framework.TimedReconnectStrategy;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class NetconfDeviceCommunicatorTest {
+
+ @Mock
+ NetconfClientSession mockSession;
+
+ @Mock
+ RemoteDevice<NetconfSessionPreferences, NetconfMessage, NetconfDeviceCommunicator> mockDevice;
+
+ NetconfDeviceCommunicator communicator;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks( this );
+
+ communicator = new NetconfDeviceCommunicator( new RemoteDeviceId( "test", InetSocketAddress.createUnresolved("localhost", 22)), mockDevice);
+ }
+
+ @SuppressWarnings("unchecked")
+ void setupSession() {
+ doReturn(Collections.<String>emptySet()).when(mockSession).getServerCapabilities();
+ doNothing().when(mockDevice).onRemoteSessionUp(any(NetconfSessionPreferences.class),
+ any(NetconfDeviceCommunicator.class));
+ communicator.onSessionUp(mockSession);
+ }
+
+ private ListenableFuture<RpcResult<NetconfMessage>> sendRequest() throws Exception {
+ return sendRequest( UUID.randomUUID().toString() );
+ }
+
+ @SuppressWarnings("unchecked")
+ private ListenableFuture<RpcResult<NetconfMessage>> sendRequest( String messageID ) throws Exception {
+ Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
+ Element element = doc.createElement( "request" );
+ element.setAttribute( "message-id", messageID );
+ doc.appendChild( element );
+ NetconfMessage message = new NetconfMessage( doc );
+
+ ChannelFuture mockChannelFuture = mock( ChannelFuture.class );
+ doReturn( mockChannelFuture ).when( mockChannelFuture )
+ .addListener( any( (GenericFutureListener.class ) ) );
+ doReturn( mockChannelFuture ).when( mockSession ).sendMessage( same( message ) );
+
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture =
+ communicator.sendRequest( message, QName.create( "mock rpc" ) );
+
+ assertNotNull( "ListenableFuture is null", resultFuture );
+ return resultFuture;
+ }
+
+ @Test
+ public void testOnSessionUp() {
+ String testCapability = "urn:opendaylight:params:xml:ns:test?module=test-module&revision=2014-06-02";
+ Collection<String> serverCapabilities =
+ Sets.newHashSet( NetconfMessageTransformUtil.NETCONF_ROLLBACK_ON_ERROR_URI.toString(),
+ NetconfMessageTransformUtil.IETF_NETCONF_MONITORING.getNamespace().toString(),
+ testCapability );
+ doReturn( serverCapabilities ).when( mockSession ).getServerCapabilities();
+
+ ArgumentCaptor<NetconfSessionPreferences> NetconfSessionPreferences =
+ ArgumentCaptor.forClass( NetconfSessionPreferences.class );
+ doNothing().when( mockDevice ).onRemoteSessionUp( NetconfSessionPreferences.capture(), eq( communicator ) );
+
+ communicator.onSessionUp( mockSession );
+
+ verify( mockSession ).getServerCapabilities();
+ verify( mockDevice ).onRemoteSessionUp( NetconfSessionPreferences.capture(), eq( communicator ) );
+
+ NetconfSessionPreferences actualCapabilites = NetconfSessionPreferences.getValue();
+ assertEquals( "containsModuleCapability", true, actualCapabilites.containsNonModuleCapability(
+ NetconfMessageTransformUtil.NETCONF_ROLLBACK_ON_ERROR_URI.toString()) );
+ assertEquals( "containsModuleCapability", false, actualCapabilites.containsNonModuleCapability(testCapability) );
+ assertEquals( "getModuleBasedCaps", Sets.newHashSet(
+ QName.create( "urn:opendaylight:params:xml:ns:test", "2014-06-02", "test-module" )),
+ actualCapabilites.getModuleBasedCaps() );
+ assertEquals( "isRollbackSupported", true, actualCapabilites.isRollbackSupported() );
+ assertEquals( "isMonitoringSupported", true, actualCapabilites.isMonitoringSupported() );
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test(timeout=5000)
+ public void testOnSessionDown() throws Exception {
+ setupSession();
+
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture1 = sendRequest();
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture2 = sendRequest();
+
+ doNothing().when( mockDevice ).onRemoteSessionDown();
+
+ communicator.onSessionDown( mockSession, new Exception( "mock ex" ) );
+
+ verifyErrorRpcResult( resultFuture1.get(), RpcError.ErrorType.TRANSPORT, "operation-failed" );
+ verifyErrorRpcResult( resultFuture2.get(), RpcError.ErrorType.TRANSPORT, "operation-failed" );
+
+ verify( mockDevice ).onRemoteSessionDown();
+
+ reset( mockDevice );
+
+ communicator.onSessionDown( mockSession, new Exception( "mock ex" ) );
+
+ verify( mockDevice, never() ).onRemoteSessionDown();
+ }
+
+ @Test
+ public void testOnSessionTerminated() throws Exception {
+ setupSession();
+
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture = sendRequest();
+
+ doNothing().when( mockDevice ).onRemoteSessionDown();
+
+ String reasonText = "testing terminate";
+ NetconfTerminationReason reason = new NetconfTerminationReason( reasonText );
+ communicator.onSessionTerminated( mockSession, reason );
+
+ RpcError rpcError = verifyErrorRpcResult( resultFuture.get(), RpcError.ErrorType.TRANSPORT,
+ "operation-failed" );
+ assertEquals( "RpcError message", reasonText, rpcError.getMessage() );
+
+ verify( mockDevice ).onRemoteSessionDown();
+ }
+
+ @Test
+ public void testClose() throws Exception {
+ communicator.close();
+ verify( mockDevice, never() ).onRemoteSessionDown();
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ @Test
+ public void testSendRequest() throws Exception {
+ setupSession();
+
+ NetconfMessage message = new NetconfMessage(
+ DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument() );
+ QName rpc = QName.create( "mock rpc" );
+
+ ArgumentCaptor<GenericFutureListener> futureListener =
+ ArgumentCaptor.forClass( GenericFutureListener.class );
+
+ ChannelFuture mockChannelFuture = mock( ChannelFuture.class );
+ doReturn( mockChannelFuture ).when( mockChannelFuture ).addListener( futureListener.capture() );
+ doReturn( mockChannelFuture ).when( mockSession ).sendMessage( same( message ) );
+
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture = communicator.sendRequest( message, rpc );
+
+ verify( mockSession ).sendMessage( same( message ) );
+
+ assertNotNull( "ListenableFuture is null", resultFuture );
+
+ verify( mockChannelFuture ).addListener( futureListener.capture() );
+ Future<Void> operationFuture = mock( Future.class );
+ doReturn( true ).when( operationFuture ).isSuccess();
+ doReturn( true ).when( operationFuture ).isDone();
+ futureListener.getValue().operationComplete( operationFuture );
+
+ try {
+ resultFuture.get( 1, TimeUnit.MILLISECONDS ); // verify it's not cancelled or has an error set
+ }
+ catch( TimeoutException e ) {} // expected
+ }
+
+ @Test
+ public void testSendRequestWithNoSession() throws Exception {
+ NetconfMessage message = new NetconfMessage(
+ DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument() );
+ QName rpc = QName.create( "mock rpc" );
+
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture = communicator.sendRequest( message, rpc );
+
+ assertNotNull( "ListenableFuture is null", resultFuture );
+
+ // Should have an immediate result
+ RpcResult<NetconfMessage> rpcResult = resultFuture.get( 3, TimeUnit.MILLISECONDS );
+
+ verifyErrorRpcResult( rpcResult, RpcError.ErrorType.TRANSPORT, "operation-failed" );
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ @Test
+ public void testSendRequestWithWithSendFailure() throws Exception {
+ setupSession();
+
+ NetconfMessage message = new NetconfMessage(
+ DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument() );
+ QName rpc = QName.create( "mock rpc" );
+
+ ArgumentCaptor<GenericFutureListener> futureListener =
+ ArgumentCaptor.forClass( GenericFutureListener.class );
+
+ ChannelFuture mockChannelFuture = mock( ChannelFuture.class );
+ doReturn( mockChannelFuture ).when( mockChannelFuture ).addListener( futureListener.capture() );
+ doReturn( mockChannelFuture ).when( mockSession ).sendMessage( same( message ) );
+
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture = communicator.sendRequest( message, rpc );
+
+ assertNotNull( "ListenableFuture is null", resultFuture );
+
+ verify( mockChannelFuture ).addListener( futureListener.capture() );
+
+ Future<Void> operationFuture = mock( Future.class );
+ doReturn( false ).when( operationFuture ).isSuccess();
+ doReturn( true ).when( operationFuture ).isDone();
+ doReturn( new Exception( "mock error" ) ).when( operationFuture ).cause();
+ futureListener.getValue().operationComplete( operationFuture );
+
+ // Should have an immediate result
+ RpcResult<NetconfMessage> rpcResult = resultFuture.get( 3, TimeUnit.MILLISECONDS );
+
+ RpcError rpcError = verifyErrorRpcResult( rpcResult, RpcError.ErrorType.TRANSPORT, "operation-failed" );
+ assertEquals( "RpcError message contains \"mock error\"", true,
+ rpcError.getMessage().contains( "mock error" ) );
+ }
+
+ private NetconfMessage createSuccessResponseMessage( String messageID ) throws ParserConfigurationException {
+ Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
+ Element rpcReply = doc.createElementNS( URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, XmlMappingConstants.RPC_REPLY_KEY);
+ rpcReply.setAttribute( "message-id", messageID );
+ Element element = doc.createElementNS( "ns", "data" );
+ element.setTextContent( messageID );
+ rpcReply.appendChild( element );
+ doc.appendChild( rpcReply );
+
+ return new NetconfMessage( doc );
+ }
+
+ //Test scenario verifying whether missing message is handled
+ @Test
+ public void testOnMissingResponseMessage() throws Exception {
+
+ setupSession();
+
+ String messageID1 = UUID.randomUUID().toString();
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture1 = sendRequest( messageID1 );
+
+ String messageID2 = UUID.randomUUID().toString();
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture2 = sendRequest( messageID2 );
+
+ String messageID3 = UUID.randomUUID().toString();
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture3 = sendRequest( messageID3 );
+
+ //response messages 1,2 are omitted
+ communicator.onMessage( mockSession, createSuccessResponseMessage( messageID3 ) );
+
+ verifyResponseMessage( resultFuture3.get(), messageID3 );
+ }
+
+ @Test
+ public void testOnSuccessfulResponseMessage() throws Exception {
+ setupSession();
+
+ String messageID1 = UUID.randomUUID().toString();
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture1 = sendRequest( messageID1 );
+
+ String messageID2 = UUID.randomUUID().toString();
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture2 = sendRequest( messageID2 );
+
+ communicator.onMessage( mockSession, createSuccessResponseMessage( messageID1 ) );
+ communicator.onMessage( mockSession, createSuccessResponseMessage( messageID2 ) );
+
+ verifyResponseMessage( resultFuture1.get(), messageID1 );
+ verifyResponseMessage( resultFuture2.get(), messageID2 );
+ }
+
+ @Test
+ public void testOnResponseMessageWithError() throws Exception {
+ setupSession();
+
+ String messageID = UUID.randomUUID().toString();
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture = sendRequest( messageID );
+
+ communicator.onMessage( mockSession, createErrorResponseMessage( messageID ) );
+
+ RpcError rpcError = verifyErrorRpcResult( resultFuture.get(), RpcError.ErrorType.RPC,
+ "missing-attribute" );
+ assertEquals( "RpcError message", "Missing attribute", rpcError.getMessage() );
+
+ String errorInfo = rpcError.getInfo();
+ assertNotNull( "RpcError info is null", errorInfo );
+ assertEquals( "Error info contains \"foo\"", true,
+ errorInfo.contains( "<bad-attribute>foo</bad-attribute>" ) );
+ assertEquals( "Error info contains \"bar\"", true,
+ errorInfo.contains( "<bad-element>bar</bad-element>" ) );
+ }
+
+ /**
+ * Test whether reconnect is scheduled properly
+ */
+ @Test
+ public void testNetconfDeviceReconnectInCommunicator() throws Exception {
+ final RemoteDevice<NetconfSessionPreferences, NetconfMessage, NetconfDeviceCommunicator> device = mock(RemoteDevice.class);
+
+ final TimedReconnectStrategy timedReconnectStrategy = new TimedReconnectStrategy(GlobalEventExecutor.INSTANCE, 10000, 0, 1.0, null, 100L, null);
+ final ReconnectStrategy reconnectStrategy = spy(new ReconnectStrategy() {
+ @Override
+ public int getConnectTimeout() throws Exception {
+ return timedReconnectStrategy.getConnectTimeout();
+ }
+
+ @Override
+ public Future<Void> scheduleReconnect(final Throwable cause) {
+ return timedReconnectStrategy.scheduleReconnect(cause);
+ }
+
+ @Override
+ public void reconnectSuccessful() {
+ timedReconnectStrategy.reconnectSuccessful();
+ }
+ });
+
+ final EventLoopGroup group = new NioEventLoopGroup();
+ final Timer time = new HashedWheelTimer();
+ try {
+ final NetconfDeviceCommunicator listener = new NetconfDeviceCommunicator(new RemoteDeviceId("test", InetSocketAddress.createUnresolved("localhost", 22)), device);
+ final NetconfReconnectingClientConfiguration cfg = NetconfReconnectingClientConfigurationBuilder.create()
+ .withAddress(new InetSocketAddress("localhost", 65000))
+ .withReconnectStrategy(reconnectStrategy)
+ .withConnectStrategyFactory(new ReconnectStrategyFactory() {
+ @Override
+ public ReconnectStrategy createReconnectStrategy() {
+ return reconnectStrategy;
+ }
+ })
+ .withAuthHandler(new LoginPassword("admin", "admin"))
+ .withConnectionTimeoutMillis(10000)
+ .withProtocol(NetconfClientConfiguration.NetconfClientProtocol.SSH)
+ .withSessionListener(listener)
+ .build();
+
+ listener.initializeRemoteConnection(new NetconfClientDispatcherImpl(group, group, time), cfg);
+
+ verify(reconnectStrategy, timeout((int) TimeUnit.MINUTES.toMillis(3)).times(101)).scheduleReconnect(any(Throwable.class));
+ } finally {
+ time.stop();
+ group.shutdownGracefully();
+ }
+ }
+
+ @Test
+ public void testOnResponseMessageWithWrongMessageID() throws Exception {
+ setupSession();
+
+ String messageID = UUID.randomUUID().toString();
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture = sendRequest( messageID );
+
+ communicator.onMessage( mockSession, createSuccessResponseMessage( UUID.randomUUID().toString() ) );
+
+ RpcError rpcError = verifyErrorRpcResult( resultFuture.get(), RpcError.ErrorType.PROTOCOL,
+ "bad-attribute" );
+ assertEquals( "RpcError message non-empty", true,
+ !Strings.isNullOrEmpty( rpcError.getMessage() ) );
+
+ String errorInfo = rpcError.getInfo();
+ assertNotNull( "RpcError info is null", errorInfo );
+ assertEquals( "Error info contains \"actual-message-id\"", true,
+ errorInfo.contains( "actual-message-id" ) );
+ assertEquals( "Error info contains \"expected-message-id\"", true,
+ errorInfo.contains( "expected-message-id" ) );
+ }
+
+ private NetconfMessage createErrorResponseMessage( String messageID ) throws Exception {
+ String xmlStr =
+ "<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"" +
+ " message-id=\"" + messageID + "\">" +
+ " <rpc-error>" +
+ " <error-type>rpc</error-type>" +
+ " <error-tag>missing-attribute</error-tag>" +
+ " <error-severity>error</error-severity>" +
+ " <error-message>Missing attribute</error-message>" +
+ " <error-info>" +
+ " <bad-attribute>foo</bad-attribute>" +
+ " <bad-element>bar</bad-element>" +
+ " </error-info>" +
+ " </rpc-error>" +
+ "</rpc-reply>";
+
+ ByteArrayInputStream bis = new ByteArrayInputStream( xmlStr.getBytes() );
+ Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse( bis );
+ return new NetconfMessage( doc );
+ }
+
+ private void verifyResponseMessage( RpcResult<NetconfMessage> rpcResult, String dataText ) {
+ assertNotNull( "RpcResult is null", rpcResult );
+ assertEquals( "isSuccessful", true, rpcResult.isSuccessful() );
+ NetconfMessage messageResult = rpcResult.getResult();
+ assertNotNull( "getResult", messageResult );
+// List<SimpleNode<?>> nodes = messageResult.getSimpleNodesByName(
+// QName.create( URI.create( "ns" ), null, "data" ) );
+// assertNotNull( "getSimpleNodesByName", nodes );
+// assertEquals( "List<SimpleNode<?>> size", 1, nodes.size() );
+// assertEquals( "SimpleNode value", dataText, nodes.iterator().next().getValue() );
+ }
+
+ private RpcError verifyErrorRpcResult( RpcResult<NetconfMessage> rpcResult,
+ RpcError.ErrorType expErrorType, String expErrorTag ) {
+ assertNotNull( "RpcResult is null", rpcResult );
+ assertEquals( "isSuccessful", false, rpcResult.isSuccessful() );
+ assertNotNull( "RpcResult errors is null", rpcResult.getErrors() );
+ assertEquals( "Errors size", 1, rpcResult.getErrors().size() );
+ RpcError rpcError = rpcResult.getErrors().iterator().next();
+ assertEquals( "getErrorSeverity", RpcError.ErrorSeverity.ERROR, rpcError.getSeverity() );
+ assertEquals( "getErrorType", expErrorType, rpcError.getErrorType() );
+ assertEquals( "getErrorTag", expErrorTag, rpcError.getTag() );
+ assertTrue( "getMessage is empty", StringUtils.isNotEmpty( rpcError.getMessage() ) );
+ return rpcError;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015 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.connect.netconf.listener;
+
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import com.google.common.collect.Lists;
+import java.util.List;
+import org.junit.Test;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil;
+import org.opendaylight.yangtools.yang.common.QName;
+
+public class NetconfSessionPreferencesTest {
+
+ @Test
+ public void testMerge() throws Exception {
+ final List<String> caps1 = Lists.newArrayList(
+ "namespace:1?module=module1&revision=2012-12-12",
+ "namespace:2?module=module2&revision=2012-12-12",
+ "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04",
+ "urn:ietf:params:netconf:base:1.0",
+ "urn:ietf:params:netconf:capability:rollback-on-error:1.0"
+ );
+ final NetconfSessionPreferences sessionCaps1 = NetconfSessionPreferences.fromStrings(caps1);
+ assertCaps(sessionCaps1, 2, 3);
+
+ final List<String> caps2 = Lists.newArrayList(
+ "namespace:3?module=module3&revision=2012-12-12",
+ "namespace:4?module=module4&revision=2012-12-12",
+ "randomNonModuleCap"
+ );
+ final NetconfSessionPreferences sessionCaps2 = NetconfSessionPreferences.fromStrings(caps2);
+ assertCaps(sessionCaps2, 1, 2);
+
+ final NetconfSessionPreferences merged = sessionCaps1.addModuleCaps(sessionCaps2);
+ assertCaps(merged, 2, 2 + 1 /*Preserved monitoring*/ + 2 /*already present*/);
+ for (final QName qName : sessionCaps2.getModuleBasedCaps()) {
+ assertThat(merged.getModuleBasedCaps(), hasItem(qName));
+ }
+ assertThat(merged.getModuleBasedCaps(), hasItem(NetconfMessageTransformUtil.IETF_NETCONF_MONITORING));
+
+ assertThat(merged.getNonModuleCaps(), hasItem("urn:ietf:params:netconf:base:1.0"));
+ assertThat(merged.getNonModuleCaps(), hasItem("urn:ietf:params:netconf:capability:rollback-on-error:1.0"));
+ }
+
+ @Test
+ public void testCapabilityNoRevision() throws Exception {
+ final List<String> caps1 = Lists.newArrayList(
+ "namespace:2?module=module2",
+ "namespace:2?module=module2&revision=2012-12-12",
+ "namespace:2?module=module1&RANDOMSTRING;revision=2013-12-12",
+ "namespace:2?module=module2&RANDOMSTRING;revision=2013-12-12" // This one should be ignored(same as first), since revision is in wrong format
+ );
+
+ final NetconfSessionPreferences sessionCaps1 = NetconfSessionPreferences.fromStrings(caps1);
+ assertCaps(sessionCaps1, 0, 3);
+ }
+
+ private void assertCaps(final NetconfSessionPreferences sessionCaps1, final int nonModuleCaps, final int moduleCaps) {
+ assertEquals(nonModuleCaps, sessionCaps1.getNonModuleCaps().size());
+ assertEquals(moduleCaps, sessionCaps1.getModuleBasedCaps().size());
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.connect.netconf.sal;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import com.google.common.util.concurrent.Futures;
+import java.net.InetSocketAddress;
+import java.util.concurrent.Executors;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.controller.md.sal.dom.spi.DefaultDOMRpcResult;
+import org.opendaylight.controller.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.controller.sal.connect.netconf.listener.NetconfDeviceCommunicator;
+import org.opendaylight.controller.sal.connect.netconf.listener.NetconfSessionPreferences;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+public class KeepaliveSalFacadeTest {
+
+ private static final RemoteDeviceId REMOTE_DEVICE_ID = new RemoteDeviceId("test", new InetSocketAddress("localhost", 22));
+
+ @Mock
+ private RemoteDeviceHandler<NetconfSessionPreferences> underlyingSalFacade;
+
+ private static java.util.concurrent.ScheduledExecutorService executorService;
+
+ @Mock
+ private NetconfDeviceCommunicator listener;
+ @Mock
+ private DOMRpcService deviceRpc;
+
+ private DOMRpcService proxyRpc;
+
+ @Before
+ public void setUp() throws Exception {
+ executorService = Executors.newScheduledThreadPool(1);
+
+ MockitoAnnotations.initMocks(this);
+
+ doNothing().when(listener).disconnect();
+ doReturn("mockedRpc").when(deviceRpc).toString();
+ doNothing().when(underlyingSalFacade).onDeviceConnected(
+ any(SchemaContext.class), any(NetconfSessionPreferences.class), any(DOMRpcService.class));
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ executorService.shutdownNow();
+ }
+
+ @Test
+ public void testKeepaliveSuccess() throws Exception {
+ final DOMRpcResult result = new DefaultDOMRpcResult(Builders.containerBuilder().withNodeIdentifier(
+ new YangInstanceIdentifier.NodeIdentifier(NetconfMessageTransformUtil.NETCONF_RUNNING_QNAME)).build());
+
+ doReturn(Futures.immediateCheckedFuture(result)).when(deviceRpc).invokeRpc(any(SchemaPath.class), any(NormalizedNode.class));
+
+ final KeepaliveSalFacade keepaliveSalFacade =
+ new KeepaliveSalFacade(REMOTE_DEVICE_ID, underlyingSalFacade, executorService, 1L);
+ keepaliveSalFacade.setListener(listener);
+
+ keepaliveSalFacade.onDeviceConnected(null, null, deviceRpc);
+
+ verify(underlyingSalFacade).onDeviceConnected(
+ any(SchemaContext.class), any(NetconfSessionPreferences.class), any(DOMRpcService.class));
+
+ verify(deviceRpc, timeout(15000).times(5)).invokeRpc(any(SchemaPath.class), any(NormalizedNode.class));
+ }
+
+ @Test
+ public void testKeepaliveFail() throws Exception {
+ final DOMRpcResult result = new DefaultDOMRpcResult(Builders.containerBuilder().withNodeIdentifier(
+ new YangInstanceIdentifier.NodeIdentifier(NetconfMessageTransformUtil.NETCONF_RUNNING_QNAME)).build());
+
+ final DOMRpcResult resultFail = new DefaultDOMRpcResult(mock(RpcError.class));
+
+ doReturn(Futures.immediateCheckedFuture(result))
+ .doReturn(Futures.immediateCheckedFuture(resultFail))
+ .doReturn(Futures.immediateFailedCheckedFuture(new IllegalStateException("illegal-state")))
+ .when(deviceRpc).invokeRpc(any(SchemaPath.class), any(NormalizedNode.class));
+
+ final KeepaliveSalFacade keepaliveSalFacade =
+ new KeepaliveSalFacade(REMOTE_DEVICE_ID, underlyingSalFacade, executorService, 1L);
+ keepaliveSalFacade.setListener(listener);
+
+ keepaliveSalFacade.onDeviceConnected(null, null, deviceRpc);
+
+ verify(underlyingSalFacade).onDeviceConnected(
+ any(SchemaContext.class), any(NetconfSessionPreferences.class), any(DOMRpcService.class));
+
+ // 1 failed that results in disconnect
+ verify(listener, timeout(15000).times(1)).disconnect();
+ // 3 attempts total
+ verify(deviceRpc, times(3)).invokeRpc(any(SchemaPath.class), any(NormalizedNode.class));
+
+ // Reconnect with same keepalive responses
+ doReturn(Futures.immediateCheckedFuture(result))
+ .doReturn(Futures.immediateCheckedFuture(resultFail))
+ .doReturn(Futures.immediateFailedCheckedFuture(new IllegalStateException("illegal-state")))
+ .when(deviceRpc).invokeRpc(any(SchemaPath.class), any(NormalizedNode.class));
+
+ keepaliveSalFacade.onDeviceConnected(null, null, deviceRpc);
+
+ // 1 failed that results in disconnect, 2 total with previous fail
+ verify(listener, timeout(15000).times(2)).disconnect();
+ // 6 attempts now total
+ verify(deviceRpc, times(3 * 2)).invokeRpc(any(SchemaPath.class), any(NormalizedNode.class));
+ }
+
+ @Test
+ public void testNonKeepaliveRpcFailure() throws Exception {
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(final InvocationOnMock invocationOnMock) throws Throwable {
+ proxyRpc = (DOMRpcService) invocationOnMock.getArguments()[2];
+ return null;
+ }
+ }).when(underlyingSalFacade).onDeviceConnected(any(SchemaContext.class), any(NetconfSessionPreferences.class), any(DOMRpcService.class));
+
+ doReturn(Futures.immediateFailedCheckedFuture(new IllegalStateException("illegal-state")))
+ .when(deviceRpc).invokeRpc(any(SchemaPath.class), any(NormalizedNode.class));
+
+ final KeepaliveSalFacade keepaliveSalFacade =
+ new KeepaliveSalFacade(REMOTE_DEVICE_ID, underlyingSalFacade, executorService, 100L);
+ keepaliveSalFacade.setListener(listener);
+
+ keepaliveSalFacade.onDeviceConnected(null, null, deviceRpc);
+
+ proxyRpc.invokeRpc(mock(SchemaPath.class), mock(NormalizedNode.class));
+
+ verify(listener, times(1)).disconnect();
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2015 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.connect.netconf.sal;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import com.google.common.util.concurrent.Futures;
+import java.net.InetSocketAddress;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.opendaylight.controller.sal.connect.netconf.listener.NetconfDeviceCapabilities;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class NetconfDeviceTopologyAdapterTest {
+
+ private RemoteDeviceId id = new RemoteDeviceId("test", new InetSocketAddress("localhost", 22));
+
+ @Mock
+ private DataBroker broker;
+ @Mock
+ private WriteTransaction writeTx;
+ @Mock
+ private BindingTransactionChain txChain;
+ @Mock
+ private Node data;
+
+ private String txIdent = "test transaction";
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ doReturn(txChain).when(broker).createTransactionChain(any(TransactionChainListener.class));
+ doReturn(writeTx).when(txChain).newWriteOnlyTransaction();
+ doNothing().when(writeTx).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class));
+ doNothing().when(writeTx).merge(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class));
+
+ doReturn(txIdent).when(writeTx).getIdentifier();
+ }
+
+ @Test
+ public void testFailedDevice() throws Exception {
+ doReturn(Futures.immediateCheckedFuture(null)).when(writeTx).submit();
+
+ NetconfDeviceTopologyAdapter adapter = new NetconfDeviceTopologyAdapter(id, broker);
+ adapter.setDeviceAsFailed(null);
+
+ verify(txChain, times(2)).newWriteOnlyTransaction();
+ verify(writeTx, times(3)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class));
+ }
+
+ @Test
+ public void testDeviceUpdate() throws Exception {
+ doReturn(Futures.immediateCheckedFuture(null)).when(writeTx).submit();
+
+ NetconfDeviceTopologyAdapter adapter = new NetconfDeviceTopologyAdapter(id, broker);
+ adapter.updateDeviceData(true, new NetconfDeviceCapabilities());
+
+ verify(txChain, times(2)).newWriteOnlyTransaction();
+ verify(writeTx, times(3)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class));
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015 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.connect.netconf.sal.tx;
+
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atMost;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_CANDIDATE_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_FILTER_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_RUNNING_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.toPath;
+
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import java.net.InetSocketAddress;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.controller.md.sal.dom.spi.DefaultDOMRpcResult;
+import org.opendaylight.controller.sal.connect.netconf.NetconfDevice;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfBaseOps;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfState;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+public class NetconfDeviceWriteOnlyTxTest {
+
+ private final RemoteDeviceId id = new RemoteDeviceId("test-mount", new InetSocketAddress(99));
+
+ @Mock
+ private DOMRpcService rpc;
+ private YangInstanceIdentifier yangIId;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ final CheckedFuture<DefaultDOMRpcResult, Exception> successFuture =
+ Futures.immediateCheckedFuture(new DefaultDOMRpcResult(((NormalizedNode<?, ?>) null)));
+
+ doReturn(successFuture)
+ .doReturn(Futures.immediateFailedCheckedFuture(new IllegalStateException("Failed tx")))
+ .doReturn(successFuture)
+ .when(rpc).invokeRpc(any(SchemaPath.class), any(NormalizedNode.class));
+
+ yangIId = YangInstanceIdentifier.builder().node(NetconfState.QNAME).build();
+ }
+
+ @Test
+ public void testIgnoreNonVisibleData() {
+ final WriteCandidateTx tx = new WriteCandidateTx(id, new NetconfBaseOps(rpc, mock(SchemaContext.class)),
+ false, 60000L);
+ final MapNode emptyList = ImmutableNodes.mapNodeBuilder(NETCONF_FILTER_QNAME).build();
+ tx.merge(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create(new YangInstanceIdentifier.NodeIdentifier(NETCONF_FILTER_QNAME)), emptyList);
+ tx.put(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create(new YangInstanceIdentifier.NodeIdentifier(NETCONF_FILTER_QNAME)), emptyList);
+
+ verify(rpc, atMost(1)).invokeRpc(any(SchemaPath.class), any(NormalizedNode.class));
+ }
+
+ @Test
+ public void testDiscardChanges() {
+ final WriteCandidateTx tx = new WriteCandidateTx(id, new NetconfBaseOps(rpc, mock(SchemaContext.class)),
+ false, 60000L);
+ final CheckedFuture<Void, TransactionCommitFailedException> submitFuture = tx.submit();
+ try {
+ submitFuture.checkedGet();
+ } catch (final TransactionCommitFailedException e) {
+ // verify discard changes was sent
+ final InOrder inOrder = inOrder(rpc);
+ inOrder.verify(rpc).invokeRpc(toPath(NetconfMessageTransformUtil.NETCONF_LOCK_QNAME), NetconfBaseOps.getLockContent(NETCONF_CANDIDATE_QNAME));
+ inOrder.verify(rpc).invokeRpc(toPath(NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME), NetconfMessageTransformUtil.COMMIT_RPC_CONTENT);
+ inOrder.verify(rpc).invokeRpc(eq(toPath(NetconfMessageTransformUtil.NETCONF_DISCARD_CHANGES_QNAME)), any(NormalizedNode.class));
+ inOrder.verify(rpc).invokeRpc(toPath(NetconfMessageTransformUtil.NETCONF_UNLOCK_QNAME), NetconfBaseOps.getUnLockContent(NETCONF_CANDIDATE_QNAME));
+ return;
+ }
+
+ fail("Submit should fail");
+ }
+
+ @Test
+ public void testFailedCommit() throws Exception {
+ final CheckedFuture<DefaultDOMRpcResult, Exception> rpcErrorFuture =
+ Futures.immediateCheckedFuture(new DefaultDOMRpcResult(RpcResultBuilder.newError(RpcError.ErrorType.APPLICATION, "a", "m")));
+
+ doReturn(Futures.immediateCheckedFuture(new DefaultDOMRpcResult(((NormalizedNode<?, ?>) null))))
+ .doReturn(rpcErrorFuture).when(rpc).invokeRpc(any(SchemaPath.class), any(NormalizedNode.class));
+
+ final WriteCandidateTx tx = new WriteCandidateTx(id, new NetconfBaseOps(rpc, mock(SchemaContext.class)),
+ false, 60000L);
+
+ final CheckedFuture<Void, TransactionCommitFailedException> submitFuture = tx.submit();
+ try {
+ submitFuture.checkedGet();
+ } catch (final TransactionCommitFailedException e) {
+ return;
+ }
+
+ fail("Submit should fail");
+ }
+
+ @Test
+ public void testDiscardChangesNotSentWithoutCandidate() {
+ doReturn(Futures.immediateCheckedFuture(new DefaultDOMRpcResult(((NormalizedNode<?, ?>) null))))
+ .doReturn(Futures.immediateFailedCheckedFuture(new IllegalStateException("Failed tx")))
+ .when(rpc).invokeRpc(any(SchemaPath.class), any(NormalizedNode.class));
+
+ final WriteRunningTx tx = new WriteRunningTx(id, new NetconfBaseOps(rpc, NetconfDevice.INIT_SCHEMA_CTX),
+ false, 60000L);
+ try {
+ tx.delete(LogicalDatastoreType.CONFIGURATION, yangIId);
+ } catch (final Exception e) {
+ // verify discard changes was sent
+ final InOrder inOrder = inOrder(rpc);
+ inOrder.verify(rpc).invokeRpc(toPath(NetconfMessageTransformUtil.NETCONF_LOCK_QNAME), NetconfBaseOps.getLockContent(NETCONF_RUNNING_QNAME));
+ inOrder.verify(rpc).invokeRpc(eq(toPath(NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME)), any(NormalizedNode.class));
+ inOrder.verify(rpc).invokeRpc(toPath(NetconfMessageTransformUtil.NETCONF_UNLOCK_QNAME), NetconfBaseOps.getUnLockContent(NETCONF_RUNNING_QNAME));
+ return;
+ }
+
+ fail("Delete should fail");
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.connect.netconf.sal.tx;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import com.google.common.util.concurrent.Futures;
+import java.net.InetSocketAddress;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.controller.md.sal.dom.spi.DefaultDOMRpcResult;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfBaseOps;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+public class ReadOnlyTxTest {
+
+ private static final YangInstanceIdentifier path = YangInstanceIdentifier.create();
+
+ @Mock
+ private DOMRpcService rpc;
+ @Mock
+ private NormalizedNode<?, ?> mockedNode;
+
+ @Before
+ public void setUp() throws DataNormalizationException {
+ MockitoAnnotations.initMocks(this);
+ doReturn(Futures.immediateCheckedFuture(new DefaultDOMRpcResult(mockedNode))).when(rpc)
+ .invokeRpc(any(SchemaPath.class), any(NormalizedNode.class));
+ doReturn("node").when(mockedNode).toString();
+ }
+
+ @Test
+ public void testRead() throws Exception {
+ final NetconfBaseOps netconfOps = new NetconfBaseOps(rpc, mock(SchemaContext.class));
+
+ final ReadOnlyTx readOnlyTx = new ReadOnlyTx(netconfOps, new RemoteDeviceId("a", new InetSocketAddress("localhost", 196)));
+
+ readOnlyTx.read(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create());
+ verify(rpc).invokeRpc(Mockito.eq(NetconfMessageTransformUtil.toPath(NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME)), any(NormalizedNode.class));
+ readOnlyTx.read(LogicalDatastoreType.OPERATIONAL, path);
+ verify(rpc).invokeRpc(Mockito.eq(NetconfMessageTransformUtil.toPath(NetconfMessageTransformUtil.NETCONF_GET_QNAME)), any(NormalizedNode.class));
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015 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.connect.netconf.schema.mapping;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.GET_SCHEMA_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_CANDIDATE_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_DATA_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_DISCARD_CHANGES_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_GET_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_LOCK_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_RUNNING_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.createEditConfigStructure;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.toFilterStructure;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.toId;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.toPath;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import javax.xml.transform.dom.DOMSource;
+import org.custommonkey.xmlunit.Diff;
+import org.custommonkey.xmlunit.ElementNameAndAttributeQualifier;
+import org.custommonkey.xmlunit.XMLUnit;
+import org.hamcrest.CoreMatchers;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.sal.connect.netconf.NetconfDevice;
+import org.opendaylight.controller.sal.connect.netconf.schema.NetconfRemoteSchemaYangSourceProvider;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfBaseOps;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.$YangModuleInfoImpl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Capabilities;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.Schema;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.ModifyAction;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+public class NetconfMessageTransformerTest {
+
+ private NetconfMessageTransformer netconfMessageTransformer;
+ private SchemaContext schema;
+
+ @Before
+ public void setUp() throws Exception {
+ XMLUnit.setIgnoreWhitespace(true);
+ XMLUnit.setIgnoreAttributeOrder(true);
+ XMLUnit.setIgnoreComments(true);
+
+ schema = getSchema(true);
+ netconfMessageTransformer = getTransformer(schema);
+
+ }
+
+ @Test
+ public void testLockRequestBaseSchemaNotPresent() throws Exception {
+ final SchemaContext partialSchema = getSchema(false);
+ final NetconfMessageTransformer transformer = getTransformer(partialSchema);
+ final NetconfMessage netconfMessage = transformer.toRpcRequest(toPath(NETCONF_LOCK_QNAME),
+ NetconfBaseOps.getLockContent(NETCONF_CANDIDATE_QNAME));
+
+ assertThat(XmlUtil.toString(netconfMessage.getDocument()), CoreMatchers.containsString("<lock"));
+ assertThat(XmlUtil.toString(netconfMessage.getDocument()), CoreMatchers.containsString("<rpc"));
+ }
+
+ @Test
+ public void tesLockSchemaRequest() throws Exception {
+ final SchemaContext partialSchema = getSchema(false);
+ final NetconfMessageTransformer transformer = getTransformer(partialSchema);
+ final String result = "<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><ok/></rpc-reply>";
+
+ transformer.toRpcResult(new NetconfMessage(XmlUtil.readXmlToDocument(result)), toPath(NETCONF_LOCK_QNAME));
+ }
+
+ @Test
+ public void testDiscardChangesRequest() throws Exception {
+ final NetconfMessage netconfMessage = netconfMessageTransformer.toRpcRequest(toPath(NETCONF_DISCARD_CHANGES_QNAME), null);
+ assertThat(XmlUtil.toString(netconfMessage.getDocument()), CoreMatchers.containsString("<discard"));
+ assertThat(XmlUtil.toString(netconfMessage.getDocument()), CoreMatchers.containsString("<rpc"));
+ assertThat(XmlUtil.toString(netconfMessage.getDocument()), CoreMatchers.containsString("message-id"));
+ }
+
+ @Test
+ public void tesGetSchemaRequest() throws Exception {
+ final NetconfMessage netconfMessage = netconfMessageTransformer.toRpcRequest(toPath(GET_SCHEMA_QNAME),
+ NetconfRemoteSchemaYangSourceProvider.createGetSchemaRequest("module", Optional.of("2012-12-12")));
+ assertSimilarXml(netconfMessage, "<rpc message-id=\"m-0\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" +
+ "<get-schema xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">\n" +
+ "<format>yang</format>\n" +
+ "<identifier>module</identifier>\n" +
+ "<version>2012-12-12</version>\n" +
+ "</get-schema>\n" +
+ "</rpc>");
+ }
+
+ @Test
+ public void tesGetSchemaResponse() throws Exception {
+ final NetconfMessageTransformer netconfMessageTransformer = getTransformer(getSchema(true));
+ final NetconfMessage response = new NetconfMessage(XmlUtil.readXmlToDocument(
+ "<rpc-reply message-id=\"101\"\n" +
+ "xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" +
+ "<data\n" +
+ "xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">\n" +
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n" +
+ "Random YANG SCHEMA\n" +
+ "</xs:schema>\n" +
+ "</data>\n" +
+ "</rpc-reply>"
+ ));
+ final DOMRpcResult compositeNodeRpcResult = netconfMessageTransformer.toRpcResult(response, toPath(GET_SCHEMA_QNAME));
+ assertTrue(compositeNodeRpcResult.getErrors().isEmpty());
+ assertNotNull(compositeNodeRpcResult.getResult());
+ final DOMSource schemaContent = ((AnyXmlNode) ((ContainerNode) compositeNodeRpcResult.getResult()).getValue().iterator().next()).getValue();
+ assertThat(((Element) schemaContent.getNode()).getTextContent(), CoreMatchers.containsString("Random YANG SCHEMA"));
+ }
+
+ @Test
+ public void testGetConfigResponse() throws Exception {
+ final NetconfMessage response = new NetconfMessage(XmlUtil.readXmlToDocument("<rpc-reply message-id=\"101\"\n" +
+ "xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" +
+ "<data>\n" +
+ "<netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">\n" +
+ "<schemas>\n" +
+ "<schema>\n" +
+ "<identifier>module</identifier>\n" +
+ "<version>2012-12-12</version>\n" +
+ "<format xmlns:x=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">x:yang</format>\n" +
+ "</schema>\n" +
+ "</schemas>\n" +
+ "</netconf-state>\n" +
+ "</data>\n" +
+ "</rpc-reply>"));
+
+ final NetconfMessageTransformer netconfMessageTransformer = getTransformer(getSchema(true));
+ final DOMRpcResult compositeNodeRpcResult = netconfMessageTransformer.toRpcResult(response, toPath(NETCONF_GET_CONFIG_QNAME));
+ assertTrue(compositeNodeRpcResult.getErrors().isEmpty());
+ assertNotNull(compositeNodeRpcResult.getResult());
+
+ final List<DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?>> values = Lists.newArrayList(
+ NetconfRemoteSchemaYangSourceProvider.createGetSchemaRequest("module", Optional.of("2012-12-12")).getValue());
+
+ final Map<QName, Object> keys = Maps.newHashMap();
+ for (final DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> value : values) {
+ keys.put(value.getNodeType(), value.getValue());
+ }
+
+ final YangInstanceIdentifier.NodeIdentifierWithPredicates identifierWithPredicates = new YangInstanceIdentifier.NodeIdentifierWithPredicates(Schema.QNAME, keys);
+ final MapEntryNode schemaNode = Builders.mapEntryBuilder().withNodeIdentifier(identifierWithPredicates).withValue(values).build();
+
+ final ContainerNode data = (ContainerNode) ((ContainerNode) compositeNodeRpcResult.getResult()).getChild(toId(NETCONF_DATA_QNAME)).get();
+ final ContainerNode state = (ContainerNode) data.getChild(toId(NetconfState.QNAME)).get();
+ final ContainerNode schemas = (ContainerNode) state.getChild(toId(Schemas.QNAME)).get();
+ final MapNode schemaParent = (MapNode) schemas.getChild(toId(Schema.QNAME)).get();
+ assertEquals(1, Iterables.size(schemaParent.getValue()));
+
+ assertEquals(schemaNode, schemaParent.getValue().iterator().next());
+ }
+
+ @Test
+ public void testGetConfigRequest() throws Exception {
+ final DataContainerChild<?, ?> filter = toFilterStructure(
+ YangInstanceIdentifier.create(toId(NetconfState.QNAME), toId(Schemas.QNAME)), schema);
+
+ final DataContainerChild<?, ?> source = NetconfBaseOps.getSourceNode(NETCONF_RUNNING_QNAME);
+
+ final NetconfMessage netconfMessage = netconfMessageTransformer.toRpcRequest(toPath(NETCONF_GET_CONFIG_QNAME),
+ NetconfMessageTransformUtil.wrap(NETCONF_GET_CONFIG_QNAME, source, filter));
+
+ assertSimilarXml(netconfMessage, "<rpc message-id=\"m-0\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" +
+ "<get-config xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" +
+ "<filter xmlns:ns0=\"urn:ietf:params:xml:ns:netconf:base:1.0\" ns0:type=\"subtree\">\n" +
+ "<netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">\n" +
+ "<schemas/>\n" +
+ "</netconf-state>" +
+ "</filter>\n" +
+ "<source>\n" +
+ "<running/>\n" +
+ "</source>\n" +
+ "</get-config>" +
+ "</rpc>");
+ }
+
+ @Test
+ public void testEditConfigRequest() throws Exception {
+ final List<DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?>> values = Lists.newArrayList(
+ NetconfRemoteSchemaYangSourceProvider.createGetSchemaRequest("module", Optional.of("2012-12-12")).getValue());
+
+ final Map<QName, Object> keys = Maps.newHashMap();
+ for (final DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> value : values) {
+ keys.put(value.getNodeType(), value.getValue());
+ }
+
+ final YangInstanceIdentifier.NodeIdentifierWithPredicates identifierWithPredicates = new YangInstanceIdentifier.NodeIdentifierWithPredicates(Schema.QNAME, keys);
+ final MapEntryNode schemaNode = Builders.mapEntryBuilder().withNodeIdentifier(identifierWithPredicates).withValue(values).build();
+
+ final YangInstanceIdentifier id = YangInstanceIdentifier.builder().node(NetconfState.QNAME).node(Schemas.QNAME).node(Schema.QNAME).nodeWithKey(Schema.QNAME, keys).build();
+ final DataContainerChild<?, ?> editConfigStructure = createEditConfigStructure(NetconfDevice.INIT_SCHEMA_CTX, id, Optional.<ModifyAction>absent(), Optional.<NormalizedNode<?, ?>>fromNullable(schemaNode));
+
+ final DataContainerChild<?, ?> target = NetconfBaseOps.getTargetNode(NETCONF_CANDIDATE_QNAME);
+
+ final ContainerNode wrap = NetconfMessageTransformUtil.wrap(NETCONF_EDIT_CONFIG_QNAME, editConfigStructure, target);
+ final NetconfMessage netconfMessage = netconfMessageTransformer.toRpcRequest(toPath(NETCONF_EDIT_CONFIG_QNAME), wrap);
+
+ assertSimilarXml(netconfMessage, "<rpc message-id=\"m-0\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" +
+ "<edit-config>\n" +
+ "<target>\n" +
+ "<candidate/>\n" +
+ "</target>\n" +
+ "<config>\n" +
+ "<netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">\n" +
+ "<schemas>\n" +
+ "<schema>\n" +
+ "<identifier>module</identifier>\n" +
+ "<version>2012-12-12</version>\n" +
+ "<format>yang</format>\n" +
+ "</schema>\n" +
+ "</schemas>\n" +
+ "</netconf-state>\n" +
+ "</config>\n" +
+ "</edit-config>\n" +
+ "</rpc>");
+ }
+
+ private void assertSimilarXml(final NetconfMessage netconfMessage, final String xmlContent) throws SAXException, IOException {
+ final Diff diff = XMLUnit.compareXML(netconfMessage.getDocument(), XmlUtil.readXmlToDocument(xmlContent));
+ diff.overrideElementQualifier(new ElementNameAndAttributeQualifier());
+ assertTrue(diff.toString(), diff.similar());
+ }
+
+ @Test
+ public void testGetRequest() throws Exception {
+
+ final QName capability = QName.create(Capabilities.QNAME, "capability");
+ final DataContainerChild<?, ?> filter = toFilterStructure(
+ YangInstanceIdentifier.create(toId(NetconfState.QNAME), toId(Capabilities.QNAME), toId(capability), new YangInstanceIdentifier.NodeWithValue(capability, "a:b:c")), schema);
+
+ final NetconfMessage netconfMessage = netconfMessageTransformer.toRpcRequest(toPath(NETCONF_GET_QNAME),
+ NetconfMessageTransformUtil.wrap(NETCONF_GET_QNAME, filter));
+
+ assertSimilarXml(netconfMessage, "<rpc message-id=\"m-0\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">" +
+ "<get xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" +
+ "<filter xmlns:ns0=\"urn:ietf:params:xml:ns:netconf:base:1.0\" ns0:type=\"subtree\">\n" +
+ "<netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">\n" +
+ "<capabilities>\n" +
+ "<capability>a:b:c</capability>\n" +
+ "</capabilities>\n" +
+ "</netconf-state>" +
+ "</filter>\n" +
+ "</get>" +
+ "</rpc>");
+ }
+
+ private NetconfMessageTransformer getTransformer(final SchemaContext schema) {
+ return new NetconfMessageTransformer(schema, true);
+ }
+
+ @Test
+ public void testCommitResponse() throws Exception {
+ final NetconfMessage response = new NetconfMessage(XmlUtil.readXmlToDocument(
+ "<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><ok/></rpc-reply>"
+ ));
+ final DOMRpcResult compositeNodeRpcResult = netconfMessageTransformer.toRpcResult(response, toPath(NETCONF_COMMIT_QNAME));
+ assertTrue(compositeNodeRpcResult.getErrors().isEmpty());
+ assertNull(compositeNodeRpcResult.getResult());
+ }
+
+ public SchemaContext getSchema(boolean addBase) {
+ final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create();
+ if(addBase) {
+ moduleInfoBackedContext.addModuleInfos(Collections.singleton($YangModuleInfoImpl.getInstance()));
+ }
+ moduleInfoBackedContext.addModuleInfos(Collections.singleton(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.$YangModuleInfoImpl.getInstance()));
+ return moduleInfoBackedContext.tryToCreateSchemaContext().get();
+ }
+}
--- /dev/null
+<ncm:schemas xmlns:ncm="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:threadpool</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>threadpool</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-04-09</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:logback:config</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>config-logging</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-07-16</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:model:statistics:types</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-statistics-types</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-09-25</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:config-dom-store</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-config-dom-datastore</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2014-06-17</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:flow:table:statistics</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-flow-table-statistics</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-12-15</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:meter:service</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>sal-meter</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-09-18</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>toaster-provider-impl</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2014-01-31</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:table:types</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-table-types</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-10-26</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:table:service</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>sal-table</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-10-26</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:shutdown</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>shutdown</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-12-18</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:port:service</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>sal-port</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-11-07</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:netty:eventexecutor</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>netty-event-executor</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-11-12</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>sal-remote</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2014-01-14</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:model:topology:view</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-topology-view</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-10-30</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:netty:threadgroup</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>threadgroup</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-11-07</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:TBD:params:xml:ns:yang:network-topology</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>network-topology</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-07-12</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl:fixed</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>threadpool-impl-fixed</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-12-01</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-sal-binding-broker-impl</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-10-28</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:ietf:params:xml:ns:yang:ietf-restconf</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>ietf-restconf</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-10-19</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:node:error:service</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>node-error</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2014-04-10</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:flow:errors</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>flow-errors</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-11-16</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:flow:service</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>sal-flow</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-08-19</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:ietf:params:xml:ns:yang:rpc-context</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>rpc-context</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-06-17</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:operational-dom-store
+ </ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-operational-dom-datastore</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2014-06-17</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:flow:types:queue</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-queue-types</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-09-25</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>ietf-netconf-monitoring</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2010-10-04</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:netconf-node-inventory</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>netconf-node-inventory</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2014-01-08</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>ietf-yang-types</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-07-15</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:meter:statistics</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-meter-statistics</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-11-11</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:flow:inventory</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>flow-node-inventory</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-08-19</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>odl-sal-netconf-connector-cfg</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-10-28</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl:scheduled</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>threadpool-impl-scheduled</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-12-01</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:TBD:params:xml:ns:yang:network-topology</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>network-topology</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-10-21</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>http://netconfcentral.org/ns/toaster</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>toaster</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2009-11-20</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:config:netconf</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>odl-netconf-cfg</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2014-04-08</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:meter:types</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-meter-types</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-09-18</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-sal-dom-broker-impl</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-10-28</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:flow:topology:discovery</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>flow-topology-discovery</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-08-19</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:yang:extension:yang-ext</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>yang-ext</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-07-09</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>threadpool-impl</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-04-05</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:flow:types:port</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-port-types</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-09-25</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-md-sal-binding</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-10-28</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:packet:service</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>packet-processing</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-07-09</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl:flexible</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>threadpool-impl-flexible</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-12-01</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:queue:service</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>sal-queue</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-11-07</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:ietf:params:xml:ns:yang:ietf-inet-types</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>ietf-inet-types</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2010-09-24</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:md:sal:rest:connector</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-rest-connector</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2014-07-24</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:flow:transaction</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>flow-capable-transaction</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-11-03</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:flow:statistics</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-flow-statistics</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-08-19</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:protocol:framework</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>protocol-framework</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2014-03-13</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:model:match:types</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-match-types</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-10-26</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>ietf-yang-types</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2010-09-24</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:group:service</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>sal-group</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-09-18</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:inmemory-datastore-provider</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-inmemory-datastore-provider</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2014-06-17</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:netty:timer</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>netty-timer</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-11-19</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:group:statistics</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-group-statistics</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-11-11</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:config</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>config</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-04-05</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:config:netconf:client:dispatcher</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>odl-netconfig-client-cfg</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2014-04-08</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:l2:types</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-l2-types</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-08-27</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:action:types</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-action-types</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-11-12</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-md-sal-dom</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-10-28</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:md:sal:common</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-md-sal-common</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-10-28</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:group:types</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-group-types</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-10-18</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring-extension</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>ietf-netconf-monitoring-extension</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-12-10</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:inventory</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-inventory</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-08-19</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:netty</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>netty</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-11-19</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:model:topology:general</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-topology</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-10-30</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:port:statistics</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-port-statistics</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version></ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:queue:statistics</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-queue-statistics</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-12-16</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:config:kitchen-service:impl</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>kitchen-service-impl</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2014-01-31</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:flow:types</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-flow-types</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-10-26</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:params:xml:ns:yang:controller:shutdown:impl</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>shutdown-impl</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-12-18</ncm:version>
+ </ncm:schema>
+ <ncm:schema>
+ <ncm:namespace>urn:opendaylight:model:topology:inventory</ncm:namespace>
+ <ncm:location>NETCONF</ncm:location>
+ <ncm:identifier>opendaylight-topology-inventory</ncm:identifier>
+ <ncm:format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</ncm:format>
+ <ncm:version>2013-10-30</ncm:version>
+ </ncm:schema>
+</ncm:schemas>
\ No newline at end of file
--- /dev/null
+<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
+<eventTime>2007-07-08T00:01:00Z</eventTime>
+<user-visited-page xmlns="org:opendaylight:notification:test:ns:yang:user-notification">
+ <ui:incoming-user xmlns:ui="org:opendaylight:notification:test:ns:yang:user-notification">ui:public-user</ui:incoming-user>
+ <ip-address>172.23.29.104</ip-address>
+ <mac>00:11:00:ff:dd:02</mac>
+ <browser-id>Chrome 35.0.1916.153 m</browser-id>
+ <region>
+ <name>Slovakia</name>
+ <time-zone>UTC/GMT+2</time-zone>
+ </region>
+ <visiting-date>2014-07-08 11:20:48</visiting-date>
+</user-visited-page>
+</notification>
\ No newline at end of file
--- /dev/null
+module config-test-rpc {
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:test:rpc:config:defs";
+ prefix "rpc";
+
+ organization
+ "Cisco Systems, Inc.";
+
+ contact
+ "lsedlak@cisco.com";
+
+ description "Test model containing hacked definition of rpc edit-config and definitions for
+ get and get-config rpc operations.
+ The rpc definition is copied from rfc 6241 Appendix C: http://tools.ietf.org/html/rfc6241#appendix-C";
+
+ revision 2014-07-21 {
+ description "Initial revision.";
+ }
+
+ extension get-filter-element-attributes {
+ description
+ "If this extension is present within an 'anyxml'
+ statement named 'filter', which must be conceptually
+ defined within the RPC input section for the <get>
+ and <get-config> protocol operations, then the
+ following unqualified XML attribute is supported
+ within the <filter> element, within a <get> or
+ <get-config> protocol operation:
+
+ type : optional attribute with allowed
+ value strings 'subtree' and 'xpath'.
+ If missing, the default value is 'subtree'.
+
+ If the 'xpath' feature is supported, then the
+ following unqualified XML attribute is
+ also supported:
+
+ select: optional attribute containing a
+ string representing an XPath expression.
+ The 'type' attribute must be equal to 'xpath'
+ if this attribute is present.";
+ }
+
+ rpc edit-config {
+ description "The <edit-config> operation loads all or part of a specified
+ configuration to the specified target configuration.";
+
+ reference "RFC 6241, Section 7.2";
+
+ input {
+ container target {
+ description "Particular configuration to edit.";
+
+ choice config-target {
+ mandatory true;
+ description "The configuration target.";
+
+ leaf candidate {
+ if-feature candidate;
+ type empty;
+ description "The candidate configuration is the config target.";
+ }
+
+ leaf running {
+ if-feature writable-running;
+ type empty;
+ description "The running configuration is the config source.";
+ }
+ }
+ }
+
+ choice edit-content {
+ mandatory true;
+ description "The content for the edit operation.";
+
+ anyxml config {
+ description
+ "Inline Config content.";
+ }
+
+ leaf url {
+ if-feature url;
+ type string;
+ description
+ "URL-based config content.";
+ }
+ }
+ }
+ }
+
+ rpc get-config {
+ description
+ "Retrieve all or part of a specified configuration.";
+
+ reference "RFC 6241, Section 7.1";
+
+ input {
+ container source {
+ description "Particular configuration to retrieve.";
+
+ choice config-source {
+ mandatory true;
+ description
+ "The configuration to retrieve.";
+ leaf candidate {
+ if-feature candidate;
+ type empty;
+ description
+ "The candidate configuration is the config source.";
+ }
+ leaf running {
+ type empty;
+ description
+ "The running configuration is the config source.";
+ }
+ leaf startup {
+ if-feature startup;
+ type empty;
+ description
+ "The startup configuration is the config source.
+ This is optional-to-implement on the server because
+ not all servers will support filtering for this
+ datastore.";
+ }
+ }
+ }
+
+ anyxml filter {
+ description "Subtree or XPath filter to use.";
+ get-filter-element-attributes;
+ }
+ }
+
+ output {
+ anyxml data {
+ description
+ "Copy of the source datastore subset that matched
+ the filter criteria (if any). An empty data container
+ indicates that the request did not produce any results.";
+ }
+ }
+ }
+
+ rpc get {
+ description "Retrieve running configuration and device state information.";
+
+ reference "RFC 6241, Section 7.7";
+
+ input {
+ anyxml filter {
+ description
+ "This parameter specifies the portion of the system
+ configuration and state data to retrieve.";
+ get-filter-element-attributes;
+ }
+ }
+
+ output {
+ anyxml data {
+ description
+ "Copy of the running datastore subset and/or state
+ data that matched the filter criteria (if any).
+ An empty data container indicates that the request did not
+ produce any results.";
+ }
+ }
+ }
+
+ rpc discard-changes {
+ if-feature candidate;
+
+ description
+ "Revert the candidate configuration to the current
+ running configuration.";
+ reference "RFC 6241, Section 8.3.4.2";
+ }
+}
--- /dev/null
+module rpc-notification-subscription {
+
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:rpc-test";
+ prefix "rpc";
+
+ organization
+ "Cisco Systems, Inc.";
+
+ contact
+ "lsedlak@cisco.com";
+
+ description
+ "Test model for testing of rpc INPUT parameter during subscription call.";
+
+ revision 2014-07-14 {
+ description
+ "Initial revision.";
+ }
+
+ rpc subscribe {
+ description
+ "Test rpc to init subscription";
+
+ input {
+ leaf stream-name {
+ type string;
+ default "NETCONF";
+ description
+ "Optional stream name param.";
+ }
+
+ anyxml data {
+ description
+ "Optional additional data.";
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+module test-module {
+ yang-version 1;
+ namespace "test:namespace";
+ prefix "tt";
+
+ description
+ "Types for testing";
+
+ revision "2013-07-22";
+
+
+ container c {
+ leaf a {
+ type string;
+ }
+ }
+
+}
--- /dev/null
+module user-notification {
+ yang-version 1;
+ namespace "org:opendaylight:notification:test:ns:yang:user-notification";
+ prefix "user";
+
+ organization "Cisco Systems";
+ contact "Lukas Sedlak";
+ description "Test model for testing notifications";
+
+ revision "2014-07-08" {
+ description "Initial revision";
+ }
+
+ identity user-identity {
+ description "Identity of user incoming to Web Page";
+ }
+
+ identity public-user {
+ base user-identity;
+ description "Identity of random public non-registered user";
+ }
+
+ notification user-visited-page {
+ leaf incoming-user {
+ type identityref {
+ base "user-identity";
+ }
+ }
+
+ leaf ip-address {
+ type string;
+ }
+
+ leaf mac {
+ type string;
+ }
+
+ leaf browser-id {
+ type string;
+ }
+
+ container region {
+ leaf name {
+ type string;
+ }
+
+ leaf time-zone {
+ type string;
+ }
+ }
+
+ leaf visiting-date {
+ type string;
+ }
+ }
+}
\ No newline at end of file
<parent>
<groupId>org.opendaylight.controller</groupId>
- <artifactId>netconf-subsystem</artifactId>
+ <artifactId>netconf-tools</artifactId>
<version>0.4.0-SNAPSHOT</version>
</parent>
<artifactId>netconf-cli</artifactId>
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.cli.io.BaseConsoleContext;
import org.opendaylight.controller.netconf.cli.io.ConsoleContext;
import org.opendaylight.controller.netconf.cli.io.ConsoleIO;
import org.opendaylight.controller.netconf.cli.reader.AbstractReader;
import org.opendaylight.controller.netconf.cli.reader.ReadingException;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
<parent>
<groupId>org.opendaylight.controller</groupId>
- <artifactId>netconf-subsystem</artifactId>
+ <artifactId>netconf-tools</artifactId>
<version>0.4.0-SNAPSHOT</version>
</parent>
import java.util.Collections;
import java.util.Set;
import javax.annotation.Nullable;
-import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.config.util.capability.Capability;
import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
}
@Override
- public void onCapabilitiesAdded(Set<Capability> addedCaps) {
-
- }
-
- @Override
- public void onCapabilitiesRemoved(Set<Capability> removedCaps) {
+ public void onSessionUp(NetconfManagementSession session) {
}
@Override
- public void onSessionUp(NetconfManagementSession session) {
+ public void onSessionDown(NetconfManagementSession session) {
}
@Override
- public void onSessionDown(NetconfManagementSession session) {
+ public void onCapabilitiesChanged(Set<Capability> added, Set<Capability> removed) {
}
}
import net.sourceforge.argparse4j.annotation.Arg;
import net.sourceforge.argparse4j.inf.ArgumentParser;
import net.sourceforge.argparse4j.inf.ArgumentParserException;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import java.util.Collections;
import java.util.Date;
import java.util.List;
-import org.opendaylight.controller.netconf.api.Capability;
-import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
+import org.opendaylight.controller.config.facade.xml.util.Util;
+import org.opendaylight.controller.config.util.capability.Capability;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
-import java.lang.management.ManagementFactory;
import java.net.BindException;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.AbstractMap;
+import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import org.apache.sshd.server.PasswordAuthenticator;
import org.apache.sshd.server.keyprovider.PEMGeneratorHostKeyProvider;
import org.apache.sshd.server.session.ServerSession;
-import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.config.util.capability.Capability;
import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
import org.opendaylight.controller.netconf.impl.NetconfServerDispatcherImpl;
import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
import org.opendaylight.controller.netconf.impl.SessionIdProvider;
aggregatedNetconfOperationServiceFactory.onAddNetconfOperationServiceFactory(simulatedOperationProvider);
aggregatedNetconfOperationServiceFactory.onAddNetconfOperationServiceFactory(monitoringService);
- final DefaultCommitNotificationProducer commitNotifier = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
-
final Set<String> serverCapabilities = exi
? NetconfServerSessionNegotiatorFactory.DEFAULT_BASE_CAPABILITIES
: Sets.newHashSet(XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0, XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_1);
final NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
- hashedWheelTimer, aggregatedNetconfOperationServiceFactory, idProvider, generateConfigsTimeout, commitNotifier, monitoringService1, serverCapabilities);
+ hashedWheelTimer, aggregatedNetconfOperationServiceFactory, idProvider, generateConfigsTimeout, monitoringService1, serverCapabilities);
final NetconfServerDispatcherImpl.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcherImpl.ServerChannelInitializer(
serverNegotiatorFactory);
@Override
public AutoCloseable registerCapabilityListener(final CapabilityListener listener) {
- listener.onCapabilitiesAdded(caps);
+ listener.onCapabilitiesChanged(caps, Collections.<Capability>emptySet());
return new AutoCloseable() {
@Override
public void close() throws Exception {}
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.controller.sal.connect.netconf.listener.NetconfDeviceCommunicator;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
import org.opendaylight.controller.netconf.nettyutil.handler.ssh.client.AsyncSshHandler;
import org.opendaylight.controller.netconf.test.tool.TestToolUtils;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.sal.connect.api.RemoteDevice;
import org.opendaylight.controller.sal.connect.netconf.listener.NetconfDeviceCommunicator;
import org.opendaylight.controller.sal.connect.netconf.listener.NetconfSessionPreferences;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.controller.sal.connect.netconf.listener.NetconfDeviceCommunicator;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import java.util.Collections;
import java.util.List;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlElement;
public class DataList {
package org.opendaylight.controller.netconf.test.tool.rpc;
import com.google.common.base.Optional;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
}
@Override
- protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws DocumentedException {
return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
}
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlRootElement;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.impl.NetconfServerSession;
import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultNetconfOperation;
import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
}
@Override
- protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws DocumentedException {
long delayAggregator = 0;
for (final Map.Entry<Notification, NetconfMessage> notification : notifications.entrySet()) {
package org.opendaylight.controller.netconf.test.tool.rpc;
import com.google.common.base.Optional;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigXmlParser;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
}
@Override
- protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws DocumentedException {
final XmlElement configElementData = operationElement.getOnlyChildElement(XmlNetconfConstants.CONFIG_KEY);
containsDelete(configElementData);
package org.opendaylight.controller.netconf.test.tool.rpc;
import com.google.common.base.Optional;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
}
@Override
- protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws DocumentedException {
final Element element = XmlUtil.createElement(document, XmlNetconfConstants.DATA_KEY, Optional.<String>absent());
for(final XmlElement e : storage.getConfigList()) {
package org.opendaylight.controller.netconf.test.tool.rpc;
import com.google.common.base.Optional;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
}
@Override
- protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws DocumentedException {
final Element element = XmlUtil.createElement(document, XmlNetconfConstants.DATA_KEY, Optional.<String>absent());
for(final XmlElement e : storage.getConfigList()) {
package org.opendaylight.controller.netconf.test.tool.rpc;
import com.google.common.base.Optional;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
}
@Override
- protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws DocumentedException {
return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
}
package org.opendaylight.controller.netconf.test.tool.rpc;
import com.google.common.base.Optional;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
}
@Override
- protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+ protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws DocumentedException {
return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-subsystem</artifactId>
+ <version>0.4.0-SNAPSHOT</version>
+ <relativePath>../</relativePath>
+ </parent>
+ <artifactId>netconf-tools</artifactId>
+
+ <version>0.4.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+ <name>${project.artifactId}</name>
+
+ <modules>
+ <module>netconf-cli</module>
+ <module>netconf-testtool</module>
+ </modules>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-maven-plugin</artifactId>
+ <version>${yangtools.version}</version>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>maven-sal-api-gen-plugin</artifactId>
+ <version>${yangtools.version}</version>
+ </dependency>
+ </dependencies>
+ <executions>
+ <execution>
+ <goals>
+ <goal>generate-sources</goal>
+ </goals>
+ <configuration>
+ <yangFilesRootDir>src/main/yang</yangFilesRootDir>
+ <codeGenerators>
+ <generator>
+ <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
+ <outputBaseDir>${salGeneratorPath}</outputBaseDir>
+ </generator>
+ <generator>
+ <codeGeneratorClass>org.opendaylight.yangtools.yang.unified.doc.generator.maven.DocumentationGeneratorImpl</codeGeneratorClass>
+ <outputBaseDir>${project.build.directory}/site/models</outputBaseDir>
+ </generator>
+ </codeGenerators>
+ <inspectDependencies>true</inspectDependencies>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+
+ </pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <configuration>
+ <failsOnError>false</failsOnError>
+ <failOnViolation>true</failOnViolation>
+ <configLocation>checkstyle-logging.xml</configLocation>
+ <consoleOutput>true</consoleOutput>
+ <includeTestSourceDirectory>true</includeTestSourceDirectory>
+ <sourceDirectory>${project.basedir}</sourceDirectory>
+ <includes>**\/*.java,**\/*.xml,**\/*.ini,**\/*.sh,**\/*.bat,**\/*.yang</includes>
+ <excludes>**\/target\/,**\/bin\/,**\/target-ide\/,**\/${jmxGeneratorPath}\/,**\/${salGeneratorPath}\/,**\/netconf\/test\/tool\/Main.java, **\/netconf\/test\/tool\/client\/stress\/StressClient.java</excludes>
+ </configuration>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>checkstyle-logging</artifactId>
+ <version>${yangtools.version}</version>
+ </dependency>
+ </dependencies>
+ <executions>
+ <execution>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+</project>