KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > hessian > micro > MicroHessianOutput


1 /*
2  * Copyright (c) 2001-2006 Caucho Technology, Inc. All rights reserved.
3  *
4  * The Apache Software License, Version 1.1
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in
15  * the documentation and/or other materials provided with the
16  * distribution.
17  *
18  * 3. The end-user documentation included with the redistribution, if
19  * any, must include the following acknowlegement:
20  * "This product includes software developed by the
21  * Caucho Technology (http://www.caucho.com/)."
22  * Alternately, this acknowlegement may appear in the software itself,
23  * if and wherever such third-party acknowlegements normally appear.
24  *
25  * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
26  * endorse or promote products derived from this software without prior
27  * written permission. For written permission, please contact
28  * info@caucho.com.
29  *
30  * 5. Products derived from this software may not be called "Resin"
31  * nor may "Resin" appear in their names without prior written
32  * permission of Caucho Technology.
33  *
34  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
35  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
36  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
37  * DISCLAIMED. IN NO EVENT SHALL CAUCHO TECHNOLOGY OR ITS CONTRIBUTORS
38  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
39  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
40  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
41  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
42  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
43  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
44  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45  *
46  * @author Scott Ferguson
47  */

48
49 package com.caucho.hessian.micro;
50
51 import java.io.IOException JavaDoc;
52 import java.io.OutputStream JavaDoc;
53 import java.util.Date JavaDoc;
54 import java.util.Enumeration JavaDoc;
55 import java.util.Hashtable JavaDoc;
56 import java.util.Vector JavaDoc;
57
58 /**
59  * Output stream for Hessian requests, compatible with microedition
60  * Java. It only uses classes and types available to J2ME. In
61  * particular, it does not have any support for the <double> type.
62  *
63  * <p>MicroHessianOutput does not depend on any classes other than
64  * in J2ME, so it can be extracted independently into a smaller package.
65  *
66  * <p>MicroHessianOutput is unbuffered, so any client needs to provide
67  * its own buffering.
68  *
69  * <pre>
70  * OutputStream os = ...; // from http connection
71  * MicroHessianOutput out = new MicroHessianOutput(os);
72  * String value;
73  *
74  * out.startCall("hello"); // start hello call
75  * out.writeString("arg1"); // write a string argument
76  * out.completeCall(); // complete the call
77  * </pre>
78  */

