The publish-and-subscribe architecture can be useful in keeping track of the availability of individuals. In this recipe, we will develop an application that uses a topic to monitor and record when a person is available. That is, when a person is at his/her desk, logged on to a computer or otherwise able to respond to requests.
A topic is similar to a queue. Messages are sent to a topic just as they are sent to a queue. However, once there they may be accessed by more than one consumer. The essential structure of a servlet used to generate a message was introduced in the introduction. Here we will address the unique elements of creating and using a topic to support a publish-and-subscribe application which include:
Create a Topic
named jms/AvailabilityTopic
and a TopicConnectionFactory
named jms/AvailabilityFactoryPool
as described in the introduction. Next, create a new Java EE application called PublishAndSubscribeApplication
. In the EJB module add a package called packt
and three classes:
Availability
a simple Java class representing the availability of an individualLoggingBean
an MDB that logs a person's availabilitySubscriberBean
an MDB that may be interested in whether someone is available or notIn the WAR module add a package called servlet
with a servlet called AvailabilityServlet
.
The Availability
class associates a name with that person's availability. It consists of a string variable for a name and a Boolean variable to indicate whether they are available or not. The class must implement the Serializable
interface otherwise the object cannot be sent as part of a message.
import java.io.Serializable; public class Availability implements Serializable { private String name; private boolean available; public Availability(String name, boolean available) { this.name = name; this.available = available; } public boolean isAvailable() { return available; } public String getName() { return name; } }
Next, create the AvailabilityServlet
as listed below. The doGet
and doPost
methods are not shown.
public class AvailabilityServlet extends HttpServlet { private Availability availability; @Resource(mappedName="jms/AvailabilityFactoryPool") private TopicConnectionFactory topicConnectionFactory; @Resource(mappedName="jms/AvailabilityTopic") private Topic topic; protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); try { Connection connection; availability = new Availability("Tom",true); try { connection = topicConnectionFactory.createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer messageProducer = (MessageProducer) session.createProducer(topic); ObjectMessage availabilityMessage = session.createObjectMessage(availability); availabilityMessage.setStringProperty("test", "tested"); messageProducer.send(availabilityMessage); System.out.println("---> availability status sent"); } catch (JMSException ex) { Logger.getLogger(AvailabilityServlet.class.getName()). log(Level.SEVERE, null, ex); } out.println("<html>"); Message-Driven Bean (MDB)using, in publish-and-subscribe applicationout.println("<head>"); out.println("<title>Servlet AvailabilityServlet</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Servlet AvailabilityServlet at " + request.getContextPath () + "</h1>"); out.println("</body>"); out.println("</html>"); } finally { out.close(); } }
We will use two MDBs. The LoggingBean
EJB logs an individual's availability for later analysis. The SubscriberBean
EJB listens to the messages and indicates it has received the message.
Add the LoggingBean
as follows:
@MessageDriven(mappedName = "jms/AvailabilityTopic", activationConfig = { @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"), @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"), @ActivationConfigProperty(propertyName = "subscriptionDurability", propertyValue = "Durable"), @ActivationConfigProperty(propertyName = "clientId", propertyValue = "LoggingBean"), @ActivationConfigProperty(propertyName = "subscriptionName", propertyValue = "LoggingBean") }) public class LoggingBean implements MessageListener { public LoggingBean() { } public void onMessage(Message message) { Message-Driven Bean (MDB)using, in publish-and-subscribe applicationObjectMessage objectMessage = (ObjectMessage) message; try { Availability availability = (Availability) objectMessage.getObject(); if(availability.isAvailable()) { Logger.getLogger(LoggingBean.class.getName()). log(Level.SEVERE, availability.getName() + " is available"); } else { Logger.getLogger(LoggingBean.class.getName()). log(Level.SEVERE, availability.getName() + " is not available"); } System.out.println("---> logging "); } catch (JMSException ex) { Logger.getLogger(LoggingBean.class.getName()). log(Level.SEVERE, null, ex); } } }
Create the SubscriberBean
next.
@MessageDriven(mappedName = "jms/AvailabilityTopic", activationConfig = { @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"), @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"), @ActivationConfigProperty(propertyName = "subscriptionDurability", propertyValue = "Durable"), @ActivationConfigProperty(propertyName = "clientId", propertyValue = "SubscriberBean"), @ActivationConfigProperty(propertyName = "subscriptionName", propertyValue = "SubscriberBean") }) public class SubscriberBean implements MessageListener { public SubscriberBean() { } public void onMessage(Message message) { System.out.println("---> subscriber "); } }
Execute the AvailabilityServlet
. You will observe the following output in the console window:
INFO: ---> availability status sent
INFO: ---> subscriber
SEVERE: Jonathan is available
INFO: ---> logging
The AvailabilityServlet
created a message that was sent to a topic. The @Resource annotation injected a TopicConnectionFactory
and a Topic
. This chapter's introduction discusses the process for establishing a connection to a queue. The approach is essentially the same for a topic except a topic is used instead of a queue.
Notice how the Availability
object was created and sent. An ObjectMessge
was used for the message and is discussed in the Handling an object-based message recipe earlier in this chapter.
The LoggingBean
is responsible for maintaining a log of the availability of individuals. The @MessageDriven annotation used the mappedName attribute to specify the topic used. Two @ActivationConfigProperty elements were used to specify the acknowledgement mode and that the destination was a topic. In addition, three other @ActivationConfigProperty elements were set for the topic:
subscriptionDurability
DurableclientId LoggingBean
subscriptionName LoggingBean
A durable message is held in the topic temporarily if the subscriber happens to become temporarily unavailable. It is sent to the subscriber once the subscriber is able to receive the message. However, it is necessary for the subscriber to register with the topic using a unique clientId
and subscriptionName
as affected by the @ActivationConfigProperty annotation.
The onMessage
method retrieved the Availability
object and used the isAvailable
method to determine whether the individual was available or not. It then logged a message to that effect.
The SubscriberBean
represents an individual or entity that is interested in knowing whether someone is available or not. Its @MessageDriven annotation is similar to the LoggingBean
. The onMessage
implementation simply displayed a message indicating the subscriber has handled the message.
3.144.82.21