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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libjava/] [classpath/] [gnu/] [CORBA/] [CDR/] [Vio.java] - Blame information for rev 14

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
/* 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 org.omg.CORBA.CustomMarshal;
45
import org.omg.CORBA.DataInputStream;
46
import org.omg.CORBA.DataOutputStream;
47
import org.omg.CORBA.MARSHAL;
48
import org.omg.CORBA.NO_IMPLEMENT;
49
import org.omg.CORBA.StringSeqHelper;
50
import org.omg.CORBA.StringValueHelper;
51
import org.omg.CORBA.SystemException;
52
import org.omg.CORBA.WStringValueHelper;
53
import org.omg.CORBA.portable.BoxedValueHelper;
54
import org.omg.CORBA.portable.InputStream;
55
import org.omg.CORBA.portable.OutputStream;
56
import org.omg.CORBA.portable.Streamable;
57
import org.omg.CORBA.portable.ValueFactory;
58
 
59
import java.io.IOException;
60
import java.io.Serializable;
61
import java.lang.reflect.Constructor;
62
import java.lang.reflect.Modifier;
63
import java.util.StringTokenizer;
64
 
65
import javax.rmi.CORBA.Util;
66
import javax.rmi.CORBA.ValueHandler;
67
 
68
/**
69
 * A specialised class for reading and writing the value types.
70
 *
71
 * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
72
 */
