OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [gnu/] [CORBA/] [CDR/] [Vio.java] - Blame information for rev 769

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 769 jeremybenn
/* Vio.java -- Value type IO operations.
2
   Copyright (C) 2005 Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
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.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
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. */
37
 
38
 
39
package gnu.CORBA.CDR;
40
 
41
import gnu.CORBA.Minor;
42
import gnu.CORBA.ObjectCreator;
43
 
44
import gnu.java.lang.CPStringBuilder;
45
 
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;
60
 
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;
66
 
67
import javax.rmi.CORBA.Util;
68
import javax.rmi.CORBA.ValueHandler;
69
 
70
/**
71
 * A specialised class for reading and writing the value types.
72
 *
73
 * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
74
 */
75
public abstract class Vio
76
{
77
  /**
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.
82
   *
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
85
   * false).
86
   */
87
  public static boolean USE_CHUNKING = false;
88
 
89
  /**
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).
93
   */
94
  public static final int vt_VALUE_TAG = 0x7fffff00;
95
 
96
  /**
97
   * The value tag flag, indicating that the codebase URL is present in the
98
   * value tag record.
99
   */
100
  public static final int vf_CODEBASE = 0x1;
101
 
102
  /**
103
   * The value tag flag, indicating that a single repository id is present in
104
   * the value tag record.
105
   */
106
  public static final int vf_ID = 0x2;
107
 
108
  /**
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.
112
   */
113
  public static final int vf_MULTIPLE_IDS = 0x4;
114
 
115
  /**
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.
119
   */
120
  public static final int vf_CHUNKING = 0x8;
121
 
122
  /**
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).
128
   */
129
  public static final int vt_INDIRECTION = 0xffffffff;
130
 
131
  /**
132
   * This tag value means that the value object being transferred is equal to
133
   * null.
134
   */
135
  public static final int vt_NULL = 0x0;
136
 
137
  /**
138
   * The size of CORBA long (java int).
139
   */
140
  static final int INT_SIZE = 4;
141
 
142
  /**
143
   * The String value helper (one instance is sufficient).
144
   */
145
  public static final WStringValueHelper m_StringValueHelper = new WStringValueHelper();
146
 
147
  /**
148
   * An instance of the value handler.
149
   */
150
  static ValueHandler handler = Util.createValueHandler();
151
 
152
  /**
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).
158
   *
159
   * @param input a stream to read from.
160
   *
161
   * @return the loaded value.
162
   *
163
   * @throws MARSHAL if the reading has failed due any reason.
164
   */
165
  public static Serializable read(InputStream input)
166
  {
167
    return read(input, (String) null);
168
  }
169
 
170
  /**
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).
176
   *
177
   * @param input a stream to read from.
178
   * @param repository_id a repository id of the object being read, may be null.
179
   *
180
   * @return the loaded value.
181
   *
182
   * @throws MARSHAL if the reading has failed due any reason.
183
   */
184
  public static Serializable read(InputStream input, String repository_id)
185
  {
186
    try
187
      {
188
        final int position = getCurrentPosition(input);
189
        // We may need to jump back if the value is read via value factory.
190
        input.mark(512);
191
 
192
        int value_tag = input.read_long();
193
        checkTag(value_tag);
194
 
195
        String codebase = null;
196
        String[] ids = null;
197
        String id = repository_id;
198
 
199
        // Check for the agreed null value.
200
        if (value_tag == vt_NULL)
201
          return null;
202
        else if (value_tag == vt_INDIRECTION)
203
          return readIndirection(input);
204
        else
205
          {
206
            // Read the value.
207
            if ((value_tag & vf_CODEBASE) != 0)
208
              {
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);
213
              }
214
 
215
            if ((value_tag & vf_MULTIPLE_IDS) != 0)
216
              {
217
                // Multiple supported repository ids are present.
218
                ids = read_string_array(input);
219
              }
220
            else if ((value_tag & vf_ID) != 0)
221
              {
222
                // Single supported repository id is present.
223
                id = read_string(input);
224
              }
225
          }
226
 
227
        BoxedValueHelper helper = getHelper(null, id);
228
        // The existing implementing object.
229
        java.lang.Object ox = null;
230
 
231
        if (helper != null)
232
          ox = null; // Helper will care about the instantiating.
233
        else if (id.equals(WStringValueHelper.id()))
234
          helper = m_StringValueHelper;
235
        else
236
          ox = createInstance(id, ids, codebase);
237
        return (Serializable) read_instance(input, position, ox, value_tag,
238
          helper, id, ids, codebase);
239
      }
240
    catch (Exception ex)
241
      {
242
        MARSHAL m = new MARSHAL();
243
        m.minor = Minor.Value;
244
        m.initCause(ex);
245
        throw m;
246
      }
247
  }
248
 
249
  /**
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.
252
   *
253
   * @param input a stream to read from.
254
   * @param value_class the class of the value being read.
255
   *
256
   * @return the loaded value.
257
   *
258
   * @throws MARSHAL if the reading has failed due any reason.
259
   */
