03 - Let us say Hello in EJB: Page 6 of 6

As noted, Eclipse complains about the class ActionLogDescription and that is because  the Table ActionLogDescription has no primary key defined. We can easily fix that by adding the annotation @Id on the field “actionLogId”, the 2 new entities should be as follows:

package com.test.hello;

import java.io.Serializable;
import javax.persistence.*;
import java.util.Date;

/**
 * The persistent class for the action_log database table.
 * 
 */
@Entity
@Table(name="action_log")
@NamedQuery(name="ActionLog.findAll", query="SELECT a FROM ActionLog a")
public class ActionLog implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name="action_time")
    private Date actionTime;

    private String username;
    public ActionLog() {
    }
    public int getId() {
        return this.id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public Date getActionTime() {
        return this.actionTime;
    }
    public void setActionTime(Date actionTime) {
        this.actionTime = actionTime;
    }
    public String getUsername() {
        return this.username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
} 
package com.test.hello;

import java.io.Serializable;
import javax.persistence.*;

/**
 * The persistent class for the action_log_descripton database table.
 * 
 */
@Entity
@Table(name="action_log_descripton")
@NamedQuery(name="ActionLogDescripton.findAll", query="SELECT a FROM ActionLogDescripton a")
public class ActionLogDescripton implements Serializable {
    private static final long serialVersionUID = 1L;

@Id
    @Column(name="action_log_id")
    private int actionLogId;

    private String description;

    public ActionLogDescripton() {
    }
    public int getActionLogId() {
        return this.actionLogId;
    }
    public void setActionLogId(int actionLogId) {
        this.actionLogId = actionLogId;
    }
    public String getDescription() {
        return this.description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
}

There may be some differences between mine and yours, but no worry about that.

Now, open the file persistence.xml and add the following line below the HelloEJB persistent unit:

<jta-data-source>java:/TestEJB3DS</jta-data-source>
   

So the final XML in the file should be as follows:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="HelloEJB" transaction-type="JTA">
        <jta-data-source>java:/TestEJB3DS</jta-data-source>
        <class>com.test.hello.ActionLog</class>
        <class>com.test.hello.ActionLogDescripton</class>
    </persistence-unit>
</persistence>

Now we will modify our web service to insert an ActionLog and ActionLogDescription records into the database in each method request. For doing that we will create a common method to be used in all web service methods. The method will be as follows:

private void doLogAction(String description) {
    ActionLog log = new ActionLog();
    log.setActionTime(new Date());
    log.setUsername(ctx.getCallerPrincipal().getName());
    entityManager.persist(log);
    ActionLogDescripton desc = new ActionLogDescripton();
    desc.setActionLogId(log.getId());
    desc.setDescription(description);
    entityManager.persist(desc);
}

As noted, the method uses 2 new fields “ctx” and “entityManager”.They should be declared in the web services as follows:

@Resource
private SessionContext ctx;

@PersistenceContext
private EntityManager entityManager;

The method doLogAction will be called with every web services method as follows:

     doLogAction("fromUSDtoGBP(amount=" + amount + ")");

So the final web service code till now will be as follows:

package com.test.hello;

import java.util.Date;

import javax.annotation.Resource;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.RolesAllowed;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.jboss.ejb3.annotation.SecurityDomain;
import org.jboss.ws.api.annotation.WebContext;

@SecurityDomain("HelloWS")
@Stateless
@WebService(serviceName = "HelloService")
@WebContext(authMethod = "BASIC", urlPattern = "/*", secureWSDLAccess = false)
@DeclareRoles({ "CLIENT", "FROM_USD_TO_GBP", "FROM_GBP_TO_USD",
        "FROM_USD_TO_EURO", "FROM_EURO_TO_USD" })

@RolesAllowed("CLIENT")
public class HelloWebService {
 
    @Resource
    private SessionContext ctx;
    @PersistenceContext
    private EntityManager entityManager;
    @RolesAllowed("CLIENT")
    public void ping() {

    }

    private void doLogAction(String description) {
        ActionLog log = new ActionLog();
        log.setActionTime(new Date());
        log.setUsername(ctx.getCallerPrincipal().getName());
        entityManager.persist(log);
        ActionLogDescripton desc = new ActionLogDescripton();
        desc.setActionLogId(log.getId());
        desc.setDescription(description);
        entityManager.persist(desc);
    } 
    @WebMethod
    @RolesAllowed("FROM_USD_TO_GBP")
    public double fromUSDtoGBP(@WebParam(name = "amount") double amount) {
        doLogAction("fromUSDtoGBP(amount=" + amount + ")");
        return amount * 0.60;
    }
    @WebMethod
    @RolesAllowed("FROM_GBP_TO_USD")
    public double fromGBPtoUSD(@WebParam(name = "amount") double amount) {
        doLogAction("fromGBPtoUSD(amount=" + amount + ")");
        return amount / 0.60;
    }
    @WebMethod
    @RolesAllowed("FROM_USD_TO_EURO")
    public double fromUSDtoEURO(@WebParam(name = "amount") double amount) {
        doLogAction("fromUSDtoEURO(amount=" + amount + ")");
        return amount * 0.72;
    }
    @WebMethod
    @RolesAllowed("FROM_EURO_TO_USD")
    public double fromEUROtoUSD(@WebParam(name = "amount") double amount) {
        doLogAction("fromEUROtoUSD(amount=" + amount + ")");
        return amount / 0.72;
    }
}

Now republish the EAR again as explained in the “Security Adding” section. Try testing the web service methods again using SoapUI, check the tables action_log and action_log_descripton. It is supposed that you find records inserted in the 2 tables reflecting the actions done by SoapUI on the web service methods.

The final step in our HelloEJB application is the database transaction management.

Adding Database Transaction Management

Transaction management is the process of preventing the database to persist incomplete scenarios, in our application a full scenario is to save 2 records in each access to the web service, one in the action_log table and the other in the action_log_description table. In case only the 1st record gets saved and the other one failed, this is considered a incomplete scenario, we are going to do that using the JEE provided annotations for database transaction management.

For all the web service methods we are going to annotate the method with the following annotation:

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) 

The annotation means that we need to start a new transaction before starting the method execution and to commit the results once the method execution finishes successfully with no exceptions.

Now in case and for any reason, the first record insertion “action_log” succeedes and the 2nd one “action_log_description” fails, both insertion will get rollback.

In case you wanted to test that, you can easily modify the line:

    desc.setDescription(description);

And replace the description variable with a string of length more than 500 characters, that will cause MySQL to reject the insertion and the whole transaction will get rolledback.

So the final code of our web service will look like the following:

package com.test.hello;

import java.util.Date;

import javax.annotation.Resource;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.RolesAllowed;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.jboss.ejb3.annotation.SecurityDomain;
import org.jboss.ws.api.annotation.WebContext;

@SecurityDomain("HelloWS")
@Stateless
@WebService(serviceName = "HelloService")
@WebContext(authMethod = "BASIC", urlPattern = "/*", secureWSDLAccess = false)
@DeclareRoles({ "CLIENT", "FROM_USD_TO_GBP", "FROM_GBP_TO_USD",
        "FROM_USD_TO_EURO", "FROM_EURO_TO_USD" })
@RolesAllowed("CLIENT")
public class HelloWebService {

    @Resource
    private SessionContext ctx;

    @PersistenceContext
    private EntityManager entityManager;

    @RolesAllowed("CLIENT")
    public void ping() {

    }

    private void doLogAction(String description) {
        ActionLog log = new ActionLog();
        log.setActionTime(new Date());
        log.setUsername(ctx.getCallerPrincipal().getName());
        entityManager.persist(log);
        ActionLogDescripton desc = new ActionLogDescripton();
        desc.setActionLogId(log.getId());
        desc.setDescription(description);
        entityManager.persist(desc);
    }

    @WebMethod
    @RolesAllowed("FROM_USD_TO_GBP")
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public double fromUSDtoGBP(@WebParam(name = "amount") double amount) {
        doLogAction("fromUSDtoGBP(amount=" + amount + ")");
        return amount * 0.60;
    }
    @WebMethod
    @RolesAllowed("FROM_GBP_TO_USD")
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public double fromGBPtoUSD(@WebParam(name = "amount") double amount) {
        doLogAction("fromGBPtoUSD(amount=" + amount + ")");
        return amount / 0.60;
    }
    @WebMethod
    @RolesAllowed("FROM_USD_TO_EURO")
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public double fromUSDtoEURO(@WebParam(name = "amount") double amount) {
        doLogAction("fromUSDtoEURO(amount=" + amount + ")");
        return amount * 0.72;
    }
    @WebMethod
    @RolesAllowed("FROM_EURO_TO_USD")
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public double fromEUROtoUSD(@WebParam(name = "amount") double amount) {
        doLogAction("fromEUROtoUSD(amount=" + amount + ")");
        return amount / 0.72;
    }
}

Summary

In this chapter, we introduced a Hello EJB project, during the example creation we learnt the following:

  • How to configure DataSources on JBOSS 7.1 AS
  • How to link JBOSS to MySQL database using MySQL Driver
  • How to configure Login Modules on JBOSS 7.1 AS
  • How to create Stateless EJB using Eclipse IDE
  • How to convert the Stateless EJB into Web Service
  • How to Secure the Web Service using Security Domains
  • How to convert non-JPA applications into JPA applications in Eclipse IDE
  • How to use Eclipse to generate Entity Beans directly from database tables
  • How to use JPA to handle the database insertion operations
  • How to use Container Transaction Management to manage the application database transactions
  • How to use SoapUI to test Web Services

Like us on Facebook