FileDocCategorySizeDatePackage
BeanCorbaServant.javaAPI DocJBoss 4.2.19273Fri Jul 13 20:53:50 BST 2007org.jboss.ejb3.iiop

BeanCorbaServant.java

/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2006, 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.ejb3.iiop;

import java.lang.reflect.Method;
import java.security.Principal;
import java.util.HashMap;

import javax.transaction.Transaction;
import javax.transaction.TransactionManager;

import org.jboss.ejb3.Container;
import org.jboss.ejb3.SessionContainer;
import org.jboss.ejb3.stateful.StatefulContainer;
import org.jboss.ejb3.stateless.StatelessContainer;
import org.jboss.iiop.CorbaORB;
import org.jboss.iiop.csiv2.SASCurrent;
import org.jboss.iiop.rmi.AttributeAnalysis;
import org.jboss.iiop.rmi.InterfaceAnalysis;
import org.jboss.iiop.rmi.OperationAnalysis;
import org.jboss.iiop.rmi.RmiIdlUtil;
import org.jboss.iiop.rmi.marshal.strategy.SkeletonStrategy;
import org.jboss.invocation.iiop.ReferenceData;
import org.jboss.logging.Logger;
import org.jboss.security.SecurityAssociation;
import org.jboss.security.SimplePrincipal;
import org.jboss.tm.TransactionManagerLocator;
import org.jboss.tm.iiop.TxServerInterceptor;
import org.omg.CORBA.BAD_OPERATION;
import org.omg.CORBA.InterfaceDef;
import org.omg.CORBA.SystemException;
import org.omg.CORBA.ORBPackage.InvalidName;
import org.omg.CORBA.portable.InputStream;
import org.omg.CORBA.portable.InvokeHandler;
import org.omg.CORBA.portable.OutputStream;
import org.omg.CORBA.portable.ResponseHandler;
import org.omg.PortableServer.Current;
import org.omg.PortableServer.POA;
import org.omg.PortableServer.Servant;

/**
 * Comment
 *
 * @author <a href="mailto:carlo.dewolf@jboss.com">Carlo de Wolf</a>
 * @version $Revision: 60233 $
 */
