1 /* Vio.java -- Value type IO operations.
2 Copyright (C) 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu
.CORBA
.CDR
;
41 import gnu
.CORBA
.Minor
;
42 import gnu
.CORBA
.ObjectCreator
;
44 import org
.omg
.CORBA
.CustomMarshal
;
45 import org
.omg
.CORBA
.DataInputStream
;
46 import org
.omg
.CORBA
.DataOutputStream
;
47 import org
.omg
.CORBA
.MARSHAL
;
48 import org
.omg
.CORBA
.NO_IMPLEMENT
;
49 import org
.omg
.CORBA
.StringSeqHelper
;
50 import org
.omg
.CORBA
.StringValueHelper
;
51 import org
.omg
.CORBA
.SystemException
;
52 import org
.omg
.CORBA
.WStringValueHelper
;
53 import org
.omg
.CORBA
.portable
.BoxedValueHelper
;
54 import org
.omg
.CORBA
.portable
.InputStream
;
55 import org
.omg
.CORBA
.portable
.OutputStream
;
56 import org
.omg
.CORBA
.portable
.Streamable
;
57 import org
.omg
.CORBA
.portable
.ValueFactory
;
59 import java
.io
.IOException
;
60 import java
.io
.Serializable
;
61 import java
.lang
.reflect
.Constructor
;
62 import java
.lang
.reflect
.Modifier
;
63 import java
.util
.StringTokenizer
;
65 import javax
.rmi
.CORBA
.Util
;
66 import javax
.rmi
.CORBA
.ValueHandler
;
69 * A specialised class for reading and writing the value types.
71 * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
73 public abstract class Vio
76 * If true, wrap value type data into chunks. This decrease the performance,
77 * and is not required for interoperability with jdk 1.5, but is left in the
78 * implementation as the optional mode for solving possible interoperability
79 * problems with non-Sun CORBA implementations.
81 * The current implementation would accept both single chunk or multiple
82 * chunks, but will always send a single chunk (if true) or unchunked data (if
85 public static boolean USE_CHUNKING
= false;
88 * The first field in the value record. The last octet may contain additional
89 * flags (vf_CODEBASE, vf_ID and vf_MULTIPLE_IDS). The tag value is different
90 * for the indirections (vt_INDIRECTION) and nulls (vt_NULL).
92 public static final int vt_VALUE_TAG
= 0x7fffff00;
95 * The value tag flag, indicating that the codebase URL is present in the
98 public static final int vf_CODEBASE
= 0x1;
101 * The value tag flag, indicating that a single repository id is present in
102 * the value tag record.
104 public static final int vf_ID
= 0x2;
107 * The value tag flag, indicating, that there are multiple repository ids
108 * present in the record. If this flag is set, the flag vf_ID must also be
109 * set, resulting the value of the least significant byte 0x6.
111 public static final int vf_MULTIPLE_IDS
= 0x4;
114 * The value tag flag, indicating the presence of chunking. Each chunk is
115 * preceeded by a positive int, indicating the number of bytes in the chunk. A
116 * sequence of chunks is terminated by a non positive int.
118 public static final int vf_CHUNKING
= 0x8;
121 * The indirection tag value. Such tag must be followed by the CORBA long,
122 * indicating the offset in the CORBA message, where the indirected
123 * information is present. This offset is assumed zero at the position where
124 * the mentioned CORBA long starts and can refer both forward (positive
125 * values) and backward (negative values).
127 public static final int vt_INDIRECTION
= 0xffffffff;
130 * This tag value means that the value object being transferred is equal to
133 public static final int vt_NULL
= 0x0;
136 * The size of CORBA long (java int).
138 static final int INT_SIZE
= 4;
141 * The String value helper (one instance is sufficient).
143 public static final WStringValueHelper m_StringValueHelper
= new WStringValueHelper();
146 * An instance of the value handler.
148 static ValueHandler handler
= Util
.createValueHandler();
151 * Read the value base from the given input stream. Determines the required
152 * class from the repository id. This includes operations that are not
153 * required when an unitialised instance or at least class of the value type
154 * is known. Hence it may be faster to use the alternative methods,
155 * read(InputStream, Class) or read(InputStream, Serializable).
157 * @param input a stream to read from.
158 * @param repository_id a repository id of the object being read, may be null.
160 * @return the loaded value.
162 * @throws MARSHAL if the reading has failed due any reason.
164 public static Serializable
read(InputStream input
)
166 return read(input
, (String
) null);
170 * Read the value base from the given input stream. Determines the required
171 * class from the repository id. This includes operations that are not
172 * required when an unitialised instance or at least class of the value type
173 * is known. Hence it may be faster to use the alternative methods,
174 * read(InputStream, Class) or read(InputStream, Serializable).
176 * @param an_input a stream to read from.
177 * @param repository_id a repository id of the object being read, may be null.
179 * @return the loaded value.
181 * @throws MARSHAL if the reading has failed due any reason.
183 public static Serializable
read(InputStream input
, String repository_id
)
187 final int position
= getCurrentPosition(input
);
188 // We may need to jump back if the value is read via value factory.
191 int value_tag
= input
.read_long();
194 String codebase
= null;
196 String id
= repository_id
;
198 // Check for the agreed null value.
199 if (value_tag
== vt_NULL
)
201 else if (value_tag
== vt_INDIRECTION
)
202 return readIndirection(input
);
206 if ((value_tag
& vf_CODEBASE
) != 0)
208 // The codebase is present. The codebase is a space
209 // separated list of URLs from where the implementing
210 // code can be downloaded.
211 codebase
= read_string(input
);
214 if ((value_tag
& vf_MULTIPLE_IDS
) != 0)
216 // Multiple supported repository ids are present.
217 ids
= read_string_array(input
);
219 else if ((value_tag
& vf_ID
) != 0)
221 // Single supported repository id is present.
222 id
= read_string(input
);
226 BoxedValueHelper helper
= getHelper(null, id
);
227 // The existing implementing object.
228 java
.lang
.Object ox
= null;
231 ox
= null; // Helper will care about the instantiating.
232 else if (id
.equals(WStringValueHelper
.id()))
233 helper
= m_StringValueHelper
;
235 ox
= createInstance(id
, ids
, codebase
);
236 return (Serializable
) read_instance(input
, position
, ox
, value_tag
,
237 helper
, id
, ids
, codebase
);
241 MARSHAL m
= new MARSHAL();
242 m
.minor
= Minor
.Value
;
249 * Read the value base from the given input stream when the value base class
250 * is available. Hence there is no need to guess it from the repository id.
252 * @param input a stream to read from.
253 * @param value_class the class of the value being read.
255 * @return the loaded value.
257 * @throws MARSHAL if the reading has failed due any reason.
259 public static Serializable
read(InputStream input
, Class value_class
)
261 final int position
= getCurrentPosition(input
);
265 String codebase
= null;
269 int value_tag
= input
.read_long();
272 // Check for the agreed null value.
273 if (value_tag
== vt_NULL
)
275 else if (value_tag
== vt_INDIRECTION
)
276 return readIndirection(input
);
280 if ((value_tag
& vf_CODEBASE
) != 0)
282 // The codebase is present.
283 codebase
= read_string(input
);
286 if ((value_tag
& vf_MULTIPLE_IDS
) != 0)
288 // Multiple supported repository ids are present.
289 ids
= read_string_array(input
);
291 else if ((value_tag
& vf_ID
) != 0)
293 // Single supported repository id is present.
294 id
= read_string(input
);
298 BoxedValueHelper vHelper
= id
!= null ?
getHelper(value_class
, id
)
299 : getHelper(value_class
, ids
);
307 ox
= createInstance(id
, ids
, codebase
);
316 if (value_class
!= null
317 && !value_class
.isAssignableFrom(ox
.getClass()))
319 MARSHAL m
= new MARSHAL(ox
.getClass() + " is not a "
320 + value_class
.getName());
321 m
.minor
= Minor
.ClassCast
;
329 ox
= read_instance(input
, position
, ox
, value_tag
, vHelper
, id
, ids
,
331 return (Serializable
) ox
;
337 catch (SystemException sysEx
)
344 MARSHAL m
= new MARSHAL("Cant read " + value_class
);
345 m
.minor
= Minor
.Value
;
352 * Read the value base from the given input stream when the unitialised
353 * instance is available. Hence there is no need to guess the class from the
354 * repository id and then to instantiate an instance.
356 * @param input a stream to read from.
358 * @param value_instance an pre-created instance of the value. If the helper
359 * is not null, this parameter is ignored an should be null.
361 * @param helper a helper to create an instance and read the object- specific
362 * part of the record. If the value_instance is used instead, this parameter
365 * @return the loaded value.
367 * @throws MARSHAL if the reading has failed due any reason.
369 public static Object
read(InputStream input
, Object value_instance
,
370 BoxedValueHelper helper
)
372 final int position
= getCurrentPosition(input
);
376 String codebase
= null;
380 int value_tag
= input
.read_long();
383 // Check for the agreed null value.
384 if (value_tag
== vt_NULL
)
386 else if (value_tag
== vt_INDIRECTION
)
387 return readIndirection(input
);
391 if ((value_tag
& vf_CODEBASE
) != 0)
393 // The codebase is present.
394 codebase
= read_string(input
);
397 if ((value_tag
& vf_MULTIPLE_IDS
) != 0)
399 // Multiple supported repository ids are present.
400 ids
= read_string_array(input
);
402 else if ((value_tag
& vf_ID
) != 0)
404 // Single supported repository id is present.
405 id
= read_string(input
);
409 Class value_class
= value_instance
== null ?
null
410 : value_instance
.getClass();
413 helper
= id
!= null ?
getHelper(value_class
, id
) : getHelper(
416 value_instance
= read_instance(input
, position
, value_instance
,
417 value_tag
, helper
, id
, ids
, codebase
);
418 return value_instance
;
422 MARSHAL m
= new MARSHAL();
423 m
.minor
= Minor
.Value
;
430 * Read using provided boxed value helper. This method expects the full value
431 * type header, followed by contents, that are delegated to the provided
432 * helper. It handles null.
434 * @param input the stream to read from.
435 * @param helper the helper that reads the type-specific part of the content.
437 * @return the value, created by the helper, or null if the header indicates
438 * that null was previously written.
440 public static Serializable
read(InputStream input
, BoxedValueHelper helper
)
442 return (Serializable
) read(input
, null, helper
);
446 * Fill in the instance fields by the data from the input stream. The method
447 * assumes that the value header, if any, is already behind. The information
448 * from the stream is stored into the passed ox parameter.
450 * @param input an input stream to read from.
452 * @param value a pre-instantiated value type object, must be either
453 * Streamable or CustomMarshal. If the helper is used, this parameter is
454 * ignored and should be null.
456 * @param value_tag the tag that must be read previously.
457 * @param helper the helper for read object specific part; may be null to read
458 * in using other methods.
460 * @return the value that was read.
462 static Object
read_instance(InputStream input
, final int position
,
463 Object value
, int value_tag
, BoxedValueHelper helper
, String id
,
464 String
[] ids
, String codebase
)
466 if (helper
!= m_StringValueHelper
&& id
!= null)
467 if (id
.equals(StringValueHelper
.id()))
470 helper
= m_StringValueHelper
;
475 if ((value_tag
& vf_CHUNKING
) != 0)
477 BufferedCdrOutput output
= createBuffer(input
, 1024);
478 // Read the current (not a nested one) value in this spec case.
479 readNestedValue(value_tag
, input
, output
, -1);
480 BufferredCdrInput ci
= new BufferredCdrInput(output
.buffer
.getBuffer());
481 ci
.setRunTime(output
.getRunTime());
483 input
= new HeadlessInput(ci
, input
);
487 if (input
instanceof BufferredCdrInput
)
489 // Highly probable case.
490 input
= new HeadlessInput((BufferredCdrInput
) input
, null);
492 else if (input
instanceof HeadlessInput
)
494 // There is no need to instantiate one more HeadlessInput
495 // as we can just reset.
496 ((HeadlessInput
) input
).subsequentCalls
= false;
500 BufferedCdrOutput bout
= new BufferedCdrOutput();
502 while ((c
= input
.read()) >= 0)
503 bout
.write((byte) c
);
504 input
= new HeadlessInput(
505 (BufferredCdrInput
) bout
.create_input_stream(), input
);
509 catch (IOException ex
)
511 MARSHAL m
= new MARSHAL("Unable to read chunks");
512 m
.minor
= Minor
.Value
;
517 return readValue(input
, position
, value
, helper
, id
, ids
, codebase
);
521 * Create a buffer, inheriting critical settings from the passed input stream.
523 private static BufferedCdrOutput
createBuffer(InputStream input
, int proposed_size
)
525 BufferedCdrOutput bout
;
526 bout
= new BufferedCdrOutput(2 * proposed_size
+ 256);
528 if (input
instanceof BufferredCdrInput
)
530 BufferredCdrInput in
= (BufferredCdrInput
) input
;
531 bout
.setBigEndian(in
.isBigEndian());
534 if (input
instanceof gnuValueStream
)
535 bout
.setRunTime(((gnuValueStream
) input
).getRunTime());
537 bout
.setRunTime(new gnuRuntime(null, null));
542 * Read the chunked nested value from the given input stream, transferring the
543 * contents to the given output stream.
545 * @param value_tag the value tag of the value being read.
546 * @param input the input stream from where the remainder of the nested value
548 * @param output the output stream where the unchunked nested value must be
551 * @return the tag that ended the nested value.
553 public static int readNestedValue(int value_tag
, InputStream input
,
554 BufferedCdrOutput output
, int level
)
560 // For the first level, this information is already behind.
561 output
.write_long(value_tag
- vf_CHUNKING
);
563 // The nested value should be aways chunked.
564 if ((value_tag
& vf_CHUNKING
) == 0)
566 MARSHAL m
= new MARSHAL("readNestedValue: must be chunked");
567 m
.minor
= Minor
.Chunks
;
570 else if (value_tag
== vt_NULL
)
572 MARSHAL m
= new MARSHAL("readNestedValue: nul");
573 m
.minor
= Minor
.Chunks
;
576 else if (value_tag
== vt_INDIRECTION
)
578 MARSHAL m
= new MARSHAL("readNestedValue: indirection");
579 m
.minor
= Minor
.Chunks
;
585 if ((value_tag
& vf_CODEBASE
) != 0)
587 String codebase
= read_string(input
);
588 write_string(output
, codebase
);
591 if ((value_tag
& vf_MULTIPLE_IDS
) != 0)
593 // Multiple supported repository ids are present.
594 String
[] ids
= read_string_array(input
);
596 write_string_array(output
, ids
);
598 else if ((value_tag
& vf_ID
) != 0)
600 id
= read_string(input
);
601 write_string(output
, id
);
615 // Read the size of the next chunk or it may also be the
616 // header of the nested value.
617 chunk_size
= input
.read_long();
619 // End of chunk terminator.
620 if (chunk_size
< 0 && chunk_size
>= level
)
622 else if (chunk_size
>= 0x7FFFFF00)
624 int onInput
= getCurrentPosition(input
) - 4;
625 int onOutput
= output
.getPosition();
626 output
.getRunTime().redirect(onInput
, onOutput
);
627 // Value over 0x7FFFFF00 indicates that the nested value
628 // starts here. Read the nested value, storing it into the output.
629 // First parameter is actually the value tag.
630 chunk_size
= readNestedValue(chunk_size
, input
, output
, level
- 1);
631 if (chunk_size
< 0 && chunk_size
>= level
)
636 // The chunk follows.
637 if (r
== null || r
.length
< chunk_size
)
638 r
= new byte[chunk_size
+ 256];
641 reading
: while (n
< chunk_size
)
642 n
+= input
.read(r
, n
, chunk_size
- n
);
643 output
.write(r
, 0, n
);
649 * Read the value (the header must be behind).
651 public static Serializable
readValue(InputStream input
, final int position
,
652 Object value
, BoxedValueHelper helper
, String id
, String
[] ids
,
656 gnuValueStream c
= ((gnuValueStream
) input
);
657 if (c
.getRunTime() == null)
659 g
= new gnuRuntime(codebase
, value
);
665 g
.addCodeBase(codebase
);
666 g
.target
= (Serializable
) value
;
669 g
.objectWritten(value
, position
);
671 if (input
instanceof HeadlessInput
)
672 ((HeadlessInput
) input
).subsequentCalls
= false;
676 // The user-defined io operations are implemented.
677 if (value
instanceof CustomMarshal
)
679 CustomMarshal marsh
= (CustomMarshal
) value
;
680 marsh
.unmarshal((DataInputStream
) input
);
683 // The IDL-generated io operations are implemented.
684 if (value
instanceof Streamable
)
686 ((Streamable
) value
)._read(input
);
688 else if (helper
!= null)
690 // If helper is non-null the value should normally be null.
691 value
= helper
.read_value(input
);
692 g
.objectWritten(value
, position
);
697 ValueFactory factory
= null;
698 org
.omg
.CORBA_2_3
.ORB orb
= (org
.omg
.CORBA_2_3
.ORB
) input
.orb();
701 factory
= orb
.lookup_value_factory(id
);
703 if (factory
== null && ids
!= null)
705 for (int i
= 0; i
< ids
.length
&& factory
== null; i
++)
707 factory
= orb
.lookup_value_factory(ids
[i
]);
713 value
= factory
.read_value((org
.omg
.CORBA_2_3
.portable
.InputStream
) input
);
718 if (!ok
&& value
instanceof Serializable
)
719 // Delegate to ValueHandler
721 if (ids
!= null && ids
.length
> 0)
724 value
= handler
.readValue(input
, position
, value
.getClass(), id
, g
);
732 MARSHAL m
= new MARSHAL(value
.getClass().getName()
733 + " must be Streamable, CustomMarshal or Serializable");
734 m
.minor
= Minor
.UnsupportedValue
;
739 MARSHAL m
= new MARSHAL("Unable to instantiate " + id
+ ":" + list(ids
)
740 + " helper " + helper
);
741 m
.minor
= Minor
.UnsupportedValue
;
746 return (Serializable
) value
;
750 * Conveniency method to list ids in exception reports.
752 static String
list(String
[] s
)
758 StringBuffer b
= new StringBuffer("{");
759 for (int i
= 0; i
< s
.length
; i
++)
770 * Write the value base into the given stream.
772 * @param output a stream to write to.
774 * @param value a value type object, must be either Streamable or
777 * @throws MARSHAL if the writing failed due any reason.
779 public static void write(OutputStream output
, Serializable value
)
781 // Write null if this is a null value.
783 output
.write_long(vt_NULL
);
784 else if (value
instanceof String
)
785 write(output
, value
, m_StringValueHelper
);
787 write(output
, value
, value
.getClass());
791 * Write the value base into the given stream, stating that it is an instance
792 * of the given class.
794 * @param output a stream to write to.
796 * @param value a value to write.
798 * @throws MARSHAL if the writing failed due any reason.
800 public static void write(OutputStream output
, Serializable value
,
803 // Write null if this is a null value.
805 output
.write_long(vt_NULL
);
806 else if (value
instanceof String
|| substitute
== String
.class)
807 writeString(output
, value
);
810 String vId
= ObjectCreator
.getRepositoryId(value
.getClass());
811 if (substitute
== null || value
.getClass().equals(substitute
))
812 write_instance(output
, value
, vId
, getHelper(value
.getClass(), vId
));
815 String vC
= ObjectCreator
.getRepositoryId(substitute
);
816 String
[] ids
= new String
[] { vId
, vC
};
817 BoxedValueHelper h
= getHelper(substitute
.getClass(), ids
);
818 // If the helper is available, it is also responsible for
819 // providing the repository Id. Otherwise, write both
822 write_instance(output
, value
, ids
, null);
824 write_instance(output
, value
, h
.get_id(), null);
830 * Write the value base into the given stream, supplementing it with an array
831 * of the provided repository ids plus the repository id, derived from the
834 * @param output a stream to write to.
836 * @param value a value to write.
838 * @throws MARSHAL if the writing failed due any reason.
840 public static void write(OutputStream output
, Serializable value
,
841 String
[] multiple_ids
)
843 // Write null if this is a null value.
845 output
.write_long(vt_NULL
);
848 String
[] ids
= new String
[multiple_ids
.length
+ 1];
849 ids
[0] = ObjectCreator
.getRepositoryId(value
.getClass());
850 System
.arraycopy(multiple_ids
, 0, ids
, 1, multiple_ids
.length
);
851 BoxedValueHelper h
= getHelper(value
.getClass(), ids
);
852 write_instance(output
, value
, ids
, h
);
857 * Write value when its repository Id is explicitly given. Only this Id is
858 * written, the type of value is not taken into consideration.
860 * @param output an output stream to write into.
861 * @param value a value to write.
862 * @param id a value repository id.
864 public static void write(OutputStream output
, Serializable value
, String id
)
867 output
.write_long(vt_NULL
);
869 write_instance(output
, value
, id
, getHelper(value
.getClass(), id
));
873 * Write standard value type header, followed by contents, produced by the
874 * boxed value helper.
876 * @param output the stream to write to.
877 * @param value the value to write, can be null.
878 * @param helper the helper that writes the value content if it is not null
879 * (must be provided for this method).
881 public static void write(OutputStream output
, Serializable value
,
882 BoxedValueHelper helper
)
885 throw new AssertionError("Helper must be provided");
887 output
.write_long(vt_NULL
);
889 write_instance(output
, value
, helper
.get_id(), helper
);
893 * Write the parameter that is surely a string and not null.
895 private static void writeString(OutputStream output
, Serializable string
)
897 write_instance(output
, string
, m_StringValueHelper
.get_id(),
898 m_StringValueHelper
);
902 * Write value when its repository Id is explicitly given. Does not handle
905 * @param output an output stream to write into.
906 * @param value a value to write.
907 * @param id a value repository id (can be either single string or string
909 * @param helper a helper, writing object - specifical part. Can be null if
910 * the value should be written using other methods.
912 static void write_instance(OutputStream output
, Serializable value
,
913 Object ids
, BoxedValueHelper helper
)
915 gnuValueStream rout
= null;
916 gnuRuntime runtime
= null;
920 if (output
instanceof gnuValueStream
)
923 rout
= (gnuValueStream
) output
;
924 runtime
= rout
.getRunTime();
928 runtime
= new gnuRuntime(null, value
);
929 rout
.setRunTime(runtime
);
930 rout
.getRunTime().objectWritten(value
,
931 position
= rout
.getPosition());
933 else if (runtime
.target
== value
)
935 if (!writeSelf(output
, value
))
936 throw new InternalError("Recursive helper call for "
937 + value
.getClass().getName());
942 position
= runtime
.isWrittenAt(value
);
945 // The object was already written.
946 output
.write_long(vt_INDIRECTION
);
947 output
.write_long(position
- rout
.getPosition());
948 // Replacing object write data by indirection reference.
953 runtime
.objectWritten(value
, position
= rout
.getPosition());
958 int value_tag
= vt_VALUE_TAG
;
960 if (ids
instanceof String
)
962 else if (ids
instanceof String
[])
963 // OMG standard requires to set both flags.
964 value_tag
|= vf_MULTIPLE_IDS
| vf_ID
;
966 int chunkSizeLocation
;
972 // Wrap the value being written into one chunk (makes sense only for
973 // compatibility reasons).
975 value_tag
|= vf_CHUNKING
;
980 output
.write_long(value_tag
);
982 if ((value_tag
& vf_MULTIPLE_IDS
) != 0)
983 write_string_array(output
, (String
[]) ids
);
984 else if ((value_tag
& vf_ID
) != 0)
985 write_string(output
, (String
) ids
);
989 // So far, write 0x55555555 instead of the chunk size (alignment may
991 output
.write_long(0x55555555);
992 // If the chunking is involved, the chunk size must be written here.
993 chunkSizeLocation
= rout
.getPosition() - INT_SIZE
;
996 // Not in use for this case.
997 chunkSizeLocation
= -1;
999 writeValue(outObj
, value
, helper
);
1003 // Write the chunk size where the place for it was reserved.
1004 int chunkSize
= rout
.getPosition() - chunkSizeLocation
- INT_SIZE
;
1005 int current
= rout
.getPosition();
1006 rout
.seek(chunkSizeLocation
);
1007 output
.write_long(chunkSize
);
1010 // The end of record marker.
1011 output
.write_long(-1);
1016 if (runtime
!= null)
1017 runtime
.target
= null;
1022 * Write value (after header).
1024 static void writeValue(OutputStream output
, Serializable value
,
1025 BoxedValueHelper helper
)
1027 ((gnuValueStream
) output
).getRunTime().target
= value
;
1029 helper
.write_value(output
, value
);
1030 else if (!writeSelf(output
, value
))
1032 // Try to find helper via class loader.
1037 if (output
instanceof BufferedCdrOutput
)
1039 BufferedCdrOutput b
= (BufferedCdrOutput
) output
;
1040 if (b
.runtime
== null)
1041 b
.runtime
= new gnuRuntime(null, value
);
1044 handler
.writeValue(output
, value
);
1050 * Try to write value supposing that it implements self-streamable interfaces.
1051 * Return false if it does not or true on success.
1053 static boolean writeSelf(OutputStream output
, Serializable value
)
1055 // User defined write method is present.
1056 if (value
instanceof CustomMarshal
)
1058 ((CustomMarshal
) value
).marshal((DataOutputStream
) output
);
1061 else if (value
instanceof Streamable
)
1063 ((Streamable
) value
)._write(output
);
1070 * Read the indirection data and return the object that was already written to
1073 * @param an_input the input stream, must be BufferredCdrInput.
1075 static Serializable
readIndirection(InputStream an_input
)
1077 if (!(an_input
instanceof gnuValueStream
))
1078 throw new NO_IMPLEMENT(gnuValueStream
.class.getName()
1079 + " expected as parameter");
1081 gnuValueStream in
= (gnuValueStream
) an_input
;
1083 int current_pos
= in
.getPosition();
1085 int offset
= an_input
.read_long();
1086 if (offset
> -INT_SIZE
)
1088 MARSHAL m
= new MARSHAL("Indirection tag refers to " + offset
1089 + " (must be less than -" + INT_SIZE
+ ")");
1090 m
.minor
= Minor
.Offset
;
1094 int stored_at
= current_pos
+ offset
;
1096 if (in
.getRunTime() == null)
1098 MARSHAL m
= new MARSHAL(stored_at
+ " offset " + offset
+ ": not written");
1099 m
.minor
= Minor
.Value
;
1103 return (Serializable
) in
.getRunTime().isObjectWrittenAt(stored_at
, offset
);
1107 * Check the passed value tag for correctness.
1109 * @param value_tag a tag to check, must be between 0x7fffff00 and 0x7fffffff
1111 * @throws MARSHAL if the tag is outside this interval.
1113 static void checkTag(int value_tag
)
1115 if ((value_tag
< 0x7fffff00 || value_tag
> 0x7fffffff)
1116 && value_tag
!= vt_NULL
&& value_tag
!= vt_INDIRECTION
)
1118 MARSHAL m
= new MARSHAL("Invalid value record, unsupported header tag: "
1119 + value_tag
+ " (0x" + Integer
.toHexString(value_tag
) + ")");
1120 m
.minor
= Minor
.ValueHeaderTag
;
1124 if ((value_tag
& vf_MULTIPLE_IDS
) != 0 && (value_tag
& vf_ID
) == 0)
1126 MARSHAL m
= new MARSHAL("Invalid value record header flag combination (0x"
1127 + Integer
.toHexString(value_tag
) + ")");
1128 m
.minor
= Minor
.ValueHeaderFlags
;
1136 static void throwIt(String msg
, String id1
, String id2
, Throwable e
)
1139 MARSHAL m
= new MARSHAL(msg
+ ":'" + id1
+ "' versus '" + id2
+ "'");
1142 m
.minor
= Minor
.Value
;
1147 * Load class by name and create the instance.
1149 static Object
createInstance(String id
, String
[] ids
, String codebase
)
1154 o
= _createInstance(id
, codebase
);
1157 for (int i
= 0; i
< ids
.length
&& o
== null; i
++)
1158 o
= _createInstance(ids
[i
], codebase
);
1162 static Object
_createInstance(String id
, String codebase
)
1166 if (id
.equals(StringValueHelper
.id()))
1168 StringTokenizer st
= new StringTokenizer(id
, ":");
1170 String prefix
= st
.nextToken();
1171 if (prefix
.equalsIgnoreCase("IDL"))
1172 return ObjectCreator
.Idl2Object(id
);
1173 else if (prefix
.equalsIgnoreCase("RMI"))
1175 String className
= st
.nextToken();
1176 String hashCode
= st
.nextToken();
1178 if (st
.hasMoreElements())
1179 sid
= st
.nextToken();
1183 Class objectClass
= Util
.loadClass(className
, codebase
,
1184 Vio
.class.getClassLoader());
1186 String rid
= ObjectCreator
.getRepositoryId(objectClass
);
1188 if (!rid
.equals(id
))
1190 // If direct string comparison fails, compare by meaning.
1191 StringTokenizer st2
= new StringTokenizer(rid
, ":");
1192 if (!st2
.nextToken().equals("RMI"))
1193 throw new InternalError("RMI format expected: '" + rid
+ "'");
1194 if (!st2
.nextToken().equals(className
))
1195 throwIt("Class name mismatch", id
, rid
, null);
1199 long h1
= Long
.parseLong(hashCode
, 16);
1200 long h2
= Long
.parseLong(st2
.nextToken(), 16);
1202 throwIt("Hashcode mismatch", id
, rid
, null);
1204 if (sid
!= null && st2
.hasMoreTokens())
1206 long s1
= Long
.parseLong(hashCode
, 16);
1207 long s2
= Long
.parseLong(st2
.nextToken(), 16);
1209 throwIt("serialVersionUID mismatch", id
, rid
, null);
1212 catch (NumberFormatException e
)
1214 throwIt("Invalid hashcode or svuid format: ", id
, rid
, e
);
1218 // Low - level instantiation required here.
1219 return instantiateAnyWay(objectClass
);
1221 catch (Exception ex
)
1223 MARSHAL m
= new MARSHAL("Unable to instantiate " + id
);
1224 m
.minor
= Minor
.Instantiation
;
1230 throw new NO_IMPLEMENT("Unsupported prefix " + prefix
+ ":");
1234 * Read string, expecting the probable indirection.
1236 static String
read_string(InputStream input
)
1238 gnuValueStream g
= (gnuValueStream
) input
;
1239 int previous
= g
.getPosition();
1240 int l
= input
.read_long();
1241 if (l
!= vt_INDIRECTION
)
1244 String s
= input
.read_string();
1245 if (g
.getRunTime() == null)
1246 g
.setRunTime(new gnuRuntime(null, null));
1247 g
.getRunTime().singleIdWritten(s
, previous
);
1252 gnuRuntime r
= g
.getRunTime();
1253 int base
= g
.getPosition();
1254 int delta
= input
.read_long();
1257 previous
= g
.getPosition();
1258 g
.seek(base
+ delta
);
1259 String indir
= input
.read_string();
1265 return (String
) r
.isObjectWrittenAt(base
+ delta
, delta
);
1271 * Read string array, expecting the probable indirection.
1273 static String
[] read_string_array(InputStream input
)
1275 gnuValueStream g
= (gnuValueStream
) input
;
1276 int previous
= g
.getPosition();
1277 int l
= input
.read_long();
1278 if (l
!= vt_INDIRECTION
)
1281 String
[] s
= StringSeqHelper
.read(input
);
1282 if (g
.getRunTime() == null)
1283 g
.setRunTime(new gnuRuntime(null, null));
1284 g
.getRunTime().objectWritten(s
, previous
);
1289 gnuRuntime r
= g
.getRunTime();
1290 int base
= g
.getPosition();
1291 int delta
= input
.read_long();
1294 previous
= g
.getPosition();
1295 g
.seek(base
+ delta
);
1296 String
[] indir
= StringSeqHelper
.read(input
);
1302 return (String
[]) r
.isObjectWrittenAt(base
+ delta
, delta
);
1308 * Write repository Id, probably shared.
1310 static void write_string(OutputStream output
, String id
)
1312 if (output
instanceof gnuValueStream
)
1314 gnuValueStream b
= (gnuValueStream
) output
;
1317 int written
= b
.getRunTime().idWrittenAt(id
);
1320 // Reuse existing id record.
1321 output
.write_long(vt_INDIRECTION
);
1322 int p
= b
.getPosition();
1323 output
.write_long(written
- p
);
1327 b
.getRunTime().singleIdWritten(id
, b
.getPosition());
1328 output
.write_string(id
);
1333 output
.write_string(id
);
1337 * Write repository Id, probably shared.
1339 static void write_string_array(OutputStream output
, String
[] ids
)
1341 if (output
instanceof gnuValueStream
)
1343 gnuValueStream b
= (gnuValueStream
) output
;
1346 int written
= b
.getRunTime().idWrittenAt(ids
);
1349 // Reuse existing id record.
1350 output
.write_long(vt_INDIRECTION
);
1351 int p
= b
.getPosition();
1352 output
.write_long(written
- p
);
1356 b
.getRunTime().multipleIdsWritten(ids
, b
.getPosition());
1357 StringSeqHelper
.write(output
, ids
);
1362 StringSeqHelper
.write(output
, ids
);
1366 * Get the helper that could write the given object, or null if no pre-defined
1367 * helper available for this object.
1369 public static BoxedValueHelper
getHelper(Class x
, Object ids
)
1371 if (x
!= null && x
.equals(String
.class))
1372 return m_StringValueHelper
;
1373 else if (x
!= null && x
.isArray())
1374 return new ArrayValueHelper(x
);
1375 else if (ids
instanceof String
)
1376 return locateHelper((String
) ids
);
1377 else if (ids
instanceof String
[])
1379 String
[] ia
= (String
[]) ids
;
1381 for (int i
= 0; i
< ia
.length
; i
++)
1383 h
= locateHelper(ia
[i
]);
1394 * Get the helper that could write the given object, or null if no pre-defined
1395 * helper available for this object.
1397 public static BoxedValueHelper
getHelper(Class x
, String id
)
1399 if (x
!= null && x
.equals(String
.class))
1400 return m_StringValueHelper
;
1401 else if (x
!= null && x
.isArray())
1402 return new ArrayValueHelper(x
);
1404 return locateHelper(id
);
1408 * Try to locate helper from the repository id.
1410 static BoxedValueHelper
locateHelper(String id
)
1414 if (id
.equals(m_StringValueHelper
.get_id()))
1415 return m_StringValueHelper
;
1417 // Try to locate helper for IDL type.
1418 if (id
.startsWith("IDL:"))
1422 Class helperClass
= ObjectCreator
.findHelper(id
);
1423 if (BoxedValueHelper
.class.isAssignableFrom(helperClass
))
1424 return (BoxedValueHelper
) helperClass
.newInstance();
1425 else if (helperClass
!= null)
1426 return new IDLTypeHelper(helperClass
);
1430 catch (Exception ex
)
1440 * Get the current position.
1442 static int getCurrentPosition(InputStream x
)
1444 if (x
instanceof gnuValueStream
)
1445 return ((gnuValueStream
) x
).getPosition();
1451 * Instantiate an instance of this class anyway; also in the case when it has
1452 * no parameterless or any other constructor. The fields will be assigned
1453 * while reading the class from the stream.
1455 * @param clazz a class for that the instance should be instantiated.
1457 public static Object
instantiateAnyWay(Class clazz
)
1460 Class first_nonserial
= clazz
;
1462 while (Serializable
.class.isAssignableFrom(first_nonserial
)
1463 || Modifier
.isAbstract(first_nonserial
.getModifiers()))
1464 first_nonserial
= first_nonserial
.getSuperclass();
1466 final Class local_constructor_class
= first_nonserial
;
1468 Constructor constructor
= local_constructor_class
.getDeclaredConstructor(new Class
[0]);
1470 return VMVio
.allocateObject(clazz
, constructor
.getDeclaringClass(),