KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > coyote > ajp > AjpMessage


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 package org.apache.coyote.ajp;
19
20 import org.apache.tomcat.util.buf.ByteChunk;
21 import org.apache.tomcat.util.buf.CharChunk;
22 import org.apache.tomcat.util.buf.MessageBytes;
23 import org.apache.tomcat.util.res.StringManager;
24
25 /**
26  * A single packet for communication between the web server and the
27  * container. Designed to be reused many times with no creation of
28  * garbage. Understands the format of data types for these packets.
29  * Can be used (somewhat confusingly) for both incoming and outgoing
30  * packets.
31  *
32  * @author Henri Gomez
33  * @author Dan Milstein
34  * @author Keith Wannamaker
35  * @author Kevin Seguin
36  * @author Costin Manolache
37  */

38 public class AjpMessage {
39
40
41     protected static org.apache.commons.logging.Log log =
42         org.apache.commons.logging.LogFactory.getLog(AjpMessage.class);
43
44     /**
45      * The string manager for this package.
46      */

47     protected static StringManager sm =
48         StringManager.getManager(Constants.Package);
49
50
51     // ------------------------------------------------------------ Constructor
52

53     
54     public AjpMessage(int packetSize) {
55         buf = new byte[packetSize];
56     }
57     
58
59     // ----------------------------------------------------- Instance Variables
60

61
62     /**
63      * Fixed size buffer.
64      */

65     protected byte buf[] = null;
66
67
68     /**
69      * The current read or write position in the buffer.
70      */

71     protected int pos;
72
73
74     /**
75      * This actually means different things depending on whether the
76      * packet is read or write. For read, it's the length of the
77      * payload (excluding the header). For write, it's the length of
78      * the packet as a whole (counting the header). Oh, well.
79      */

80     protected int len;
81
82     
83     // --------------------------------------------------------- Public Methods
84

85
86     /**
87      * Prepare this packet for accumulating a message from the container to
88      * the web server. Set the write position to just after the header
89      * (but leave the length unwritten, because it is as yet unknown).
90      */

91     public void reset() {
92         len = 4;
93         pos = 4;
94     }
95
96
97     /**
98      * For a packet to be sent to the web server, finish the process of
99      * accumulating data and write the length of the data payload into
100      * the header.
101      */

102     public void end() {
103         len = pos;
104         int dLen = len - 4;
105
106         buf[0] = (byte) 0x41;
107         buf[1] = (byte) 0x42;
108         buf[2] = (byte) ((dLen>>>8) & 0xFF);
109         buf[3] = (byte) (dLen & 0xFF);
110     }
111
112
113     /**
114      * Return the underlying byte buffer.
115      */

116     public byte[] getBuffer() {
117         return buf;
118     }
119
120
121     /**
122      * Return the current message length. For read, it's the length of the
123      * payload (excluding the header). For write, it's the length of
124      * the packet as a whole (counting the header).
125      */

126     public int getLen() {
127         return len;
128     }
129     
130
131     /**
132      * Add a short integer (2 bytes) to the message.
133      */

134     public void appendInt(int val) {
135         buf[pos++] = (byte) ((val >>> 8) & 0xFF);
136         buf[pos++] = (byte) (val & 0xFF);
137     }
138
139
140     /**
141      * Append a byte (1 byte) to the message.
142      */

143     public void appendByte(int val) {
144         buf[pos++] = (byte) val;
145     }
146     
147     
148     /**
149      * Append an int (4 bytes) to the message.
150      */

151     public void appendLongInt(int val) {
152         buf[pos++] = (byte) ((val >>> 24) & 0xFF);
153         buf[pos++] = (byte) ((val >>> 16) & 0xFF);
154         buf[pos++] = (byte) ((val >>> 8) & 0xFF);
155         buf[pos++] = (byte) (val & 0xFF);
156     }
157
158     
159     /**
160      * Write a MessageBytes out at the current write position.
161      * A null MessageBytes is encoded as a string with length 0.
162      */

163     public void appendBytes(MessageBytes mb) {
164         if (mb == null) {
165             log.error(sm.getString("ajpmessage.null"),
166                     new NullPointerException JavaDoc());
167             appendInt(0);
168             appendByte(0);
169             return;
170         }
171         if (mb.getType() == MessageBytes.T_BYTES) {
172             ByteChunk bc = mb.getByteChunk();
173             appendByteChunk(bc);
174         } else if (mb.getType() == MessageBytes.T_CHARS) {
175             CharChunk cc = mb.getCharChunk();
176             appendCharChunk(cc);
177         } else {
178             appendString(mb.toString());
179         }
180     }
181
182     
183     /**
184      * Write a ByteChunk out at the current write position.
185      * A null ByteChunk is encoded as a string with length 0.
186      */

187     public void appendByteChunk(ByteChunk bc) {
188         if (bc == null) {
189             log.error(sm.getString("ajpmessage.null"),
190                     new NullPointerException JavaDoc());
191             appendInt(0);
192             appendByte(0);
193             return;
194         }
195         appendBytes(bc.getBytes(), bc.getStart(), bc.getLength());
196     }
197
198     
199     /**
200      * Write a CharChunk out at the current write position.
201      * A null CharChunk is encoded as a string with length 0.
202      */

203     public void appendCharChunk(CharChunk cc) {
204         if (cc == null) {
205             log.error(sm.getString("ajpmessage.null"),
206                     new NullPointerException JavaDoc());
207             appendInt(0);
208             appendByte(0);
209             return;
210         }
211         int start = cc.getStart();
212         int end = cc.getEnd();
213         appendInt(end - start);
214         char[] cbuf = cc.getBuffer();
215         for (int i = start; i < end; i++) {
216             char c = cbuf[i];
217             // Note: This is clearly incorrect for many strings,
218
// but is the only consistent approach within the current
219
// servlet framework. It must suffice until servlet output
220
// streams properly encode their output.
221
if ((c <= 31) && (c != 9)) {
222                 c = ' ';
223             } else if (c == 127) {
224                 c = ' ';
225             }
226             appendByte(c);
227         }
228         appendByte(0);
229     }
230
231     
232     /**
233      * Write a String out at the current write position. Strings are
234      * encoded with the length in two bytes first, then the string, and
235      * then a terminating \0 (which is <B>not</B> included in the
236      * encoded length). The terminator is for the convenience of the C
237      * code, where it saves a round of copying. A null string is
238      * encoded as a string with length 0.
239      */

240     public void appendString(String JavaDoc str) {
241         if (str == null) {
242             log.error(sm.getString("ajpmessage.null"),
243                     new NullPointerException JavaDoc());
244             appendInt(0);
245             appendByte(0);
246             return;
247         }
248         int len = str.length();
249         appendInt(len);
250         for (int i = 0; i < len; i++) {
251             char c = str.charAt (i);
252             // Note: This is clearly incorrect for many strings,
253
// but is the only consistent approach within the current
254
// servlet framework. It must suffice until servlet output
255
// streams properly encode their output.
256
if ((c <= 31) && (c != 9)) {
257                 c = ' ';
258             } else if (c == 127) {
259                 c = ' ';
260             }
261             appendByte(c);
262         }
263         appendByte(0);
264     }
265
266     
267     /**
268      * Copy a chunk of bytes into the packet, starting at the current
269      * write position. The chunk of bytes is encoded with the length
270      * in two bytes first, then the data itself, and finally a
271      * terminating \0 (which is <B>not</B> included in the encoded
272      * length).
273      *
274      * @param b The array from which to copy bytes.
275      * @param off The offset into the array at which to start copying
276      * @param numBytes The number of bytes to copy.
277      */

278     public void appendBytes(byte[] b, int off, int numBytes) {
279         if (pos + numBytes + 3 > buf.length) {
280             log.error(sm.getString("ajpmessage.overflow", "" + numBytes, "" + pos),
281                     new ArrayIndexOutOfBoundsException JavaDoc());
282             if (log.isDebugEnabled()) {
283                 dump("Overflow/coBytes");
284             }
285             return;
286         }
287         appendInt(numBytes);
288         System.arraycopy(b, off, buf, pos, numBytes);
289         pos += numBytes;
290         appendByte(0);
291     }
292
293     
294     /**
295      * Read an integer from packet, and advance the read position past
296      * it. Integers are encoded as two unsigned bytes with the
297      * high-order byte first, and, as far as I can tell, in
298      * little-endian order within each byte.
299      */

300     public int getInt() {
301         int b1 = buf[pos++] & 0xFF;
302         int b2 = buf[pos++] & 0xFF;
303         return (b1<<8) + b2;
304     }
305
306
307     public int peekInt() {
308         int b1 = buf[pos] & 0xFF;
309         int b2 = buf[pos+1] & 0xFF;
310         return (b1<<8) + b2;
311     }
312
313     
314     public byte getByte() {
315         byte res = buf[pos++];
316         return res;
317     }
318
319     
320     public byte peekByte() {
321         byte res = buf[pos];
322         return res;
323     }
324
325     
326     public void getBytes(MessageBytes mb) {
327         int length = getInt();
328         if ((length == 0xFFFF) || (length == -1)) {
329             mb.recycle();
330             return;
331         }
332         mb.setBytes(buf, pos, length);
333         pos += length;
334         pos++; // Skip the terminating \0
335
}
336     
337     
338     /**
339      * Copy a chunk of bytes from the packet into an array and advance
340      * the read position past the chunk. See appendBytes() for details
341      * on the encoding.
342      *
343      * @return The number of bytes copied.
344      */

345     public int getBytes(byte[] dest) {
346         int length = getInt();
347         if (pos + length > buf.length) {
348             log.error(sm.getString("ajpmessage.read", "" + length));
349             return 0;
350         }
351     
352         if ((length == 0xFFFF) || (length == -1)) {
353             return 0;
354         }
355
356         System.arraycopy(buf, pos, dest, 0, length);
357         pos += length;
358         pos++; // Skip terminating \0
359
return length;
360     }
361
362     
363     /**
364      * Read a 32 bits integer from packet, and advance the read position past
365      * it. Integers are encoded as four unsigned bytes with the
366      * high-order byte first, and, as far as I can tell, in
367      * little-endian order within each byte.
368      */

369     public int getLongInt() {
370         int b1 = buf[pos++] & 0xFF; // No swap, Java order
371
b1 <<= 8;
372         b1 |= (buf[pos++] & 0xFF);
373         b1 <<= 8;
374         b1 |= (buf[pos++] & 0xFF);
375         b1 <<=8;
376         b1 |= (buf[pos++] & 0xFF);
377         return b1;
378     }
379
380
381     public int getHeaderLength() {
382         return 4;
383     }
384
385     
386     public int getPacketSize() {
387         return buf.length;
388     }
389     
390     
391     public int processHeader() {
392         pos = 0;
393         int mark = getInt();
394         len = getInt();
395         // Verify message signature
396
if ((mark != 0x1234) && (mark != 0x4142)) {
397             log.error(sm.getString("ajpmessage.invalid", "" + mark));
398             if (log.isDebugEnabled()) {
399                 dump("In: ");
400             }
401             return -1;
402         }
403         if (log.isDebugEnabled()) {
404             log.debug("Received " + len + " " + buf[0]);
405         }
406         return len;
407     }
408     
409
410     /**
411      * Dump the contents of the message, prefixed with the given String.
412      */

413     public void dump(String JavaDoc msg) {
414         if (log.isDebugEnabled()) {
415             log.debug(msg + ": " + buf + " " + pos +"/" + (len + 4));
416         }
417         int max = pos;
418         if (len + 4 > pos)
419             max = len+4;
420         if (max > 1000)
421             max = 1000;
422         if (log.isDebugEnabled()) {
423             for (int j = 0; j < max; j += 16) {
424                 log.debug(hexLine(buf, j, len));
425             }
426         }
427     }
428
429
430     // ------------------------------------------------------ Protected Methods
431

432
433     protected static String JavaDoc hexLine(byte buf[], int start, int len) {
434         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
435         for (int i = start; i < start + 16 ; i++) {
436             if (i < len + 4) {
437                 sb.append(hex(buf[i]) + " ");
438             } else {
439                 sb.append(" ");
440             }
441         }
442         sb.append(" | ");
443         for (int i = start; i < start + 16 && i < len + 4; i++) {
444             if (!Character.isISOControl((char) buf[i])) {
445                 sb.append(new Character JavaDoc((char) buf[i]));
446             } else {
447                 sb.append(".");
448             }
449         }
450         return sb.toString();
451     }
452
453
454     protected static String JavaDoc hex(int x) {
455         String JavaDoc h = Integer.toHexString(x);
456         if (h.length() == 1) {
457             h = "0" + h;
458         }
459         return h.substring(h.length() - 2);
460     }
461
462
463 }
464
Popular Tags