001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.wicket.util.io;
018:
019: import java.io.DataInputStream;
020: import java.io.EOFException;
021: import java.io.IOException;
022: import java.io.InputStream;
023: import java.io.ObjectInputStream;
024: import java.io.ObjectStreamClass;
025: import java.io.Serializable;
026: import java.lang.reflect.Array;
027: import java.lang.reflect.InvocationTargetException;
028: import java.util.HashMap;
029:
030: import org.apache.wicket.util.collections.IntHashMap;
031:
032: /**
033: * @author jcompagner
034: */
035: public final class WicketObjectInputStream extends ObjectInputStream {
036:
037: private final IntHashMap handledObjects = new IntHashMap();
038: private short handleCounter = 0;
039:
040: private final DataInputStream in;
041: private ClassStreamHandler currentStreamHandler;
042: private HandleArrayListStack stack = new HandleArrayListStack();
043: private HandleArrayListStack defaultRead = new HandleArrayListStack();
044:
045: /**
046: * Construct.
047: * @param in
048: * @throws IOException
049: */
050: public WicketObjectInputStream(InputStream in) throws IOException {
051: super ();
052: this .in = new DataInputStream(in);
053: }
054:
055: /**
056: * @see java.io.ObjectInputStream#readObjectOverride()
057: */
058: protected Object readObjectOverride() throws IOException,
059: ClassNotFoundException {
060: Object value = null;
061: int token = in.read();
062: if (token == ClassStreamHandler.NULL) {
063: return null;
064: } else if (token == ClassStreamHandler.HANDLE) {
065: short handle = in.readShort();
066: value = handledObjects.get(handle);
067: if (value == null) {
068: throw new RuntimeException(
069: "Expected to find a handle for " + handle);
070: }
071: } else if (token == ClassStreamHandler.CLASS_DEF) {
072: short classDef = in.readShort();
073: ClassStreamHandler oldStreamHandler = currentStreamHandler;
074: currentStreamHandler = ClassStreamHandler.lookup(classDef);
075: if (currentStreamHandler.getStreamClass() == String.class) {
076: value = in.readUTF();
077: handledObjects.put(handleCounter++, value);
078: } else {
079: try {
080: value = currentStreamHandler.createObject();
081: handledObjects.put(handleCounter++, value);
082: stack.push(value);
083: if (!currentStreamHandler.invokeReadMethod(this ,
084: value)) {
085: currentStreamHandler.readFields(this , value);
086: }
087: value = currentStreamHandler.readResolve(value);
088: stack.pop();
089: } catch (IllegalArgumentException ex) {
090: throw new RuntimeException(ex);
091: } catch (InstantiationException ex) {
092: throw new RuntimeException(ex);
093: } catch (IllegalAccessException ex) {
094: throw new RuntimeException(ex);
095: } catch (InvocationTargetException ex) {
096: throw new RuntimeException(ex);
097: }
098: }
099: currentStreamHandler = oldStreamHandler;
100: } else if (token == ClassStreamHandler.CLASS) {
101: short classDef = in.readShort();
102: ClassStreamHandler lookup = ClassStreamHandler
103: .lookup(classDef);
104: value = lookup.getStreamClass();
105: } else if (token == ClassStreamHandler.ARRAY) {
106: short classDef = in.readShort();
107: ClassStreamHandler lookup = ClassStreamHandler
108: .lookup(classDef);
109: int length = in.readInt();
110: Object[] array = (Object[]) Array.newInstance(lookup
111: .getStreamClass(), length);
112: handledObjects.put(handleCounter++, array);
113: for (int i = 0; i < array.length; i++) {
114: array[i] = readObjectOverride();
115: }
116: value = array;
117: } else if (token == ClassStreamHandler.PRIMITIVE_ARRAY) {
118: short classDef = in.readShort();
119: ClassStreamHandler lookup = ClassStreamHandler
120: .lookup(classDef);
121: value = lookup.readArray(this );
122: handledObjects.put(handleCounter++, value);
123: } else {
124: throw new RuntimeException("not a valid token found: "
125: + token);
126: }
127: return value;
128: }
129:
130: /**
131: * @see java.io.ObjectInputStream#defaultReadObject()
132: */
133: public void defaultReadObject() throws IOException,
134: ClassNotFoundException {
135: Object currentObject = stack.peek();
136: if (!defaultRead.contains(currentObject)) {
137: defaultRead.add(currentObject);
138: currentStreamHandler.readFields(this , currentObject);
139: }
140: }
141:
142: /**
143: * @see java.io.ObjectInputStream#close()
144: */
145: public void close() throws IOException {
146: stack = null;
147: defaultRead = null;
148: currentStreamHandler = null;
149: in.close();
150: }
151:
152: /**
153: * Reads in a boolean.
154: *
155: * @return the boolean read.
156: * @throws EOFException If end of file is reached.
157: * @throws IOException If other I/O error has occurred.
158: */
159: public boolean readBoolean() throws IOException {
160: return in.readBoolean();
161: }
162:
163: /**
164: * Reads an 8 bit byte.
165: *
166: * @return the 8 bit byte read.
167: * @throws EOFException If end of file is reached.
168: * @throws IOException If other I/O error has occurred.
169: */
170: public byte readByte() throws IOException {
171: return in.readByte();
172: }
173:
174: /**
175: * Reads an unsigned 8 bit byte.
176: *
177: * @return the 8 bit byte read.
178: * @throws EOFException If end of file is reached.
179: * @throws IOException If other I/O error has occurred.
180: */
181: public int readUnsignedByte() throws IOException {
182: return in.readUnsignedByte();
183: }
184:
185: /**
186: * Reads a 16 bit char.
187: *
188: * @return the 16 bit char read.
189: * @throws EOFException If end of file is reached.
190: * @throws IOException If other I/O error has occurred.
191: */
192: public char readChar() throws IOException {
193: return in.readChar();
194: }
195:
196: /**
197: * Reads a 16 bit short.
198: *
199: * @return the 16 bit short read.
200: * @throws EOFException If end of file is reached.
201: * @throws IOException If other I/O error has occurred.
202: */
203: public short readShort() throws IOException {
204: return in.readShort();
205: }
206:
207: /**
208: * Reads an unsigned 16 bit short.
209: *
210: * @return the 16 bit short read.
211: * @throws EOFException If end of file is reached.
212: * @throws IOException If other I/O error has occurred.
213: */
214: public int readUnsignedShort() throws IOException {
215: return in.readUnsignedShort();
216: }
217:
218: /**
219: * Reads a 32 bit int.
220: *
221: * @return the 32 bit integer read.
222: * @throws EOFException If end of file is reached.
223: * @throws IOException If other I/O error has occurred.
224: */
225: public int readInt() throws IOException {
226: return in.readInt();
227: }
228:
229: /**
230: * Reads a 64 bit long.
231: *
232: * @return the read 64 bit long.
233: * @throws EOFException If end of file is reached.
234: * @throws IOException If other I/O error has occurred.
235: */
236: public long readLong() throws IOException {
237: return in.readLong();
238: }
239:
240: /**
241: * Reads a 32 bit float.
242: *
243: * @return the 32 bit float read.
244: * @throws EOFException If end of file is reached.
245: * @throws IOException If other I/O error has occurred.
246: */
247: public float readFloat() throws IOException {
248: return in.readFloat();
249: }
250:
251: /**
252: * Reads a 64 bit double.
253: *
254: * @return the 64 bit double read.
255: * @throws EOFException If end of file is reached.
256: * @throws IOException If other I/O error has occurred.
257: */
258: public double readDouble() throws IOException {
259: return in.readDouble();
260: }
261:
262: /**
263: * Reads bytes, blocking until all bytes are read.
264: *
265: * @param buf the buffer into which the data is read
266: * @throws EOFException If end of file is reached.
267: * @throws IOException If other I/O error has occurred.
268: */
269: public void readFully(byte[] buf) throws IOException {
270: in.readFully(buf, 0, buf.length);
271: }
272:
273: /**
274: * Reads bytes, blocking until all bytes are read.
275: *
276: * @param buf the buffer into which the data is read
277: * @param off the start offset of the data
278: * @param len the maximum number of bytes to read
279: * @throws EOFException If end of file is reached.
280: * @throws IOException If other I/O error has occurred.
281: */
282: public void readFully(byte[] buf, int off, int len)
283: throws IOException {
284: int endoff = off + len;
285: if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
286: throw new IndexOutOfBoundsException();
287: }
288: in.readFully(buf, off, len);
289: }
290:
291: /**
292: * @see java.io.ObjectInputStream#readUTF()
293: */
294: public String readUTF() throws IOException {
295: String s = in.readUTF();
296: return s;
297: }
298:
299: /**
300: * @see java.io.ObjectInputStream#read()
301: */
302: public int read() throws IOException {
303: return in.read();
304: }
305:
306: /**
307: * @see java.io.InputStream#read(byte[])
308: */
309: public int read(byte[] b) throws IOException {
310: return in.read(b);
311: }
312:
313: /**
314: * @see java.io.ObjectInputStream#read(byte[], int, int)
315: */
316: public int read(byte[] buf, int off, int len) throws IOException {
317: return in.read(buf, off, len);
318: }
319:
320: /**
321: * @see java.io.ObjectInputStream#readFields()
322: */
323: public GetField readFields() throws IOException,
324: ClassNotFoundException {
325: GetFieldImpl field = new GetFieldImpl();
326: field.read();
327: return field;
328: }
329:
330: private class GetFieldImpl extends GetField {
331: private final HashMap values = new HashMap();
332:
333: private void read() throws IOException, ClassNotFoundException {
334: short token = readShort();
335: ClassStreamHandler lookup = ClassStreamHandler
336: .lookup(boolean.class);
337: if (token == lookup.getClassId()) {
338: short count = readShort();
339: for (int i = 0; i < count; i++) {
340: String key = (String) readObjectOverride();
341: values.put(key, readBoolean() ? Boolean.TRUE
342: : Boolean.FALSE);
343: }
344: token = readShort();
345: if (token == ClassStreamHandler.NULL) {
346: return;
347: }
348: }
349: lookup = ClassStreamHandler.lookup(byte.class);
350: if (token == lookup.getClassId()) {
351: short count = readShort();
352: for (int i = 0; i < count; i++) {
353: String key = (String) readObjectOverride();
354: values.put(key, new Byte(readByte()));
355: }
356: token = readShort();
357: if (token == ClassStreamHandler.NULL) {
358: return;
359: }
360: }
361: lookup = ClassStreamHandler.lookup(short.class);
362: if (token == lookup.getClassId()) {
363: short count = readShort();
364: for (int i = 0; i < count; i++) {
365: String key = (String) readObjectOverride();
366: values.put(key, new Short(readShort()));
367: }
368: token = readShort();
369: if (token == ClassStreamHandler.NULL) {
370: return;
371: }
372: }
373: lookup = ClassStreamHandler.lookup(char.class);
374: if (token == lookup.getClassId()) {
375: short count = readShort();
376: for (int i = 0; i < count; i++) {
377: String key = (String) readObjectOverride();
378: values.put(key, new Character(readChar()));
379: }
380: token = readShort();
381: if (token == ClassStreamHandler.NULL) {
382: return;
383: }
384: }
385: lookup = ClassStreamHandler.lookup(int.class);
386: if (token == lookup.getClassId()) {
387: short count = readShort();
388: for (int i = 0; i < count; i++) {
389: String key = (String) readObjectOverride();
390: values.put(key, new Integer(readInt()));
391: }
392: token = readShort();
393: if (token == ClassStreamHandler.NULL) {
394: return;
395: }
396: }
397: lookup = ClassStreamHandler.lookup(long.class);
398: if (token == lookup.getClassId()) {
399: short count = readShort();
400: for (int i = 0; i < count; i++) {
401: String key = (String) readObjectOverride();
402: values.put(key, new Long(readLong()));
403: }
404: token = readShort();
405: if (token == ClassStreamHandler.NULL) {
406: return;
407: }
408: }
409: lookup = ClassStreamHandler.lookup(float.class);
410: if (token == lookup.getClassId()) {
411: short count = readShort();
412: for (int i = 0; i < count; i++) {
413: String key = (String) readObjectOverride();
414: values.put(key, new Float(readFloat()));
415: }
416: token = readShort();
417: if (token == ClassStreamHandler.NULL) {
418: return;
419: }
420: }
421: lookup = ClassStreamHandler.lookup(double.class);
422: if (token == lookup.getClassId()) {
423: short count = readShort();
424: for (int i = 0; i < count; i++) {
425: String key = (String) readObjectOverride();
426: values.put(key, new Double(readDouble()));
427: }
428: token = readShort();
429: if (token == ClassStreamHandler.NULL) {
430: return;
431: }
432: }
433: lookup = ClassStreamHandler.lookup(Serializable.class);
434: if (token == lookup.getClassId()) {
435: short count = readShort();
436: for (int i = 0; i < count; i++) {
437: String key = (String) readObjectOverride();
438: values.put(key, readObjectOverride());
439: }
440: token = readShort();
441: }
442: if (token != ClassStreamHandler.NULL) {
443: throw new RuntimeException("Expected NULL end byte");
444: }
445: }
446:
447: /**
448: * @see java.io.ObjectInputStream.GetField#defaulted(java.lang.String)
449: */
450: public boolean defaulted(String name) throws IOException {
451: return values.get(name) == null;
452: }
453:
454: /**
455: * @see java.io.ObjectInputStream.GetField#get(java.lang.String, byte)
456: */
457: public byte get(String name, byte val) throws IOException {
458: Object o = values.get(name);
459: if (o instanceof Byte) {
460: return ((Byte) o).byteValue();
461: }
462: return val;
463: }
464:
465: /**
466: * @see java.io.ObjectInputStream.GetField#get(java.lang.String, char)
467: */
468: public char get(String name, char val) throws IOException {
469: Object o = values.get(name);
470: if (o instanceof Byte) {
471: return ((Character) o).charValue();
472: }
473: return val;
474: }
475:
476: /**
477: * @see java.io.ObjectInputStream.GetField#get(java.lang.String, double)
478: */
479: public double get(String name, double val) throws IOException {
480: Object o = values.get(name);
481: if (o instanceof Double) {
482: return ((Double) o).doubleValue();
483: }
484: return val;
485: }
486:
487: /**
488: * @see java.io.ObjectInputStream.GetField#get(java.lang.String, float)
489: */
490: public float get(String name, float val) throws IOException {
491: Object o = values.get(name);
492: if (o instanceof Float) {
493: return ((Float) o).floatValue();
494: }
495: return val;
496: }
497:
498: /**
499: * @see java.io.ObjectInputStream.GetField#get(java.lang.String, int)
500: */
501: public int get(String name, int val) throws IOException {
502: Object o = values.get(name);
503: if (o instanceof Integer) {
504: return ((Integer) o).intValue();
505: }
506: return val;
507: }
508:
509: /**
510: * @see java.io.ObjectInputStream.GetField#get(java.lang.String, long)
511: */
512: public long get(String name, long val) throws IOException {
513: Object o = values.get(name);
514: if (o instanceof Long) {
515: return ((Long) o).longValue();
516: }
517: return val;
518: }
519:
520: /**
521: * @see java.io.ObjectInputStream.GetField#get(java.lang.String, short)
522: */
523: public short get(String name, short val) throws IOException {
524: Object o = values.get(name);
525: if (o instanceof Short) {
526: return ((Short) o).shortValue();
527: }
528: return val;
529: }
530:
531: /**
532: * @see java.io.ObjectInputStream.GetField#get(java.lang.String, boolean)
533: */
534: public boolean get(String name, boolean val) throws IOException {
535: Object o = values.get(name);
536: if (o instanceof Boolean) {
537: return ((Boolean) o).booleanValue();
538: }
539: return val;
540: }
541:
542: /**
543: * @see java.io.ObjectInputStream.GetField#get(java.lang.String, java.lang.Object)
544: */
545: public Object get(String name, Object val) throws IOException {
546: Object o = values.get(name);
547: if (o != null) {
548: return o;
549: }
550: return val;
551: }
552:
553: /**
554: * @see java.io.ObjectInputStream.GetField#getObjectStreamClass()
555: */
556: public ObjectStreamClass getObjectStreamClass() {
557: return null;
558: }
559:
560: }
561: }
|