EJB and JMS

advertisement
Enterprise
Java
Asynchronous EJB
v141202
Asynchronous EJB
1
Goals
Enterprise
Java
• Be able to produce messages from the EJB server
• Be able to consume messages within the EJB server
• Be able to define timers within EJB server
v141202
Asynchronous EJB
2
Objectives
•
•
•
•
Enterprise
Java
EJB JMS Producers
EJB JMS Consumers (Message Driven Beans; MDBs)
Asynchronous Methods
EJB Timers
v141202
v111128
Asynchronous
EJB
Asynchronous EJB
33
EJB JMS Producers
Enterprise
Java
• Obtain Resources
– ConnectionFactory
– Destination
• Create Session
– integrate with JTA transaction
• Publish Message
v141202
v111128
Asynchronous
EJB
Asynchronous EJB
44
Obtaining a ConnectionFactory
Enterprise
Java
• Using annotations
@Stateless
public class SellerEJB ... {
@Resource(lookup=“java:/JmsXA")
private ConnectionFactory connFactory;
– Lookup points to global JNDI name
– benefits
• concise & simple
– drawbacks
• mixes deployment concepts with Java code
v141202
v111128
Asynchronous
EJB
Asynchronous EJB
55
Enterprise
Java
Obtaining a ConnectionFactory (cont.)
• Using ejb-jar.xml
<ejb-name>SellerEJB</ejb-name>
<resource-ref>
<res-ref-name>jms/ConnectionFactory</res-ref-name>
<res-type>javax.jms.ConnectionFactory</res-type>
<lookup-name>java:/JmsXA</lookup-name>
<injection-target>
<injection-target-class>
ejava.examples.asyncmarket.ejb.SellerEJB
</injection-target-class>
<injection-target-name>
connFactory
</injection-target-name>
</injection-target>
</resource-ref>
...
– Lookup moved away from code to DD
– factory injected into EJB
– ejb-jar.xml is no longer vendor/deployment-neutral
v141202
v111128
Asynchronous
EJB
Asynchronous EJB
66
Enterprise
Java
Obtaining a ConnectionFactory (cont.)
• Using jboss-ejb3.xml
<session>
<ejb-name>SellerEJB</ejb-name>
<resource-ref>
<res-ref-name>jms/ConnectionFactory</res-ref-name>
<jndi-name>java:/JmsXA</jndi-name>
</resource-ref>
</session>
– Lookup is now removed
• replaced with vendor/deployment specific reference
– Required 3 files to complete
v141202
v111128
Asynchronous
EJB
Asynchronous EJB
77
Obtaining a Destination
Enterprise
Java
• Using annotations
@Stateless
public class SellerEJB implements SellerLocal, SellerRemote {
...
@Resource(lookup="java:/topic/ejava/examples/asyncMarket/topic1",
type=Topic.class)
private Destination sellTopic;
– Lookup points to global JNDI entry
– benefits
• concise and simple
– drawbacks
• mixes deployment properties with implementation
v141202
v111128
Asynchronous
EJB
Asynchronous EJB
88
Obtaining a Destination (cont.)
Enterprise
Java
• Using ejb-jar.xml
<resource-env-ref>
<resource-env-ref-name>jms/sellTopic</resource-env-ref-name>
<resource-env-ref-type>javax.jms.Topic</resource-env-ref-type>
<lookup-name>topic/ejava/examples/asyncMarket/topic</lookup-name>
<injection-target>
<injection-target-class>
ejava.examples.asyncmarket.ejb.SellerEJB
</injection-target-class>
<injection-target-name>sellTopic</injection-target-name>
</injection-target>
</resource-env-ref>
– mappedName moved away from Java and to DD
– note resource-env-ref used for Destinations
v141202
v111128
Asynchronous
EJB
Asynchronous EJB
99
Getting a Session
Enterprise
Java
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public long sellProduct(String sellerId, AuctionItem item)
throws MarketException {
Connection connection = null;
Session session = null;
try {
connection = connFactory.createConnection();
session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
...
}
catch (JMSException ex) {
log.error("error publishing sell", ex);
ctx.setRollbackOnly();
throw new EJBException("error publishing sell:" + ex);
}
finally {
try {
if (session != null)
{ session.close(); }
if (connection != null) { connection.close(); }
} catch (JMSException ex) {
log.error("unable to close resources", ex);
}
}
}
v141202
v111128
Asynchronous
EJB
Asynchronous EJB
1010
Enterprise
Java
Integrating JMS into the Transaction
Person seller = sellerDAO.getPersonByUserId(sellerId);
seller.getItems().add(item);
item.setOwner(seller);
auctionItemDAO.createItem(item);
publishForSale(session, item);
return item.getId();
v141202
v111128
Asynchronous
EJB
Asynchronous EJB
1111
Publishing the Message
Enterprise
Java
protected void publishForSale(Session session, AuctionItem item)
throws JMSException {
MessageProducer producer = null;
try {
producer = session.createProducer(sellTopic);
MapMessage message = session.createMapMessage();
message.setJMSType("forSale");
message.setLong("id", item.getId());
message.setString("name", item.getName());
message.setString("seller", item.getOwner().getUserId());
message.setLong("startDate", item.getStartDate().getTime());
message.setLong("endDate", item.getEndDate().getTime());
message.setDouble("minBid", item.getMinBid());
message.setDouble("bids", item.getBids().size());
message.setDouble("highestBid",
(item.getHighestBid() == null ? 0.00 :
item.getHighestBid().getAmount()));
producer.send(message);
}
finally {
if (producer != null)
{ producer.close(); }
}
}
v141202
v111128
Asynchronous
EJB
Asynchronous EJB
1212
EJB JMS Consumers; MDBs
Enterprise
Java
• “Message Driven Bean”
• Introduced in EJB 2.0 to support JMS providers
• Extended in EJB 2.1 to support non-JMS message
providers
– using the Java EE Connector API
• commonly called JCA
• EJB 3.0 added @Annotation support for configuration
• Java EE Providers
– must support a JMS provider
– must support external providers through JCA
• Session and Entity Beans cannot be a MessageListener
– can poll for messages with MessageConsumer.receive()
– can be wrapped by an MDB to be called asynchronously
v141202
v111128
Asynchronous
EJB
Asynchronous EJB
1313
MessageDriven Bean Configuration
•
•
•
•
•
Enterprise
Java
Destination Type
Destination
Selector
Message Acknowledgement
...
v141202
v111128
Asynchronous
EJB
Asynchronous EJB
1414
MDB Configuration
Enterprise
Java
• Using annotations
@MessageDriven(name="BuyerMDB", activationConfig={
@ActivationConfigProperty(
propertyName="destinationType",
propertyValue="javax.jms.Topic"),
@ActivationConfigProperty(
propertyName="destination",
propertyValue="topic/ejava/.../topic1"),
@ActivationConfigProperty(
propertyName="messageSelector",
propertyValue=
"JMSType in ('forSale', 'saleUpdate')"),
@ActivationConfigProperty(
propertyName="acknowledgeMode",
propertyValue="Auto-acknowledge")
})
public class BuyerMDB implements MessageListener {
v141202
v111128
Asynchronous
EJB
Asynchronous EJB
1515
MDB Configuration (cont.)
Enterprise
Java
• Using ejb-jar.xml
<message-driven>
<ejb-name>BuyerMDB</ejb-name>
<ejb-class>ejava.examples.asyncmarket.ejb.BuyerMDB</ejb-class>
<message-destination-type>
javax.jms.Topic
</message-destination-type>
<activation-config>
<activation-config-property>
<activation-config-property-name>
...
</activation-config-property-name>
<activation-config-property-value>
...
</activation-config-property-value>
</activation-config-property>
</activation-config>
v141202
v111128
Asynchronous
EJB
Asynchronous EJB
1616
MDB Configuration (cont.)
Enterprise
Java
• Using jboss.xml
<message-driven>
<ejb-name>BuyerMDB</ejb-name>
<destination-jndi-name>
topic/ejava/examples/asyncMarket/topic1
</destination-jndi-name>
v141202
v111128
Asynchronous
EJB
Asynchronous EJB
1717
MDB Structure
Enterprise
Java
@MessageDriven(name="BuyerMDB", activationConfig={ ... })
public class BuyerMDB implements MessageListener {
@PostConstruct
public void init() { ... }
public void onMessage(Message message) {
try {
log.debug("onMessage:" + message.getJMSMessageID());
MapMessage auctionMsg = (MapMessage)message;
long itemId = auctionMsg.getLong("id");
processAuctionItem(itemId);
}
catch (Exception ex) {
log.error("error processing message", ex);
}
}
v141202
Asynchronous EJB
18
MDB and Transactions
Enterprise
Java
• SUPPORTED
– message receipt/acknowledgement integrated with
overall transaction
• NOT_SUPPORTED
– message receipt/acknowledgement independent of
transactions within processing
v141202
v111128
Asynchronous
EJB
Asynchronous EJB
1919
Asynchronous Methods
Enterprise
Java
• Scenario
– Task(s) may take considerable time to complete
– Client need not wait for them to complete
• @javax.ejb.Asynchronous
– Return control to the client before EJB is invoked
– Any session bean business method may be made
@Asynchronous* (*see Serialization note below)
• null return type
– Client and issued task fully decoupled from one another
• java.util.concurrent.Future return type
– Allows task and client to coordinate a future return value
– Client returns instance of javax.ejb.AsyncResult
– Not Serializable (i.e., cannot use directly with RMI client)
v141202
Asynchronous EJB
20
Synchronous Example: Client EJB
Enterprise
Java
@Stateless
public class AuctionMgmtEJB implements AuctionMgmtRemote, AuctionMgmtLocal {
private @EJB AuctionMgmtActionEJB actions;
public void workSync(int count, long delay) {
DateFormat df = new SimpleDateFormat("HH:mm:ss.SSS");
long startTime = System.currentTimeMillis();
for (int i=0; i<count; i++) {
log.info(String.format("%s issuing sync request, delay=%d",
df.format(new Date()), delay));
Date date= actions.doWorkSync(delay);
log.info(String.format("sync waitTime=%d msecs",
System.currentTimeMillis()-startTime));
}
long syncTime = System.currentTimeMillis() - startTime;
log.info(String.format("workSync time=%d msecs", syncTime));
}
v141202
Asynchronous EJB
21
Synchronous Example: Helper EJB
Enterprise
Java
@Stateless
public class AuctionMgmtActionEJB {
public Date doWorkSync(long delay) {
DateFormat df = new SimpleDateFormat("HH:mm:ss.SSS");
log.debug(String.format("sync method %d starting %d delay at %s",
Thread.currentThread().getId(), delay, df.format(new Date())));
try { Thread.sleep(delay); }
catch (Exception ex) { ... }
Date now = new Date();
log.debug(String.format("sync method %d completed %d delay at %s",
Thread.currentThread().getId(), delay, df.format(now)));
return now;
}
v141202
Asynchronous EJB
22
Synchronous Example: Results
Enterprise
Java
11:06:44,624 INFO [AuctionMgmtEJB:306] 11:06:44.612 issuing sync request, delay=3000
11:06:44,626 DEBUG [AuctionMgmtActionEJB:24] sync method 163 starting 3000 delay at 11:06:44.626
11:06:47,628 DEBUG [AuctionMgmtActionEJB:30] sync method 163 completed 3000 delay at
11:06:47,630 INFO [AuctionMgmtEJB:309] sync waitTime=3018 msecs
11:06:47,631 INFO [AuctionMgmtEJB:306] 11:06:47.631 issuing sync request, delay=3000
11:06:47,634 DEBUG [AuctionMgmtActionEJB:24] sync method 163 starting 3000 delay at 11:06:47.634
11:06:50,636 DEBUG [AuctionMgmtActionEJB:30] sync method 163 completed 3000 delay at
11:06:50,637 INFO [AuctionMgmtEJB:309] sync waitTime=6025 msecs
11:06:50,637 INFO [AuctionMgmtEJB:306] 11:06:50.637 issuing sync request, delay=3000
11:06:50,638 DEBUG [AuctionMgmtActionEJB:24] sync method 163 starting 3000 delay at 11:06:50.638
11:06:53,640 DEBUG [AuctionMgmtActionEJB:30] sync method 163 completed 3000 delay at
11:06:53.640
11:06:53,641 INFO [AuctionMgmtEJB:309] sync waitTime=9029 msecs
11:06:53,642 INFO [AuctionMgmtEJB:312] workSync time=9030 msecs
v141202
Asynchronous EJB
23
Asynchronous Example: Client EJB
Enterprise
Java
@Stateless
public class AuctionMgmtEJB implements AuctionMgmtRemote, AuctionMgmtLocal {
public void workAsync(int count, long delay) {
DateFormat df = new SimpleDateFormat("HH:mm:ss.SSS");
long startTime = System.currentTimeMillis();
List<Future<Date>> results = new ArrayList<Future<Date>>();
for (int i=0; i<count; i++) {
log.info(String.format("%s issuing async request,
delay=%d", df.format(new Date()), delay));
Future<Date> date = actions.doWorkAsync(delay);
results.add(date);
log.info(String.format("async waitTime=%d msecs",
System.currentTimeMillis()-startTime));
}
for (Future<Date> f: results) {
log.info(String.format("%s getting async response",
df.format(new Date())));
try { Date date = f.get(); } catch (Exception ex) {
throw new EJBException("unexpected error in future.get():"+ex);}
log.info(String.format("%s got async response", df.format(new Date())));
}
long asyncTime = System.currentTimeMillis() - startTime;
log.info(String.format("workAsync time=%d msecs", asyncTime));
}
v141202
Asynchronous EJB
24
Enterprise
Java
Asynchronous Example: Helper EJB
@Stateless
public class AuctionMgmtActionEJB {
@javax.ejb.Asynchronous
public java.util.concurrent.Future<Date> doWorkAsync(long delay) {
DateFormat df = new SimpleDateFormat("HH:mm:ss.SSS");
log.debug(String.format("async method %d starting %d delay at %s",
Thread.currentThread().getId(), delay, df.format(new Date())));
try { Thread.sleep(delay); }
catch (Exception ex) { ... }
Date now = new Date();
log.debug(String.format("async method %d completed %d delay at %s",
Thread.currentThread().getId(), delay, df.format(now)));
return new javax.ejb.AsyncResult<Date>(now);
}
v141202
Asynchronous EJB
25
Asynchronous Example: Results
Enterprise
Java
11:06:53,650 INFO [AuctionMgmtEJB:325] 11:06:53.650 issuing async request, delay=3000
11:06:53,658 INFO [AuctionMgmtEJB:328] async waitTime=8 msecs
11:06:53,659 INFO [AuctionMgmtEJB:325] 11:06:53.659 issuing async request, delay=3000
11:06:53,659 DEBUG [AuctionMgmtActionEJB:41] async method 166 starting 3000 delay at 11:06:53.659
11:06:53,668 DEBUG [AuctionMgmtActionEJB:41] async method 167 starting 3000 delay at 11:06:53.668
11:06:53,668 INFO [AuctionMgmtEJB:328] async waitTime=18 msecs
11:06:53,669 INFO [AuctionMgmtEJB:325] 11:06:53.669 issuing async request, delay=3000
11:06:53,670 INFO [AuctionMgmtEJB:328] async waitTime=20 msecs
11:06:53,670 DEBUG [AuctionMgmtActionEJB:41] async method 168 starting 3000 delay at 11:06:53.670
11:06:53,671 INFO [AuctionMgmtEJB:331] 11:06:53.671 getting async response
11:06:56,667 DEBUG [AuctionMgmtActionEJB:47] async method 166 completed 3000 delay at
11:06:56,669 DEBUG [AuctionMgmtActionEJB:47] async method 167 completed 3000 delay at
11:06:56,669 INFO [AuctionMgmtEJB:339] 11:06:56.669 got async response
11:06:56,670 INFO [AuctionMgmtEJB:331] 11:06:56.670 getting async response
11:06:56,671 INFO [AuctionMgmtEJB:339] 11:06:56.671 got async response
11:06:56,672 DEBUG [AuctionMgmtActionEJB:47] async method 168 completed 3000 delay at
11:06:56,673 INFO [AuctionMgmtEJB:331] 11:06:56.672 getting async response
11:06:56,673 INFO [AuctionMgmtEJB:339] 11:06:56.673 got async response
11:06:56,674 INFO [AuctionMgmtEJB:342] workAsync time=3024 msecs
v141202
Asynchronous EJB
26
EJB Timers
Enterprise
Java
• Performs similar role of job schedulers
– “cron”
• Two types
– Single-action
• createTimer(Date expiration, Serializable info)
– fires once at or after a specific time in the future
• createTimer(long duration, Serializable info)
– fires once after a specific delay period
– Interval-timer
• createTimer(Date intialExpiration, long
intervalDuration, Serializable info)
– continually fires every intervalDuration after the
initialExpiration time
• createTimer(long initialDuration, long
intervalDuration, Serializable info)
– continually fires every intervalDuration after the
initialDuration delay
v141202
v111128
Asynchronous
EJB
Asynchronous EJB
2727
EJB Timers
Enterprise
Java
• Original EJB Timer Service part of EJB 2.1
• EJB 3.0 added annotation-based extensions that
eliminated inheritance-based solution requirements
• EJB 3.1 provided an overhaul of the overall service
– Added declarative scheduling
• @javax.ejb.ScheduleExpression
• @javax.ejb.Schedule
v141202
Asynchronous EJB
28
Declarative Calendar Timer
Enterprise
Java
@Schedule(second="*/10", minute ="*", hour="*",
dayOfMonth="*", month="*", year="*”, persistent=false)
public void execute(Timer timer) {
log.info("timer fired:" + timer);
try {
checkAuction();
}
catch (Exception ex) {
log.error("error checking auction", ex);
}
}
v141202
Asynchronous EJB
29
Programmatic Calendar Timer
Enterprise
Java
ScheduleExpression schedule = new ScheduleExpression();
schedule.second("*/10");
schedule.minute("*");
schedule.hour("*");
schedule.dayOfMonth("*");
schedule.month("*");
schedule.year("*");
auctionMgmt.initTimers(schedule);
public void initTimers(ScheduleExpression schedule) {
cancelTimers();
log.debug("initializing timers, schedule="+schedule);
timerService.createCalendarTimer(schedule);
}
@Timeout
public void execute(Timer timer) {
log.info("timer fired:" + timer);
try {
checkAuction();
}
catch (Exception ex) {
log.error("error checking auction", ex);
}
}
v141202
Asynchronous EJB
30
Programmatic Interval Timer
Enterprise
Java
auctionMgmt.initTimers(10*1000);
public void initTimers(long delay) {
cancelTimers();
log.debug("initializing timers, checkItemInterval="+delay);
timerService.createTimer(0,delay, "checkAuctionTimer");
}
@Timeout
public void execute(Timer timer) {
log.info("timer fired:" + timer);
try {
checkAuction();
}
catch (Exception ex) {
log.error("error checking auction", ex);
}
}
v141202
Asynchronous EJB
31
EJB Timers
Enterprise
Java
• Accessing TimerService
– Using Annotations
@Resource private TimerService timerService;
• Getting Timers
timerService.getTimers()
• Cancelling Timers
for (Timer timer :
(Collection<Timer>)timerService.getTimers()) {
timer.cancel();
}
• Timers
– associated with the EJB that created them
– are automatically integrated into JTA transaction
v141202
Asynchronous EJB
32
EJB Timer Callbacks
Enterprise
Java
• Using annotations
public class AuctionMgmtEJB ...
@Timeout
public void execute(Timer timer) {
try {
checkAuction();
}
catch (Exception ex) {
log.error("error checking auction", ex);
}
}
• Using interfaces
public class AuctionMgmtEJB implements TimedObject, ...
public void ejbTimeout(Timer timer) {
...
}
}
v141202
Asynchronous EJB
33
javax.ejb.TimerService
Enterprise
Java
public interface javax.ejb.TimerService{
javax.ejb.Timer createTimer(long, java.io.Serializable) throws ...;
javax.ejb.Timer createSingleActionTimer(long, javax.ejb.TimerConfig)
throws ...;
javax.ejb.Timer createTimer(long, long, java.io.Serializable) throws ...;
javax.ejb.Timer createIntervalTimer(long, long, javax.ejb.TimerConfig)
throws ...;
javax.ejb.Timer createTimer(java.util.Date, java.io.Serializable) throws ...;
javax.ejb.Timer createSingleActionTimer(java.util.Date, javax.ejb.TimerConfig)
throws ...;
javax.ejb.Timer createTimer(java.util.Date, long, java.io.Serializable)
throws ...;
javax.ejb.Timer createIntervalTimer(java.util.Date, long,javax.ejb.TimerConfig)
throws ...;
javax.ejb.Timer createCalendarTimer(javax.ejb.ScheduleExpression) throws ...;
javax.ejb.Timer createCalendarTimer(javax.ejb.ScheduleExpression,
javax.ejb.TimerConfig) throws ...;
java.util.Collection getTimers() throws ...;
}
v141202
Asynchronous EJB
34
Summary
Enterprise
Java
• EJB JMS Publishers
– integrates into Session and MDB processing
• EJB JMS Subscriber
– implemented using MDB
– MDBs support more than JMS using JCA
• Asynchronous Methods
• EJB Timers
– schedule re-activation of Session Bean
– Single-action and interval
v141202
v111128
Asynchronous
EJB
Asynchronous EJB
3535
References
Enterprise
Java
• Java Messaging Service API
– http://java.sun.com/javaee/5/docs/api/javax/jms/packagesummary.html
• “Enterprise JavaBeans 3.0, 5th Edition”; Burke &
Monsen-Haefel; ISBN 0-596-00978-X; O'Reilly
v141202
Asynchronous EJB
36
Download