73
public abstract class Vio
74
{
75
  /**
76
   * If true, wrap value type data into chunks. This decrease the performance,
77
   * and is not required for interoperability with jdk 1.5, but is left in the
78
   * implementation as the optional mode for solving possible interoperability
79
   * problems with non-Sun CORBA implementations.
80
   *
81
   * The current implementation would accept both single chunk or multiple
82
   * chunks, but will always send a single chunk (if true) or unchunked data (if
83
   * false).
84
   */
85
  public static boolean USE_CHUNKING = false;
86
 
87
  /**
88
   * The first field in the value record. The last octet may contain additional
89
   * flags (vf_CODEBASE, vf_ID and vf_MULTIPLE_IDS). The tag value is different
90
   * for the indirections (vt_INDIRECTION) and nulls (vt_NULL).
91
   */
92
  public static final int vt_VALUE_TAG = 0x7fffff00;
93
 
94
  /**
95
   * The value tag flag, indicating that the codebase URL is present in the
96
   * value tag record.
97
   */
98
  public static final int vf_CODEBASE = 0x1;
99
 
100
  /**
101
   * The value tag flag, indicating that a single repository id is present in
102
   * the value tag record.
103
   */
104
  public static final int vf_ID = 0x2;
105
 
106
  /**
107
   * The value tag flag, indicating, that there are multiple repository ids
108
   * present in the record. If this flag is set, the flag vf_ID must also be
109
   * set, resulting the value of the least significant byte 0x6.
110
   */
111
  public static final int vf_MULTIPLE_IDS = 0x4;
112
 
113
  /**
114
   * The value tag flag, indicating the presence of chunking. Each chunk is
115
   * preceeded by a positive int, indicating the number of bytes in the chunk. A
116
   * sequence of chunks is terminated by a non positive int.
117
   */
118
  public static final int vf_CHUNKING = 0x8;
119
 
120
  /**
121
   * The indirection tag value. Such tag must be followed by the CORBA long,
122
   * indicating the offset in the CORBA message, where the indirected
123
   * information is present. This offset is assumed zero at the position where
124
   * the mentioned CORBA long starts and can refer both forward (positive
125
   * values) and backward (negative values).
126
   */
127
  public static final int vt_INDIRECTION = 0xffffffff;
128
 
129
  /**
130
   * This tag value means that the value object being transferred is equal to
131
   * null.
132
   */
133
  public static final int vt_NULL = 0x0;
134
 
135
  /**
136
   * The size of CORBA long (java int).
137
   */
138
  static final int INT_SIZE = 4;
139
 
140
  /**
141
   * 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.
158
   * @param repository_id a repository id of the object being read, may be null.
159
   *
160
   * @return the loaded value.
161
   *
162
   * @throws MARSHAL if the reading has failed due any reason.
163
   */
164
  public static Serializable read(InputStream input)
165
  {
166
    return read(input, (String) null);
167
  }
168
 
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
186
      {
187
        final int position = getCurrentPosition(input);
188
        // We may need to jump back if the value is read via value factory.
189
        input.mark(512);
190
 
191
        int value_tag = input.read_long();
192
        checkTag(value_tag);
193
 
194
        String codebase = null;
195
        String[] ids = null;
196
        String id = repository_id;
197
 
198
        // Check for the agreed null value.
199
        if (value_tag == vt_NULL)
200
          return null;
201
        else if (value_tag == vt_INDIRECTION)
202
          return readIndirection(input);
203
        else
204
          {
205
            // Read the value.
206
            if ((value_tag & vf_CODEBASE) != 0)
207
              {
208
                // The codebase is present. The codebase is a space
209
                // separated list of URLs from where the implementing
210
                // code can be downloaded.
211
                codebase = read_string(input);
212
              }
213
 
214
            if ((value_tag & vf_MULTIPLE_IDS) != 0)
215
              {
216
                // Multiple supported repository ids are present.
217
                ids = read_string_array(input);
218
              }
219
            else if ((value_tag & vf_ID) != 0)
220
              {
221
                // Single supported repository id is present.
222
                id = read_string(input);
223
              }
224
          }
225
 
226
        BoxedValueHelper helper = getHelper(null, id);
227
        // 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
235
          ox = createInstance(id, ids, codebase);
236
        return (Serializable) read_instance(input, position, ox, value_tag,
237
          helper, id, ids, codebase);
238
      }
239
    catch (Exception ex)
240
      {
241
        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 the value base class
250
   * is available. Hence there is no need to guess it from the repository id.
251
   *
252
   * @param input a stream to read from.
253
   * @param value_class the class of the value being read.
254
   *
255
   * @return the loaded value.
256
   *
257
   * @throws MARSHAL if the reading has failed due any reason.
258
   */
259
  public static Serializable read(InputStream input, Class value_class)
260
  {
261
    final int position = getCurrentPosition(input);
262
 
263
    String id = null;
264
    String[] ids = null;
265
    String codebase = null;
266
 
267
    try
268
      {
269
        int value_tag = input.read_long();
270
        checkTag(value_tag);
271
 
272
        // Check for the agreed null value.
273
        if (value_tag == vt_NULL)
274
          return null;
275
        else if (value_tag == vt_INDIRECTION)
276
          return readIndirection(input);
277
        else
278
          {
279
            // Read the value.
280
            if ((value_tag & vf_CODEBASE) != 0)
281
              {
282
                // The codebase is present.
283
                codebase = read_string(input);
284
              }
285
 
286
            if ((value_tag & vf_MULTIPLE_IDS) != 0)
287
              {
288
                // Multiple supported repository ids are present.
289
                ids = read_string_array(input);
290
              }
291
            else if ((value_tag & vf_ID) != 0)
292
              {
293
                // Single supported repository id is present.
294
                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
        ox = read_instance(input, position, ox, value_tag, vHelper, id, ids,
330
          codebase);
331
        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)
343
      {
344
        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 the unitialised
353
   * instance is available. Hence there is no need to guess the class from the
354
   * repository id and then to instantiate an instance.
355
   *
356
   * @param input a stream to read from.
357
   *
358
   * @param value_instance an pre-created instance of the value. If the helper
359
   * is not null, this parameter is ignored an should be null.
360
   *
361
   * @param helper a helper to create an instance and read the object- specific
362
   * part of the record. If the value_instance is used instead, this parameter
363
   * should be null.
364
   *
365
   * @return the loaded value.
366
   *
367
   * @throws MARSHAL if the reading has failed due any reason.
368
   */
369
  public static Object read(InputStream input, Object value_instance,
370
    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
379
      {
380
        int value_tag = input.read_long();
381
        checkTag(value_tag);
382
 
383
        // Check for the agreed null value.
384
        if (value_tag == vt_NULL)
385
          return null;
386
        else if (value_tag == vt_INDIRECTION)
387
          return readIndirection(input);
388
        else
389
          {
390
            // Read the value.
391
            if ((value_tag & vf_CODEBASE) != 0)
392
              {
393
                // The codebase is present.
394
                codebase = read_string(input);
395
              }
396
 
397
            if ((value_tag & vf_MULTIPLE_IDS) != 0)
398
              {
399
                // Multiple supported repository ids are present.
400
                ids = read_string_array(input);
401
              }
402
            else if ((value_tag & vf_ID) != 0)
403
              {
404
                // Single supported repository id is present.
405
                id = read_string(input);
406
              }
407
          }
408
 
409
        Class value_class = value_instance == null ? null
410
          : 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;
419
      }
420
    catch (Exception ex)
421
      {
422
        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 the full value
431
   * type header, followed by contents, that are delegated to the provided
432
   * helper. It handles null.
433
   *
434
   * @param input the stream to read from.
435
   * @param helper the helper that reads the type-specific part of the content.
436
   *
437
   * @return the value, created by the helper, or null if the header indicates
438
   * that null was previously written.
439
   */
440
  public static Serializable read(InputStream input, BoxedValueHelper helper)
441
  {
442
    return (Serializable) read(input, null, helper);
443
  }
444
 
445
  /**
446
   * Fill in the instance fields by the data from the input stream. The method
447
   * assumes that the value header, if any, is already behind. The information
448
   * from the stream is stored into the passed ox parameter.
449
   *
450
   * @param input an input stream to read from.
451
   *
452
   * @param value a pre-instantiated value type object, must be either
453
   * Streamable or CustomMarshal. If the helper is used, this parameter is
454
   * ignored and should be null.
455
   *
456
   * @param value_tag the tag that must be read previously.
457
   * @param helper the helper for read object specific part; may be null to read
458
   * in using other methods.
459
   *
460
   * @return the value that was read.
461
   */
462
  static Object read_instance(InputStream input, final int position,
463
    Object value, int value_tag, BoxedValueHelper helper, String id,
464
    String[] ids, String codebase)
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
474
      {
475
        if ((value_tag & vf_CHUNKING) != 0)
476
          {
477
            BufferedCdrOutput output = createBuffer(input, 1024);
478
            // Read the current (not a nested one) value in this spec case.
479
            readNestedValue(value_tag, input, output, -1);
480
            BufferredCdrInput ci = new BufferredCdrInput(output.buffer.getBuffer());
481
            ci.setRunTime(output.getRunTime());
482
 
483
            input = new HeadlessInput(ci, input);
484
          }
485
        else
486
          {
487
            if (input instanceof BufferredCdrInput)
488
              {
489
                // Highly probable case.
490
                input = new HeadlessInput((BufferredCdrInput) input, null);
491
              }
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
499
              {
500
                BufferedCdrOutput bout = new BufferedCdrOutput();
501
                int c;
502
                while ((c = input.read()) >= 0)
503
                  bout.write((byte) c);
504
                input = new HeadlessInput(
505
                  (BufferredCdrInput) bout.create_input_stream(), input);
506
              }
507
          }
508
      }
509
    catch (IOException ex)
510
      {
511
        MARSHAL m = new MARSHAL("Unable to read chunks");
512
        m.minor = Minor.Value;
513
        m.initCause(ex);
514
        throw m;
515
      }
516
 
517
    return readValue(input, position, value, helper, id, ids, codebase);
518
  }
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
        BufferredCdrInput in = (BufferredCdrInput) input;
531
        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
            MARSHAL m = new MARSHAL("readNestedValue: must be chunked");
567
            m.minor = Minor.Chunks;
568
            throw m;
569
          }
570
        else if (value_tag == vt_NULL)
571
          {
572
            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
683
    // The IDL-generated io operations are implemented.
684
    if (value instanceof Streamable)
685
      {
686
        ((Streamable) value)._read(input);
687
      }
688
    else if (helper != null)
689
      {
690
        // If helper is non-null the value should normally be null.
691
        value = helper.read_value(input);
692
        g.objectWritten(value, position);
693
      }
694
    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
        if (id != null)
701
          factory = orb.lookup_value_factory(id);
702
 
703
        if (factory == null && ids != null)
704
          {
705
            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
        if (ids != null && ids.length > 0)
722
          id = ids[0];
723
 
724
        value = handler.readValue(input, position, value.getClass(), id, g);
725
        ok = true;
726
      }
727
 
728
    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.
771
   *
772
   * @param output a stream to write to.
773
   *
774
   * @param value a value type object, must be either Streamable or
775
   * CustomMarshal.
776
   *
777
   * @throws MARSHAL if the writing failed due any reason.
778
   */
779
  public static void write(OutputStream output, Serializable value)
780
  {
781
    // Write null if this is a null value.
782
    if (value == null)
783
      output.write_long(vt_NULL);
784
    else if (value instanceof String)
785
      write(output, value, m_StringValueHelper);
786
    else
787
      write(output, value, value.getClass());
788
  }
789
 
790
  /**
791
   * Write the value base into the given stream, stating that it is an instance
792
   * of the given class.
793
   *
794
   * @param output a stream to write to.
795
   *
796
   * @param value a value to write.
797
   *
798
   * @throws MARSHAL if the writing failed due any reason.
799
   */
800
  public static void write(OutputStream output, Serializable value,
801
    Class substitute)
802
  {
803
    // Write null if this is a null value.
804
    if (value == null)
805
      output.write_long(vt_NULL);
806
    else if (value instanceof String || substitute == String.class)
807
      writeString(output, value);
808
    else
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
847
      {
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. 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.
861
   * @param value a value to write.
862
   * @param id a value repository id.
863
   */
864
  public static void write(OutputStream output, Serializable value, String id)
865
  {
866
    if (value == null)
867
      output.write_long(vt_NULL);
868
    else
869
      write_instance(output, value, id, getHelper(value.getClass(), id));
870
  }
871
 
872
  /**
873
   * Write standard value type header, followed by contents, produced by the
874
   * boxed value helper.
875
   *
876
   * @param output the stream to write to.
877
   * @param value the value to write, can be null.
878
   * @param helper the helper that writes the value content if it is not null
879
   * (must be provided for this method).
880
   */
881
  public static void write(OutputStream output, Serializable value,
882
    BoxedValueHelper helper)
883
  {
884
    if (helper == null)
885
      throw new AssertionError("Helper must be provided");
886
    if (value == null)
887
      output.write_long(vt_NULL);
888
    else
889
      write_instance(output, value, helper.get_id(), helper);
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
        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 (USE_CHUNKING)
971
          {
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
996
          // 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
            // 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 (after header).
1023
   */
1024
  static void writeValue(OutputStream output, Serializable value,
1025
    BoxedValueHelper helper)
1026
  {
1027
    ((gnuValueStream) output).getRunTime().target = value;
1028
    if (helper != null)
1029
      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
  static boolean writeSelf(OutputStream output, Serializable value)
1054
  {
1055
    // User defined write method is present.
1056
    if (value instanceof CustomMarshal)
1057
      {
1058
        ((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
  /**
1070
   * 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
    int offset = an_input.read_long();
1086
    if (offset > -INT_SIZE)
1087
      {
1088
        MARSHAL m = new MARSHAL("Indirection tag refers to " + offset
1089
        + " (must be less than -" + INT_SIZE + ")");
1090
        m.minor = Minor.Offset;
1091
        throw m;
1092
      }
1093
 
1094
    int stored_at = current_pos + offset;
1095
 
1096
    if (in.getRunTime() == null)
1097
      {
1098
        MARSHAL m = new MARSHAL(stored_at + " offset " + offset + ": not written");
1099
        m.minor = Minor.Value;
1100
        throw m;
1101
      }
1102
 
1103
    return (Serializable) in.getRunTime().isObjectWrittenAt(stored_at, offset);
1104
  }
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
1182
          {
1183
            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 (Exception ex)
1222
          {
1223
            MARSHAL m = new MARSHAL("Unable to instantiate " + id);
1224
            m.minor = Minor.Instantiation;
1225
            m.initCause(ex);
1226
            throw m;
1227
          }
1228
      }
1229
    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
        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
1251
      {
1252
        gnuRuntime r = g.getRunTime();
1253
        int base = g.getPosition();
1254
        int delta = input.read_long();
1255
        if (r == null)
1256
          {
1257
            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
  /**
1271
   * Read string array, expecting the probable indirection.
1272
   */
1273
  static String[] read_string_array(InputStream input)
1274
  {
1275
    gnuValueStream g = (gnuValueStream) input;
1276
    int previous = g.getPosition();
1277
    int l = input.read_long();
1278
    if (l != vt_INDIRECTION)
1279
      {
1280
        g.seek(previous);
1281
        String[] s = StringSeqHelper.read(input);
1282
        if (g.getRunTime() == null)
1283
          g.setRunTime(new gnuRuntime(null, null));
1284
        g.getRunTime().objectWritten(s, previous);
1285
        return s;
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
        else
1301
          {
1302
            return (String[]) r.isObjectWrittenAt(base + delta, delta);
1303
          }
1304
      }
1305
  }
1306
 
1307
  /**
1308
   * Write repository Id, probably shared.
1309
   */
1310
  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
  /**
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
        gnuValueStream b = (gnuValueStream) output;
1344
        if (b != null)
1345
          {
1346
            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
      }
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
            h = locateHelper(ia[i]);
1384
            if (h != null)
1385
              return h;
1386
          }
1387
        return null;
1388
      }
1389
    else
1390
      return null;
1391
  }
1392
 
1393
  /**
1394
   * 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
   * Get the current position.
1441
   */
1442
  static int getCurrentPosition(InputStream x)
1443
  {
1444
    if (x instanceof gnuValueStream)
1445
      return ((gnuValueStream) x).getPosition();
1446
    else
1447
      return 0;
1448
  }
1449
 
1450
  /**
1451
   * Instantiate an instance of this class anyway; also in the case when it has
1452
   * no parameterless or any other constructor. The fields will be assigned
1453
   * while reading the class from the stream.
1454
   *
1455
   * @param clazz a class for that the instance should be instantiated.
1456
   */
1457
  public static Object instantiateAnyWay(Class clazz)
1458
    throws Exception
1459
  {
1460
    Class first_nonserial = clazz;
1461
 
1462
    while (Serializable.class.isAssignableFrom(first_nonserial)
1463
      || Modifier.isAbstract(first_nonserial.getModifiers()))
1464
      first_nonserial = first_nonserial.getSuperclass();
1465
 
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
}

powered by: WebSVN 2.1.0

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