| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.directmemory.lightning.internal.instantiator.basic; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.DataOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.NotSerializableException; |
| import java.io.ObjectInputStream; |
| import java.io.ObjectStreamClass; |
| import java.io.ObjectStreamConstants; |
| import java.io.Serializable; |
| |
| import org.apache.directmemory.lightning.instantiator.ObjectInstantiator; |
| import org.apache.directmemory.lightning.internal.instantiator.ObjenesisException; |
| |
| /** |
| * Instantiates a class by using a dummy input stream that always feeds data for an empty object of the same kind. NOTE: |
| * This instantiator may not work properly if the class being instantiated defines a "readResolve" method, since it may |
| * return objects that have been returned previously (i.e., there's no guarantee that the returned object is a new one), |
| * or even objects from a completely different class. |
| * |
| * @author Leonardo Mesquita |
| * @see org.apache.directmemory.lightning.instantiator.ObjectInstantiator |
| */ |
| public class ObjectInputStreamInstantiator |
| implements ObjectInstantiator |
| { |
| |
| private static class MockStream |
| extends InputStream |
| { |
| |
| private int pointer; |
| |
| private byte[] data; |
| |
| private int sequence; |
| |
| private static final int[] NEXT = new int[] { 1, 2, 2 }; |
| |
| private byte[][] buffers; |
| |
| private final byte[] firstData; |
| |
| private static byte[] HEADER; |
| |
| private static byte[] REPEATING_DATA; |
| |
| static |
| { |
| initialize(); |
| } |
| |
| private static void initialize() |
| { |
| try |
| { |
| ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); |
| DataOutputStream dout = new DataOutputStream( byteOut ); |
| dout.writeShort( ObjectStreamConstants.STREAM_MAGIC ); |
| dout.writeShort( ObjectStreamConstants.STREAM_VERSION ); |
| HEADER = byteOut.toByteArray(); |
| |
| byteOut = new ByteArrayOutputStream(); |
| dout = new DataOutputStream( byteOut ); |
| |
| dout.writeByte( ObjectStreamConstants.TC_OBJECT ); |
| dout.writeByte( ObjectStreamConstants.TC_REFERENCE ); |
| dout.writeInt( ObjectStreamConstants.baseWireHandle ); |
| REPEATING_DATA = byteOut.toByteArray(); |
| } |
| catch ( IOException e ) |
| { |
| throw new Error( "IOException", e ); |
| } |
| |
| } |
| |
| public MockStream( Class<?> clazz ) |
| { |
| this.pointer = 0; |
| this.sequence = 0; |
| this.data = HEADER; |
| |
| // (byte) TC_OBJECT |
| // (byte) TC_CLASSDESC |
| // (short length) |
| // (byte * className.length) |
| // (long)serialVersionUID |
| // (byte) SC_SERIALIZABLE |
| // (short)0 <fields> |
| // TC_ENDBLOCKDATA |
| // TC_NULL |
| ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); |
| DataOutputStream dout = new DataOutputStream( byteOut ); |
| try |
| { |
| dout.writeByte( ObjectStreamConstants.TC_OBJECT ); |
| dout.writeByte( ObjectStreamConstants.TC_CLASSDESC ); |
| dout.writeUTF( clazz.getName() ); |
| dout.writeLong( ObjectStreamClass.lookup( clazz ).getSerialVersionUID() ); |
| dout.writeByte( ObjectStreamConstants.SC_SERIALIZABLE ); |
| dout.writeShort( (short) 0 ); // Zero fields |
| dout.writeByte( ObjectStreamConstants.TC_ENDBLOCKDATA ); |
| dout.writeByte( ObjectStreamConstants.TC_NULL ); |
| } |
| catch ( IOException e ) |
| { |
| throw new Error( "IOException", e ); |
| } |
| this.firstData = byteOut.toByteArray(); |
| buffers = new byte[][] { HEADER, firstData, REPEATING_DATA }; |
| } |
| |
| private void advanceBuffer() |
| { |
| pointer = 0; |
| sequence = NEXT[sequence]; |
| data = buffers[sequence]; |
| } |
| |
| @Override |
| public int read() |
| throws IOException |
| { |
| int result = data[pointer++]; |
| if ( pointer >= data.length ) |
| { |
| advanceBuffer(); |
| } |
| |
| return result; |
| } |
| |
| @Override |
| public int available() |
| throws IOException |
| { |
| return Integer.MAX_VALUE; |
| } |
| |
| @Override |
| public int read( byte[] b, int off, int len ) |
| throws IOException |
| { |
| int left = len; |
| int remaining = data.length - pointer; |
| |
| while ( remaining <= left ) |
| { |
| System.arraycopy( data, pointer, b, off, remaining ); |
| off += remaining; |
| left -= remaining; |
| advanceBuffer(); |
| remaining = data.length - pointer; |
| } |
| if ( left > 0 ) |
| { |
| System.arraycopy( data, pointer, b, off, left ); |
| pointer += left; |
| } |
| |
| return len; |
| } |
| } |
| |
| private ObjectInputStream inputStream; |
| |
| public ObjectInputStreamInstantiator( Class<?> clazz ) |
| { |
| if ( Serializable.class.isAssignableFrom( clazz ) ) |
| { |
| try |
| { |
| this.inputStream = new ObjectInputStream( new MockStream( clazz ) ); |
| } |
| catch ( IOException e ) |
| { |
| throw new Error( "IOException", e ); |
| } |
| } |
| else |
| { |
| throw new ObjenesisException( new NotSerializableException( clazz + " not serializable" ) ); |
| } |
| } |
| |
| @Override |
| public Object newInstance() |
| { |
| try |
| { |
| return inputStream.readObject(); |
| } |
| catch ( ClassNotFoundException e ) |
| { |
| throw new Error( "ClassNotFoundException", e ); |
| } |
| catch ( Exception e ) |
| { |
| throw new ObjenesisException( e ); |
| } |
| } |
| } |