17 - Case Study - Library Book Reservation Web Service

Introduction

In this chapter, we are going to make a case study to illustrate the use of the previously explained chapters. The case study will cover the following points:

  • Stateless Session Beans
  • JAX-WS Web Services
  • JAX-RS Web Services
  • Transaction Management
  • Message Driven Beans
  • Web Components as EJB client

Problem Definition

We need to create a system that can handle the related operations for books reservations in a library. The system should integrate with an existing system in the library that manages the visitor information and also the system should have a web interface that displays all books and their reservation status. The system should expose the core functions as REST web service and also XML based web service for other systems to be able to integrate with our system.

System Design

Our design of the system will involve creating a stateless session bean to handle the application business logic.

The bean will use JDBC interfaces to access the backend database and also JTA transaction management for managing application transactions.

The bean will be exposed as JAX-WS web service and also as JAX-RS web service.

A topic will be created for the events related to books reservation status change. The system will read from a topic related to the visitors system to sync the visitors’ data with the other system through a Message Driven Bean.

A web component will be used to expose the web page that prints the books reservation status and also will expose a function to reserve a book providing the visitor name who will reserve the book and the reservation end date.

The following diagram presents high level system design:

      

Database Design

Our database design for the problem will consist of 4 tables, one for the visitors’ data that will be retrieved from the visitors’ management system (existing system in the library), the 2nd table will hold the library books information, the 3rd one will contain the books reservation data as a relation between the visitors and the books tables, the final table is the application action logs which will log all actions done by the system, the database will look like the following:

      

 

The database diagram will look like the following:

System Use Cases

Add a Book: Adding a new book to the application database, the action should insert a record in the book table and also a record with the action in the action table.

Remove a Book: Marking a book as removed from the database, the book shouldn’t be displayed anywhere in the system once marked as removed.

Get All Books: The action will be used by the web services and also the web interface to display all the stored books in the application database.

Reserve a Book: Providing a visitor Id and expiry date, the system should create a reservation record for a book to the visitor that should expire after 7 days from the reservation date.

Add Visitor: The action will  be triggered by a request on the Visitors System JMS Topic and a in the action, a record should be inserted in the visitor table, the Visitor System will be running on a JBOSS AS.

JBOSS Configuration

Now, the 1st thing that we need to do for developing our application is to configure the server, that our application will be deployed on. As per the problem definition and the application use cases, all that we will need from the server, to expose to our application, is a DataSource with a connection pool to the application database, which is MySQL database using the following configuration lines (standalone-full.xml). You can also refer back to chapter 2 for more details on how you can create a database on MySQL database and  configure a DataSouce on JBOSS to connect to the database. The following lines will be used:

<datasource jta="true" jndi-name="java:/BookResDB" pool-name=" BookResDB" enabled="true" use-ccm="false">
    <connection-url>jdbc:mysql://localhost:3306/ ejb_app_1_db</connection-url>
    <driver-class>com.mysql.jdbc.Driver</driver-class>
    <driver>mysql-connector-java-5.1.30-bin.jar_com.mysql.jdbc.Driver_5_1</driver>    <security>
        <user-name>root</user-name>
    </security>
    <validation>
        <validate-on-match>false</validate-on-match>
        <background-validation>false</background-validation>
    </validation>
    <statement>
        <share-prepared-statements>false</share-prepared-statements>
    </statement>
</datasource>

You will also need to configure JBOSS to start using the standalone-full.xml file instead of the default standalone.xml file. You can do that by starting JBOSS using the following command: ./standalone.sh --server-config=standalone-full.xml

In case of using Eclipse IDE, you can choose to change the file standalone.xml to be standalone-full.xml during the Server adding wizard. For more information on this refer back to chapter 2.

Coding the Code Module

Now let us use Eclipse IDE to start writing our application source code, prepare a new environment for the application and add JBOSS server configured with the standalone-full.xml file to our environment servers.

As our application will contain only one web module and only one EJB module, instead of creating an EAR project and adding the EJB project and web project to the EAR, we can use only one web module as the application wrapper and add our EJB beans and the web beans to the same project. This is valid only in JEE 7.

