KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > net > protocol > AbstractTCNetworkMessage


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;
5
6 import com.tc.bytes.TCByteBuffer;
7 import com.tc.exception.TCInternalError;
8 import com.tc.logging.TCLogger;
9 import com.tc.logging.TCLogging;
10 import com.tc.util.Assert;
11 import com.tc.util.StringUtil;
12 import com.tc.util.concurrent.SetOnceFlag;
13
14 /**
15  * Base class for network messages
16  *
17  * @author teck
18  */

19 public class AbstractTCNetworkMessage implements TCNetworkMessage {
20   protected static final TCLogger logger = TCLogging.getLogger(TCNetworkMessage.class);
21
22   protected AbstractTCNetworkMessage(TCNetworkHeader header) {
23     this(header, null, null, false);
24   }
25
26   protected AbstractTCNetworkMessage(TCNetworkHeader header, TCNetworkMessage msgPayload) {
27     this(header, msgPayload, null, true);
28   }
29
30   protected AbstractTCNetworkMessage(TCNetworkHeader header, TCByteBuffer[] payload) {
31     this(header, null, payload, true);
32   }
33
34   private AbstractTCNetworkMessage(TCNetworkHeader header, TCNetworkMessage msgPayload, TCByteBuffer[] payload,
35                                    boolean seal) {
36     Assert.eval(header != null);
37
38     this.header = header;
39     this.messagePayload = msgPayload;
40     this.payloadData = (payload == null) ? EMPTY_BUFFER_ARRAY : payload;
41
42     if (msgPayload != null) {
43       payloadData = msgPayload.getEntireMessageData();
44     }
45
46     if (seal) {
47       seal();
48     }
49   }
50
51   public final int getDataLength() {
52     checkSealed();
53     return dataLength;
54   }
55
56   public final int getHeaderLength() {
57     checkSealed();
58     return headerLength;
59   }
60
61   public final int getTotalLength() {
62     checkSealed();
63     return totalLength;
64   }
65
66   public final TCNetworkHeader getHeader() {
67     checkNotRecycled();
68     return header;
69   }
70
71   public final TCNetworkMessage getMessagePayload() {
72     checkNotRecycled();
73     return messagePayload;
74   }
75
76   public final TCByteBuffer[] getPayload() {
77     checkNotRecycled();
78     return payloadData;
79   }
80
81   protected final void setPayload(TCByteBuffer[] newPayload) {
82     checkNotSealed();
83
84     entireMessageData = null;
85
86     if (newPayload == null) {
87       payloadData = EMPTY_BUFFER_ARRAY;
88     } else {
89       payloadData = newPayload;
90     }
91   }
92
93   protected final void setMessagePayload(TCNetworkMessage subMessage) {
94     checkNotSealed();
95
96     entireMessageData = null;
97
98     if (subMessage == null) {
99       payloadData = EMPTY_BUFFER_ARRAY;
100       this.messagePayload = null;
101     } else {
102       if (!subMessage.isSealed()) { throw new IllegalStateException JavaDoc("Message paylaod is not yet sealed"); }
103       this.messagePayload = subMessage;
104       this.payloadData = subMessage.getEntireMessageData();
105     }
106   }
107
108   public final TCByteBuffer[] getEntireMessageData() {
109     checkSealed();
110
111     // this array should have already been set in seal()
112
Assert.eval(entireMessageData != null);
113
114     return entireMessageData;
115   }
116
117   public final String JavaDoc toString() {
118     try {
119       return toString0();
120     } catch (Exception JavaDoc e) {
121       logger.warn("Exception in toString()", e);
122       return "EXCEPTION in toString(): " + e.getMessage();
123     }
124   }
125
126   protected final String JavaDoc toString0() {
127     StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
128     buf.append("Message Class: ").append(getClass().getName()).append("\n");
129     buf.append("Sealed: ").append(sealed.isSet()).append(", ");
130     buf.append("Header Length: ").append(getHeaderLength()).append(", ");
131     buf.append("Data Length: ").append(getDataLength()).append(", ");
132     buf.append("Total Length: ").append(getTotalLength()).append("\n");
133
134     String JavaDoc extraMsgInfo = describeMessage();
135     if (extraMsgInfo != null) {
136       buf.append(extraMsgInfo);
137     }
138
139     if (header != null) {
140       buf.append("Header (").append(header.getClass().getName()).append(")\n");
141       buf.append(StringUtil.indentLines(header.toString()));
142       if (buf.charAt(buf.length() - 1) != '\n') {
143         buf.append('\n');
144       }
145     }
146
147     buf.append("Payload:\n");
148     if (messagePayload != null) {
149       buf.append(StringUtil.indentLines(messagePayload.toString())).append("\n");
150     } else {
151       if (payloadData != null) {
152         buf.append(StringUtil.indentLines(describePayload()));
153       } else {
154         buf.append(StringUtil.indentLines("*** No payoad data ***\n"));
155       }
156     }
157
158     return buf.toString();
159   }
160
161   // override this method to add more information about your message
162
protected String JavaDoc describeMessage() {
163     return null;
164   }
165
166   // override this method to add more description to your payload data
167
protected String JavaDoc describePayload() {
168     StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
169
170     if ((payloadData != null) && (payloadData.length != 0)) {
171       for (int i = 0; i < payloadData.length; i++) {
172         if (payloadData[i] != null) {
173           //
174
}
175
176         buf.append("Buffer ").append(i).append(": ");
177
178         if (payloadData[i] != null) {
179           buf.append(payloadData[i].toString());
180         } else {
181           buf.append("null");
182         }
183
184         buf.append("\n");
185       }
186     } else {
187       buf.append("No payload buffers present");
188     }
189
190     return buf.toString();
191   }
192   
193   protected String JavaDoc dump() {
194     StringBuffer JavaDoc toRet = new StringBuffer JavaDoc(toString());
195     toRet.append("\n\n");
196     if(entireMessageData != null) {
197       for (int i = 0; i < entireMessageData.length; i++) {
198         toRet.append('[').append(i).append(']').append('=').append(entireMessageData[i].toString());
199         toRet.append(" = { ");
200           byte ba[] = entireMessageData[i].array();
201         for (int j = 0 ; j < ba.length; j++) {
202           toRet.append(Byte.toString(ba[j])).append(' ');
203         }
204         toRet.append(" } \n\n");
205       }
206     }
207     return toRet.toString();
208   }
209
210   public final boolean isSealed() {
211     return sealed.isSet();
212   }
213
214   public final void seal() {
215     if (sealed.attemptSet()) {
216       final int size = 1 + ((payloadData == null) ? 0 : payloadData.length);
217       entireMessageData = new TCByteBuffer[size];
218       entireMessageData[0] = header.getDataBuffer();
219       System.arraycopy(payloadData, 0, entireMessageData, 1, payloadData.length);
220
221       long dataLen = 0;
222       for (int i = 1; i < entireMessageData.length; i++) {
223         dataLen += entireMessageData[i].limit();
224       }
225
226       if (dataLen > Integer.MAX_VALUE) { throw new TCInternalError("Message too big"); }
227
228       this.dataLength = (int) dataLen;
229       this.headerLength = header.getHeaderByteLength();
230       this.totalLength = this.headerLength + this.dataLength;
231     } else {
232       throw new IllegalStateException JavaDoc("Message is sealed");
233     }
234   }
235
236   public final void wasSent() {
237     fireSentCallback();
238     doRecycleOnWrite();
239   }
240
241   // Can be overloaded by sub classes to decide when to recycle differently.
242
public void doRecycleOnWrite() {
243     recycle();
244   }
245
246   public void recycle() {
247     if (entireMessageData != null) {
248       int i = 0;
249       if (entireMessageData.length > 1 && entireMessageData[0].array() == entireMessageData[1].array()) {
250         // This is done as TCMessageParser creates a dupilcate of the first buffer for the header.
251
// @see TCMessageParser.parseMessage()
252
// Can be done more elegantly, but it is done like this keeping performance in mind.
253
i++;
254       }
255       for (; i < entireMessageData.length; i++) {
256         entireMessageData[i].recycle();
257       }
258       entireMessageData = null;
259     } else {
260       logger.warn("Entire Message is null ! Probably recycle was called twice !");
261       Thread.dumpStack();
262     }
263   }
264
265   protected boolean isRecycled() {
266     return isSealed() && entireMessageData == null;
267   }
268
269   private void fireSentCallback() {
270     if (sentCallback != null) {
271       if (sentCallbackFired.attemptSet()) {
272         try {
273           sentCallback.run();
274         } catch (Exception JavaDoc e) {
275           logger.error("Caught exception running sent callback", e);
276         }
277       }
278     }
279   }
280
281   public final void setSentCallback(Runnable JavaDoc callback) {
282     this.sentCallback = callback;
283   }
284
285   public final Runnable JavaDoc getSentCallback() {
286     return this.sentCallback;
287   }
288   
289   private void checkNotRecycled() {
290     if (isRecycled()) { throw new IllegalStateException JavaDoc("Message is already Recycled"); }
291   }
292
293   private void checkSealed() {
294     if (!isSealed()) { throw new IllegalStateException JavaDoc("Message is not sealed"); }
295   }
296
297   private void checkNotSealed() {
298     if (sealed.isSet()) { throw new IllegalStateException JavaDoc("Message is sealed"); }
299   }
300
301   private final SetOnceFlag sealed = new SetOnceFlag();
302   private final SetOnceFlag sentCallbackFired = new SetOnceFlag();
303   private static final TCByteBuffer[] EMPTY_BUFFER_ARRAY = {};
304   private final TCNetworkHeader header;
305   private TCByteBuffer[] payloadData;
306   private TCNetworkMessage messagePayload;
307   private TCByteBuffer[] entireMessageData;
308   private int totalLength;
309   private int dataLength;
310   private int headerLength;
311   private Runnable JavaDoc sentCallback = null;
312
313 }
Popular Tags