Remove NettyEndpointConfiguration.baseUri()
[netconf.git] / protocol / netconf-server / src / main / java / org / opendaylight / netconf / server / SendErrorExceptionUtil.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;
9
10 import static com.google.common.base.Preconditions.checkState;
11
12 import io.netty.channel.Channel;
13 import io.netty.channel.ChannelFuture;
14 import io.netty.channel.ChannelFutureListener;
15 import javax.xml.XMLConstants;
16 import org.opendaylight.netconf.api.DocumentedException;
17 import org.opendaylight.netconf.api.NamespaceURN;
18 import org.opendaylight.netconf.api.NetconfSession;
19 import org.opendaylight.netconf.api.messages.NetconfMessage;
20 import org.opendaylight.netconf.api.messages.RpcMessage;
21 import org.opendaylight.netconf.api.messages.RpcReplyMessage;
22 import org.opendaylight.netconf.api.xml.XmlUtil;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25 import org.w3c.dom.Attr;
26 import org.w3c.dom.Document;
27
28 final class SendErrorExceptionUtil {
29     private static final Logger LOG = LoggerFactory.getLogger(SendErrorExceptionUtil.class);
30
31     private SendErrorExceptionUtil() {
32         // Hidden on purpose
33     }
34
35     static void sendErrorMessage(final NetconfSession session, final DocumentedException sendErrorException) {
36         LOG.trace("Sending error", sendErrorException);
37         final Document errorDocument = createDocument(sendErrorException);
38         ChannelFuture channelFuture = session.sendMessage(new NetconfMessage(errorDocument));
39         channelFuture.addListener(new SendErrorVerifyingListener(sendErrorException));
40     }
41
42     static void sendErrorMessage(final Channel channel, final DocumentedException sendErrorException) {
43         LOG.trace("Sending error", sendErrorException);
44         final Document errorDocument = createDocument(sendErrorException);
45         ChannelFuture channelFuture = channel.writeAndFlush(new NetconfMessage(errorDocument));
46         channelFuture.addListener(new SendErrorVerifyingListener(sendErrorException));
47     }
48
49     static void sendErrorMessage(final NetconfSession session, final DocumentedException sendErrorException,
50             final NetconfMessage incommingMessage) {
51         final Document errorDocument = createDocument(sendErrorException);
52         if (LOG.isTraceEnabled()) {
53             LOG.trace("Sending error {}", XmlUtil.toString(errorDocument));
54         }
55
56         tryToCopyAttributes(incommingMessage.getDocument(), errorDocument, sendErrorException);
57         ChannelFuture channelFuture = session.sendMessage(new NetconfMessage(errorDocument));
58         channelFuture.addListener(new SendErrorVerifyingListener(sendErrorException));
59     }
60
61     // FIXME: this should be handled through RpcMessage.toReply(DocumentedException)
62     @SuppressWarnings("checkstyle:IllegalCatch")
63     private static void tryToCopyAttributes(final Document incommingDocument, final Document errorDocument,
64             final DocumentedException sendErrorException) {
65         try {
66             final var incommingRpc = incommingDocument.getDocumentElement();
67             checkState(RpcMessage.ELEMENT_NAME.equals(incommingRpc.getLocalName())
68                 && NamespaceURN.BASE.equals(incommingRpc.getNamespaceURI()), "Missing %s element",
69                 RpcMessage.ELEMENT_NAME);
70
71             final var rpcReply = errorDocument.getDocumentElement();
72             checkState(rpcReply.getTagName().equals(RpcReplyMessage.ELEMENT_NAME), "Missing %s element",
73                 RpcReplyMessage.ELEMENT_NAME);
74
75             final var incomingAttributes = incommingRpc.getAttributes();
76             for (int i = 0; i < incomingAttributes.getLength(); i++) {
77                 final var attr = (Attr) incomingAttributes.item(i);
78                 // skip namespace
79                 if (attr.getNodeName().equals(XMLConstants.XMLNS_ATTRIBUTE)) {
80                     continue;
81                 }
82                 rpcReply.setAttributeNode((Attr) errorDocument.importNode(attr, true));
83             }
84         } catch (final Exception e) {
85             LOG.warn("Unable to copy incomming attributes to {}, returned rpc-error might be invalid for client",
86                     sendErrorException, e);
87         }
88     }
89
90     private static Document createDocument(final DocumentedException sendErrorException) {
91         return sendErrorException.toXMLDocument();
92     }
93
94     /**
95      * Checks if netconf error was sent successfully.
96      */
97     private static final class SendErrorVerifyingListener implements ChannelFutureListener {
98         private final DocumentedException sendErrorException;
99
100         SendErrorVerifyingListener(final DocumentedException sendErrorException) {
101             this.sendErrorException = sendErrorException;
102         }
103
104         @Override
105         public void operationComplete(final ChannelFuture channelFuture) {
106             final var cause = channelFuture.cause();
107             if (cause != null) {
108                 throw new IllegalStateException("Unable to send exception " + sendErrorException, cause);
109             }
110         }
111     }
112 }