From the package explorer in Eclipse IDE, right click with the mouse, then select New -> Dynamic Web Project.

   

Set the project Name as BookReservationWeb, web module version as 3.1 and then click finish.

        

Now our environment contains a configured JBOSS server and a web module called BookReservationWeb.

      

Now let us create the core module that will handle all the application logic and will play as a wrapper for all the database operations too. We can separate the business logic from database direct actions, but as our logic and database operations are simple, both will be combined in the same layer.

Our core logic will be included in a Stateless Session bean with Container Managed Transactions. As the problem definition stated that the core application actions should be exposed as RESTfull web service and also as XML based web service, the session bean will be exposed as RESTfull web service using the JAX-RS API and the JAX-WS API.

In Eclipse IDE, from the package explorer view, select the web module and right click with the mouse, select New, and then Other.

From the Dialog Box select Session Bean (EJB 3.x).

        

From the “Create EJB 3.x Session Bean” dialog, set the bean package as “com.bookreservation.ejb” and the bean name as “AppLogic”, keep the rest as is and then click Finish.

    

Modify the default code generated by Eclipse to be as follows:

    

package com.bookreservation.ejb;

import java.util.List;

import javax.annotation.Resource;
import javax.ejb.LocalBean;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.sql.DataSource;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;

import org.jboss.logging.Logger;

@Stateless
@LocalBean
@Path("/logic")
@WebService
public class AppLogic {

      private static final Logger logger = Logger.getLogger(AppLogic.class);

      @Resource(name = "java:/BookResDB")
      private DataSource bookResDB;

      @Resource
      SessionContext context;

      public AppLogic() {

      }
      @GET
    @Path("addBook")
    @WebMethod
    public void addBook(
            @WebParam(name = "title") @QueryParam("title") String title)
            throws Exception {
    }
    @GET
    @Path("removeBook")
    @WebMethod
    public void removeBook(
            @WebParam(name = "title") @QueryParam("title") String title)
            throws Exception {
    }
    @GET
    @Produces("application/json")
    @Path("getAllBooks")
    @WebMethod
    public List<String> getAllBooks() throws Exception {
        return null;
    }
    @GET
    @Path("reserveBook")
    @WebMethod
    public void reserveBook(
            @WebParam(name = "bookTitle") @QueryParam("bookTitle") String bookTitle,
            @WebParam(name = "visitor") @QueryParam("visitor") String visitor)
            throws Exception {
    }
    @GET
    @Path("addVisitor")
    @WebMethod
    public void addVisitor(
            @WebParam(name = "visitorId") @QueryParam("visitorId") int visitorId,
            @WebParam(name = "visitorName") @QueryParam("visitorName") String visitorName)
            throws Exception {
    }
}

The code was modified to declare the bean as web service using the annotation @WebService, and also was declared as RESTful web service using the annotation @Path. The methods were also annotated with the annotation @WebMethod to be declared as web service method and  with @GET to be declared as a service for HTTP GET request.

The method parameters were annotated with @WebParam to override the default generated name in the WSDL file, and also annotated with @QueryParam to be bound to an HTTP parameter when serving HTTP GET requests.

Also the bean injects a resource that will represent the database data source and pool configured in JBOSS standalone-full.xml file.

Now, as the bean will be exposed as RESTful web service and also as XML web service, we need to expose an Exception mapper provider for the RESTful web service to map the produced Exceptions to JSON object format. As the XML web service can map by default the Exception object and convert them to XML format, no special exception mapper will be provided for the XML web service. Create a new class under package com.bookreservation called RestExceptionMapper with the following code:

package com.bookreservation;

import javax.json.Json;
import javax.json.JsonObjectBuilder;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

@Provider
public class RestExceptionMapper implements ExceptionMapper<Exception> {
    public Response toResponse(Exception e) {
        JsonObjectBuilder json = Json.createObjectBuilder();
        json.add("error", e.getMessage());
        return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                .entity(json.build().toString()).type("application/json")
                .build();
    }
} 