260
  public static Serializable read(InputStream input, Class value_class)
261
  {
262
    final int position = getCurrentPosition(input);
263
 
264
    String id = null;
265
    String[] ids = null;
266
    String codebase = null;
267
 
268
    try
269
      {
270
        int value_tag = input.read_long();
271
        checkTag(value_tag);
272
 
273
        // Check for the agreed null value.
274
        if (value_tag == vt_NULL)
275
          return null;
276
        else if (value_tag == vt_INDIRECTION)
277
          return readIndirection(input);
278
        else
279
          {
280
            // Read the value.
281
            if ((value_tag & vf_CODEBASE) != 0)
282
              {
283
                // The codebase is present.
284
                codebase = read_string(input);
285
              }
286
 
287
            if ((value_tag & vf_MULTIPLE_IDS) != 0)
288
              {
289
                // Multiple supported repository ids are present.
290
                ids = read_string_array(input);
291
              }
292
            else if ((value_tag & vf_ID) != 0)
293
              {
294
                // Single supported repository id is present.
295
                id = read_string(input);
296
              }
297
          }
298
 
299
        BoxedValueHelper vHelper = id != null ? getHelper(value_class, id)
300
          : getHelper(value_class, ids);
301
 
302
        java.lang.Object ox;
303
 
304
        if (vHelper == null)
305
          {
306
            try
307
              {
308
                ox = createInstance(id, ids, codebase);
309
              }
310
            catch (Exception e)
311
              {
312
                ox = null;
313
              }
314
 
315
            if (ox != null)
316
              {
317
                if (value_class != null
318
                  && !value_class.isAssignableFrom(ox.getClass()))
319
                  {
320
                    MARSHAL m = new MARSHAL(ox.getClass() + " is not a "
321
                    + value_class.getName());
322
                    m.minor = Minor.ClassCast;
323
                    throw m;
324
                  }
325
              }
326
          }
327
        else
328
          ox = null;
329
 
330
        ox = read_instance(input, position, ox, value_tag, vHelper, id, ids,
331
          codebase);
332
        return (Serializable) ox;
333
      }
334
    catch (MARSHAL m)
335
      {
336
        throw m;
337
      }
338
    catch (SystemException sysEx)
339
      {
340
        // OK.
341
        throw sysEx;
342
      }
343
    catch (Exception ex)
344
      {
345
        MARSHAL m = new MARSHAL("Cant read " + value_class);
346
        m.minor = Minor.Value;
347
        m.initCause(ex);
348
        throw m;
349
      }
350
  }
351
 
352
  /**
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.
356
   *
357
   * @param input a stream to read from.
358
   *
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.
361
   *
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
364
   * should be null.
365
   *
366
   * @return the loaded value.
367
   *
368
   * @throws MARSHAL if the reading has failed due any reason.
369
   */
370
  public static Object read(InputStream input, Object value_instance,
371
    BoxedValueHelper helper)
372
  {
373
    final int position = getCurrentPosition(input);
374
 
375
    String id = null;
376
    String[] ids = null;
377
    String codebase = null;
378
 
379
    try
380
      {
381
        int value_tag = input.read_long();
382
        checkTag(value_tag);
383
 
384
        // Check for the agreed null value.
385
        if (value_tag == vt_NULL)
386
          return null;
387
        else if (value_tag == vt_INDIRECTION)
388
          return readIndirection(input);
389
        else
390
          {
391
            // Read the value.
392
            if ((value_tag & vf_CODEBASE) != 0)
393
              {
394
                // The codebase is present.
395
                codebase = read_string(input);
396
              }
397
 
398
            if ((value_tag & vf_MULTIPLE_IDS) != 0)
399
              {
400
                // Multiple supported repository ids are present.
401
                ids = read_string_array(input);
402
              }
403
            else if ((value_tag & vf_ID) != 0)
404
              {
405
                // Single supported repository id is present.
406
                id = read_string(input);
407
              }
408
          }
409
 
410
        Class value_class = value_instance == null ? null
411
          : value_instance.getClass();
412
 
413
        if (helper == null)
414
          helper = id != null ? getHelper(value_class, id) : getHelper(
415
            value_class, ids);
416
 
417
        value_instance = read_instance(input, position, value_instance,
418
          value_tag, helper, id, ids, codebase);
419
        return value_instance;
420
      }
421
    catch (Exception ex)
422
      {
423
        MARSHAL m = new MARSHAL();
424
        m.minor = Minor.Value;
425
        m.initCause(ex);
426
        throw m;
427
      }
428
  }
429
 
430
  /**
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.
434
   *
435
   * @param input the stream to read from.
436
   * @param helper the helper that reads the type-specific part of the content.
437
   *
438
   * @return the value, created by the helper, or null if the header indicates
439
   * that null was previously written.
440
   */
441
  public static Serializable read(InputStream input, BoxedValueHelper helper)
442
  {
443
    return (Serializable) read(input, null, helper);
444
  }
