User: reverbel
Date: 01/08/14 14:25:41
Added: iiop/src/main/org/jboss/ejb/plugins/iiop/server
IIOPContainerInvoker.java SkeletonStrategy.java
Log:
Preliminary version of IIOP container invoker.
Revision Changes Path
1.1
contrib/iiop/src/main/org/jboss/ejb/plugins/iiop/server/IIOPContainerInvoker.java
Index: IIOPContainerInvoker.java
===================================================================
/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.ejb.plugins.iiop.server;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.ServerException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.ejb.EJBMetaData;
import javax.ejb.EJBHome;
import javax.ejb.EJBObject;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
import org.omg.CORBA.ORB;
import org.omg.CORBA.BAD_OPERATION;
import org.omg.CORBA.Policy;
import org.omg.CORBA.portable.InvokeHandler;
import org.omg.CORBA.portable.InputStream;
import org.omg.CORBA.portable.OutputStream;
import org.omg.CORBA.portable.ResponseHandler;
import org.omg.CORBA.portable.UnknownException;
import org.omg.PortableServer.Current;
//import org.omg.PortableServer.CurrentHelper; // not available in jdk1.4
import org.omg.PortableServer.POA;
import org.omg.PortableServer.POAManager;
import org.omg.PortableServer.Servant;
import org.omg.PortableServer.IdAssignmentPolicyValue;
import org.omg.PortableServer.LifespanPolicyValue;
import org.omg.PortableServer.ServantRetentionPolicyValue;
import org.omg.PortableServer.RequestProcessingPolicyValue;
import org.omg.PortableServer.IdUniquenessPolicyValue;
import org.omg.CosNaming.NamingContext;
import org.omg.CosNaming.NamingContextExt;
import org.omg.CosNaming.NamingContextExtHelper;
import org.omg.CosNaming.NamingContextHelper;
import org.omg.CosNaming.NamingContextPackage.NotFound;
import org.omg.CosNaming.NameComponent;
import org.jboss.ejb.Container;
import org.jboss.ejb.ContainerInvokerContainer;
import org.jboss.ejb.ContainerInvoker;
import org.jboss.ejb.DeploymentException;
import org.jboss.ejb.MethodInvocation;
import org.jboss.ejb.plugins.iiop.EJBMetaDataImpl;
import org.jboss.ejb.plugins.iiop.RmiIdlUtil;
import org.jboss.metadata.EntityMetaData;
import org.jboss.metadata.MetaData;
import org.jboss.metadata.SessionMetaData;
import org.w3c.dom.Element;
import org.jboss.iiop.rmi.AttributeAnalysis;
import org.jboss.iiop.rmi.OperationAnalysis;
import org.jboss.iiop.rmi.InterfaceAnalysis;
/**
* A <code>ContainerInvoker</code> for invoking enterprise beans
* over the IIOP invocation transport.
* <p>
* An <code>IIOPContainerInvoker</code> provides two CORBA servants: one for
* its container's <code>EJBHome</code>, another for its container's set of
* <code>EJBObjects</code>.
* The <code>EJBObject</code> servant is the <code>IIOPContainerInvoker</code>
* itself, which extends <code>org.omg.PortableServer.Servant</code> and
* implements <code>org.omg.CORBA.portable.InvokeHandler</code>.
* The <code>EJBHome</code> servant is a field of the
* <code>IIOPContainerInvoker</code>. This field is an instance of an inner
* class of the container invoker.
* <p>
* An <code>IIOPContainerInvoker</code> has its own POA, used for all
* <code>EJBObject</code>s in its container. This POA's lifespan policy
* depends on the kind of container: transient for a session container,
* persistent for an entity container.
* <p>
* The <code>EJBHome</code> is registered on a different POA, which is shared
* by all <code>IIOPContainerInvokers</code> and has persistent lifespan
* policy.
* <p>
* The JNDI name of a bean is the "reference data" field embedded into the
* CORBA references for the beans' <code>EJBHome</code>. The JNDI name is also
* used as the name of POA of the bean's <code>IIOPContainerInvoker</code>.
* The id of a bean instance is the "reference data" field embedded into the
* CORBA reference for the corresponding <code>EJBObject</code>.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Francisco Reverbel</a>
* @version $Revision: 1.1 $
*/
public class IIOPContainerInvoker
extends Servant
implements InvokeHandler, ContainerInvoker
{
// Constants --------------------------------------------------------------
private static final byte[] nullId = createNullId();
// Attributes -------------------------------------------------------------
/**
* This <code>IIOPContainerInvoker</code>'s container.
*/
private Container container;
/**
* <code>JNDI</code> name of the enterprise bean in the container.
*/
private String jndiName;
/**
* <code>EJBMetaData</code> the enterprise bean in the container.
*/
private EJBMetaDataImpl ejbMetaData;
/**
* Mapping from bean methods to <code>SkeletonStrategy</code> instances.
*/
private Map beanMethodInvokerMap;
/**
* Mapping from home methods to <code>SkeletonStrategy</code> instances.
*/
private Map homeMethodInvokerMap;
/**
* CORBA repository ids of the RMI-IDL interfaces implemented by the bean
* (<code>EJBObject</code> instance).
*/
private String[] beanRepositoryIds;
/**
* CORBA repository ids of the RMI-IDL interfaces implemented by the bean's
* home (<code>EJBHome</code> instance).
*/
private String[] homeRepositoryIds;
/**
* A reference for the ORB.
*/
private ORB orb;
/**
* EJBHomes are registered on this POA.
*/
private POA homePOA;
/**
* POA for all <code>EJBObject</code>s in the container.
*/
private POA poa;
/**
* Thread-local <code>Current</code> object from which we get the target oid
* in an incoming IIOP request.
*/
private Current poaCurrent;
/**
* Servant for the container's <code>EJBHome</code>.
*/
private HomeServant ejbHomeServant;
private EJBHome ejbHome;
// Implementation of the interface ContainerPlugin -------------------------
public void setContainer(Container con)
{
this.container = con;
}
public void init() throws Exception
{
// Initialize orb and homePoa references
try {
orb = (ORB)new InitialContext().lookup("java:/JBossCorbaORB");
}
catch (NamingException e) {
throw new RuntimeException("Cannot lookup java:/JBossCorbaORB: " + e);
}
try {
homePOA = (POA)new InitialContext().lookup("java:/JBossCorbaHomePOA");
}
catch (NamingException e) {
throw new RuntimeException("Cannot lookup java:/JBossCorbaHomePOA: "
+ e);
}
// Create bean method mappings for container invoker
System.err.println("Bean methods: ---------------------");
InterfaceAnalysis interfaceAnalysis =
InterfaceAnalysis.getInterfaceAnalysis(
((ContainerInvokerContainer)container).getRemoteClass());
beanMethodInvokerMap = new HashMap();
AttributeAnalysis[] attrs = interfaceAnalysis.getAttributes();
for (int i = 0; i < attrs.length; i++) {
OperationAnalysis op = attrs[i].getAccessorAnalysis();
System.err.println(" " + op.getJavaName());
System.err.println(" " + op.getIDLName());
beanMethodInvokerMap.put(op.getIDLName(),
new SkeletonStrategy(op.getMethod()));
op = attrs[i].getMutatorAnalysis();
if (op != null) {
System.err.println(" " + op.getJavaName());
System.err.println(" " + op.getIDLName());
beanMethodInvokerMap.put(op.getIDLName(),
new SkeletonStrategy(op.getMethod()));
}
}
OperationAnalysis[] ops = interfaceAnalysis.getOperations();
for (int i = 0; i < ops.length; i++) {
System.err.println(" " + ops[i].getJavaName());
System.err.println(" " + ops[i].getIDLName());
beanMethodInvokerMap.put(ops[i].getIDLName(),
new SkeletonStrategy(
ops[i].getMethod()));
}
// Initialize repository ids of remote interface
beanRepositoryIds = interfaceAnalysis.getAllTypeIds();
// Create home method mappings for container invoker
System.err.println("Home methods: ---------------------");
interfaceAnalysis =
InterfaceAnalysis.getInterfaceAnalysis(
((ContainerInvokerContainer)container).getHomeClass());
attrs = interfaceAnalysis.getAttributes();
for (int i = 0; i < attrs.length; i++) {
OperationAnalysis op = attrs[i].getAccessorAnalysis();
System.err.println(" " + op.getJavaName());
System.err.println(" " + op.getIDLName());
homeMethodInvokerMap.put(op.getIDLName(),
new SkeletonStrategy(op.getMethod()));
op = attrs[i].getMutatorAnalysis();
if (op != null) {
System.err.println(" " + op.getJavaName());
System.err.println(" " + op.getIDLName());
homeMethodInvokerMap.put(op.getIDLName(),
new SkeletonStrategy(op.getMethod()));
}
}
ops = interfaceAnalysis.getOperations();
homeMethodInvokerMap = new HashMap();
for (int i = 0; i < ops.length; i++) {
System.err.println(" " + ops[i].getJavaName());
System.err.println(" " + ops[i].getIDLName());
homeMethodInvokerMap.put(ops[i].getIDLName(),
new SkeletonStrategy(ops[i].getMethod()));
}
// Initialize repository ids of home interface
homeRepositoryIds = interfaceAnalysis.getAllTypeIds();
// The jndi name will be embedded into the EJBHome CORBA reference
jndiName = container.getBeanMetaData().getJndiName();
// Activate ejbHome and get a CORBA reference to it
ejbHomeServant = new HomeServant();
homePOA.activate_object_with_id(jndiName.getBytes(), ejbHomeServant);
ejbHome = (EJBHome)PortableRemoteObject.narrow(
homePOA.id_to_reference(jndiName.getBytes()), EJBHome.class);
// Get a reference for the root POA
POA rootPOA = null;
try {
rootPOA = (POA)new InitialContext().lookup("java:/JBossCorbaPOA");
}
catch (NamingException e) {
throw new RuntimeException("Cannot lookup java:/JBossCorbaPOA: " + e);
}
// Initialize policies for bean POA
// (policies[0] will be set later on, depending on the kind of bean)
Policy[] policies = new Policy[5];
policies[1] = rootPOA.create_id_assignment_policy(
IdAssignmentPolicyValue.USER_ID);
policies[2] = rootPOA.create_servant_retention_policy(
ServantRetentionPolicyValue.NON_RETAIN);
policies[3] = rootPOA.create_request_processing_policy(
RequestProcessingPolicyValue.USE_DEFAULT_SERVANT);
policies[4] = rootPOA.create_id_uniqueness_policy(
IdUniquenessPolicyValue.MULTIPLE_ID);
// Set policies[0] and create metadata depending on the kind of bean
if (container.getBeanMetaData() instanceof EntityMetaData) {
// This is an entity bean (lifespan: persistent)
policies[0] = rootPOA.create_lifespan_policy(
LifespanPolicyValue.PERSISTENT);
Class pkClass;
EntityMetaData metaData = (EntityMetaData)container.getBeanMetaData();
String pkClassName = metaData.getPrimaryKeyClass();
try {
if (pkClassName != null)
pkClass = container.getClassLoader().loadClass(pkClassName);
else
pkClass = container.getClassLoader().loadClass(
metaData.getEjbClass()).getField(
metaData.getPrimKeyField()).getClass();
}
catch (NoSuchFieldException e) {
System.err.println("Unable to identify Bean's Primary Key class! "
+ "Did you specify a primary key class and/or field? "
+ "Does that field exist?");
throw new RuntimeException("Primary Key Problem");
}
catch (NullPointerException e) {
System.err.println("Unable to identify Bean's Primary Key class! "
+ "Did you specify a primary key class and/or field? "
+ "Does that field exist?");
throw new RuntimeException("Primary Key Problem");
}
ejbMetaData = new EJBMetaDataImpl(
((ContainerInvokerContainer)container).getRemoteClass(),
((ContainerInvokerContainer)container).getHomeClass(),
pkClass,
false, // Session
false, // Stateless
ejbHome);
}
else {
// This is a session bean (lifespan: transient)
policies[0] = rootPOA.create_lifespan_policy(
LifespanPolicyValue.TRANSIENT);
if (((SessionMetaData)container.getBeanMetaData()).isStateless()) {
// Stateless session bean
ejbMetaData = new EJBMetaDataImpl(
((ContainerInvokerContainer)container).getRemoteClass(),
((ContainerInvokerContainer)container).getHomeClass(),
null, // No PK
true, // Session
true, // Stateless
ejbHome);
}
else {
// Stateful session bean
ejbMetaData = new EJBMetaDataImpl(
((ContainerInvokerContainer)container).getRemoteClass(),
((ContainerInvokerContainer)container).getHomeClass(),
null, // No PK
true, // Session
false, // Stateless
ejbHome);
}
}
// Create bean POA (with name jndiName) and set its servant
poa = rootPOA.create_POA(jndiName, null, policies);
poa.set_servant(this);
// Get the POACurrent object
// TODO: make this code CORBA-compliant
// (jdk1.4 still does not have a CurrentHelper class,
// so I am doing it the unofficial way)
//poaCurrent = CurrentHelper.narrow(
// orb.resolve_initial_references("POACurrent"));
poaCurrent = (Current)orb.resolve_initial_references("POACurrent");
}
public void start() throws Exception
{
// Activate bean POA
poa.the_POAManager().activate();
// Just for testing
System.err.println("EJBHome reference for " + jndiName + ":");
System.err.println(orb.object_to_string((org.omg.CORBA.Object)ejbHome));
try {
// Bind the bean home in the JNDI initial context
Context context = new InitialContext();
rebind(context, jndiName, ejbHome);
System.err.println("Bound " + container.getBeanMetaData().getEjbName()
+ " to " + jndiName);
}
catch (Exception e) {
throw new ServerException(
"Could not bind either home or invoker in JNDI", e);
}
try {
// Register bean home in the CORBA name service
NamingContextExt rootContext = NamingContextExtHelper.narrow(
orb.resolve_initial_references("NameService"));
rebind(rootContext, jndiName, (org.omg.CORBA.Object)ejbHome);
}
catch (Exception e) {
throw new ServerException(
"Could not bind EJBHome in CORBA naming service", e);
}
// TODO: this should be after all beans were deployed
// ORBSingleton.start(); //!!!!!!!!!!!!!!!!!!
}
public void stop()
{
// TODO: put each call that might throw exceptions within a separate
// try block so that if one fails the following ones will be
// executed anyway
try {
// Unbind the bean home from JNDI initial context
Context ctx = new InitialContext();
ctx.unbind(jndiName);
// Unregister bean home from CORBA name service
NamingContext rootContext = NamingContextHelper.narrow(
orb.resolve_initial_references("NameService"));
NameComponent[] name = new NameComponent[1];
name[0] = new NameComponent(jndiName, "");
rootContext.unbind(name);
// Deactivate the EJBHome
homePOA.deactivate_object(jndiName.getBytes());
// Destroy its POA
poa.the_POAManager().deactivate(false, /* etherealize_objects */
true /* wait_for_completion */ );
poa.destroy(false, /* etherealize_objects */
false /* wait_for_completion */ );
}
catch (Exception e) {
e.printStackTrace();
}
}
public void destroy()
{
}
// Implementation of the interface ContainerInvoker ------------------------
public EJBMetaData getEJBMetaData()
{
return ejbMetaData;
}
public EJBHome getEJBHome()
{
return ejbHome;
}
public EJBObject getStatelessSessionEJBObject()
throws RemoteException
{
return (EJBObject)PortableRemoteObject.narrow(
poa.create_reference_with_id(nullId, beanRepositoryIds[0]),
EJBObject.class);
}
public EJBObject getStatefulSessionEJBObject(Object id)
throws RemoteException
{
return (EJBObject)PortableRemoteObject.narrow(
poa.create_reference_with_id(toByteArray(id),
beanRepositoryIds[0]),
EJBObject.class);
}
public EJBObject getEntityEJBObject(Object id)
throws RemoteException
{
return (EJBObject)PortableRemoteObject.narrow(
poa.create_reference_with_id(toByteArray(id),
beanRepositoryIds[0]),
EJBObject.class);
}
public Collection getEntityCollection(Collection ids)
throws RemoteException
{
ArrayList list = new ArrayList(ids.size());
Iterator idEnum = ids.iterator();
while(idEnum.hasNext()) {
list.add((EJBObject)PortableRemoteObject.narrow(
poa.create_reference_with_id(toByteArray(idEnum.next()),
beanRepositoryIds[0]),
EJBObject.class));
}
return list;
}
// Implementation of the interface InvokeHandler ---------------------------
/**
* Returns an array with the CORBA repository ids of the RMI-IDL interfaces
* implemented by the container's <code>EJBObject</code>s.
*/
public String[] _all_interfaces(POA poa, byte[] objectId)
{
return beanRepositoryIds;
}
/**
* Receives IIOP requests to the the container's <code>EJBObject</code>s
* and forwards them to the container.
*/
public OutputStream _invoke(String opName,
InputStream in,
ResponseHandler handler)
{
System.err.println("EJBObject invocation: " + opName);
ClassLoader oldCl = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(container.getClassLoader());
try {
SkeletonStrategy op =
(SkeletonStrategy) beanMethodInvokerMap.get(opName);
if (op == null) {
throw new BAD_OPERATION(opName);
}
Object id;
try {
id = toObject(poaCurrent.get_object_id());
}
catch (Exception e) {
e.printStackTrace();
throw new UnknownException(e);
}
Object[] params =
op.readParams((org.omg.CORBA_2_3.portable.InputStream)in);
MethodInvocation mi = new MethodInvocation(id,
op.getMethod(),
params,
null, /* tx */
null, /* identity */
null /* credential */);
org.omg.CORBA_2_3.portable.OutputStream out;
try {
Object retVal = container.invoke(mi);
out = (org.omg.CORBA_2_3.portable.OutputStream)
handler.createReply();
if (op.isNonVoid()) {
op.writeRetval(out, retVal);
}
}
catch (Exception e) {
out = (org.omg.CORBA_2_3.portable.OutputStream)
handler.createExceptionReply();
op.writeException(out, e);
}
return out;
}
finally {
Thread.currentThread().setContextClassLoader(oldCl);
}
}
// Static methods ----------------------------------------------------------
/**
* Returns the CORBA repository id of a given the RMI-IDL interface.
*/
public static String rmiRepositoryId(Class clz)
{
return "RMI:" + clz.getName() + ":0000000000000000";
}
/**
* (Re)binds a value to a name in a given JNDI context, creating any
* non-existent intermediate contexts along the way.
*/
public static void rebind(Context ctx, String name, Object val)
throws NamingException
{
Name n = ctx.getNameParser("").parse(name);
while (n.size() > 1) {
String ctxName = n.get(0);
try {
ctx = (Context)ctx.lookup(ctxName);
}
catch (NameNotFoundException e) {
ctx = ctx.createSubcontext(ctxName);
}
n = n.getSuffix(1);
}
ctx.rebind(n.get(0), val);
}
/**
* (Re)binds an object to a name in a given CORBA naming context, creating
* any non-existent intermediate contexts along the way.
*/
public static void rebind(NamingContextExt ctx,
String strName, org.omg.CORBA.Object obj)
throws Exception
{
NameComponent[] name = ctx.to_name(strName);
NamingContext intermediateCtx = ctx;
for (int i = 0; i < name.length - 1; i++ ) {
NameComponent[] relativeName = new NameComponent[] { name[i] };
try {
intermediateCtx = NamingContextHelper.narrow(
intermediateCtx.resolve(relativeName));
}
catch (NotFound e) {
intermediateCtx = intermediateCtx.bind_new_context(relativeName);
}
}
intermediateCtx.rebind(new NameComponent[] { name[name.length - 1] },
obj);
}
/**
* Returns an array with the CORBA repository ids of all RMI-IDL interfaces
* implemented or extended by a given class or interface, sorted so that
* no derived interface appears after a base interface.
*/
public static String[] rmiInterfaces(Class clz)
{
Class[] interfs = clz.getInterfaces();
ArrayList list = new ArrayList(interfs.length);
list.add(clz);
for (int i = 0; i < interfs.length; i++) {
if (interfs[i] != Remote.class
&& RmiIdlUtil.isRMIIDLRemoteInterface(interfs[i])) {
list.add(interfs[i]);
}
}
Object[] remoteInterfs = list.toArray();
arraysort(remoteInterfs);
String[] repositoryIds = new String[remoteInterfs.length];
for (int i = 0; i < remoteInterfs.length; i++) {
repositoryIds[i] = rmiRepositoryId((Class)remoteInterfs[i]);
}
return repositoryIds;
}
/**
* Sorts an array of classes or interfaces so that no derived class or
* interface appears after a base class or interface.
*/
protected static void arraysort(Object[] a)
{
int len = a.length;
for (int i = 0; i < len - 1; i++) {
for (int j = i + 1; j < len; j++) {
if (((Class)a[i]).isAssignableFrom((Class)a[j])) {
Object tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
}
}
}
/**
* Creates a null id. The null id is the "reference data" field embedded
* into the CORBA references for session beans.
*/
protected static byte[] createNullId()
{
byte[] nullId = null;
try {
nullId = toByteArray(new Integer(0));
}
catch (Exception e) {
}
return nullId;
}
/**
* Receives an object and converts it into a byte array. Used to embed
* a JBoss oid into the "reference data" (object id) field of a CORBA
* reference.
*/
protected static byte[] toByteArray(Object obj)
throws RemoteException
{
try {
ByteArrayOutputStream os = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(obj);
oos.flush();
byte[] a = os.toByteArray();
os.close();
return a;
}
catch (IOException ioe) {
throw new ServerException("Object id serialization error", ioe);
}
}
/**
* Receives a byte array previously returned by a call to
* <code>toByteArray</code> and retrieves an object from it. Used to extract
* a JBoss oid from the "reference data" (object id) field of a CORBA
* reference.
*/
protected static Object toObject(byte[] a)
throws IOException, ClassNotFoundException
{
ByteArrayInputStream is = new ByteArrayInputStream(a);
ObjectInputStream ois = new ObjectInputStream(is);
Object obj = ois.readObject();
is.close();
return obj;
}
// Inner class for the EJBHome servant--------------------------------------
private class HomeServant
extends Servant
implements InvokeHandler {
// Implementation of the interface InvokeHandler ------------------------
/**
* Returns an array with the CORBA repository ids of the RMI-IDL
* interfaces implemented by the container's <code>EJBHome</code>.
*/
public String[] _all_interfaces(POA poa, byte[] objectId)
{
return homeRepositoryIds;
}
/**
* Receives IIOP requests to the the container's <code>EJBHome</code>
* and forwards them to the container.
*/
public OutputStream _invoke(String opName,
InputStream in,
ResponseHandler handler)
{
System.err.println("EJBHome invocation: " + opName);
ClassLoader oldCl = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(
container.getClassLoader());
try {
SkeletonStrategy op =
(SkeletonStrategy) homeMethodInvokerMap.get(opName);
if (op == null) {
throw new BAD_OPERATION(opName);
}
Object[] params =
op.readParams((org.omg.CORBA_2_3.portable.InputStream)in);
MethodInvocation mi = new MethodInvocation(null,
op.getMethod(),
params,
null, /* tx */
null, /* identity */
null /* credential*/);
org.omg.CORBA_2_3.portable.OutputStream out;
try {
Object retVal = container.invokeHome(mi);
out = (org.omg.CORBA_2_3.portable.OutputStream)
handler.createReply();
if (op.isNonVoid()) {
op.writeRetval(out, retVal);
}
}
catch (Exception e) {
out = (org.omg.CORBA_2_3.portable.OutputStream)
handler.createExceptionReply();
op.writeException(out, e);
}
return out;
}
finally {
Thread.currentThread().setContextClassLoader(oldCl);
}
}
}
}
1.1
contrib/iiop/src/main/org/jboss/ejb/plugins/iiop/server/SkeletonStrategy.java
Index: SkeletonStrategy.java
===================================================================
/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.ejb.plugins.iiop.server;
import java.lang.reflect.Method;
import java.rmi.RemoteException;
import org.omg.CORBA.portable.UnknownException;
import org.omg.CORBA_2_3.portable.InputStream;
import org.omg.CORBA_2_3.portable.OutputStream;
import org.jboss.iiop.rmi.ExceptionAnalysis;
import org.jboss.iiop.rmi.RMIIIOPViolationException;
import org.jboss.ejb.plugins.iiop.CDRStream;
import org.jboss.ejb.plugins.iiop.CDRStreamReader;
import org.jboss.ejb.plugins.iiop.CDRStreamWriter;
/**
* A <code>SkeletonStrategy</code> for a given method knows how to unmarshal
* the sequence of method parameters from a CDR input stream, how to marshal
* into a CDR output stream the return value of the method, and how to marshal
* into a CDR output stream any exception thrown by the method.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Francisco Reverbel</a>
* @version $Revision: 1.1 $
*/
public class SkeletonStrategy
{
/**
* Each <code>CDRStreamReader</code> in the array unmarshals a method
* parameter.
*/
private CDRStreamReader[] paramReaders;
/**
* A <code>Method</code> instance.
*/
private Method m;
/**
* Each <code>ExceptionWriter</code> in the array knows how to marshal
* an exception that may be thrown be the method. The array is sorted so
* that no writer for a derived exception appears after the base
* exception writer.
*/
private ExceptionWriter[] excepWriters;
/**
* A <code>CDRStreamWriter</code> that marshals the return value of the
* method.
*/
private CDRStreamWriter retvalWriter;
// Public -----------------------------------------------------------------
/*
* Constructs a <code>SkeletonStrategy</code> for a given method.
*/
public SkeletonStrategy(Method m)
{
// Keep the method
this.m = m;
// Initialize paramReaders
Class[] paramTypes = m.getParameterTypes();
int len = paramTypes.length;
paramReaders = new CDRStreamReader[len];
for (int i = 0; i < len; i++) {
paramReaders[i] = CDRStream.readerFor(paramTypes[i]);
}
// Initialize excepWriters
Class[] excepTypes = m.getExceptionTypes();
len = excepTypes.length;
int n = 0;
for (int i = 0; i < len; i++) {
if (!RemoteException.class.isAssignableFrom(excepTypes[i])) {
n++;
}
}
excepWriters = new ExceptionWriter[n];
int j = 0;
for (int i = 0; i < len; i++) {
if (!RemoteException.class.isAssignableFrom(excepTypes[i])) {
excepWriters[j++] = new ExceptionWriter(excepTypes[i]);
}
}
ExceptionWriter.arraysort(excepWriters);
// Initialize retvalWriter
retvalWriter = CDRStream.writerFor(m.getReturnType());
}
/**
* Unmarshals the sequence of method parameters from an input stream.
*
* @param in a CDR input stream
* @return an object array with the parameters.
*/
public Object[] readParams(InputStream in)
{
int len = paramReaders.length;
Object[] params = new Object[len];
for (int i = 0; i < len; i++ ) {
params[i] = paramReaders[i].read(in);
}
return params;
}
/**
* Returns this <code>SkeletonStrategy</code>'s method.
*/
public Method getMethod()
{
return m;
}
/**
* Returns true if this <code>SkeletonStrategy</code>'s method is non void.
*/
public boolean isNonVoid()
{
return (retvalWriter != null);
}
/**
* Marshals into an output stream the return value of the method.
*
* @param out a CDR output stream
* @param retVal the value to be written.
*/
public void writeRetval(OutputStream out, Object retVal)
{
retvalWriter.write(out, retVal);
}
/**
* Marshals into an output stream an exception thrown by the method.
*
* @param out a CDR output stream
* @param e the exception to be written.
*/
public void writeException(OutputStream out, Exception e)
{
int len = excepWriters.length;
for (int i = 0; i < len; i++) {
if (excepWriters[i].getExceptionClass().isInstance(e)) {
excepWriters[i].write(out, e);
return;
}
}
throw new UnknownException(e);
}
// Static inner class (private) --------------------------------------------
/**
* An <code>ExceptionWriter</code> knows how to write exceptions of a given
* class to a CDR output stream.
*/
private static class ExceptionWriter
implements CDRStreamWriter
{
/**
* The exception class.
*/
private Class clz;
/**
* The CORBA repository id of the exception class.
*/
private String reposId;
/**
* Constructs an <code>ExceptionWriter</code> for a given exception
* class.
*/
ExceptionWriter(Class clz)
{
this.clz = clz;
try {
this.reposId = ExceptionAnalysis.getExceptionAnalysis(clz)
.getExceptionRepositoryId();
}
catch (RMIIIOPViolationException e) {
throw new RuntimeException("Cannot obtain "
+ "exception repository id for "
+ clz.getName() + ":\n" + e);
}
}
/**
* Gets the exception <code>Class</code>.
*/
Class getExceptionClass()
{
return clz;
}
/**
* Writes an exception to a CDR output stream.
*/
public void write(OutputStream out, Object excep)
{
out.write_string(reposId);
out.write_value((Exception)excep, clz);
}
/**
* Sorts an <code>ExceptionWriter</code> array so that no derived
* exception strategy appears after a base exception strategy.
*/
static void arraysort(ExceptionWriter[] a)
{
int len = a.length;
for (int i = 0; i < len - 1; i++) {
for (int j = i + 1; j < len; j++) {
if (a[i].clz.isAssignableFrom(a[j].clz)) {
ExceptionWriter tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
}
}
}
} // end of inner class ExceptionWriter
}
_______________________________________________
Jboss-development mailing list
[EMAIL PROTECTED]
http://lists.sourceforge.net/lists/listinfo/jboss-development