You will note that eclipse will complain about the package javax.json (i.e. JsonObjectBuilder), you can fix that by adding an external Jar to the web project. The jar will be located at: JBOSS_HOME/modules/system/layers/base/org/glassfish/javax/json/main/javax.json-1.0.3.jar

The 3nd step here is to add a REST application class that will make the classes to be  treated as REST web service (i.e. AppLogic bean). Add a Java class to the project called RestApplication inside the package com.bookreservation and override the default generated code with the following:

package com.bookreservation;

import java.util.HashSet;
import java.util.Set;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

import com.bookreservation.ejb.AppLogic;

@ApplicationPath("/rest")
public class RestApplication extends Application {
    @Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> classes = new HashSet<Class<?>>();
        classes.add(AppLogic.class);
        classes.add(RestExceptionMapper.class);
        return classes;
    }
}

The class will declare a REST package under path “/rest” and will contain only one restful web service class AppLogic, will listen to path /rest/logic and has an exception mapper called RestExceptionMapper.

Now let us modify the web application configuration by adding the support of JAX-RS 1.1 like the following:

              

Now you will see that eclipse displays a list of the all exposed REST web services requests as  declared in the AppLogic bean:

           

Also, you will find that Eclipse has detected the JAX-WS interface provided by the AppLogic bean class:

             

Now, let us implement  the 1st method (addBook) of our AppLogic bean class.The method takes one parameter - book title, adds the book in the database book table and sets an action log with the action description. By default the method will use the called transaction if  any or will start a new transaction if no transaction was started by the client. This is the default transaction type, also is equals to @TransactionAttribute(TransactionAttributeType.REQUIRED) annotation;

The code for the method  will be as follows:

@GET
@Path("addBook")
@WebMethod
public void addBook(
        @WebParam(name = "title") @QueryParam("title") String title)
        throws Exception {
    try (Connection con = bookResDB.getConnection();
            PreparedStatement addBookSt = con
                    .prepareStatement("insert into book (title) values (?)");
            PreparedStatement logActionSt = con
                    .prepareStatement("insert into action_log (description) values (?)")) {
        addBookSt.setString(1, title);
        addBookSt.executeUpdate();
        logActionSt.setString(1, "Book Added [" + title + "]");
        logActionSt.executeUpdate();
    } catch (Exception e) {
        logger.error("Failed to add book record", e);
        context.setRollbackOnly();
        throw e;
    }
} 

The method declares a connection object and 2 prepared statements, one for the book insertion and the other for the action log insertion.  In case of failure, the method logs the error and then marks the transaction as rolled back, then propagates the exception object to the caller.

The method removeBook will look like the following:

@GET
@Path("removeBook")
@WebMethod
public void removeBook(
        @WebParam(name = "title") @QueryParam("title") String title)
        throws Exception {
    try (Connection con = bookResDB.getConnection();
            PreparedStatement rmBookSt = con
                    .prepareStatement("remove from book where title = ?");
            PreparedStatement logActionSt = con
                    .prepareStatement("insert into action_log (description) values (?)")) {
        rmBookSt.setString(1, title);
        rmBookSt.executeUpdate();
        logActionSt.setString(1, "Book Removed [" + title + "]");
        logActionSt.executeUpdate();
    } catch (Exception e) {
        logger.error("Failed to add remove record", e);
        context.setRollbackOnly();
        throw e;
    }
}

Following the same guidelines, the method getAllBooks, reserveBook, addVisitor will look like the following:

@GET
@Produces("application/json")
@Path ("getAllBooks")
@WebMethod
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public List<String> getAllBooks() throws Exception {
    try (Connection con = bookResDB.getConnection();
            PreparedStatement getBooksSt = con
                    .prepareStatement("select title from book")) {
        ResultSet resultSet = getBooksSt.executeQuery();
        ArrayList<String> res = new ArrayList<String>();
        while (resultSet.next()) {
            res.add(resultSet.getString("TITLE"));
        }
        return res;
    } catch (Exception e) {
        logger.error("Failed to get books records", e);
        throw e;
    }
}

