| GenericCommand.java |
/* PAT: Persistent Applications Toolkit (patsystem.sf.net)
* Copyright (C) 2004, 2005 Tomasz Nazar, nthx at irc dot pl
*
* This library 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 of the License, or (at your option) any later version.
*
* This library 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Full version of the license is /docs/LICENSE.txt
*/
package org.nthx.pat;
import org.apache.log4j.Logger;
import org.prevayler.Command;
import org.prevayler.PrevalentSystem;
import java.io.Serializable;
import java.lang.reflect.Method;
/** Generic command for storing "transaction" information and invoking
* transactions.
* <p>The trick is not to store objects involved in transaction:
* <ul><li>target object - on which method is invoked
* <li>argument objects
* </ul>
* .. but to store their ids (OID) only ({@link ObjectForStream ObjectForStream
* really}).. And recovering real objects having an
* OID and vice versa.
*
* @version $Id: GenericCommand.java 3725 2005-06-09 23:57:03Z nthx $
* @author nthx@users.sourceforge.net
*/
public class GenericCommand
implements Command
{
//--- Fields ----------------
private String command;
private ObjectForStream[] targetAndArgsForStream;
private Class[] parameterTypes; //to differ between 'long' and 'Long', etc.
private Class targetClass;
//--- Constructors ----------
public GenericCommand(Object target, Method method, Object[] params)
{
String command = method.getName();
this.command = command;
this.targetAndArgsForStream = CommandGenerationHelper.targetAndBos2FakeOIDs(target, params);
this.parameterTypes = method.getParameterTypes();
this.targetClass = method.getDeclaringClass();
}
//--- Implementation --------
/** Invoked during writing (made by AOP) and reading (made by Prevayler
* deserialisation)
*/
public Serializable execute(PrevalentSystem system)
throws Throwable
{
// log.debug("GC: command: " + command);
// CommandGenerationHelper.showParamsForStream(targetAndArgsForStream);
// logCommand();
Object[] recoveredParams =
CommandGenerationHelper.fakeBOs2targetAndBos((IdentityMap)system,
targetAndArgsForStream,
targetClass+"."+command,
parameterTypes);
Object recoveredTarget = recoveredParams[0];
Method commandMethod = targetClass.getMethod(command, parameterTypes);
try
{
Object[] recoveredParamsOnly =
new Object[recoveredParams.length - 1];
System.arraycopy(recoveredParams, 1,
recoveredParamsOnly, 0,
recoveredParamsOnly.length);
commandMethod.setAccessible(true);
return (java.io.Serializable) commandMethod.invoke(
recoveredTarget,
recoveredParamsOnly);
} catch (IllegalAccessException e)
{
throw e.getCause();
} catch (java.lang.reflect.InvocationTargetException e)
{
//log.error("Normal execution error. Commands may throw them: " + e.getMessage(), e);
//normal execution Exception: commands may throw them..
//XXX: i'm not sure if above stmnt is true
throw e.getCause();
}
}
private void logCommand()
{
StringBuffer params = new StringBuffer();
for (int i=1; i<targetAndArgsForStream.length; i++)
{
if (targetAndArgsForStream[i] instanceof Identifiable)
params.append(targetAndArgsForStream[i].objectOrOID);
else
params.append(".., ");
}
log.debug("Recovering: " + command + "("+params+")");
}
public String toString()
{
String result = "<" + command + "\n";
if (null != targetAndArgsForStream)
{
for (int i = 0; i < targetAndArgsForStream.length; i++)
result = result + "\t<arg" + i + " " + targetAndArgsForStream[i].getClass().getName()
+ "\n\t " + targetAndArgsForStream[i] + "/>\n";
}
result = result + "\n</" + command + ">";
return result;
}
//--- internal Fields -------
private static Logger log = Logger.getLogger("pat");
}