IDLJavaSerializationOutputStream.java revision 608:7e06bf1dcb09
1/* 2 * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25package com.sun.corba.se.impl.encoding; 26 27import java.io.IOException; 28import java.io.ObjectOutputStream; 29import java.io.ByteArrayOutputStream; 30 31import java.nio.ByteBuffer; 32 33import com.sun.corba.se.spi.orb.ORB; 34import com.sun.corba.se.spi.ior.IOR; 35import com.sun.corba.se.spi.ior.IORFactories; 36import com.sun.corba.se.spi.ior.iiop.GIOPVersion; 37import com.sun.corba.se.spi.logging.CORBALogDomains; 38import com.sun.corba.se.spi.presentation.rmi.StubAdapter; 39 40import com.sun.corba.se.impl.util.Utility; 41import com.sun.corba.se.impl.orbutil.ORBConstants; 42import com.sun.corba.se.impl.orbutil.ORBUtility; 43import com.sun.corba.se.impl.corba.TypeCodeImpl; 44import com.sun.corba.se.impl.logging.ORBUtilSystemException; 45import com.sun.corba.se.impl.protocol.giopmsgheaders.Message; 46 47import org.omg.CORBA.Any; 48import org.omg.CORBA.TypeCode; 49import org.omg.CORBA.Principal; 50import org.omg.CORBA.CompletionStatus; 51 52/** 53 * Implementation class that uses Java serialization for output streams. 54 * This assumes a GIOP version 1.2 message format. 55 * 56 * This class uses a ByteArrayOutputStream as the underlying buffer. The 57 * first 16 bytes are direct writes into the underlying buffer. This allows 58 * [GIOPHeader (12 bytes) + requestID (4 bytes)] to be written as bytes. 59 * Subsequent write operations on this output stream object uses 60 * ObjectOutputStream class to write into the buffer. This allows marshaling 61 * complex types and graphs using the ObjectOutputStream implementation. 62 * 63 * Note, this class assumes a GIOP 1.2 style header. Note, we expect that the 64 * first 16 bytes are written only using the write_octet, write_long or 65 * write_ulong method calls. 66 * 67 * @author Ram Jeyaraman 68 */ 69final class IDLJavaSerializationOutputStream extends CDROutputStreamBase { 70 71 private ORB orb; 72 private byte encodingVersion; 73 private ObjectOutputStream os; 74 private _ByteArrayOutputStream bos; 75 private BufferManagerWrite bufferManager; 76 77 // [GIOPHeader(12) + requestID(4)] bytes 78 private final int directWriteLength = Message.GIOPMessageHeaderLength + 4; 79 80 protected ORBUtilSystemException wrapper; 81 82 class _ByteArrayOutputStream extends ByteArrayOutputStream { 83 84 _ByteArrayOutputStream(int initialSize) { 85 super(initialSize); 86 } 87 88 byte[] getByteArray() { 89 return this.buf; 90 } 91 } 92 93 class MarshalObjectOutputStream extends ObjectOutputStream { 94 95 ORB orb; 96 97 MarshalObjectOutputStream(java.io.OutputStream out, ORB orb) 98 throws IOException { 99 100 super(out); 101 this.orb = orb; 102 java.security.AccessController.doPrivileged( 103 new java.security.PrivilegedAction() { 104 public Object run() { 105 // needs SerializablePermission("enableSubstitution") 106 enableReplaceObject(true); 107 return null; 108 } 109 } 110 ); 111 } 112 113 /** 114 * Checks for objects that are instances of java.rmi.Remote 115 * that need to be serialized as proxy (Stub) objects. 116 */ 117 protected final Object replaceObject(Object obj) throws IOException { 118 try { 119 if ((obj instanceof java.rmi.Remote) && 120 !(StubAdapter.isStub(obj))) { 121 return Utility.autoConnect(obj, orb, true); 122 } 123 } catch (Exception e) { 124 IOException ie = new IOException("replaceObject failed"); 125 ie.initCause(e); 126 throw ie; 127 } 128 return obj; 129 } 130 } 131 132 public IDLJavaSerializationOutputStream(byte encodingVersion) { 133 super(); 134 this.encodingVersion = encodingVersion; 135 } 136 137 public void init(org.omg.CORBA.ORB orb, boolean littleEndian, 138 BufferManagerWrite bufferManager, 139 byte streamFormatVersion, 140 boolean usePooledByteBuffers) { 141 this.orb = (ORB) orb; 142 this.bufferManager = bufferManager; 143 wrapper = ORBUtilSystemException.get((ORB) orb, 144 CORBALogDomains.RPC_ENCODING); 145 bos = 146 new _ByteArrayOutputStream(ORBConstants.GIOP_DEFAULT_BUFFER_SIZE); 147 } 148 149 // Called from read_octet or read_long or read_ulong method. 150 private void initObjectOutputStream() { 151 //System.out.print(" os "); 152 if (os != null) { 153 throw wrapper.javaStreamInitFailed(); 154 } 155 try { 156 os = new MarshalObjectOutputStream(bos, orb); 157 } catch (Exception e) { 158 throw wrapper.javaStreamInitFailed(e); 159 } 160 } 161 162 // org.omg.CORBA.portable.OutputStream 163 164 // Primitive types. 165 166 public final void write_boolean(boolean value) { 167 try { 168 os.writeBoolean(value); 169 } catch (Exception e) { 170 throw wrapper.javaSerializationException(e, "write_boolean"); 171 } 172 } 173 174 public final void write_char(char value) { 175 try { 176 os.writeChar(value); 177 } catch (Exception e) { 178 throw wrapper.javaSerializationException(e, "write_char"); 179 } 180 } 181 182 public final void write_wchar(char value) { 183 this.write_char(value); 184 } 185 186 public final void write_octet(byte value) { 187 188 // check if size < [ GIOPHeader(12) + requestID(4)] bytes 189 if (bos.size() < directWriteLength) { 190 bos.write(value); // direct write. 191 if (bos.size() == directWriteLength) { 192 initObjectOutputStream(); 193 } 194 return; 195 } 196 197 try { 198 os.writeByte(value); 199 } catch (Exception e) { 200 throw wrapper.javaSerializationException(e, "write_octet"); 201 } 202 } 203 204 public final void write_short(short value) { 205 try { 206 os.writeShort(value); 207 } catch (Exception e) { 208 throw wrapper.javaSerializationException(e, "write_short"); 209 } 210 } 211 212 public final void write_ushort(short value) { 213 this.write_short(value); 214 } 215 216 public final void write_long(int value) { 217 218 // check if size < [ GIOPHeader(12) + requestID(4)] bytes 219 if (bos.size() < directWriteLength) { 220 221 // Use big endian (network byte order). This is fixed. 222 // Both the writer and reader use the same byte order. 223 bos.write((byte)((value >>> 24) & 0xFF)); 224 bos.write((byte)((value >>> 16) & 0xFF)); 225 bos.write((byte)((value >>> 8) & 0xFF)); 226 bos.write((byte)((value >>> 0) & 0xFF)); 227 228 if (bos.size() == directWriteLength) { 229 initObjectOutputStream(); 230 } else if (bos.size() > directWriteLength) { 231 // Cannot happen. All direct writes are contained 232 // within the first 16 bytes. 233 wrapper.javaSerializationException("write_long"); 234 } 235 return; 236 } 237 238 try { 239 os.writeInt(value); 240 } catch (Exception e) { 241 throw wrapper.javaSerializationException(e, "write_long"); 242 } 243 } 244 245 public final void write_ulong(int value) { 246 this.write_long(value); 247 } 248 249 public final void write_longlong(long value) { 250 try { 251 os.writeLong(value); 252 } catch (Exception e) { 253 throw wrapper.javaSerializationException(e, "write_longlong"); 254 } 255 } 256 257 public final void write_ulonglong(long value) { 258 this.write_longlong(value); 259 } 260 261 public final void write_float(float value) { 262 try { 263 os.writeFloat(value); 264 } catch (Exception e) { 265 throw wrapper.javaSerializationException(e, "write_float"); 266 } 267 } 268 269 public final void write_double(double value) { 270 try { 271 os.writeDouble(value); 272 } catch (Exception e) { 273 throw wrapper.javaSerializationException(e, "write_double"); 274 } 275 } 276 277 // String types. 278 279 public final void write_string(String value) { 280 try { 281 os.writeUTF(value); 282 } catch (Exception e) { 283 throw wrapper.javaSerializationException(e, "write_string"); 284 } 285 } 286 287 public final void write_wstring(String value) { 288 try { 289 os.writeObject(value); 290 } catch (Exception e) { 291 throw wrapper.javaSerializationException(e, "write_wstring"); 292 } 293 } 294 295 // Array types. 296 297 public final void write_boolean_array(boolean[] value, 298 int offset, int length) { 299 for (int i = 0; i < length; i++) { 300 write_boolean(value[offset + i]); 301 } 302 } 303 304 public final void write_char_array(char[] value, int offset, int length) { 305 for (int i = 0; i < length; i++) { 306 write_char(value[offset + i]); 307 } 308 } 309 310 public final void write_wchar_array(char[] value, int offset, int length) { 311 write_char_array(value, offset, length); 312 } 313 314 public final void write_octet_array(byte[] value, int offset, int length) { 315 try { 316 os.write(value, offset, length); 317 } catch (Exception e) { 318 throw wrapper.javaSerializationException(e, "write_octet_array"); 319 } 320 } 321 322 public final void write_short_array(short[] value, 323 int offset, int length) { 324 for (int i = 0; i < length; i++) { 325 write_short(value[offset + i]); 326 } 327 } 328 329 public final void write_ushort_array(short[] value, 330 int offset, int length){ 331 write_short_array(value, offset, length); 332 } 333 334 public final void write_long_array(int[] value, int offset, int length) { 335 for (int i = 0; i < length; i++) { 336 write_long(value[offset + i]); 337 } 338 } 339 340 public final void write_ulong_array(int[] value, int offset, int length) { 341 write_long_array(value, offset, length); 342 } 343 344 public final void write_longlong_array(long[] value, 345 int offset, int length) { 346 for (int i = 0; i < length; i++) { 347 write_longlong(value[offset + i]); 348 } 349 } 350 351 public final void write_ulonglong_array(long[] value, 352 int offset,int length) { 353 write_longlong_array(value, offset, length); 354 } 355 356 public final void write_float_array(float[] value, 357 int offset, int length) { 358 for (int i = 0; i < length; i++) { 359 write_float(value[offset + i]); 360 } 361 } 362 363 public final void write_double_array(double[] value, 364 int offset, int length) { 365 for (int i = 0; i < length; i++) { 366 write_double(value[offset + i]); 367 } 368 } 369 370 // Complex types (objects and graphs). 371 372 public final void write_Object(org.omg.CORBA.Object value) { 373 if (value == null) { 374 IOR nullIOR = IORFactories.makeIOR(orb); 375 nullIOR.write(parent); 376 return; 377 } 378 // IDL to Java formal 01-06-06 1.21.4.2 379 if (value instanceof org.omg.CORBA.LocalObject) { 380 throw wrapper.writeLocalObject(CompletionStatus.COMPLETED_MAYBE); 381 } 382 IOR ior = ORBUtility.connectAndGetIOR(orb, value); 383 ior.write(parent); 384 return; 385 } 386 387 public final void write_TypeCode(TypeCode tc) { 388 if (tc == null) { 389 throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE); 390 } 391 TypeCodeImpl tci; 392 if (tc instanceof TypeCodeImpl) { 393 tci = (TypeCodeImpl) tc; 394 } else { 395 tci = new TypeCodeImpl(orb, tc); 396 } 397 tci.write_value((org.omg.CORBA_2_3.portable.OutputStream) parent); 398 } 399 400 public final void write_any(Any any) { 401 if (any == null) { 402 throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE); 403 } 404 write_TypeCode(any.type()); 405 any.write_value(parent); 406 } 407 408 public final void write_Principal(Principal p) { 409 // We don't need an implementation for this method, since principal 410 // is absent in GIOP version 1.2 or above. 411 write_long(p.name().length); 412 write_octet_array(p.name(), 0, p.name().length); 413 } 414 415 public final void write_fixed(java.math.BigDecimal bigDecimal) { 416 // This string might contain sign and/or dot 417 this.write_fixed(bigDecimal.toString(), bigDecimal.signum()); 418 } 419 420 // The string may contain a sign and dot 421 private void write_fixed(String string, int signum) { 422 423 int stringLength = string.length(); 424 425 // Each octet contains (up to) two decimal digits. 426 byte doubleDigit = 0; 427 char ch; 428 byte digit; 429 430 // First calculate the string length without optional sign and dot. 431 int numDigits = 0; 432 for (int i=0; i<stringLength; i++) { 433 ch = string.charAt(i); 434 if (ch == '-' || ch == '+' || ch == '.') 435 continue; 436 numDigits++; 437 } 438 439 for (int i=0; i<stringLength; i++) { 440 ch = string.charAt(i); 441 if (ch == '-' || ch == '+' || ch == '.') 442 continue; 443 digit = (byte)Character.digit(ch, 10); 444 if (digit == -1) { 445 throw wrapper.badDigitInFixed( 446 CompletionStatus.COMPLETED_MAYBE); 447 } 448 // If the fixed type has an odd number of decimal digits, then the 449 // representation begins with the first (most significant) digit. 450 // Otherwise, this first half-octet is all zero, and the first 451 // digit is in the second half-octet. 452 if (numDigits % 2 == 0) { 453 doubleDigit |= digit; 454 this.write_octet(doubleDigit); 455 doubleDigit = 0; 456 } else { 457 doubleDigit |= (digit << 4); 458 } 459 numDigits--; 460 } 461 462 // The sign configuration in the last half-octet of the representation, 463 // is 0xD for negative numbers and 0xC for positive and zero values. 464 if (signum == -1) { 465 doubleDigit |= 0xd; 466 } else { 467 doubleDigit |= 0xc; 468 } 469 this.write_octet(doubleDigit); 470 } 471 472 public final org.omg.CORBA.ORB orb() { 473 return this.orb; 474 } 475 476 // org.omg.CORBA_2_3.portable.OutputStream 477 478 public final void write_value(java.io.Serializable value) { 479 write_value(value, (String) null); 480 } 481 482 public final void write_value(java.io.Serializable value, 483 java.lang.Class clz) { 484 write_value(value); 485 } 486 487 public final void write_value(java.io.Serializable value, 488 String repository_id) { 489 try { 490 os.writeObject(value); 491 } catch (Exception e) { 492 throw wrapper.javaSerializationException(e, "write_value"); 493 } 494 } 495 496 public final void write_value(java.io.Serializable value, 497 org.omg.CORBA.portable.BoxedValueHelper factory) { 498 this.write_value(value, (String) null); 499 } 500 501 public final void write_abstract_interface(java.lang.Object obj) { 502 503 boolean isCorbaObject = false; // Assume value type. 504 org.omg.CORBA.Object theCorbaObject = null; 505 506 // Is it a CORBA.Object? 507 if (obj != null && obj instanceof org.omg.CORBA.Object) { 508 theCorbaObject = (org.omg.CORBA.Object)obj; 509 isCorbaObject = true; 510 } 511 512 // Write the boolean flag. 513 this.write_boolean(isCorbaObject); 514 515 // Now write out the object. 516 if (isCorbaObject) { 517 write_Object(theCorbaObject); 518 } else { 519 try { 520 write_value((java.io.Serializable)obj); 521 } catch(ClassCastException cce) { 522 if (obj instanceof java.io.Serializable) { 523 throw cce; 524 } else { 525 ORBUtility.throwNotSerializableForCorba( 526 obj.getClass().getName()); 527 } 528 } 529 } 530 } 531 532 // com.sun.corba.se.os.encoding.MarshalOutputStream 533 534 public final void start_block() { 535 throw wrapper.giopVersionError(); 536 } 537 538 public final void end_block() { 539 throw wrapper.giopVersionError(); 540 } 541 542 public final void putEndian() { 543 throw wrapper.giopVersionError(); 544 } 545 546 public void writeTo(java.io.OutputStream s) throws IOException { 547 try { 548 os.flush(); 549 bos.writeTo(s); 550 } catch (Exception e) { 551 throw wrapper.javaSerializationException(e, "writeTo"); 552 } 553 } 554 555 public final byte[] toByteArray() { 556 try { 557 os.flush(); 558 return bos.toByteArray(); // new copy. 559 } catch (Exception e) { 560 throw wrapper.javaSerializationException(e, "toByteArray"); 561 } 562 } 563 564 // org.omg.CORBA.DataOutputStream 565 566 public final void write_Abstract (java.lang.Object value) { 567 write_abstract_interface(value); 568 } 569 570 public final void write_Value(java.io.Serializable value) { 571 write_value(value); 572 } 573 574 public final void write_any_array(org.omg.CORBA.Any[] value, 575 int offset, int length) { 576 for(int i = 0; i < length; i++) { 577 write_any(value[offset + i]); 578 } 579 } 580 581 // org.omg.CORBA.portable.ValueBase 582 583 public final String[] _truncatable_ids() { 584 throw wrapper.giopVersionError(); 585 } 586 587 // Other. 588 589 public final int getSize() { 590 try { 591 os.flush(); 592 return bos.size(); 593 } catch (Exception e) { 594 throw wrapper.javaSerializationException(e, "write_boolean"); 595 } 596 } 597 598 public final int getIndex() { 599 return getSize(); 600 } 601 602 protected int getRealIndex(int index) { 603 return getSize(); 604 } 605 606 public final void setIndex(int value) { 607 throw wrapper.giopVersionError(); 608 } 609 610 public final ByteBuffer getByteBuffer() { 611 throw wrapper.giopVersionError(); 612 } 613 614 public final void setByteBuffer(ByteBuffer byteBuffer) { 615 throw wrapper.giopVersionError(); 616 } 617 618 public final boolean isLittleEndian() { 619 // Java serialization uses network byte order, that is, big-endian. 620 return false; 621 } 622 623 public ByteBufferWithInfo getByteBufferWithInfo() { 624 try { 625 os.flush(); 626 } catch (Exception e) { 627 throw wrapper.javaSerializationException( 628 e, "getByteBufferWithInfo"); 629 } 630 ByteBuffer byteBuffer = ByteBuffer.wrap(bos.getByteArray()); 631 byteBuffer.limit(bos.size()); 632 return new ByteBufferWithInfo(this.orb, byteBuffer, bos.size()); 633 } 634 635 public void setByteBufferWithInfo(ByteBufferWithInfo bbwi) { 636 throw wrapper.giopVersionError(); 637 } 638 639 public final BufferManagerWrite getBufferManager() { 640 return bufferManager; 641 } 642 643 // This will stay a custom add-on until the java-rtf issue is resolved. 644 // Then it should be declared in org.omg.CORBA.portable.OutputStream. 645 // 646 // Pads the string representation of bigDecimal with zeros to fit the given 647 // digits and scale before it gets written to the stream. 648 public final void write_fixed(java.math.BigDecimal bigDecimal, 649 short digits, short scale) { 650 String string = bigDecimal.toString(); 651 String integerPart; 652 String fractionPart; 653 StringBuffer stringBuffer; 654 655 // Get rid of the sign 656 if (string.charAt(0) == '-' || string.charAt(0) == '+') { 657 string = string.substring(1); 658 } 659 660 // Determine integer and fraction parts 661 int dotIndex = string.indexOf('.'); 662 if (dotIndex == -1) { 663 integerPart = string; 664 fractionPart = null; 665 } else if (dotIndex == 0 ) { 666 integerPart = null; 667 fractionPart = string; 668 } else { 669 integerPart = string.substring(0, dotIndex); 670 fractionPart = string.substring(dotIndex + 1); 671 } 672 673 // Pad both parts with zeros as necessary 674 stringBuffer = new StringBuffer(digits); 675 if (fractionPart != null) { 676 stringBuffer.append(fractionPart); 677 } 678 while (stringBuffer.length() < scale) { 679 stringBuffer.append('0'); 680 } 681 if (integerPart != null) { 682 stringBuffer.insert(0, integerPart); 683 } 684 while (stringBuffer.length() < digits) { 685 stringBuffer.insert(0, '0'); 686 } 687 688 // This string contains no sign or dot 689 this.write_fixed(stringBuffer.toString(), bigDecimal.signum()); 690 } 691 692 public final void writeOctetSequenceTo( 693 org.omg.CORBA.portable.OutputStream s) { 694 byte[] buf = this.toByteArray(); // new copy. 695 s.write_long(buf.length); 696 s.write_octet_array(buf, 0, buf.length); 697 } 698 699 public final GIOPVersion getGIOPVersion() { 700 return GIOPVersion.V1_2; 701 } 702 703 public final void writeIndirection(int tag, int posIndirectedTo) { 704 throw wrapper.giopVersionError(); 705 } 706 707 void freeInternalCaches() {} 708 709 void printBuffer() { 710 byte[] buf = this.toByteArray(); 711 712 System.out.println("+++++++ Output Buffer ++++++++"); 713 System.out.println(); 714 System.out.println("Current position: " + buf.length); 715 //System.out.println("Total length : " + buf.length); 716 System.out.println(); 717 718 char[] charBuf = new char[16]; 719 720 try { 721 722 for (int i = 0; i < buf.length; i += 16) { 723 724 int j = 0; 725 726 // For every 16 bytes, there is one line 727 // of output. First, the hex output of 728 // the 16 bytes with each byte separated 729 // by a space. 730 while (j < 16 && j + i < buf.length) { 731 int k = buf[i + j]; 732 if (k < 0) 733 k = 256 + k; 734 String hex = Integer.toHexString(k); 735 if (hex.length() == 1) 736 hex = "0" + hex; 737 System.out.print(hex + " "); 738 j++; 739 } 740 741 // Add any extra spaces to align the 742 // text column in case we didn't end 743 // at 16 744 while (j < 16) { 745 System.out.print(" "); 746 j++; 747 } 748 749 // Now output the ASCII equivalents. Non-ASCII 750 // characters are shown as periods. 751 int x = 0; 752 753 while (x < 16 && x + i < buf.length) { 754 if (ORBUtility.isPrintable((char)buf[i + x])) { 755 charBuf[x] = (char) buf[i + x]; 756 } else { 757 charBuf[x] = '.'; 758 } 759 x++; 760 } 761 System.out.println(new String(charBuf, 0, x)); 762 } 763 } catch (Throwable t) { 764 t.printStackTrace(); 765 } 766 System.out.println("++++++++++++++++++++++++++++++"); 767 } 768 769 public void alignOnBoundary(int octetBoundary) { 770 throw wrapper.giopVersionError(); 771 } 772 773 // Needed by request and reply messages for GIOP versions >= 1.2 only. 774 public void setHeaderPadding(boolean headerPadding) { 775 // no-op. We don't care about body alignment while using 776 // Java serialization. What the GIOP spec states does not apply here. 777 } 778 779 // ValueOutputStream ----------------------------- 780 781 public void start_value(String rep_id) { 782 throw wrapper.giopVersionError(); 783 } 784 785 public void end_value() { 786 throw wrapper.giopVersionError(); 787 } 788 789 // java.io.OutputStream 790 791 // Note: These methods are defined in the super class and accessible. 792 793 //public abstract void write(byte b[]) throws IOException; 794 //public abstract void write(byte b[], int off, int len) 795 // throws IOException; 796 //public abstract void flush() throws IOException; 797 //public abstract void close() throws IOException; 798} 799