Fix warnings reported in toaster
[controller.git] / opendaylight / netconf / netconf-util / src / main / java / org / opendaylight / controller / netconf / util / messages / NetconfMessageFactory.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
9 package org.opendaylight.controller.netconf.util.messages;
10
11 import java.io.ByteArrayInputStream;
12 import java.io.IOException;
13 import java.nio.ByteBuffer;
14 import java.util.Arrays;
15 import java.util.List;
16
17 import org.opendaylight.controller.netconf.api.NetconfDeserializerException;
18 import org.opendaylight.controller.netconf.api.NetconfMessage;
19 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
20 import org.opendaylight.protocol.framework.DeserializerException;
21 import org.opendaylight.protocol.framework.DocumentedException;
22 import org.opendaylight.protocol.framework.ProtocolMessageFactory;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25 import org.w3c.dom.Comment;
26 import org.w3c.dom.Document;
27 import org.xml.sax.SAXException;
28
29 import com.google.common.base.Charsets;
30 import com.google.common.base.Optional;
31 import com.google.common.collect.ImmutableList;
32
33 /**
34  * NetconfMessageFactory for (de)serializing DOM documents.
35  */
36 public final class NetconfMessageFactory implements ProtocolMessageFactory<NetconfMessage> {
37
38     private static final Logger logger = LoggerFactory.getLogger(NetconfMessageFactory.class);
39     private static final List<byte[]> POSSIBLE_STARTS = ImmutableList.of(
40         "[".getBytes(Charsets.UTF_8), "\r\n[".getBytes(Charsets.UTF_8), "\n[".getBytes(Charsets.UTF_8));
41     private static final List<byte[]> POSSIBLE_ENDS = ImmutableList.of(
42         "]\n".getBytes(Charsets.UTF_8), "]\r\n".getBytes(Charsets.UTF_8));
43
44     private final Optional<String> clientId;
45
46     public NetconfMessageFactory() {
47         clientId = Optional.absent();
48     }
49
50     public NetconfMessageFactory(Optional<String> clientId) {
51         this.clientId = clientId;
52     }
53
54     @Override
55     public NetconfMessage parse(byte[] bytes) throws DeserializerException, DocumentedException {
56         logMessage(bytes);
57
58         String additionalHeader = null;
59
60         if (startsWithAdditionalHeader(bytes)) {
61             // Auth information containing username, ip address... extracted for monitoring
62             int endOfAuthHeader = getAdditionalHeaderEndIndex(bytes);
63             if (endOfAuthHeader > -1) {
64                 byte[] additionalHeaderBytes = Arrays.copyOfRange(bytes, 0, endOfAuthHeader + 2);
65                 additionalHeader = additionalHeaderToString(additionalHeaderBytes);
66                 bytes = Arrays.copyOfRange(bytes, endOfAuthHeader + 2, bytes.length);
67             }
68         }
69         NetconfMessage message;
70         try {
71             Document doc = XmlUtil.readXmlToDocument(new ByteArrayInputStream(bytes));
72             message = new NetconfMessage(doc, additionalHeader);
73         } catch (final SAXException | IOException | IllegalStateException e) {
74             throw new NetconfDeserializerException("Could not parse message from " + new String(bytes), e);
75         }
76         return message;
77     }
78
79     private static int findByteSequence(final byte[] bytes, final byte[] sequence) {
80         if (bytes.length < sequence.length) {
81             throw new IllegalArgumentException("Sequence to be found is longer than the given byte array.");
82         }
83         if (bytes.length == sequence.length) {
84             if (Arrays.equals(bytes, sequence)) {
85                 return 0;
86             } else {
87                 return -1;
88             }
89         }
90         int j = 0;
91         for (int i = 0; i < bytes.length; i++) {
92             if (bytes[i] == sequence[j]) {
93                 j++;
94                 if (j == sequence.length) {
95                     return i - j + 1;
96                 }
97             } else {
98                 j = 0;
99             }
100         }
101         return -1;
102     }
103
104     private int getAdditionalHeaderEndIndex(byte[] bytes) {
105         for (byte[] possibleEnd : POSSIBLE_ENDS) {
106             int idx = findByteSequence(bytes, possibleEnd);
107
108             if (idx != -1) {
109                 return idx;
110             }
111         }
112
113         return -1;
114     }
115
116     private boolean startsWithAdditionalHeader(byte[] bytes) {
117         for (byte[] possibleStart : POSSIBLE_STARTS) {
118             int i = 0;
119             for (byte b : possibleStart) {
120                 if(bytes[i] != b)
121                     break;
122
123                 return true;
124             }
125         }
126
127         return false;
128     };
129
130     private void logMessage(byte[] bytes) {
131         String s = Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString();
132         logger.debug("Parsing message \n{}", s);
133     }
134
135     private String additionalHeaderToString(byte[] bytes) {
136         return Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString();
137     }
138
139     @Override
140     public byte[] put(NetconfMessage netconfMessage) {
141         if (clientId.isPresent()) {
142             Comment comment = netconfMessage.getDocument().createComment("clientId:" + clientId.get());
143             netconfMessage.getDocument().appendChild(comment);
144         }
145         ByteBuffer msgBytes;
146         if(netconfMessage.getAdditionalHeader().isPresent()) {
147             String header = netconfMessage.getAdditionalHeader().get();
148             logger.trace("Header of netconf message parsed \n{}", header);
149             msgBytes = Charsets.UTF_8.encode(header + xmlToString(netconfMessage.getDocument()));
150         } else {
151             msgBytes = Charsets.UTF_8.encode(xmlToString(netconfMessage.getDocument()));
152         }
153         String content = xmlToString(netconfMessage.getDocument());
154
155         logger.trace("Putting message \n{}", content);
156         byte[] b = new byte[msgBytes.limit()];
157         msgBytes.get(b);
158         return b;
159     }
160
161     private String xmlToString(Document doc) {
162         return XmlUtil.toString(doc, false);
163     }
164 }