Novell is now a part of Micro Focus

How to Build J2EE Applications Using Novell Technologies: Part 3

Articles and Tips: article

J. Jeffrey Hanson
Chief Architect
Zareus Inc.
Jhanson583@aol.com

01 Jul 2002


This AppNote is the third in a series that outlines a platform and methodology for developing applications on NetWare with the Java 2 Platform Enterprise Edition (J2EE) using a service-oriented architecture. In this AppNote we continue our exploration of the Web tier by constructing mechanisms that allow us to dynamically configure our controller servlet.


Topics

Java application development, J2EE, servlets

Products

Java 2 Enterprise Edition

Audience

developers

Level

intermediate

Prerequisite Skills

familiarity with Java programming

Operating System

n/a

Tools

none

Sample Code

yes

Introduction

This is the third in a series of AppNotes outlining a platform and methodology for Java 2 Platform Enterprise Edition (J2EE) application development on NetWare using a service-oriented architecture.

In the previous AppNote we began our journey into the J2EE development world by developing a servlet on the Web tier that responds to HTTP requests sent from a browser on the client tier. This servlet acts as the point of control for all HTTP-based requests.

In this AppNote, we will continue our exploration of the Web tier by constructing mechanisms that allow us to dynamically configure our controller servlet. We will also cross the chasm into the business tier and begin exploring some exciting technologies that will enable us to build a very sophisticated and powerful middleware service framework.

Dynamic Configuration Maneuvers

As we concluded our last discussion (see "How to Build J2EE Applications Using Novell Technologies: Part 2" in the June 2002 issue of Novell AppNotes), our Web tier was left with its MVC (model/view/controller) exposed, showing a simple Front Controller servlet, a skeletal TaskMaster, and a skeletal ViewMaster. We are now going to shelter these poor items and give them some substance and power.

To review, the Front Controller servlet is going to guard the HTTP gate and field all requests coming in and then give them to the TaskMaster to process. The TaskMaster will parse the HTTP URL and extract the relative URI/PathInfo string in order to determine if the request is for a task or a view. Remember that a task is a request for some action to be performed, while a view is a request for a specific page to be returned. For example, the following URL is requesting a task to be performed: http://www.mycompany.com/mywebapp/GetAccounts.

In contrast, the following URL is requesting a page/view to be returned: http://www.mycompany.com/mywebapp/login.html.

Before we get too far ahead of ourselves, let's take a look at how the TaskMaster and ViewMaster load their lists of tasks and views.

One of the major benefits of our system is the ability to configure the client- requests flow of control by domain experts. Typically, a Web page designer or a middleware engineer is not the best person to be making decisions about concerns such as where to direct the application if the user login fails, or if the user doesn't have enough money in his/her account to cover a payment, or if the loan application form is not filled in correctly. These types of decisions are best left up to the expert for each particular domain.

On the Web tier, the TaskMaster and ViewMaster both read their respective lists of tasks and views from XML files. These lists could be placed in a database, a directory service, an Excel spreadsheet, or the back seat of my 63 Buick for that matter, but we are going to use XML files.

When the TaskMaster and ViewMaster are first instantiated, they attempt to find a file that contains the list of their tasks or views. If the file is found, they load it and store the tasks or views in a HashMap for quick lookup later. The TaskMaster and ViewMaster both use the Xerces SAX parser (one of the Apache offerings) to parse their XML files and extract the tasks or views.

Here is an example of a TASKS.XML file:

<tasks>

   <task>

      <name>AuthenticateUser</name>

      <class>com.mycompany.task.Authenticate</class>

      <results>

         <Success>ViewAccounts</Success>

         <Error>LoginError</Error>

      </results>

   </task>

   

   <task>

      <name>AddAccount</name>

      <class>com.mycompany.task.AddAccount</class>

      <results>

         <Success>ViewAccounts</Success>

         <Error>AddAccountError</Error>

      </results>

   </task>

   

   <task>

      <name>UpdateAccount</name>

      <class>com.mycompany.task.UpdateAccount</class>

      <results>

         <Success>ViewAccounts</Success>

         <Error>UpdateAccountError</Error>

      </results>

   </task>

</tasks>

Here is an example of a VIEWS.XML file:

<views>



   <view>

      <name>ViewAccounts</name>

      <uri>/views/ViewAccounts.jsp</uri>

   </view>

   

   <view>

      <name>LoginError</name>

      <uri>/errors/LoginError.jsp</uri>

   </view>

   

   <view>

      <name>AddAccountError</name>

      <uri>/errors/Error.jsp</uri>

   </view>

   

   <view>

      <name>UpdateAccountError</name>

      <uri>/errors/Error.jsp</uri>

   </view>

</views>

Task or View, View or Task

Once the TaskMaster has determined whether the request is for a task or a view, it will act as follows:

  • If the request is for a task, the TaskMaster will look through its list of tasks that it loaded at startup and, if the task is found it will hand the request over to the task. If the task is not found, an exception occurs.

  • If the request is for a view, the TaskMaster will hand the request directly over to the ViewMaster to process.

Tasks can be chained. In other words, one task can execute another task and return that task's URI as its result. This new task can also return another task's URI as its result. This allows a complex set of task interactions to occur with one request from the client, as follows:

