KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > net > protocol > delivery > OOOProtocolMessageHeader


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
3  */

4 package com.tc.net.protocol.delivery;
5
6 import com.tc.bytes.TCByteBuffer;
7 import com.tc.net.protocol.AbstractTCNetworkHeader;
8 import com.tc.net.protocol.TCProtocolException;
9
10 /**
11  * Header for once and only once protocol messages.
12  */

13 class OOOProtocolMessageHeader extends AbstractTCNetworkHeader {
14
15   private static final short TYPE_ACK_REQUEST = 1;
16   private static final short TYPE_ACK = 2;
17   private static final short TYPE_SEND = 3;
18
19   private static final short VERSION = 1;
20
21   private static final int MAGIC_NUM = 0xBBBBBBBB;
22   private static final int MAGIC_NUM_OFFSET = 0;
23   private static final int MAGIC_NUM_LENGTH = 4;
24
25   private static final int VERSION_OFFSET = MAGIC_NUM_OFFSET + MAGIC_NUM_LENGTH;
26   private static final int VERSION_LENGTH = 1;
27
28   private static final int TYPE_OFFSET = VERSION_OFFSET + VERSION_LENGTH;
29   private static final int TYPE_LENGTH = 1;
30
31   private static final int SEQUENCE_OFFSET = TYPE_OFFSET + TYPE_LENGTH;
32   private static final int SEQUENCE_LENGTH = 8;
33
34   static final int HEADER_LENGTH;
35
36   static {
37     int tmp = MAGIC_NUM_LENGTH + VERSION_LENGTH + TYPE_LENGTH + SEQUENCE_LENGTH;
38     // This padding is here to ensure that the header is a multiple of four bytes.
39
HEADER_LENGTH = tmp + (tmp % 4);
40   }
41
42   private OOOProtocolMessageHeader(short version, short type, long sequence) {
43     super(HEADER_LENGTH, HEADER_LENGTH);
44     putValues(version, type, sequence);
45     try {
46       validate();
47     } catch (TCProtocolException e) {
48       throw new InternalError JavaDoc();
49     }
50   }
51
52   private OOOProtocolMessageHeader(TCByteBuffer buffer) {
53     super(buffer, HEADER_LENGTH, HEADER_LENGTH);
54   }
55
56   public int getHeaderByteLength() {
57     return HEADER_LENGTH;
58   }
59
60   private void putValues(short version, short type, long sequence) {
61     data.putInt(MAGIC_NUM_OFFSET, MAGIC_NUM);
62     data.putUbyte(VERSION_OFFSET, version);
63     data.putUbyte(TYPE_OFFSET, type);
64     data.putLong(SEQUENCE_OFFSET, sequence);
65   }
66
67   protected void setHeaderLength(short headerLength) {
68     throw new UnsupportedOperationException JavaDoc("These messages are fixed length.");
69   }
70
71   public void validate() throws TCProtocolException {
72     int magic = getMagicNumber();
73     if (magic != MAGIC_NUM) {
74       throw new TCProtocolException("Bad magic number: " + magic + " != " + MAGIC_NUM);
75     }
76
77     short version = getVersion();
78     if (getVersion() != VERSION) { throw new TCProtocolException("Reported version " + version
79                                                                  + " is not equal to supported version: " + VERSION); }
80     short type = getType();
81     if (!isValidType(type)) { throw new TCProtocolException("Unknown message type: " + type); }
82
83     final boolean ack = isAck();
84     final boolean ackReq = isAckRequest();
85     final boolean send = isSend();
86
87     if (ack && (ackReq || send)) { throw new TCProtocolException("Invalid type, ack= " + ack + ", ackRe=" + ackReq
88                                                                  + ", send=" + send); }
89   }
90
91   public String JavaDoc toString() {
92     StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
93     
94     buf.append("valid: ");
95     try {
96       validate();
97       buf.append("true");
98     } catch (TCProtocolException e) {
99       buf.append("false (").append(e.getMessage()).append(")");
100     }
101     buf.append(", ");
102
103     buf.append("type: ");
104     if (isAck()) {
105       buf.append("ACK ").append(getSequence());
106     } else if (isAckRequest()) {
107       buf.append("ACK REQ");
108     } else if (isSend()) {
109       buf.append("SEND " + getSequence());
110     } else {
111       buf.append("UNKNOWN");
112     }
113     buf.append('\n');
114
115     return buf.toString();
116   }
117
118   private int getMagicNumber() {
119     return data.getInt(MAGIC_NUM_OFFSET);
120   }
121
122   private short getVersion() {
123     return data.getUbyte(VERSION_OFFSET);
124   }
125
126   private short getType() {
127     return data.getUbyte(TYPE_OFFSET);
128   }
129
130   private boolean isValidType(short type) {
131     return type == TYPE_SEND || type == TYPE_ACK_REQUEST || type == TYPE_ACK;
132   }
133
134   long getSequence() {
135     return data.getLong(SEQUENCE_OFFSET);
136   }
137
138   boolean isAckRequest() {
139     return getType() == TYPE_ACK_REQUEST;
140   }
141
142   boolean isAck() {
143     return getType() == TYPE_ACK;
144   }
145
146   boolean isSend() {
147     return getType() == TYPE_SEND;
148   }
149
150   static class ProtocolMessageHeaderFactory {
151     /**
152      * Use to create new headers for sending ack request messages.
153      */

154     OOOProtocolMessageHeader createNewAckRequest() {
155       return new OOOProtocolMessageHeader(VERSION, TYPE_ACK_REQUEST, 0);
156     }
157
158     /**
159      * Use to create new headers for sending ack messages.
160      */

161     OOOProtocolMessageHeader createNewAck(long sequence) {
162       return new OOOProtocolMessageHeader(VERSION, TYPE_ACK, sequence);
163     }
164
165     /**
166      * Use to create new headers for sending wrapped messages.
167      */

168     OOOProtocolMessageHeader createNewSend(long sequence) {
169       return new OOOProtocolMessageHeader(VERSION, TYPE_SEND, sequence);
170     }
171
172     /**
173      * Use with buffers read off of the network.
174      */

175     OOOProtocolMessageHeader createNewHeader(TCByteBuffer buffer) {
176       return new OOOProtocolMessageHeader(buffer.duplicate().limit(OOOProtocolMessageHeader.HEADER_LENGTH));
177     }
178   }
179 }
Popular Tags