445
 
446
  /**
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.
450
   *
451
   * @param input an input stream to read from.
452
   *
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.
456
   *
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.
460
   *
461
   * @return the value that was read.
462
   */
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)
466
  {
467
    if (helper != m_StringValueHelper && id != null)
468
      if (id.equals(StringValueHelper.id()))
469
        {
470
          value = null;
471
          helper = m_StringValueHelper;
472
        }
473
 
474
    try
475
      {
476
        if ((value_tag & vf_CHUNKING) != 0)
477
          {
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());
483
 
484
            input = new HeadlessInput(ci, input);
485
          }
486
        else
487
          {
488
            if (input instanceof BufferredCdrInput)
489
              {
490
                // Highly probable case.
491
                input = new HeadlessInput((BufferredCdrInput) input, null);
492
              }
493
            else if (input instanceof HeadlessInput)
494
              {
495
                // There is no need to instantiate one more HeadlessInput
496
                // as we can just reset.
497
                ((HeadlessInput) input).subsequentCalls = false;
498
              }
499
            else
500
              {
501
                BufferedCdrOutput bout = new BufferedCdrOutput();
502
                int c;
503
                while ((c = input.read()) >= 0)
504
                  bout.write((byte) c);
505
                input = new HeadlessInput(
506
                  (BufferredCdrInput) bout.create_input_stream(), input);
507
              }
508
          }
509
      }
510
    catch (IOException ex)
511
      {
512
        MARSHAL m = new MARSHAL("Unable to read chunks");
513
        m.minor = Minor.Value;
514
        m.initCause(ex);
515
        throw m;
516
      }
517
 
518
    return readValue(input, position, value, helper, id, ids, codebase);
519
  }
520
 
521
  /**
522
   * Create a buffer, inheriting critical settings from the passed input stream.
523
   */
524
  private static BufferedCdrOutput createBuffer(InputStream input, int proposed_size)
525
  {
526
    BufferedCdrOutput bout;
527
    bout = new BufferedCdrOutput(2 * proposed_size + 256);
528
 
529
    if (input instanceof BufferredCdrInput)
530
      {
531
        BufferredCdrInput in = (BufferredCdrInput) input;
532
        bout.setBigEndian(in.isBigEndian());
533
      }
534
 
535
    if (input instanceof gnuValueStream)
536
      bout.setRunTime(((gnuValueStream) input).getRunTime());
537
    else
538
      bout.setRunTime(new gnuRuntime(null, null));
539
    return bout;
540
  }
541
 
542
  /**
543
   * Read the chunked nested value from the given input stream, transferring the
544
   * contents to the given output stream.
545
   *
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
548
   * must be read.
549
   * @param output the output stream where the unchunked nested value must be
550
   * copied.
551
   *
552
   * @return the tag that ended the nested value.
553
   */
554
  public static int readNestedValue(int value_tag, InputStream input,
555
    BufferedCdrOutput output, int level)
556
    throws IOException
557
  {
558
    String id = null;
559
    if (level < -1)
560
      {
561
        // For the first level, this information is already behind.
562
        output.write_long(value_tag - vf_CHUNKING);
563
 
564
        // The nested value should be aways chunked.
565
        if ((value_tag & vf_CHUNKING) == 0)
566
          {
567
            MARSHAL m = new MARSHAL("readNestedValue: must be chunked");
568
            m.minor = Minor.Chunks;
569
            throw m;
570
          }
571
        else if (value_tag == vt_NULL)
572
          {
573
            MARSHAL m = new MARSHAL("readNestedValue: nul");
574
            m.minor = Minor.Chunks;
575
            throw m;
576
          }
577
        else if (value_tag == vt_INDIRECTION)
578
          {
579
            MARSHAL m = new MARSHAL("readNestedValue: indirection");
580
            m.minor = Minor.Chunks;
581
            throw m;
582
          }
583
        else
584
          {
585
            // Read the value.
586
            if ((value_tag & vf_CODEBASE) != 0)
587
              {
588
                String codebase = read_string(input);
589
                write_string(output, codebase);
590
              }
591
 
592
            if ((value_tag & vf_MULTIPLE_IDS) != 0)
593
              {
594
                // Multiple supported repository ids are present.
595
                String[] ids = read_string_array(input);
596
                id = ids[0];
597
                write_string_array(output, ids);
598
              }
599
            else if ((value_tag & vf_ID) != 0)
600
              {
601
                id = read_string(input);
602
                write_string(output, id);
603
              }
604
          }
605
      }
606
 
607
    int n = -1;
608
 
609
    // Read all chunks.
610
    int chunk_size;
611
 
612
    byte[] r = null;
613
 
614
    while (true)
615
      {
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();
619
 
620
        // End of chunk terminator.
621
        if (chunk_size < 0 && chunk_size >= level)
622
          return chunk_size;
623
        else if (chunk_size >= 0x7FFFFF00)
624
          {
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)
633
              return chunk_size;
634
          }
635
        else
636
          {
637
            // The chunk follows.
638
            if (r == null || r.length < chunk_size)
639
              r = new byte[chunk_size + 256];
640
 
641
            n = 0;
642
            while (n < chunk_size)
643
              n += input.read(r, n, chunk_size - n);
644
            output.write(r, 0, n);
645
          }
646
      }
