Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

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

Lean service architectures with Java EE 6

Elements and patterns of a lean SOA

  • Print
  • Feedback

Page 3 of 6

Separation of concerns, or divide and conquer

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.

Listing 2. Structure 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.

Domain objects or structures?

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.

Listing 3. The DAO implementation

@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:

  • Print
  • Feedback

Resources

More from JavaWorld