Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 3 of 6
Listing 1's OrderServiceBean emphasizes the business logic and hides the component's implementation. These are the responsibilities of a typical Facade
pattern. Furthermore, the OrderServiceBean ensures the component's consistency by starting a transaction before every method is exposed over the business interface.
Transactions are a cross-cutting concern -- an aspect -- already implemented by the EJB container. Implementing both the controller logic and the actual business logic would be too much responsibility for a single facade.
The intention of a service is straightforward -- it is the realization of the business logic. In the SOA world it has rather procedural nature. A service resides behind the facade, so it can never be accessed directly by the UI or other presentation components. A service is stateless and can be only called by the facade. Every facade's method starts a new transaction, so a service can safely rely on the transactions' existence. Listing 2 shows the transaction and remoting configuration of a service.
@Stateless
@Local(OrderProcessor.class)
@TransactionAttribute(TransactionAttributeType.MANDATORY)
public class OrderProcessorBean implements OrderProcessor {
@PersistenceContext
private EntityManager em;
public Order processOrder(int customerId, int productId, BigDecimal price) {
Order order = new Order(customerId, productId, price);
this.em.persist(order);
return order;
}
}
In Listing 2, the concerns are clearly separated. The facade provides the cross-cutting functionality and plays the controller
role, and the service focuses on the actual domain-logic implementation. The clearly separated roles and responsibilities
make it possible to predefine a service's structure and configuration easily. A service is a stateless session bean with local
business interface. It is always invoked by the facade in a transaction, so it can be deployed with the MANDATORY setting. This restrictive TransactionAttribute further emphasizes the encapsulation; it is not possible to call it directly without a transaction. The bean implementation
exposes the business interface with the @Local annotation, so the interface is independent of the EJB API.
Since services implement the actual business logic, and the facade cares about the cross-cutting concerns, there is no more functionality left to be implemented in the domain objects. The Java Persistence API (JPA) entities consist only of annotated attributes and getters/setters; they contain no business logic, as you can see in Listing 3.
@Entity
@Table(name="T_ORDER")
@NamedQueries({
@NamedQuery(name="",query="SELECT o FROM Order o where o.customerId = :customerId")
})
public class Order {
public final static String PREFIX ="..ordermgmt.domain.Order";
public final static String findByCustomerId = PREFIX + "findByCustomerId";
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private int customerId;
private int productId;
private double price;
public Order() { }
public Order(int customerId,int productId,BigDecimal price){
this.customerId = customerId;
this.productId = productId;
this.price = price.doubleValue();
}
public Long getId() {
return id;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getProductId() {
return productId;
}
public void setProductId(int productId) {
this.productId = productId;
}
}
Although the anemic object model is considered to be an antipattern, it fits very well into a SOA. Most of the application is data-driven, with only small amount of object-specific or type-dependent logic. For simpler applications, anemic JPA entities have advantages too: