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