79 public class MicroHessianOutput {
80   protected OutputStream JavaDoc os;
81
82   /**
83    * Creates a new Hessian output stream, initialized with an
84    * underlying output stream.
85    *
86    * @param os the underlying output stream.
87    */

88   public MicroHessianOutput(OutputStream JavaDoc os)
89   {
90     init(os);
91   }
92
93   /**
94    * Creates an uninitialized Hessian output stream.
95    */

96   public MicroHessianOutput()
97   {
98   }
99
100   public void init(OutputStream JavaDoc os)
101   {
102     this.os = os;
103   }
104
105   /**
106    * Writes the method call:
107    *
108    * <code><pre>
109    * c major minor
110    * m b16 b8 method-namek
111    * </pre></code>
112    *
113    * @param method the method name to call.
114    */

115   public void startCall(String JavaDoc method)
116     throws IOException JavaDoc
117   {
118     os.write('c');
119     os.write(0);
120     os.write(1);
121
122     os.write('m');
123     int len = method.length();
124     os.write(len >> 8);
125     os.write(len);
126     printString(method, 0, len);
127   }
128
129   /**
130    * Writes the method call:
131    *
132    * <code><pre>
133    * z
134    * </pre></code>
135    */

136   public void completeCall()
137     throws IOException JavaDoc
138   {
139     os.write('z');
140   }
141
142   /**
143    * Writes a boolean value to the stream. The boolean will be written
144    * with the following syntax:
145    *
146    * <code><pre>
147    * T
148    * F
149    * </pre></code>
150    *
151    * @param value the boolean value to write.
152    */

153   public void writeBoolean(boolean value)
154     throws IOException JavaDoc
155   {
156     if (value)
157       os.write('T');
158     else
159       os.write('F');
160   }
161
162   /**
163    * Writes an integer value to the stream. The integer will be written
164    * with the following syntax:
165    *
166    * <code><pre>
167    * I b32 b24 b16 b8
168    * </pre></code>
169    *
170    * @param value the integer value to write.
171    */

172   public void writeInt(int value)
173     throws IOException JavaDoc
174   {
175     os.write('I');
176     os.write(value >> 24);
177     os.write(value >> 16);
178     os.write(value >> 8);
179     os.write(value);
180   }
181
182   /**
183    * Writes a long value to the stream. The long will be written
184    * with the following syntax:
185    *
186    * <code><pre>
187    * L b64 b56 b48 b40 b32 b24 b16 b8
188    * </pre></code>
189    *
190    * @param value the long value to write.
191    */

192   public void writeLong(long value)
193     throws IOException JavaDoc
194   {
195     os.write('L');
196     os.write((byte) (value >> 56));
197     os.write((byte) (value >> 48));
198     os.write((byte) (value >> 40));
199     os.write((byte) (value >> 32));
200     os.write((byte) (value >> 24));
201     os.write((byte) (value >> 16));
202     os.write((byte) (value >> 8));
203     os.write((byte) (value));
204   }
205
206   /**
207    * Writes a date to the stream.
208    *
209    * <code><pre>
210    * T b64 b56 b48 b40 b32 b24 b16 b8
211    * </pre></code>
212    *
213    * @param time the date in milliseconds from the epoch in UTC
214    */

215   public void writeUTCDate(long time)
216     throws IOException JavaDoc
217   {
218     os.write('d');
219     os.write((byte) (time >> 56));
220     os.write((byte) (time >> 48));
221     os.write((byte) (time >> 40));
222     os.write((byte) (time >> 32));
223     os.write((byte) (time >> 24));
224     os.write((byte) (time >> 16));
225     os.write((byte) (time >> 8));
226     os.write((byte) (time));
227   }
228
229   /**
230    * Writes a null value to the stream.
231    * The null will be written with the following syntax
232    *
233    * <code><pre>
234    * N
235    * </pre></code>
236    *
237    * @param value the string value to write.
238    */

239   public void writeNull()
240     throws IOException JavaDoc
241   {
242     os.write('N');
243   }
244
245   /**
246    * Writes a string value to the stream using UTF-8 encoding.
247    * The string will be written with the following syntax:
248    *
249    * <code><pre>
250    * S b16 b8 string-value
251    * </pre></code>
252    *
253    * If the value is null, it will be written as
254    *
255    * <code><pre>
256    * N
257    * </pre></code>
258    *
259    * @param value the string value to write.
260    */

261   public void writeString(String JavaDoc value)
262     throws IOException JavaDoc
263   {
264     if (value == null) {
265       os.write('N');
266     }
267     else {
268       int len = value.length();
269
270       os.write('S');
271       os.write(len >> 8);
272       os.write(len);
273
274       printString(value);
275     }
276   }
277
278   /**
279    * Writes a byte array to the stream.
280    * The array will be written with the following syntax:
281    *
282    * <code><pre>
283    * B b16 b18 bytes
284    * </pre></code>
285    *
286    * If the value is null, it will be written as
287    *
288    * <code><pre>
289    * N
290    * </pre></code>
291    *
292    * @param value the string value to write.
293    */

294   public void writeBytes(byte []buffer)
295     throws IOException JavaDoc
296   {
297     if (buffer == null)
298       os.write('N');
299     else
300       writeBytes(buffer, 0, buffer.length);
301   }
302   /**
303    * Writes a byte array to the stream.
304    * The array will be written with the following syntax:
305    *
306    * <code><pre>
307    * B b16 b18 bytes
308    * </pre></code>
309    *
310    * If the value is null, it will be written as
311    *
312    * <code><pre>
313    * N
314    * </pre></code>
315    *
316    * @param value the string value to write.
317    */

318   public void writeBytes(byte []buffer, int offset, int length)
319     throws IOException JavaDoc
320   {
321     if (buffer == null) {
322       os.write('N');
323     }
324     else {
325       os.write('B');
326       os.write(length << 8);
327       os.write(length);
328       os.write(buffer, offset, length);
329     }
330   }
331
332   /**
333    * Writes a reference.
334    *
335    * <code><pre>
336    * R b32 b24 b16 b8
337    * </pre></code>
338    *
339    * @param value the integer value to write.
340    */

341   public void writeRef(int value)
342     throws IOException JavaDoc
343   {
344     os.write('R');
345     os.write(value << 24);
346     os.write(value << 16);
347     os.write(value << 8);
348     os.write(value);
349   }
350
351   /**
352    * Writes a generic object to the output stream.
353    */

354   public void writeObject(Object JavaDoc object)
355     throws IOException JavaDoc
356   {
357     if (object == null)
358       writeNull();
359     else if (object instanceof String JavaDoc)
360       writeString((String JavaDoc) object);
361     else if (object instanceof Boolean JavaDoc)
362       writeBoolean(((Boolean JavaDoc) object).booleanValue());
363     else if (object instanceof Integer JavaDoc)
364       writeInt(((Number JavaDoc) object).intValue());
365     else if (object instanceof Long JavaDoc)
366       writeLong(((Number JavaDoc) object).longValue());
367     else if (object instanceof Date JavaDoc)
368       writeUTCDate(((Date JavaDoc) object).getTime());
369     else if (object instanceof byte[]) {
370       byte []data = (byte []) object;
371       writeBytes(data, 0, data.length);
372     }
373     else if (object instanceof Vector JavaDoc) {
374       Vector JavaDoc vector = (Vector JavaDoc) object;
375
376       int size = vector.size();
377       writeListBegin(size, null);
378       for (int i = 0; i < size; i++)
379         writeObject(vector.get(i));
380       
381       writeListEnd();
382     }
383     else if (object instanceof Hashtable JavaDoc) {
384       Hashtable JavaDoc hashtable = (Hashtable JavaDoc) object;
385
386       writeMapBegin(null);
387       Enumeration JavaDoc e = hashtable.keys();
388       while (e.hasMoreElements()) {
389         Object JavaDoc key = e.nextElement();
390         Object JavaDoc value = hashtable.get(key);
391
392         writeObject(key);
393         writeObject(value);
394       }
395       writeMapEnd();
396     }
397     else
398       writeCustomObject(object);
399   }
400   
401   /**
402    * Applications which override this can do custom serialization.
403    *
404    * @param object the object to write.
405    */

406   public void writeCustomObject(Object JavaDoc object)
407     throws IOException JavaDoc
408   {
409     throw new IOException JavaDoc("unexpected object: " + object);
410   }
411
412   /**
413    * Writes the list header to the stream. List writers will call
414    * <code>writeListBegin</code> followed by the list contents and then
415    * call <code>writeListEnd</code>.
416    *
417    * <code><pre>
418    * &lt;list>
419    * &lt;type>java.util.ArrayList&lt;/type>
420    * &lt;length>3&lt;/length>
421    * &lt;int>1&lt;/int>
422    * &lt;int>2&lt;/int>
423    * &lt;int>3&lt;/int>
424    * &lt;/list>
425    * </pre></code>
426    */

427   public void writeListBegin(int length, String JavaDoc type)
428     throws IOException JavaDoc
429   {
430     os.write('V');
431     os.write('t');
432     printLenString(type);
433     
434     os.write('l');
435     os.write(length >> 24);
436     os.write(length >> 16);
437     os.write(length >> 8);
438     os.write(length);
439   }
440
441   /**
442    * Writes the tail of the list to the stream.
443    */

444   public void writeListEnd()
445     throws IOException JavaDoc
446   {
447     os.write('z');
448   }
449
450   /**
451    * Writes the map header to the stream. Map writers will call
452    * <code>writeMapBegin</code> followed by the map contents and then
453    * call <code>writeMapEnd</code>.
454    *
455    * <code><pre>
456    * Mt b16 b8 type (<key> <value>)z
457    * </pre></code>
458    */

459   public void writeMapBegin(String JavaDoc type)
460     throws IOException JavaDoc
461   {
462     os.write('M');
463     os.write('t');
464     printLenString(type);
465   }
466
467   /**
468    * Writes the tail of the map to the stream.
469    */

470   public void writeMapEnd()
471     throws IOException JavaDoc
472   {
473     os.write('z');
474   }
475
476   /**
477    * Writes a remote object reference to the stream. The type is the
478    * type of the remote interface.
479    *
480    * <code><pre>
481    * 'r' 't' b16 b8 type url
482    * </pre></code>
483    */

484   public void writeRemote(String JavaDoc type, String JavaDoc url)
485     throws IOException JavaDoc
486   {
487     os.write('r');
488     os.write('t');
489     printLenString(type);
490     os.write('S');
491     printLenString(url);
492   }
493
494   /**
495    * Prints a string to the stream, encoded as UTF-8 with preceeding length
496    *
497    * @param v the string to print.
498    */

499   public void printLenString(String JavaDoc v)
500     throws IOException JavaDoc
501   {
502     if (v == null) {
503       os.write(0);
504       os.write(0);
505     }
506     else {
507       int len = v.length();
508       os.write(len >> 8);
509       os.write(len);
510
511       printString(v, 0, len);
512     }
513   }
514
515   /**
516    * Prints a string to the stream, encoded as UTF-8
517    *
518    * @param v the string to print.
519    */

520   public void printString(String JavaDoc v)
521     throws IOException JavaDoc
522   {
523     printString(v, 0, v.length());
524   }
525   
526   /**
527    * Prints a string to the stream, encoded as UTF-8
528    *
529    * @param v the string to print.
530    */

531   public void printString(String JavaDoc v, int offset, int length)
532     throws IOException JavaDoc
533   {
534     for (int i = 0; i < length; i++) {
535       char ch = v.charAt(i + offset);
536
537       if (ch < 0x80)
538         os.write(ch);
539       else if (ch < 0x800) {
540         os.write(0xc0 + ((ch >> 6) & 0x1f));
541         os.write(0x80 + (ch & 0x3f));
542       }
543       else {
544         os.write(0xe0 + ((ch >> 12) & 0xf));
545         os.write(0x80 + ((ch >> 6) & 0x3f));
546         os.write(0x80 + (ch & 0x3f));
547       }
548     }
549   }
550 }
551
Popular Tags