/** * * Copyright 2004-2005 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.geronimo.interop.rmi.iiop; import java.io.IOException; import java.io.ObjectOutput; import java.io.ObjectStreamClass; import java.io.ObjectStreamField; import java.lang.reflect.Method; /** ** An implementation of java.io.ObjectOutputStream.PutField ** Provide programatic access to the persistent fields to be written ** to ObjectOutput. **/ public class PutField extends java.io.ObjectOutputStream.PutField { /** class descriptor describing serializable fields */ private final ObjectStreamClass desc; /** primitive field values */ private final byte[] primVals; /** object field values */ private final Object[] objVals; private int primDataSize = 0; private int numObjFields = 0; private ObjectStreamField[] _fields = null; private static Method setOffsetMethod; static { try { Class osFieldClass = java.io.ObjectStreamField.class; Class[] params = new Class[1]; params[0] = int.class; setOffsetMethod = osFieldClass.getDeclaredMethod("setOffset", params); setOffsetMethod.setAccessible(true); } catch (Throwable t) { t.printStackTrace(); } } /** * Creates PutField object for writing fields defined in given * class descriptor. */ PutField(ObjectStreamClass desc) { this.desc = desc; computeOffsets(); primVals = new byte[primDataSize]; objVals = new Object[numObjFields]; } /** * Put the value of the named boolean field into the persistent field. * * @param name the name of the serializable field * @param val the value to assign to the field */ public void put(String name, boolean val) { Bits.putBoolean(primVals, getFieldOffset(name, Boolean.TYPE), val); } /** * Put the value of the named byte field into the persistent field. * * @param name the name of the serializable field * @param val the value to assign to the field */ public void put(String name, byte val) { primVals[getFieldOffset(name, Byte.TYPE)] = val; } /** * Put the value of the named char field into the persistent field. * * @param name the name of the serializable field * @param val the value to assign to the field */ public void put(String name, char val) { Bits.putChar(primVals, getFieldOffset(name, Character.TYPE), val); } /** * Put the value of the named short field into the persistent field. * * @param name the name of the serializable field * @param val the value to assign to the field */ public void put(String name, short val) { Bits.putShort(primVals, getFieldOffset(name, Short.TYPE), val); } /** * Put the value of the named int field into the persistent field. * * @param name the name of the serializable field * @param val the value to assign to the field */ public void put(String name, int val) { Bits.putInt(primVals, getFieldOffset(name, Integer.TYPE), val); } /** * Put the value of the named long field into the persistent field. * * @param name the name of the serializable field * @param val the value to assign to the field */ public void put(String name, long val) { Bits.putLong(primVals, getFieldOffset(name, Long.TYPE), val); } /** * Put the value of the named float field into the persistent field. * * @param name the name of the serializable field * @param val the value to assign to the field */ public void put(String name, float val) { Bits.putFloat(primVals, getFieldOffset(name, Float.TYPE), val); } /** * Put the value of the named double field into the persistent field. * * @param name the name of the serializable field * @param val the value to assign to the field */ public void put(String name, double val) { Bits.putDouble(primVals, getFieldOffset(name, Double.TYPE), val); } /** * Put the value of the named Object field into the persistent field. * * @param name the name of the serializable field * @param val the value to assign to the field */ public void put(String name, Object val) { objVals[getFieldOffset(name, Object.class)] = val; } /** * Write the data and fields to the specified ObjectOutput stream. * * @param out the stream to write the data and fields to * @throws IOException if I/O errors occur while writing to the * underlying stream * @deprecated This method does not write the values contained by this * <code>PutField</code> object in a proper format, and may * result in corruption of the serialization stream. The * correct way to write <code>PutField</code> data is by * calling the {@link java.io.ObjectOutputStream#writeFields()} * method. */ public void write(ObjectOutput out) throws IOException { /* * Applications should *not* use this method to write PutField * data, as it will lead to stream corruption if the PutField * object writes any primitive data (since block data mode is not * unset/set properly, as is done in OOS.writeFields()). This * broken implementation is being retained solely for behavioral * compatibility, in order to support applications which use * OOS.PutField.write() for writing only non-primitive data. * * Serialization of unshared objects is not implemented here since * it is not necessary for backwards compatibility; also, unshared * semantics may not be supported by the given ObjectOutput * instance. Applications which write unshared objects using the * PutField API must use OOS.writeFields(). */ throw new IOException("PutField.write(ObjectOutput) - not supported for RMI/IIOP"); } /** * Writes buffered primitive data and object fields to stream. */ void writeFields(ObjectOutputStream o) throws IOException { org.apache.geronimo.interop.rmi.iiop.ObjectOutputStream out = (org.apache.geronimo.interop.rmi.iiop.ObjectOutputStream)o; out._cdrOutput.write_align(4, 4); // write any necessary padding //Write out the primitive values first for(int i = 0; i < primVals.length; i++) { out.writeByte(primVals[i]); } //Write out the object fields java.io.ObjectStreamField[] fields = desc.getFields(); int numPrimFields = fields.length - objVals.length; for (int i = 0; i < objVals.length; i++) { out.writeObject(ValueType.getInstance(objVals[i].getClass()), objVals[i]); } } /** * Returns offset of field with given name and type. A specified type * of null matches all types, Object.class matches all non-primitive * types, and any other non-null type matches assignable types only. * Throws IllegalArgumentException if no matching field found. */ private int getFieldOffset(String name, Class type) { ObjectStreamField field = getField(name, type); if (field == null) { throw new IllegalArgumentException("no such field"); } return field.getOffset(); } private ObjectStreamField getField(String name, Class type) { if(type == null) { //Return match by name for(int i = 0; i < _fields.length; i++) { if(_fields[i].getName().equals(name)) { return _fields[i]; } } return (ObjectStreamField)null; } else if(type == java.lang.Object.class) { //Return match for name, and any non-primitive type for(int i = 0; i < _fields.length; i++) { if(_fields[i].getName().equals(name) && !_fields[i].getType().isPrimitive()) { return _fields[i]; } } return (ObjectStreamField)null; } else { for(int i = 0; i < _fields.length; i++) { if(_fields[i].getName().equals(name) && _fields[i].getType().equals(type)) { return _fields[i]; } } return (ObjectStreamField)null; } } private void computeOffsets() { try { computeFieldOffsets(); } catch(Exception e) { throw new RuntimeException(org.apache.geronimo.interop.util.ExceptionUtil.causedBy(e)); } } private void computeFieldOffsets() throws Exception { primDataSize = 0; numObjFields = 0; int firstObjIndex = -1; java.io.ObjectStreamField[] fields = desc.getFields(); _fields = new ObjectStreamField[fields.length]; Object[] args = new Object[1]; for (int i = 0; i < fields.length; i++) { java.io.ObjectStreamField f = fields[i]; _fields[i] = new ObjectStreamField(fields[i].getName(), fields[i].getType()); ObjectStreamField _f = _fields[i]; switch (f.getTypeCode()) { case 'Z': case 'B': args[0] = new Integer(primDataSize++); setOffsetMethod.invoke(_f, args); break; case 'C': case 'S': args[0] = new Integer(primDataSize); setOffsetMethod.invoke(_f, args); primDataSize += 2; break; case 'I': case 'F': args[0] = new Integer(primDataSize); setOffsetMethod.invoke(_f, args); primDataSize += 4; break; case 'J': case 'D': args[0] = new Integer(primDataSize); setOffsetMethod.invoke(_f, args); primDataSize += 8; break; case '[': case 'L': args[0] = new Integer(numObjFields++); setOffsetMethod.invoke(_f, args); if (firstObjIndex == -1) { firstObjIndex = i; } break; default: break; } } if (firstObjIndex != -1 && firstObjIndex + numObjFields != fields.length) { //throw new InvalidClassException(name, "illegal field order"); } } }