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