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

Reply via email to