[jboss-cvs] JBossAS SVN: r104828 - in projects/ejb-book/trunk/chxx-poker/src: main/java/org/jboss/ejb3/examples/chxx/transactions/entity and 3 other directories.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Sat May 15 16:46:25 EDT 2010
Author: ALRubinger
Date: 2010-05-15 16:46:25 -0400 (Sat, 15 May 2010)
New Revision: 104828
Added:
projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/api/PokerGameLocalBusiness.java
projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/impl/PokerGameBean.java
projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/impl/PokerServiceConstants.java
Removed:
projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/api/PokerGame.java
Modified:
projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/api/BankLocalBusiness.java
projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/entity/User.java
projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/impl/BankBean.java
projects/ejb-book/trunk/chxx-poker/src/test/java/org/jboss/ejb3/examples/chxx/transactions/TransactionalPokerGameIntegrationTest.java
projects/ejb-book/trunk/chxx-poker/src/test/java/org/jboss/ejb3/examples/chxx/transactions/ejb/DbInitializerBean.java
projects/ejb-book/trunk/chxx-poker/src/test/java/org/jboss/ejb3/examples/chxx/transactions/ejb/DbInitializerLocalBusiness.java
projects/ejb-book/trunk/chxx-poker/src/test/java/org/jboss/ejb3/examples/chxx/transactions/ejb/DbQueryBean.java
projects/ejb-book/trunk/chxx-poker/src/test/java/org/jboss/ejb3/examples/chxx/transactions/ejb/TxWrappingBean.java
Log:
[EJBBOOK-23] Flesh out more Tx examples, now all passing
Modified: projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/api/BankLocalBusiness.java
===================================================================
--- projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/api/BankLocalBusiness.java 2010-05-15 19:35:12 UTC (rev 104827)
+++ projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/api/BankLocalBusiness.java 2010-05-15 20:46:25 UTC (rev 104828)
@@ -87,4 +87,17 @@
*/
void transfer(long accountIdFrom, long accountIdTo, BigDecimal amount) throws IllegalArgumentException,
InsufficientBalanceException;
+
+ /**
+ * Transfers the specified amount from one account to another
+ * @param accountFrom The account from which we'll withdraw
+ * @param accountTo The account to which we'll deposit
+ * @param amount The amount to be transferred
+ * @throws IllegalArgumentException If the amount is not specified, the amount is
+ * less that 0, or either account ID is invalid
+ * @throws InsufficientBalanceException If the amount is greater than the current
+ * balance of the "from" account
+ */
+ void transfer(Account accountFrom, Account accountTo, BigDecimal amount) throws IllegalArgumentException,
+ InsufficientBalanceException;
}
Deleted: projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/api/PokerGame.java
===================================================================
--- projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/api/PokerGame.java 2010-05-15 19:35:12 UTC (rev 104827)
+++ projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/api/PokerGame.java 2010-05-15 20:46:25 UTC (rev 104828)
@@ -1,44 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2010, 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.examples.chxx.transactions.api;
-
-import java.math.BigDecimal;
-
-import org.jboss.ejb3.examples.chxx.transactions.entity.User;
-
-/**
- * Contract of a service capable of simulating
- * a single game of poker. The actual gameplay is not modeled,
- * only the inputs and outputs of a single trial.
- *
- * @author <a href="mailto:andrew.rubinger at jboss.org">ALR</a>
- * @version $Revision: $
- */
-public interface PokerGame
-{
- //-------------------------------------------------------------------------------------||
- // Contracts --------------------------------------------------------------------------||
- //-------------------------------------------------------------------------------------||
-
- boolean bet(User user, BigDecimal amount);
-
-}
Copied: projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/api/PokerGameLocalBusiness.java (from rev 104691, projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/api/PokerGame.java)
===================================================================
--- projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/api/PokerGameLocalBusiness.java (rev 0)
+++ projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/api/PokerGameLocalBusiness.java 2010-05-15 20:46:25 UTC (rev 104828)
@@ -0,0 +1,67 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2010, 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.examples.chxx.transactions.api;
+
+import java.math.BigDecimal;
+
+import org.jboss.ejb3.examples.chxx.transactions.entity.User;
+
+/**
+ * Contract of a service capable of simulating
+ * a single game of poker. The actual gameplay is not modeled,
+ * only the inputs and outputs of a single trial.
+ *
+ * @author <a href="mailto:andrew.rubinger at jboss.org">ALR</a>
+ * @version $Revision: $
+ */
+public interface PokerGameLocalBusiness
+{
+ //-------------------------------------------------------------------------------------||
+ // Constants --------------------------------------------------------------------------||
+ //-------------------------------------------------------------------------------------||
+
+ /**
+ * Name to which we'll bind in JNDI
+ */
+ String JNDI_NAME = "PokerGameLocal";
+
+ //-------------------------------------------------------------------------------------||
+ // Contracts --------------------------------------------------------------------------||
+ //-------------------------------------------------------------------------------------||
+
+ /**
+ * Places a single bet, returning if the bet won or lost. If the result
+ * is a win, the amount specified will be transferred from the Poker Service
+ * account to {@link User#getAccount()}, else it will be deducted from the user account
+ * and placed into the Poker Service account.
+ *
+ * @return Whether the bet won or lost
+ * @param userId The ID of the user placing the bet
+ * @param amount The amount of the bet
+ * @throws IllegalArgumentException If either the user of the amount is not specified or
+ * the amount is a negative number.
+ * @throws InsufficientBalanceException If the user does not have enough in his/her account
+ * to cover the bet
+ */
+ boolean bet(long userId, BigDecimal amount) throws IllegalArgumentException, InsufficientBalanceException;
+
+}
Modified: projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/entity/User.java
===================================================================
--- projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/entity/User.java 2010-05-15 19:35:12 UTC (rev 104827)
+++ projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/entity/User.java 2010-05-15 20:46:25 UTC (rev 104828)
@@ -45,11 +45,6 @@
private String name;
/**
- * Email address of the user
- */
- private String email;
-
- /**
* The user's poker account
*/
@OneToOne(cascade = CascadeType.PERSIST)
@@ -76,22 +71,6 @@
}
/**
- * @return the email
- */
- public String getEmail()
- {
- return email;
- }
-
- /**
- * @param email the email to set
- */
- public void setEmail(final String email)
- {
- this.email = email;
- }
-
- /**
* @return the account
*/
public Account getAccount()
@@ -118,7 +97,7 @@
@Override
public String toString()
{
- return "User [id=" + this.getId() + ", email=" + email + ", name=" + name + ", pokerAccount=" + account + "]";
+ return "User [id=" + this.getId() + ", name=" + name + ", pokerAccount=" + account + "]";
}
}
Modified: projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/impl/BankBean.java
===================================================================
--- projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/impl/BankBean.java 2010-05-15 19:35:12 UTC (rev 104827)
+++ projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/impl/BankBean.java 2010-05-15 20:46:25 UTC (rev 104828)
@@ -39,10 +39,10 @@
/**
* The bank with which users and the Poker provider
- * may interact with underlying accounts. For instance users
- * may wish to make cash deposits into their personal account,
- * or the Poker provider may transfer money from the user's account
- * to the poker account when the user places a bet.
+ * may interact with underlying accounts. For instance
+ * winning or losing a bet will result in an account
+ * transfer between the user account and te poker
+ * system account.
*
* @author <a href="mailto:andrew.rubinger at jboss.org">ALR</a>
* @version $Revision: $
@@ -106,8 +106,14 @@
// Get the account
final Account account = this.getAccount(accountId);
+ // We don't expose this account object to callers at all; its changes
+ // elsewhere in the (optional) Tx should not be synchronized with the DB
+ // in case of a write
+ em.detach(account);
+
// Return the current balance
return account.getBalance();
+
}
/**
@@ -124,6 +130,31 @@
final Account accountFrom = this.getAccount(accountIdFrom);
final Account accountTo = this.getAccount(accountIdTo);
+ // Delegate
+ this.transfer(accountFrom, accountTo, amount);
+
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see org.jboss.ejb3.examples.chxx.transactions.api.BankLocalBusiness#transfer(org.jboss.ejb3.examples.chxx.transactions.entity.Account, org.jboss.ejb3.examples.chxx.transactions.entity.Account, java.math.BigDecimal)
+ */
+ @Override
+ @TransactionAttribute(TransactionAttributeType.REQUIRED)
+ // Default Tx Attribute; create a new Tx if not present, else use the existing
+ public void transfer(final Account accountFrom, final Account accountTo, final BigDecimal amount)
+ throws IllegalArgumentException, InsufficientBalanceException
+ {
+ // Precondition checks
+ if (accountFrom == null)
+ {
+ throw new IllegalArgumentException("accountFrom must be specified");
+ }
+ if (accountTo == null)
+ {
+ throw new IllegalArgumentException("accountTo must be specified");
+ }
+
// Withdraw (which will throw InsufficientBalance if that's the case)
accountFrom.withdraw(amount);
Added: projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/impl/PokerGameBean.java
===================================================================
--- projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/impl/PokerGameBean.java (rev 0)
+++ projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/impl/PokerGameBean.java 2010-05-15 20:46:25 UTC (rev 104828)
@@ -0,0 +1,141 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2010, 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.examples.chxx.transactions.impl;
+
+import java.math.BigDecimal;
+
+import javax.ejb.EJB;
+import javax.ejb.Local;
+import javax.ejb.Stateless;
+import javax.ejb.TransactionAttribute;
+import javax.ejb.TransactionAttributeType;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+
+import org.jboss.ejb3.annotation.LocalBinding;
+import org.jboss.ejb3.examples.chxx.transactions.api.BankLocalBusiness;
+import org.jboss.ejb3.examples.chxx.transactions.api.InsufficientBalanceException;
+import org.jboss.ejb3.examples.chxx.transactions.api.PokerGameLocalBusiness;
+import org.jboss.ejb3.examples.chxx.transactions.entity.Account;
+import org.jboss.ejb3.examples.chxx.transactions.entity.User;
+
+/**
+ * Implementation of a service capable of placing single
+ * bets upon a poker game. Though the gameplay itself is not
+ * modeled, its inputs and outputs are done transactionally.
+ * Each game is to take place in its own Tx, suspending
+ * an existing Tx if one is in play. This is to ensure
+ * that the output of each game is committed (you win or lose)
+ * regardless of if an error occurrs later within the caller's Tx.
+ * Once your money's on the table, there's no going back! :)
+ *
+ * @author <a href="mailto:andrew.rubinger at jboss.org">ALR</a>
+ * @version $Revision: $
+ */
+ at Stateless
+ at Local(PokerGameLocalBusiness.class)
+ at LocalBinding(jndiBinding = PokerGameLocalBusiness.JNDI_NAME)
+ at TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
+// Each game must be in a new Tx, suspending the existing enclosing Tx if necessary;
+// At the class-level, this annotation now applied to all methods
+public class PokerGameBean implements PokerGameLocalBusiness
+{
+
+ //-------------------------------------------------------------------------------------||
+ // Class Members ----------------------------------------------------------------------||
+ //-------------------------------------------------------------------------------------||
+
+ /**
+ * Zero value used for comparison
+ */
+ private static final BigDecimal ZERO = new BigDecimal(0);
+
+ //-------------------------------------------------------------------------------------||
+ // Instance Members -------------------------------------------------------------------||
+ //-------------------------------------------------------------------------------------||
+
+ /**
+ * Hook to JPA
+ */
+ @PersistenceContext
+ private EntityManager em;
+
+ /**
+ * The bank service which will handle account transfers
+ * during win/lose
+ */
+ @EJB
+ private BankLocalBusiness bank;
+
+ //-------------------------------------------------------------------------------------||
+ // Required Implementations -----------------------------------------------------------||
+ //-------------------------------------------------------------------------------------||
+ /**
+ * @see org.jboss.ejb3.examples.chxx.transactions.api.PokerGameLocalBusiness#bet(long, java.math.BigDecimal)
+ */
+ @Override
+ public boolean bet(final long userId, final BigDecimal amount) throws IllegalArgumentException,
+ InsufficientBalanceException
+ {
+ // Precondition checks
+ if (userId < 0)
+ {
+ throw new IllegalArgumentException("userId must be valid (>0)");
+ }
+ if (amount == null)
+ {
+ throw new IllegalArgumentException("amount must be specified");
+ }
+ if (amount.compareTo(ZERO) < 0)
+ {
+ throw new IllegalArgumentException("amount must be greater than 0");
+ }
+
+ // Check the balance of the user account
+ final Account userAccount = em.find(User.class, new Long(userId)).getAccount();
+ final BigDecimal currentBalanceUserAccount = userAccount.getBalance();
+ if (amount.compareTo(currentBalanceUserAccount) > 0)
+ {
+ throw new InsufficientBalanceException("Cannot place bet of " + amount + " when the user account has only "
+ + currentBalanceUserAccount);
+ }
+
+ // Fake the game logic and just determine if the user wins
+ final boolean win = Math.random() > 0.5;
+
+ // Get the Poker Service account (assume we always have enough to back our bet, these are just tests :))
+ final Account pokerServiceAccount = em.find(Account.class, PokerServiceConstants.ACCOUNT_POKERGAME_ID);
+
+ // Transfer the money based upon the outcome
+ if (win)
+ {
+ bank.transfer(pokerServiceAccount, userAccount, amount);
+ }
+ else
+ {
+ bank.transfer(userAccount, pokerServiceAccount, amount);
+ }
+
+ // Return the outcome
+ return win;
+ }
+}
Added: projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/impl/PokerServiceConstants.java
===================================================================
--- projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/impl/PokerServiceConstants.java (rev 0)
+++ projects/ejb-book/trunk/chxx-poker/src/main/java/org/jboss/ejb3/examples/chxx/transactions/impl/PokerServiceConstants.java 2010-05-15 20:46:25 UTC (rev 104828)
@@ -0,0 +1,46 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2010, 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.examples.chxx.transactions.impl;
+
+import java.math.BigDecimal;
+
+/**
+ * Constants used by the implementation of the
+ * {@link PokerGameBean}
+ *
+ * @author <a href="mailto:andrew.rubinger at jboss.org">ALR</a>
+ * @version $Revision: $
+ */
+public interface PokerServiceConstants
+{
+ //-------------------------------------------------------------------------------------||
+ // Constants --------------------------------------------------------------------------||
+ //-------------------------------------------------------------------------------------||
+
+ long USER_POKERGAME_ID = 1L;
+
+ String USER_POKERGAME_NAME = "The Poker Game System";
+
+ long ACCOUNT_POKERGAME_ID = 1L;
+
+ BigDecimal INITIAL_ACCOUNT_BALANCE_POKERGAME = new BigDecimal(10000);
+}
Modified: projects/ejb-book/trunk/chxx-poker/src/test/java/org/jboss/ejb3/examples/chxx/transactions/TransactionalPokerGameIntegrationTest.java
===================================================================
--- projects/ejb-book/trunk/chxx-poker/src/test/java/org/jboss/ejb3/examples/chxx/transactions/TransactionalPokerGameIntegrationTest.java 2010-05-15 19:35:12 UTC (rev 104827)
+++ projects/ejb-book/trunk/chxx-poker/src/test/java/org/jboss/ejb3/examples/chxx/transactions/TransactionalPokerGameIntegrationTest.java 2010-05-15 20:46:25 UTC (rev 104828)
@@ -36,6 +36,7 @@
import org.jboss.arquillian.api.RunModeType;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.ejb3.examples.chxx.transactions.api.BankLocalBusiness;
+import org.jboss.ejb3.examples.chxx.transactions.api.PokerGameLocalBusiness;
import org.jboss.ejb3.examples.chxx.transactions.ejb.DbInitializerBean;
import org.jboss.ejb3.examples.chxx.transactions.ejb.DbInitializerLocalBusiness;
import org.jboss.ejb3.examples.chxx.transactions.ejb.DbQueryLocalBusiness;
@@ -45,6 +46,7 @@
import org.jboss.ejb3.examples.chxx.transactions.entity.Account;
import org.jboss.ejb3.examples.chxx.transactions.entity.User;
import org.jboss.ejb3.examples.chxx.transactions.impl.BankBean;
+import org.jboss.ejb3.examples.chxx.transactions.impl.PokerServiceConstants;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.After;
@@ -54,7 +56,9 @@
import org.junit.runner.RunWith;
/**
- * Testing dev only
+ * Test cases to ensure that the Poker Game
+ * is respecting transactional boundaries at the appropriate
+ * granularity.
*
* @author <a href="mailto:andrew.rubinger at jboss.org">ALR</a>
* @version $Revision: $
@@ -75,7 +79,9 @@
/**
* Naming Context
+ * @deprecated Remove when Arquillian will inject the EJB proxies
*/
+ @Deprecated
private static Context jndiContext;
/**
@@ -120,6 +126,12 @@
// TODO: Support Injection of @EJB here when Arquillian for Embedded JBossAS will support it
private BankLocalBusiness bank;
+ /**
+ * Poker Game EJB Proxy
+ */
+ // TODO: Support Injection of @EJB here when Arquillian for Embedded JBossAS will support it
+ private PokerGameLocalBusiness pokerGame;
+
//-------------------------------------------------------------------------------------||
// Lifecycle --------------------------------------------------------------------------||
//-------------------------------------------------------------------------------------||
@@ -143,15 +155,11 @@
public void injectEjbs() throws Exception
{
// Fake injection by doing manual lookups for the time being
- Object obj = jndiContext.lookup(DbInitializerLocalBusiness.JNDI_NAME);
- log.info(obj.getClass().getClassLoader().toString());
- log.info(DbInitializerLocalBusiness.class.getClassLoader().toString());
- log.info((obj instanceof DbInitializerLocalBusiness) + "");
-
dbInitializer = (DbInitializerLocalBusiness) jndiContext.lookup(DbInitializerLocalBusiness.JNDI_NAME);
txWrapper = (TxWrappingLocalBusiness) jndiContext.lookup(TxWrappingLocalBusiness.JNDI_NAME);
db = (DbQueryLocalBusiness) jndiContext.lookup(DbQueryLocalBusiness.JNDI_NAME);
bank = (BankLocalBusiness) jndiContext.lookup(BankLocalBusiness.JNDI_NAME);
+ pokerGame = (PokerGameLocalBusiness) jndiContext.lookup(PokerGameLocalBusiness.JNDI_NAME);
}
/**
@@ -166,13 +174,9 @@
}
//-------------------------------------------------------------------------------------||
- // Required Implementations -----------------------------------------------------------||
+ // Tests ------------------------------------------------------------------------------||
//-------------------------------------------------------------------------------------||
- //-------------------------------------------------------------------------------------||
- // Functional Methods -----------------------------------------------------------------||
- //-------------------------------------------------------------------------------------||
-
/**
* Ensures that Transfers between accounts obey the ACID properties of Transactions
*/
@@ -181,19 +185,22 @@
{
// Init
- final long alrubingerAccountId = DbInitializerBean.ACCOUNT_ALRUBINGERL_ID;
- final long pokerAccountId = DbInitializerBean.ACCOUNT_POKERGAME_ID;
+ final long alrubingerAccountId = DbInitializerBean.ACCOUNT_ALRUBINGER_ID;
+ final long pokerAccountId = PokerServiceConstants.ACCOUNT_POKERGAME_ID;
- // Ensure there's $500 in the ALR account, and $0 in the poker account
- this.executeInTx(new CheckBalanceOfAccountTask(alrubingerAccountId, new BigDecimal(500)),
- new CheckBalanceOfAccountTask(pokerAccountId, new BigDecimal(0)));
+ // Ensure there's the expected amounts in both the ALR and Poker accounts
+ final BigDecimal expectedinitialALR = DbInitializerLocalBusiness.INITIAL_ACCOUNT_BALANCE_ALR;
+ final BigDecimal expectedinitialPoker = PokerServiceConstants.INITIAL_ACCOUNT_BALANCE_POKERGAME;
+ this.executeInTx(new CheckBalanceOfAccountTask(alrubingerAccountId, expectedinitialALR),
+ new CheckBalanceOfAccountTask(pokerAccountId, expectedinitialPoker));
- // Transfer $100
- bank.transfer(alrubingerAccountId, pokerAccountId, new BigDecimal(100));
+ // Transfer $100 from ALR to Poker
+ final BigDecimal oneHundred = new BigDecimal(100);
+ bank.transfer(alrubingerAccountId, pokerAccountId, oneHundred);
- // Ensure there's $400 in the ALR account, and 100 in the poker account
- this.executeInTx(new CheckBalanceOfAccountTask(alrubingerAccountId, new BigDecimal(400)),
- new CheckBalanceOfAccountTask(pokerAccountId, new BigDecimal(100)));
+ // Ensure there's $100 less in the ALR account, and $100 more in the poker account
+ this.executeInTx(new CheckBalanceOfAccountTask(alrubingerAccountId, expectedinitialALR.subtract(oneHundred)),
+ new CheckBalanceOfAccountTask(pokerAccountId, expectedinitialPoker.add(oneHundred)));
// Now make a transfer, check it succeeded within the context of a Transaction, then
// intentionally throw an exception. The Tx should complete as rolled back,
@@ -204,16 +211,15 @@
@Override
public Void call() throws Exception
{
- bank.transfer(alrubingerAccountId, pokerAccountId, new BigDecimal(100));
+ bank.transfer(alrubingerAccountId, pokerAccountId, oneHundred);
return null;
}
};
try
{
- this.executeInTx(transferTask,
- new CheckBalanceOfAccountTask(alrubingerAccountId, new BigDecimal(300)),
- new CheckBalanceOfAccountTask(pokerAccountId, new BigDecimal(200)),
- ForcedTestExceptionTask.INSTANCE);
+ this.executeInTx(transferTask, new CheckBalanceOfAccountTask(alrubingerAccountId, expectedinitialALR.subtract(
+ oneHundred).subtract(oneHundred)), new CheckBalanceOfAccountTask(pokerAccountId, expectedinitialPoker
+ .add(oneHundred).add(oneHundred)), ForcedTestExceptionTask.INSTANCE);
}
// Expected
catch (final ForcedTestException fte)
@@ -223,18 +229,150 @@
Assert.assertTrue("Did not receive expected exception as signaled from the test; was not rolled back",
gotExpectedException);
- // Now that we've checked the tranfer succeeded from within the Tx, then we threw an
+ // Now that we've checked the transfer succeeded from within the Tx, then we threw an
// exception before committed, ensure the Tx rolled back and the transfer was reverted from the
// perspective of everyone outside the Tx.
- this.executeInTx(new CheckBalanceOfAccountTask(alrubingerAccountId, new BigDecimal(400)),
- new CheckBalanceOfAccountTask(pokerAccountId, new BigDecimal(100)));
+ this.executeInTx(new CheckBalanceOfAccountTask(alrubingerAccountId, expectedinitialALR.subtract(oneHundred)),
+ new CheckBalanceOfAccountTask(pokerAccountId, expectedinitialPoker.add(oneHundred)));
}
+ /**
+ * Ensures that when we make a sequence of bets enclosed in a single Tx,
+ * some exceptional condition at the end doesn't roll back the prior
+ * history. Once we've won/lost a bet, that bet's done. This tests that
+ * each bet takes place in its own isolated Tx.
+ */
+ @Test
+ public void sequenceOfBetsDoesntRollBackAll() throws Throwable
+ {
+ // Get the original balance for ALR; this is done outside a Tx
+ final BigDecimal originalBalance = bank.getBalance(DbInitializerLocalBusiness.ACCOUNT_ALRUBINGER_ID);
+ log.info("Starting balance before playing poker: " + originalBalance);
+
+ // Execute 11 bets enclosed in a new Tx, and ensure that the account transfers
+ // took place as expected. Then throw an exception to rollback the parent Tx.
+ final BigDecimal betAmount = new BigDecimal(20);
+ final Place11BetsThenForceExceptionTask task = new Place11BetsThenForceExceptionTask(betAmount);
+ boolean gotForcedException = false;
+ try
+ {
+ this.executeInTx(task);
+ }
+ catch (final ForcedTestException tfe)
+ {
+ // Expected
+ gotForcedException = true;
+ }
+ Assert.assertTrue("Did not obtain the test exception as expected", gotForcedException);
+
+ // Now we've ensured that from inside the calling Tx we saw the account balances
+ // were as expected. But we rolled back that enclosing Tx, so ensure that the outcome
+ // of the games was not ignored
+ final BigDecimal afterBetsBalance = bank.getBalance(DbInitializerLocalBusiness.ACCOUNT_ALRUBINGER_ID);
+ final int gameOutcomeCount = task.gameOutcomeCount;
+ new AssertGameOutcome(originalBalance, afterBetsBalance, gameOutcomeCount, betAmount).call();
+ }
+
//-------------------------------------------------------------------------------------||
// Internal Helpers -------------------------------------------------------------------||
//-------------------------------------------------------------------------------------||
/**
+ * Task which asserts given an account original balance,
+ * ending balance, game outcome count, and bet amount, that funds
+ * remaining are as expected.
+ */
+ private static final class AssertGameOutcome implements Callable<Void>
+ {
+ private final BigDecimal originalBalance;
+
+ private final int gameOutcomeCount;
+
+ private final BigDecimal betAmount;
+
+ private final BigDecimal afterBetsBalance;
+
+ AssertGameOutcome(final BigDecimal originalBalance, final BigDecimal afterBetsBalance,
+ final int gameOutcomeCount, final BigDecimal betAmount)
+ {
+ this.originalBalance = originalBalance;
+ this.gameOutcomeCount = gameOutcomeCount;
+ this.betAmount = betAmount;
+ this.afterBetsBalance = afterBetsBalance;
+ }
+
+ @Override
+ public Void call() throws Exception
+ {
+ // Calculate expected
+ final BigDecimal expectedGains = betAmount.multiply(new BigDecimal(gameOutcomeCount));
+ final BigDecimal expectedBalance = originalBalance.add(expectedGains);
+
+ // Assert
+ Assert.assertTrue("Balance after all bets was not as expected " + expectedBalance + " but was "
+ + afterBetsBalance, expectedBalance.compareTo(afterBetsBalance) == 0);
+
+ // Return
+ return null;
+ }
+
+ }
+
+ /**
+ * A task that places 11 bets, then manually throws a {@link ForcedTestException}.
+ * This is so we may check that the balance transfers happened as
+ * expected from within the context of the Tx in which this task will run, but
+ * also such that we can ensure that even if an exceptional case happens after bets have taken
+ * place, the completed bets do not roll back. Once the money's on the table, you can't take
+ * it back. ;)
+ */
+ private final class Place11BetsThenForceExceptionTask implements Callable<Void>
+ {
+ /**
+ * Tracks how many games won/lost. A negative
+ * number indicates games lost; positive: won.
+ */
+ private int gameOutcomeCount = 0;
+
+ private final BigDecimal betAmount;
+
+ Place11BetsThenForceExceptionTask(final BigDecimal betAmount)
+ {
+ this.betAmount = betAmount;
+ }
+
+ @Override
+ public Void call() throws Exception
+ {
+
+ // Find the starting balance
+ final long alrubingerAccountId = DbInitializerLocalBusiness.ACCOUNT_ALRUBINGER_ID;
+ final BigDecimal startingBalance = bank.getBalance(alrubingerAccountId);
+
+ // Now run 11 bets
+ for (int i = 0; i < 11; i++)
+ {
+ // Track whether we win or lose
+ final boolean win = pokerGame.bet(DbInitializerLocalBusiness.ACCOUNT_ALRUBINGER_ID, betAmount);
+ gameOutcomeCount += win ? 1 : -1;
+ }
+ log.info("Won " + gameOutcomeCount + " games at " + betAmount + "/game");
+
+ // Get the user's balance after the bets
+ final BigDecimal afterBetsBalance = bank.getBalance(alrubingerAccountId);
+
+ // Ensure that money's been allocated properly
+ new AssertGameOutcome(startingBalance, afterBetsBalance, gameOutcomeCount, betAmount).call();
+
+ // Now force an exception to get a Tx rollback. This should *not* affect the
+ // money already transferred during the bets, as they should have taken place
+ // in nested Txs and already committed.
+ throw new ForcedTestException();
+ }
+
+ }
+
+ /**
* A task that checks that the account balance of an {@link Account}
* with specified ID equals a specified expected value. Typically to be run
* inside of a Tx via {@link TransactionalPokerGameIntegrationTest#executeInTx(Callable...)}.
@@ -261,7 +399,7 @@
public Void call() throws Exception
{
final Account account = db.find(Account.class, accountId);
- Assert.assertEquals("Balance was not as expected", expectedBalance, account.getBalance());
+ Assert.assertTrue("Balance was not as expected", expectedBalance.compareTo(account.getBalance()) == 0);
return null;
}
@@ -302,6 +440,7 @@
}
catch (final TaskExecutionException tee)
{
+ // Unwrap the real cause
throw tee.getCause();
}
}
Modified: projects/ejb-book/trunk/chxx-poker/src/test/java/org/jboss/ejb3/examples/chxx/transactions/ejb/DbInitializerBean.java
===================================================================
--- projects/ejb-book/trunk/chxx-poker/src/test/java/org/jboss/ejb3/examples/chxx/transactions/ejb/DbInitializerBean.java 2010-05-15 19:35:12 UTC (rev 104827)
+++ projects/ejb-book/trunk/chxx-poker/src/test/java/org/jboss/ejb3/examples/chxx/transactions/ejb/DbInitializerBean.java 2010-05-15 20:46:25 UTC (rev 104828)
@@ -39,10 +39,13 @@
import org.jboss.ejb3.annotation.LocalBinding;
import org.jboss.ejb3.examples.chxx.transactions.entity.Account;
import org.jboss.ejb3.examples.chxx.transactions.entity.User;
+import org.jboss.ejb3.examples.chxx.transactions.impl.PokerServiceConstants;
/**
* Singleton EJB to initialize and prepropulate
- * the database state before running tests.
+ * the database state before running tests. Also permits
+ * refreshing the DB with default state via
+ * {@link DbInitializerLocalBusiness#refreshWithDefaultData()}.
*
* @author <a href="mailto:andrew.rubinger at jboss.org">ALR</a>
* @version $Revision: $
@@ -122,22 +125,20 @@
final User alrubinger = new User();
alrubinger.setId(USER_ALRUBINGER_ID);
alrubinger.setName(USER_ALRUBINGER_NAME);
- alrubinger.setEmail(USER_ALRUBINGER_EMAIL);
final Account alrubingerAccount = new Account();
alrubingerAccount.deposit(INITIAL_ACCOUNT_BALANCE_ALR);
alrubingerAccount.setOwner(alrubinger);
- alrubingerAccount.setId(ACCOUNT_ALRUBINGERL_ID);
+ alrubingerAccount.setId(ACCOUNT_ALRUBINGER_ID);
alrubinger.setAccount(alrubingerAccount);
// Poker Game Service
final User pokerGameService = new User();
- pokerGameService.setId(USER_POKERGAME_ID);
- pokerGameService.setName(USER_POKERGAME_NAME);
- pokerGameService.setEmail(USER_POKERGAME_EMAIL);
+ pokerGameService.setId(PokerServiceConstants.USER_POKERGAME_ID);
+ pokerGameService.setName(PokerServiceConstants.USER_POKERGAME_NAME);
final Account pokerGameAccount = new Account();
- pokerGameAccount.deposit(INITIAL_ACCOUNT_BALANCE_POKERGAME);
+ pokerGameAccount.deposit(PokerServiceConstants.INITIAL_ACCOUNT_BALANCE_POKERGAME);
pokerGameAccount.setOwner(pokerGameService);
- pokerGameAccount.setId(ACCOUNT_POKERGAME_ID);
+ pokerGameAccount.setId(PokerServiceConstants.ACCOUNT_POKERGAME_ID);
pokerGameService.setAccount(pokerGameAccount);
// Persist
Modified: projects/ejb-book/trunk/chxx-poker/src/test/java/org/jboss/ejb3/examples/chxx/transactions/ejb/DbInitializerLocalBusiness.java
===================================================================
--- projects/ejb-book/trunk/chxx-poker/src/test/java/org/jboss/ejb3/examples/chxx/transactions/ejb/DbInitializerLocalBusiness.java 2010-05-15 19:35:12 UTC (rev 104827)
+++ projects/ejb-book/trunk/chxx-poker/src/test/java/org/jboss/ejb3/examples/chxx/transactions/ejb/DbInitializerLocalBusiness.java 2010-05-15 20:46:25 UTC (rev 104828)
@@ -45,26 +45,14 @@
* Test Data
*/
- public static final long USER_ALRUBINGER_ID = 1L;
+ long USER_ALRUBINGER_ID = 2L;
- public static final String USER_ALRUBINGER_NAME = "Andrew Lee Rubinger";
+ String USER_ALRUBINGER_NAME = "Andrew Lee Rubinger";
- public static final String USER_ALRUBINGER_EMAIL = "alr at fake.com";
+ long ACCOUNT_ALRUBINGER_ID = 2L;
- public static final long ACCOUNT_ALRUBINGERL_ID = 1L;
+ BigDecimal INITIAL_ACCOUNT_BALANCE_ALR = new BigDecimal(500);
- public static final long USER_POKERGAME_ID = 2L;
-
- public static final String USER_POKERGAME_NAME = "The Poker Game System";
-
- public static final String USER_POKERGAME_EMAIL = "pokergame at fake.com";
-
- public static final long ACCOUNT_POKERGAME_ID = 2L;
-
- public static final BigDecimal INITIAL_ACCOUNT_BALANCE_ALR = new BigDecimal(500);
-
- public static final BigDecimal INITIAL_ACCOUNT_BALANCE_POKERGAME = new BigDecimal(0);
-
//-------------------------------------------------------------------------------------||
// Contracts --------------------------------------------------------------------------||
//-------------------------------------------------------------------------------------||
Modified: projects/ejb-book/trunk/chxx-poker/src/test/java/org/jboss/ejb3/examples/chxx/transactions/ejb/DbQueryBean.java
===================================================================
--- projects/ejb-book/trunk/chxx-poker/src/test/java/org/jboss/ejb3/examples/chxx/transactions/ejb/DbQueryBean.java 2010-05-15 19:35:12 UTC (rev 104827)
+++ projects/ejb-book/trunk/chxx-poker/src/test/java/org/jboss/ejb3/examples/chxx/transactions/ejb/DbQueryBean.java 2010-05-15 20:46:25 UTC (rev 104828)
@@ -31,8 +31,12 @@
import org.jboss.ejb3.annotation.LocalBinding;
/**
+ * Implementation of a test EJB which exposes generic database
+ * query operations directly via the {@link EntityManager}.
+ * Used in validating pre- and postconditions during testing.
+ * All methods will be executed in an existing Transaction, which
+ * is {@link TransactionAttributeType#MANDATORY}.
*
- *
*
* @author <a href="mailto:andrew.rubinger at jboss.org">ALR</a>
* @version $Revision: $
Modified: projects/ejb-book/trunk/chxx-poker/src/test/java/org/jboss/ejb3/examples/chxx/transactions/ejb/TxWrappingBean.java
===================================================================
--- projects/ejb-book/trunk/chxx-poker/src/test/java/org/jboss/ejb3/examples/chxx/transactions/ejb/TxWrappingBean.java 2010-05-15 19:35:12 UTC (rev 104827)
+++ projects/ejb-book/trunk/chxx-poker/src/test/java/org/jboss/ejb3/examples/chxx/transactions/ejb/TxWrappingBean.java 2010-05-15 20:46:25 UTC (rev 104828)
@@ -31,7 +31,8 @@
import org.jboss.ejb3.annotation.LocalBinding;
/**
- * EJB which wraps
+ * EJB which wraps a specified series of {@link Callable}
+ * tasks within the context of a new Transaction
*
* @author <a href="mailto:andrew.rubinger at jboss.org">ALR</a>
* @version $Revision: $
More information about the jboss-cvs-commits
mailing list