ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Wiring Your Web Application with Open Source Java
Pages: 1, 2, 3

Now that we have our container service beans configured and wired together we need to wire our business service object and our DAO object together. Then we need to wire these objects to the transaction manager.



Here is what this looks like in the Spring configuration file:

<!-- ORDER SERVICE -->
<bean id="orderService"
  class="org.
         springframework.
         transaction.
         interceptor.
         TransactionProxyFactoryBean">
  <property name="transactionManager">
    <ref local="myTransactionManager"/>
  </property>
  <property name="target">
    <ref local="orderTarget"/>
  </property>
  <property name="transactionAttributes">
    <props>
      <prop key="find*">
     PROPAGATION_REQUIRED,readOnly,-OrderException
      </prop>
      <prop key="save*">
     PROPAGATION_REQUIRED,-OrderException
      </prop>
    </props>
  </property>
</bean>

<!-- ORDER TARGET PRIMARY BUSINESS OBJECT:
Hibernate implementation -->
<bean id="orderTarget"
         class="com.
                meagle.
                service.
                spring.
                OrderServiceSpringImpl">
  <property name="orderDAO">
    <ref local="orderDAO"/>
  </property>
</bean>

<!-- ORDER DAO OBJECT -->
<bean id="orderDAO"
         class="com.
                meagle.
                service.
                dao.
                hibernate.
                OrderHibernateDAO">
  <property name="sessionFactory">
    <ref local="mySessionFactory"/>
  </property>
</bean>

Figure 4 is an overview of what we have wired together. This shows how each object is related and set into other objects by Spring. Compare this with the Spring configuration file in the sample application to see these relationships.

Figure 4
Figure 4. This is how Spring will assemble the beans based on this configuration.

This example uses a TransactionProxyFactoryBean, which has a setter for a transaction manager that we have already defined. This is a convenience object that knows how to deal with declarative transaction handling and your service objects. You can define how transactions are handled through the transactionAttributes property, which defines patterns for method names, and how they participate in a transaction. For more information about configuring isolation levels and commits or rollbacks on a transaction see TransactionAttributeEditor.

The class TransactionProxyFactoryBean also has a setter for a target, which will be a reference to our business service object called orderTarget. The orderTarget bean defines which business service class to use and it has a property which refers to setOrderDAO(). This property will populate the orderDAO bean that is our DAO object to communicate with our persistence layer.

One more note about Spring and beans is that beans can operate in two modes. These are defined as singleton and prototype. The default mode for a bean is singleton that means that one shared instance of the bean will be managed. This is used for stateless operations like a stateless session bean would provide. The prototype mode allows new instances of the bean to be create when the bean is served through Spring. You should only use prototype mode when each user needs their own copy of the bean.

Providing a Service Locator

Now that we have wired up our services with our DAO we need to expose our services to other layers. This is generally used from code in a layer such as UI that uses Struts or Swing. An easy way to handle this is with a service locator patterned class to return resources from a Spring context. This can also be done directly through Spring by referencing the bean ID.

Here is an example of how a service locator can be configured in a Struts Action:

public abstract class BaseAction extends Action {

  private IOrderService orderService;

  public void setServlet(ActionServlet
                                 actionServlet) {
    super.setServlet(actionServlet);
    ServletContext servletContext =
               actionServlet.getServletContext();

    WebApplicationContext wac =
      WebApplicationContextUtils.
         getRequiredWebApplicationContext(
                                 servletContext);

      this.orderService = (IOrderService)
                     wac.getBean("orderService");
  }

  protected IOrderService getOrderService() {
    return orderService;
  }
}

UI Layer Configuration

The UI Layer for the example application uses the Struts framework. Here we will discuss what is related to Struts when layering an application. Let's begin by examining an Action configuration within the struts-config.xml file.

<action path="/SaveNewOrder"
    type="com.meagle.action.SaveOrderAction"
    name="OrderForm"
    scope="request"
    validate="true"
    input="/NewOrder.jsp">
  <display-name>Save New Order</display-name>
  <exception key="error.order.save"
    path="/NewOrder.jsp"
    scope="request"
    type="com.meagle.exception.OrderException"/>
  <exception key="error.order.not.enough.money"
    path="/NewOrder.jsp"
    scope="request"
    type="com.
          meagle.
          exception.
          OrderMinimumAmountException"/>
  <forward name="success" path="/ViewOrder.jsp"/>
  <forward name="failure" path="/NewOrder.jsp"/>
</action>

The SaveNewOrder Action is used to persist an order that the user submitted from the UI layer. This is a typical Struts Action; however, notice the exception configuration for this action. These exceptions are also configured in the Spring configuration file, applicationContext-hibernate.xml, for our business service objects in the transactionAttributes property. When these exceptions get thrown back from the business layer we can handle them appropriately in our UI. The first exception, OrderException, will be used by this action when there is a failure saving the order object in the persistence layer. This will cause the transaction to rollback and propagate the exception back through the business object to the Struts layer. The OrderMinimumAmountException will also be handled in a transaction within the business object logic that fails when the order placed does not meet the minimum order amount. Again, the transaction will rollback and this exception can be handled properly by the UI layer.

The last wiring step is to allow our presentation layer to interact with our business layer. This is done by using the service locator that was previously discussed. The service layer acts as an interface to our business logic and persistence layer. Here is how the SaveNewOrder Action in Struts might use a service locator to invoke a business method:

public ActionForward execute(
  ActionMapping mapping,
  ActionForm form,
  javax.servlet.http.HttpServletRequest request,
  javax.servlet.http.HttpServletResponse response)
  throws java.lang.Exception {

  OrderForm oForm = (OrderForm) form;

  // Use the form to build an Order object that
  // can be saved in the persistence layer.
  // See the full source code in the sample app.

  // Obtain the wired business service object
  // from the service locator configuration
  // in BaseAction.
  // Delegate the save to the service layer and
  // further upstream to save the Order object.
  getOrderService().saveNewOrder(order);

  oForm.setOrder(order);

  ActionMessages messages = new ActionMessages();
  messages.add(
      ActionMessages.GLOBAL_MESSAGE,
	    new ActionMessage(
      "message.order.saved.successfully"));

  saveMessages(request, messages);

  return mapping.findForward("success");
}

Conclusion

This article covers a lot of ground in terms of technology and architecture. The main concept to take away is how to better separate your application, user interface, persistence logic, and any other application layer you require. Doing this will decouple your code, allow new code components to be added, and make your application more maintainable in the future. The technologies covered here address specific problems well. However, by using this type of architecture you can replace application layers with other technologies. For example, you might not want to use Hibernate for persistence. Since you are coding to interfaces in your DAO objects it should be apparent to you how you might use another technology or framework, such as iBATIS, as a substitute. Or you might want to replace your UI layer with a different framework than Struts. Switching UI layer implementations should not directly affect your business logic or your persistence layer. Replacing your persistence layer should not affect your UI logic or business service layer. Wiring a web application is not a trivial task but it can be made easier to deal with by decoupling your application layers and wiring it together with suitable frameworks.

Mark Eagle is a Senior Software Engineer at MATRIX Resources, Inc. in Atlanta, GA.


Return to ONJava.com.