Add is{Notification,Rpc,RpcReply}Message methods
[netconf.git] / protocol / netconf-api / src / main / java / org / opendaylight / netconf / api / messages / RpcReplyMessage.java
1 /*
2  * Copyright (c) 2023 PANTHEON.tech s.r.o. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.netconf.api.messages;
9
10 import com.google.common.collect.ImmutableMap;
11 import org.eclipse.jdt.annotation.NonNull;
12 import org.eclipse.jdt.annotation.Nullable;
13 import org.opendaylight.netconf.api.DocumentedException;
14 import org.opendaylight.netconf.api.NamespaceURN;
15 import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
16 import org.opendaylight.yangtools.yang.common.ErrorSeverity;
17 import org.opendaylight.yangtools.yang.common.ErrorTag;
18 import org.opendaylight.yangtools.yang.common.ErrorType;
19 import org.w3c.dom.Document;
20
21 /**
22  * A NETCONF RPC reply message, as defined in
23  * <a href="https://www.rfc-editor.org/rfc/rfc6241#section-4.2">RFC6241, section 4.2</a>. Its document element is
24  * guaranteed to be an {@code <rpc-reply/>} in the {@value NamespaceURN#BASE} namespace.
25  */
26 public final class RpcReplyMessage extends NetconfMessage {
27     private RpcReplyMessage(final Document document) {
28         super(document);
29     }
30
31     /**
32      * Return an {@link RpcReplyMessage} backed by specified {@link Document}.
33      *
34      * @param document Backing document
35      * @return An {@link RpcReplyMessage}
36      * @throws DocumentedException if the document's structure does not form a valid {@code rpc-reply} message
37      * @throws NullPointerException if {@code document} is {@code null}
38      */
39     public static @NonNull RpcReplyMessage of(final Document document) throws DocumentedException {
40         final var root = document.getDocumentElement();
41         final var rootName = root.getLocalName();
42         if (!XmlNetconfConstants.RPC_REPLY_KEY.equals(rootName)) {
43             throw new DocumentedException("Unexpected element name " + rootName, ErrorType.PROTOCOL,
44                 ErrorTag.UNKNOWN_ELEMENT, ErrorSeverity.ERROR, ImmutableMap.of("bad-element", rootName));
45         }
46         final var rootNs = root.getNamespaceURI();
47         if (!NamespaceURN.BASE.equals(rootNs)) {
48             throw new DocumentedException("Unexpected element namespace " + rootNs, ErrorType.PROTOCOL,
49                 ErrorTag.UNKNOWN_NAMESPACE, ErrorSeverity.ERROR, ImmutableMap.of(
50                     "bad-element", rootName,
51                     "bad-namespace", rootNs));
52         }
53
54         return new RpcReplyMessage(document);
55     }
56
57     /**
58      * Return an {@link RpcReplyMessage} representation.
59      *
60      * @param ex DocumentedException specifying the error
61      * @return An {@link RpcReplyMessage}
62      * @throws NullPointerException if {@code ex} is {@code null}
63      */
64     public static @NonNull RpcReplyMessage of(final DocumentedException ex) {
65         return new RpcReplyMessage(ex.toXMLDocument());
66     }
67
68     public @Nullable String messageId() {
69         final var attr = getDocument().getDocumentElement().getAttributeNode(XmlNetconfConstants.MESSAGE_ID);
70         return attr == null ? null : attr.getValue();
71     }
72
73     public static boolean isRpcReplyMessage(final Document document) {
74         final var root = document.getDocumentElement();
75         return NamespaceURN.BASE.equals(root.getNamespaceURI())
76             && XmlNetconfConstants.RPC_REPLY_KEY.equals(root.getLocalName());
77     }
78 }