/[classpath]/classpath/gnu/CORBA/CDR/Vio.java
ViewVC logotype

Diff of /classpath/gnu/CORBA/CDR/Vio.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.2.2.3 by gnu_andrew, Sat Sep 10 15:31:35 2005 UTC revision 1.2.2.4 by gnu_andrew, Wed Nov 2 00:43:24 2005 UTC
# Line 1  Line 1 
1  /* gnuValueBaseHelper.java --  /* Vio.java -- Value type IO operations.
2     Copyright (C) 2005 Free Software Foundation, Inc.     Copyright (C) 2005 Free Software Foundation, Inc.
3    
4  This file is part of GNU Classpath.  This file is part of GNU Classpath.
# Line 38  exception statement from your version. * Line 38  exception statement from your version. *
38    
39  package gnu.CORBA.CDR;  package gnu.CORBA.CDR;
40    
41    import gnu.CORBA.Minor;
42  import gnu.CORBA.ObjectCreator;  import gnu.CORBA.ObjectCreator;
43    
44  import org.omg.CORBA.CustomMarshal;  import org.omg.CORBA.CustomMarshal;
# Line 46  import org.omg.CORBA.DataOutputStream; Line 47  import org.omg.CORBA.DataOutputStream;
47  import org.omg.CORBA.MARSHAL;  import org.omg.CORBA.MARSHAL;
48  import org.omg.CORBA.NO_IMPLEMENT;  import org.omg.CORBA.NO_IMPLEMENT;
49  import org.omg.CORBA.StringSeqHelper;  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;  import org.omg.CORBA.portable.BoxedValueHelper;
54  import org.omg.CORBA.portable.InputStream;  import org.omg.CORBA.portable.InputStream;
55  import org.omg.CORBA.portable.OutputStream;  import org.omg.CORBA.portable.OutputStream;
56  import org.omg.CORBA.portable.Streamable;  import org.omg.CORBA.portable.Streamable;
57  import org.omg.CORBA.portable.ValueFactory;  import org.omg.CORBA.portable.ValueFactory;
58    
 import java.io.ByteArrayOutputStream;  
59  import java.io.IOException;  import java.io.IOException;
60  import java.io.Serializable;  import java.io.Serializable;
61    import java.lang.reflect.Constructor;
62    import java.lang.reflect.Modifier;
63    import java.util.StringTokenizer;
64    
65  import java.lang.reflect.Method;  import javax.rmi.CORBA.Util;
66    import javax.rmi.CORBA.ValueHandler;
67    
68  /**  /**
69   * A specialised class for reading and writing the value types.   * A specialised class for reading and writing the value types.
70   *   *
71   * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)   * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
72   */   */
73  public abstract class Vio  public abstract class Vio
74  {  {
75    /**    /**
76     * If true, wrap value type data into chunks. This decrease the     * If true, wrap value type data into chunks. This decrease the performance,
77     * performance, but is required for the interoperability with     * and is not required for interoperability with jdk 1.5, but is left in the
78     * Sun's CORBA implementation. Chunking may increase the security,     * implementation as the optional mode for solving possible interoperability
79     * as there is more control on the number of bytes being transferred.     * problems with non-Sun CORBA implementations.
80     *     *
81     * The current implementation would accept both single chunk or multiple     * The current implementation would accept both single chunk or multiple
82     * chunks, but will always send a single chunk.     * chunks, but will always send a single chunk (if true) or unchunked data (if
83       * false).
84     */     */
85    public static boolean USE_CHUNKING = true;    public static boolean USE_CHUNKING = false;
86    
87    /**    /**
88     * The first field in the value record. The last octet may contain     * The first field in the value record. The last octet may contain additional
89     * additional flags (vf_CODEBASE, vf_ID and vf_MULTIPLE_IDS). The tag     * flags (vf_CODEBASE, vf_ID and vf_MULTIPLE_IDS). The tag value is different
90     * value is different for the indirections (vt_INDIRECTION) and     * for the indirections (vt_INDIRECTION) and nulls (vt_NULL).
    * nulls (vt_NULL).  
91     */     */
92    public static final int vt_VALUE_TAG = 0x7fffff00;    public static final int vt_VALUE_TAG = 0x7fffff00;
93    
94    /**    /**
95     * The value tag flag, indicating that the codebase URL is present     * The value tag flag, indicating that the codebase URL is present in the
96     * in the value tag record.     * value tag record.
97     */     */
98    public static final int vf_CODEBASE = 0x1;    public static final int vf_CODEBASE = 0x1;
99    
100    /**    /**
101     * The value tag flag, indicating that a single repository id is present     * The value tag flag, indicating that a single repository id is present in
102     * in the value tag record.     * the value tag record.
103     */     */
104    public static final int vf_ID = 0x2;    public static final int vf_ID = 0x2;
105    
106    /**    /**
107     * The value tag flag, indicating, that there are multiple repository     * The value tag flag, indicating, that there are multiple repository ids
108     * ids present in the record. If this flag is set, the flag vf_ID must     * present in the record. If this flag is set, the flag vf_ID must also be
109     * also be set, resulting the value of the least significant byte 0x6.     * set, resulting the value of the least significant byte 0x6.
110     */     */
111    public static final int vf_MULTIPLE_IDS = 0x4;    public static final int vf_MULTIPLE_IDS = 0x4;
112    
113    /**    /**
114     * The value tag flag, indicating the presence of chunking. Each chunk is     * 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.     * preceeded by a positive int, indicating the number of bytes in the chunk. A
116     * A sequence of chunks is terminated by a non positive int.     * sequence of chunks is terminated by a non positive int.
117     */     */
118    public static final int vf_CHUNKING = 0x8;    public static final int vf_CHUNKING = 0x8;
119    
120    /**    /**
121     * The indirection tag value. Such tag must be followed by the CORBA long,     * The indirection tag value. Such tag must be followed by the CORBA long,
122     * indicating the offset in the CORBA message, where the indirected     * indicating the offset in the CORBA message, where the indirected
123     * information is present. This offset is assumed zero at the position     * information is present. This offset is assumed zero at the position where
124     * where the mentioned CORBA long starts and can refer both forward     * the mentioned CORBA long starts and can refer both forward (positive
125     * (positive values) and backward (negative values).     * values) and backward (negative values).
126     */     */
127    public static final int vt_INDIRECTION = 0xffffffff;    public static final int vt_INDIRECTION = 0xffffffff;
128    
129    /**    /**
130     * This tag value means that the value object being transferred is equal     * This tag value means that the value object being transferred is equal to
131     * to null.     * null.
132     */     */
133    public static final int vt_NULL = 0x0;    public static final int vt_NULL = 0x0;
134    
135    /**    /**
136     * Read the value base from the given input stream. Determines the     * The size of CORBA long (java int).
137     * required class from the repository id. This includes operations     */
138     * that are not required when an unitialised instance or at least    static final int INT_SIZE = 4;
139     * class of the value type is known. Hence it may be faster to use  
140     * the alternative methods, read(InputStream, Class) or    /**
141     * read(InputStream, Serializable).     * The String value helper (one instance is sufficient).
142     *     */
143      public static final WStringValueHelper m_StringValueHelper = new WStringValueHelper();
144    
145      /**
146       * An instance of the value handler.
147       */
148      static ValueHandler handler = Util.createValueHandler();
149    
150      /**
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).
156       *
157     * @param input a stream to read from.     * @param input a stream to read from.
158     *     * @param repository_id a repository id of the object being read, may be null.
159       *
160     * @return the loaded value.     * @return the loaded value.
161     *     *
162     * @throws MARSHAL if the reading has failed due any reason.     * @throws MARSHAL if the reading has failed due any reason.
163     */     */
164    public static Serializable read(InputStream input)    public static Serializable read(InputStream input)
165    {    {
166      // Explicitly prevent the stream from closing as we may need      return read(input, (String) null);
167      // to read the subsequent bytes as well. Stream may be auto-closed    }
168      // in its finalizer.  
169      /**
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).
175       *
176       * @param an_input a stream to read from.
177       * @param repository_id a repository id of the object being read, may be null.
178       *
179       * @return the loaded value.
180       *
181       * @throws MARSHAL if the reading has failed due any reason.
182       */
183      public static Serializable read(InputStream input, String repository_id)
184      {
185      try      try
186        {        {
187            final int position = getCurrentPosition(input);
188          // We may need to jump back if the value is read via value factory.          // We may need to jump back if the value is read via value factory.
189          input.mark(512);          input.mark(512);
190    
# Line 154  public abstract class Vio Line 193  public abstract class Vio
193    
194          String codebase = null;          String codebase = null;
195          String[] ids = null;          String[] ids = null;
196          String id = null;          String id = repository_id;
   
         // The existing implementing object.  
         java.lang.Object ox = null;  
197    
198          // Check for the agreed null value.          // Check for the agreed null value.
199          if (value_tag == vt_NULL)          if (value_tag == vt_NULL)
200            return null;            return null;
201          else if (value_tag == vt_INDIRECTION)          else if (value_tag == vt_INDIRECTION)
202              return readIndirection(input);
           // TODO FIXME Implement support for indirections.  
           throw new NO_IMPLEMENT("Indirections unsupported");  
203          else          else
204            {            {
205              // Read the value.              // Read the value.
# Line 174  public abstract class Vio Line 208  public abstract class Vio
208                  // The codebase is present. The codebase is a space                  // The codebase is present. The codebase is a space
209                  // separated list of URLs from where the implementing                  // separated list of URLs from where the implementing
210                  // code can be downloaded.                  // code can be downloaded.
211                  codebase = input.read_string();                  codebase = read_string(input);
212                }                }
213    
214              if ((value_tag & vf_MULTIPLE_IDS) != 0)              if ((value_tag & vf_MULTIPLE_IDS) != 0)
215                {                {
216                  // Multiple supported repository ids are present.                  // Multiple supported repository ids are present.
217                  ids = StringSeqHelper.read(input);                  ids = read_string_array(input);
                 for (int i = 0; (i < ids.length) && (ox == null); i++)  
                   {  
                     ox = ObjectCreator.Idl2Object(ids [ i ]);  
   
                     if (ox == null)  
                       {  
                         // Try to find the value factory.  
                         ValueFactory f =  
                           ((org.omg.CORBA_2_3.ORB) input.orb()).lookup_value_factory(ids [ i ]);  
   
                         if (f != null)  
                           {  
                             // Reset, as the value factory reads from beginning.  
                             input.reset();  
                             return f.read_value((org.omg.CORBA_2_3.portable.InputStream) input);  
                           }  
                       }  
                   }  
218                }                }
219              else if ((value_tag & vf_ID) != 0)              else if ((value_tag & vf_ID) != 0)
220                {                {
221                  // Single supported repository id is present.                  // Single supported repository id is present.
222                  id = input.read_string();                  id = read_string(input);
                 ox = ObjectCreator.Idl2Object(id);  
   
                 if (ox == null)  
                   {  
                     // Try to find the value factory.  
                     ValueFactory f =  
                       ((org.omg.CORBA_2_3.ORB) input.orb()).lookup_value_factory(id);  
   
                     if (f != null)  
                       {  
                         input.reset();  
                         return f.read_value((org.omg.CORBA_2_3.portable.InputStream) input);  
                       }  
                   }  
223                }                }
224            }            }
225    
226          if (ox == null)          BoxedValueHelper helper = getHelper(null, id);
227            throw new MARSHAL("Unable to instantiate the value type");          // The existing implementing object.
228            java.lang.Object ox = null;
229    
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          else
235            {            ox = createInstance(id, ids, codebase);
236              read_instance(input, ox, value_tag, null);          return (Serializable) read_instance(input, position, ox, value_tag,
237              return (Serializable) ox;            helper, id, ids, codebase);
           }  
238        }        }
239      catch (Exception ex)      catch (Exception ex)
240        {        {
241          throw new MARSHAL(ex + ":" + ex.getMessage());          MARSHAL m = new MARSHAL();
242            m.minor = Minor.Value;        
243            m.initCause(ex);
244            throw m;
245        }        }
246    }    }
247    
248    /**    /**
249     * Read the value base from the given input stream when     * Read the value base from the given input stream when the value base class
250     * the value base class is available. Hence there is no need     * is available. Hence there is no need to guess it from the repository id.
251     * to guess it from the repository id.     *
    *  
252     * @param input a stream to read from.     * @param input a stream to read from.
253     * @param value_class the class of the value being read.     * @param value_class the class of the value being read.
254     *     *
255     * @return the loaded value.     * @return the loaded value.
256     *     *
257     * @throws MARSHAL if the reading has failed due any reason.     * @throws MARSHAL if the reading has failed due any reason.
258     */     */
259    public static Serializable read(InputStream input, Class value_class)    public static Serializable read(InputStream input, Class value_class)
260    {    {
261      // Explicitly prevent the stream from closing as we may need      final int position = getCurrentPosition(input);
262      // to read the subsequent bytes as well. Stream may be auto-closed  
263      // in its finalizer.      String id = null;
264        String[] ids = null;
265        String codebase = null;
266    
267      try      try
268        {        {
269          int value_tag = input.read_long();          int value_tag = input.read_long();
270          checkTag(value_tag);          checkTag(value_tag);
271    
         // The existing implementing object.  
         java.lang.Object ox = value_class.newInstance();  
   
272          // Check for the agreed null value.          // Check for the agreed null value.
273          if (value_tag == vt_NULL)          if (value_tag == vt_NULL)
274            return null;            return null;
275          else if (value_tag == vt_INDIRECTION)          else if (value_tag == vt_INDIRECTION)
276              return readIndirection(input);
           // TODO FIXME Implement support for indirections.  
           throw new NO_IMPLEMENT("Indirections unsupported");  
277          else          else
278            {            {
279              // Read the value.              // Read the value.
280              if ((value_tag & vf_CODEBASE) != 0)              if ((value_tag & vf_CODEBASE) != 0)
281                {                {
282                  // The codebase is present, but skip it.                  // The codebase is present.
283                  input.read_string();                  codebase = read_string(input);
284                }                }
285    
286              if ((value_tag & vf_MULTIPLE_IDS) != 0)              if ((value_tag & vf_MULTIPLE_IDS) != 0)
287                {                {
288                  // Multiple supported repository ids are present, but skip them.                  // Multiple supported repository ids are present.
289                  StringSeqHelper.read(input);                  ids = read_string_array(input);
290                }                }
291              else if ((value_tag & vf_ID) != 0)              else if ((value_tag & vf_ID) != 0)
292                {                {
293                  // Single supported repository id is present, but skip it.                  // Single supported repository id is present.
294                  input.read_string();                  id = read_string(input);
295                  }
296              }
297    
298            BoxedValueHelper vHelper = id != null ? getHelper(value_class, id)
299              : getHelper(value_class, ids);
300    
301            java.lang.Object ox;
302    
303            if (vHelper == null)
304              {
305                try
306                  {
307                    ox = createInstance(id, ids, codebase);
308                  }
309                catch (Exception e)
310                  {
311                    ox = null;
312                  }
313    
314                if (ox != null)
315                  {
316                    if (value_class != null
317                      && !value_class.isAssignableFrom(ox.getClass()))
318                      {
319                        MARSHAL m = new MARSHAL(ox.getClass() + " is not a "
320                        + value_class.getName());
321                        m.minor = Minor.ClassCast;
322                        throw m;
323                      }
324                }                }
325            }            }
326            else
327              ox = null;
328    
329          read_instance(input, ox, value_tag, null);          ox = read_instance(input, position, ox, value_tag, vHelper, id, ids,
330              codebase);
331          return (Serializable) ox;          return (Serializable) ox;
332        }        }
333        catch (MARSHAL m)
334          {
335            throw m;
336          }
337        catch (SystemException sysEx)
338          {
339            // OK.
340            throw sysEx;
341          }
342      catch (Exception ex)      catch (Exception ex)
343        {        {
344          throw new MARSHAL(ex + ":" + ex.getMessage());          MARSHAL m = new MARSHAL("Cant read " + value_class);
345            m.minor = Minor.Value;
346            m.initCause(ex);
347            throw m;
348        }        }
349    }    }
350    
351    /**    /**
352     * Read the value base from the given input stream when     * Read the value base from the given input stream when the unitialised
353     * the unitialised instance is available. Hence there is no need     * instance is available. Hence there is no need to guess the class from the
354     * to guess the class from the repository id and then to instantiate     * repository id and then to instantiate an instance.
355     * an instance.     *
    *  
356     * @param input a stream to read from.     * @param input a stream to read from.
357     *     *
358     * @param value_instance an pre-created instance of the value. If the     * @param value_instance an pre-created instance of the value. If the helper
359     * helper is not null, this parameter is ignored an should be null.     * is not null, this parameter is ignored an should be null.
360     *     *
361     * @param helper a helper to create an instance and read the object-     * @param helper a helper to create an instance and read the object- specific
362     * specific part of the record. If the value_instance is used instead,     * part of the record. If the value_instance is used instead, this parameter
363     * this parameter should be null.     * should be null.
364     *     *
365     * @return the loaded value.     * @return the loaded value.
366     *     *
367     * @throws MARSHAL if the reading has failed due any reason.     * @throws MARSHAL if the reading has failed due any reason.
368     */     */
369    public static Object read(InputStream input, Object value_instance,    public static Object read(InputStream input, Object value_instance,
370      Object helper      BoxedValueHelper helper)
   )  
371    {    {
372        final int position = getCurrentPosition(input);
373    
374        String id = null;
375        String[] ids = null;
376        String codebase = null;
377    
378      try      try
379        {        {
380          int value_tag = input.read_long();          int value_tag = input.read_long();
# Line 329  public abstract class Vio Line 384  public abstract class Vio
384          if (value_tag == vt_NULL)          if (value_tag == vt_NULL)
385            return null;            return null;
386          else if (value_tag == vt_INDIRECTION)          else if (value_tag == vt_INDIRECTION)
387              return readIndirection(input);
           // TODO FIXME Implement support for indirections.  
           throw new NO_IMPLEMENT("Indirections unsupported");  
388          else          else
389            {            {
390              // Read the value.              // Read the value.
391              if ((value_tag & vf_CODEBASE) != 0)              if ((value_tag & vf_CODEBASE) != 0)
392                {                {
393                  // The codebase is present, but skip it.                  // The codebase is present.
394                  input.read_string();                  codebase = read_string(input);
395                }                }
396    
397              if ((value_tag & vf_MULTIPLE_IDS) != 0)              if ((value_tag & vf_MULTIPLE_IDS) != 0)
398                {                {
399                  // Multiple supported repository ids are present, but skip them.                  // Multiple supported repository ids are present.
400                  StringSeqHelper.read(input);                  ids = read_string_array(input);
401                }                }
402              else if ((value_tag & vf_ID) != 0)              else if ((value_tag & vf_ID) != 0)
403                {                {
404                  // Single supported repository id is present, but skip it.                  // Single supported repository id is present.
405                  input.read_string();                  id = read_string(input);
406                }                }
407            }            }
408    
409          value_instance =          Class value_class = value_instance == null ? null
410            read_instance(input, value_instance, value_tag, helper);            : value_instance.getClass();
411    
412            if (helper == null)
413              helper = id != null ? getHelper(value_class, id) : getHelper(
414                value_class, ids);
415    
416            value_instance = read_instance(input, position, value_instance,
417              value_tag, helper, id, ids, codebase);
418          return value_instance;          return value_instance;
419        }        }
420      catch (Exception ex)      catch (Exception ex)
421        {        {
422          throw new MARSHAL(ex + ":" + ex.getMessage());          MARSHAL m = new MARSHAL();
423            m.minor = Minor.Value;
424            m.initCause(ex);
425            throw m;
426        }        }
427    }    }
428    
429    /**    /**
430     * Read using provided boxed value helper. This method expects     * Read using provided boxed value helper. This method expects the full value
431     * the full value type header, followed by contents, that are     * type header, followed by contents, that are delegated to the provided
432     * delegated to the provided helper. It handles null.     * helper. It handles null.
433     *     *
434     * @param input the stream to read from.     * @param input the stream to read from.
435     * @param helper the helper that reads the type-specific part of     * @param helper the helper that reads the type-specific part of the content.
436     * the content.     *
437     *     * @return the value, created by the helper, or null if the header indicates
438     * @return the value, created by the helper, or null if the     * that null was previously written.
    * header indicates that null was previously written.  
439     */     */
440    public static Serializable read(InputStream input, Object helper)    public static Serializable read(InputStream input, BoxedValueHelper helper)
441    {    {
442      return (Serializable) read(input, null, helper);      return (Serializable) read(input, null, helper);
443    }    }
444    
445    /**    /**
446     * Fill in the instance fields by the data from the input stream.     * Fill in the instance fields by the data from the input stream. The method
447     * The method assumes that the value header, if any, is already     * assumes that the value header, if any, is already behind. The information
448     * behind. The information from the stream is stored into the     * from the stream is stored into the passed ox parameter.
449     * passed ox parameter.     *
    *  
450     * @param input an input stream to read from.     * @param input an input stream to read from.
451     *     *
452     * @param value a pre-instantiated value type object, must be either     * @param value a pre-instantiated value type object, must be either
453     * Streamable or CustomMarshal. If the helper is used, this parameter     * Streamable or CustomMarshal. If the helper is used, this parameter is
454     * is ignored and should be null.     * ignored and should be null.
455     *     *
456     * @param value_tag the tag that must be read previously.     * @param value_tag the tag that must be read previously.
457     * @param helper the helper for read object specific part; may be     * @param helper the helper for read object specific part; may be null to read
458     * null to read in using other methods.     * in using other methods.
459     *     *
460     * @return the value that was read.     * @return the value that was read.
461     */     */
462    private static Object read_instance(InputStream input, Object value,    static Object read_instance(InputStream input, final int position,
463      int value_tag, Object helper      Object value, int value_tag, BoxedValueHelper helper, String id,
464    )      String[] ids, String codebase)
465    {    {
466        if (helper != m_StringValueHelper && id != null)
467          if (id.equals(StringValueHelper.id()))
468            {
469              value = null;
470              helper = m_StringValueHelper;
471            }
472    
473      try      try
474        {        {
475          if ((value_tag & vf_CHUNKING) != 0)          if ((value_tag & vf_CHUNKING) != 0)
476            {            {
477              ByteArrayOutputStream bout = null;              BufferedCdrOutput output = createBuffer(input, 1024);
478              int n = -1;              // Read the current (not a nested one) value in this spec case.
479                readNestedValue(value_tag, input, output, -1);
480              // Read all chunks.              BufferredCdrInput ci = new BufferredCdrInput(output.buffer.getBuffer());
481              int chunk_size = input.read_long();              ci.setRunTime(output.getRunTime());
             if (chunk_size < 0)  
               throw new MARSHAL("Invalid first chunk size " + chunk_size);  
   
             byte[] r = new byte[ chunk_size ];  
   
             while (chunk_size > 0)  
               {  
                 if (r.length < chunk_size)  
                   r = new byte[ chunk_size + 256 ];  
   
                 n = 0;  
                 reading:  
                 while (n < chunk_size)  
                   n += input.read(r, n, r.length - n);  
   
                 // Read the size of the next chunk.  
                 chunk_size = input.read_long();  
   
                 // If the value is non negative, there is more than one chunk.  
                 // Accumulate chunks in the buffer.  
                 // The last chunk (or the only chunk, if only one chunk is  
                 // present) is not written in the buffer. It is stored in the  
                 // array r, avoiding unnecessary buffer operations.  
                 if (chunk_size > 0)  
                   {  
                     bout = new ByteArrayOutputStream(2 * chunk_size);  
                     bout.write(r, 0, chunk_size);  
                   }  
               }  
482    
483              if (bout != null)              input = new HeadlessInput(ci, input);
               {  
                 // More than one chunk was present.  
                 // Add the last chunk.  
                 bout.write(r, 0, n);  
                 input = new noHeaderInput(bout.toByteArray());  
               }  
             else  
               {  
                 // Only one chunk was present.  
                 input = new noHeaderInput(r);  
               }  
484            }            }
485          else          else
486            {            {
487              if (input instanceof cdrBufInput)              if (input instanceof BufferredCdrInput)
488                {                {
489                  // Highly probable case.                  // Highly probable case.
490                  input =                  input = new HeadlessInput((BufferredCdrInput) input, null);
491                    new noHeaderInput(((cdrBufInput) input).buffer.getBuffer());                }
492                else if (input instanceof HeadlessInput)
493                  {
494                    // There is no need to instantiate one more HeadlessInput
495                    // as we can just reset.
496                    ((HeadlessInput) input).subsequentCalls = false;
497                }                }
498              else              else
499                {                {
500                  cdrBufOutput bout = new cdrBufOutput();                  BufferedCdrOutput bout = new BufferedCdrOutput();
501                  int c;                  int c;
502                  while ((c = input.read()) >= 0)                  while ((c = input.read()) >= 0)
503                    bout.write((byte) c);                    bout.write((byte) c);
504                  input = new noHeaderInput(bout.buffer.toByteArray());                  input = new HeadlessInput(
505                      (BufferredCdrInput) bout.create_input_stream(), input);
506                }                }
507            }            }
508        }        }
509      catch (IOException ex)      catch (IOException ex)
510        {        {
511          MARSHAL m = new MARSHAL("Unable to read chunks");          MARSHAL m = new MARSHAL("Unable to read chunks");
512            m.minor = Minor.Value;
513          m.initCause(ex);          m.initCause(ex);
514          throw m;          throw m;
515        }        }
516    
517      // The user-defines io operations are implemented.      return readValue(input, position, value, helper, id, ids, codebase);
518      if (value instanceof CustomMarshal)    }
519    
520      /**
521       * Create a buffer, inheriting critical settings from the passed input stream.
522       */
523      private static BufferedCdrOutput createBuffer(InputStream input, int proposed_size)
524      {
525        BufferedCdrOutput bout;
526        bout = new BufferedCdrOutput(2 * proposed_size + 256);
527    
528        if (input instanceof BufferredCdrInput)
529        {        {
530          CustomMarshal marsh = (CustomMarshal) value;          BufferredCdrInput in = (BufferredCdrInput) input;
531          try          bout.setBigEndian(in.isBigEndian());
532          }
533    
534        if (input instanceof gnuValueStream)
535          bout.setRunTime(((gnuValueStream) input).getRunTime());
536        else
537          bout.setRunTime(new gnuRuntime(null, null));
538        return bout;
539      }
540    
541      /**
542       * Read the chunked nested value from the given input stream, transferring the
543       * contents to the given output stream.
544       *
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.
550       *
551       * @return the tag that ended the nested value.
552       */
553      public static int readNestedValue(int value_tag, InputStream input,
554        BufferedCdrOutput output, int level)
555        throws IOException
556      {
557        String id = null;
558        if (level < -1)
559          {
560            // For the first level, this information is already behind.
561            output.write_long(value_tag - vf_CHUNKING);
562    
563            // The nested value should be aways chunked.
564            if ((value_tag & vf_CHUNKING) == 0)
565            {            {
566              marsh.unmarshal((DataInputStream) input);              MARSHAL m = new MARSHAL("readNestedValue: must be chunked");
567                m.minor = Minor.Chunks;
568                throw m;
569            }            }
570          catch (ClassCastException ex)          else if (value_tag == vt_NULL)
571            {            {
572              incorrect_plug_in(ex);              MARSHAL m = new MARSHAL("readNestedValue: nul");
573                m.minor = Minor.Chunks;
574                throw m;
575              }
576            else if (value_tag == vt_INDIRECTION)
577              {
578                MARSHAL m = new MARSHAL("readNestedValue: indirection");
579                m.minor = Minor.Chunks;
580                throw m;
581              }
582            else
583              {
584                // Read the value.
585                if ((value_tag & vf_CODEBASE) != 0)
586                  {
587                    String codebase = read_string(input);
588                    write_string(output, codebase);
589                  }
590    
591                if ((value_tag & vf_MULTIPLE_IDS) != 0)
592                  {
593                    // Multiple supported repository ids are present.
594                    String[] ids = read_string_array(input);
595                    id = ids[0];
596                    write_string_array(output, ids);
597                  }
598                else if ((value_tag & vf_ID) != 0)
599                  {
600                    id = read_string(input);
601                    write_string(output, id);
602                  }
603              }
604          }
605    
606        int n = -1;
607    
608        // Read all chunks.
609        int chunk_size;
610    
611        byte[] r = null;
612    
613        while (true)
614          {
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();
618    
619            // End of chunk terminator.
620            if (chunk_size < 0 && chunk_size >= level)
621              return chunk_size;
622            else if (chunk_size >= 0x7FFFFF00)
623              {
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;
633              }
634            else
635              {
636                // The chunk follows.
637                if (r == null || r.length < chunk_size)
638                  r = new byte[chunk_size + 256];
639    
640                n = 0;
641                reading: while (n < chunk_size)
642                  n += input.read(r, n, chunk_size - n);
643                output.write(r, 0, n);
644            }            }
645        }        }
646      }
647    
648      /**
649       * Read the value (the header must be behind).
650       */
651      public static Serializable readValue(InputStream input, final int position,
652        Object value, BoxedValueHelper helper, String id, String[] ids,
653        String codebase)
654      {
655        gnuRuntime g;
656        gnuValueStream c = ((gnuValueStream) input);
657        if (c.getRunTime() == null)
658          {
659            g = new gnuRuntime(codebase, value);
660            c.setRunTime(g);
661          }
662        else
663          {
664            g = c.getRunTime();
665            g.addCodeBase(codebase);
666            g.target = (Serializable) value;
667          }
668        if (value != null)
669          g.objectWritten(value, position);
670    
671        if (input instanceof HeadlessInput)
672          ((HeadlessInput) input).subsequentCalls = false;
673    
674        boolean ok = true;
675    
676        // The user-defined io operations are implemented.
677        if (value instanceof CustomMarshal)
678          {
679            CustomMarshal marsh = (CustomMarshal) value;
680            marsh.unmarshal((DataInputStream) input);
681          }
682      else      else
683      // The IDL-generated io operations are implemented.      // The IDL-generated io operations are implemented.
684      if (value instanceof Streamable)      if (value instanceof Streamable)
685        {        {
686          ((Streamable) value)._read(input);          ((Streamable) value)._read(input);
687        }        }
688      else if (helper instanceof BoxedValueHelper)      else if (helper != null)
689        value = ((BoxedValueHelper) helper).read_value(input);        {
690      else if (helper instanceof ValueFactory)          // If helper is non-null the value should normally be null.
691        value =          value = helper.read_value(input);
692          ((ValueFactory) helper).read_value((org.omg.CORBA_2_3.portable.InputStream) input);          g.objectWritten(value, position);
693          }
694      else      else
695          {
696            ok = false;
697            ValueFactory factory = null;
698            org.omg.CORBA_2_3.ORB orb = (org.omg.CORBA_2_3.ORB) input.orb();
699    
700        // Stating the interfaces that the USER should use.          if (id != null)
701        throw new MARSHAL("The " + value.getClass().getName() +            factory = orb.lookup_value_factory(id);
         " must implement either StreamableValue or CustomValue."  
       );  
702    
703      // The negative end of state marker is expected from OMG standard.          if (factory == null && ids != null)
704      // If the chunking is used, this marker is already extracted.            {
705      if ((value_tag & vf_CHUNKING) == 0)              for (int i = 0; i < ids.length && factory == null; i++)
706                  {
707                    factory = orb.lookup_value_factory(ids[i]);
708                  }
709              }
710    
711            if (factory != null)
712              {
713                value = factory.read_value((org.omg.CORBA_2_3.portable.InputStream) input);
714                ok = true;
715              }
716          }
717    
718        if (!ok && value instanceof Serializable)
719        // Delegate to ValueHandler
720        {        {
721          int eor = input.read_long();          if (ids != null && ids.length > 0)
722          if (eor >= 0)            id = ids[0];
723            throw new MARSHAL("End of state marker has an invalid value " + eor);  
724            value = handler.readValue(input, position, value.getClass(), id, g);
725            ok = true;
726        }        }
727    
728      return value;      if (!ok)
729          {
730            if (value != null)
731              {
732                MARSHAL m = new MARSHAL(value.getClass().getName()
733                + " must be Streamable, CustomMarshal or Serializable");
734                m.minor = Minor.UnsupportedValue;
735                throw m;
736              }
737            else
738              {
739                MARSHAL m = new MARSHAL("Unable to instantiate " + id + ":" + list(ids)
740                + " helper " + helper);
741                m.minor = Minor.UnsupportedValue;
742                throw m;
743              }
744          }
745        else
746          return (Serializable) value;
747      }
748    
749      /**
750       * Conveniency method to list ids in exception reports.
751       */
752      static String list(String[] s)
753      {
754        if (s == null)
755          return "null";
756        else
757          {
758            StringBuffer b = new StringBuffer("{");
759            for (int i = 0; i < s.length; i++)
760              {
761                b.append(s[i]);
762                b.append(" ");
763              }
764            b.append("}");
765            return b.toString();
766          }
767    }    }
768    
769    /**    /**
770     * Write the value base into the given stream.     * Write the value base into the given stream.
771     *     *
772     * @param output a stream to write to.     * @param output a stream to write to.
773     *     *
774     * @param value a value type object, must be either Streamable or     * @param value a value type object, must be either Streamable or
775     * CustomMarshal.     * CustomMarshal.
776     *     *
777     * @throws MARSHAL if the writing failed due any reason.     * @throws MARSHAL if the writing failed due any reason.
778     */     */
779    public static void write(OutputStream output, Serializable value)    public static void write(OutputStream output, Serializable value)
# Line 537  public abstract class Vio Line 781  public abstract class Vio
781      // Write null if this is a null value.      // Write null if this is a null value.
782      if (value == null)      if (value == null)
783        output.write_long(vt_NULL);        output.write_long(vt_NULL);
784        else if (value instanceof String)
785          write(output, value, m_StringValueHelper);
786      else      else
787        write(output, value, ObjectCreator.toIDL(value.getClass().getName()));        write(output, value, value.getClass());
788    }    }
789    
790    /**    /**
791     * Write the value base into the given stream, stating that it is an     * Write the value base into the given stream, stating that it is an instance
792     * instance of the given class. The written record has no repository     * of the given class.
793     * id and requires to supply a class or initialised instance for reading     *
    * rather than an actual class it is.  
    *  
    * This results writing a different repository id.  
    *  
    * If the passed value implements the {@link CustomMarshal},  
    * the helper uses {@link CustomMarshal#marshal}  
    * to write the content in a user defined way. Otherwise,  
    * this implementation initialises the {@link ObjectOutputStream}  
    * and writes through it.  
    *  
794     * @param output a stream to write to.     * @param output a stream to write to.
795     *     *
796     * @param value a value to write.     * @param value a value to write.
797     *     *
798     * @throws MARSHAL if the writing failed due any reason.     * @throws MARSHAL if the writing failed due any reason.
799     */     */
800    public static void write(OutputStream output, Serializable value,    public static void write(OutputStream output, Serializable value,
801      Class substitute      Class substitute)
   )  
