Eliminate HandlingPriority.CANNOT_HANDLE
[netconf.git] / protocol / netconf-server / src / main / java / org / opendaylight / netconf / server / api / operations / AbstractNetconfOperation.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  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.server.api.operations;
9
10 import static java.util.Objects.requireNonNull;
11
12 import org.eclipse.jdt.annotation.NonNull;
13 import org.opendaylight.netconf.api.DocumentedException;
14 import org.opendaylight.netconf.api.NamespaceURN;
15 import org.opendaylight.netconf.api.messages.RpcMessage;
16 import org.opendaylight.netconf.api.messages.RpcReplyMessage;
17 import org.opendaylight.netconf.api.xml.XmlElement;
18 import org.opendaylight.netconf.api.xml.XmlUtil;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.SessionIdType;
20 import org.w3c.dom.Attr;
21 import org.w3c.dom.Document;
22 import org.w3c.dom.Element;
23
24 public abstract class AbstractNetconfOperation implements NetconfOperation {
25     private final @NonNull SessionIdType sessionId;
26
27     protected AbstractNetconfOperation(final SessionIdType sessionId) {
28         this.sessionId = requireNonNull(sessionId);
29     }
30
31     public final @NonNull SessionIdType sessionId() {
32         return sessionId;
33     }
34
35     @Override
36     public final HandlingPriority canHandle(final Document message) throws DocumentedException {
37         final var operationNameAndNamespace = new OperationNameAndNamespace(message);
38         return canHandle(operationNameAndNamespace.getOperationName(), operationNameAndNamespace.getNamespace());
39     }
40
41     protected HandlingPriority canHandle(final String operationName, final String operationNamespace) {
42         return operationName.equals(getOperationName()) && operationNamespace.equals(getOperationNamespace())
43             ? getHandlingPriority() : null;
44     }
45
46     public static final class OperationNameAndNamespace {
47         private final String operationName;
48         private final String namespace;
49         private final XmlElement operationElement;
50
51         public OperationNameAndNamespace(final Document message) throws DocumentedException {
52             final var requestElement = getRequestElementWithCheck(message);
53             operationElement = requestElement.getOnlyChildElement();
54             operationName = operationElement.getName();
55             namespace = operationElement.getNamespace();
56         }
57
58         public String getOperationName() {
59             return operationName;
60         }
61
62         public String getNamespace() {
63             return namespace;
64         }
65
66         public XmlElement getOperationElement() {
67             return operationElement;
68         }
69     }
70
71     protected static XmlElement getRequestElementWithCheck(final Document message) throws DocumentedException {
72         return XmlElement.fromDomElementWithExpected(message.getDocumentElement(), RpcMessage.ELEMENT_NAME,
73             NamespaceURN.BASE);
74     }
75
76     protected @NonNull HandlingPriority getHandlingPriority() {
77         return HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY;
78     }
79
80     protected String getOperationNamespace() {
81         return NamespaceURN.BASE;
82     }
83
84     protected abstract String getOperationName();
85
86     @Override
87     public Document handle(final Document requestMessage,
88             final NetconfOperationChainedExecution subsequentOperation) throws DocumentedException {
89         final var requestElement = getRequestElementWithCheck(requestMessage);
90         final var document = XmlUtil.newDocument();
91         final var operationElement = requestElement.getOnlyChildElement();
92         final var attributes = requestElement.getAttributes();
93
94         final var response = handle(document, operationElement, subsequentOperation);
95         final var rpcReply = document.createElementNS(NamespaceURN.BASE, RpcReplyMessage.ELEMENT_NAME);
96         if (XmlUtil.hasNamespace(response)) {
97             rpcReply.appendChild(response);
98         } else {
99             // FIXME: use getLocalName() instead
100             final var responseNS = document.createElementNS(NamespaceURN.BASE, response.getNodeName());
101             final var list = response.getChildNodes();
102             while (list.getLength() != 0) {
103                 responseNS.appendChild(list.item(0));
104             }
105             rpcReply.appendChild(responseNS);
106         }
107
108         for (var attribute : attributes.values()) {
109             rpcReply.setAttributeNode((Attr) document.importNode(attribute, true));
110         }
111         document.appendChild(rpcReply);
112         return document;
113     }
114
115     protected abstract Element handle(Document document, XmlElement message,
116                                       NetconfOperationChainedExecution subsequentOperation)
117             throws DocumentedException;
118
119     @Override
120     public String toString() {
121         final var sb = new StringBuilder(getClass().getName());
122         try {
123             sb.append("{name=").append(getOperationName());
124         } catch (UnsupportedOperationException e) {
125             // no problem
126         }
127         return sb
128             .append(", namespace=").append(getOperationNamespace())
129             .append(", session=").append(sessionId.getValue())
130             .append('}')
131             .toString();
132     }
133 }