1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package net.sf.beep4j.internal;
17
18 import java.nio.ByteBuffer;
19 import java.nio.charset.Charset;
20
21 import net.sf.beep4j.ProtocolException;
22 import net.sf.beep4j.internal.util.Assert;
23 import net.sf.beep4j.internal.util.ByteUtil;
24
25
26
27
28
29
30 public class DataHeader {
31
32 private static final String EOL = "\r\n";
33
34 private static final char FINAL = '.';
35
36 private static final char INTERMEDIATE = '*';
37
38 private static final String SPACE = " ";
39
40 private static final Charset charset = Charset.forName("US-ASCII");
41
42
43
44
45 protected MessageType type;
46
47
48
49
50 protected int payloadSize;
51
52
53
54
55 protected int channel;
56
57
58
59
60 protected int messageNumber;
61
62
63
64
65 protected boolean intermediate;
66
67
68
69
70 protected long sequenceNumber;
71
72
73
74
75
76
77
78
79
80
81
82 public DataHeader(MessageType type, int channel, int messageNumber, boolean intermediate, long sequenceNumber, int size) {
83 Assert.notNull("type", type);
84 this.type = type;
85 this.channel = channel;
86 this.messageNumber = messageNumber;
87 this.intermediate = intermediate;
88 this.sequenceNumber = sequenceNumber;
89 this.payloadSize = size;
90 }
91
92
93
94
95
96
97
98 public static final DataHeader parseHeader(String[] tokens) {
99 if (tokens.length == 0) {
100 throw new ProtocolException("header has 0 tokens");
101 }
102
103 MessageType type = parseMessageType(tokens[0]);
104
105 if (type == MessageType.ANS && tokens.length != 7) {
106 throw new ProtocolException("expecting 7 tokens in ANS header, was " + tokens.length);
107 } else if (type != MessageType.ANS && tokens.length != 6) {
108 throw new ProtocolException("expecting 6 tokens in header, was " + tokens.length);
109 }
110
111 int channel = ByteUtil.parseUnsignedInt("channel number", tokens[1]);
112 int messageNumber = ByteUtil.parseUnsignedInt("message number", tokens[2]);
113 boolean intermediate = parseIntermediate(tokens[3]);
114 long sequenceNumber = ByteUtil.parseUnsignedLong("sequence number", tokens[4]);
115 int payloadSize = ByteUtil.parseUnsignedInt("size", tokens[5]);
116
117 if (MessageType.ANS == type) {
118 int answerNumber = ByteUtil.parseUnsignedInt("answer number", tokens[6]);
119 return new ANSHeader(channel, messageNumber, intermediate, sequenceNumber, payloadSize, answerNumber);
120 } else {
121 return new DataHeader(type, channel, messageNumber, intermediate, sequenceNumber, payloadSize);
122 }
123 }
124
125 private static MessageType parseMessageType(String s) {
126 try {
127 return MessageType.valueOf(s);
128 } catch (IllegalArgumentException e) {
129 throw new ProtocolException("'" + s + "' is an invalid message type");
130 }
131 }
132
133 private static boolean parseIntermediate(String s) {
134 if ("*".equals(s)) {
135 return true;
136 } else if (".".equals(s)) {
137 return false;
138 } else {
139 throw new ProtocolException("'" + s + "' is an invalid intermediate indicator");
140 }
141 }
142
143 public MessageType getType() {
144 return type;
145 }
146
147 public int getChannel() {
148 return channel;
149 }
150
151 public int getMessageNumber() {
152 return messageNumber;
153 }
154
155 public boolean isIntermediate() {
156 return intermediate;
157 }
158
159 public int getPayloadSize() {
160 return payloadSize;
161 }
162
163 public long getSequenceNumber() {
164 return sequenceNumber;
165 }
166
167
168
169
170
171
172
173
174
175
176 public DataHeader[] split(int size) {
177 MessageType type = getType();
178
179 DataHeader[] result = new DataHeader[2];
180 result[0] = new DataHeader(type, channel, messageNumber, true, sequenceNumber, size);
181 result[1] = new DataHeader(type, channel, messageNumber, false, sequenceNumber + size, payloadSize - size);
182
183 return result;
184 }
185
186
187
188
189
190
191 public ByteBuffer asByteBuffer() {
192 StringBuilder builder = new StringBuilder(type.name());
193
194 builder.append(SPACE);
195 builder.append(channel);
196 builder.append(SPACE);
197 builder.append(messageNumber);
198 builder.append(SPACE);
199 builder.append(intermediate ? INTERMEDIATE : FINAL);
200 builder.append(SPACE);
201 builder.append(sequenceNumber);
202 builder.append(SPACE);
203 builder.append(payloadSize);
204 builder.append(EOL);
205
206 return charset.encode(builder.toString());
207 }
208
209 @Override
210 public boolean equals(Object obj) {
211 if (this == obj) {
212 return true;
213 } else if (obj == null) {
214 return false;
215 } else if (getClass() == obj.getClass()) {
216 DataHeader header = (DataHeader) obj;
217 return type == header.type
218 && channel == header.channel
219 && messageNumber == header.messageNumber
220 && intermediate == header.intermediate
221 && sequenceNumber == header.sequenceNumber
222 && payloadSize == header.payloadSize;
223 } else {
224 return false;
225 }
226 }
227
228 @Override
229 public int hashCode() {
230 int result = 17;
231 result = result * 23 + type.hashCode();
232 result = result * 23 + channel;
233 result = result * 23 + messageNumber;
234 result = result * 23 + (intermediate ? 1 : 0);
235 result = result * 23 + payloadSize;
236 result = result * 23 + new Long(sequenceNumber).hashCode();
237 return result;
238 }
239
240 @Override
241 public String toString() {
242 return type.name() + " "
243 + channel + " "
244 + messageNumber + " "
245 + (intermediate ? "*" : ".") + " "
246 + sequenceNumber + " "
247 + payloadSize;
248 }
249
250
251
252
253
254
255
256 public static class ANSHeader extends DataHeader {
257
258 private final int answerNumber;
259
260 public ANSHeader(int channel, int messageNumber, boolean intermediate, long sequenceNumber, int payloadSize, int answerNumber) {
261 super(MessageType.ANS, channel, messageNumber, intermediate, sequenceNumber, payloadSize);
262 this.answerNumber = answerNumber;
263 }
264
265 public int getAnswerNumber() {
266 return answerNumber;
267 }
268
269 @Override
270 public DataHeader[] split(int size) {
271 DataHeader[] result = new DataHeader[2];
272 result[0] = new ANSHeader(channel, messageNumber, true, sequenceNumber, size, answerNumber);
273 result[1] = new ANSHeader(channel, messageNumber, false, sequenceNumber + size, payloadSize - size, answerNumber);
274 return result;
275 }
276
277 @Override
278 public ByteBuffer asByteBuffer() {
279 StringBuilder builder = new StringBuilder();
280
281 builder.append(type.name());
282 builder.append(SPACE);
283 builder.append(channel);
284 builder.append(SPACE);
285 builder.append(messageNumber);
286 builder.append(SPACE);
287 builder.append(intermediate ? INTERMEDIATE : FINAL);
288 builder.append(SPACE);
289 builder.append(sequenceNumber);
290 builder.append(SPACE);
291 builder.append(payloadSize);
292 builder.append(SPACE);
293 builder.append(answerNumber);
294 builder.append(EOL);
295
296 return charset.encode(builder.toString());
297 }
298
299 @Override
300 public boolean equals(Object obj) {
301 if (!super.equals(obj)) {
302 return false;
303 } else if (obj.getClass().equals(obj)) {
304 ANSHeader header = (ANSHeader) obj;
305 return answerNumber == header.answerNumber;
306 } else {
307 return false;
308 }
309 }
310
311 @Override
312 public int hashCode() {
313 int result = super.hashCode();
314 result = result * 23 + answerNumber;
315 return result;
316 }
317
318 @Override
319 public String toString() {
320 return super.toString() + " " + answerNumber;
321 }
322
323 }
324
325 }