| /* |
| * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| /* |
| * Licensed Materials - Property of IBM |
| * RMI-IIOP v1.0 |
| * Copyright IBM Corp. 1998 1999 All Rights Reserved |
| * |
| */ |
| |
| package com.sun.corba.se.impl.io; |
| |
| import java.io.IOException; |
| import java.io.StreamCorruptedException; |
| import java.io.NotActiveException; |
| import java.io.InputStream; |
| import java.io.ObjectInputStream; |
| import java.util.*; |
| import java.lang.reflect.Array; |
| import java.lang.reflect.Constructor; |
| |
| import org.omg.CORBA.portable.ValueInputStream; |
| |
| import com.sun.corba.se.spi.orb.ORB; |
| import com.sun.corba.se.spi.orb.ORBVersion; |
| import com.sun.corba.se.spi.orb.ORBVersionFactory; |
| import com.sun.corba.se.spi.logging.CORBALogDomains; |
| import com.sun.corba.se.impl.logging.UtilSystemException; |
| import com.sun.corba.se.impl.logging.OMGSystemException; |
| |
| public abstract class InputStreamHook extends ObjectInputStream |
| { |
| // These should be visible in all the nested classes |
| static final OMGSystemException omgWrapper = |
| OMGSystemException.get( CORBALogDomains.RPC_ENCODING ) ; |
| |
| static final UtilSystemException utilWrapper = |
| UtilSystemException.get( CORBALogDomains.RPC_ENCODING ) ; |
| |
| private class HookGetFields extends ObjectInputStream.GetField { |
| private Map fields = null; |
| |
| HookGetFields(Map fields){ |
| this.fields = fields; |
| } |
| |
| /** |
| * Get the ObjectStreamClass that describes the fields in the stream. |
| * |
| * REVISIT! This doesn't work since we have our own ObjectStreamClass. |
| */ |
| public java.io.ObjectStreamClass getObjectStreamClass() { |
| return null; |
| } |
| |
| /** |
| * Return true if the named field is defaulted and has no value |
| * in this stream. |
| */ |
| public boolean defaulted(String name) |
| throws IOException, IllegalArgumentException { |
| return (!fields.containsKey(name)); |
| } |
| |
| /** |
| * Get the value of the named boolean field from the persistent field. |
| */ |
| public boolean get(String name, boolean defvalue) |
| throws IOException, IllegalArgumentException { |
| if (defaulted(name)) |
| return defvalue; |
| else return ((Boolean)fields.get(name)).booleanValue(); |
| } |
| |
| /** |
| * Get the value of the named char field from the persistent fields. |
| */ |
| public char get(String name, char defvalue) |
| throws IOException, IllegalArgumentException { |
| if (defaulted(name)) |
| return defvalue; |
| else return ((Character)fields.get(name)).charValue(); |
| |
| } |
| |
| /** |
| * Get the value of the named byte field from the persistent fields. |
| */ |
| public byte get(String name, byte defvalue) |
| throws IOException, IllegalArgumentException { |
| if (defaulted(name)) |
| return defvalue; |
| else return ((Byte)fields.get(name)).byteValue(); |
| |
| } |
| |
| /** |
| * Get the value of the named short field from the persistent fields. |
| */ |
| public short get(String name, short defvalue) |
| throws IOException, IllegalArgumentException { |
| if (defaulted(name)) |
| return defvalue; |
| else return ((Short)fields.get(name)).shortValue(); |
| |
| } |
| |
| /** |
| * Get the value of the named int field from the persistent fields. |
| */ |
| public int get(String name, int defvalue) |
| throws IOException, IllegalArgumentException { |
| if (defaulted(name)) |
| return defvalue; |
| else return ((Integer)fields.get(name)).intValue(); |
| |
| } |
| |
| /** |
| * Get the value of the named long field from the persistent fields. |
| */ |
| public long get(String name, long defvalue) |
| throws IOException, IllegalArgumentException { |
| if (defaulted(name)) |
| return defvalue; |
| else return ((Long)fields.get(name)).longValue(); |
| |
| } |
| |
| /** |
| * Get the value of the named float field from the persistent fields. |
| */ |
| public float get(String name, float defvalue) |
| throws IOException, IllegalArgumentException { |
| if (defaulted(name)) |
| return defvalue; |
| else return ((Float)fields.get(name)).floatValue(); |
| |
| } |
| |
| /** |
| * Get the value of the named double field from the persistent field. |
| */ |
| public double get(String name, double defvalue) |
| throws IOException, IllegalArgumentException { |
| if (defaulted(name)) |
| return defvalue; |
| else return ((Double)fields.get(name)).doubleValue(); |
| |
| } |
| |
| /** |
| * Get the value of the named Object field from the persistent field. |
| */ |
| public Object get(String name, Object defvalue) |
| throws IOException, IllegalArgumentException { |
| if (defaulted(name)) |
| return defvalue; |
| else return fields.get(name); |
| |
| } |
| |
| public String toString(){ |
| return fields.toString(); |
| } |
| } |
| |
| public InputStreamHook() |
| throws IOException { |
| super(); |
| } |
| |
| public void defaultReadObject() |
| throws IOException, ClassNotFoundException, NotActiveException |
| { |
| readObjectState.beginDefaultReadObject(this); |
| |
| defaultReadObjectDelegate(); |
| |
| readObjectState.endDefaultReadObject(this); |
| } |
| |
| abstract void defaultReadObjectDelegate(); |
| |
| abstract void readFields(java.util.Map fieldToValueMap) |
| throws java.io.InvalidClassException, java.io.StreamCorruptedException, |
| ClassNotFoundException, java.io.IOException; |
| |
| |
| // See java.io.ObjectInputStream.GetField |
| // Remember that this is equivalent to defaultReadObject |
| // in RMI-IIOP |
| public ObjectInputStream.GetField readFields() |
| throws IOException, ClassNotFoundException, NotActiveException { |
| |
| HashMap fieldValueMap = new HashMap(); |
| |
| // We were treating readFields same as defaultReadObject. It is |
| // incorrect if the state is readOptionalData. If this line |
| // is uncommented, it will throw a stream corrupted exception. |
| // _REVISIT_: The ideal fix would be to add a new state. In |
| // writeObject user may do one of the following |
| // 1. Call defaultWriteObject() |
| // 2. Put out optional fields |
| // 3. Call writeFields |
| // We have the state defined for (1) and (2) but not for (3), so |
| // we should ideally introduce a new state for 3 and have the |
| // beginDefaultReadObject do nothing. |
| //readObjectState.beginDefaultReadObject(this); |
| |
| readFields(fieldValueMap); |
| |
| readObjectState.endDefaultReadObject(this); |
| |
| return new HookGetFields(fieldValueMap); |
| } |
| |
| // The following is a State pattern implementation of what |
| // should be done when the sender's Serializable has a |
| // writeObject method. This was especially necessary for |
| // RMI-IIOP stream format version 2. Please see the |
| // state diagrams in the docs directory of the workspace. |
| // |
| // On the reader's side, the main factors are whether or not |
| // we have a readObject method and whether or not the |
| // sender wrote default data |
| |
| protected void setState(ReadObjectState newState) { |
| readObjectState = newState; |
| } |
| |
| protected abstract byte getStreamFormatVersion(); |
| abstract org.omg.CORBA_2_3.portable.InputStream getOrbStream(); |
| |
| // Description of possible actions |
| protected static class ReadObjectState { |
| public void beginUnmarshalCustomValue(InputStreamHook stream, |
| boolean calledDefaultWriteObject, |
| boolean hasReadObject) throws IOException {} |
| |
| public void endUnmarshalCustomValue(InputStreamHook stream) throws IOException {} |
| public void beginDefaultReadObject(InputStreamHook stream) throws IOException {} |
| public void endDefaultReadObject(InputStreamHook stream) throws IOException {} |
| public void readData(InputStreamHook stream) throws IOException {} |
| } |
| |
| protected ReadObjectState readObjectState = DEFAULT_STATE; |
| |
| protected static final ReadObjectState DEFAULT_STATE = new DefaultState(); |
| protected static final ReadObjectState IN_READ_OBJECT_OPT_DATA |
| = new InReadObjectOptionalDataState(); |
| protected static final ReadObjectState IN_READ_OBJECT_NO_MORE_OPT_DATA |
| = new InReadObjectNoMoreOptionalDataState(); |
| protected static final ReadObjectState IN_READ_OBJECT_DEFAULTS_SENT |
| = new InReadObjectDefaultsSentState(); |
| protected static final ReadObjectState NO_READ_OBJECT_DEFAULTS_SENT |
| = new NoReadObjectDefaultsSentState(); |
| |
| protected static final ReadObjectState IN_READ_OBJECT_REMOTE_NOT_CUSTOM_MARSHALED |
| = new InReadObjectRemoteDidNotUseWriteObjectState(); |
| protected static final ReadObjectState IN_READ_OBJECT_PAST_DEFAULTS_REMOTE_NOT_CUSTOM |
| = new InReadObjectPastDefaultsRemoteDidNotUseWOState(); |
| |
| protected static class DefaultState extends ReadObjectState { |
| |
| public void beginUnmarshalCustomValue(InputStreamHook stream, |
| boolean calledDefaultWriteObject, |
| boolean hasReadObject) |
| throws IOException { |
| |
| if (hasReadObject) { |
| if (calledDefaultWriteObject) |
| stream.setState(IN_READ_OBJECT_DEFAULTS_SENT); |
| else { |
| try { |
| if (stream.getStreamFormatVersion() == 2) |
| ((ValueInputStream)stream.getOrbStream()).start_value(); |
| } catch( Exception e ) { |
| // This will happen for Big Integer which uses |
| // writeFields in it's writeObject. We should be past |
| // start_value by now. |
| // NOTE: If we don't log any exception here we should |
| // be fine. If there is an error, it will be caught |
| // while reading the optional data. |
| |
| } |
| stream.setState(IN_READ_OBJECT_OPT_DATA); |
| } |
| } else { |
| if (calledDefaultWriteObject) |
| stream.setState(NO_READ_OBJECT_DEFAULTS_SENT); |
| else |
| // XXX I18N and logging needed. |
| throw new StreamCorruptedException("No default data sent"); |
| } |
| } |
| } |
| |
| // REVISIT. If a readObject exits here without reading |
| // default data, we won't skip it. This could be done automatically |
| // as in line 1492 in IIOPInputStream. |
| protected static class InReadObjectRemoteDidNotUseWriteObjectState extends ReadObjectState { |
| |
| public void beginUnmarshalCustomValue(InputStreamHook stream, |
| boolean calledDefaultWriteObject, |
| boolean hasReadObject) |
| { |
| throw utilWrapper.badBeginUnmarshalCustomValue() ; |
| } |
| |
| public void endDefaultReadObject(InputStreamHook stream) { |
| stream.setState(IN_READ_OBJECT_PAST_DEFAULTS_REMOTE_NOT_CUSTOM); |
| } |
| |
| public void readData(InputStreamHook stream) { |
| stream.throwOptionalDataIncompatibleException(); |
| } |
| } |
| |
| protected static class InReadObjectPastDefaultsRemoteDidNotUseWOState extends ReadObjectState { |
| |
| public void beginUnmarshalCustomValue(InputStreamHook stream, |
| boolean calledDefaultWriteObject, |
| boolean hasReadObject) |
| { |
| throw utilWrapper.badBeginUnmarshalCustomValue() ; |
| } |
| |
| public void beginDefaultReadObject(InputStreamHook stream) throws IOException |
| { |
| // XXX I18N and logging needed. |
| throw new StreamCorruptedException("Default data already read"); |
| } |
| |
| |
| public void readData(InputStreamHook stream) { |
| stream.throwOptionalDataIncompatibleException(); |
| } |
| } |
| |
| protected void throwOptionalDataIncompatibleException() |
| { |
| throw omgWrapper.rmiiiopOptionalDataIncompatible2() ; |
| } |
| |
| |
| protected static class InReadObjectDefaultsSentState extends ReadObjectState { |
| |
| public void beginUnmarshalCustomValue(InputStreamHook stream, |
| boolean calledDefaultWriteObject, |
| boolean hasReadObject) { |
| // This should never happen. |
| throw utilWrapper.badBeginUnmarshalCustomValue() ; |
| } |
| |
| public void endUnmarshalCustomValue(InputStreamHook stream) { |
| |
| // In stream format version 2, we can skip over |
| // the optional data this way. In stream format version 1, |
| // we will probably wind up with an error if we're |
| // unmarshaling a superclass. |
| if (stream.getStreamFormatVersion() == 2) { |
| ((ValueInputStream)stream.getOrbStream()).start_value(); |
| ((ValueInputStream)stream.getOrbStream()).end_value(); |
| } |
| |
| stream.setState(DEFAULT_STATE); |
| } |
| |
| public void endDefaultReadObject(InputStreamHook stream) throws IOException { |
| |
| // Read the fake valuetype header in stream format version 2 |
| if (stream.getStreamFormatVersion() == 2) |
| ((ValueInputStream)stream.getOrbStream()).start_value(); |
| |
| stream.setState(IN_READ_OBJECT_OPT_DATA); |
| } |
| |
| public void readData(InputStreamHook stream) throws IOException { |
| org.omg.CORBA.ORB orb = stream.getOrbStream().orb(); |
| if ((orb == null) || |
| !(orb instanceof com.sun.corba.se.spi.orb.ORB)) { |
| throw new StreamCorruptedException( |
| "Default data must be read first"); |
| } |
| ORBVersion clientOrbVersion = |
| ((com.sun.corba.se.spi.orb.ORB)orb).getORBVersion(); |
| |
| // Fix Date interop bug. For older versions of the ORB don't do |
| // anything for readData(). Before this used to throw |
| // StreamCorruptedException for older versions of the ORB where |
| // calledDefaultWriteObject always returns true. |
| if ((ORBVersionFactory.getPEORB().compareTo(clientOrbVersion) <= 0) || |
| (clientOrbVersion.equals(ORBVersionFactory.getFOREIGN()))) { |
| // XXX I18N and logging needed. |
| throw new StreamCorruptedException("Default data must be read first"); |
| } |
| } |
| } |
| |
| protected static class InReadObjectOptionalDataState extends ReadObjectState { |
| |
| public void beginUnmarshalCustomValue(InputStreamHook stream, |
| boolean calledDefaultWriteObject, |
| boolean hasReadObject) |
| { |
| // This should never happen. |
| throw utilWrapper.badBeginUnmarshalCustomValue() ; |
| } |
| |
| public void endUnmarshalCustomValue(InputStreamHook stream) throws IOException |
| { |
| if (stream.getStreamFormatVersion() == 2) { |
| ((ValueInputStream)stream.getOrbStream()).end_value(); |
| } |
| stream.setState(DEFAULT_STATE); |
| } |
| |
| public void beginDefaultReadObject(InputStreamHook stream) throws IOException |
| { |
| // XXX I18N and logging needed. |
| throw new StreamCorruptedException("Default data not sent or already read/passed"); |
| } |
| |
| |
| } |
| |
| protected static class InReadObjectNoMoreOptionalDataState |
| extends InReadObjectOptionalDataState { |
| |
| public void readData(InputStreamHook stream) throws IOException { |
| stream.throwOptionalDataIncompatibleException(); |
| } |
| } |
| |
| protected static class NoReadObjectDefaultsSentState extends ReadObjectState { |
| public void endUnmarshalCustomValue(InputStreamHook stream) throws IOException { |
| // Code should read default fields before calling this |
| |
| if (stream.getStreamFormatVersion() == 2) { |
| ((ValueInputStream)stream.getOrbStream()).start_value(); |
| ((ValueInputStream)stream.getOrbStream()).end_value(); |
| } |
| |
| stream.setState(DEFAULT_STATE); |
| } |
| } |
| } |