1. /*
  2. * @(#)OutputStreamHook.java 1.13 03/12/19
  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 java.io.IOException;
  17. import java.io.OutputStream;
  18. import java.io.ObjectOutputStream;
  19. import java.io.ObjectOutput;
  20. import java.util.Hashtable;
  21. import org.omg.CORBA.INTERNAL;
  22. public abstract class OutputStreamHook extends ObjectOutputStream
  23. {
  24. private HookPutFields putFields = null;
  25. /**
  26. * Since ObjectOutputStream.PutField methods specify no exceptions,
  27. * we are not checking for null parameters on put methods.
  28. */
  29. private class HookPutFields extends ObjectOutputStream.PutField
  30. {
  31. private Hashtable fields = new Hashtable();
  32. /**
  33. * Put the value of the named boolean field into the persistent field.
  34. */
  35. public void put(String name, boolean value){
  36. fields.put(name, new Boolean(value));
  37. }
  38. /**
  39. * Put the value of the named char field into the persistent fields.
  40. */
  41. public void put(String name, char value){
  42. fields.put(name, new Character(value));
  43. }
  44. /**
  45. * Put the value of the named byte field into the persistent fields.
  46. */
  47. public void put(String name, byte value){
  48. fields.put(name, new Byte(value));
  49. }
  50. /**
  51. * Put the value of the named short field into the persistent fields.
  52. */
  53. public void put(String name, short value){
  54. fields.put(name, new Short(value));
  55. }
  56. /**
  57. * Put the value of the named int field into the persistent fields.
  58. */
  59. public void put(String name, int value){
  60. fields.put(name, new Integer(value));
  61. }
  62. /**
  63. * Put the value of the named long field into the persistent fields.
  64. */
  65. public void put(String name, long value){
  66. fields.put(name, new Long(value));
  67. }
  68. /**
  69. * Put the value of the named float field into the persistent fields.
  70. *
  71. */
  72. public void put(String name, float value){
  73. fields.put(name, new Float(value));
  74. }
  75. /**
  76. * Put the value of the named double field into the persistent field.
  77. */
  78. public void put(String name, double value){
  79. fields.put(name, new Double(value));
  80. }
  81. /**
  82. * Put the value of the named Object field into the persistent field.
  83. */
  84. public void put(String name, Object value){
  85. fields.put(name, value);
  86. }
  87. /**
  88. * Write the data and fields to the specified ObjectOutput stream.
  89. */
  90. public void write(ObjectOutput out) throws IOException {
  91. OutputStreamHook hook = (OutputStreamHook)out;
  92. ObjectStreamField[] osfields = hook.getFieldsNoCopy();
  93. // Write the fields to the stream in the order
  94. // provided by the ObjectStreamClass. (They should
  95. // be sorted appropriately already.)
  96. for (int i = 0; i < osfields.length; i++) {
  97. Object value = fields.get(osfields[i].getName());
  98. hook.writeField(osfields[i], value);
  99. }
  100. }
  101. }
  102. abstract void writeField(ObjectStreamField field, Object value) throws IOException;
  103. public OutputStreamHook()
  104. throws java.io.IOException {
  105. super();
  106. }
  107. public void defaultWriteObject() throws IOException {
  108. writeObjectState.defaultWriteObject(this);
  109. defaultWriteObjectDelegate();
  110. }
  111. public abstract void defaultWriteObjectDelegate();
  112. public ObjectOutputStream.PutField putFields()
  113. throws IOException {
  114. putFields = new HookPutFields();
  115. return putFields;
  116. }
  117. // Stream format version, saved/restored during recursive calls
  118. protected byte streamFormatVersion = 1;
  119. // Return the stream format version currently being used
  120. // to serialize an object
  121. public byte getStreamFormatVersion() {
  122. return streamFormatVersion;
  123. }
  124. abstract ObjectStreamField[] getFieldsNoCopy();
  125. // User uses PutFields to simulate default data.
  126. // See java.io.ObjectOutputStream.PutFields
  127. public void writeFields()
  128. throws IOException {
  129. writeObjectState.defaultWriteObject(this);
  130. putFields.write(this);
  131. }
  132. public abstract org.omg.CORBA_2_3.portable.OutputStream getOrbStream();
  133. protected abstract void beginOptionalCustomData();
  134. // The following is a State pattern implementation of what
  135. // should be done when a Serializable has a
  136. // writeObject method. This was especially necessary for
  137. // RMI-IIOP stream format version 2. Please see the
  138. // state diagrams in the docs directory of the workspace.
  139. protected WriteObjectState writeObjectState = NOT_IN_WRITE_OBJECT;
  140. protected void setState(WriteObjectState newState) {
  141. writeObjectState = newState;
  142. }
  143. // Description of possible actions
  144. protected static class WriteObjectState {
  145. public void enterWriteObject(OutputStreamHook stream) throws IOException {}
  146. public void exitWriteObject(OutputStreamHook stream) throws IOException {}
  147. public void defaultWriteObject(OutputStreamHook stream) throws IOException {}
  148. public void writeData(OutputStreamHook stream) throws IOException {}
  149. }
  150. protected static class DefaultState extends WriteObjectState {
  151. public void enterWriteObject(OutputStreamHook stream) throws IOException {
  152. stream.setState(IN_WRITE_OBJECT);
  153. }
  154. }
  155. protected static final WriteObjectState NOT_IN_WRITE_OBJECT = new DefaultState();
  156. protected static final WriteObjectState IN_WRITE_OBJECT = new InWriteObjectState();
  157. protected static final WriteObjectState WROTE_DEFAULT_DATA = new WroteDefaultDataState();
  158. protected static final WriteObjectState WROTE_CUSTOM_DATA = new WroteCustomDataState();
  159. protected static class InWriteObjectState extends WriteObjectState {
  160. public void enterWriteObject(OutputStreamHook stream) throws IOException {
  161. // XXX I18N, logging needed.
  162. throw new IOException("Internal state failure: Entered writeObject twice");
  163. }
  164. public void exitWriteObject(OutputStreamHook stream) throws IOException {
  165. // We didn't write any data, so write the
  166. // called defaultWriteObject indicator as false
  167. stream.getOrbStream().write_boolean(false);
  168. // If we're in stream format verison 2, we must
  169. // put the "null" marker to say that there isn't
  170. // any optional data
  171. if (stream.getStreamFormatVersion() == 2)
  172. stream.getOrbStream().write_long(0);
  173. stream.setState(NOT_IN_WRITE_OBJECT);
  174. }
  175. public void defaultWriteObject(OutputStreamHook stream) throws IOException {
  176. // The writeObject method called defaultWriteObject
  177. // or writeFields, so put the called defaultWriteObject
  178. // indicator as true
  179. stream.getOrbStream().write_boolean(true);
  180. stream.setState(WROTE_DEFAULT_DATA);
  181. }
  182. public void writeData(OutputStreamHook stream) throws IOException {
  183. // The writeObject method first called a direct
  184. // write operation. Write the called defaultWriteObject
  185. // indicator as false, put the special stream format
  186. // version 2 header (if stream format version 2, of course),
  187. // and write the data
  188. stream.getOrbStream().write_boolean(false);
  189. stream.beginOptionalCustomData();
  190. stream.setState(WROTE_CUSTOM_DATA);
  191. }
  192. }
  193. protected static class WroteDefaultDataState extends InWriteObjectState {
  194. public void exitWriteObject(OutputStreamHook stream) throws IOException {
  195. // We only wrote default data, so if in stream format
  196. // version 2, put the null indicator to say that there
  197. // is no optional data
  198. if (stream.getStreamFormatVersion() == 2)
  199. stream.getOrbStream().write_long(0);
  200. stream.setState(NOT_IN_WRITE_OBJECT);
  201. }
  202. public void defaultWriteObject(OutputStreamHook stream) throws IOException {
  203. // XXX I18N, logging needed.
  204. throw new IOException("Called defaultWriteObject/writeFields twice");
  205. }
  206. public void writeData(OutputStreamHook stream) throws IOException {
  207. // The writeObject method called a direct write operation.
  208. // If in stream format version 2, put the fake valuetype
  209. // header.
  210. stream.beginOptionalCustomData();
  211. stream.setState(WROTE_CUSTOM_DATA);
  212. }
  213. }
  214. protected static class WroteCustomDataState extends InWriteObjectState {
  215. public void exitWriteObject(OutputStreamHook stream) throws IOException {
  216. // In stream format version 2, we must tell the ORB
  217. // stream to close the fake custom valuetype.
  218. if (stream.getStreamFormatVersion() == 2)
  219. ((org.omg.CORBA.portable.ValueOutputStream)stream.getOrbStream()).end_value();
  220. stream.setState(NOT_IN_WRITE_OBJECT);
  221. }
  222. public void defaultWriteObject(OutputStreamHook stream) throws IOException {
  223. // XXX I18N, logging needed.
  224. throw new IOException("Cannot call defaultWriteObject/writeFields after writing custom data in RMI-IIOP");
  225. }
  226. // We don't have to do anything special here, just let
  227. // the stream write the data.
  228. public void writeData(OutputStreamHook stream) throws IOException {}
  229. }
  230. }