Add netconf.api.NamespaceURN
[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 com.google.common.base.Preconditions;
11 import io.netty.channel.Channel;
12 import io.netty.channel.ChannelFuture;
13 import io.netty.channel.ChannelFutureListener;
14 import javax.xml.XMLConstants;
15 import org.opendaylight.netconf.api.DocumentedException;
16 import org.opendaylight.netconf.api.NamespaceURN;
17 import org.opendaylight.netconf.api.NetconfMessage;
18 import org.opendaylight.netconf.api.NetconfSession;
19 import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
20 import org.opendaylight.netconf.api.xml.XmlUtil;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23 import org.w3c.dom.Attr;
24 import org.w3c.dom.Document;
25 import org.w3c.dom.Element;
26 import org.w3c.dom.NamedNodeMap;
27
28 public final class SendErrorExceptionUtil {
29     private static final Logger LOG = LoggerFactory.getLogger(SendErrorExceptionUtil.class);
30
31     private SendErrorExceptionUtil() {
32         // Hidden on purpose
33     }
34
35     public 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     public 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     public 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     @SuppressWarnings("checkstyle:IllegalCatch")
62     private static void tryToCopyAttributes(final Document incommingDocument, final Document errorDocument,
63             final DocumentedException sendErrorException) {
64         try {
65             final Element incommingRpc = incommingDocument.getDocumentElement();
66             Preconditions.checkState(
67                 XmlNetconfConstants.RPC_KEY.equals(incommingRpc.getLocalName())
68                 && NamespaceURN.BASE.equals(incommingRpc.getNamespaceURI()),
69                     "Missing %s element", XmlNetconfConstants.RPC_KEY);
70
71             final Element rpcReply = errorDocument.getDocumentElement();
72             Preconditions.checkState(rpcReply.getTagName().equals(XmlNetconfConstants.RPC_REPLY_KEY),
73                     "Missing %s element", XmlNetconfConstants.RPC_REPLY_KEY);
74
75             final NamedNodeMap incomingAttributes = incommingRpc.getAttributes();
76             for (int i = 0; i < incomingAttributes.getLength(); i++) {
77                 final Attr 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             Preconditions.checkState(channelFuture.isSuccess(), "Unable to send exception %s", sendErrorException,
107                     channelFuture.cause());
108         }
109     }
110 }