blob: b5c7af01745d011a739705e4f9f1d1288c9d8f98 [file] [log] [blame]
Andreas Wundsam62cbcff2014-05-09 16:35:00 -07001package org.projectfloodlight.openflow.types;
2
3import java.util.Arrays;
4
5import org.jboss.netty.buffer.ChannelBuffer;
6import org.jboss.netty.buffer.ChannelBuffers;
7import org.projectfloodlight.openflow.exceptions.OFParseError;
8import org.projectfloodlight.openflow.protocol.OFErrorMsg;
9import org.projectfloodlight.openflow.protocol.OFFactories;
10import org.projectfloodlight.openflow.protocol.OFFactory;
11import org.projectfloodlight.openflow.protocol.OFMessage;
12import org.projectfloodlight.openflow.protocol.OFVersion;
13import org.projectfloodlight.openflow.protocol.Writeable;
14import org.projectfloodlight.openflow.util.ChannelUtils;
15import org.slf4j.Logger;
16import org.slf4j.LoggerFactory;
17
18import com.google.common.base.Optional;
19import com.google.common.hash.PrimitiveSink;
20
21/** A special-purpose wrapper for the 'data' field in an {@link OFErrorMsg} message
22 * that contains a byte serialization of the offending message.
23 *
24 * This attempts to parse the offending message on demand, and if successful
25 * will present the parsed message.
26 *
27 * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
28 */
29public class OFErrorCauseData implements Writeable, PrimitiveSinkable {
30 private static final Logger logger =
31 LoggerFactory.getLogger(OFErrorCauseData.class);
32
33 private final byte[] data;
34 private final OFVersion version;
35
36 private OFErrorCauseData(byte[] data, OFVersion version) {
37 this.data = data;
38 this.version = version;
39 }
40
41 public static OFErrorCauseData of(byte[] data, OFVersion version) {
42 return new OFErrorCauseData(Arrays.copyOf(data, data.length), version);
43 }
44
45 public byte[] getData() {
46 return Arrays.copyOf(data, data.length);
47 }
48
49 public Optional<OFMessage> getParsedMessage() {
50 OFFactory factory = OFFactories.getFactory(version);
51 try {
52 OFMessage msg = factory.getReader().readFrom(ChannelBuffers.wrappedBuffer(data));
53 if(msg != null)
54 return Optional.of(msg);
55 else
56 return Optional.absent();
57 } catch (OFParseError e) {
58 logger.debug("Error parsing error cause data as OFMessage: {}", e.getMessage(), e);
59 return Optional.absent();
60 }
61 }
62
63 public static OFErrorCauseData read(ChannelBuffer bb, int length, OFVersion version) {
64 byte[] bytes = ChannelUtils.readBytes(bb, length);
65 return of(bytes, version);
66 }
67
68 @Override
69 public void putTo(PrimitiveSink sink) {
70 sink.putBytes(data);
71 }
72
73 @Override
74 public void writeTo(ChannelBuffer bb) {
75 bb.writeBytes(data);
76 }
77
78 @Override
79 public String toString() {
80 Optional<OFMessage> parsedMessage = getParsedMessage();
81 if(parsedMessage.isPresent()) {
82 return String.valueOf(parsedMessage.get());
83 } else {
84 StringBuilder b = new StringBuilder();
85 b.append("[unparsed: ");
86 for(int i=0; i<data.length; i++) {
87 if(i>0)
88 b.append(" ");
89 b.append(String.format("%02x", data[i]));
90 }
91 b.append("]");
92 return b.toString();
93 }
94 }
95
96 @Override
97 public int hashCode() {
98 final int prime = 31;
99 int result = 1;
100 result = prime * result + Arrays.hashCode(data);
101 result = prime * result + ((version == null) ? 0 : version.hashCode());
102 return result;
103 }
104
105 @Override
106 public boolean equals(Object obj) {
107 if (this == obj)
108 return true;
109 if (obj == null)
110 return false;
111 if (getClass() != obj.getClass())
112 return false;
113 OFErrorCauseData other = (OFErrorCauseData) obj;
114 if (!Arrays.equals(data, other.data))
115 return false;
116 if (version != other.version)
117 return false;
118 return true;
119 }
120
121}