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 gnu.java.lang.CPStringBuilder;
46 import org.omg.CORBA.CustomMarshal;
47 import org.omg.CORBA.DataInputStream;
48 import org.omg.CORBA.DataOutputStream;
49 import org.omg.CORBA.MARSHAL;
50 import org.omg.CORBA.NO_IMPLEMENT;
51 import org.omg.CORBA.StringSeqHelper;
52 import org.omg.CORBA.StringValueHelper;
53 import org.omg.CORBA.SystemException;
54 import org.omg.CORBA.WStringValueHelper;
55 import org.omg.CORBA.portable.BoxedValueHelper;
56 import org.omg.CORBA.portable.InputStream;
57 import org.omg.CORBA.portable.OutputStream;
58 import org.omg.CORBA.portable.Streamable;
59 import org.omg.CORBA.portable.ValueFactory;
61 import java.io.IOException;
62 import java.io.Serializable;
63 import java.lang.reflect.Constructor;
64 import java.lang.reflect.Modifier;
65 import java.util.StringTokenizer;
67 import javax.rmi.CORBA.Util;
68 import javax.rmi.CORBA.ValueHandler;
71 * A specialised class for reading and writing the value types.
73 * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
75 public abstract class Vio
78 * If true, wrap value type data into chunks. This decrease the performance,
79 * and is not required for interoperability with jdk 1.5, but is left in the
80 * implementation as the optional mode for solving possible interoperability
81 * problems with non-Sun CORBA implementations.
83 * The current implementation would accept both single chunk or multiple
84 * chunks, but will always send a single chunk (if true) or unchunked data (if
87 public static boolean USE_CHUNKING = false;
90 * The first field in the value record. The last octet may contain additional
91 * flags (vf_CODEBASE, vf_ID and vf_MULTIPLE_IDS). The tag value is different
92 * for the indirections (vt_INDIRECTION) and nulls (vt_NULL).
94 public static final int vt_VALUE_TAG = 0x7fffff00;
97 * The value tag flag, indicating that the codebase URL is present in the
100 public static final int vf_CODEBASE = 0x1;
103 * The value tag flag, indicating that a single repository id is present in
104 * the value tag record.
106 public static final int vf_ID = 0x2;
109 * The value tag flag, indicating, that there are multiple repository ids
110 * present in the record. If this flag is set, the flag vf_ID must also be
111 * set, resulting the value of the least significant byte 0x6.
113 public static final int vf_MULTIPLE_IDS = 0x4;
116 * The value tag flag, indicating the presence of chunking. Each chunk is
117 * preceeded by a positive int, indicating the number of bytes in the chunk. A
118 * sequence of chunks is terminated by a non positive int.
120 public static final int vf_CHUNKING = 0x8;
123 * The indirection tag value. Such tag must be followed by the CORBA long,
124 * indicating the offset in the CORBA message, where the indirected
125 * information is present. This offset is assumed zero at the position where
126 * the mentioned CORBA long starts and can refer both forward (positive
127 * values) and backward (negative values).
129 public static final int vt_INDIRECTION = 0xffffffff;
132 * This tag value means that the value object being transferred is equal to
135 public static final int vt_NULL = 0x0;
138 * The size of CORBA long (java int).
140 static final int INT_SIZE = 4;
143 * The String value helper (one instance is sufficient).
145 public static final WStringValueHelper m_StringValueHelper = new WStringValueHelper();
148 * An instance of the value handler.
150 static ValueHandler handler = Util.createValueHandler();
153 * Read the value base from the given input stream. Determines the required
154 * class from the repository id. This includes operations that are not
155 * required when an unitialised instance or at least class of the value type
156 * is known. Hence it may be faster to use the alternative methods,
157 * read(InputStream, Class) or read(InputStream, Serializable).
159 * @param input a stream to read from.
161 * @return the loaded value.
163 * @throws MARSHAL if the reading has failed due any reason.
165 public static Serializable read(InputStream input)
167 return read(input, (String) null);
171 * Read the value base from the given input stream. Determines the required
172 * class from the repository id. This includes operations that are not
173 * required when an unitialised instance or at least class of the value type
174 * is known. Hence it may be faster to use the alternative methods,
175 * read(InputStream, Class) or read(InputStream, Serializable).
177 * @param input a stream to read from.
178 * @param repository_id a repository id of the object being read, may be null.
180 * @return the loaded value.
182 * @throws MARSHAL if the reading has failed due any reason.
184 public static Serializable read(InputStream input, String repository_id)
188 final int position = getCurrentPosition(input);
189 // We may need to jump back if the value is read via value factory.
192 int value_tag = input.read_long();
195 String codebase = null;
197 String id = repository_id;
199 // Check for the agreed null value.
200 if (value_tag == vt_NULL)
202 else if (value_tag == vt_INDIRECTION)
203 return readIndirection(input);
207 if ((value_tag & vf_CODEBASE) != 0)
209 // The codebase is present. The codebase is a space
210 // separated list of URLs from where the implementing
211 // code can be downloaded.
212 codebase = read_string(input);
215 if ((value_tag & vf_MULTIPLE_IDS) != 0)
217 // Multiple supported repository ids are present.
218 ids = read_string_array(input);
220 else if ((value_tag & vf_ID) != 0)
222 // Single supported repository id is present.
223 id = read_string(input);
227 BoxedValueHelper helper = getHelper(null, id);
228 // The existing implementing object.
229 java.lang.Object ox = null;
232 ox = null; // Helper will care about the instantiating.
233 else if (id.equals(WStringValueHelper.id()))
234 helper = m_StringValueHelper;
236 ox = createInstance(id, ids, codebase);
237 return (Serializable) read_instance(input, position, ox, value_tag,
238 helper, id, ids, codebase);
242 MARSHAL m = new MARSHAL();
243 m.minor = Minor.Value;
250 * Read the value base from the given input stream when the value base class
251 * is available. Hence there is no need to guess it from the repository id.
253 * @param input a stream to read from.
254 * @param value_class the class of the value being read.
256 * @return the loaded value.
258 * @throws MARSHAL if the reading has failed due any reason.
260 public static Serializable read(InputStream input, Class value_class)
262 final int position = getCurrentPosition(input);
266 String codebase = null;
270 int value_tag = input.read_long();
273 // Check for the agreed null value.
274 if (value_tag == vt_NULL)
276 else if (value_tag == vt_INDIRECTION)
277 return readIndirection(input);
281 if ((value_tag & vf_CODEBASE) != 0)
283 // The codebase is present.
284 codebase = read_string(input);
287 if ((value_tag & vf_MULTIPLE_IDS) != 0)
289 // Multiple supported repository ids are present.
290 ids = read_string_array(input);
292 else if ((value_tag & vf_ID) != 0)
294 // Single supported repository id is present.
295 id = read_string(input);
299 BoxedValueHelper vHelper = id != null ? getHelper(value_class, id)
300 : getHelper(value_class, ids);
308 ox = createInstance(id, ids, codebase);
317 if (value_class != null
318 && !value_class.isAssignableFrom(ox.getClass()))
320 MARSHAL m = new MARSHAL(ox.getClass() + " is not a "
321 + value_class.getName());
322 m.minor = Minor.ClassCast;
330 ox = read_instance(input, position, ox, value_tag, vHelper, id, ids,
332 return (Serializable) ox;
338 catch (SystemException sysEx)
345 MARSHAL m = new MARSHAL("Cant read " + value_class);
346 m.minor = Minor.Value;
353 * Read the value base from the given input stream when the unitialised
354 * instance is available. Hence there is no need to guess the class from the
355 * repository id and then to instantiate an instance.
357 * @param input a stream to read from.
359 * @param value_instance an pre-created instance of the value. If the helper
360 * is not null, this parameter is ignored an should be null.
362 * @param helper a helper to create an instance and read the object- specific
363 * part of the record. If the value_instance is used instead, this parameter
366 * @return the loaded value.
368 * @throws MARSHAL if the reading has failed due any reason.
370 public static Object read(InputStream input, Object value_instance,
371 BoxedValueHelper helper)
373 final int position = getCurrentPosition(input);
377 String codebase = null;
381 int value_tag = input.read_long();
384 // Check for the agreed null value.
385 if (value_tag == vt_NULL)
387 else if (value_tag == vt_INDIRECTION)
388 return readIndirection(input);
392 if ((value_tag & vf_CODEBASE) != 0)
394 // The codebase is present.
395 codebase = read_string(input);
398 if ((value_tag & vf_MULTIPLE_IDS) != 0)
400 // Multiple supported repository ids are present.
401 ids = read_string_array(input);
403 else if ((value_tag & vf_ID) != 0)
405 // Single supported repository id is present.
406 id = read_string(input);
410 Class value_class = value_instance == null ? null
411 : value_instance.getClass();
414 helper = id != null ? getHelper(value_class, id) : getHelper(
417 value_instance = read_instance(input, position, value_instance,
418 value_tag, helper, id, ids, codebase);
419 return value_instance;
423 MARSHAL m = new MARSHAL();
424 m.minor = Minor.Value;
431 * Read using provided boxed value helper. This method expects the full value
432 * type header, followed by contents, that are delegated to the provided
433 * helper. It handles null.
435 * @param input the stream to read from.
436 * @param helper the helper that reads the type-specific part of the content.
438 * @return the value, created by the helper, or null if the header indicates
439 * that null was previously written.
441 public static Serializable read(InputStream input, BoxedValueHelper helper)
443 return (Serializable) read(input, null, helper);
447 * Fill in the instance fields by the data from the input stream. The method
448 * assumes that the value header, if any, is already behind. The information
449 * from the stream is stored into the passed ox parameter.
451 * @param input an input stream to read from.
453 * @param value a pre-instantiated value type object, must be either
454 * Streamable or CustomMarshal. If the helper is used, this parameter is
455 * ignored and should be null.
457 * @param value_tag the tag that must be read previously.
458 * @param helper the helper for read object specific part; may be null to read
459 * in using other methods.
461 * @return the value that was read.
463 static Object read_instance(InputStream input, final int position,
464 Object value, int value_tag, BoxedValueHelper helper, String id,
465 String[] ids, String codebase)
467 if (helper != m_StringValueHelper && id != null)
468 if (id.equals(StringValueHelper.id()))
471 helper = m_StringValueHelper;
476 if ((value_tag & vf_CHUNKING) != 0)
478 BufferedCdrOutput output = createBuffer(input, 1024);
479 // Read the current (not a nested one) value in this spec case.
480 readNestedValue(value_tag, input, output, -1);
481 BufferredCdrInput ci = new BufferredCdrInput(output.buffer.getBuffer());
482 ci.setRunTime(output.getRunTime());
484 input = new HeadlessInput(ci, input);
488 if (input instanceof BufferredCdrInput)
490 // Highly probable case.
491 input = new HeadlessInput((BufferredCdrInput) input, null);
493 else if (input instanceof HeadlessInput)
495 // There is no need to instantiate one more HeadlessInput
496 // as we can just reset.
497 ((HeadlessInput) input).subsequentCalls = false;
501 BufferedCdrOutput bout = new BufferedCdrOutput();
503 while ((c = input.read()) >= 0)
504 bout.write((byte) c);
505 input = new HeadlessInput(
506 (BufferredCdrInput) bout.create_input_stream(), input);
510 catch (IOException ex)
512 MARSHAL m = new MARSHAL("Unable to read chunks");
513 m.minor = Minor.Value;
518 return readValue(input, position, value, helper, id, ids, codebase);
522 * Create a buffer, inheriting critical settings from the passed input stream.
524 private static BufferedCdrOutput createBuffer(InputStream input, int proposed_size)
526 BufferedCdrOutput bout;
527 bout = new BufferedCdrOutput(2 * proposed_size + 256);
529 if (input instanceof BufferredCdrInput)
531 BufferredCdrInput in = (BufferredCdrInput) input;
532 bout.setBigEndian(in.isBigEndian());
535 if (input instanceof gnuValueStream)
536 bout.setRunTime(((gnuValueStream) input).getRunTime());
538 bout.setRunTime(new gnuRuntime(null, null));
543 * Read the chunked nested value from the given input stream, transferring the
544 * contents to the given output stream.
546 * @param value_tag the value tag of the value being read.
547 * @param input the input stream from where the remainder of the nested value
549 * @param output the output stream where the unchunked nested value must be
552 * @return the tag that ended the nested value.
554 public static int readNestedValue(int value_tag, InputStream input,
555 BufferedCdrOutput output, int level)
561 // For the first level, this information is already behind.
562 output.write_long(value_tag - vf_CHUNKING);
564 // The nested value should be aways chunked.
565 if ((value_tag & vf_CHUNKING) == 0)
567 MARSHAL m = new MARSHAL("readNestedValue: must be chunked");
568 m.minor = Minor.Chunks;
571 else if (value_tag == vt_NULL)
573 MARSHAL m = new MARSHAL("readNestedValue: nul");
574 m.minor = Minor.Chunks;
577 else if (value_tag == vt_INDIRECTION)
579 MARSHAL m = new MARSHAL("readNestedValue: indirection");
580 m.minor = Minor.Chunks;
586 if ((value_tag & vf_CODEBASE) != 0)
588 String codebase = read_string(input);
589 write_string(output, codebase);
592 if ((value_tag & vf_MULTIPLE_IDS) != 0)
594 // Multiple supported repository ids are present.
595 String[] ids = read_string_array(input);
597 write_string_array(output, ids);
599 else if ((value_tag & vf_ID) != 0)
601 id = read_string(input);
602 write_string(output, id);
616 // Read the size of the next chunk or it may also be the
617 // header of the nested value.
618 chunk_size = input.read_long();
620 // End of chunk terminator.
621 if (chunk_size < 0 && chunk_size >= level)
623 else if (chunk_size >= 0x7FFFFF00)
625 int onInput = getCurrentPosition(input) - 4;
626 int onOutput = output.getPosition();
627 output.getRunTime().redirect(onInput, onOutput);
628 // Value over 0x7FFFFF00 indicates that the nested value
629 // starts here. Read the nested value, storing it into the output.
630 // First parameter is actually the value tag.
631 chunk_size = readNestedValue(chunk_size, input, output, level - 1);
632 if (chunk_size < 0 && chunk_size >= level)
637 // The chunk follows.
638 if (r == null || r.length < chunk_size)
639 r = new byte[chunk_size + 256];
642 while (n < chunk_size)
643 n += input.read(r, n, chunk_size - n);
644 output.write(r, 0, n);
650 * Read the value (the header must be behind).
652 public static Serializable readValue(InputStream input, final int position,
653 Object value, BoxedValueHelper helper, String id, String[] ids,
657 gnuValueStream c = ((gnuValueStream) input);
658 if (c.getRunTime() == null)
660 g = new gnuRuntime(codebase, value);
666 g.addCodeBase(codebase);
667 g.target = (Serializable) value;
670 g.objectWritten(value, position);
672 if (input instanceof HeadlessInput)
673 ((HeadlessInput) input).subsequentCalls = false;
677 // The user-defined io operations are implemented.
678 if (value instanceof CustomMarshal)
680 CustomMarshal marsh = (CustomMarshal) value;
681 marsh.unmarshal((DataInputStream) input);
684 // The IDL-generated io operations are implemented.
685 if (value instanceof Streamable)
687 ((Streamable) value)._read(input);
689 else if (helper != null)
691 // If helper is non-null the value should normally be null.
692 value = helper.read_value(input);
693 g.objectWritten(value, position);
698 ValueFactory factory = null;
699 org.omg.CORBA_2_3.ORB orb = (org.omg.CORBA_2_3.ORB) input.orb();
702 factory = orb.lookup_value_factory(id);
704 if (factory == null && ids != null)
706 for (int i = 0; i < ids.length && factory == null; i++)
708 factory = orb.lookup_value_factory(ids[i]);
714 value = factory.read_value((org.omg.CORBA_2_3.portable.InputStream) input);
719 if (!ok && value instanceof Serializable)
720 // Delegate to ValueHandler
722 if (ids != null && ids.length > 0)
725 value = handler.readValue(input, position, value.getClass(), id, g);
733 MARSHAL m = new MARSHAL(value.getClass().getName()
734 + " must be Streamable, CustomMarshal or Serializable");
735 m.minor = Minor.UnsupportedValue;
740 MARSHAL m = new MARSHAL("Unable to instantiate " + id + ":" + list(ids)
741 + " helper " + helper);
742 m.minor = Minor.UnsupportedValue;
747 return (Serializable) value;
751 * Conveniency method to list ids in exception reports.
753 static String list(String[] s)
759 CPStringBuilder b = new CPStringBuilder("{");
760 for (int i = 0; i < s.length; i++)
771 * Write the value base into the given stream.
773 * @param output a stream to write to.
775 * @param value a value type object, must be either Streamable or
778 * @throws MARSHAL if the writing failed due any reason.
780 public static void write(OutputStream output, Serializable value)
782 // Write null if this is a null value.
784 output.write_long(vt_NULL);
785 else if (value instanceof String)
786 write(output, value, m_StringValueHelper);
788 write(output, value, value.getClass());
792 * Write the value base into the given stream, stating that it is an instance
793 * of the given class.
795 * @param output a stream to write to.
797 * @param value a value to write.
799 * @throws MARSHAL if the writing failed due any reason.
801 public static void write(OutputStream output, Serializable value,
804 // Write null if this is a null value.
806 output.write_long(vt_NULL);
807 else if (value instanceof String || substitute == String.class)
808 writeString(output, value);
811 String vId = ObjectCreator.getRepositoryId(value.getClass());
812 if (substitute == null || value.getClass().equals(substitute))
813 write_instance(output, value, vId, getHelper(value.getClass(), vId));
816 String vC = ObjectCreator.getRepositoryId(substitute);
817 String[] ids = new String[] { vId, vC };
818 BoxedValueHelper h = getHelper(substitute.getClass(), ids);
819 // If the helper is available, it is also responsible for
820 // providing the repository Id. Otherwise, write both
823 write_instance(output, value, ids, null);
825 write_instance(output, value, h.get_id(), null);
831 * Write the value base into the given stream, supplementing it with an array
832 * of the provided repository ids plus the repository id, derived from the
835 * @param output a stream to write to.
837 * @param value a value to write.
839 * @throws MARSHAL if the writing failed due any reason.
841 public static void write(OutputStream output, Serializable value,
842 String[] multiple_ids)
844 // Write null if this is a null value.
846 output.write_long(vt_NULL);
849 String[] ids = new String[multiple_ids.length + 1];
850 ids[0] = ObjectCreator.getRepositoryId(value.getClass());
851 System.arraycopy(multiple_ids, 0, ids, 1, multiple_ids.length);
852 BoxedValueHelper h = getHelper(value.getClass(), ids);
853 write_instance(output, value, ids, h);
858 * Write value when its repository Id is explicitly given. Only this Id is
859 * written, the type of value is not taken into consideration.
861 * @param output an output stream to write into.
862 * @param value a value to write.
863 * @param id a value repository id.
865 public static void write(OutputStream output, Serializable value, String id)
868 output.write_long(vt_NULL);
870 write_instance(output, value, id, getHelper(value.getClass(), id));
874 * Write standard value type header, followed by contents, produced by the
875 * boxed value helper.
877 * @param output the stream to write to.
878 * @param value the value to write, can be null.
879 * @param helper the helper that writes the value content if it is not null
880 * (must be provided for this method).
882 public static void write(OutputStream output, Serializable value,
883 BoxedValueHelper helper)
886 throw new AssertionError("Helper must be provided");
888 output.write_long(vt_NULL);
890 write_instance(output, value, helper.get_id(), helper);
894 * Write the parameter that is surely a string and not null.
896 private static void writeString(OutputStream output, Serializable string)
898 write_instance(output, string, m_StringValueHelper.get_id(),
899 m_StringValueHelper);
903 * Write value when its repository Id is explicitly given. Does not handle
906 * @param output an output stream to write into.
907 * @param value a value to write.
908 * @param ids a value repository id (can be either single string or string
910 * @param helper a helper, writing object - specifical part. Can be null if
911 * the value should be written using other methods.
913 static void write_instance(OutputStream output, Serializable value,
914 Object ids, BoxedValueHelper helper)
916 gnuValueStream rout = null;
917 gnuRuntime runtime = null;
921 if (output instanceof gnuValueStream)
924 rout = (gnuValueStream) output;
925 runtime = rout.getRunTime();
929 runtime = new gnuRuntime(null, value);
930 rout.setRunTime(runtime);
931 rout.getRunTime().objectWritten(value,
932 position = rout.getPosition());
934 else if (runtime.target == value)
936 if (!writeSelf(output, value))
937 throw new InternalError("Recursive helper call for "
938 + value.getClass().getName());
943 position = runtime.isWrittenAt(value);
946 // The object was already written.
947 output.write_long(vt_INDIRECTION);
948 output.write_long(position - rout.getPosition());
949 // Replacing object write data by indirection reference.
954 runtime.objectWritten(value, position = rout.getPosition());
959 int value_tag = vt_VALUE_TAG;
961 if (ids instanceof String)
963 else if (ids instanceof String[])
964 // OMG standard requires to set both flags.
965 value_tag |= vf_MULTIPLE_IDS | vf_ID;
967 int chunkSizeLocation;
973 // Wrap the value being written into one chunk (makes sense only for
974 // compatibility reasons).
976 value_tag |= vf_CHUNKING;
981 output.write_long(value_tag);
983 if ((value_tag & vf_MULTIPLE_IDS) != 0)
984 write_string_array(output, (String[]) ids);
985 else if ((value_tag & vf_ID) != 0)
986 write_string(output, (String) ids);
990 // So far, write 0x55555555 instead of the chunk size (alignment may
992 output.write_long(0x55555555);
993 // If the chunking is involved, the chunk size must be written here.
994 chunkSizeLocation = rout.getPosition() - INT_SIZE;
997 // Not in use for this case.
998 chunkSizeLocation = -1;
1000 writeValue(outObj, value, helper);
1004 // Write the chunk size where the place for it was reserved.
1005 int chunkSize = rout.getPosition() - chunkSizeLocation - INT_SIZE;
1006 int current = rout.getPosition();
1007 rout.seek(chunkSizeLocation);
1008 output.write_long(chunkSize);
1011 // The end of record marker.
1012 output.write_long(-1);
1017 if (runtime != null)
1018 runtime.target = null;
1023 * Write value (after header).
1025 static void writeValue(OutputStream output, Serializable value,
1026 BoxedValueHelper helper)
1028 ((gnuValueStream) output).getRunTime().target = value;
1030 helper.write_value(output, value);
1031 else if (!writeSelf(output, value))
1033 // Try to find helper via class loader.
1038 if (output instanceof BufferedCdrOutput)
1040 BufferedCdrOutput b = (BufferedCdrOutput) output;
1041 if (b.runtime == null)
1042 b.runtime = new gnuRuntime(null, value);
1045 handler.writeValue(output, value);
1051 * Try to write value supposing that it implements self-streamable interfaces.
1052 * Return false if it does not or true on success.
1054 static boolean writeSelf(OutputStream output, Serializable value)
1056 // User defined write method is present.
1057 if (value instanceof CustomMarshal)
1059 ((CustomMarshal) value).marshal((DataOutputStream) output);
1062 else if (value instanceof Streamable)
1064 ((Streamable) value)._write(output);
1071 * Read the indirection data and return the object that was already written to
1074 * @param an_input the input stream, must be BufferredCdrInput.
1076 static Serializable readIndirection(InputStream an_input)
1078 if (!(an_input instanceof gnuValueStream))
1079 throw new NO_IMPLEMENT(gnuValueStream.class.getName()
1080 + " expected as parameter");
1082 gnuValueStream in = (gnuValueStream) an_input;
1084 int current_pos = in.getPosition();
1086 int offset = an_input.read_long();
1087 if (offset > -INT_SIZE)
1089 MARSHAL m = new MARSHAL("Indirection tag refers to " + offset
1090 + " (must be less than -" + INT_SIZE + ")");
1091 m.minor = Minor.Offset;
1095 int stored_at = current_pos + offset;
1097 if (in.getRunTime() == null)
1099 MARSHAL m = new MARSHAL(stored_at + " offset " + offset + ": not written");
1100 m.minor = Minor.Value;
1104 return (Serializable) in.getRunTime().isObjectWrittenAt(stored_at, offset);
1108 * Check the passed value tag for correctness.
1110 * @param value_tag a tag to check, must be between 0x7fffff00 and 0x7fffffff
1112 * @throws MARSHAL if the tag is outside this interval.
1114 static void checkTag(int value_tag)
1116 if ((value_tag < 0x7fffff00 || value_tag > 0x7fffffff)
1117 && value_tag != vt_NULL && value_tag != vt_INDIRECTION)
1119 MARSHAL m = new MARSHAL("Invalid value record, unsupported header tag: "
1120 + value_tag + " (0x" + Integer.toHexString(value_tag) + ")");
1121 m.minor = Minor.ValueHeaderTag;
1125 if ((value_tag & vf_MULTIPLE_IDS) != 0 && (value_tag & vf_ID) == 0)
1127 MARSHAL m = new MARSHAL("Invalid value record header flag combination (0x"
1128 + Integer.toHexString(value_tag) + ")");
1129 m.minor = Minor.ValueHeaderFlags;
1137 static void throwIt(String msg, String id1, String id2, Throwable e)
1140 MARSHAL m = new MARSHAL(msg + ":'" + id1 + "' versus '" + id2 + "'");
1143 m.minor = Minor.Value;
1148 * Load class by name and create the instance.
1150 static Object createInstance(String id, String[] ids, String codebase)
1155 o = _createInstance(id, codebase);
1158 for (int i = 0; i < ids.length && o == null; i++)
1159 o = _createInstance(ids[i], codebase);
1163 static Object _createInstance(String id, String codebase)
1167 if (id.equals(StringValueHelper.id()))
1169 StringTokenizer st = new StringTokenizer(id, ":");
1171 String prefix = st.nextToken();
1172 if (prefix.equalsIgnoreCase("IDL"))
1173 return ObjectCreator.Idl2Object(id);
1174 else if (prefix.equalsIgnoreCase("RMI"))
1176 String className = st.nextToken();
1177 String hashCode = st.nextToken();
1179 if (st.hasMoreElements())
1180 sid = st.nextToken();
1184 Class objectClass = Util.loadClass(className, codebase,
1185 Vio.class.getClassLoader());
1187 String rid = ObjectCreator.getRepositoryId(objectClass);
1189 if (!rid.equals(id))
1191 // If direct string comparison fails, compare by meaning.
1192 StringTokenizer st2 = new StringTokenizer(rid, ":");
1193 if (!st2.nextToken().equals("RMI"))
1194 throw new InternalError("RMI format expected: '" + rid + "'");
1195 if (!st2.nextToken().equals(className))
1196 throwIt("Class name mismatch", id, rid, null);
1200 long h1 = Long.parseLong(hashCode, 16);
1201 long h2 = Long.parseLong(st2.nextToken(), 16);
1203 throwIt("Hashcode mismatch", id, rid, null);
1205 if (sid != null && st2.hasMoreTokens())
1207 long s1 = Long.parseLong(hashCode, 16);
1208 long s2 = Long.parseLong(st2.nextToken(), 16);
1210 throwIt("serialVersionUID mismatch", id, rid, null);
1213 catch (NumberFormatException e)
1215 throwIt("Invalid hashcode or svuid format: ", id, rid, e);
1219 // Low - level instantiation required here.
1220 return instantiateAnyWay(objectClass);
1222 catch (Exception ex)
1224 MARSHAL m = new MARSHAL("Unable to instantiate " + id);
1225 m.minor = Minor.Instantiation;
1231 throw new NO_IMPLEMENT("Unsupported prefix " + prefix + ":");
1235 * Read string, expecting the probable indirection.
1237 static String read_string(InputStream input)
1239 gnuValueStream g = (gnuValueStream) input;
1240 int previous = g.getPosition();
1241 int l = input.read_long();
1242 if (l != vt_INDIRECTION)
1245 String s = input.read_string();
1246 if (g.getRunTime() == null)
1247 g.setRunTime(new gnuRuntime(null, null));
1248 g.getRunTime().singleIdWritten(s, previous);
1253 gnuRuntime r = g.getRunTime();
1254 int base = g.getPosition();
1255 int delta = input.read_long();
1258 previous = g.getPosition();
1259 g.seek(base + delta);
1260 String indir = input.read_string();
1266 return (String) r.isObjectWrittenAt(base + delta, delta);
1272 * Read string array, expecting the probable indirection.
1274 static String[] read_string_array(InputStream input)
1276 gnuValueStream g = (gnuValueStream) input;
1277 int previous = g.getPosition();
1278 int l = input.read_long();
1279 if (l != vt_INDIRECTION)
1282 String[] s = StringSeqHelper.read(input);
1283 if (g.getRunTime() == null)
1284 g.setRunTime(new gnuRuntime(null, null));
1285 g.getRunTime().objectWritten(s, previous);
1290 gnuRuntime r = g.getRunTime();
1291 int base = g.getPosition();
1292 int delta = input.read_long();
1295 previous = g.getPosition();
1296 g.seek(base + delta);
1297 String[] indir = StringSeqHelper.read(input);
1303 return (String[]) r.isObjectWrittenAt(base + delta, delta);
1309 * Write repository Id, probably shared.
1311 static void write_string(OutputStream output, String id)
1313 if (output instanceof gnuValueStream)
1315 gnuValueStream b = (gnuValueStream) output;
1318 int written = b.getRunTime().idWrittenAt(id);
1321 // Reuse existing id record.
1322 output.write_long(vt_INDIRECTION);
1323 int p = b.getPosition();
1324 output.write_long(written - p);
1328 b.getRunTime().singleIdWritten(id, b.getPosition());
1329 output.write_string(id);
1334 output.write_string(id);
1338 * Write repository Id, probably shared.
1340 static void write_string_array(OutputStream output, String[] ids)
1342 if (output instanceof gnuValueStream)
1344 gnuValueStream b = (gnuValueStream) output;
1347 int written = b.getRunTime().idWrittenAt(ids);
1350 // Reuse existing id record.
1351 output.write_long(vt_INDIRECTION);
1352 int p = b.getPosition();
1353 output.write_long(written - p);
1357 b.getRunTime().multipleIdsWritten(ids, b.getPosition());
1358 StringSeqHelper.write(output, ids);
1363 StringSeqHelper.write(output, ids);
1367 * Get the helper that could write the given object, or null if no pre-defined
1368 * helper available for this object.
1370 public static BoxedValueHelper getHelper(Class x, Object ids)
1372 if (x != null && x.equals(String.class))
1373 return m_StringValueHelper;
1374 else if (x != null && x.isArray())
1375 return new ArrayValueHelper(x);
1376 else if (ids instanceof String)
1377 return locateHelper((String) ids);
1378 else if (ids instanceof String[])
1380 String[] ia = (String[]) ids;
1382 for (int i = 0; i < ia.length; i++)
1384 h = locateHelper(ia[i]);
1395 * Get the helper that could write the given object, or null if no pre-defined
1396 * helper available for this object.
1398 public static BoxedValueHelper getHelper(Class x, String id)
1400 if (x != null && x.equals(String.class))
1401 return m_StringValueHelper;
1402 else if (x != null && x.isArray())
1403 return new ArrayValueHelper(x);
1405 return locateHelper(id);
1409 * Try to locate helper from the repository id.
1411 static BoxedValueHelper locateHelper(String id)
1415 if (id.equals(m_StringValueHelper.get_id()))
1416 return m_StringValueHelper;
1418 // Try to locate helper for IDL type.
1419 if (id.startsWith("IDL:"))
1423 Class helperClass = ObjectCreator.findHelper(id);
1424 if (BoxedValueHelper.class.isAssignableFrom(helperClass))
1425 return (BoxedValueHelper) helperClass.newInstance();
1426 else if (helperClass != null)
1427 return new IDLTypeHelper(helperClass);
1431 catch (Exception ex)
1441 * Get the current position.
1443 static int getCurrentPosition(InputStream x)
1445 if (x instanceof gnuValueStream)
1446 return ((gnuValueStream) x).getPosition();
1452 * Instantiate an instance of this class anyway; also in the case when it has
1453 * no parameterless or any other constructor. The fields will be assigned
1454 * while reading the class from the stream.
1456 * @param clazz a class for that the instance should be instantiated.
1458 public static Object instantiateAnyWay(Class clazz)
1461 Class first_nonserial = clazz;
1463 while (Serializable.class.isAssignableFrom(first_nonserial)
1464 || Modifier.isAbstract(first_nonserial.getModifiers()))
1465 first_nonserial = first_nonserial.getSuperclass();
1467 final Class local_constructor_class = first_nonserial;
1469 Constructor constructor = local_constructor_class.getDeclaredConstructor(new Class[0]);
1471 return VMVio.allocateObject(clazz, constructor.getDeclaringClass(),