647
  }
648
 
649
  /**
650
   * Read the value (the header must be behind).
651
   */
652
  public static Serializable readValue(InputStream input, final int position,
653
    Object value, BoxedValueHelper helper, String id, String[] ids,
654
    String codebase)
655
  {
656
    gnuRuntime g;
657
    gnuValueStream c = ((gnuValueStream) input);
658
    if (c.getRunTime() == null)
659
      {
660
        g = new gnuRuntime(codebase, value);
661
        c.setRunTime(g);
662
      }
663
    else
664
      {
665
        g = c.getRunTime();
666
        g.addCodeBase(codebase);
667
        g.target = (Serializable) value;
668
      }
669
    if (value != null)
670
      g.objectWritten(value, position);
671
 
672
    if (input instanceof HeadlessInput)
673
      ((HeadlessInput) input).subsequentCalls = false;
674
 
675
    boolean ok = true;
676
 
677
    // The user-defined io operations are implemented.
678
    if (value instanceof CustomMarshal)
679
      {
680
        CustomMarshal marsh = (CustomMarshal) value;
681
        marsh.unmarshal((DataInputStream) input);
682
      }
683
    else
684
    // The IDL-generated io operations are implemented.
685
    if (value instanceof Streamable)
686
      {
687
        ((Streamable) value)._read(input);
688
      }
689
    else if (helper != null)
690
      {
691
        // If helper is non-null the value should normally be null.
692
        value = helper.read_value(input);
693
        g.objectWritten(value, position);
694
      }
695
    else
696
      {
697
        ok = false;
698
        ValueFactory factory = null;
699
        org.omg.CORBA_2_3.ORB orb = (org.omg.CORBA_2_3.ORB) input.orb();
700
 
701
        if (id != null)
702
          factory = orb.lookup_value_factory(id);
703
 
704
        if (factory == null && ids != null)
705
          {
706
            for (int i = 0; i < ids.length && factory == null; i++)
707
              {
708
                factory = orb.lookup_value_factory(ids[i]);
709
              }
710
          }
711
 
712
        if (factory != null)
713
          {
714
            value = factory.read_value((org.omg.CORBA_2_3.portable.InputStream) input);
715
            ok = true;
716
          }
717
      }
718
 
719
    if (!ok && value instanceof Serializable)
720
    // Delegate to ValueHandler
721
      {
722
        if (ids != null && ids.length > 0)
723
          id = ids[0];
724
 
725
        value = handler.readValue(input, position, value.getClass(), id, g);
726
        ok = true;
727
      }
728
 
729
    if (!ok)
730
      {
731
        if (value != null)
732
          {
733
            MARSHAL m = new MARSHAL(value.getClass().getName()
734
            + " must be Streamable, CustomMarshal or Serializable");
735
            m.minor = Minor.UnsupportedValue;
736
            throw m;
737
          }
738
        else
739
          {
740
            MARSHAL m = new MARSHAL("Unable to instantiate " + id + ":" + list(ids)
741
            + " helper " + helper);
742
            m.minor = Minor.UnsupportedValue;
743
            throw m;
744
          }
745
      }
746
    else
747
      return (Serializable) value;
748
  }
749
 
750
  /**
751
   * Conveniency method to list ids in exception reports.
752
   */
753
  static String list(String[] s)
754
  {
755
    if (s == null)
756
      return "null";
757
    else
758
      {
759
        CPStringBuilder b = new CPStringBuilder("{");
760
        for (int i = 0; i < s.length; i++)
761
          {
762
            b.append(s[i]);
763
            b.append(" ");
764
          }
765
        b.append("}");
766
        return b.toString();
767
      }
768
  }
769
 
770
  /**
771
   * Write the value base into the given stream.
772
   *
773
   * @param output a stream to write to.
774
   *
775
   * @param value a value type object, must be either Streamable or
776
   * CustomMarshal.
777
   *
778
   * @throws MARSHAL if the writing failed due any reason.
779
   */
780
  public static void write(OutputStream output, Serializable value)
781
  {
782
    // Write null if this is a null value.
783
    if (value == null)
784
      output.write_long(vt_NULL);
785
    else if (value instanceof String)
786
      write(output, value, m_StringValueHelper);
787
    else
788
      write(output, value, value.getClass());
789
  }
790
 
791
  /**
792
   * Write the value base into the given stream, stating that it is an instance
793
   * of the given class.
794
   *
795
   * @param output a stream to write to.
796
   *
797
   * @param value a value to write.
798
   *
799
   * @throws MARSHAL if the writing failed due any reason.
800
   */
801
  public static void write(OutputStream output, Serializable value,
802
    Class substitute)