public class BeanCorbaServant extends Servant
   implements InvokeHandler
{
   private static final Logger log = Logger.getLogger(BeanCorbaServant.class);

   private final IORFactory factory;
   private final Current poaCurrent;
   private final Container container;
   private final InterfaceDef interfaceDef;
   private final String repositoryIds[];
   private SASCurrent sasCurrent;

   private HashMap<String, SkeletonStrategy> methodMap;
   
   protected BeanCorbaServant(IORFactory factory, Current poaCurrent, Container container, InterfaceDef interfaceDef, InterfaceAnalysis interfaceAnalysis)
   {
      assert factory != null;
      assert poaCurrent != null;
      assert container != null;
      assert container instanceof SessionContainer; // see invoke
      assert interfaceDef != null;
      assert interfaceAnalysis != null;
      
      this.factory = factory;
      this.poaCurrent = poaCurrent;
      this.container = container;
      this.interfaceDef = interfaceDef;
      this.repositoryIds = interfaceAnalysis.getAllTypeIds();
      
      try
      {
         this.sasCurrent = (SASCurrent) CorbaORB.getInstance().resolve_initial_references("SASCurrent");
      }
      catch (InvalidName e)
      {
         log.warn("Can't find SASCurrent");
         this.sasCurrent = null;
      }
      
      this.methodMap = new HashMap<String, SkeletonStrategy>();
      AttributeAnalysis[] attrs = interfaceAnalysis.getAttributes();
      for (int i = 0; i < attrs.length; i++) {
         OperationAnalysis op = attrs[i].getAccessorAnalysis();

         log.debug("    " + op.getJavaName() + ": " + op.getIDLName());
         methodMap.put(op.getIDLName(),
                           new SkeletonStrategy(op.getMethod()));
         op = attrs[i].getMutatorAnalysis();
         if (op != null) {
            log.debug("    " + op.getJavaName() + ": " + op.getIDLName());
            methodMap.put(op.getIDLName(),
                              new SkeletonStrategy(op.getMethod()));
         }
      }

      OperationAnalysis[] ops = interfaceAnalysis.getOperations();
      for (int i = 0; i < ops.length; i++) {
         log.debug("    " + ops[i].getJavaName() + ": " + ops[i].getIDLName());
         methodMap.put(ops[i].getIDLName(),
                           new SkeletonStrategy(ops[i].getMethod()));
      }
   }
   
   @Override
   public String[] _all_interfaces(POA poa, byte[] objectId)
   {
      return (String[]) repositoryIds.clone();
   }

   /**
    * Returns an IR object describing the bean's remote interface.
    */
   @Override
   public org.omg.CORBA.Object _get_interface_def()
   {
      if (interfaceDef != null)
         return interfaceDef;
      else
         return super._get_interface_def();
   }
   
   public OutputStream _invoke(String opName, InputStream in, ResponseHandler handler) throws SystemException
   {
      log.trace("invoke: " + opName);
      
      SkeletonStrategy op = (SkeletonStrategy) methodMap.get(opName);
      if (op == null)
      {
         log.debug("Unable to find opname '" + opName + "' valid operations:" + methodMap.keySet());
         throw new BAD_OPERATION(opName);
      }

      org.omg.CORBA_2_3.portable.OutputStream out;
      try
      {
         Object id = ReferenceData.extractObjectId(poaCurrent.get_object_id());
         log.trace("id = " + id);
         
         Transaction tx = TxServerInterceptor.getCurrentTransaction();
         log.trace("tx = " + tx);
         
         if(sasCurrent != null)
         {
            byte username[] = sasCurrent.get_incoming_username();
            byte credentials[] = sasCurrent.get_incoming_password();
            byte principalName[] = sasCurrent.get_incoming_principal_name();
            
            if(username != null && username.length > 0)
            {
               String name = new String(username, "UTF-8");
               int domainIndex = name.lastIndexOf("@");
               if(domainIndex > 0)
                  name = name.substring(0, domainIndex);
               log.debug("username = " + name);
               Principal principal = new SimplePrincipal(name);
               SecurityAssociation.setPrincipal(principal);
            }
            
            if(credentials != null && credentials.length > 0)
            {
               SecurityAssociation.setCredential(new String(credentials, "UTF-8").toCharArray());
            }
            
            if(principalName != null && principalName.length > 0)
               log.warn("principalName = " + new String(principalName, "UTF-8")); // FIXME: implement principalName support
         }
         
         Object args[] = op.readParams((org.omg.CORBA_2_3.portable.InputStream) in);
         
         Object retVal = invoke(tx, id, op.getMethod(), args);
         
         out = (org.omg.CORBA_2_3.portable.OutputStream) handler.createReply();
         if(op.isNonVoid())
            op.writeRetval(out, retVal);
      }
      catch(Throwable t)
      {
         // TODO: check log level before stacktrace?
         t.printStackTrace();
         if(t instanceof Exception)
         {
            Exception e = (Exception) t;
            RmiIdlUtil.rethrowIfCorbaSystemException(e);
            out = (org.omg.CORBA_2_3.portable.OutputStream) handler.createExceptionReply();
            op.writeException(out, e);
         }
         else
            throw new RuntimeException("NYI");
      }
      return out;
   }

   private TransactionManager getTransactionManager()
   {
      //return TxUtil.getTransactionManager();
      return TransactionManagerLocator.getInstance().locate();
   }
   
   private Object invoke(Object id, Method method, Object args[]) throws Throwable
   {
      // TODO: Support other containers beside Stateless and Stateful?
      return ((SessionContainer) container).invoke(factory, id, method, args, null);
   }
   
   private Object invoke(Transaction tx, Object id, Method method, Object args[]) throws Throwable
   {
      if(tx == null)
         return invoke(id, method, args);
      
      // FIXME: refactor TxServerInterceptor so that it pushed the tpc into the invocation like ClientTxPropegationInterceptor
      // this would require the localInvoke to be also refactored, so that it uses invocation instead of localInvoke.
      TransactionManager tm = getTransactionManager();
      
      // see TxPropagationInterceptor
      if(tm.getTransaction() != null)
         throw new RuntimeException("cannot import a transaction context when a transaction is already associated with the thread");
      tm.resume(tx);
      try
      {
         return invoke(id, method, args);
      }
      finally
      {
         tm.suspend();
      }
   }
}