public boolean process(HttpServletRequest req,HttpServletResponse res)

                     throws TaskException

{

   String pathInfo = req.getPathInfo();

   String viewURL = pathInfo;   // default is to assume it is a view URI

   if (tasks.get(pathInfo) != null)

   {

      viewURL = execute(req, res, pathInfo);

   }

   try

   {

      viewMaster.execute(req, res, viewURL);

   }

   catch(Exception e)

   {

      throw new TaskException(e.getMessage());

   }

   

   return false;

}

   

public String execute(HttpServletRequest req,HttpServletResponse res,

                     String taskID)throws TaskException

{

   Task task = (Task)tasks.get(taskID);

   String result = task.execute(req, res);"

   if (tasks.get(result) != null)   // recurse for task chaining

      return execute(req, res, result);

   return result;

}

A domain expert, using our XML-file configuration mechanism, orchestrates this entire process. While XML is quite easily understood and programmed, a graphical tool would make our domain expert's life a lot easier. We will discuss tools for this very thing in a later AppNote.

So, as you may have determined by now, each task performs some logic and returns either another task's URI or the URI for a view. This is accomplished when the task's execute method is called, as follows:

public String execute(HttpServletRequest req,

                     HttpServletResponse res)

{

   //   do some stuff (validate parameters, call a service, etc.)

   return this.nextURI";

}

The ViewMaster is primarily responsible for caching view aliases and their associated URIs, passing HTTP request parameters to a view and forwarding the HTTP request to the view's URI, as follows:

public void execute(HttpServletRequest req,HttpServletResponse res,

                  String viewID)throws ViewException

{

   req.setAttribute("CurrentView", viewID);

   

   View view = (View)views.get(viewID);

   if (view != null)

   {

      view.setRequestProperties(req);

      RequestDispatcher dispatcher =

         servletContext.getRequestDispatcher(view.getURI());

      try

      {

         dispatcher.forward(req, res);

      }

      catch(IOException e)

      {

         throw new ViewException(e.getMessage());

      }

      catch(ServletException e)

      {

         throw new ViewException(e.getMessage());

      }

   }

}

Since the ViewMaster is completely decoupled from the rest of the system, it can create views for any conceivable device. We are going to use JSP as our view-creation language, but other systems could use XML/XSLT, WML, PHP, etc. just as easily.

Reaching Across the Chasm

Now that we have sufficiently stormed across the Web tier's field of battle, we come to the second line of demarcation: the "business tier" line. The business tier is responsible for performing business logic requests for horizontal or vertical domains. This would include authenticating a user, retrieving the user's contact information, retrieving the user's account information, adding a new user, sending an e-mail to Mom, applying for a loan to buy my 63 Buick, or other useful services.

Since our business logic is likely to be shared across multiple Web tiers, it makes sense for us to separate the business tier in a way that allows us to install it on a separate machine or machines and still be accessible from the Web tier. However, if the customer is a small business that wants everything on one machine, we must comply. This leaves us with the problem of supporting both the local and distributed customer scenarios. We could write, maintain, and debug two sets of code-or we could create one abstraction that will handle both scenarios and is configurable by an IT person. Since one step is usually easier than two, we'll opt for the latter.

Our abstraction of local and distributed scenarios is embodied in an object we call the "Service Broker." The Service Broker accepts calls from the tasks and makes requests to services on the business tier. According to configurable properties, the Service Broker determines what protocol to use to communicate with the business tier. If we install our business tier on the same machine as our Web tier, the Service Broker just makes a normal Java method call. If the business tier and Web tier are separated across machines, the Service Broker uses whatever protocol the IT/domain expert wishes. This could include HTTP, IIOP, RMI, JMS, and others.

Servicing the Front

Our business tier is based on a service-oriented architecture (SOA). An SOA has a powerful service layer consisting of service components that perform specific domain functions. These services must have the ability to be invoked remotely, but they must be location-agnostic and have the ability to be discovered and used dynamically. These services must be easily constructed from existing code, as most companies have extensive libraries of existing business logic that must be accessible from the Web tier.

A Service is formally defined as "a set of software components that perform a specific set of business logic, does not maintain state or session information, and consists of a published interface that is configurable by an expert in a particular domain." Our services will adhere to this definition by performing specific sets of business logic, ignore state or session information, and use JMX (Java Management Extensions) to configure their published interfaces. We will discuss JMX later as we explore our platform's kernel and service manager.

Conclusion

In this AppNote we have discussed how our platform uses XML-configurable components and services to allow maximum flexibility and extensibility. We introduced our service-oriented business tier and discussed the technologies used to communicate from the Web tier to the business tier.

In the next AppNote in this series, we will further explore the business tier and introduce how our services interact with the data tier. We will also introduce some additional Java-based technologies that differentiate our platform from other similar offerings.

For Additional Information

For more information about the technologies discussed in this AppNote, refer to the following resources:

* Originally published in Novell AppNotes


Disclaimer

The origin of this information may be internal or external to Novell. While Novell makes all reasonable efforts to verify this information, Novell does not make explicit or implied claims to its validity.

© Copyright Micro Focus or one of its affiliates