View Javadoc
1   package ejava.examples.asyncmarket.ejb;
2   
3   import java.util.List;
4   
5   import javax.annotation.PostConstruct;
6   import javax.annotation.Resource;
7   import javax.annotation.security.PermitAll;
8   import javax.ejb.ActivationConfigProperty;
9   import javax.ejb.EJB;
10  import javax.ejb.MessageDriven;
11  import javax.ejb.MessageDrivenContext;
12  import javax.jms.MapMessage;
13  import javax.jms.Message;
14  import javax.jms.MessageListener;
15  import javax.persistence.EntityManager;
16  import javax.persistence.PersistenceContext;
17  
18  import org.apache.commons.logging.Log;
19  import org.apache.commons.logging.LogFactory;
20  
21  import ejava.examples.asyncmarket.MarketException;
22  import ejava.examples.asyncmarket.bo.AuctionItem;
23  import ejava.examples.asyncmarket.bo.Bid;
24  import ejava.examples.asyncmarket.bo.Order;
25  import ejava.examples.asyncmarket.dao.AuctionItemDAO;
26  import ejava.examples.asyncmarket.dao.OrderDAO;
27  import ejava.examples.asyncmarket.jpa.JPAAuctionItemDAO;
28  import ejava.examples.asyncmarket.jpa.JPAOrderDAO;
29  
30  
31  /**
32   * This class will listen for market events and cause further bidding to 
33   * occur. Note that this is mostly a technology demonstration and not
34   * a great architectural demonstration. It would be best to restrict
35   * this class to only the async/JMS interface and move all detailed
36   * processing and business logic to lower level classes. Architecturally,
37   * MDBs should be restricted to just interface adaption. If you place 
38   * too much business logic here it becomes harder to test and reuse.
39   *  
40   */
41  @MessageDriven(activationConfig={
42  		/* I placed the first few in the ejb-jar.xml DD
43  		 * since they are configuration options that,
44  		 * when they change, do not impact the code.
45          @ActivationConfigProperty(
46                  propertyName="destinationType",
47                  propertyValue="javax.jms.Topic"),            
48          @ActivationConfigProperty(
49                  propertyName="destination",
50                  propertyValue="java:/topic/ejava/examples/asyncMarket/topic1"),            
51          @ActivationConfigProperty(
52                  propertyName="messageSelector",
53                  propertyValue="JMSType in ('forSale', 'saleUpdate')"),
54          */
55  		//This one, however, would impact the code if it were changed
56          @ActivationConfigProperty(
57                  propertyName="acknowledgeMode",
58                  propertyValue="Auto-acknowledge")            
59  })
60  public class BuyerMDB implements MessageListener {
61      private static final Log log = LogFactory.getLog(BuyerMDB.class);
62      
63      @EJB
64      private BuyerLocal buyer;
65      @EJB
66      private AuctionMgmtLocal auctionMgmt;     
67      @PersistenceContext(unitName="asyncMarket")
68      private EntityManager em;
69      
70      private AuctionItemDAO auctionItemDAO;
71      private OrderDAO orderDAO;
72      
73      @Resource
74      private MessageDrivenContext ctx;
75      
76      @PostConstruct
77      public void init() {
78          log.info("*** BuyerMDB init() ***");
79          log.debug("ctx=" + ctx);
80          log.debug("buyer=" + buyer);
81          log.debug("auctionMgmt=" + auctionMgmt);
82          log.debug("em=" + em);
83          
84          orderDAO = new JPAOrderDAO();
85          ((JPAOrderDAO)orderDAO).setEntityManager(em);
86          
87          auctionItemDAO = new JPAAuctionItemDAO();
88          ((JPAAuctionItemDAO)auctionItemDAO).setEntityManager(em);        
89      }
90  
91      @PermitAll
92      public void onMessage(Message message) {
93          try {
94              log.debug("onMessage:" + message.getJMSMessageID());
95              MapMessage auctionMsg = (MapMessage)message;
96              long itemId = auctionMsg.getLong("id");
97              processAuctionItem(itemId);
98          }
99          catch (Exception ex) {
100             log.error("error processing message", ex);
101         }
102     }
103     
104     protected void processAuctionItem(long itemId) {
105         int index=0;
106         List<Order> orders = null;
107         do {
108             orders = orderDAO.getOrdersforItem(itemId, index, 10);
109             for (Order order: orders) {
110                 processOrder(order);
111             }
112             index += orders.size();            
113         } while (orders.size() > 0);        
114     }
115 
116     protected void processOrder(Order order) {
117         log.debug("processing order:" + order);
118         try {
119             AuctionItem item = order.getItem();
120             Bid highestBid = item.getHighestBid();
121             if (highestBid == null) {
122                 if (item.getMinBid() < order.getMaxBid()) {
123                     buyer.bidProduct(item.getId(), 
124                                      order.getBuyer().getUserId(), 
125                                      item.getMinBid());
126                     log.debug("placed initial bid for order:" + order);
127                 }
128             }
129             else if (highestBid.getAmount() < order.getMaxBid()
130             		// add don't bid against ourself
131             		&& item.getHighestBid().getBidder().getId() !=
132             		   order.getBuyer().getId()){
133                 buyer.bidProduct(item.getId(), 
134                                  order.getBuyer().getUserId(), 
135                                  item.getHighestBid().getAmount() + 1.00);
136                 log.debug("placed new bid for order:" + order);
137             }
138         }
139         catch (MarketException ex) {
140             log.error("error processing order:" + order, ex);
141         }
142     }
143 }