@GET
@Path("reserveBook")
@WebMethod
public void reserveBook(
        @WebParam(name = "bookTitle") @QueryParam("bookTitle") String bookTitle,
        @WebParam(name = "visitor") @QueryParam("visitor") String visitor)
        throws Exception {
    try (Connection con = bookResDB.getConnection();
            PreparedStatement resBookSt = con
                    .prepareStatement("insert into book_reservation "
                            + "(book_id, visitor_id, reservation_date, expiration_date) values ("
                            + "(select id from book where title = ?), (select id from "
                            + "visitor where full_name = ?), now(), now() + INTERVAL 2 DAY)");
            PreparedStatement logActionSt = con
                    .prepareStatement("insert into action_log (description) values (?)")) {
        resBookSt.setString(1, bookTitle);
        resBookSt.setString(2, visitor);
        resBookSt.executeUpdate();
        logActionSt.setString(1, "Book [" + bookTitle
                + "] reserved for visitor [" + visitor + "]");
        logActionSt.executeUpdate();
    } catch (Exception e) {
        logger.error("Failed to add book reservation record", e);
        context.setRollbackOnly();
        throw e;
    }
}

@GET
@Path("addVisitor")
@WebMethod
public void addVisitor(
        @WebParam(name = "visitorId") @QueryParam("visitorId") int visitorId,
        @WebParam(name = "visitorName") @QueryParam("visitorName") String visitorName)
        throws Exception {
    try (Connection con = bookResDB.getConnection();
            PreparedStatement addVisitorSt = con
                    .prepareStatement("insert into visitor (id, full_name) values (?, ?)");
            PreparedStatement logActionSt = con
                    .prepareStatement("insert into action_log (description) values (?)")) {
        addVisitorSt.setInt(1, visitorId);
        addVisitorSt.setString(2, visitorName);
        addVisitorSt.executeUpdate();
        logActionSt.setString(1, "Visitor Added [id = " + visitorId
                + ", name = " + visitorName + "]");
        logActionSt.executeUpdate();
    } catch (Exception e) {
        logger.error("Failed to add visitor record", e);
        context.setRollbackOnly();
    }
}

Only one note in the above code that needs to be mentioned, the use of annotation @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) in the method getAllBooks. As the method contains only 1 SQL statement, there is no need to open a transaction for the method to increase the method execution performance.

Now let us test our core module before we start creating the web interface. What we have till now are  the core functions, XML interface and RESTful interface for the functions.

Make sure, you have created the database and configured JBOSS data source. Deploy the web module to JBOSS and using SoupUI start JBOSS. You should see lines like the following in your console view:

        

If you saw such lines, then your deployment was successful. Now let us test our core function using SoupUi for the XML interface and DHC (Dev HTTP Client) Chrome plugin.

In SoupUI, create a new project for the WSDL: http://localhost:8080/BookReservationWeb/AppLogic?WSDL   and change the IP and port to be your JBOSS IP and port. The project will create a client for 5 methods:

    

Now, let us test the 1st method, addBook:

        

Testing getAllBooks:

      

Now let us test the same methods but from the RESTful interface, using DHC plugin of Chrome browser, the method addBook:

    

 The method getAllBooks:

      

  

Coding the Web Module

Now let us develop the web module that will expose the core functions into a web interface. The module will be developed using JSF2 technology that is part of the JEE 7 technologies.

In Eclipse, add the JSF2 facet to our web module, right click on the project in the project explorer and select Configure, then “Add JSF Capabilities”. Make sure that JSF 2.2 is checked and click “OK”

Now we need to create a new XHTML page and a Backing Bean that will display a list of the available books in the library with the status of each book. The problem is that the only available method in the application core login module can only retrieve a list of the books but not the books reservation status. So let us modify this:

In the package com.bookreservation.ejb, add a new class called “Book”  with the following code:

package com.bookreservation.ejb;

public class Book {

    private String title;
    private String reservationStatus;