802    {    {
803      // Write null if this is a null value.      // Write null if this is a null value.
804      if (value == null)      if (value == null)
805        output.write_long(vt_NULL);        output.write_long(vt_NULL);
806        else if (value instanceof String || substitute == String.class)
807          writeString(output, value);
808        else
809          {
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
814              {
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);
825              }
826          }
827      }
828    
829      /**
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.
833       *
834       * @param output a stream to write to.
835       *
836       * @param value a value to write.
837       *
838       * @throws MARSHAL if the writing failed due any reason.
839       */
840      public static void write(OutputStream output, Serializable value,
841        String[] multiple_ids)
842      {
843        // Write null if this is a null value.
844        if (value == null)
845          output.write_long(vt_NULL);
846      else      else
847        write(output, value, ObjectCreator.toIDL(substitute.getName()));        {
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);
853          }
854    }    }
855    
856    /**    /**
857     * Write value when its repository Id is explicitly given.     * Write value when its repository Id is explicitly given. Only this Id is
858     *     * written, the type of value is not taken into consideration.
859       *
860     * @param output an output stream to write into.     * @param output an output stream to write into.
861     * @param value a value to write.     * @param value a value to write.
862     * @param id a value repository id.     * @param id a value repository id.
# Line 585  public abstract class Vio Line 866  public abstract class Vio
866      if (value == null)      if (value == null)
867        output.write_long(vt_NULL);        output.write_long(vt_NULL);
868      else      else
869        write_instance(output, value, id, null);        write_instance(output, value, id, getHelper(value.getClass(), id));
870    }    }
871    
872    /**    /**
873     * Write standard value type header, followed by contents, produced     * Write standard value type header, followed by contents, produced by the
874     * by the boxed value helper.     * boxed value helper.
875     *     *
876     * @param output the stream to write to.     * @param output the stream to write to.
877     * @param value the value to write, can be null.     * @param value the value to write, can be null.
878     * @param helper the helper that writes the value content if it is     * @param helper the helper that writes the value content if it is not null
879     * not null.     * (must be provided for this method).
880     */     */
881    public static void write(OutputStream output, Serializable value,    public static void write(OutputStream output, Serializable value,
882      Object helper      BoxedValueHelper helper)
   )  
