1. /*
  2. * @(#)InputStreamHook.java 1.18 04/03/01
  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.StreamCorruptedException;
  18. import java.io.NotActiveException;
  19. import java.io.InputStream;
  20. import java.io.ObjectInputStream;
  21. import java.util.*;
  22. import java.lang.reflect.Array;
  23. import java.lang.reflect.Constructor;
  24. import org.omg.CORBA.portable.ValueInputStream;
  25. import com.sun.corba.se.spi.orb.ORB;
  26. import com.sun.corba.se.spi.orb.ORBVersion;
  27. import com.sun.corba.se.spi.orb.ORBVersionFactory;
  28. import com.sun.corba.se.spi.logging.CORBALogDomains;
  29. import com.sun.corba.se.impl.logging.UtilSystemException;
  30. import com.sun.corba.se.impl.logging.OMGSystemException;
  31. public abstract class InputStreamHook extends ObjectInputStream
  32. {
  33. // These should be visible in all the nested classes
  34. static final OMGSystemException omgWrapper =
  35. OMGSystemException.get( CORBALogDomains.RPC_ENCODING ) ;
  36. static final UtilSystemException utilWrapper =
  37. UtilSystemException.get( CORBALogDomains.RPC_ENCODING ) ;
  38. private class HookGetFields extends ObjectInputStream.GetField {
  39. private Map fields = null;
  40. HookGetFields(Map fields){
  41. this.fields = fields;
  42. }
  43. /**
  44. * Get the ObjectStreamClass that describes the fields in the stream.
  45. *
  46. * REVISIT! This doesn't work since we have our own ObjectStreamClass.
  47. */
  48. public java.io.ObjectStreamClass getObjectStreamClass() {
  49. return null;
  50. }
  51. /**
  52. * Return true if the named field is defaulted and has no value
  53. * in this stream.
  54. */
  55. public boolean defaulted(String name)
  56. throws IOException, IllegalArgumentException {
  57. return (!fields.containsKey(name));
  58. }
  59. /**
  60. * Get the value of the named boolean field from the persistent field.
  61. */
  62. public boolean get(String name, boolean defvalue)
  63. throws IOException, IllegalArgumentException {
  64. if (defaulted(name))
  65. return defvalue;
  66. else return ((Boolean)fields.get(name)).booleanValue();
  67. }
  68. /**
  69. * Get the value of the named char field from the persistent fields.
  70. */
  71. public char get(String name, char defvalue)
  72. throws IOException, IllegalArgumentException {
  73. if (defaulted(name))
  74. return defvalue;
  75. else return ((Character)fields.get(name)).charValue();
  76. }
  77. /**
  78. * Get the value of the named byte field from the persistent fields.
  79. */
  80. public byte get(String name, byte defvalue)
  81. throws IOException, IllegalArgumentException {
  82. if (defaulted(name))
  83. return defvalue;
  84. else return ((Byte)fields.get(name)).byteValue();
  85. }
  86. /**
  87. * Get the value of the named short field from the persistent fields.
  88. */
  89. public short get(String name, short defvalue)
  90. throws IOException, IllegalArgumentException {
  91. if (defaulted(name))
  92. return defvalue;
  93. else return ((Short)fields.get(name)).shortValue();
  94. }
  95. /**
  96. * Get the value of the named int field from the persistent fields.
  97. */
  98. public int get(String name, int defvalue)
  99. throws IOException, IllegalArgumentException {
  100. if (defaulted(name))
  101. return defvalue;
  102. else return ((Integer)fields.get(name)).intValue();
  103. }
  104. /**
  105. * Get the value of the named long field from the persistent fields.
  106. */
  107. public long get(String name, long defvalue)
  108. throws IOException, IllegalArgumentException {
  109. if (defaulted(name))
  110. return defvalue;
  111. else return ((Long)fields.get(name)).longValue();
  112. }
  113. /**
  114. * Get the value of the named float field from the persistent fields.
  115. */
  116. public float get(String name, float defvalue)
  117. throws IOException, IllegalArgumentException {
  118. if (defaulted(name))
  119. return defvalue;
  120. else return ((Float)fields.get(name)).floatValue();
  121. }
  122. /**
  123. * Get the value of the named double field from the persistent field.
  124. */
  125. public double get(String name, double defvalue)
  126. throws IOException, IllegalArgumentException {
  127. if (defaulted(name))
  128. return defvalue;
  129. else return ((Double)fields.get(name)).doubleValue();
  130. }
  131. /**
  132. * Get the value of the named Object field from the persistent field.
  133. */
  134. public Object get(String name, Object defvalue)
  135. throws IOException, IllegalArgumentException {
  136. if (defaulted(name))
  137. return defvalue;
  138. else return fields.get(name);
  139. }
  140. public String toString(){
  141. return fields.toString();
  142. }
  143. }
  144. public InputStreamHook()
  145. throws IOException {
  146. super();
  147. }
  148. public void defaultReadObject()
  149. throws IOException, ClassNotFoundException, NotActiveException
  150. {
  151. readObjectState.beginDefaultReadObject(this);
  152. defaultReadObjectDelegate();
  153. readObjectState.endDefaultReadObject(this);
  154. }
  155. public abstract void defaultReadObjectDelegate();
  156. abstract void readFields(java.util.Map fieldToValueMap)
  157. throws java.io.InvalidClassException, java.io.StreamCorruptedException,
  158. ClassNotFoundException, java.io.IOException;
  159. // See java.io.ObjectInputStream.GetField
  160. // Remember that this is equivalent to defaultReadObject
  161. // in RMI-IIOP
  162. public ObjectInputStream.GetField readFields()
  163. throws IOException, ClassNotFoundException, NotActiveException {
  164. HashMap fieldValueMap = new HashMap();
  165. // We were treating readFields same as defaultReadObject. It is
  166. // incorrect if the state is readOptionalData. If this line
  167. // is uncommented, it will throw a stream corrupted exception.
  168. // _REVISIT_: The ideal fix would be to add a new state. In
  169. // writeObject user may do one of the following
  170. // 1. Call defaultWriteObject()
  171. // 2. Put out optional fields
  172. // 3. Call writeFields
  173. // We have the state defined for (1) and (2) but not for (3), so
  174. // we should ideally introduce a new state for 3 and have the
  175. // beginDefaultReadObject do nothing.
  176. //readObjectState.beginDefaultReadObject(this);
  177. readFields(fieldValueMap);
  178. readObjectState.endDefaultReadObject(this);
  179. return new HookGetFields(fieldValueMap);
  180. }
  181. // The following is a State pattern implementation of what
  182. // should be done when the sender's Serializable has a
  183. // writeObject method. This was especially necessary for
  184. // RMI-IIOP stream format version 2. Please see the
  185. // state diagrams in the docs directory of the workspace.
  186. //
  187. // On the reader's side, the main factors are whether or not
  188. // we have a readObject method and whether or not the
  189. // sender wrote default data
  190. protected void setState(ReadObjectState newState) {
  191. readObjectState = newState;
  192. }
  193. protected abstract byte getStreamFormatVersion();
  194. protected abstract org.omg.CORBA_2_3.portable.InputStream getOrbStream();
  195. // Description of possible actions
  196. protected static class ReadObjectState {
  197. public void beginUnmarshalCustomValue(InputStreamHook stream,
  198. boolean calledDefaultWriteObject,
  199. boolean hasReadObject) throws IOException {}
  200. public void endUnmarshalCustomValue(InputStreamHook stream) throws IOException {}
  201. public void beginDefaultReadObject(InputStreamHook stream) throws IOException {}
  202. public void endDefaultReadObject(InputStreamHook stream) throws IOException {}
  203. public void readData(InputStreamHook stream) throws IOException {}
  204. }
  205. protected ReadObjectState readObjectState = DEFAULT_STATE;
  206. protected static final ReadObjectState DEFAULT_STATE = new DefaultState();
  207. protected static final ReadObjectState IN_READ_OBJECT_OPT_DATA
  208. = new InReadObjectOptionalDataState();
  209. protected static final ReadObjectState IN_READ_OBJECT_NO_MORE_OPT_DATA
  210. = new InReadObjectNoMoreOptionalDataState();
  211. protected static final ReadObjectState IN_READ_OBJECT_DEFAULTS_SENT
  212. = new InReadObjectDefaultsSentState();
  213. protected static final ReadObjectState NO_READ_OBJECT_DEFAULTS_SENT
  214. = new NoReadObjectDefaultsSentState();
  215. protected static final ReadObjectState IN_READ_OBJECT_REMOTE_NOT_CUSTOM_MARSHALED
  216. = new InReadObjectRemoteDidNotUseWriteObjectState();
  217. protected static final ReadObjectState IN_READ_OBJECT_PAST_DEFAULTS_REMOTE_NOT_CUSTOM
  218. = new InReadObjectPastDefaultsRemoteDidNotUseWOState();
  219. protected static class DefaultState extends ReadObjectState {
  220. public void beginUnmarshalCustomValue(InputStreamHook stream,
  221. boolean calledDefaultWriteObject,
  222. boolean hasReadObject)
  223. throws IOException {
  224. if (hasReadObject) {
  225. if (calledDefaultWriteObject)
  226. stream.setState(IN_READ_OBJECT_DEFAULTS_SENT);
  227. else {
  228. try {
  229. if (stream.getStreamFormatVersion() == 2)
  230. ((ValueInputStream)stream.getOrbStream()).start_value();
  231. } catch( Exception e ) {
  232. // This will happen for Big Integer which uses
  233. // writeFields in it's writeObject. We should be past
  234. // start_value by now.
  235. // NOTE: If we don't log any exception here we should
  236. // be fine. If there is an error, it will be caught
  237. // while reading the optional data.
  238. }
  239. stream.setState(IN_READ_OBJECT_OPT_DATA);
  240. }
  241. } else {
  242. if (calledDefaultWriteObject)
  243. stream.setState(NO_READ_OBJECT_DEFAULTS_SENT);
  244. else
  245. // XXX I18N and logging needed.
  246. throw new StreamCorruptedException("No default data sent");
  247. }
  248. }
  249. }
  250. // REVISIT. If a readObject exits here without reading
  251. // default data, we won't skip it. This could be done automatically
  252. // as in line 1492 in IIOPInputStream.
  253. protected static class InReadObjectRemoteDidNotUseWriteObjectState extends ReadObjectState {
  254. public void beginUnmarshalCustomValue(InputStreamHook stream,
  255. boolean calledDefaultWriteObject,
  256. boolean hasReadObject)
  257. {
  258. throw utilWrapper.badBeginUnmarshalCustomValue() ;
  259. }
  260. public void endDefaultReadObject(InputStreamHook stream) {
  261. stream.setState(IN_READ_OBJECT_PAST_DEFAULTS_REMOTE_NOT_CUSTOM);
  262. }
  263. public void readData(InputStreamHook stream) {
  264. stream.throwOptionalDataIncompatibleException();
  265. }
  266. }
  267. protected static class InReadObjectPastDefaultsRemoteDidNotUseWOState extends ReadObjectState {
  268. public void beginUnmarshalCustomValue(InputStreamHook stream,
  269. boolean calledDefaultWriteObject,
  270. boolean hasReadObject)
  271. {
  272. throw utilWrapper.badBeginUnmarshalCustomValue() ;
  273. }
  274. public void beginDefaultReadObject(InputStreamHook stream) throws IOException
  275. {
  276. // XXX I18N and logging needed.
  277. throw new StreamCorruptedException("Default data already read");
  278. }
  279. public void readData(InputStreamHook stream) {
  280. stream.throwOptionalDataIncompatibleException();
  281. }
  282. }
  283. protected void throwOptionalDataIncompatibleException()
  284. {
  285. throw omgWrapper.rmiiiopOptionalDataIncompatible2() ;
  286. }
  287. protected static class InReadObjectDefaultsSentState extends ReadObjectState {
  288. public void beginUnmarshalCustomValue(InputStreamHook stream,
  289. boolean calledDefaultWriteObject,
  290. boolean hasReadObject) {
  291. // This should never happen.
  292. throw utilWrapper.badBeginUnmarshalCustomValue() ;
  293. }
  294. public void endUnmarshalCustomValue(InputStreamHook stream) {
  295. // In stream format version 2, we can skip over
  296. // the optional data this way. In stream format version 1,
  297. // we will probably wind up with an error if we're
  298. // unmarshaling a superclass.
  299. if (stream.getStreamFormatVersion() == 2) {
  300. ((ValueInputStream)stream.getOrbStream()).start_value();
  301. ((ValueInputStream)stream.getOrbStream()).end_value();
  302. }
  303. stream.setState(DEFAULT_STATE);
  304. }
  305. public void endDefaultReadObject(InputStreamHook stream) throws IOException {
  306. // Read the fake valuetype header in stream format version 2
  307. if (stream.getStreamFormatVersion() == 2)
  308. ((ValueInputStream)stream.getOrbStream()).start_value();
  309. stream.setState(IN_READ_OBJECT_OPT_DATA);
  310. }
  311. public void readData(InputStreamHook stream) throws IOException {
  312. ORB orb = (com.sun.corba.se.spi.orb.ORB)stream.getOrbStream().orb();
  313. ORBVersion clientOrbVersion = orb.getORBVersion();
  314. // Fix Date interop bug. For older versions of the ORB don't do
  315. // anything for readData(). Before this used to throw
  316. // StreamCorruptedException for older versions of the ORB where
  317. // calledDefaultWriteObject always returns true.
  318. if ((ORBVersionFactory.getPEORB().compareTo(clientOrbVersion) <= 0) ||
  319. (clientOrbVersion.equals(ORBVersionFactory.getFOREIGN()))) {
  320. // XXX I18N and logging needed.
  321. throw new StreamCorruptedException("Default data must be read first");
  322. }
  323. }
  324. }
  325. protected static class InReadObjectOptionalDataState extends ReadObjectState {
  326. public void beginUnmarshalCustomValue(InputStreamHook stream,
  327. boolean calledDefaultWriteObject,
  328. boolean hasReadObject)
  329. {
  330. // This should never happen.
  331. throw utilWrapper.badBeginUnmarshalCustomValue() ;
  332. }
  333. public void endUnmarshalCustomValue(InputStreamHook stream) throws IOException
  334. {
  335. if (stream.getStreamFormatVersion() == 2) {
  336. ((ValueInputStream)stream.getOrbStream()).end_value();
  337. }
  338. stream.setState(DEFAULT_STATE);
  339. }
  340. public void beginDefaultReadObject(InputStreamHook stream) throws IOException
  341. {
  342. // XXX I18N and logging needed.
  343. throw new StreamCorruptedException("Default data not sent or already read/passed");
  344. }
  345. }
  346. protected static class InReadObjectNoMoreOptionalDataState
  347. extends InReadObjectOptionalDataState {
  348. public void readData(InputStreamHook stream) throws IOException {
  349. stream.throwOptionalDataIncompatibleException();
  350. }
  351. }
  352. protected static class NoReadObjectDefaultsSentState extends ReadObjectState {
  353. public void endUnmarshalCustomValue(InputStreamHook stream) throws IOException {
  354. // Code should read default fields before calling this
  355. if (stream.getStreamFormatVersion() == 2) {
  356. ((ValueInputStream)stream.getOrbStream()).start_value();
  357. ((ValueInputStream)stream.getOrbStream()).end_value();
  358. }
  359. stream.setState(DEFAULT_STATE);
  360. }
  361. }
  362. }