KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > fractal > rmi > io > RmiMarshaller


1 /***
2  * Fractal RMI: a binder for remote method calls between Fractal components.
3  * Copyright (C) 2003 France Telecom R&D
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * Contact: Eric.Bruneton@rd.francetelecom.com
20  *
21  * Author: Eric Bruneton
22  *
23  * adapted from Jonathan:
24  * org.objectweb.jeremie.libs.presentation.StdMarshallerFactory
25  * (authors: B. Dumant, K. Milsted)
26  * with some comments copied from:
27  * org.objectweb.jonathan.apis.presentation.Marshaller
28  * (author: B. Dumant)
29  */

30
31 package org.objectweb.fractal.rmi.io;
32
33 import org.objectweb.jonathan.apis.binding.NamingContext;
34 import org.objectweb.jonathan.apis.kernel.Context;
35 import org.objectweb.jonathan.apis.kernel.ContextFactory;
36 import org.objectweb.jonathan.apis.kernel.InternalException;
37 import org.objectweb.jonathan.apis.kernel.JonathanException;
38 import org.objectweb.jonathan.apis.presentation.Marshaller;
39 import org.objectweb.jonathan.apis.resources.Chunk;
40 import org.objectweb.jonathan.apis.resources.ChunkFactory;
41
42 import java.io.IOException JavaDoc;
43 import java.io.OutputStream JavaDoc;
44
45 /**
46  * A {@link Marshaller} that uses an {@link RmiObjectOutputStream} to
47  * marshall object values.
48  */

