I am using JBoss3.0.0RC2 and have a complex process that creates new orders 
as they are submitted from the web.  On order submission, a credit card is 
authorized via SSL.  If the credit card is declined then the order is rolled 
back, however the credit card information must stay because we must have a 
log of all calls to the credit card interface.

To accomplish this, I have two methods set to RequiresNew.  One is the method 
that creates the credit card bean and the other is the one that creates the 
credit card interface log entry bean.  All other methods have transactioning 
set to Required.

I have had success in various tests done with simple Entity beans and a 
Session bean with the RequiresNew method(s).  I get an odd error when I use 
the more complex credit card bean:

java.rmi.ServerException: removing bean lock and it has tx set!


I have narrowed the issue to a very specific call to the following method:

  public CustomerCreditCardLocal getCustomerCreditCard(
      Integer                          customerNo,
      Integer                          ccTypeCd,
      String                           ccNum,
      java.util.Date                   ccExpDate,
      String                           nameOnCard ) {
    try {
      CustomerCreditCardLocalHome creditCardHome = 
(CustomerCreditCardLocalHome)getInitialContext().lookup("local/"+CustomerCreditCard.BEAN_NAME)
 
;
      CustomerCreditCardLocal creditCard = null ;
      try {
        creditCard = creditCardHome.findByCustomerCC(customerNo,
                                                     ccNum,
                                                     ccExpDate) ;
      } catch (FinderException fe) {
      } //end try
      if (creditCard == null) {
        Integer customerCCNo = 
((MoneyHandlerLocal)sessionContext.getEJBLocalObject()).createCustomerCreditCard(customerNo,
                                                                              
                                  ccTypeCd,
                                                                              
                                  ccNum,
                                                                              
                                  ccExpDate,
                                                                              
                                  nameOnCard) ;
        try {
          creditCardHome = 
(CustomerCreditCardLocalHome)getInitialContext().lookup("local/"+CustomerCreditCard.BEAN_NAME)
 
;
          creditCard = creditCardHome.findByPrimaryKey(customerCCNo) ;
        } catch (FinderException fe) {
        } //end try
      } //end if
      System.out.println("customerCCNo: 
"+creditCard.getCustomerCCNo().toString());
      return creditCard ;
    } catch (NamingException ne) {
      throw new EJBException(ne) ;
    } catch (CreateException ce) {
      throw new EJBException(ce) ;
    } //end try
  } //end getCustomerCreditCard()

The createCustomerCreditCard() method is set to RequiresNew and simply calls 
create on CustomerCreditCardLocalHome and returns the PK.

The error occurs on the System.out.println when I try to call 
getCustomerCCNo() on the newly created bean.  What is interesting is that 
there is no record created in the database.  It is also odd that if the 
credit card entry already exists in the DB then everything works.  Even the 
credit card log creation that uses the same approach to make sure it is in 
it's own transaction happens without a hitch.

The only thing that is different between the credit card bean and all the 
other beans that have been successful using RequiresNew is that the passed 
credit card number is being encrypted.  I can't understand how that would 
make a difference.  Calling the bean create method from a remote client works 
fine (thats how I tested the code for when the record already exists).  Here 
is most of the bean definition (package identification removed for client 
privacy reasons):

import java.io.*;
import java.sql.*;
import java.util.*;
import java.security.Key;
import javax.ejb.*;
import javax.naming.*;
import javax.sql.*;
import com.atomicpc.db.*;
import com.atomicpc.util.*;

public abstract class CustomerCreditCardBean implements EntityBean {
  public static final String           SEQUENCE_NAME = "customer_cc_no_seq" ;

  private static Key                   publicKey = null ;


  //CREATE METHODS
  public Integer ejbCreate(
      Integer                          customerNo,
      Integer                          typeCd,
      String                           unencryptedCardNo,
      java.util.Date                   expirationDt,
      String                           nameOnCard )
      throws CreateException {
    setCustomerCCNo(Global.getNextKey(SEQUENCE_NAME));
    setCustomerNo(customerNo);
    setTypeCd(typeCd);
    setUnencryptedCardNo(unencryptedCardNo);
    setExpirationDt(expirationDt);
    setNameOnCard(nameOnCard);
    setCreatedDt(new java.util.Date());
    setLockedFl(Boolean.FALSE);
    setInactiveFl(Boolean.FALSE);
    return null ;
  } //end ejbCreate()

  public void ejbPostCreate(
      Integer                          customerNo,
      Integer                          typeCd,
      String                           unencryptedCardNo,
      java.util.Date                   expirationDt,
      String                           nameOnCard ) {
  } //end ejbPostCreate()


  //CMP FIELDS
  public abstract Integer getCustomerCCNo() ;
  public abstract void setCustomerCCNo(
      Integer                          customerCCNo ) ;

  public abstract Integer getCustomerNo() ;
  public abstract void setCustomerNo(
      Integer                          customerNo ) ;

  public abstract Integer getTypeCd() ;
  public abstract void setTypeCd(
      Integer                          typeCd ) ;

  public abstract String getCardNo() ;
  public abstract void setCardNo(
      String                           cardNo ) ;

  public abstract java.util.Date getExpirationDt() ;
  public abstract void setExpirationDt(
      java.util.Date                   expirationDt ) ;

  public abstract String getNameOnCard() ;
  public abstract void setNameOnCard(
      String                           nameOnCard ) ;

  public abstract java.util.Date getCreatedDt() ;
  public abstract void setCreatedDt(
      java.util.Date                   createdDt ) ;

  public abstract Boolean getLockedFl() ;
  public abstract void setLockedFl(
      Boolean                          lockedFl ) ;

  public abstract Boolean getInactiveFl() ;
  public abstract void setInactiveFl(
      Boolean                          inactiveFl ) ;


  //CALLBACK METHODS
  public void setEntityContext(
      EntityContext                    entityContext ) {} ;
  public void unsetEntityContext() {} ;
  public void ejbLoad() {} ;
  public void ejbStore() {} ;
  public void ejbActivate() {} ;
  public void ejbPassivate() {} ;
  public void ejbRemove() {} ;

  public void setUnencryptedCardNo(
      String                           unencryptedCardNo ) {
    setCardNo(getEncryptedCardNo(unencryptedCardNo));
  } //end setUnencryptedCardNo()

  public String getEncryptedCardNo(
      String                           unencryptedCardNo ) {
    if (unencryptedCardNo != null) {
      try {
        return new String(Security.encryptRSA(getPublicKey(),
                                              unencryptedCardNo.getBytes()));
      } catch (Exception e) {
        throw new EJBException(e) ;
      } //end try
    } //end if
    return null ;
  } //end setUnencryptedCardNo()

  public Integer ejbFindByCustomerCC(
      Integer                          customerNo,
      String                           cardNo,
      java.util.Date                   expirationDt ) {
    Integer customerCCNo = null ;
    if (customerNo != null
       && cardNo != null
       && expirationDt != null) {
      String encryptedCardNo = getEncryptedCardNo(cardNo) ;
      String sqlText = "SELECT customer_cc_no "
                     + "  FROM customer_cc "
                     + " WHERE customer_no   = ? "
                     + "   AND card_no       = ? "
                     + "   AND expiration_dt = ? "
                     + "   AND NOT inactive_fl " ;
      Connection connection = null ;
      PreparedStatement s = null ;
      ResultSet rs = null ;
      try {
        DataSource dataSource = (DataSource)(new 
InitialContext()).lookup(Global.DATA_SOURCE_NAME) ;
        connection = dataSource.getConnection() ;
        s = connection.prepareStatement(sqlText);
        s.setInt(1,customerNo.intValue());
        s.setString(2,encryptedCardNo);
        s.setDate(3,new java.sql.Date(expirationDt.getTime()));
        rs = s.executeQuery() ;
        if (rs.next()) {
          customerCCNo = new Integer(rs.getInt(1)) ;
        } //end while
        rs.close();
        s.close();
        connection.close();
      } catch (Exception e) {
        System.out.println(sqlText);
        DBUtil.close(rs);
        DBUtil.close(s);
        DBUtil.close(connection);
        throw new EJBException(e);
      } //end try
    } //end if
    return customerCCNo ;
  } //end ejbFindByCustomerCC()

  private static synchronized Key getPublicKey() {
    if (publicKey == null) {
      try {
        publicKey = Security.loadKey(Global.CREDIT_CARD_PUBLIC_KEY_FILE) ;
      } catch (IOException ioe) {
        throw new EJBException(ioe);
      } //end try
    } //end if
    return publicKey ;
  } //end getPublicKey()

} //end CustomerCreditCardBean

Any hints on what I should try next are welcome.


_______________________________________________________________

Don't miss the 2002 Sprint PCS Application Developer's Conference
August 25-28 in Las Vegas -- http://devcon.sprintpcs.com/adp/index.cfm

_______________________________________________
JBoss-user mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/jboss-user

Reply via email to