KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mr > core > net > CNLMessage


1 /*
2  * Copyright 2002 by
3  * <a HREF="http://www.coridan.com">Coridan</a>
4  * <a HREF="mailto: support@coridan.com ">support@coridan.com</a>
5  *
6  * The contents of this file are subject to the Mozilla Public License Version
7  * 1.1 (the "License"); you may not use this file except in compliance with the
8  * License. You may obtain a copy of the License at
9  * http://www.mozilla.org/MPL/
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  *
16  * The Original Code is "MantaRay" (TM).
17  *
18  * The Initial Developer of the Original Code is Uri Schneider.
19  * Portions created by the Initial Developer are Copyright (C) 2006
20  * Coridan Inc. All Rights Reserved.
21  *
22  * Contributor(s): all the names of the contributors are added in the source
23  * code where applicable.
24  *
25  * Alternatively, the contents of this file may be used under the terms of the
26  * LGPL license (the "GNU LESSER GENERAL PUBLIC LICENSE"), in which case the
27  * provisions of LGPL are applicable instead of those above. If you wish to
28  * allow use of your version of this file only under the terms of the LGPL
29  * License and not to allow others to use your version of this file under
30  * the MPL, indicate your decision by deleting the provisions above and
31  * replace them with the notice and other provisions required by the LGPL.
32  * If you do not delete the provisions above, a recipient may use your version
33  * of this file under either the MPL or the GNU LESSER GENERAL PUBLIC LICENSE.
34  
35  *
36  * This library is free software; you can redistribute it and/or modify it
37  * under the terms of the MPL as stated above or under the terms of the GNU
38  * Lesser General Public License as published by the Free Software Foundation;
39  * either version 2.1 of the License, or any later version.
40  *
41  * This library is distributed in the hope that it will be useful, but WITHOUT
42  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
43  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
44  * License for more details.
45  */

46 package org.mr.core.net;
47
48 import java.net.SocketAddress JavaDoc;
49 import java.nio.ByteBuffer JavaDoc;
50 import java.security.MessageDigest JavaDoc;
51 import java.security.NoSuchAlgorithmException JavaDoc;
52
53 import org.mr.core.protocol.MantaBusMessage;
54 import org.mr.core.util.byteable.NetOutByteBufferPool;
55
56 /**
57  * CNLMessage.java
58  *
59  * A message object used by the network layer.<p> It can be used in
60  * both directions, incoming and outgoing. A CNL message is composed
61  * of a CNL header (type, id, length, and optionally an MD5
62  * signature), and of a payload, which resides in one or more byte
63  * buffers. It provides serializing and deserializing of the header
64  * into/from a byte buffer, and accessors for the header fields and
65  * the payload.
66  *
67  * Created: Sun Jan 25 14:03:01 2004
68  *
69  * @author Uri Schneider
70  * @version 1.0
71  */

