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

Design a simple service-oriented J2EE application framework

Leverage Struts, Spring, Hibernate, and Axis

  • Print
  • Feedback

Today, developers are inundated with open source frameworks that help with J2EE programming: Struts, Spring, Hibernate, Tiles, Avalon, WebWorks, Tapestry, or Oracle ADF, to name a few. Many developers find that these frameworks are not the panacea to their problems. Just because they are open source doesn't mean they are easy to change and improve. When a framework falls short in a key area, addresses only a specific domain, or is just bloated and too expensive, you might need to build your own framework on top of it. Building a framework like Struts is a nontrivial task. But incrementally developing a framework that leverages Struts and other frameworks doesn't have to be.

In this article, I show you how to develop X18p (Xiangnong 18 Palm, named for a legendary powerful kung fu fighter), a sample framework that addresses two common issues ignored by most J2EE frameworks: tight coupling and bloated DAO (data access object) code. As you'll see later, X18p leverages Struts, Spring, Axis, Hibernate, and other frameworks at various layers. Hopefully, with similar steps, you can roll your own framework with ease and grow it from project to project.

The approach I take in developing this framework uses concepts from IBM's Rational Unified Process (RUP). I follow these steps:

  1. Set simple goals initially
  2. Analyze the existing J2EE application architecture and identify the issues
  3. Compare alternative frameworks and select the one that is simplest to build with
  4. Develop code incrementally and refactor often
  5. Meet with framework's end-user and collect feedback regularly
  6. Test, test, test


Step 1. Set simple goals

It is tempting to set ambitious goals and implement a cutting-edge framework that solves all problems. If you have sufficient resources, that is not a bad idea. Generally, developing a framework upfront for your project is considered overhead that fails to provide tangible business value. Starting smaller helps you lower the unforeseen risks, enjoy less development time, lower the learning curve, and get project stakeholders' buy-in. For X18p, I set only two goals based on my past encounters with J2EE code:

  1. Reduce J2EE Action code coupling
  2. Reduce code repetition at J2EE DAO layer


Overall, I want to provide better quality code and reduce the total cost of development and maintenance by increasing my productivity. With that, we go through two iterations of Steps 2 through 6 to meet those goals.

Reduce code coupling

Step 2. Analyze previous J2EE application architecture

If a J2EE application framework is in place, we first must see how it can be improved. Obviously, starting from scratch doesn't make sense. For X18p, let's look at a typical J2EE Struts application example, shown in Figure 1.

Figure 1. J2EE Struts application architecture. Click on thumbnail to view full-sized image.

Action calls XXXManager, and XXXManager calls XXXDAOs. In a typical J2EE design that incorporates Struts, we have the following items:

  • HttpServlet or a Struts Action layer that handles HttpRequest and HttpResponse
  • Business logic layer
  • Data access layer
  • Domain layer that maps to the domain entities


What's wrong with the above architecture? The answer: tight coupling. The architecture works just fine if the logic in Action is simple. But what if you need to access many EJB (Enterprise JavaBeans) components? What if you need to access Web services from various sources? What if you need to access JMX (Java Management Extensions)? Does Struts have a tool that helps you look up those resources from the struts-config.xml file? The answer is no. Struts is meant to be a Web-tier-only framework. It is possible to code Actions as various clients and call the back end via the Service Locator pattern. However, doing so will mix two different types of code in Action's execute() method.

The first type of code relates to the Web-tier HttpRequest/HttpResponse. For instance, code retrieves HTTP form data from ActionForm or HttpRequest. You also have code that sets data in an HTTP request or HTTP session and forwards it to a JSP (JavaServer Pages) page to display.

The second code type, however, relates to the business tier. In Action, you also invoke backend code such as EJBObject, a JMS (Java Message Service) topic, or even JDBC (Java Database Connectivity) datasources and retrieve the result data from the JDBC datasources. You may use the Service Locator pattern in Action to help you do the lookup. It's also possible for Action to reference only a local POJO (plain old Java object) xxxManager. Nevertheless, a backend object or xxxManager's method-level signatures are exposed to Action.

That's how Action works, right? The nature of Action is a servlet that is supposed to care about how to take data in from HTML and set data out to HTML with an HTTP request/session. It also interfaces to the business-logic layer to get or update data from that layer, but in what form or protocol, Action could care less.

As you can imagine, when a Struts application grows, you could end up with tight references between Actions (Web tier) and business managers (business tier) (see the red lines and arrows in Figure 1).

To solve this problem, we can consider the open frameworks in the market—let them inspire our own thinking before we make an impact. Spring Framework comes on my radar screen.

Step 3. Compare alternative frameworks

The core of Spring Framework is a concept called BeanFactory, which is a good lookup factory implementation. It differs from the Service Locator pattern in that it has an Inversion-of-Control (IoC) feature previously called Injection Dependency. The idea is to get an object by calling your ApplicationContext's getBean() method. This method looks up the Spring configuration file for object definitions, creates the object, and returns a java.lang.Object object. getBean() is good for object lookups. It appears that only one object reference, ApplicationContext, must be referenced in the Action. However, that is not the case if we use it directly in the Action, because we must cast getBean()'s return object type back to the EJB/JMX/JMS/Web service client. Action still must be aware of the backend object at the method level. Tight coupling still exists.

If we want to avoid an object-method-level reference, what else we can use? Naturally, service, comes to mind. Service is a ubiquitous but neutral concept. Anything can be a service, not necessarily just the so-called Web services. Action can treat a stateless session bean's method as a service as well. It can treat calling a JMS topic as consuming a service too. The way we design to consume a service can be very generic.

With strategy formulated, danger spotted, and risk mitigated from the above analysis and comparison, we can spur our creativity and add a thin service broker layer to demonstrate the service-oriented concept.

  • Print
  • Feedback

Resources