X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-netconf-connector%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fsal%2Fconnect%2Fnetconf%2Futil%2FNetconfMessageTransformUtil.java;h=0aeec64690d971abfa7f74b1bd58385e669163fe;hb=refs%2Fchanges%2F64%2F8964%2F4;hp=0c6ad45fbb86eda0631e5cf2b1465079fd2df183;hpb=11161d86d92f769c85de7e7c8621a4f7ad1bb6f9;p=controller.git diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/util/NetconfMessageTransformUtil.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/util/NetconfMessageTransformUtil.java index 0c6ad45fbb..0aeec64690 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/util/NetconfMessageTransformUtil.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/util/NetconfMessageTransformUtil.java @@ -7,50 +7,56 @@ */ package org.opendaylight.controller.sal.connect.netconf.util; +import com.google.common.base.Predicate; +import com.google.common.collect.Collections2; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.List; - import java.util.Map; +import java.util.Map.Entry; + import javax.annotation.Nullable; 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.controller.netconf.util.xml.XmlUtil; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.RpcError; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; +import org.opendaylight.yangtools.yang.common.RpcError.ErrorSeverity; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl; import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode; import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl; -import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils; import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder; +import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.w3c.dom.Document; import org.w3c.dom.Element; -import com.google.common.base.Predicate; -import com.google.common.collect.Collections2; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; - public class NetconfMessageTransformUtil { private NetconfMessageTransformUtil() { } - public static final QName IETF_NETCONF_MONITORING = QName.create( - "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring", "2010-10-04", "ietf-netconf-monitoring"); + public static final QName IETF_NETCONF_MONITORING = QName.create("urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring", "2010-10-04", "ietf-netconf-monitoring"); public static URI NETCONF_URI = URI.create("urn:ietf:params:xml:ns:netconf:base:1.0"); public static QName NETCONF_QNAME = QName.create(NETCONF_URI, null, "netconf"); public static QName NETCONF_DATA_QNAME = QName.create(NETCONF_QNAME, "data"); public static QName NETCONF_RPC_REPLY_QNAME = QName.create(NETCONF_QNAME, "rpc-reply"); public static QName NETCONF_ERROR_OPTION_QNAME = QName.create(NETCONF_QNAME, "error-option"); public static QName NETCONF_RUNNING_QNAME = QName.create(NETCONF_QNAME, "running"); - static List> RUNNING = Collections.> singletonList(new SimpleNodeTOImpl<>(NETCONF_RUNNING_QNAME, - null, null)); + static List> RUNNING = Collections.> singletonList(new SimpleNodeTOImpl<>(NETCONF_RUNNING_QNAME, null, null)); public static QName NETCONF_SOURCE_QNAME = QName.create(NETCONF_QNAME, "source"); public static CompositeNode CONFIG_SOURCE_RUNNING = new CompositeNodeTOImpl(NETCONF_SOURCE_QNAME, null, RUNNING); public static QName NETCONF_CANDIDATE_QNAME = QName.create(NETCONF_QNAME, "candidate"); @@ -58,6 +64,7 @@ public class NetconfMessageTransformUtil { public static QName NETCONF_CONFIG_QNAME = QName.create(NETCONF_QNAME, "config"); public static QName NETCONF_COMMIT_QNAME = QName.create(NETCONF_QNAME, "commit"); public static QName NETCONF_OPERATION_QNAME = QName.create(NETCONF_QNAME, "operation"); + public static QName NETCONF_DEFAULT_OPERATION_QNAME = QName.create(NETCONF_OPERATION_QNAME, "default-operation"); public static QName NETCONF_EDIT_CONFIG_QNAME = QName.create(NETCONF_QNAME, "edit-config"); public static QName NETCONF_GET_CONFIG_QNAME = QName.create(NETCONF_QNAME, "get-config"); public static QName NETCONF_TYPE_QNAME = QName.create(NETCONF_QNAME, "type"); @@ -70,7 +77,7 @@ public class NetconfMessageTransformUtil { public static Node toFilterStructure(final InstanceIdentifier identifier) { Node previous = null; - if (identifier.getPath().isEmpty()) { + if (Iterables.isEmpty(identifier.getPathArguments())) { return null; } @@ -96,28 +103,82 @@ public class NetconfMessageTransformUtil { return new CompositeNodeTOImpl(argument.getNodeType(), null, list); } - public static void checkValidReply(final NetconfMessage input, final NetconfMessage output) { + public static void checkValidReply(final NetconfMessage input, final NetconfMessage output) + throws NetconfDocumentedException { final String inputMsgId = input.getDocument().getDocumentElement().getAttribute("message-id"); final String outputMsgId = output.getDocument().getDocumentElement().getAttribute("message-id"); if(inputMsgId.equals(outputMsgId) == false) { - final String requestXml = XmlUtil.toString(input.getDocument()); - final String responseXml = XmlUtil.toString(output.getDocument()); - throw new IllegalStateException(String.format("Rpc request and reply message IDs must be same. Request: %s, response: %s", requestXml, responseXml)); + Map errorInfo = ImmutableMap.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 new IllegalStateException(String.format("Response contains error: %s", XmlUtil.toString(output.getDocument()))); + throw NetconfDocumentedException.fromXMLDocument( output.getDocument() ); + } + } + + public static RpcError toRpcError( final NetconfDocumentedException ex ) + { + StringBuilder infoBuilder = new StringBuilder(); + Map errorInfo = ex.getErrorInfo(); + if( errorInfo != null ) + { + for( Entry e: errorInfo.entrySet() ) { + infoBuilder.append( '<' ).append( e.getKey() ).append( '>' ).append( e.getValue() ) + .append( "' ); + + } + } + + 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 CompositeNode flattenInput(final CompositeNode node) { final QName inputQName = QName.create(node.getNodeType(), "input"); final CompositeNode input = node.getFirstCompositeByName(inputQName); - if (input == null) + if (input == null) { return node; + } if (input instanceof CompositeNode) { final List> nodes = ImmutableList.> builder() // @@ -125,7 +186,7 @@ public class NetconfMessageTransformUtil { .addAll(Collections2.filter(node.getValue(), new Predicate>() { @Override public boolean apply(@Nullable final Node input) { - return input.getNodeType() != inputQName; + return !inputQName.equals(input.getNodeType()); } })) // .build(); @@ -149,11 +210,41 @@ public class NetconfMessageTransformUtil { } public static boolean isDataRetrievalOperation(final QName rpc) { - return NETCONF_URI == rpc.getNamespace() + return NETCONF_URI.equals(rpc.getNamespace()) && (rpc.getLocalName().equals(NETCONF_GET_CONFIG_QNAME.getLocalName()) || rpc.getLocalName().equals( NETCONF_GET_QNAME.getLocalName())); } + public static boolean isDataEditOperation(final QName rpc) { + return NETCONF_URI.equals(rpc.getNamespace()) + && rpc.getLocalName().equals(NETCONF_EDIT_CONFIG_QNAME.getLocalName()); + } + + /** + * Creates artificial schema node for edit-config rpc. This artificial schema looks like: + *
+     * {@code
+     * rpc
+     *   edit-config
+     *     config
+     *         // All schema nodes from remote schema
+     *     config
+     *   edit-config
+     * rpc
+     * }
+     * 
+ * + * This makes the translation of rpc edit-config request(especially the config node) + * to xml use schema which is crucial for some types of nodes e.g. identity-ref. + */ + public static DataNodeContainer createSchemaForEdit(final SchemaContext schemaContext) { + final QName config = QName.create(NETCONF_EDIT_CONFIG_QNAME, "config"); + final QName editConfig = QName.create(NETCONF_EDIT_CONFIG_QNAME, "edit-config"); + final NodeContainerProxy configProxy = new NodeContainerProxy(config, schemaContext.getChildNodes()); + final NodeContainerProxy editConfigProxy = new NodeContainerProxy(editConfig, Sets.newHashSet(configProxy)); + return new NodeContainerProxy(NETCONF_RPC_QNAME, Sets.newHashSet(editConfigProxy)); + } + public static CompositeNodeTOImpl wrap(final QName name, final Node node) { if (node != null) { return new CompositeNodeTOImpl(name, null, Collections.> singletonList(node));