803
  {
804
    // Write null if this is a null value.
805
    if (value == null)
806
      output.write_long(vt_NULL);
807
    else if (value instanceof String || substitute == String.class)
808
      writeString(output, value);
809
    else
810
      {
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));
814
        else
815
          {
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
821
            // ids.
822
            if (h == null)
823
              write_instance(output, value, ids, null);
824
            else
825
              write_instance(output, value, h.get_id(), null);
826
          }
827
      }
828
  }
829
 
830
  /**
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
833
   * passed value.
834
   *
835
   * @param output a stream to write to.
836
   *
837
   * @param value a value to write.
838
   *
839
   * @throws MARSHAL if the writing failed due any reason.
840
   */
841
  public static void write(OutputStream output, Serializable value,
842
    String[] multiple_ids)
843
  {
844
    // Write null if this is a null value.
845
    if (value == null)
846
      output.write_long(vt_NULL);
847
    else
848
      {
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);
854
      }
855
  }
856
 
857
  /**
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.
860
   *
861
   * @param output an output stream to write into.
862
   * @param value a value to write.
863
   * @param id a value repository id.
864
   */
865
  public static void write(OutputStream output, Serializable value, String id)
866
  {
867
    if (value == null)
868
      output.write_long(vt_NULL);
869
    else
870
      write_instance(output, value, id, getHelper(value.getClass(), id));
871
  }
872
 
873
  /**
874
   * Write standard value type header, followed by contents, produced by the
875
   * boxed value helper.
876
   *
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).
881
   */
882
  public static void write(OutputStream output, Serializable value,
883
    BoxedValueHelper helper)
884
  {
885
    if (helper == null)
886
      throw new AssertionError("Helper must be provided");
887
    if (value == null)
888
      output.write_long(vt_NULL);
889
    else
890
      write_instance(output, value, helper.get_id(), helper);
891
  }
892
 
893
  /**
894
   * Write the parameter that is surely a string and not null.
895
   */
896
  private static void writeString(OutputStream output, Serializable string)
897
  {
898
    write_instance(output, string, m_StringValueHelper.get_id(),
899
      m_StringValueHelper);
900
  }
901
 
902
  /**
903
   * Write value when its repository Id is explicitly given. Does not handle
904
   * null.
905
   *
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
909
   * array).
910
   * @param helper a helper, writing object - specifical part. Can be null if
911
   * the value should be written using other methods.
912
   */
913
  static void write_instance(OutputStream output, Serializable value,
914
    Object ids, BoxedValueHelper helper)
915
  {
916
    gnuValueStream rout = null;
917
    gnuRuntime runtime = null;
918
 
919
    try
920
      {
921
        if (output instanceof gnuValueStream)
922
          {
923
            int position;
924
            rout = (gnuValueStream) output;
925
            runtime = rout.getRunTime();
926
 
927
            if (runtime == null)
928
              {
929
                runtime = new gnuRuntime(null, value);
930
                rout.setRunTime(runtime);
931
                rout.getRunTime().objectWritten(value,
932
                  position = rout.getPosition());
933
              }
934
            else if (runtime.target == value)
935
              {
936
                if (!writeSelf(output, value))
937
                  throw new InternalError("Recursive helper call for "
938
                    + value.getClass().getName());
939
                return;
940
              }
941
            else
942
              {
943
                position = runtime.isWrittenAt(value);
944
                if (position >= 0)
945
                  {
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.
950
                    return;
951
                  }
952
                else
953
                  {
954
                    runtime.objectWritten(value, position = rout.getPosition());
955
                  }
956
              }
957
          }
958
 
959
        int value_tag = vt_VALUE_TAG;
960
 
961
        if (ids instanceof String)
962
          value_tag |= vf_ID;
963
        else if (ids instanceof String[])
964
          // OMG standard requires to set both flags.
965
          value_tag |= vf_MULTIPLE_IDS | vf_ID;
966
 
967
        int chunkSizeLocation;
968
 
969
        OutputStream outObj;
970
 
971
        if (USE_CHUNKING)
972
          {
973
            // Wrap the value being written into one chunk (makes sense only for
974
            // compatibility reasons).
975
            outObj = output;
976
            value_tag |= vf_CHUNKING;
977
          }
978
        else
979
          outObj = output;
980
 
981
        output.write_long(value_tag);
982
 
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);
987
 
988
        if (USE_CHUNKING)
989
          {
990
            // So far, write 0x55555555 instead of the chunk size (alignment may
991
            // take place).
992
            output.write_long(0x55555555);
993
            // If the chunking is involved, the chunk size must be written here.
994
            chunkSizeLocation = rout.getPosition() - INT_SIZE;
995
          }
996
        else
997
          // Not in use for this case.
998
          chunkSizeLocation = -1;
999
 
1000
        writeValue(outObj, value, helper);
1001
 
1002
        if (USE_CHUNKING)
1003
          {
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);
1009
            rout.seek(current);
1010
 
1011
            // The end of record marker.
1012
            output.write_long(-1);
1013
          }
