Enterprise Java Development@TOPIC@

Chapter 85. Overview of EJB Styles

85.1. EJB Uses
85.2. EJB Granularity
85.3. EJB Bean Types
85.3.1. Entities (formerly Entity EJB)
85.3.2. Stateless Session EJB
85.3.3. Stateful Session EJB
85.3.4. Singleton Session EJB
85.3.5. Message Driven EJB (MDB)
85.4. EJB Interface Styles
85.4.1. Business Interface
85.4.2. Remote Interface
85.4.3. Local Interface
85.4.4. No Interface EJB
85.4.5. Other Interface Types
85.5. EJB Deployments
85.5.1. EJB Module
85.5.2. Naked EJB Deployment
85.5.3. EJB EAR Deployment
85.5.4. EJB WAR ("flexible") Deployment
85.5.5. EAR Deployment Class Loaders


  • Performs stateless actions on server-side

  • Maintains no conversational state

    • Each method ignorant of what went before it and after it

    • Persistence Context re-instantiated with each call (Transaction-Scope)

  • Methods take in a set of parameters and return a result

  • Maintains implementation state

    • example: DataSource

    • example: JMS connections

    • example: References to other EJBs

  • Examples:

    • TaxCalculator.calcTax(doubt amount)

    • BuyerMgmt.placeBid(int auctionId, double amount)

    • Dmv.getExpiredLicenses()

  • Good for implementing stateless access to resources

  • Contains no means to provide individualized access other than through separate deployments and call parameters


Figure 85.5. Example Stateful EJB

@javax.ejb.Stateful

public class ReservationEJB implements ReservationRemote {
    @PersistenceContext(unitName="ejbjpa-hotel", type=PersistenceContextType.EXTENDED)
    private EntityManager em;
    
    @EJB
    private HotelMgmtLocal hotelMgmt;
    
    @Resource
    private SessionContext ctx;
    
    private List<Guest> guests = new LinkedList<Guest>();
    @Override
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public int addGuest(Guest guest) {
        if (guest!=null) {
            guests.add(guest);
            em.persist(guest); //<== no transaction active yet
        }
        return guests.size();
    }
    @Override
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    @Remove
    public List<Guest> reserveRooms() throws RoomUnavailableExcepton {
        List<Room> rooms = hotelMgmt.getAvailableRooms(null, 0, guests.size());
        if (rooms.size() < guests.size()) {
            //no rollback needed, we didn't do anything
            throw new RoomUnavailableExcepton(String.format("found on %d out of %d required", 
                    rooms.size(), guests.size()));
        }
        //assign each one of them a room
        List<Guest> completed = new ArrayList<Guest>(guests.size());
        Iterator<Room> roomItr = rooms.iterator();
        for (Guest guest: guests) {
            Room room = roomItr.next();
            try {
                //the room could be unavailable -- depending on whether pessimistic lock created
                guest = hotelMgmt.checkIn(guest, room); //<== will attempt to also persist guest
                completed.add(guest);
            } catch (RoomUnavailableExcepton ex) {
                //rollback any previous reservations
                ctx.setRollbackOnly();
                throw ex;
            }
        }
        return completed;
    }
}

  • Used to cache resources for client on server-side

  • Maintains conversational state

    • Object can cache values between calls

      • example: iterator

      • Persistence Context (with cache of entities) can be retained between calls (Extended-Scope)

    • Lifetime ends on timeout or specific client call

  • Maintains implementation state

    • Not sharable between clients

    • All resources allocated to perform work for one instance

  • Able to react to transaction completion/rollback (i.e., get callback)

    • example: commit data cache

    • example: issue message

  • Good for caching client state and back-end resource state over a multi-call session

  • Inefficient to scale cached state for each user and across multiple servers


  • Used to receive JMS messages

  • Similar to Stateless EJB, but with no callable interface

  • Typically provides a JMS facade for injected Session EJBs

  • Good for implementing a JMS interface facade to business logic

  • Unable to be called outside the scope of a JMS/JCA call -- should delegate to Session EJBs

  • Has no client context (i.e., anonymous)

Figure 85.13. Example JAX-RS Interface



import java.net.URI;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
@Path("/products")
public class ProductsResource {
        @Inject
        private InventoryMgmtEJB ejb;
        @Context 
        private UriInfo uriInfo;
        @POST @Path("")
        @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
        @Produces(MediaType.APPLICATION_XML)
        public Response createProduct(
                        @FormParam("name") String name,
                        @FormParam("quantity") Integer quantity,
                        @FormParam("price") Double price,
                        @FormParam("category") String category) {
             Product product = new Product(name, quantity, price);
             Product p = ejb.addProduct(product, category);
             URI uri = UriBuilder.fromUri(uriInfo.getAbsolutePath())
                                     .path(ProductsResource.class, "getProduct")
                                     .build(p.getId());
             return Response.created(uri)
                             .entity(p)
                             .build();
        }
}