/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file 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.invocation.pooled.interfaces;
import org.jboss.invocation.Invocation;
import org.jboss.invocation.InvocationType;
import org.jboss.invocation.MarshalledInvocation;
import org.jboss.invocation.MarshalledValue;
import javax.transaction.Transaction;
import java.io.IOException;
import java.lang.reflect.Method;
import java.security.Principal;
import java.util.HashMap;
import java.util.Iterator;
/**
* The MarshalledInvocation is an invocation that travels. As such it serializes
* its payload because of lack of ClassLoader visibility.
* As such it contains Marshalled data representing the byte[] of the Invocation object it extends
* Besides handling the specifics of "marshalling" the payload, which could be done at the Invocation level
* the Marshalled Invocation can hold optimization and needed code for distribution for example the
* TransactionPropagationContext which is a serialization of the TX for distribution purposes as
* well as the "hash" for the methods that we send, as opposed to sending Method objects.
* Serialization "optimizations" should be coded here in the externalization implementation of the class
*
* @author <a href="mailto:marc@jboss.org">Marc Fleury</a>
* @version $Revision: 81030 $
*/
public class PooledMarshalledInvocation
extends MarshalledInvocation
implements java.io.Externalizable
{
// Constants -----------------------------------------------------
/** Serial Version Identifier. */
static final long serialVersionUID = -728630295444149842L;
private transient Transaction tx;
private transient Object credential;
private transient Principal principal;
private transient Object enterpriseContext;
private transient Object id;
private transient PooledMarshalledValue pooledMarshalledArgs;
// Constructors --------------------------------------------------
public PooledMarshalledInvocation()
{
// For externalization to work
}
public PooledMarshalledInvocation(Invocation invocation)
{
this.payload = invocation.payload;
this.as_is_payload = invocation.as_is_payload;
this.method = invocation.getMethod();
this.objectName = invocation.getObjectName();
this.args = invocation.getArguments();
this.invocationType = invocation.getType();
}
/*
public MarshalledInvocation(Map payload)
{
super(payload);
}
public MarshalledInvocation(Map payload, Map as_is_payload)
{
super(payload);
this.as_is_payload = as_is_payload;
}
*/
public PooledMarshalledInvocation(
Object id,
Method m,
Object[] args,
Transaction tx,
Principal identity,
Object credential)
{
super(id, m, args, tx, identity, credential);
}
// Public --------------------------------------------------------
public Object getEnterpriseContext()
{
return enterpriseContext;
}
public void setEnterpriseContext(Object enterpriseContext)
{
this.enterpriseContext = enterpriseContext;
}
public Object getId()
{
if (id == null) id = super.getId();
return id;
}
public void setId(Object id)
{
super.setId(id);
this.id = id;
}
public void setTransaction(Transaction tx)
{
super.setTransaction(tx);
this.tx = tx;
}
public Transaction getTransaction()
{
if (tx == null) tx = super.getTransaction();
return this.tx;
}
public Object getCredential()
{
if (credential == null) credential = super.getCredential();
return credential;
}
public void setCredential(Object credential)
{
super.setCredential(credential);
this.credential = credential;
}
public Principal getPrincipal()
{
if (principal == null) principal = super.getPrincipal();
return principal;
}
public void setPrincipal(Principal principal)
{
super.setPrincipal(principal);
this.principal = principal;
}
public Object[] getArguments()
{
if (this.args == null)
{
try
{
this.args = (Object[]) pooledMarshalledArgs.get();
}
catch (Exception e)
{
e.printStackTrace();
}
}
return args;
}
// Externalizable implementation ---------------------------------
public void writeExternal(java.io.ObjectOutput out)
throws IOException
{
out.writeObject(invocationType);
// FIXME marcf: the "specific" treatment of Transactions should be abstracted.
// Write the TPC, not the local transaction
out.writeObject(tpc);
long methodHash = calculateHash(this.method);
out.writeLong(methodHash);
out.writeInt(((Integer)this.objectName).intValue());
out.writeObject(new PooledMarshalledValue(this.args));
// Write out payload hashmap
// Don't use hashmap serialization to avoid not-needed data being
// marshalled
// The map contains only serialized representations of every other object
// Everything else is possibly tied to classloaders that exist inside the
// server but not in the generic JMX land. they will travel in the payload
// as MarshalledValue objects, see the Invocation getter logic
//
if (payload == null)
out.writeInt(0);
else
{
out.writeInt(payload.size());
Iterator keys = payload.keySet().iterator();
while (keys.hasNext())
{
Object currentKey = keys.next();
// This code could be if (object.getClass().getName().startsWith("java")) then don't serialize.
// Bench the above for speed.
out.writeObject(currentKey);
out.writeObject(new MarshalledValue(payload.get(currentKey)));
}
}
// This map is "safe" as is
//out.writeObject(as_is_payload);
if (as_is_payload == null)
out.writeInt(0);
else
{
out.writeInt(as_is_payload.size());
Iterator keys = as_is_payload.keySet().iterator();
while (keys.hasNext())
{
Object currentKey = keys.next();
out.writeObject(currentKey);
out.writeObject(as_is_payload.get(currentKey));
}
}
}
public void readExternal(java.io.ObjectInput in)
throws IOException, ClassNotFoundException
{
invocationType = (InvocationType)in.readObject();
tpc = in.readObject();
this.methodHash = in.readLong();
this.objectName = new Integer(in.readInt());
pooledMarshalledArgs = (PooledMarshalledValue) in.readObject();
int payloadSize = in.readInt();
if (payloadSize > 0)
{
payload = new HashMap();
for (int i = 0; i < payloadSize; i++)
{
Object key = in.readObject();
Object value = in.readObject();
payload.put(key, value);
}
}
int as_is_payloadSize = in.readInt();
if (as_is_payloadSize > 0)
{
as_is_payload = new HashMap();
for (int i = 0; i < as_is_payloadSize; i++)
{
Object key = in.readObject();
Object value = in.readObject();
as_is_payload.put(key, value);
}
}
}
}