883    {    {
884        if (helper == null)
885          throw new AssertionError("Helper must be provided");
886      if (value == null)      if (value == null)
887        output.write_long(vt_NULL);        output.write_long(vt_NULL);
888      else      else
889          write_instance(output, value, helper.get_id(), helper);
890      }
891    
892      /**
893       * Write the parameter that is surely a string and not null.
894       */
895      private static void writeString(OutputStream output, Serializable string)
896      {
897        write_instance(output, string, m_StringValueHelper.get_id(),
898          m_StringValueHelper);
899      }
900    
901      /**
902       * Write value when its repository Id is explicitly given. Does not handle
903       * null.
904       *
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.
911       */
912      static void write_instance(OutputStream output, Serializable value,
913        Object ids, BoxedValueHelper helper)
914      {
915        gnuValueStream rout = null;
916        gnuRuntime runtime = null;
917    
918        try
919        {        {
920          String id;          if (output instanceof gnuValueStream)
921              {
922                int position;
923                rout = (gnuValueStream) output;
924                runtime = rout.getRunTime();
925    
926                if (runtime == null)
927                  {
928                    runtime = new gnuRuntime(null, value);
929                    rout.setRunTime(runtime);
930                    rout.getRunTime().objectWritten(value,
931                      position = rout.getPosition());
932                  }
933                else if (runtime.target == value)
934                  {
935                    if (!writeSelf(output, value))
936                      throw new InternalError("Recursive helper call for "
937                        + value.getClass().getName());
938                    return;
939                  }
940                else
941                  {
942                    position = runtime.isWrittenAt(value);
943                    if (position >= 0)
944                      {
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;
950                      }
951                    else
952                      {
953                        runtime.objectWritten(value, position = rout.getPosition());
954                      }
955                  }
956              }
957    
958            int value_tag = vt_VALUE_TAG;
959    
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;
965    
966            int chunkSizeLocation;
967    
968            OutputStream outObj;
969    
970          if (helper instanceof BoxedValueHelper)          if (USE_CHUNKING)
971            id = ((BoxedValueHelper) helper).get_id();            {
972                // Wrap the value being written into one chunk (makes sense only for
973                // compatibility reasons).
974                outObj = output;
975                value_tag |= vf_CHUNKING;
976              }
977            else
978              outObj = output;
979    
980            output.write_long(value_tag);
981    
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);
986    
987            if (USE_CHUNKING)
988              {
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;
994              }
995          else          else
996            id = "";            // Not in use for this case.
997              chunkSizeLocation = -1;
998    
999            writeValue(outObj, value, helper);
1000    
1001            if (USE_CHUNKING)
1002              {
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);
1009    
1010          write_instance(output, value, id, helper);              // The end of record marker.
1011                output.write_long(-1);
1012              }
1013          }
1014        finally
1015          {
1016            if (runtime != null)
1017              runtime.target = null;
1018        }        }
1019    }    }
1020    
1021    /**    /**
1022     * Write value when its repository Id is explicitly given.     * Write value (after header).
1023     * Does not handle null.     */
1024     *    static void writeValue(OutputStream output, Serializable value,
1025     * @param output an output stream to write into.      BoxedValueHelper helper)
1026     * @param value a value to write.    {
1027     * @param id a value repository id.      ((gnuValueStream) output).getRunTime().target = value;
1028     * @param helper a helper, writing object - specifica part. Can be null      if (helper != null)
1029     * if the value should be written unsing other methods.        helper.write_value(output, value);
1030        else if (!writeSelf(output, value))
1031          {
1032            // Try to find helper via class loader.
1033            boolean ok = false;
1034    
1035            if (!ok)
1036              {
1037                if (output instanceof BufferedCdrOutput)
1038                  {
1039                    BufferedCdrOutput b = (BufferedCdrOutput) output;
1040                    if (b.runtime == null)
1041                      b.runtime = new gnuRuntime(null, value);
1042                  }
1043    
1044                handler.writeValue(output, value);
1045              }
1046          }
1047      }
1048    
1049      /**
1050       * Try to write value supposing that it implements self-streamable interfaces.
1051       * Return false if it does not or true on success.
1052     */     */
1053    private static void write_instance(OutputStream output, Serializable value,    static boolean writeSelf(OutputStream output, Serializable value)
     String id, Object helper  
   )  