    public Book(String title, String reservationStatus) {
        this.title = title;
        this.reservationStatus = reservationStatus;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getReservationStatus() {
        return reservationStatus;
    }
    public void setReservationStatus(String reservationStatus) {
        this.reservationStatus = reservationStatus;
    }
}

Now we will modify the method AppLogin.getAllBooks to instead of retrieving a list of  strings that hold the books names, it will return a list of Book models that hold the book name and the book reservation status. The method code will look like the following:

@GET
@Produces("application/json")
@Path("getAllBooks")
@WebMethod
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public List<Book> getAllBooks() throws Exception {
    try (Connection con = bookResDB.getConnection();
            PreparedStatement getBooksSt = con
                    .prepareStatement("select title, (case when (select count(1) "
                            + "from book_reservation where book_id = book.id) = 0 "
                            + "then 'Free' Else 'Reserved' End) RES_STATUS from book order by title")) {
        ResultSet resultSet = getBooksSt.executeQuery();
        ArrayList<Book> res = new ArrayList<Book>();
        while (resultSet.next()) {
            res.add(new Book(resultSet.getString("TITLE"), resultSet
                    .getString("RES_STATUS")));
        }
        return res;
    } catch (Exception e) {
        logger.error("Failed to get books records", e);
        throw e;
    }
}

Deploy the project and use SoupUI to test the getAllBooks method. The following response should be produced.

       

When using DHC to test the method again, the following response should be produced

         

As this is done, let us create the XHTML page and the Backing Bean. Right click on the project in the project explorer view, select to create a new class under package com.bookreservation.web. The new class name will be WebBean with the following code:  

package com.bookreservation.web;

import java.util.List;

import javax.ejb.EJB;
import javax.faces.bean.RequestScoped;

import com.bookreservation.ejb.AppLogic;
import com.bookreservation.ejb.Book;

@ManagedBean(name="webBean")
@RequestScoped
public class WebBean {

    @EJB
    private AppLogic logic;

