IIOPOutputStream.java revision 807:408c9c621938
1/* 2 * Copyright (c) 1998, 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 */ 25/* 26 * Licensed Materials - Property of IBM 27 * RMI-IIOP v1.0 28 * Copyright IBM Corp. 1998 1999 All Rights Reserved 29 * 30 */ 31 32package com.sun.corba.se.impl.io; 33 34import org.omg.CORBA.portable.OutputStream; 35 36import java.security.AccessController ; 37import java.security.PrivilegedAction ; 38 39import java.io.IOException; 40import java.io.InvalidClassException; 41import java.io.Externalizable; 42import java.io.NotSerializableException; 43import java.io.NotActiveException; 44 45import java.lang.reflect.InvocationTargetException; 46 47import javax.rmi.CORBA.Util; 48 49import sun.corba.Bridge ; 50 51import com.sun.corba.se.impl.util.Utility; 52import com.sun.corba.se.impl.util.RepositoryId; 53 54import com.sun.corba.se.spi.logging.CORBALogDomains ; 55import com.sun.corba.se.impl.logging.UtilSystemException ; 56 57/** 58 * IIOPOutputStream is ... 59 * 60 * @author Stephen Lewallen 61 * @since JDK1.1.6 62 */ 63 64public class IIOPOutputStream 65 extends com.sun.corba.se.impl.io.OutputStreamHook 66{ 67 private UtilSystemException wrapper = UtilSystemException.get( 68 CORBALogDomains.RPC_ENCODING ) ; 69 70 private static Bridge bridge = 71 (Bridge)AccessController.doPrivileged( 72 new PrivilegedAction() { 73 public Object run() { 74 return Bridge.get() ; 75 } 76 } 77 ) ; 78 79 private org.omg.CORBA_2_3.portable.OutputStream orbStream; 80 81 private Object currentObject = null; 82 83 private ObjectStreamClass currentClassDesc = null; 84 85 private int recursionDepth = 0; 86 87 private int simpleWriteDepth = 0; 88 89 private IOException abortIOException = null; 90 91 private java.util.Stack classDescStack = new java.util.Stack(); 92 93 // Used when calling an object's writeObject method 94 private Object[] writeObjectArgList = {this}; 95 96 public IIOPOutputStream() 97 throws java.io.IOException 98 { 99 super(); 100 } 101 102 // If using RMI-IIOP stream format version 2, this tells 103 // the ORB stream (which must be a ValueOutputStream) to 104 // begin a new valuetype to contain the optional data 105 // of the writeObject method. 106 protected void beginOptionalCustomData() { 107 108 if (streamFormatVersion == 2) { 109 110 org.omg.CORBA.portable.ValueOutputStream vout 111 = (org.omg.CORBA.portable.ValueOutputStream)orbStream; 112 113 vout.start_value(currentClassDesc.getRMIIIOPOptionalDataRepId()); 114 } 115 } 116 117 final void setOrbStream(org.omg.CORBA_2_3.portable.OutputStream os) { 118 orbStream = os; 119 } 120 121 final org.omg.CORBA_2_3.portable.OutputStream getOrbStream() { 122 return orbStream; 123 } 124 125 final void increaseRecursionDepth(){ 126 recursionDepth++; 127 } 128 129 final int decreaseRecursionDepth(){ 130 return --recursionDepth; 131 } 132 133 /** 134 * Override the actions of the final method "writeObject()" 135 * in ObjectOutputStream. 136 * @since JDK1.1.6 137 */ 138 public final void writeObjectOverride(Object obj) 139 throws IOException 140 { 141 writeObjectState.writeData(this); 142 143 Util.writeAbstractObject((OutputStream)orbStream, obj); 144 } 145 146 /** 147 * Override the actions of the final method "writeObject()" 148 * in ObjectOutputStream. 149 * @since JDK1.1.6 150 */ 151 public final void simpleWriteObject(Object obj, byte formatVersion) 152 /* throws IOException */ 153 { 154 byte oldStreamFormatVersion = streamFormatVersion; 155 156 streamFormatVersion = formatVersion; 157 158 Object prevObject = currentObject; 159 ObjectStreamClass prevClassDesc = currentClassDesc; 160 simpleWriteDepth++; 161 162 try { 163 // if (!checkSpecialClasses(obj) && !checkSubstitutableSpecialClasses(obj)) 164 outputObject(obj); 165 166 } catch (IOException ee) { 167 if (abortIOException == null) 168 abortIOException = ee; 169 } finally { 170 /* Restore state of previous call incase this is a nested call */ 171 streamFormatVersion = oldStreamFormatVersion; 172 simpleWriteDepth--; 173 currentObject = prevObject; 174 currentClassDesc = prevClassDesc; 175 } 176 177 /* If the recursion depth is 0, test for and clear the pending exception. 178 * If there is a pending exception throw it. 179 */ 180 IOException pending = abortIOException; 181 if (simpleWriteDepth == 0) 182 abortIOException = null; 183 if (pending != null) { 184 bridge.throwException( pending ) ; 185 } 186 } 187 188 // Required by the superclass. 189 ObjectStreamField[] getFieldsNoCopy() { 190 return currentClassDesc.getFieldsNoCopy(); 191 } 192 193 /** 194 * Override the actions of the final method "defaultWriteObject()" 195 * in ObjectOutputStream. 196 * @since JDK1.1.6 197 */ 198 public final void defaultWriteObjectDelegate() 199 /* throws IOException */ 200 { 201 try { 202 if (currentObject == null || currentClassDesc == null) 203 // XXX I18N, Logging needed. 204 throw new NotActiveException("defaultWriteObjectDelegate"); 205 206 ObjectStreamField[] fields = 207 currentClassDesc.getFieldsNoCopy(); 208 if (fields.length > 0) { 209 outputClassFields(currentObject, currentClassDesc.forClass(), 210 fields); 211 } 212 } catch(IOException ioe) { 213 bridge.throwException(ioe); 214 } 215 } 216 217 /** 218 * Override the actions of the final method "enableReplaceObject()" 219 * in ObjectOutputStream. 220 * @since JDK1.1.6 221 */ 222 public final boolean enableReplaceObjectDelegate(boolean enable) 223 /* throws SecurityException */ 224 { 225 return false; 226 227 } 228 229 230 protected final void annotateClass(Class<?> cl) throws IOException{ 231 // XXX I18N, Logging needed. 232 throw new IOException("Method annotateClass not supported"); 233 } 234 235 public final void close() throws IOException{ 236 // no op 237 } 238 239 protected final void drain() throws IOException{ 240 // no op 241 } 242 243 public final void flush() throws IOException{ 244 try{ 245 orbStream.flush(); 246 } catch(Error e) { 247 IOException ioexc = new IOException(e.getMessage()); 248 ioexc.initCause(e) ; 249 throw ioexc ; 250 } 251 } 252 253 protected final Object replaceObject(Object obj) throws IOException{ 254 // XXX I18N, Logging needed. 255 throw new IOException("Method replaceObject not supported"); 256 } 257 258 /** 259 * Reset will disregard the state of any objects already written 260 * to the stream. The state is reset to be the same as a new 261 * ObjectOutputStream. The current point in the stream is marked 262 * as reset so the corresponding ObjectInputStream will be reset 263 * at the same point. Objects previously written to the stream 264 * will not be refered to as already being in the stream. They 265 * will be written to the stream again. 266 * @since JDK1.1 267 */ 268 public final void reset() throws IOException{ 269 try{ 270 //orbStream.reset(); 271 272 if (currentObject != null || currentClassDesc != null) 273 // XXX I18N, Logging needed. 274 throw new IOException("Illegal call to reset"); 275 276 abortIOException = null; 277 278 if (classDescStack == null) 279 classDescStack = new java.util.Stack(); 280 else 281 classDescStack.setSize(0); 282 283 } catch(Error e) { 284 IOException ioexc = new IOException(e.getMessage()); 285 ioexc.initCause(e) ; 286 throw ioexc ; 287 } 288 } 289 290 public final void write(byte b[]) throws IOException{ 291 try{ 292 writeObjectState.writeData(this); 293 294 orbStream.write_octet_array(b, 0, b.length); 295 } catch(Error e) { 296 IOException ioexc = new IOException(e.getMessage()); 297 ioexc.initCause(e) ; 298 throw ioexc ; 299 } 300 } 301 302 public final void write(byte b[], int off, int len) throws IOException{ 303 try{ 304 writeObjectState.writeData(this); 305 306 orbStream.write_octet_array(b, off, len); 307 } catch(Error e) { 308 IOException ioexc = new IOException(e.getMessage()); 309 ioexc.initCause(e) ; 310 throw ioexc ; 311 } 312 } 313 314 public final void write(int data) throws IOException{ 315 try{ 316 writeObjectState.writeData(this); 317 318 orbStream.write_octet((byte)(data & 0xFF)); 319 } catch(Error e) { 320 IOException ioexc = new IOException(e.getMessage()); 321 ioexc.initCause(e) ; 322 throw ioexc ; 323 } 324 } 325 326 public final void writeBoolean(boolean data) throws IOException{ 327 try{ 328 writeObjectState.writeData(this); 329 330 orbStream.write_boolean(data); 331 } catch(Error e) { 332 IOException ioexc = new IOException(e.getMessage()); 333 ioexc.initCause(e) ; 334 throw ioexc ; 335 } 336 } 337 338 public final void writeByte(int data) throws IOException{ 339 try{ 340 writeObjectState.writeData(this); 341 342 orbStream.write_octet((byte)data); 343 } catch(Error e) { 344 IOException ioexc = new IOException(e.getMessage()); 345 ioexc.initCause(e) ; 346 throw ioexc ; 347 } 348 } 349 350 public final void writeBytes(String data) throws IOException{ 351 try{ 352 writeObjectState.writeData(this); 353 354 byte buf[] = data.getBytes(); 355 orbStream.write_octet_array(buf, 0, buf.length); 356 } catch(Error e) { 357 IOException ioexc = new IOException(e.getMessage()); 358 ioexc.initCause(e) ; 359 throw ioexc ; 360 } 361 } 362 363 public final void writeChar(int data) throws IOException{ 364 try{ 365 writeObjectState.writeData(this); 366 367 orbStream.write_wchar((char)data); 368 } catch(Error e) { 369 IOException ioexc = new IOException(e.getMessage()); 370 ioexc.initCause(e) ; 371 throw ioexc ; 372 } 373 } 374 375 public final void writeChars(String data) throws IOException{ 376 try{ 377 writeObjectState.writeData(this); 378 379 char buf[] = data.toCharArray(); 380 orbStream.write_wchar_array(buf, 0, buf.length); 381 } catch(Error e) { 382 IOException ioexc = new IOException(e.getMessage()); 383 ioexc.initCause(e) ; 384 throw ioexc ; 385 } 386 } 387 388 public final void writeDouble(double data) throws IOException{ 389 try{ 390 writeObjectState.writeData(this); 391 392 orbStream.write_double(data); 393 } catch(Error e) { 394 IOException ioexc = new IOException(e.getMessage()); 395 ioexc.initCause(e) ; 396 throw ioexc ; 397 } 398 } 399 400 public final void writeFloat(float data) throws IOException{ 401 try{ 402 writeObjectState.writeData(this); 403 404 orbStream.write_float(data); 405 } catch(Error e) { 406 IOException ioexc = new IOException(e.getMessage()); 407 ioexc.initCause(e) ; 408 throw ioexc ; 409 } 410 } 411 412 public final void writeInt(int data) throws IOException{ 413 try{ 414 writeObjectState.writeData(this); 415 416 orbStream.write_long(data); 417 } catch(Error e) { 418 IOException ioexc = new IOException(e.getMessage()); 419 ioexc.initCause(e) ; 420 throw ioexc ; 421 } 422 } 423 424 public final void writeLong(long data) throws IOException{ 425 try{ 426 writeObjectState.writeData(this); 427 428 orbStream.write_longlong(data); 429 } catch(Error e) { 430 IOException ioexc = new IOException(e.getMessage()); 431 ioexc.initCause(e) ; 432 throw ioexc ; 433 } 434 } 435 436 public final void writeShort(int data) throws IOException{ 437 try{ 438 writeObjectState.writeData(this); 439 440 orbStream.write_short((short)data); 441 } catch(Error e) { 442 IOException ioexc = new IOException(e.getMessage()); 443 ioexc.initCause(e) ; 444 throw ioexc ; 445 } 446 } 447 448 protected final void writeStreamHeader() throws IOException{ 449 // no op 450 } 451 452 /** 453 * Helper method for correcting the Kestrel bug 4367783 (dealing 454 * with larger than 8-bit chars). The old behavior is preserved 455 * in orbutil.IIOPInputStream_1_3 in order to interoperate with 456 * our legacy ORBs. 457 */ 458 protected void internalWriteUTF(org.omg.CORBA.portable.OutputStream stream, 459 String data) 460 { 461 stream.write_wstring(data); 462 } 463 464 public final void writeUTF(String data) throws IOException{ 465 try{ 466 writeObjectState.writeData(this); 467 468 internalWriteUTF(orbStream, data); 469 } catch(Error e) { 470 IOException ioexc = new IOException(e.getMessage()); 471 ioexc.initCause(e) ; 472 throw ioexc ; 473 } 474 } 475 476 // INTERNAL UTILITY METHODS 477 /* 478 * Check for special cases of serializing objects. 479 * These objects are not subject to replacement. 480 */ 481 private boolean checkSpecialClasses(Object obj) throws IOException { 482 483 /* 484 * If this is a class, don't allow substitution 485 */ 486 //if (obj instanceof Class) { 487 // throw new IOException("Serialization of Class not supported"); 488 //} 489 490 if (obj instanceof ObjectStreamClass) { 491 // XXX I18N, Logging needed. 492 throw new IOException("Serialization of ObjectStreamClass not supported"); 493 } 494 495 return false; 496 } 497 498 /* 499 * Check for special cases of substitutable serializing objects. 500 * These classes are replaceable. 501 */ 502 private boolean checkSubstitutableSpecialClasses(Object obj) 503 throws IOException 504 { 505 if (obj instanceof String) { 506 orbStream.write_value((java.io.Serializable)obj); 507 return true; 508 } 509 510 //if (obj.getClass().isArray()) { 511 // outputArray(obj); 512 // return true; 513 //} 514 515 return false; 516 } 517 518 /* 519 * Write out the object 520 */ 521 private void outputObject(final Object obj) throws IOException{ 522 523 currentObject = obj; 524 Class currclass = obj.getClass(); 525 526 /* Get the Class descriptor for this class, 527 * Throw a NotSerializableException if there is none. 528 */ 529 currentClassDesc = ObjectStreamClass.lookup(currclass); 530 if (currentClassDesc == null) { 531 // XXX I18N, Logging needed. 532 throw new NotSerializableException(currclass.getName()); 533 } 534 535 /* If the object is externalizable, 536 * call writeExternal. 537 * else do Serializable processing. 538 */ 539 if (currentClassDesc.isExternalizable()) { 540 // Write format version 541 orbStream.write_octet(streamFormatVersion); 542 543 Externalizable ext = (Externalizable)obj; 544 ext.writeExternal(this); 545 546 } else { 547 548 /* The object's classes should be processed from supertype to subtype 549 * Push all the clases of the current object onto a stack. 550 * Remember the stack pointer where this set of classes is being pushed. 551 */ 552 if (currentClassDesc.forClass().getName().equals("java.lang.String")) { 553 this.writeUTF((String)obj); 554 return; 555 } 556 int stackMark = classDescStack.size(); 557 try { 558 ObjectStreamClass next; 559 while ((next = currentClassDesc.getSuperclass()) != null) { 560 classDescStack.push(currentClassDesc); 561 currentClassDesc = next; 562 } 563 564 /* 565 * For currentClassDesc and all the pushed class descriptors 566 * If the class is writing its own data 567 * set blockData = true; call the class writeObject method 568 * If not 569 * invoke either the defaultWriteObject method. 570 */ 571 do { 572 573 WriteObjectState oldState = writeObjectState; 574 575 try { 576 577 setState(NOT_IN_WRITE_OBJECT); 578 579 if (currentClassDesc.hasWriteObject()) { 580 invokeObjectWriter(currentClassDesc, obj ); 581 } else { 582 defaultWriteObjectDelegate(); 583 } 584 } finally { 585 setState(oldState); 586 } 587 588 } while (classDescStack.size() > stackMark && 589 (currentClassDesc = (ObjectStreamClass)classDescStack.pop()) != null); 590 } finally { 591 classDescStack.setSize(stackMark); 592 } 593 } 594 } 595 596 /* 597 * Invoke writer. 598 * _REVISIT_ invokeObjectWriter and invokeObjectReader behave inconsistently with each other since 599 * the reader returns a boolean...fix later 600 */ 601 private void invokeObjectWriter(ObjectStreamClass osc, Object obj) 602 throws IOException 603 { 604 Class c = osc.forClass() ; 605 606 try { 607 608 // Write format version 609 orbStream.write_octet(streamFormatVersion); 610 611 writeObjectState.enterWriteObject(this); 612 613 // writeObject(obj, c, this); 614 osc.invokeWriteObject( obj, this ) ; 615 616 writeObjectState.exitWriteObject(this); 617 618 } catch (InvocationTargetException e) { 619 Throwable t = e.getTargetException(); 620 if (t instanceof IOException) 621 throw (IOException)t; 622 else if (t instanceof RuntimeException) 623 throw (RuntimeException) t; 624 else if (t instanceof Error) 625 throw (Error) t; 626 else 627 // XXX I18N, Logging needed. 628 throw new Error("invokeObjectWriter internal error",e); 629 } 630 } 631 632 void writeField(ObjectStreamField field, Object value) throws IOException { 633 switch (field.getTypeCode()) { 634 case 'B': 635 if (value == null) 636 orbStream.write_octet((byte)0); 637 else 638 orbStream.write_octet(((Byte)value).byteValue()); 639 break; 640 case 'C': 641 if (value == null) 642 orbStream.write_wchar((char)0); 643 else 644 orbStream.write_wchar(((Character)value).charValue()); 645 break; 646 case 'F': 647 if (value == null) 648 orbStream.write_float((float)0); 649 else 650 orbStream.write_float(((Float)value).floatValue()); 651 break; 652 case 'D': 653 if (value == null) 654 orbStream.write_double((double)0); 655 else 656 orbStream.write_double(((Double)value).doubleValue()); 657 break; 658 case 'I': 659 if (value == null) 660 orbStream.write_long((int)0); 661 else 662 orbStream.write_long(((Integer)value).intValue()); 663 break; 664 case 'J': 665 if (value == null) 666 orbStream.write_longlong((long)0); 667 else 668 orbStream.write_longlong(((Long)value).longValue()); 669 break; 670 case 'S': 671 if (value == null) 672 orbStream.write_short((short)0); 673 else 674 orbStream.write_short(((Short)value).shortValue()); 675 break; 676 case 'Z': 677 if (value == null) 678 orbStream.write_boolean(false); 679 else 680 orbStream.write_boolean(((Boolean)value).booleanValue()); 681 break; 682 case '[': 683 case 'L': 684 // What to do if it's null? 685 writeObjectField(field, value); 686 break; 687 default: 688 // XXX I18N, Logging needed. 689 throw new InvalidClassException(currentClassDesc.getName()); 690 } 691 } 692 693 private void writeObjectField(ObjectStreamField field, 694 Object objectValue) throws IOException { 695 696 if (ObjectStreamClassCorbaExt.isAny(field.getTypeString())) { 697 javax.rmi.CORBA.Util.writeAny(orbStream, objectValue); 698 } 699 else { 700 Class type = field.getType(); 701 int callType = ValueHandlerImpl.kValueType; 702 703 if (type.isInterface()) { 704 String className = type.getName(); 705 706 if (java.rmi.Remote.class.isAssignableFrom(type)) { 707 708 // RMI Object reference... 709 710 callType = ValueHandlerImpl.kRemoteType; 711 712 713 } else if (org.omg.CORBA.Object.class.isAssignableFrom(type)){ 714 715 // IDL Object reference... 716 callType = ValueHandlerImpl.kRemoteType; 717 718 } else if (RepositoryId.isAbstractBase(type)) { 719 // IDL Abstract Object reference... 720 callType = ValueHandlerImpl.kAbstractType; 721 } else if (ObjectStreamClassCorbaExt.isAbstractInterface(type)) { 722 callType = ValueHandlerImpl.kAbstractType; 723 } 724 } 725 726 switch (callType) { 727 case ValueHandlerImpl.kRemoteType: 728 Util.writeRemoteObject(orbStream, objectValue); 729 break; 730 case ValueHandlerImpl.kAbstractType: 731 Util.writeAbstractObject(orbStream, objectValue); 732 break; 733 case ValueHandlerImpl.kValueType: 734 try{ 735 orbStream.write_value((java.io.Serializable)objectValue, type); 736 } 737 catch(ClassCastException cce){ 738 if (objectValue instanceof java.io.Serializable) 739 throw cce; 740 else 741 Utility.throwNotSerializableForCorba(objectValue.getClass().getName()); 742 } 743 } 744 } 745 } 746 747 /* Write the fields of the specified class by invoking the appropriate 748 * write* method on this class. 749 */ 750 private void outputClassFields(Object o, Class cl, 751 ObjectStreamField[] fields) 752 throws IOException { 753 754 for (int i = 0; i < fields.length; i++) { 755 if (fields[i].getField() == null) 756 throw new InvalidClassException(cl.getName(), 757 "Nonexistent field " + fields[i].getName()); 758 switch (fields[i].getTypeCode()) { 759 case 'B': 760 byte byteValue = bridge.getByte(o, fields[i].getFieldID()) ; 761 orbStream.write_octet(byteValue); 762 break; 763 case 'C': 764 char charValue = bridge.getChar(o, fields[i].getFieldID()) ; 765 orbStream.write_wchar(charValue); 766 break; 767 case 'F': 768 float floatValue = bridge.getFloat(o, fields[i].getFieldID()) ; 769 orbStream.write_float(floatValue); 770 break; 771 case 'D' : 772 double doubleValue = bridge.getDouble(o, fields[i].getFieldID()) ; 773 orbStream.write_double(doubleValue); 774 break; 775 case 'I': 776 int intValue = bridge.getInt(o, fields[i].getFieldID()) ; 777 orbStream.write_long(intValue); 778 break; 779 case 'J': 780 long longValue = bridge.getLong(o, fields[i].getFieldID()) ; 781 orbStream.write_longlong(longValue); 782 break; 783 case 'S': 784 short shortValue = bridge.getShort(o, fields[i].getFieldID()) ; 785 orbStream.write_short(shortValue); 786 break; 787 case 'Z': 788 boolean booleanValue = bridge.getBoolean(o, fields[i].getFieldID()) ; 789 orbStream.write_boolean(booleanValue); 790 break; 791 case '[': 792 case 'L': 793 Object objectValue = bridge.getObject(o, fields[i].getFieldID()) ; 794 writeObjectField(fields[i], objectValue); 795 break; 796 default: 797 throw new InvalidClassException(cl.getName()); 798 } 799 } 800 } 801} 802