1014
      }
1015
    finally
1016
      {
1017
        if (runtime != null)
1018
          runtime.target = null;
1019
      }
1020
  }
1021
 
1022
  /**
1023
   * Write value (after header).
1024
   */
1025
  static void writeValue(OutputStream output, Serializable value,
1026
    BoxedValueHelper helper)
1027
  {
1028
    ((gnuValueStream) output).getRunTime().target = value;
1029
    if (helper != null)
1030
      helper.write_value(output, value);
1031
    else if (!writeSelf(output, value))
1032
      {
1033
        // Try to find helper via class loader.
1034
        boolean ok = false;
1035
 
1036
        if (!ok)
1037
          {
1038
            if (output instanceof BufferedCdrOutput)
1039
              {
1040
                BufferedCdrOutput b = (BufferedCdrOutput) output;
1041
                if (b.runtime == null)
1042
                  b.runtime = new gnuRuntime(null, value);
1043
              }
1044
 
1045
            handler.writeValue(output, value);
1046
          }
1047
      }
1048
  }
1049
 
1050
  /**
1051
   * Try to write value supposing that it implements self-streamable interfaces.
1052
   * Return false if it does not or true on success.
1053
   */
1054
  static boolean writeSelf(OutputStream output, Serializable value)
1055
  {
1056
    // User defined write method is present.
1057
    if (value instanceof CustomMarshal)
1058
      {
1059
        ((CustomMarshal) value).marshal((DataOutputStream) output);
1060
        return true;
1061
      }
1062
    else if (value instanceof Streamable)
1063
      {
1064
        ((Streamable) value)._write(output);
1065
        return true;
1066
      }
1067
    return false;
1068
  }
1069
 
1070
  /**
1071
   * Read the indirection data and return the object that was already written to
1072
   * this stream.
1073
   *
1074
   * @param an_input the input stream, must be BufferredCdrInput.
1075
   */
1076
  static Serializable readIndirection(InputStream an_input)
1077
  {
1078
    if (!(an_input instanceof gnuValueStream))
1079
      throw new NO_IMPLEMENT(gnuValueStream.class.getName()
1080
        + " expected as parameter");
1081
 
1082
    gnuValueStream in = (gnuValueStream) an_input;
1083
 
1084
    int current_pos = in.getPosition();
1085
 
1086
    int offset = an_input.read_long();
1087
    if (offset > -INT_SIZE)
1088
      {
1089
        MARSHAL m = new MARSHAL("Indirection tag refers to " + offset
1090
        + " (must be less than -" + INT_SIZE + ")");
1091
        m.minor = Minor.Offset;
1092
        throw m;
1093
      }
1094
 
1095
    int stored_at = current_pos + offset;
1096
 
1097
    if (in.getRunTime() == null)
1098
      {
1099
        MARSHAL m = new MARSHAL(stored_at + " offset " + offset + ": not written");
1100
        m.minor = Minor.Value;
1101
        throw m;
1102
      }
1103
 
1104
    return (Serializable) in.getRunTime().isObjectWrittenAt(stored_at, offset);
1105
  }
1106
 
1107
  /**
1108
   * Check the passed value tag for correctness.
1109
   *
1110
   * @param value_tag a tag to check, must be between 0x7fffff00 and 0x7fffffff
1111
   *
1112
   * @throws MARSHAL if the tag is outside this interval.
1113
   */
1114
  static void checkTag(int value_tag)
1115
  {
1116
    if ((value_tag < 0x7fffff00 || value_tag > 0x7fffffff)
1117
      && value_tag != vt_NULL && value_tag != vt_INDIRECTION)
1118
      {
1119
        MARSHAL m = new MARSHAL("Invalid value record, unsupported header tag: "
1120
        + value_tag + " (0x" + Integer.toHexString(value_tag) + ")");
1121
        m.minor = Minor.ValueHeaderTag;
1122
        throw m;
1123
      }
1124
 
1125
    if ((value_tag & vf_MULTIPLE_IDS) != 0 && (value_tag & vf_ID) == 0)
1126
      {
1127
        MARSHAL m = new MARSHAL("Invalid value record header flag combination (0x"
1128
        + Integer.toHexString(value_tag) + ")");
1129
        m.minor = Minor.ValueHeaderFlags;
1130
        throw m;
1131
      }
1132
  }
1133
 
1134
  /**
1135
   * Throw MARSHAL.
1136
   */
1137
  static void throwIt(String msg, String id1, String id2, Throwable e)
1138
    throws MARSHAL
1139
  {
1140
    MARSHAL m = new MARSHAL(msg + ":'" + id1 + "' versus '" + id2 + "'");
1141
    if (e != null)
1142
      m.initCause(e);
1143
    m.minor = Minor.Value;
1144
    throw m;
1145
  }
1146
 
1147
  /**
1148
   * Load class by name and create the instance.
1149
   */
1150
  static Object createInstance(String id, String[] ids, String codebase)