    public List<Book> getBooks() {
        try {
            return logic.getAllBooks();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

The code simply declares a RequestScoped backing bean that has only one method called getBooks that calls the method getAllBooks from the injected EJB object “logic”.    

For the XHMTL page, right click on the web project in the project explorer view, select New, then XHMTL Page, set the file name as index.xhtml and click “Finish”.  Change the default generated code to be as follows:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html">
    <h:head>
       <title>Book Library</title>
       <style>.w100p { width:100%; } .col2 { width:150px; }</style>
    </h:head>
    <h:body>
      <h3>Library Books</h3>
      <h:dataTable id="booksTable" value="#{webBean.books}" 
         var="book" styleClass="w100p" style="text-align: left;" columnClasses="none, col2">
        <h:column >
            <f:facet name="header"><h:outputLabel value="Book Title" /></f:facet>
            <h:outputText value="#{book.title}" />
        </h:column>
        <h:column>
            <f:facet name="header"><h:outputLabel value="Reservation Status" /></f:facet>
            <h:outputText value="#{book.reservationStatus}" />
        </h:column>
      </h:dataTable>
    </h:body>
</html>

Deploy the project again and in your browser type the following URL: http://localhost:8080/BookReservationWeb/faces/index.xhtml where localhost and 8080 are your Server IP and Server Port. You are supposed to see the following on your browser page:

     

Now adding the book reservation feature from the web module, for this we will need to display a list with available “free” books and another one with available visitors. As both methods do not exist in our application core login bean, let us add them. Add the following 2 methods in our AppLogin bean:

@GET
@Produces("application/json")
@Path("getFreeBooks")
@WebMethod
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public List<String> getFreeBooks() throws Exception {
    try (Connection con = bookResDB.getConnection();
            PreparedStatement getBooksSt = con
                    .prepareStatement("select title from book where (select count(1) "
                            + "from book_reservation where book_id = book.id) = 0 order by title")) {
        ResultSet resultSet = getBooksSt.executeQuery();
        ArrayList<String> res = new ArrayList<String>();
        while (resultSet.next()) {
            res.add(resultSet.getString("TITLE"));
        }
        return res;
    } catch (Exception e) {
        logger.error("Failed to get free books records", e);
        throw e;
    }
}
@GET
@Produces("application/json")
@Path("getVisitors")
@WebMethod
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public List<String> getVisitors() throws Exception {
    try (Connection con = bookResDB.getConnection();
            PreparedStatement getBooksSt = con
                    .prepareStatement("select full_name from visitor order by full_name")) {
        ResultSet resultSet = getBooksSt.executeQuery();
        ArrayList<String> res = new ArrayList<String>();
        while (resultSet.next()) {
            res.add(resultSet.getString("FULL_NAME"));
        }
        return res;
    } catch (Exception e) {
        logger.error("Failed to get visitors records", e);
        throw e;
    }
}

Method getFreeBooks will get non reserved books and method getVisitors will get the added visitors in our database.

In the backing bean “WebBean” add the following 2 methods:

public List<String> getFreeBooks() {
    try {
        return logic.getFreeBooks();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}
public List<String> getVisitors() {
    try {
        return logic.getVisitors();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}
public void reserveBook(String bookTitle, String visitor) {
    try {
        logic.reserveBook(bookTitle, visitor);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Now, let us modify our index.xhtml page again to add a form to reserve books from:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html">
<h:head>
    <title>Book Library</title>
    <style>.w100p { width:100%; } .col2 { width:150px; }</style>
</h:head>
<h:body>
    <h3>Library Books</h3>
    <h:dataTable id="booksTable" value="#{webBean.books}" 
        var="book" styleClass="w100p" style="text-align: left;" columnClasses="none, col2">
        <h:column >
            <f:facet name="header"><h:outputLabel value="Book Title" /></f:facet>
            <h:outputText value="#{book.title}" />
        </h:column>
        <h:column>
            <f:facet name="header"><h:outputLabel value="Reservation Status" /></f:facet>
            <h:outputText value="#{book.reservationStatus}" />
        </h:column>
    </h:dataTable>
    <h:form>
        <h:panelGrid columns="2">
            <h:outputLabel value="Book Title" />
            <h:selectOneMenu value="#{bookTitle}">
                <f:selectItems value="#{webBean.freeBooks}" var="book" itemLabel="#{book}" itemValue="#{book}" />
            </h:selectOneMenu>
            <h:outputLabel value="Visitor" />
            <h:selectOneMenu value="#{visitor}">
                <f:selectItems value="#{webBean.visitors}" var="visitor" itemLabel="#{visitor}" itemValue="#{visitor}" />
            </h:selectOneMenu>
        </h:panelGrid>
        <h:commandButton action="#{webBean.reserveBook(bookTitle, visitor)}" value="Reserve" />
    </h:form>
</h:body>
</html>

When running the application again, you should see the following on the browser screen:

        

Select book “EJB3 Book #2” and Visitor “Visitor #1” and click “Reserve” button, the books table should be modified as follows:

     

Book #2 status changed from Free to Reserved.

Visitors System Integration

It is assumed that the visitors system is already deployed on the same Wildfly instance and the system topic already configured in the standalone-full.xml file as follows:

<jms-topic name="visitorsTopic">
    <entry name="topic/visitorsTopic"/>
    <entry name="java:jboss/exported/jms/topic/visitorsTopic"/>
</jms-topic>

Also the creation action is communicated in the message, formatted in a JSON format (i.e. {“id”:”10”, “name”:”someone name”}) Our MDB will look like the following:

package com.bookreservation.ejb;

import java.io.StringReader;

import javax.ejb.ActivationConfigProperty;
import javax.ejb.EJB;
import javax.ejb.MessageDriven;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonReader;

@MessageDriven(activationConfig = {
        @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
        @ActivationConfigProperty(propertyName = "destination", propertyValue = "topic/visitorsTopic") })
public class VisitorsMDB implements MessageListener {

      @EJB
      private AppLogic logic;

      @Override
    public void onMessage(Message message) {
        TextMessage textMessage = (TextMessage) message;
        try {
            System.out.println("Message Received [" + textMessage.getText()
                    + "]");
            JsonReader reader = Json.createReader(new StringReader(
                    textMessage.getText()));
            JsonObject personObject = reader.readObject();
            int id = personObject.getInt("id");
            String name = personObject.getString("name");
            reader.close();
            logic.addVisitor(id, name);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

Like us on Facebook