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