72
73 public class CNLMessage {
74     public static final byte CNL_NETWORK = 0;
75     public static final byte CNL_MANTA = 1;
76     public static final byte CNL_MD5_MASK = 0x10;
77     public static final byte CNL_TYPE_MASK = 0x0F;
78     public static final int CNL_HEADERLEN = 25;
79
80     private byte type;
81     private int id;
82     private int length;
83     private byte[] md5;
84     private ByteBuffer JavaDoc[] buffers;
85     private ByteBuffer JavaDoc headerBuffer;
86     private int nUsers;
87     private MantaBusMessage busMessage;
88     private boolean isTCP;
89     private SocketAddress JavaDoc source;
90     private SocketAddress JavaDoc dest;
91     private String JavaDoc password;
92     private boolean sent;
93
94     /**
95      * Construct a message from a pre-allocated buffer.
96      * The buffer should contain a serialized message.
97      *
98      * @param type
99      * @param value
100      */

101     public CNLMessage(byte type, ByteBuffer JavaDoc[] buffers) {
102         this.type = type;
103         this.id = 0;
104         this.length = 0;
105         this.md5 = new byte[16];
106         for (int i = 0; i < buffers.length; i++) {
107             buffers[i].rewind();
108             this.length += buffers[i].remaining();
109         }
110         this.buffers = buffers;
111         this.nUsers = 0;
112         this.sent = false;
113     }
114
115     /**
116      * Default contructor.
117      */

118     public CNLMessage(boolean isTCP) {
119         this.type = -1;
120         this.id = 0;
121         this.length = 0;
122         this.md5 = new byte[16];
123         this.buffers = null;
124         this.nUsers = 0;
125         this.isTCP = isTCP;
126         this.sent = false;
127     }
128
129     /**
130      * Read the header portion of a CNL message from a buffer.
131      * @param buffer
132      */

133     public void readHeader(ByteBuffer JavaDoc buffer) {
134         this.type = buffer.get();
135         this.id = buffer.getInt();
136         this.length = buffer.getInt();
137         buffer.get(md5);
138     }
139
140     public void setBuffer(ByteBuffer JavaDoc buffer) {
141         this.buffers = new ByteBuffer JavaDoc[1];
142         this.buffers[0] = buffer;
143         this.busMessage = null;
144     }
145
146     public void setBusMessage(MantaBusMessage busMessage) {
147         this.busMessage = busMessage;
148     }
149
150     /**
151      * Get the Type value.
152      * @return the Type value.
153      */

154     public byte getType() {
155         return (byte) (type & CNL_TYPE_MASK);
156     }
157
158     /**
159      * Get the Length value.
160      * @return the Length value.
161      */

162     public int getLength() {
163         return length;
164     }
165
166     /**
167      * Get the message's total length
168      * @return total length
169      */

170     public int getTotalLength() {
171         return this.length + CNL_HEADERLEN;
172     }
173
174     /**
175      * Get the ID value
176      * @return the ID value
177      */

178     public int getID() {
179         return this.id;
180     }
181
182     public boolean isSigned() {
183         return (this.type & CNL_MD5_MASK) != 0;
184     }
185
186     /**
187      * get the MD5 signature that was sent in the message header, or
188      * null, if the message was not signed when sent
189      */

190     public byte[] getMessageMD5() {
191         if (isSigned()) {
192             return this.md5;
193         } else {
194             return null;
195         }
196     }
197
198     /**
199      * get a <code>MessageDigest</code> object, already updated with
200      * the message's contents, lacking only the password.
201      */

202     public MessageDigest JavaDoc getPartialMD5() {
203         return partialDigest();
204     }
205
206     /**
207      * Serialize this message's header into a newly allocated ByteBuffer.
208      * @return the buffer
209      */

210     public ByteBuffer JavaDoc headerAsBuffer(int id) {
211         if (this.headerBuffer == null) {
212             if (isSigned()) {
213                 this.id = id;
214                 this.md5 = realSignMessage(this.password);
215             }
216             this.headerBuffer =
217                 NetOutByteBufferPool.getInstance().getBuffer(CNL_HEADERLEN);
218             this.headerBuffer.limit(CNL_HEADERLEN);
219             this.headerBuffer.put(this.type);
220             this.headerBuffer.putInt(id);
221             this.headerBuffer.putInt(this.length);
222             this.headerBuffer.put(this.md5);
223             this.headerBuffer.flip();
224         }
225
226         return this.headerBuffer.duplicate();
227     }
228
229     public void headerToBuffer(ByteBuffer JavaDoc buf, int id) {
230         this.id = id;
231         if (isSigned()) {
232             this.md5 = realSignMessage(this.password);
233         }
234         buf.put(this.type);
235         buf.putInt(id);
236         buf.putInt(this.length);
237         buf.put(this.md5);
238         buf.flip();
239     }
240
241     /**
242      * Return a buffer containing the message's payload.
243      * @return the buffer
244      */

245     public ByteBuffer JavaDoc[] valueAsBuffers() {
246         ByteBuffer JavaDoc[] dups = new ByteBuffer JavaDoc[this.buffers.length];
247         for (int i = 0; i < dups.length; i++) {
248             dups[i] = this.buffers[i].duplicate();
249         }
250         return dups;
251     }
252
253     /**
254      * Return the message's own ByteBuffer object, containing a
255      * serialized message. DO NOT use this method to aquire the
256      * buffer for outgoing messages, as it is not thread-safe, and
257      * outgoing messages are shared between Transports.
258      *
259      * @Return a <code>ByteBuffer</code> value
260      */

261     public ByteBuffer JavaDoc[] buffers() {
262         return this.buffers;
263     }
264     
265     public synchronized void use() {
266         this.nUsers++;
267     }
268
269     public synchronized void unuse() {
270         this.nUsers--;
271         if (this.nUsers == 0) {
272             // release buffer
273
// ProtocolManager.getProtocolByteBufferPool().release(this.buffer);
274
if (this.headerBuffer != null) {
275                 NetOutByteBufferPool.getInstance().release(this.headerBuffer);
276             }
277             if (this.busMessage != null) {
278                 this.busMessage.release(wasSent());
279             }
280         } else if (this.nUsers < 0) {
281 // System.out.println("ERROR!! CALL THE POLICE!!");
282
// Thread.dumpStack();
283
}
284     }
285
286     /**
287      * set this message's source (for incoming messages)
288      *
289      * @param source
290      */

291     public void setSourceAddress(SocketAddress JavaDoc source) {
292         this.source = source;
293     }
294
295     /**
296      * set this message's destination (for incoming messages)
297      *
298      * @param local
299      */

300     public void setDestAddress(SocketAddress JavaDoc dest) {
301         this.dest = dest;
302     }
303
304     /**
305      * @return this message's source address (for incoming messages)
306      */

307     public SocketAddress JavaDoc getSourceAddress() {
308         return this.source;
309     }
310
311     /**
312      * @return this message's source address (for incoming messages)
313      */

314     public SocketAddress JavaDoc getDestAddress() {
315         return this.dest;
316     }
317
318     /**
319      * @return
320      */

321     public boolean isTCP() {
322         return this.isTCP;
323     }
324
325     public String JavaDoc toString() {
326         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
327         if (type == CNL_NETWORK) {
328             buf.append("NET: ");
329         } else if (type == CNL_MANTA) {
330             buf.append("APP: ");
331         } else {
332             buf.append((int)type).append(": ");
333         }
334         buf.append(id).append("/").append(length).append("b");
335         if (this.busMessage != null) {
336             buf.append(" ").append(this.busMessage.getMessageId());
337         }
338         return buf.toString();
339     }
340
341     public void signMessage(String JavaDoc password) {
342         this.password = password;
343         this.type = (byte) (this.type | CNL_MD5_MASK);
344     }
345
346     public void setSent() {
347         this.sent = true;
348     }
349
350     public boolean wasSent() {
351         return this.sent;
352     }
353
354     /* return a MessageDigest object containing a partial digest of
355      * the message - only the password is missing */

356     private MessageDigest JavaDoc partialDigest() {
357         MessageDigest JavaDoc digest;
358         try {
359             digest = MessageDigest.getInstance("MD5");
360         } catch (NoSuchAlgorithmException JavaDoc e) {
361             // won't happen. promise.
362
return null;
363         }
364         digest.update(type);
365         digest.update((byte)((id >>> 24) & 0xFF));
366         digest.update((byte)((id >>> 16) & 0xFF));
367         digest.update((byte)((id >>> 8) & 0xFF));
368         digest.update((byte)((id >>> 0) & 0xFF));
369         digest.update((byte)((length >>> 24) & 0xFF));
370         digest.update((byte)((length >>> 16) & 0xFF));
371         digest.update((byte)((length >>> 8) & 0xFF));
372         digest.update((byte)((length >>> 0) & 0xFF));
373         for (int i = 0; i < this.buffers.length; ++i) {
374             digest.update(this.buffers[i].array(), 0, buffers[i].limit());
375         }
376         return digest;
377     }
378
379     private byte[] realSignMessage(String JavaDoc password) {
380         MessageDigest JavaDoc digest = partialDigest();
381         digest.update(password.getBytes());
382         return digest.digest();
383     }
384 } // CNLMessage
385
Popular Tags