49
50 public class RmiMarshaller extends OutputStream JavaDoc implements Marshaller {
51
52   /**
53    * The domain used to instantiate {@link #os os}.
54    */

55
56   protected NamingContext domain;
57
58   /**
59    * The chunk factory used to create new chunks to marshall data.
60    */

61
62   protected ChunkFactory chunkFactory;
63
64   /**
65    * The context factory used to create the context associated with this
66    * marshaller. See {@link #getContext getContext}.
67    */

68
69   protected ContextFactory contextFactory;
70
71   /**
72    * The object output stream used to marshall object values. This stream is
73    * lazily instantiated, i.e., it is instantiated at the first call to {@link
74    * #writeValue writeValue} or to {@link #writeReference writeReference}.
75    */

76
77   protected RmiObjectOutputStream os;
78
79   private Chunk first;
80
81   private Chunk current;
82
83   private int offset;
84
85   private int top;
86
87   private Context context;
88
89   // --------------------------------------------------------------------------
90
// Constructors
91
// --------------------------------------------------------------------------
92

93   /**
94    * Constructs a new {@link RmiMarshaller}.
95    *
96    * @param domain the domain to be used to instantiate {@link #os os}.
97    * @param chunkFactory the chunk factory to be used to create new chunks to
98    * marshall data.
99    * @param contextFactory the context factory to be used to create the context
100    * associated with this marshaller.
101    */

102
103   public RmiMarshaller (
104     final NamingContext domain,
105     final ChunkFactory chunkFactory,
106     final ContextFactory contextFactory)
107   {
108     super();
109     this.domain = domain;
110     this.chunkFactory = chunkFactory;
111     this.contextFactory = contextFactory;
112     first = chunkFactory.newChunk();
113     current = first;
114     top = current.data.length;
115   }
116
117   // --------------------------------------------------------------------------
118
// Implementation of the Marshaller interface
119
// --------------------------------------------------------------------------
120

121   /**
122    * Returns true if this marshaller is little-endian, false otherwise.
123    *
124    * @return true if this marshaller is little-endian, false otherwise.
125    */

126
127   public boolean isLittleEndian () {
128     return false;
129   }
130
131   /**
132    * Returns a {@link Context} associated with this marshaller.
133    *
134    * @return a {@link Context} associated with this marshaller.
135    */

136
137   public Context getContext () {
138     if (context == null) {
139       try {
140         context = contextFactory.newContext();
141       } catch (NullPointerException JavaDoc e) {
142         e.printStackTrace(System.err);
143         throw new InternalException("Context factory required.");
144       }
145     }
146     return context;
147   }
148
149   /**
150    * Returns the state of the message as a (chain of) chunk(s). The returned
151    * chunk(s) are NOT duplicated. If the caller keeps a reference to them, it
152    * must {@link #reset() reset} the message, and not continue to use it.
153    *
154    * @return the state of the message as a (chain of) chunk(s).
155    */

156
157   public Chunk getState () {
158     if (current.next == null) {
159       current.top = offset;
160     }
161     return first;
162   }
163
164   /**
165    * Returns the position in the message at which the next byte will be written.
166    *
167    * @return the current offset in the message.
168    * @see #setOffset
169    */

170
171   public int getOffset () {
172     Chunk c = first;
173     int size = 0;
174     while (c != current) {
175       size += c.top - c.offset;
176       c = c.next;
177     }
178     return size + offset - current.offset;
179   }
180
181   /**
182    * Sets the offset in the message. This method may be used to override data
183    * already written into the message.
184    *
185    * @param off the new offset.
186    * @see #getOffset
187    */

188
189   public void setOffset (int off) {
190     if (current.next == null && offset > current.top) {
191       current.top = offset;
192     }
193     Chunk c = first;
194     int sz = c.top - c.offset;
195     while (off > sz) {
196       off -= sz;
197       c = c.next;
198       sz = c.top - c.offset;
199     }
200     offset = c.offset + off;
201     current = c;
202     if (current.next == null) {
203       top = current.data.length;
204     } else {
205       top = current.top;
206     }
207   }
208
209   /**
210    * Checks if the given marshaller has the same content as this one.
211    *
212    * @param other a marshaller.
213    * @return true if the this marshaller and the given one have the same
214    * contents, i.e., contain the same bits, false otherwise.
215    */

216
217   public boolean sameContents (final Marshaller other) {
218     if (other == null) {
219       return false;
220     } else {
221       Chunk mine = getState(), yours = other.getState();
222       if (mine == yours) {
223         return true;
224       }
225
226       byte[] my_data = null, your_data = null;
227       int my_top = 0, my_offset = 0, your_top = 0, your_offset = 0;
228       if (mine != null) {
229         my_data = mine.data;
230         my_top = mine.top;
231         my_offset = mine.offset;
232       }
233       if (yours != null) {
234         your_data = yours.data;
235         your_top = yours.top;
236         your_offset = yours.offset;
237       }
238       while (mine != null && yours != null) {
239         if (your_top - your_offset > my_top - my_offset) {
240           while (my_offset < my_top &&
241             my_data[my_offset] == your_data[your_offset++]) {
242             my_offset++;
243           }
244           if (my_offset < my_top) {
245             return false;
246           } else {
247             mine = mine.next;
248             if (mine != null) {
249               my_data = mine.data;
250               my_top = mine.top;
251               my_offset = mine.offset;
252             }
253           }
254         } else {
255           while (your_offset < your_top &&
256             my_data[my_offset++] == your_data[your_offset]) {
257             your_offset++;
258           }
259           if (your_offset < your_top) {
260             return false;
261           } else {
262             yours = yours.next;
263             if (yours != null) {
264               your_data = yours.data;
265               your_top = yours.top;
266               your_offset = yours.offset;
267             }
268           }
269         }
270       }
271       if (yours == null) {
272         if (mine != null && mine.top == my_offset) {
273           mine = mine.next;
274         }
275         while (mine != null && mine.top == mine.offset) {
276           mine = mine.next;
277         }
278         return mine == null;
279       } else {
280         if (yours.top == your_offset) {
281           yours = yours.next;
282         }
283         while (yours != null && yours.top == yours.offset) {
284           yours = yours.next;
285         }
286         return yours == null;
287       }
288     }
289   }
290
291   /**
292    * Resets this marshaller. This method causes the message to lose all its
293    * references to the underlying chunks, without {@link Chunk#release()
294    * releasing} them. This method must not be used if no reference to chunks
295    * present in the message is held by an entity in charge of their release.
296    * It also releases the context associated with the target marshaller.
297    */

298
299   public void reset () {
300     first = null;
301     current = null;
302     offset = 0;
303     top = 0;
304     context = null;
305   }
306
307   /**
308    * Returns an output stream to write into the message. Closing the output
309    * stream has the same effect as closing the marshaller itself.
310    *
311    * @return an output stream to write into the message.
312    */

313
314   public OutputStream JavaDoc outputStream () {
315     return this;
316   }
317
318   /**
319    * Writes a byte.
320    *
321    * @param v a byte.
322    * @throws JonathanException if a marshal error occurred.
323    */

324
325   public void writeByte (final byte v) throws JonathanException {
326     if (offset >= top) {
327       prepare();
328     }
329     current.data[offset++] = v;
330   }
331
332   /**
333    * Writes a boolean.
334    *
335    * @param v a boolean.
336    * @throws JonathanException if a marshal error occurred.
337    */

338
339   public void writeBoolean (final boolean v) throws JonathanException {
340     if (offset >= top) {
341       prepare();
342     }
343     current.data[offset++] = (byte)(v ? 1 : 0);
344   }
345
346   /**
347    * Writes an 8 bits char. The method used to translate the provided
348    * <tt>char</tt> into an 8 bits entity is not specified.
349    *
350    * @param v a char.
351    * @throws JonathanException if a marshal error occurred.
352    */

353
354   public void writeChar8 (final char v) throws JonathanException {
355     if (offset >= top) {
356       prepare();
357     }
358     current.data[offset++] = (byte)v;
359   }
360
361   /**
362    * Writes a 16 bits char.
363    *
364    * @param v a char.
365    * @throws JonathanException if a marshal error occurred.
366    */

367
368   public void writeChar16 (final char v) throws JonathanException {
369     if (top - offset < 2) {
370       prepare();
371     }
372     byte[] data = current.data;
373     data[offset++] = (byte)(v >>> 8);
374     data[offset++] = (byte)v;
375   }
376
377   /**
378    * Writes a short.
379    *
380    * @param v a short.
381    * @throws JonathanException if a marshal error occurred.
382    */

383
384   public void writeShort (final short v) throws JonathanException {
385     if (top - offset < 2) {
386       prepare();
387     }
388     byte[] data = current.data;
389     data[offset++] = (byte)(v >>> 8);
390     data[offset++] = (byte)v;
391   }
392
393   /**
394    * Writes an int.
395    *
396    * @param v an int;
397    * @throws JonathanException if a marshal error occurred.
398    */

399
400   public void writeInt (final int v) throws JonathanException {
401     if (top - offset < 4) {
402       prepare();
403     }
404     byte[] data = current.data;
405     data[offset++] = (byte)(v >>> 24);
406     data[offset++] = (byte)(v >>> 16);
407     data[offset++] = (byte)(v >>> 8);
408     data[offset++] = (byte)v;
409   }
410
411   /**
412    * Writes a float.
413    *
414    * @param v a float.
415    * @throws JonathanException if a marshal error occurred.
416    */

417
418   public void writeFloat (final float v) throws JonathanException {
419     int i = Float.floatToIntBits(v);
420     if (top - offset < 4) {
421       prepare();
422     }
423     byte[] data = current.data;
424     data[offset++] = (byte)(i >>> 24);
425     data[offset++] = (byte)(i >>> 16);
426     data[offset++] = (byte)(i >>> 8);
427     data[offset++] = (byte)i;
428   }
429
430   /**
431    * Writes a long.
432    *
433    * @param v a long.
434    * @throws JonathanException if a marshal error occurred.
435    */

436
437   public void writeLong (final long v) throws JonathanException {
438     if (top - offset < 8) {
439       prepare();
440     }
441     byte[] data = current.data;
442     data[offset++] = (byte)(v >>> 56);
443     data[offset++] = (byte)(v >>> 48);
444     data[offset++] = (byte)(v >>> 40);
445     data[offset++] = (byte)(v >>> 32);
446     data[offset++] = (byte)(v >>> 24);
447     data[offset++] = (byte)(v >>> 16);
448     data[offset++] = (byte)(v >>> 8);
449     data[offset++] = (byte)v;
450   }
451
452   /**
453    * Writes a double.
454    *
455    * @param v a double.
456    * @throws JonathanException if a marshal error occurred.
457    */

458
459   public void writeDouble (final double v) throws JonathanException {
460     long l = Double.doubleToLongBits(v);
461     if (top - offset < 8) {
462       prepare();
463     }
464     byte[] data = current.data;
465     data[offset++] = (byte)(l >>> 56);
466     data[offset++] = (byte)(l >>> 48);
467     data[offset++] = (byte)(l >>> 40);
468     data[offset++] = (byte)(l >>> 32);
469     data[offset++] = (byte)(l >>> 24);
470     data[offset++] = (byte)(l >>> 16);
471     data[offset++] = (byte)(l >>> 8);
472     data[offset++] = (byte)l;
473   }
474
475   /**
476    * Writes a string of 8 bits chars.
477    *
478    * @param v a string.
479    * @throws JonathanException if a marshal error occurred.
480    */

481
482   public void writeString8 (final String JavaDoc v) throws JonathanException {
483     int len = v.length();
484     writeInt(len + 1);
485     byte[] data = current.data;
486     int off = 0;
487     int max = top - offset;
488     while (max < len) {
489       while (off < max) {
490         data[offset++] = (byte)(v.charAt(off++));
491       }
492       prepare();
493       data = current.data;
494       max = top - offset + off;
495     }
496     while (off < len) {
497       data[offset++] = (byte)(v.charAt(off++));
498     }
499     if (offset >= top) {
500       prepare();
501     }
502     current.data[offset++] = (byte)0;
503   }
504
505   /**
506    * Writes a string of 16 bits chars.
507    *
508    * @param v a string.
509    * @throws JonathanException if a marshal error occurred.
510    */

511
512   public void writeString16 (final String JavaDoc v) throws JonathanException {
513     throw new InternalException("Not implemented");
514   }
515
516   /**
517    * Writes a chunk in the message.
518    * The target becomes the "owner" of the provided chunk, and therefore is not
519    * supposed to duplicate it. If the entity invoking this operation wants to
520    * keep a reference to the chunk, it must be duplicated.
521    *
522    * @param chunk the chunk to be written.
523    */

524
525   public void write (final Chunk chunk) {
526     if (current.next != null) {
527       throw new InternalException("Illicit operation");
528     }
529     current.top = offset;
530     current.next = chunk;
531     Chunk c = chunk;
532     while (c != null) {
533       current = c;
534       c = c.next;
535     }
536     offset = current.top;
537     top = current.data.length;
538   }
539
540   /**
541    * Writes an array of bytes.
542    *
543    * @param array an array of bytes.
544    * @param off index of the first byte of the array that must be written.
545    * @param len number of bytes of the array that must be written.
546    * @throws JonathanException if a marshal error occurred.
547    */

548
549   public void writeByteArray (final byte[] array, int off, int len)
550     throws JonathanException
551   {
552     int max = top - offset;
553     while (max < len) {
554       if (max > 0) {
555         System.arraycopy(array, off, current.data, offset, max);
556         off += max;
557         len -= max;
558         offset = top;
559       }
560       prepare();
561       max = top - offset;
562     }
563     System.arraycopy(array,off,current.data,offset,len);
564     offset += len;
565   }
566
567   /**
568    * Writes an object reference in the marshaller.
569    *
570    * @param v an object reference.
571    * @throws JonathanException if a marshal error occurred.
572    */

573
574   public void writeReference (final Object JavaDoc v) throws JonathanException {
575     try {
576       initObjectStream();
577       os.writeObject(v);
578       os.drain();
579     } catch (IOException JavaDoc e) {
580       throw new JonathanException(e);
581     }
582   }
583
584   /**
585    * Writes a value in the marshaller.
586    *
587    * @param v an object.
588    * @throws JonathanException if a marshal error occurred.
589    */

590
591   public void writeValue (final Object JavaDoc v) throws JonathanException {
592     try {
593       initObjectStream();
594       os.writeObject(v);
595       os.drain();
596     } catch (IOException JavaDoc e) {
597       throw new JonathanException(e);
598     }
599   }
600
601   // --------------------------------------------------------------------------
602
// Overriden methods
603
// --------------------------------------------------------------------------
604

605   public void write (final int b) throws IOException JavaDoc {
606     try {
607       if (top <= offset) {
608         prepare();
609       }
610       current.data[offset++] = (byte)b;
611     } catch (JonathanException e) {
612       throw new IOException JavaDoc(e.getMessage());
613     }
614   }
615
616   public void write (final byte[] b, final int off, final int len)
617     throws IOException JavaDoc
618   {
619     try {
620       writeByteArray(b, off, len);
621     } catch (JonathanException e) {
622       throw new IOException JavaDoc(e.getMessage());
623     }
624   }
625
626   public void close () {
627     Chunk cur = first;
628     Chunk next;
629     while (cur != null) {
630       next = cur.next;
631       cur.release();
632       cur = next;
633     }
634     first = null;
635     current = null;
636     offset = 0;
637     top = 0;
638     if (context != null) {
639       context.release();
640       context = null;
641     }
642   }
643
644   // --------------------------------------------------------------------------
645
// Utility methods
646
// --------------------------------------------------------------------------
647

648   /**
649    * Instantiates the delegate object output stream {@link #os os}. This
650    * method creates {@link RmiObjectOutputStream} stream.
651    *
652    * @throws IOException if the delegate object output stream cannot be created.
653    */

654
655   protected void initObjectStream () throws IOException JavaDoc {
656     if (os == null) {
657       os = new RmiObjectOutputStream(this, domain);
658     }
659   }
660
661   private void prepare () throws JonathanException {
662     if (current == null) {
663       Chunk chunk = chunkFactory.newChunk();
664       first = chunk;
665       current = chunk;
666       offset = 0;
667       top = current.data.length;
668     } else if (current.next == null) {
669       current.top = offset;
670       Chunk chunk = chunkFactory.newChunk();
671       current.next = chunk;
672       current = chunk;
673       offset = 0;
674       top = current.data.length;
675     } else {
676       current = current.next;
677       offset = current.offset;
678       if (current.next != null) {
679         top = current.top;
680       } else {
681         top = current.data.length;
682       }
683     }
684   }
685 }
686
Popular Tags