Dead
[official-gcc.git] / gomp-20050608-branch / libjava / classpath / gnu / CORBA / CDR / Vio.java
blobfd878cb3555eed79d954a2b0c28152bc27b6c534
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)
9 any later version.
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
19 02110-1301 USA.
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
24 combination.
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;
68 /**
69 * A specialised class for reading and writing the value types.
71 * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
73 public abstract class Vio
75 /**
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
83 * false).
85 public static boolean USE_CHUNKING = false;
87 /**
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;
94 /**
95 * The value tag flag, indicating that the codebase URL is present in the
96 * value tag record.
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
131 * null.
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.
189 input.mark(512);
191 int value_tag = input.read_long();
192 checkTag(value_tag);
194 String codebase = null;
195 String[] ids = null;
196 String id = repository_id;
198 // Check for the agreed null value.
199 if (value_tag == vt_NULL)
200 return null;
201 else if (value_tag == vt_INDIRECTION)
202 return readIndirection(input);
203 else
205 // Read the value.
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;
230 if (helper != null)
231 ox = null; // Helper will care about the instantiating.
232 else if (id.equals(WStringValueHelper.id()))
233 helper = m_StringValueHelper;
234 else
235 ox = createInstance(id, ids, codebase);
236 return (Serializable) read_instance(input, position, ox, value_tag,
237 helper, id, ids, codebase);
239 catch (Exception ex)
241 MARSHAL m = new MARSHAL();
242 m.minor = Minor.Value;
243 m.initCause(ex);
244 throw m;
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);
263 String id = null;
264 String[] ids = null;
265 String codebase = null;
269 int value_tag = input.read_long();
270 checkTag(value_tag);
272 // Check for the agreed null value.
273 if (value_tag == vt_NULL)
274 return null;
275 else if (value_tag == vt_INDIRECTION)
276 return readIndirection(input);
277 else
279 // Read the value.
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);
301 java.lang.Object ox;
303 if (vHelper == null)
307 ox = createInstance(id, ids, codebase);
309 catch (Exception e)
311 ox = null;
314 if (ox != null)
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;
322 throw m;
326 else
327 ox = null;
329 ox = read_instance(input, position, ox, value_tag, vHelper, id, ids,
330 codebase);
331 return (Serializable) ox;
333 catch (MARSHAL m)
335 throw m;
337 catch (SystemException sysEx)
339 // OK.
340 throw sysEx;
342 catch (Exception ex)
344 MARSHAL m = new MARSHAL("Cant read " + value_class);
345 m.minor = Minor.Value;
346 m.initCause(ex);
347 throw m;
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
363 * should be null.
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);
374 String id = null;
375 String[] ids = null;
376 String codebase = null;
380 int value_tag = input.read_long();
381 checkTag(value_tag);
383 // Check for the agreed null value.
384 if (value_tag == vt_NULL)
385 return null;
386 else if (value_tag == vt_INDIRECTION)
387 return readIndirection(input);
388 else
390 // Read the value.
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();
412 if (helper == null)
413 helper = id != null ? getHelper(value_class, id) : getHelper(
414 value_class, ids);
416 value_instance = read_instance(input, position, value_instance,
417 value_tag, helper, id, ids, codebase);
418 return value_instance;
420 catch (Exception ex)
422 MARSHAL m = new MARSHAL();
423 m.minor = Minor.Value;
424 m.initCause(ex);
425 throw m;
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()))
469 value = null;
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);
485 else
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;
498 else
500 BufferedCdrOutput bout = new BufferedCdrOutput();
501 int c;
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;
513 m.initCause(ex);
514 throw m;
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());
536 else
537 bout.setRunTime(new gnuRuntime(null, null));
538 return bout;
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
547 * must be read.
548 * @param output the output stream where the unchunked nested value must be
549 * copied.
551 * @return the tag that ended the nested value.
553 public static int readNestedValue(int value_tag, InputStream input,
554 BufferedCdrOutput output, int level)
555 throws IOException
557 String id = null;
558 if (level < -1)
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;
568 throw m;
570 else if (value_tag == vt_NULL)
572 MARSHAL m = new MARSHAL("readNestedValue: nul");
573 m.minor = Minor.Chunks;
574 throw m;
576 else if (value_tag == vt_INDIRECTION)
578 MARSHAL m = new MARSHAL("readNestedValue: indirection");
579 m.minor = Minor.Chunks;
580 throw m;
582 else
584 // Read the value.
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);
595 id = ids[0];
596 write_string_array(output, ids);
598 else if ((value_tag & vf_ID) != 0)
600 id = read_string(input);
601 write_string(output, id);
606 int n = -1;
608 // Read all chunks.
609 int chunk_size;
611 byte[] r = null;
613 while (true)
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)
621 return chunk_size;
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)
632 return chunk_size;
634 else
636 // The chunk follows.
637 if (r == null || r.length < chunk_size)
638 r = new byte[chunk_size + 256];
640 n = 0;
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,
653 String codebase)
655 gnuRuntime g;
656 gnuValueStream c = ((gnuValueStream) input);
657 if (c.getRunTime() == null)
659 g = new gnuRuntime(codebase, value);
660 c.setRunTime(g);
662 else
664 g = c.getRunTime();
665 g.addCodeBase(codebase);
666 g.target = (Serializable) value;
668 if (value != null)
669 g.objectWritten(value, position);
671 if (input instanceof HeadlessInput)
672 ((HeadlessInput) input).subsequentCalls = false;
674 boolean ok = true;
676 // The user-defined io operations are implemented.
677 if (value instanceof CustomMarshal)
679 CustomMarshal marsh = (CustomMarshal) value;
680 marsh.unmarshal((DataInputStream) input);
682 else
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);
694 else
696 ok = false;
697 ValueFactory factory = null;
698 org.omg.CORBA_2_3.ORB orb = (org.omg.CORBA_2_3.ORB) input.orb();
700 if (id != null)
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]);
711 if (factory != null)
713 value = factory.read_value((org.omg.CORBA_2_3.portable.InputStream) input);
714 ok = true;
718 if (!ok && value instanceof Serializable)
719 // Delegate to ValueHandler
721 if (ids != null && ids.length > 0)
722 id = ids[0];
724 value = handler.readValue(input, position, value.getClass(), id, g);
725 ok = true;
728 if (!ok)
730 if (value != null)
732 MARSHAL m = new MARSHAL(value.getClass().getName()
733 + " must be Streamable, CustomMarshal or Serializable");
734 m.minor = Minor.UnsupportedValue;
735 throw m;
737 else
739 MARSHAL m = new MARSHAL("Unable to instantiate " + id + ":" + list(ids)
740 + " helper " + helper);
741 m.minor = Minor.UnsupportedValue;
742 throw m;
745 else
746 return (Serializable) value;
750 * Conveniency method to list ids in exception reports.
752 static String list(String[] s)
754 if (s == null)
755 return "null";
756 else
758 StringBuffer b = new StringBuffer("{");
759 for (int i = 0; i < s.length; i++)
761 b.append(s[i]);
762 b.append(" ");
764 b.append("}");
765 return b.toString();
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
775 * CustomMarshal.
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.
782 if (value == null)
783 output.write_long(vt_NULL);
784 else if (value instanceof String)
785 write(output, value, m_StringValueHelper);
786 else
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,
801 Class substitute)
803 // Write null if this is a null value.
804 if (value == null)
805 output.write_long(vt_NULL);
806 else if (value instanceof String || substitute == String.class)
807 writeString(output, value);
808 else
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));
813 else
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
820 // ids.
821 if (h == null)
822 write_instance(output, value, ids, null);
823 else
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
832 * passed value.
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.
844 if (value == null)
845 output.write_long(vt_NULL);
846 else
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)
866 if (value == null)
867 output.write_long(vt_NULL);
868 else
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)
884 if (helper == null)
885 throw new AssertionError("Helper must be provided");
886 if (value == null)
887 output.write_long(vt_NULL);
888 else
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
903 * null.
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
908 * array).
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)
922 int position;
923 rout = (gnuValueStream) output;
924 runtime = rout.getRunTime();
926 if (runtime == null)
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());
938 return;
940 else
942 position = runtime.isWrittenAt(value);
943 if (position >= 0)
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.
949 return;
951 else
953 runtime.objectWritten(value, position = rout.getPosition());
958 int value_tag = vt_VALUE_TAG;
960 if (ids instanceof String)
961 value_tag |= vf_ID;
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;
968 OutputStream outObj;
970 if (USE_CHUNKING)
972 // Wrap the value being written into one chunk (makes sense only for
973 // compatibility reasons).
974 outObj = output;
975 value_tag |= vf_CHUNKING;
977 else
978 outObj = output;
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);
987 if (USE_CHUNKING)
989 // So far, write 0x55555555 instead of the chunk size (alignment may
990 // take place).
991 output.write_long(0x55555555);
992 // If the chunking is involved, the chunk size must be written here.
993 chunkSizeLocation = rout.getPosition() - INT_SIZE;
995 else
996 // Not in use for this case.
997 chunkSizeLocation = -1;
999 writeValue(outObj, value, helper);
1001 if (USE_CHUNKING)
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);
1008 rout.seek(current);
1010 // The end of record marker.
1011 output.write_long(-1);
1014 finally
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;
1028 if (helper != null)
1029 helper.write_value(output, value);
1030 else if (!writeSelf(output, value))
1032 // Try to find helper via class loader.
1033 boolean ok = false;
1035 if (!ok)
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);
1059 return true;
1061 else if (value instanceof Streamable)
1063 ((Streamable) value)._write(output);
1064 return true;
1066 return false;
1070 * Read the indirection data and return the object that was already written to
1071 * this stream.
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;
1091 throw m;
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;
1100 throw m;
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;
1121 throw m;
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;
1129 throw m;
1134 * Throw MARSHAL.
1136 static void throwIt(String msg, String id1, String id2, Throwable e)
1137 throws MARSHAL
1139 MARSHAL m = new MARSHAL(msg + ":'" + id1 + "' versus '" + id2 + "'");
1140 if (e != null)
1141 m.initCause(e);
1142 m.minor = Minor.Value;
1143 throw m;
1147 * Load class by name and create the instance.
1149 static Object createInstance(String id, String[] ids, String codebase)
1151 Object o = null;
1153 if (id != null)
1154 o = _createInstance(id, codebase);
1156 if (ids != null)
1157 for (int i = 0; i < ids.length && o == null; i++)
1158 o = _createInstance(ids[i], codebase);
1159 return o;
1162 static Object _createInstance(String id, String codebase)
1164 if (id == null)
1165 return null;
1166 if (id.equals(StringValueHelper.id()))
1167 return "";
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();
1177 String sid = null;
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);
1201 if (h1 != h2)
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);
1208 if (s1 != s2)
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;
1225 m.initCause(ex);
1226 throw m;
1229 else
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)
1243 g.seek(previous);
1244 String s = input.read_string();
1245 if (g.getRunTime() == null)
1246 g.setRunTime(new gnuRuntime(null, null));
1247 g.getRunTime().singleIdWritten(s, previous);
1248 return s;
1250 else
1252 gnuRuntime r = g.getRunTime();
1253 int base = g.getPosition();
1254 int delta = input.read_long();
1255 if (r == null)
1257 previous = g.getPosition();
1258 g.seek(base + delta);
1259 String indir = input.read_string();
1260 g.seek(previous);
1261 return indir;
1263 else
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)
1280 g.seek(previous);
1281 String[] s = StringSeqHelper.read(input);
1282 if (g.getRunTime() == null)
1283 g.setRunTime(new gnuRuntime(null, null));
1284 g.getRunTime().objectWritten(s, previous);
1285 return s;
1287 else
1289 gnuRuntime r = g.getRunTime();
1290 int base = g.getPosition();
1291 int delta = input.read_long();
1292 if (r == null)
1294 previous = g.getPosition();
1295 g.seek(base + delta);
1296 String[] indir = StringSeqHelper.read(input);
1297 g.seek(previous);
1298 return indir;
1300 else
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;
1315 if (b != null)
1317 int written = b.getRunTime().idWrittenAt(id);
1318 if (written >= 0)
1320 // Reuse existing id record.
1321 output.write_long(vt_INDIRECTION);
1322 int p = b.getPosition();
1323 output.write_long(written - p);
1325 else
1327 b.getRunTime().singleIdWritten(id, b.getPosition());
1328 output.write_string(id);
1332 else
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;
1344 if (b != null)
1346 int written = b.getRunTime().idWrittenAt(ids);
1347 if (written >= 0)
1349 // Reuse existing id record.
1350 output.write_long(vt_INDIRECTION);
1351 int p = b.getPosition();
1352 output.write_long(written - p);
1354 else
1356 b.getRunTime().multipleIdsWritten(ids, b.getPosition());
1357 StringSeqHelper.write(output, ids);
1361 else
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;
1380 BoxedValueHelper h;
1381 for (int i = 0; i < ia.length; i++)
1383 h = locateHelper(ia[i]);
1384 if (h != null)
1385 return h;
1387 return null;
1389 else
1390 return null;
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);
1403 else
1404 return locateHelper(id);
1408 * Try to locate helper from the repository id.
1410 static BoxedValueHelper locateHelper(String id)
1412 if (id != null)
1414 if (id.equals(m_StringValueHelper.get_id()))
1415 return m_StringValueHelper;
1416 else
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);
1427 else
1428 return null;
1430 catch (Exception ex)
1432 return null;
1436 return null;
1440 * Get the current position.
1442 static int getCurrentPosition(InputStream x)
1444 if (x instanceof gnuValueStream)
1445 return ((gnuValueStream) x).getPosition();
1446 else
1447 return 0;
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)
1458 throws Exception
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(),
1471 constructor);