1/*
2 * Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24import java.io.*;
25import java.lang.reflect.Field;
26import java.lang.reflect.Method;
27import java.lang.reflect.Modifier;
28import java.lang.reflect.InvocationTargetException;
29import java.security.*;
30
31public class XObjectOutputStream extends AbstractObjectOutputStream {
32    XObjectOutputStream(OutputStream out) throws IOException {
33        super(out);
34    }
35
36    protected boolean enableReplaceObject(boolean enable)
37    {
38        throw new Error("not implemented");
39    }
40
41    protected void annotateClass(Class<?> cl) throws IOException {
42    }
43
44    public void close() throws IOException{
45        out.close();
46    }
47
48    protected Object replaceObject(Object obj) throws IOException {
49        return obj;
50    }
51
52    protected void writeStreamHeader() throws IOException {
53        super.writeStreamHeader();
54    }
55
56    protected final void writeObjectOverride(Object obj) throws IOException {
57        Object prevCurrentObject = currentObject;
58        currentObject = obj;
59        System.out.println("writeObjectOverride(" + obj.toString() + ")");
60        try {
61        //     ** Preserving reference semantics.
62        //     if (obj already serialized) {
63        //       look up streamId for obj and write it into 'this' stream.
64        //       return;
65        //     }
66        //
67        //     if (obj instanceof Class) {
68        //       //Special processing for classes.
69        //       //Might need to call this.annotateClass(obj.getClass())
70        //       //someday.
71        //       return;
72        //     }
73        //
74        //     **Replacement semantics
75        //     Object replacement = obj;
76        //     if (enableReplace)
77        //       replacement = this.writeReplace(obj);
78        //     if (replacement instanceof Replaceable)
79        //       replacement = ((Replaceable)replacement).replaceObject(this);
80        //     if (obj != replacement) {
81        //       //record that all future occurances of obj should be replaced
82        //       //with replacement
83        //     }
84        //
85        //     if obj is Externalizeable {
86        //      Object[] argList = {this};
87        //      invokeMethod(obj, writeExternalMethod, argList);
88        //     else
89
90        Method writeObjectMethod = getWriteObjectMethod(obj.getClass());
91
92        if (writeObjectMethod != null) {
93            Object[] arglist = {this};
94            invokeMethod(obj, writeObjectMethod, arglist);
95        } else
96            defaultWriteObject();
97        } finally {
98            currentObject = prevCurrentObject;
99        }
100    }
101
102    /* Since defaultWriteObject() does not take the object to write as a parameter,
103     * implementation is required to store currentObject when writeObject is called.
104     */
105    public void defaultWriteObject() throws IOException {
106        Object obj = currentObject;
107        System.out.println("XObjectOutputStream.defaultWriteObject(" +
108                            obj.toString() + ")");
109
110        //In order to access package, private and protected fields,
111        //one needs to use Priviledged Access and be trusted code.
112        //This test will avoid that problem by only serializing public fields.
113        Field[] fields = obj.getClass().getFields();
114        for (int i= 0; i < fields.length; i++) {
115            //Skip non-Serializable fields.
116            int mods = fields[i].getModifiers();
117            if (Modifier.isStatic(mods) || Modifier.isTransient(mods))
118                continue;
119            Class FieldType = fields[i].getType();
120            if (FieldType.isPrimitive()) {
121                System.out.println("Field " + fields[i].getName() +
122                                    " has primitive type " + FieldType.toString());
123            } else {
124                System.out.println("**Field " + fields[i].getName() +
125                                   " is an Object of type " + FieldType.toString());
126                try {
127                    writeObject(fields[i].get(obj));
128                    if (FieldType.isArray()) {
129                        Object[] array = ((Object[]) fields[i].get(obj));
130                        Class componentType = FieldType.getComponentType();
131                        if (componentType.isPrimitive())
132                            System.out.println("Output " + array.length + " primitive elements of" +
133                                               componentType.toString());
134                        else {
135                            System.out.println("Output " + array.length + " of Object elements of" +
136                                               componentType.toString());
137                            for (int k = 0; k < array.length; k++) {
138                                writeObject(array[k]);
139                            }
140                        }
141                    }
142                } catch (IllegalAccessException e) {
143                    throw new IOException(e.getMessage());
144                }
145            }
146        }
147    }
148
149    public PutField putFields() throws IOException {
150        currentPutField = new InternalPutField();
151        return currentPutField;
152    }
153
154    public void writeFields() throws IOException {
155        currentPutField.write(this);
156    }
157
158    static final class InternalPutField extends ObjectOutputStream.PutField {
159        String fieldName[];
160        int    intValue[];
161        int next;
162
163        InternalPutField() {
164            fieldName = new String[10];
165            intValue = new int[10];
166            next = 0;
167        }
168        /**
169         * Put the value of the named boolean field into the persistent field.
170         */
171        public void put(String name, boolean value) {
172        }
173
174        /**
175         * Put the value of the named char field into the persistent fields.
176         */
177        public void put(String name, char value) {
178        }
179
180        /**
181         * Put the value of the named byte field into the persistent fields.
182         */
183        public void put(String name, byte value) {
184        }
185
186        /**
187         * Put the value of the named short field into the persistent fields.
188         */
189        public void put(String name, short value) {
190        }
191
192        /**
193         * Put the value of the named int field into the persistent fields.
194         */
195        public void put(String name, int value) {
196            if (next < fieldName.length) {
197                fieldName[next] = name;
198                intValue[next] = value;
199                next++;
200            }
201        }
202
203        /**
204         * Put the value of the named long field into the persistent fields.
205         */
206        public void put(String name, long value) {
207        }
208
209        /**
210         * Put the value of the named float field into the persistent fields.
211         */
212        public void put(String name, float value) {
213        }
214
215        /**
216         * Put the value of the named double field into the persistent field.
217         */
218        public void put(String name, double value) {
219        }
220
221        /**
222         * Put the value of the named Object field into the persistent field.
223         */
224        public void put(String name, Object value) {
225        }
226
227        /**
228         * Write the data and fields to the specified ObjectOutput stream.
229         */
230        public void write(ObjectOutput out) throws IOException {
231            for (int i = 0; i < next; i++)
232                System.out.println(fieldName[i] + "=" + intValue[i]);
233        }
234    };
235
236
237    /**
238     * Writes a byte. This method will block until the byte is actually
239     * written.
240     * @param b the byte
241     * @exception IOException If an I/O error has occurred.
242     * @since     JDK1.1
243     */
244    public void write(int data) throws IOException {
245    }
246
247    /**
248     * Writes an array of bytes. This method will block until the bytes
249     * are actually written.
250     * @param b the data to be written
251     * @exception IOException If an I/O error has occurred.
252     * @since     JDK1.1
253     */
254    public void write(byte b[]) throws IOException {
255    }
256
257    /**
258     * Writes a sub array of bytes.
259     * @param b the data to be written
260     * @param off       the start offset in the data
261     * @param len       the number of bytes that are written
262     * @exception IOException If an I/O error has occurred.
263     * @since     JDK1.1
264     */
265    public void write(byte b[], int off, int len) throws IOException {
266    }
267
268    public void writeBoolean(boolean data) throws IOException {
269    }
270
271    public void writeByte(int data) throws IOException {
272    }
273
274    public void writeShort(int data)  throws IOException {
275    }
276
277    public void writeChar(int data)  throws IOException {
278    }
279    public void writeInt(int data)  throws IOException{}
280    public void writeLong(long data)  throws IOException{}
281    public void writeFloat(float data) throws IOException{}
282    public void writeDouble(double data) throws IOException{}
283    public void writeBytes(String data) throws IOException{}
284    public void writeChars(String data) throws IOException{}
285    public void writeUTF(String data) throws IOException{}
286    public void reset() throws IOException {}
287    public void available() throws IOException {}
288    public void drain() throws IOException {}
289
290    private Object currentObject = null;
291    private InternalPutField currentPutField;
292
293
294    /********************************************************************/
295
296    /* CODE LIFTED FROM ObjectStreamClass constuctor.
297     * ObjectStreamClass.writeObjectMethod is private.
298     *
299     * Look for the writeObject method
300     * Set the accessible flag on it here.
301     * Subclass of AbstractObjectOutputStream will call it as necessary.
302     */
303    public static Method getWriteObjectMethod(final Class cl) {
304
305        Method writeObjectMethod = (Method)
306            java.security.AccessController.doPrivileged
307            (new java.security.PrivilegedAction() {
308                public Object run() {
309                    Method m = null;
310                    try {
311                        Class[] args = {ObjectOutputStream.class};
312                        m = cl.getDeclaredMethod("writeObject", args);
313                        int mods = m.getModifiers();
314                        // Method must be private and non-static
315                        if (!Modifier.isPrivate(mods) ||
316                            Modifier.isStatic(mods)) {
317                            m = null;
318                        } else {
319                            m.setAccessible(true);
320                        }
321                    } catch (NoSuchMethodException e) {
322                        m = null;
323                    }
324                    return m;
325                }
326            });
327        return writeObjectMethod;
328    }
329
330    /*************************************************************/
331
332    /* CODE LIFTED FROM ObjectOutputStream. */
333    private static void invokeMethod(final Object obj, final Method m,
334                                        final Object[] argList)
335        throws IOException
336    {
337        try {
338            java.security.AccessController.doPrivileged
339                (new java.security.PrivilegedExceptionAction() {
340                    public Object run() throws InvocationTargetException,
341                                        java.lang.IllegalAccessException {
342                        m.invoke(obj, argList);
343                        return null;
344                    }
345                });
346        } catch (java.security.PrivilegedActionException e) {
347            Exception ex = e.getException();
348            if (ex instanceof InvocationTargetException) {
349                Throwable t =
350                        ((InvocationTargetException)ex).getTargetException();
351                if (t instanceof IOException)
352                    throw (IOException)t;
353                else if (t instanceof RuntimeException)
354                    throw (RuntimeException) t;
355                else if (t instanceof Error)
356                    throw (Error) t;
357                else
358                    throw new Error("interal error");
359            } else {
360                // IllegalAccessException cannot happen
361            }
362        }
363    }
364};
365