blob: 824b809951901bc671e26bc8d927acb91ac86caa [file] [log] [blame]
alshabib1f44e8e2014-08-14 15:19:57 -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 /** A default 'empty' cause. Note: the OFVersion OF_13 passed in here is irrelevant,
34 * because parsing of the 0-byte array will always return null, irrespective of the
35 * version.
36 */
37 public static final OFErrorCauseData NONE = new OFErrorCauseData(new byte[0], OFVersion.OF_13);
38
39 private final byte[] data;
40 private final OFVersion version;
41
42 private OFErrorCauseData(byte[] data, OFVersion version) {
43 this.data = data;
44 this.version = version;
45 }
46
47 public static OFErrorCauseData of(byte[] data, OFVersion version) {
48 return new OFErrorCauseData(Arrays.copyOf(data, data.length), version);
49 }
50
51 public byte[] getData() {
52 return Arrays.copyOf(data, data.length);
53 }
54
55 public Optional<OFMessage> getParsedMessage() {
56 OFFactory factory = OFFactories.getFactory(version);
57 try {
58 OFMessage msg = factory.getReader().readFrom(ChannelBuffers.wrappedBuffer(data));
59 if(msg != null)
60 return Optional.of(msg);
61 else
62 return Optional.absent();
63 } catch (OFParseError e) {
64 logger.debug("Error parsing error cause data as OFMessage: {}", e.getMessage(), e);
65 return Optional.absent();
66 }
67 }
68
69 public static OFErrorCauseData read(ChannelBuffer bb, int length, OFVersion version) {
70 byte[] bytes = ChannelUtils.readBytes(bb, length);
71 return of(bytes, version);
72 }
73
74 @Override
75 public void putTo(PrimitiveSink sink) {
76 sink.putBytes(data);
77 }
78
79 @Override
80 public void writeTo(ChannelBuffer bb) {
81 bb.writeBytes(data);
82 }
83
84 @Override
85 public String toString() {
86 Optional<OFMessage> parsedMessage = getParsedMessage();
87 if(parsedMessage.isPresent()) {
88 return String.valueOf(parsedMessage.get());
89 } else {
90 StringBuilder b = new StringBuilder();
91 b.append("[unparsed: ");
92 for(int i=0; i<data.length; i++) {
93 if(i>0)
94 b.append(" ");
95 b.append(String.format("%02x", data[i]));
96 }
97 b.append("]");
98 return b.toString();
99 }
100 }
101
102 @Override
103 public int hashCode() {
104 final int prime = 31;
105 int result = 1;
106 result = prime * result + Arrays.hashCode(data);
107 result = prime * result + ((version == null) ? 0 : version.hashCode());
108 return result;
109 }
110
111 @Override
112 public boolean equals(Object obj) {
113 if (this == obj)
114 return true;
115 if (obj == null)
116 return false;
117 if (getClass() != obj.getClass())
118 return false;
119 OFErrorCauseData other = (OFErrorCauseData) obj;
120 if (!Arrays.equals(data, other.data))
121 return false;
122 if (version != other.version)
123 return false;
124 return true;
125 }
126
127}