/*
* JBoss, Home of Professional Open Source
* Copyright 2006, JBoss Inc., and others contributors as indicated
* by the @authors tag. All rights reserved.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* 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,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
* (C) 2005-2006,
*/
package org.jboss.internal.soa.esb.message.format.serialized;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.jboss.internal.soa.esb.message.format.DeferredDeserialisationException;
import org.jboss.soa.esb.util.ContextObjectInputStream;
/**
* Wrapper class for serialised values, supporting JIT deserialisation.
*
* @author <a href='kevin.conner@jboss.com'>Kevin Conner</a>
*/
public class SerializedValueImpl implements Serializable
{
/**
* The serial version UID for this class.
*/
private static final long serialVersionUID = -5354588126152655437L;
/**
* The transient value.
*/
private transient Serializable value ;
/**
* The serialised form.
*/
private byte[] serialisedForm ;
/**
* Construct the serialised value wrapper for the specific value.
* @param value The serializable value.
*/
private SerializedValueImpl(final Serializable value)
{
this.value = value ;
}
/**
* Get the wrapped value.
* @return The wrapped value.
*/
public Serializable getValue()
{
if ((value == null) && (serialisedForm != null))
{
final ByteArrayInputStream bais = new ByteArrayInputStream(serialisedForm) ;
final ObjectInputStream ois ;
try
{
ois = new ContextObjectInputStream(bais) ;
}
catch (final IOException ioe)
{
throw new DeferredDeserialisationException("Error creating object input stream", ioe) ;
}
try
{
value = (Serializable)ois.readObject() ;
}
catch (final IOException ioe)
{
throw new DeferredDeserialisationException("Error reading object input stream", ioe) ;
}
catch (final ClassNotFoundException cnfe)
{
throw new DeferredDeserialisationException("Error constructing object value", cnfe) ;
}
serialisedForm = null ;
}
return value ;
}
/**
* Handle the serialisation.
* @param stream The object output stream.
* @throws IOException For errors during serialisation.
*/
private void writeObject(final ObjectOutputStream stream)
throws IOException
{
if (value != null)
{
final ByteArrayOutputStream baos = new ByteArrayOutputStream() ;
final ObjectOutputStream oos = new ObjectOutputStream(baos) ;
oos.writeObject(value) ;
serialisedForm = baos.toByteArray() ;
}
stream.defaultWriteObject() ;
}
/**
* Return a string representation of this object.
* @return the string representation of the value or a deferred identifier.
*/
public String toString()
{
if (value != null)
{
return value.toString() ;
}
else
{
return "Deferred serialized value: " + Integer.toHexString(System.identityHashCode(this)) ;
}
}
/**
* Create a wrapper for the specific value.
* @param value The value to wrap.
* @return a wrapped value or the value it serialisation is safe.
*/
public static Serializable wrap(final Serializable value)
{
if (value != null)
{
final Class<?> componentType = getComponentType(value.getClass()) ;
if ((componentType != Boolean.class) &&
(componentType != Boolean.TYPE) &&
(componentType != Byte.class) &&
(componentType != Byte.TYPE) &&
(componentType != Short.class) &&
(componentType != Short.TYPE) &&
(componentType != Character.class) &&
(componentType != Character.TYPE) &&
(componentType != Integer.class) &&
(componentType != Integer.TYPE) &&
(componentType != Long.class) &&
(componentType != Long.TYPE) &&
(componentType != Float.class) &&
(componentType != Float.TYPE) &&
(componentType != Double.class) &&
(componentType != Double.TYPE) &&
(componentType != String.class) &&
(componentType != SerializedValueImpl.class))
{
return new SerializedValueImpl(value) ;
}
}
return value ;
}
/**
* Unwrap the object, returning the value.
* @param wrapped The wrapped value.
* @return the unwrapped object.
*/
public static Serializable unwrap(final Serializable value)
{
if (value instanceof SerializedValueImpl)
{
return ((SerializedValueImpl)value).getValue() ;
}
return value ;
}
/**
* Wrap the entries in the specified list.
* @param list The list to be wrapped.
*/
public static void wrapList(final List<Serializable> list)
{
final int listSize = list.size() ;
for(int count = 0 ; count < listSize ; count++)
{
final Serializable current = list.get(count) ;
final Serializable wrapped = SerializedValueImpl.wrap(current) ;
if (current != wrapped)
{
list.set(count, wrapped) ;
}
}
}
/**
* Wrap the values in the specified map.
* @param map The map to be wrapped.
*/
public static <K> void wrapMap(final Map<K, Serializable> map)
{
if (map.size() > 0)
{
Hashtable<K, Serializable> wrappedMap = null ;
for(Entry<K, Serializable> entry: map.entrySet())
{
final Serializable current = entry.getValue() ;
final Serializable wrapped = SerializedValueImpl.wrap(current) ;
if (current != wrapped)
{
if (wrappedMap == null)
{
wrappedMap = new Hashtable<K, Serializable>() ;
}
wrappedMap.put(entry.getKey(), wrapped) ;
}
}
if (wrappedMap != null)
{
map.putAll(wrappedMap) ;
}
}
}
/**
* Get the component type for this class.
* @param clazz The class to check.
* @return The component type for the class.
*/
private static Class<?> getComponentType(final Class<?> clazz)
{
if (clazz.isArray())
{
return getComponentType(clazz.getComponentType()) ;
}
else
{
return clazz ;
}
}
}