1054    {    {
1055      // This implementation always writes a single repository id.      // User defined write method is present.
1056      // It never writes multiple repository ids and currently does not use      if (value instanceof CustomMarshal)
1057      // a codebase.        {
1058      int value_tag = vt_VALUE_TAG | vf_ID;          ((CustomMarshal) value).marshal((DataOutputStream) output);
1059            return true;
1060          }
1061        else if (value instanceof Streamable)
1062          {
1063            ((Streamable) value)._write(output);
1064            return true;
1065          }
1066        return false;
1067      }
1068    
1069      OutputStream outObj;    /**
1070      cdrBufOutput out = null;     * Read the indirection data and return the object that was already written to
1071       * this stream.
1072       *
1073       * @param an_input the input stream, must be BufferredCdrInput.
1074       */
1075      static Serializable readIndirection(InputStream an_input)
1076      {
1077        if (!(an_input instanceof gnuValueStream))
1078          throw new NO_IMPLEMENT(gnuValueStream.class.getName()
1079            + " expected as parameter");
1080    
1081        gnuValueStream in = (gnuValueStream) an_input;
1082    
1083        int current_pos = in.getPosition();
1084    
1085      if (USE_CHUNKING)      int offset = an_input.read_long();
1086        if (offset > -INT_SIZE)
1087        {        {
1088          out = new cdrBufOutput();          MARSHAL m = new MARSHAL("Indirection tag refers to " + offset
1089          out.setOrb(output.orb());          + " (must be less than -" + INT_SIZE + ")");
1090          outObj = out;          m.minor = Minor.Offset;
1091          value_tag |= vf_CHUNKING;          throw m;
1092        }        }
     else  
       outObj = output;  
1093    
1094      output.write_long(value_tag);      int stored_at = current_pos + offset;
     output.write_string(id);  
1095    
1096      if (helper instanceof BoxedValueHelper)      if (in.getRunTime() == null)
1097        {        {
1098          ((BoxedValueHelper) helper).write_value(outObj, value);          MARSHAL m = new MARSHAL(stored_at + " offset " + offset + ": not written");
1099            m.minor = Minor.Value;
1100            throw m;
1101        }        }
1102      else  
1103      // User defince write method is present.      return (Serializable) in.getRunTime().isObjectWrittenAt(stored_at, offset);
1104      if (value instanceof CustomMarshal)    }
1105    
1106      /**
1107       * Check the passed value tag for correctness.
1108       *
1109       * @param value_tag a tag to check, must be between 0x7fffff00 and 0x7fffffff
1110       *
1111       * @throws MARSHAL if the tag is outside this interval.
1112       */
1113      static void checkTag(int value_tag)
1114      {
1115        if ((value_tag < 0x7fffff00 || value_tag > 0x7fffffff)
1116          && value_tag != vt_NULL && value_tag != vt_INDIRECTION)
1117          {
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;
1122          }
1123    
1124        if ((value_tag & vf_MULTIPLE_IDS) != 0 && (value_tag & vf_ID) == 0)
1125          {
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;
1130          }
1131      }
1132    
1133      /**
1134       * Throw MARSHAL.
1135       */
1136      static void throwIt(String msg, String id1, String id2, Throwable e)
1137        throws MARSHAL
1138      {
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;
1144      }
1145    
1146      /**
1147       * Load class by name and create the instance.
1148       */
1149      static Object createInstance(String id, String[] ids, String codebase)
1150      {
1151        Object o = null;
1152    
1153        if (id != null)
1154          o = _createInstance(id, codebase);
1155    
1156        if (ids != null)
1157          for (int i = 0; i < ids.length && o == null; i++)
1158            o = _createInstance(ids[i], codebase);
1159        return o;
1160      }
1161    
1162      static Object _createInstance(String id, String codebase)
1163      {
1164        if (id == null)
1165          return null;
1166        if (id.equals(StringValueHelper.id()))
1167          return "";
1168        StringTokenizer st = new StringTokenizer(id, ":");
1169    
1170        String prefix = st.nextToken();
1171        if (prefix.equalsIgnoreCase("IDL"))
1172          return ObjectCreator.Idl2Object(id);
1173        else if (prefix.equalsIgnoreCase("RMI"))
1174        {        {
1175            String className = st.nextToken();
1176            String hashCode = st.nextToken();
1177            String sid = null;
1178            if (st.hasMoreElements())
1179              sid = st.nextToken();
1180    
1181          try          try
1182            {            {
1183              ((CustomMarshal) value).marshal((DataOutputStream) outObj);              Class objectClass = Util.loadClass(className, codebase,
1184                  Vio.class.getClassLoader());
1185    
1186                String rid = ObjectCreator.getRepositoryId(objectClass);
1187    
1188                if (!rid.equals(id))
1189                  {
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);
1196    
1197                    try
1198                      {
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);
1203    
1204                        if (sid != null && st2.hasMoreTokens())
1205                          {
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);
1210                          }
1211                      }
1212                    catch (NumberFormatException e)
1213                      {
1214                        throwIt("Invalid hashcode or svuid format: ", id, rid, e);
1215                      }
1216                  }
1217    
1218                // Low - level instantiation required here.
1219                return instantiateAnyWay(objectClass);
1220            }            }
1221          catch (ClassCastException ex)          catch (Exception ex)
1222            {            {
1223              incorrect_plug_in(ex);              MARSHAL m = new MARSHAL("Unable to instantiate " + id);
1224                m.minor = Minor.Instantiation;
1225                m.initCause(ex);
1226                throw m;
1227            }            }
1228        }        }
1229      else if (value instanceof Streamable)      else
1230          throw new NO_IMPLEMENT("Unsupported prefix " + prefix + ":");
1231      }
1232    
1233      /**
1234       * Read string, expecting the probable indirection.
1235       */
1236      static String read_string(InputStream input)
1237      {
1238        gnuValueStream g = (gnuValueStream) input;
1239        int previous = g.getPosition();
1240        int l = input.read_long();
1241        if (l != vt_INDIRECTION)
1242        {        {
1243          ((Streamable) value)._write(outObj);          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;
1249        }        }
1250      else      else
1251        {        {
1252          // Try to find helper via class loader.          gnuRuntime r = g.getRunTime();
1253          boolean ok = false;          int base = g.getPosition();
1254          try          int delta = input.read_long();
1255            if (r == null)
1256            {            {
1257              Class helperClass = Class.forName(ObjectCreator.toHelperName(id));              previous = g.getPosition();
1258                g.seek(base + delta);
1259                String indir = input.read_string();
1260                g.seek(previous);
1261                return indir;
1262              }
1263            else
1264              {
1265                return (String) r.isObjectWrittenAt(base + delta, delta);
1266              }
1267          }
1268      }
1269    
1270              // It will be the helper for the encapsulated boxed value, not the    /**
1271              // for the global boxed value type itself.     * Read string array, expecting the probable indirection.
1272              Method write =     */
1273                helperClass.getMethod("write",    static String[] read_string_array(InputStream input)
1274                  new Class[]    {
1275                  {      gnuValueStream g = (gnuValueStream) input;
1276                    org.omg.CORBA.portable.OutputStream.class, value.getClass()      int previous = g.getPosition();
1277                  }      int l = input.read_long();
1278                );      if (l != vt_INDIRECTION)
1279              write.invoke(null, new Object[] { outObj, value });        {
1280              ok = true;          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;
1286          }
1287        else
1288          {
1289            gnuRuntime r = g.getRunTime();
1290            int base = g.getPosition();
1291            int delta = input.read_long();
1292            if (r == null)
1293              {
1294                previous = g.getPosition();
1295                g.seek(base + delta);
1296                String[] indir = StringSeqHelper.read(input);
1297                g.seek(previous);
1298                return indir;
1299            }            }
1300          catch (Exception ex)          else
1301            {            {
1302              ok = false;              return (String[]) r.isObjectWrittenAt(base + delta, delta);
1303            }            }
1304          }
1305      }
1306    
1307          // Stating the interfaces that the USER should use.    /**
1308          if (!ok)     * Write repository Id, probably shared.
1309            throw new MARSHAL("The " + value.getClass().getName() +     */
1310              " must implement either StreamableValue" + " or CustomValue."    static void write_string(OutputStream output, String id)
1311            );    {
1312        if (output instanceof gnuValueStream)
1313          {
1314            gnuValueStream b = (gnuValueStream) output;
1315            if (b != null)
1316              {
1317                int written = b.getRunTime().idWrittenAt(id);
1318                if (written >= 0)
1319                  {
1320                    // Reuse existing id record.
1321                    output.write_long(vt_INDIRECTION);
1322                    int p = b.getPosition();
1323                    output.write_long(written - p);
1324                  }
1325                else
1326                  {
1327                    b.getRunTime().singleIdWritten(id, b.getPosition());
1328                    output.write_string(id);
1329                  }
1330              }
1331        }        }
1332        else
1333          output.write_string(id);
1334      }
1335    
1336      if (USE_CHUNKING)    /**
1337       * Write repository Id, probably shared.
1338       */
1339      static void write_string_array(OutputStream output, String[] ids)
1340      {
1341        if (output instanceof gnuValueStream)
1342        {        {
1343          output.write_long(out.buffer.size());          gnuValueStream b = (gnuValueStream) output;
1344          try          if (b != null)
1345            {            {
1346              out.buffer.writeTo(output);              int written = b.getRunTime().idWrittenAt(ids);
1347                if (written >= 0)
1348                  {
1349                    // Reuse existing id record.
1350                    output.write_long(vt_INDIRECTION);
1351                    int p = b.getPosition();
1352                    output.write_long(written - p);
1353                  }
1354                else
1355                  {
1356                    b.getRunTime().multipleIdsWritten(ids, b.getPosition());
1357                    StringSeqHelper.write(output, ids);
1358                  }
1359            }            }
1360          catch (IOException ex)        }
1361        else
1362          StringSeqHelper.write(output, ids);
1363      }
1364    
1365      /**
1366       * Get the helper that could write the given object, or null if no pre-defined
1367       * helper available for this object.
1368       */
1369      public static BoxedValueHelper getHelper(Class x, Object ids)
1370      {
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[])
1378          {
1379            String[] ia = (String[]) ids;
1380            BoxedValueHelper h;
1381            for (int i = 0; i < ia.length; i++)
1382            {            {
1383              MARSHAL m = new MARSHAL();              h = locateHelper(ia[i]);
1384              m.initCause(ex);              if (h != null)
1385              throw m;                return h;
1386            }            }
1387            return null;
1388        }        }
1389        else
1390          return null;
1391      }
1392    
1393      // The end of record marker, required by OMG standard.    /**
1394      output.write_long(-1);     * Get the helper that could write the given object, or null if no pre-defined
1395       * helper available for this object.
1396       */
1397      public static BoxedValueHelper getHelper(Class x, String id)
1398      {
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);
1405      }
1406    
1407      /**
1408       * Try to locate helper from the repository id.
1409       */
1410      static BoxedValueHelper locateHelper(String id)
1411      {
1412        if (id != null)
1413          {
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:"))
1419              {
1420                try
1421                  {
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;
1429                  }
1430                catch (Exception ex)
1431                  {
1432                    return null;
1433                  }
1434              }
1435          }
1436        return null;
1437    }    }
1438    
1439    /**    /**
1440     * This can be called if the alternative CORBA implementation     * Get the current position.
    * is incorrectly plugged in.  
    *  
    * @throws NO_IMPLEMENT, always.  
1441     */     */
1442    static void incorrect_plug_in(Throwable ex) throws NO_IMPLEMENT    static int getCurrentPosition(InputStream x)
1443    {    {
1444      NO_IMPLEMENT no = new NO_IMPLEMENT("Incorrect CORBA plug-in");      if (x instanceof gnuValueStream)
1445      no.initCause(ex);        return ((gnuValueStream) x).getPosition();
1446      throw no;      else
1447          return 0;
1448    }    }
1449    
1450    /**    /**
1451     * Check the passed value tag for correctness.     * 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     * @param value_tag a tag to check, must be between 0x7fffff00 and 0x7fffffff     * while reading the class from the stream.
1454     *     *
1455     * @throws MARSHAL if the tag is outside this interval.     * @param clazz a class for that the instance should be instantiated.
1456     */     */
1457    private static final void checkTag(int value_tag)    public static Object instantiateAnyWay(Class clazz)
1458        throws Exception
1459    {    {
1460      if ((value_tag < 0x7fffff00 || value_tag > 0x7fffffff) &&      Class first_nonserial = clazz;
1461        value_tag != vt_NULL &&  
1462        value_tag != vt_INDIRECTION      while (Serializable.class.isAssignableFrom(first_nonserial)
1463      )        || Modifier.isAbstract(first_nonserial.getModifiers()))
1464        throw new MARSHAL("Invalid value record, unsupported header tag: " +        first_nonserial = first_nonserial.getSuperclass();
1465          value_tag  
1466        );      final Class local_constructor_class = first_nonserial;
1467    
1468        Constructor constructor = local_constructor_class.getDeclaredConstructor(new Class[0]);
1469    
1470        return VMVio.allocateObject(clazz, constructor.getDeclaringClass(),
1471          constructor);
1472    }    }
1473  }  }

Legend:
Removed from v.1.2.2.3  
changed lines
  Added in v.1.2.2.4

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26