Enterprise Java Development@TOPIC@
Implement a task
Interact with other beans
Examples:
TaxDistrict.calcTax(double amount)
Teller.transfer(long fromAccount, long toAccount, double amount)
Registrar.listStudents(String course, int offset, int limit)
Session EJB per Use Case too fine
CreateAccountEJB
DepositEJB
WithdrawEJB
TransferEJB
Group cohesive Use Cases into larger-grain Session EJBs
Teller
createAccount()
deposit()
withdraw()
transfer()
All are POJO-based
i.e., most Java classes can be made into an EJB
Figure 85.1. Example Entity
@javax.persistence.Entity
@javax.persistence.Queries({
@javax.persistence.Query(name="Reservation.getReservationsByName", query="
select r from Reservation r
where r.person.firstName like :firstName and
r.person.lastName like :lastName")
})
public class Reservation {
@javax.persistence.Id
private long id;
private String confirmation;
@javax.persistence.Temporal(javax.persistence.TemporalType.DATE)
private Date startDate;
@javax.persistence.Temporal(javax.persistence.TemporalType.DATE)
private Date endDate;
@javax.persistence.ManyToOne
@javax.persistence.JoinColumn
private Person person;
Represents shared data in the database
Typically interact at row/object level
Moved to Java Persistence API (JPA) Spec in EJB 3.0/JavaEE 5
Not constrained to server-side
Examples:
Account, Owner
Account.deposit(double amount)
Account.getOwner()
Good for representing persistent information
Contains no means to access external resources other than directly related information
Figure 85.3. Example Stateless EJB
@javax.ejb.Stateless
public class HotelMgmtEJB implements HotelMgmtRemote, HotelMgmtLocal {
@PersistenceContext(unitName="ejbjpa-hotel")
private EntityManager em;
private HotelDAO dao;
private HotelMgmt hotelMgmt;
@PostConstruct
public void init() {
dao = new JPAHotelDAO();
((JPAHotelDAO)dao).setEntityManager(em);
hotelMgmt = new HotelMgmtImpl();
((HotelMgmtImpl)hotelMgmt).setHotelDao(dao);
}
@Override
public Room getRoom(int number) {
return hotelMgmt.getRoom(number);
}
}
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
Figure 85.7. Example Singleton EJB
@javax.ejb.Singleton
@javax.ejb.Startup
@javax.ejb.ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
@javax.ejb.AccessTimeout(value=3000)
public class StatsEJB implements StatsLocal, StatsRemote {
private int total;
@Override
@javax.ejb.Lock(LockType.WRITE)
public void increment() { ... }
@Override
@javax.ejb.Lock(LockType.READ)
public int getTotal() { ... }
...
}
Provides a single Session EJB instance on server-side
Single instance shared across all clients
Has READ/WRITE lock and timeout concerns
Good for tracking shared state in memory
Creates a bottleneck for concurrent access
Figure 85.8. Example Message Driven EJB
@javax.ejb.MessageDriven(activationConfig={
@javax.ejb.ActivationConfigProperty(
propertyName="destinationType",
propertyValue="javax.jms.Topic"),
@javax.ejb.ActivationConfigProperty(
propertyName="destination",
propertyValue="java:/topic/ejava/examples/asyncMarket/topic1"),
@javax.ejb.ActivationConfigProperty(
propertyName="messageSelector",
propertyValue="JMSType in ('forSale', 'saleUpdate')"),
@javax.ejb.ActivationConfigProperty(
propertyName="acknowledgeMode",
propertyValue="Auto-acknowledge")
})
public class BuyerMDB implements MessageListener {
@javax.ejb.EJB
private BuyerLocal buyer;
@javax.annotation.security.PermitAll
public void onMessage(javax.jms.Message message) {
...
}
}
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.9. Example Business Interface
public interface Teller {
Account createAccount(String accNum) throws BankException;
void updateAccount(Account account) throws BankException;
Account getAccount(String acctNum) throws BankException;
}
Pure POJO
No ties to EJB
No sense of local or remote
Figure 85.10. Example Remote Interface
@javax.ejb.Remote
public interface TellerRemote extends Teller {
Ledger getLedger() throws BankException;
List<Owner> getOwners(int index, int count) throws BankException;
String whoAmI();
}
public class Ledger implements java.io.Serializable {
...
}
Uses RMI-based technology to provide built-in implementation
Data types must be built-in types or Serializable types
Pass-by-value semantics between client and EJB
Usable by local (same application/EAR) and remote (outside of same application/EAR) endpoints
Pass-by-reference semantics between client and EJB
client and EJB share the same object instance
Must load class from same classloader
Data types need not be built-in or Serializable types
Restricted to be from application (e.g., must be from same EAR to share reference)
Remote clients are different from local clients and require different considerations when designing the remote interface. Although JavaEE/EJB make it technically possible to implement location independence the interface hierarchies, this is usually not feasible when dealing with non-trivial interface requirements. Design local interfaces for local clients (within the deployed application) and design remote interfaces for remote clients.
Figure 85.12. Example No Interface EJB
@javax.ejb.Singleton
@javax.ejb.Startup
@javax.ejb.ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
@javax.ejb.AccessTimeout(value=3000)
public class StatsEJB {
private int total;
@javax.ejb.Lock(LockType.WRITE)
public void increment() { ... }
@javax.ejb.Lock(LockType.READ)
public int getTotal() { ... }
...
}
Interfaces are an encapsulation issue and not an EJB issue
If you do not need the encapsulation of an interface -- EJB will *not* make you add one for local access
Must have interface when using remote clients
JAX-RS support
SOAP support
CORBA/IIOP support
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();
}
}
EJB modules are deployable by themselves
Contain no mechanism to bring in dependencies
Can only be communicated with using remote interface
Can deploy multiple EJB modules, multiple WARs, and utility libraries
Provides means to use local interfaces/pass by reference between EJBs and WAR/WEB
Convenient wrapper for entire application
Can deploy multiple EJB modules within WEB-INF/lib
Can deploy multiple EJB beans within WEB-INF/classes
Realistically useful when Servlet or JSP wishes to use declarative JTA transactions or security access control within a helper class
Ideal use for No-interface Session EJB
Eliminates need for EAR in some cases
Arranged in a parent/child relationship
May access classes/resources loaded by local and parent class loaders
Do not have access to classes/resources loaded by sibling class loaders
Requests for classes are first delegated to parent class loader
Classes loaded by one EJB deployment are not sharable with other deployments
Must use remote interfaces and pass-by-value serialized data
No pass by reference
EJB classes/resources can be shared with single Web App if loaded in WEB-INF/lib
Local interfaces/resources are local to that WAR
EJB classes cannot be shared across WARs
Must again resort to remote interfaces and pass-by-value serialized data to share implementations
EAR class loader is root to deployed application
EJB class loader is host to all EJBs and root to WAR class loaders
WAR class loaders are separate
Allows two separate WARs to generate the same class from two separate index.jsp files
Disallows WAR from duplicating EAR/EJB-supplied classes
EJBs and WARs-to-EJBs can share information using pass-by-reference