View Javadoc
1   package ejava.examples.ejbsessionbank.ejb;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   
6   import javax.annotation.PostConstruct;
7   import javax.annotation.PreDestroy;
8   import javax.annotation.Resource;
9   import javax.ejb.EJB;
10  import javax.ejb.EJBException;
11  import javax.ejb.SessionContext;
12  import javax.ejb.Stateless;
13  import javax.persistence.EntityManager;
14  import javax.persistence.PersistenceContext;
15  
16  import org.apache.commons.logging.Log;
17  import org.apache.commons.logging.LogFactory;
18  
19  import ejava.examples.ejbsessionbank.bl.BankException;
20  import ejava.examples.ejbsessionbank.bl.Teller;
21  import ejava.examples.ejbsessionbank.blimpl.TellerImpl;
22  import ejava.examples.ejbsessionbank.bo.Account;
23  import ejava.examples.ejbsessionbank.bo.Ledger;
24  import ejava.examples.ejbsessionbank.bo.Owner;
25  import ejava.examples.ejbsessionbank.dao.AccountDAO;
26  import ejava.examples.ejbsessionbank.dao.DAOException;
27  import ejava.examples.ejbsessionbank.dao.OwnerDAO;
28  import ejava.examples.ejbsessionbank.dto.OwnerDTO;
29  import ejava.examples.ejbsessionbank.jpa.JPAAccountDAO;
30  import ejava.examples.ejbsessionbank.jpa.JPAOwnerDAO;
31  
32  /**
33   * This class implements a Stateless Session Bean wrapper around the 
34   * Teller business logic. With the light-weight EJB3 design for session 
35   * beans, there is no reason why the TellerImpl couldn't be the session bean
36   * and we could possibly do so through the deployment descriptor. However,
37   * adding this specific class permits a clear separation between implementing
38   * the business logic and handling RMI, transactions, and security (coming)
39   * issues that are part of being a session bean. 
40   *
41   * @author jcstaff
42   */
43  @Stateless
44  public class TellerEJB implements TellerLocal, TellerRemote {
45      private static final Log log = LogFactory.getLog(TellerEJB.class);
46  
47      @Resource
48      protected SessionContext ctx;
49      
50      /** The peristence context will be defined as a property to allow a 
51       * derived class to override this value and assist in unit testing.
52       */    
53      @PersistenceContext(unitName="ejbsessionbank")
54      protected EntityManager em;
55      
56      @Resource(name="daoClass")
57      protected String daoClassName;
58      
59      @EJB
60      private StatsLocal stats;
61  
62      protected Teller teller;
63      
64      /**
65       * This method performs one-time initialization for the session bean.
66       * The name of the DAO class is provided through a JNDI ENC property 
67       * value.
68       */
69      @PostConstruct
70      public void init() {
71          log.debug("init(), daoClass=" + daoClassName);
72          teller = new TellerImpl();
73          
74          try {
75              AccountDAO dao = (AccountDAO)Thread.currentThread()
76                                                 .getContextClassLoader()
77                                                 .loadClass(daoClassName)
78                                                 .newInstance();            
79              ((JPAAccountDAO)dao).setEntityManager(em);
80              ((TellerImpl)teller).setAcctDAO(dao);
81              
82              OwnerDAO ownerDAO = new JPAOwnerDAO();
83              ((JPAOwnerDAO)ownerDAO).setEntityManager(em);            
84              ((TellerImpl)teller).setOwnerDAO(ownerDAO);
85          }
86          catch (Exception ex) {
87              log.fatal("error loading dao class:" + daoClassName, ex);
88              throw new EJBException("error loading dao class:" + daoClassName 
89                 + ", " + ex);
90          }
91          
92      }
93  
94      /**
95       * This method will perform one-time cleanup for the object. There is 
96       * really nothing that needs to be done at this time. The operations 
97       * supplied demo some types of cleanup that could be done.
98       *
99       */
100     @PreDestroy
101     public void close() {
102         log.debug("close");
103         teller = null;
104     }
105 
106     public Account createAccount(String accountNumber) throws BankException {
107         debug();
108         try {
109         	Account account = teller.createAccount(accountNumber);
110         	stats.open();
111             return account;
112         }
113         catch (DAOException ex) {
114             ctx.setRollbackOnly();
115             log.fatal("internal error creating account", ex);
116             throw new BankException("internal error creating account:" + ex);
117         }
118     }
119     
120     public Account closeAccount(String acctNum) throws BankException {
121         debug();
122         try {
123             Account account = teller.closeAccount(acctNum);
124             stats.close();
125             return account;
126         }
127         catch (DAOException ex) {
128             ctx.setRollbackOnly();
129             log.fatal("internal error closing account", ex);
130             throw new BankException("internal error closing account:" + ex);
131         }
132     }
133 
134     public Account getAccount(String acctNum) throws BankException {
135         debug();
136         try {
137             return teller.getAccount(acctNum);
138         }
139         catch (DAOException ex) {
140             ctx.setRollbackOnly();
141             log.fatal("internal error getting account", ex);
142             throw new BankException("internal error getting account:" + ex);
143         }
144     }
145 
146     public List<Account> getOverdrawnAccounts(int index, int count) throws BankException {
147         debug();
148         try {
149             return teller.getOverdrawnAccounts(index, count);
150         }
151         catch (DAOException ex) {
152             ctx.setRollbackOnly();
153             log.fatal("internal getting accounts", ex);
154             throw new BankException("internal getting accounts:" + ex);
155         }
156     }
157 
158     public List<Account> getAccounts(int index, int count) throws BankException {
159         debug();
160         try {
161             return teller.getAccounts(index, count);
162         }
163         catch (DAOException ex) {
164             ctx.setRollbackOnly();
165             log.fatal("internal getting accounts", ex);
166             throw new BankException("internal getting accounts:" + ex);
167         }
168     }
169 
170     public void updateAccount(Account account) throws BankException {
171         debug();
172         try {
173             log.debug("in EJB, about to update account:" + account);
174             teller.updateAccount(account);
175         }
176         catch (DAOException ex) {
177             ctx.setRollbackOnly();
178             log.fatal("internal error updating account", ex);
179             throw new BankException("internal error updating account:" + ex);
180         }
181     }
182 
183     public Ledger getLedger() throws BankException {
184         debug();
185         try {
186             Ledger ledger = new Ledger(
187                     teller.getLedgerCount(),
188                     teller.getLedgerSum(),
189                     teller.getLedgerAveBalance());            
190             return ledger;
191         }
192         catch (DAOException ex) {
193             ctx.setRollbackOnly();
194             log.fatal("internal error getting ledger", ex);
195             throw new BankException("internal error getting ledger:" + ex);
196         }
197     }
198 
199     /**
200      * This method takes advantage of the DAO/Business logic knowledge
201      * of how to create a DTO. Note that the query is not actually known
202      * to the business logic or DAO. It is expressed in an ORM.xml file.
203      */
204     public Ledger getLedger2() throws BankException {
205         debug();
206         try {
207             return teller.getLedger();
208         }
209         catch (DAOException ex) {
210             ctx.setRollbackOnly();
211             log.fatal("internal error getting ledger", ex);
212             throw new BankException("internal error getting ledger:" + ex);
213         }
214     }
215     
216     /**
217      * This method is and example of a method that may be too fine for a 
218      * remote method and should be encapsulated in a remote facade call.
219      */
220     public double getLedgerAveBalance() throws BankException {
221         debug();
222         try {
223             return teller.getLedgerAveBalance();
224         }
225         catch (DAOException ex) {
226             ctx.setRollbackOnly();
227             log.fatal("internal error getting ledger ave balance", ex);
228             throw new BankException(
229                     "internal error getting ledger ave balance:" + ex);
230         }
231     }
232 
233     /**
234      * This method is and example of a method that may be too fine for a 
235      * remote method and should be encapsulated in a remote facade call.
236      */
237     public long getLedgerCount() throws BankException {
238         debug();
239         try {
240             return teller.getLedgerCount();
241         }
242         catch (DAOException ex) {
243             ctx.setRollbackOnly();
244             log.fatal("internal error getting ledger count", ex);
245             throw new BankException(
246                     "internal error getting ledger count:" + ex);
247         }
248     }
249 
250     /**
251      * This method is and example of a method that may be too fine for a 
252      * remote method and should be encapsulated in a remote facade call.
253      */
254     public double getLedgerSum() throws BankException {
255         debug();
256         try {
257             return teller.getLedgerSum();
258         }
259         catch (DAOException ex) {
260             ctx.setRollbackOnly();
261             log.fatal("internal error getting ledger sum", ex);
262             throw new BankException(
263                     "internal error getting ledger sum:" + ex);
264         }
265     }
266     
267     private void debug() {
268         if (log.isDebugEnabled()) {
269             //nothing yet...
270         }
271     }
272     
273     // -- this half was added to provide a richer data model to demo
274     // -- lazy load issues.
275 
276     public Owner addOwner(long ownerId, String accountNumber)
277             throws BankException {
278         try {
279             log.debug("in EJB, about to add owner to account");
280             return teller.addOwner(ownerId, accountNumber);
281         }
282         catch (DAOException ex) {
283             ctx.setRollbackOnly();
284             log.fatal("internal error updating account", ex);
285             throw new BankException("internal error updating account:" + ex);
286         }
287     }
288 
289     public Owner createOwner(String firstName, String lastName, String ssn)
290             throws BankException {
291         try {
292             log.debug("in EJB, about to create owner:" + firstName);
293             return teller.createOwner(firstName, lastName, ssn);
294         }
295         catch (DAOException ex) {
296             ctx.setRollbackOnly();
297             log.fatal("internal error updating account", ex);
298             throw new BankException("internal error updating account:" + ex);
299         }
300     }
301 
302     public Owner openAccount(long ownerId, String accountNumber)
303             throws BankException {
304         try {
305             log.debug("in EJB, about to open account for owner");
306             return teller.openAccount(ownerId, accountNumber);
307         }
308         catch (DAOException ex) {
309             ctx.setRollbackOnly();
310             log.fatal("internal error updating account", ex);
311             throw new BankException("internal error updating account:" + ex);
312         }
313     }
314 
315     public void removeOwner(long ownerId) throws BankException {
316         try {
317             log.debug("in EJB, about to remove owner:" + ownerId);
318             teller.removeOwner(ownerId);
319         }
320         catch (DAOException ex) {
321             ctx.setRollbackOnly();
322             log.fatal("internal error updating account", ex);
323             throw new BankException("internal error updating account:" + ex);
324         }
325     }
326 
327     public List<Owner> getOwners(int index, int count) throws BankException {
328         try {
329             log.debug("in EJB, about to get owners");
330             return teller.getOwners(index, count);
331         }
332         catch (DAOException ex) {
333             ctx.setRollbackOnly();
334             log.fatal("internal error updating account", ex);
335             throw new BankException("internal error updating account:" + ex);
336         }
337     }
338 
339     public List<Owner> getOwnersLoaded(int index, int count) 
340         throws BankException {
341         List<Owner> owners = getOwners(index, count);
342         for(Owner owner : owners) {
343             for (Account account : owner.getAccounts()) {
344                 account.getBalance(); //call a method to get loaded
345             }
346         }
347         return owners;
348     }
349     
350     public List<Owner> getOwnersPOJO(int index, int count) 
351         throws BankException {
352         List<Owner> ownersPOJO = new ArrayList<Owner>();
353         for(Owner owner : getOwners(index, count)) {
354             Owner ownerPOJO = new Owner(owner.getId());
355             ownerPOJO.setFirstName(owner.getFirstName());
356             ownerPOJO.setLastName(owner.getLastName());
357             ownerPOJO.setSsn(owner.getSsn());
358             for (Account account : owner.getAccounts()) {
359                 Account accountPOJO = new Account(account.getId());
360                 accountPOJO.setAccountNumber(account.getAccountNumber());
361                 accountPOJO.deposit(account.getBalance());
362                 ownerPOJO.getAccounts().add(accountPOJO);
363             }
364             ownersPOJO.add(ownerPOJO);
365         }
366         return ownersPOJO;
367     }
368 
369     public List<OwnerDTO> getOwnersDTO(int index, int count) 
370         throws BankException {
371         List<OwnerDTO> ownersDTO = new ArrayList<OwnerDTO>();
372         for(Owner owner : getOwners(index, count)) {
373             OwnerDTO ownerDTO = new OwnerDTO(owner.getId());
374             ownerDTO.setFirstName(owner.getFirstName());
375             ownerDTO.setLastName(owner.getLastName());
376             ownerDTO.setAccounts(owner.getAccounts().size());
377             ownersDTO.add(ownerDTO);
378         }
379         return ownersDTO;
380     }
381 
382     @Override
383     public String whoAmI() {
384     	return ctx.getCallerPrincipal().getName();
385     }
386 }