/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.serial.io;
import org.jboss.serial.classmetamodel.ClassDescriptorStrategy;
import org.jboss.serial.classmetamodel.ClassResolver;
import org.jboss.serial.classmetamodel.DefaultClassDescriptorStrategy;
import org.jboss.serial.exception.SerializationException;
import org.jboss.serial.objectmetamodel.DataContainer;
import org.jboss.serial.objectmetamodel.DataContainerConstants;
import org.jboss.serial.objectmetamodel.DefaultObjectDescriptorStrategy;
import org.jboss.serial.objectmetamodel.ObjectDescriptorStrategy;
import org.jboss.serial.objectmetamodel.ObjectSubstitutionInterface;
import org.jboss.serial.util.ClassMetaConsts;
import org.jboss.serial.util.StringUtilBuffer;
import org.jboss.serial.util.StringUtil;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.Arrays;
/**
* @author <a href="mailto:clebert.suconic@jboss.com">Clebert Suconic</a>
*/
public class JBossObjectInputStream extends ObjectInputStream implements DataContainerConstants
{
InputStream is;
DataInputStream dis;
DataContainer container;
ClassLoader classLoader;
StringUtilBuffer buffer;
private static Constructor constructorObjectStreamClass;
private static Field setNameField;
ClassDescriptorStrategy classDescriptorStrategy = new DefaultClassDescriptorStrategy();
ObjectDescriptorStrategy objectDescriptorStrategy = new DefaultObjectDescriptorStrategy();
static
{
try
{
constructorObjectStreamClass = ObjectStreamClass.class.getDeclaredConstructor(ClassMetaConsts.EMPTY_CLASS_ARRY);
constructorObjectStreamClass.setAccessible(true);
setNameField = ObjectStreamClass.class.getDeclaredField("name");
setNameField.setAccessible(true);
}
catch (Exception e)
{
constructorObjectStreamClass = null;
setNameField=null;
e.printStackTrace();
}
}
private static Field fieldEnableResolve;
static
{
try {
fieldEnableResolve = ObjectInputStream.class.getDeclaredField("enableResolve");
fieldEnableResolve.setAccessible(true);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
protected ObjectSubstitutionInterface getSubstitutionInterface() throws IOException
{
try
{
if (fieldEnableResolve.getBoolean(this))
{
return new ObjectSubstitutionInterface()
{
public Object replaceObject(Object obj) throws IOException {
return JBossObjectInputStream.this.resolveObject(obj);
}
};
} else
{
return null;
}
}
catch (IllegalAccessException ex)
{
throw new SerializationException(ex.getMessage(),ex);
}
}
public JBossObjectInputStream(InputStream is) throws IOException
{
this(is,Thread.currentThread().getContextClassLoader());
}
public JBossObjectInputStream(InputStream is,StringUtilBuffer buffer) throws IOException
{
this(is,Thread.currentThread().getContextClassLoader(),buffer);
}
public JBossObjectInputStream(InputStream is, ClassLoader loader) throws IOException
{
this(is,loader,null);
}
/** In case of InputStream is null, the only method that can be used on this class is smartClone */
public JBossObjectInputStream(InputStream is, ClassLoader loader,StringUtilBuffer buffer) throws IOException
{
super();
this.buffer=buffer;
if (is!=null)
{
this.is=is;
readStreamHeader();
if (is instanceof DataInputStream)
{
dis = (DataInputStream)is;
} else
{
dis = new DataInputStream(is);
}
}
this.classLoader =loader;
}
private void checkSignature(InputStream is) throws IOException {
byte signature[] = new byte[openSign.length];
is.read(signature);
if (!Arrays.equals(signature,openSign))
{
throw new IOException("Mismatch version of JBossSerialization signature");
}
}
ClassResolver resolver = new ClassResolver()
{
public Class resolveClass(String name) throws ClassNotFoundException {
if (constructorObjectStreamClass!=null)
{
try
{
ObjectStreamClass streamClass = (ObjectStreamClass)constructorObjectStreamClass.newInstance(ClassMetaConsts.EMPTY_OBJECT_ARRAY);
setNameField.set(streamClass,name);
return JBossObjectInputStream.this.resolveClass(streamClass);
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
}
return null;
}
};
protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
return Class.forName(desc.getName(),false,getClassLoader());
}
/** This is the old method of reading objects, always loading everything to a datacontainer*/
public Object readObjectUsingDataContainer() throws IOException,
ClassNotFoundException
{
DataContainer container = new DataContainer(classLoader,false,buffer);
container.setClassResolver(resolver);
container.loadData(dis);
ObjectInput input = container.getInput();
return input.readObject();
}
public Object readObjectOverride() throws IOException,
ClassNotFoundException
{
DataContainer container = new DataContainer(classLoader,this.getSubstitutionInterface(), false,buffer,classDescriptorStrategy,objectDescriptorStrategy);
container.setClassResolver(resolver);
//container.loadData(dis);
//ObjectInput input = container.getInput();
ObjectInput input = container.getDirectInput(dis);
return input.readObject();
}
public Object readUnshared() throws IOException, ClassNotFoundException
{
return readObjectOverride();
}
public void defaultReadObject() throws IOException, ClassNotFoundException
{
}
public void registerValidation(ObjectInputValidation obj, int prio)
throws NotActiveException, InvalidObjectException
{
}
protected void readStreamHeader() throws IOException,
StreamCorruptedException
{
checkSignature(is);
}
protected ObjectStreamClass readClassDescriptor() throws IOException,
ClassNotFoundException
{
return null;
}
protected ClassDescriptorStrategy getClassDescriptorStrategy()
{
return classDescriptorStrategy;
}
protected void setClassDescriptorStrategy(ClassDescriptorStrategy classDescriptorStrategy)
{
this.classDescriptorStrategy = classDescriptorStrategy;
}
protected ObjectDescriptorStrategy getObjectDescriptorStrategy()
{
return objectDescriptorStrategy;
}
protected void setObjectDescriptorStrategy(ObjectDescriptorStrategy objectDescriptorStrategy)
{
this.objectDescriptorStrategy = objectDescriptorStrategy;
}
public int read() throws IOException
{
return dis.read();
}
public int read(byte[] buf, int off, int len) throws IOException
{
return dis.read(buf, off, len);
}
/**
* Returns the number of bytes that can be read without blocking.
*
* @return the number of available bytes.
* @throws IOException
* if there are I/O errors while reading from the underlying
* <code>InputStream</code>
*/
public int available() throws IOException
{
return 1;
}
public void close() throws IOException
{
}
public boolean readBoolean() throws IOException
{
return dis.readBoolean();
}
public byte readByte() throws IOException
{
return dis.readByte();
}
public int readUnsignedByte() throws IOException
{
return dis.readUnsignedByte();
}
public char readChar() throws IOException
{
return dis.readChar();
}
public short readShort() throws IOException
{
return dis.readShort();
}
public int readUnsignedShort() throws IOException
{
return dis.readUnsignedShort();
}
public int readInt() throws IOException
{
return dis.readInt();
}
public long readLong() throws IOException
{
return dis.readLong();
}
public float readFloat() throws IOException
{
return dis.readFloat();
}
public double readDouble() throws IOException
{
return dis.readDouble();
}
public void readFully(byte[] buf) throws IOException
{
dis.readFully(buf);
}
public void readFully(byte[] buf, int off, int len) throws IOException
{
dis.readFully(buf, off, len);
}
public int skipBytes(int len) throws IOException
{
return dis.skipBytes(len);
}
public String readLine() throws IOException
{
return dis.readLine();
}
public String readUTF() throws IOException
{
return StringUtil.readString(dis,buffer);
}
/*
* (non-Javadoc)
*
* @see java.io.ObjectInput#read(byte[])
*/
public int read(byte[] b) throws IOException
{
return dis.read(b);
}
/*
* (non-Javadoc)
*
* @see java.io.ObjectInput#skip(long)
*/
public long skip(long n) throws IOException
{
return dis.skip(n);
}
public ClassLoader getClassLoader() {
if (classLoader==null){
return Thread.currentThread().getContextClassLoader();
}
else
{
return classLoader;
}
}
public void setClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
}