1151
  {
1152
    Object o = null;
1153
 
1154
    if (id != null)
1155
      o = _createInstance(id, codebase);
1156
 
1157
    if (ids != null)
1158
      for (int i = 0; i < ids.length && o == null; i++)
1159
        o = _createInstance(ids[i], codebase);
1160
    return o;
1161
  }
1162
 
1163
  static Object _createInstance(String id, String codebase)
1164
  {
1165
    if (id == null)
1166
      return null;
1167
    if (id.equals(StringValueHelper.id()))
1168
      return "";
1169
    StringTokenizer st = new StringTokenizer(id, ":");
1170
 
1171
    String prefix = st.nextToken();
1172
    if (prefix.equalsIgnoreCase("IDL"))
1173
      return ObjectCreator.Idl2Object(id);
1174
    else if (prefix.equalsIgnoreCase("RMI"))
1175
      {
1176
        String className = st.nextToken();
1177
        String hashCode = st.nextToken();
1178
        String sid = null;
1179
        if (st.hasMoreElements())
1180
          sid = st.nextToken();
1181
 
1182
        try
1183
          {
1184
            Class objectClass = Util.loadClass(className, codebase,
1185
              Vio.class.getClassLoader());
1186
 
1187
            String rid = ObjectCreator.getRepositoryId(objectClass);
1188
 
1189
            if (!rid.equals(id))
1190
              {
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);
1197
 
1198
                try
1199
                  {
1200
                    long h1 = Long.parseLong(hashCode, 16);
1201
                    long h2 = Long.parseLong(st2.nextToken(), 16);
1202
                    if (h1 != h2)
1203
                      throwIt("Hashcode mismatch", id, rid, null);
1204
 
1205
                    if (sid != null && st2.hasMoreTokens())
1206
                      {
1207
                        long s1 = Long.parseLong(hashCode, 16);
1208
                        long s2 = Long.parseLong(st2.nextToken(), 16);
1209
                        if (s1 != s2)
1210
                          throwIt("serialVersionUID mismatch", id, rid, null);
1211
                      }
1212
                  }
1213
                catch (NumberFormatException e)
1214
                  {
1215
                    throwIt("Invalid hashcode or svuid format: ", id, rid, e);
1216
                  }
1217
              }
1218
 
1219
            // Low - level instantiation required here.
1220
            return instantiateAnyWay(objectClass);
1221
          }
1222
        catch (Exception ex)
1223
          {
1224
            MARSHAL m = new MARSHAL("Unable to instantiate " + id);
1225
            m.minor = Minor.Instantiation;
1226
            m.initCause(ex);
1227
            throw m;
1228
          }
1229
      }
1230
    else
1231
      throw new NO_IMPLEMENT("Unsupported prefix " + prefix + ":");
1232
  }
1233
 
1234
  /**
1235
   * Read string, expecting the probable indirection.
1236
   */
1237
  static String read_string(InputStream input)
1238
  {
1239
    gnuValueStream g = (gnuValueStream) input;
1240
    int previous = g.getPosition();
1241
    int l = input.read_long();
1242
    if (l != vt_INDIRECTION)
1243
      {
1244
        g.seek(previous);
1245
        String s = input.read_string();
1246
        if (g.getRunTime() == null)
1247
          g.setRunTime(new gnuRuntime(null, null));
1248
        g.getRunTime().singleIdWritten(s, previous);
1249
        return s;
1250
      }
1251
    else
1252
      {
1253
        gnuRuntime r = g.getRunTime();
1254
        int base = g.getPosition();
1255
        int delta = input.read_long();
1256
        if (r == null)
1257
          {
1258
            previous = g.getPosition();
1259
            g.seek(base + delta);
1260
            String indir = input.read_string();
1261
            g.seek(previous);
1262
            return indir;
1263
          }
1264
        else
1265
          {
1266
            return (String) r.isObjectWrittenAt(base + delta, delta);
1267
          }
1268
      }
1269
  }
1270
 
1271
  /**
1272
   * Read string array, expecting the probable indirection.
1273
   */
1274
  static String[] read_string_array(InputStream input)
1275
  {
1276
    gnuValueStream g = (gnuValueStream) input;
1277
    int previous = g.getPosition();
1278
    int l = input.read_long();
1279
    if (l != vt_INDIRECTION)
1280
      {
1281
        g.seek(previous);
1282
        String[] s = StringSeqHelper.read(input);
1283
        if (g.getRunTime() == null)
1284
          g.setRunTime(new gnuRuntime(null, null));
1285
        g.getRunTime().objectWritten(s, previous);
1286
        return s;
1287
      }
1288
    else
1289
      {
1290
        gnuRuntime r = g.getRunTime();
1291
        int base = g.getPosition();
1292
        int delta = input.read_long();
1293
        if (r == null)
1294
          {
1295
            previous = g.getPosition();
1296
            g.seek(base + delta);
1297
            String[] indir = StringSeqHelper.read(input);
1298
            g.seek(previous);
1299
            return indir;
1300
          }
1301
        else
1302
          {
1303
            return (String[]) r.isObjectWrittenAt(base + delta, delta);
1304
          }
1305
      }
1306
  }
1307
 
1308
  /**
1309
   * Write repository Id, probably shared.
1310
   */
1311
  static void write_string(OutputStream output, String id)
1312
  {
1313
    if (output instanceof gnuValueStream)
1314
      {
1315
        gnuValueStream b = (gnuValueStream) output;
1316
        if (b != null)
1317
          {
1318
            int written = b.getRunTime().idWrittenAt(id);
1319
            if (written >= 0)
1320
              {
1321
                // Reuse existing id record.
1322
                output.write_long(vt_INDIRECTION);
1323
                int p = b.getPosition();
1324
                output.write_long(written - p);
1325
              }
1326
            else
1327
              {
1328
                b.getRunTime().singleIdWritten(id, b.getPosition());
1329
                output.write_string(id);
1330
              }
1331
          }
1332
      }
1333
    else
1334
      output.write_string(id);
1335
  }
1336
 
1337
  /**
1338
   * Write repository Id, probably shared.
1339
   */
1340
  static void write_string_array(OutputStream output, String[] ids)
1341
  {
1342
    if (output instanceof gnuValueStream)
1343
      {
1344
        gnuValueStream b = (gnuValueStream) output;
1345
        if (b != null)
1346
          {
1347
            int written = b.getRunTime().idWrittenAt(ids);
1348
            if (written >= 0)
1349
              {
1350
                // Reuse existing id record.
1351
                output.write_long(vt_INDIRECTION);
1352
                int p = b.getPosition();
1353
                output.write_long(written - p);
1354
              }
1355
            else
1356
              {
1357
                b.getRunTime().multipleIdsWritten(ids, b.getPosition());
1358
                StringSeqHelper.write(output, ids);
1359
              }
1360
          }
1361
      }
1362
    else
1363
      StringSeqHelper.write(output, ids);
1364
  }
1365
 
1366
  /**
1367
   * Get the helper that could write the given object, or null if no pre-defined
1368
   * helper available for this object.
1369
   */
1370
  public static BoxedValueHelper getHelper(Class x, Object ids)
1371
  {
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[])
1379
      {
1380
        String[] ia = (String[]) ids;
1381
        BoxedValueHelper h;
1382
        for (int i = 0; i < ia.length; i++)
1383
          {
1384
            h = locateHelper(ia[i]);
1385
            if (h != null)
1386
              return h;
1387
          }
1388
        return null;
1389
      }
1390
    else
1391
      return null;
1392
  }
1393
 
1394
  /**
1395
   * Get the helper that could write the given object, or null if no pre-defined
1396
   * helper available for this object.
1397
   */
1398
  public static BoxedValueHelper getHelper(Class x, String id)
1399
  {
1400
    if (x != null && x.equals(String.class))
1401
      return m_StringValueHelper;
1402
    else if (x != null && x.isArray())
1403
      return new ArrayValueHelper(x);
1404
    else
1405
      return locateHelper(id);
1406
  }
1407
 
1408
  /**
1409
   * Try to locate helper from the repository id.
1410
   */
1411
  static BoxedValueHelper locateHelper(String id)
1412
  {
1413
    if (id != null)
1414
      {
1415
        if (id.equals(m_StringValueHelper.get_id()))
1416
          return m_StringValueHelper;
1417
        else
1418
        // Try to locate helper for IDL type.
1419
        if (id.startsWith("IDL:"))
1420
          {
1421
            try
1422
              {
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);
1428
                else
1429
                  return null;
1430
              }
1431
            catch (Exception ex)
1432
              {
1433
                return null;
1434
              }
1435
          }
1436
      }
1437
    return null;
1438
  }
1439
 
1440
  /**
1441
   * Get the current position.
1442
   */
1443
  static int getCurrentPosition(InputStream x)
1444
  {
1445
    if (x instanceof gnuValueStream)
1446
      return ((gnuValueStream) x).getPosition();
1447
    else
1448
      return 0;
1449
  }
1450
 
1451
  /**
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.
1455
   *
1456
   * @param clazz a class for that the instance should be instantiated.
1457
   */
1458
  public static Object instantiateAnyWay(Class clazz)
1459
    throws Exception
1460
  {
1461
    Class first_nonserial = clazz;
1462
 
1463
    while (Serializable.class.isAssignableFrom(first_nonserial)
1464
      || Modifier.isAbstract(first_nonserial.getModifiers()))
1465
      first_nonserial = first_nonserial.getSuperclass();
1466
 
1467
    final Class local_constructor_class = first_nonserial;
1468
 
1469
    Constructor constructor = local_constructor_class.getDeclaredConstructor(new Class[0]);
1470
 
1471
    return VMVio.allocateObject(clazz, constructor.getDeclaringClass(),
1472
      constructor);
1473
  }
1474
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.