Chapter 4 Designing the Middle Tiers

Arguably the middle tier and business layers are some of the more difficult layers to clearly define. Somewhere between the persistence and presentation layers are one or more layers that provide a continuum of cleanly separated yet reusable functionality, which is the goal, right? This is the nirvana that architects search for within their organization or domain. Unfortunately, nirvana is way beyond the scope of this book, and probably beyond the reach of many organizations. This chapter can help you to begin that search by outlining some of the options that are available for your application. It also talks about the specifics of deploying middle layers and dependent libraries within WebSphere Application Server for use by other layers and applications.

Business Logic

The issue begins with where exactly business logic should be placed within the code. Chapter 3, “Persistence Matters,” touched briefly on the idea of a rich domain model where entity components contain internal logic as well as attribute storage. This muddies the waters a bit when an entity component can perform specific operations. For example, take the case of sales tax calculation. It would stand to reason that an order object that contained both the overall order data and a list of order items could in fact calculate for itself the sales tax and other receipt information for that order. In fact, storing that information within the order when it is complete may be wise. This persistence may be important in cases where the sales tax rate is subject to change from time to time. Take a look at Figure 4.1 to see what I mean.

Image

Figure 4.1   Rich domain model

In this example the Order Entity itself computes the details that are necessary to complete the order. This signifies a somewhat rich domain model in which the domain entities have some logic encapsulated within themselves to help make decisions. As I mentioned there is some sense in this approach because some of this information might need to be persisted.

On the other hand this type of computational logic could be contained within the business logic layer (see Figure 4.2 ) of the application, perhaps using the order date to determine the tax rate for orders over time. This approach actually puts more of the onus on the business layer, perhaps using this layer to perform additional tasks such as determination of other discounts that may be applied from time to time, such as buy two items get the third one free, or special discounts for specific types of orders.

In this case, the option exists that the Order Entity still needs to be updated to hold additional information. This information may be created by some calculated results of an operation.

Image

Figure 4.2   Business layer logic

Another HelloWorld Example

Okay, maybe this example isn't the simplest ever, but it is simple enough that everyone can relate to it. Using the classic Hello World example I show how you can design a business layer, and how you can use that business layer within your applications.

The example consists of one interface and an implementation class (see Figure 4.3) making up the business layer. An interface is probably not needed for this simple of an example, but it does allow me to separate the implementation of the business layer from the clients who use it.

Image

Figure 4.3   Business layer class model

The interface Hello really consists of one method, that being the helloWorld() method. It's not rocket science as far as examples go, but is simple enough to keep the focus on the design. I have added two additional methods that will make sense to you later in this chapter. They are designed to illustrate how a single layer may be shared across multiple applications within a single JVM. This concept is not always readily apparent unless you are used to working with multiple applications such as in a portal framework.

package com.ibmpress.biz.hello;


public interface Hello {


   public String helloWorld(String name);


   public void setWhosBeenHere(String value);
   public String getWhosBeenHere();


}

As expected the implementation for this interface is just as simple. I have created a single instance variable to hold some state information as different client applications use the service. The other methods simply echo parameters that are passed to them.

package com.ibmpress.biz.hello;

public class HelloImpl implements Hello {

   private String whos_been_here = "original value";


   public String helloWorld(String name) {
             return "Hello " + name;
   }
       public void setWhosBeenHere(String value) {
             whos_been_here = value;
   }

   public String getWhosBeenHere() {
      return whos_been_here;
   }
}

At this point I really have a number of choices for making my object visible to client applications and for making sure that I control the number of instances that are created within the environment. For this simple class I do not really care if multiple instances of this object are created, but if I were to use this object to access some backend, or manage a shared resource, I would definitely want to manage the creation of these objects. I could turn it into a session EJB like we used in Chapter 3 or perhaps add a getInstance() method and make the class into a singleton.

If you look back at Figure 4.3 you can see I have decided to use the Spring framework to control the creation of Hello beans. The Spring bean factory actually defaults to a singleton approach but provides a clean way of instantiating and accessing my objects. Defining the bean is as simple as declaring it within the application.xml file used by the Spring application context.

<?xml version=“1.0” encoding=“UTF-8”?>
<!DOCTYPE beans PUBLIC “-//SPRING//DTD BEAN//EN”
“http://www.springframework.org/dtd/spring-beans.dtd”>

<beans>

   <!—HelloWorld Bean —>
   <bean id=“helloBean” class=“com.ibmpress.biz.hello.HelloImpl” />

</beans>

Making the Business Layer Accessible

There is a slight problem with using Spring in this context, that is, within a business layer. I could actually package this code within my enterprise application (EAR) file, or web application to ensure that I could access the application or web application context of Spring to access the beans, but what if I want to share this layer between different applications? Some decisions have to be made about the accessibility, deployment, and reuse of the business layer. In many cases making these decisions can be easy. A layered architecture can exist completely within the context of a single enterprise application or even web application.

A single deployable .ear file is not really the issue and may be the most common scenario within your organization. Applications rely on a logical separation within the JVM. This separation is part of the specification in many cases, such as not sharing session state between different applications. If you are wondering why I'm even bringing this up, think of portaltype situations where essentially separate applications share the same presentation space. Again the question arises: Why not make life easier by choosing a different distributed technology for this layer, such as EJBs or Web Services?

The reason is that every design decision has to be made with some trade-offs and limitations in mind. Distributing the layer comes at some cost, though initially that cost may not seem to be very big; however, requirements can sometimes grow. If I decided to locate the business layer on another tier I now have additional infrastructure to manage, with a total cost of ownership (TCO) of perhaps double what I initially considered. I have to make sure this tier is as robust as my original tier. This is in addition to any latency between system calls, which may or may not be acceptable based on application performance requirements.

So, in this case I am considering the least distributed approach where multiple layers live within the same application server, providing fast response and limiting overall ownership costs. Do not think there is only one approach worth taking. The point of this book is to show you how to design your architecture to take into account many different application requirements and constraints.

My goal in this example is to be able to share a Spring bean between multiple web applications. Doing so allows me to provide a single business layer interface that different applications can reuse as needed. Even as the business logic grows within this layer, updates can be made without affecting existing applications and without recoding or managing several instances of the same code base. We will talk in Chapter 10, “Managing Your Applications,” about some of the governance issues and trade-offs with single versus multiple instances of your code base.

I have decided to go ahead and create a singleton, which can act as a wrapper around the Spring context. This simple class creates the Spring context and then passes to it any bean request that may come from client applications. This isolates the client from having to understand or use Spring, but allows the business layer to take advantage of cool features like dependency injection. Advantages may exist to having the client application work more closely with the Spring framework, but in terms of simplicity within my environment and limiting the possible amount of confusion with the development, this approach provides a very simple solution to what can be a very complicated problem.

BizLayerDAO is a very simple class that serves as a single entry point into any object within the business layer. The constructor creates the Spring context and stores it locally so that any object lookup uses the same context.

package com.ibmpress.biz.dao;

import org.springframework.context.ApplicationContext;
import
org.springframework.context.support
.ClassPathXmlApplicationContext;

public class BizLayerDAO {

   static private BizLayerDAO _instance = null;
   static private ApplicationContext context;

   protected BizLayerDAO() {

                context = new
                ClassPathXmlApplicationContext(“applicationContext.xml”);

                 }

   static public BizLayerDAO getInstance() {
     if(null == _instance) {
         _instance = new BizLayerDAO();
     }
     return _instance;
     }

     public Object getBean(String beanname) {
          return context.getBean(beanname);
     }
}

The rest of the class is an out-of-the-box singleton implementation with a getInstance() method allowing client code to use the singleton. The getBean() method simply returns the object that is provided by the Spring context.

Getting Ready for Unit Testing

Testing within the development framework, in this case using Eclipse or Rational Application Developer, is fairly simple. Having my business layer consist of the Plain Old Java Object (POJO) approach allows me to keep things simple.

I created a simple test class using JUnit to demonstrate the idea of building and running a set of unit tests. Then as I continue to build new functionality within my business layer I can add additional tests as needed. Notice that the test class has no real knowledge of Spring being used to provide the requested Hello object.

package com.ibmpress.biz.test;

import static org.junit.Assert.*;
import org.junit.Test;

import com.ibmpress.biz.dao.BizLayerDAO;
import com.ibmpress.biz.hello.Hello;
import com.ibmpress.biz.hello.HelloImpl;

public class HelloTest {

   public void testHelloWorld() {

   BizLayerDAO dao = BizLayerDAO.getInstance();
   Hello helloBean = (Hello) dao.getBean("helloBean");
   assertEquals("Result should append name to Hello",
                          "Hello Joey", helloBean.helloWorld("Joey"));
   }
}

Finally, let's take a quick look at the structure of this project (see Figure 4.4) within the development environment. Within Eclipse this project can be set up as a simple Java project. There are several dependencies within the project, including the Spring framework itself and some dependent libraries that Spring uses.

Image

Figure 4.4   Project structure

The package structure is very straightforward and you can deploy the entire project as a JAR file within your application or environment. Notice that this layer is a simple POJO-based layer. The interface for each service and the implementation is in one package, and the data access point is in a separate package. Both are wrapped within the same project structure. Some testing classes have been added but they may not get packaged and deployed with the final code drop. One of the advantages of Spring is that you can get away with writing simple Java classes and wrapping them into a complete framework that will manage the objects and how they are accessed, as well as any dependencies the objects themselves might require.

WebSphere Shared Libraries

To support the use of third party frameworks and libraries you can leverage WebSphere Shared Libraries, which are designed to allow sharing of dependent JAR files across multiple applications. You can make shared libraries globally available across the entire JVM, or make them available to specific web applications only. This feature makes providing middle layer functionality encapsulated within JAR files to your applications easy. The process for the installation and configuration of shared libraries is not hard, but you must perform several steps to make these libraries available, as follow:

1.  To set up a shared library you need to use the WebSphere administrative console or Network Deployment manager console. Click Environment and then Shared Libraries as shown in Figure 4.5

Image

Figure 4.5  Creating a shared library

    As with most everything in WebSphere Application Server, scope can be important in maintaining control of system resources. Limiting the visibility of resources to the system or set of systems that requires access helps maintain security reduced potential resource constraints. You can set some resources, like data sources, at multiple scopes. In these cases, some resource scopes have precedence over other scopes.

2.  For this example, choose Cell scope, and click New to continue (see Figure 4.6).

Image

Figure 4.6  Creating a library at the right system scope

3.  Identify the shared library settings (see Figure 4.7). Before you set up the library, the best practice is to actually deploy the module. Enter the following:
Name: Classic Models BizLayer
Description: Customer Models sample Business Logic Layer components
Classpath: ${WAS_LIBS_DIR}/bizlayer
This step creates a directory under the WAS_LIBS_DIR called bizlayer, and places the JAR file and Spring libraries within this directory. WAS_LIB_DIR is a WebSphere variable that is usually set to the /WebSphere/AppServer/lib directory.

Image

Figure 4.7 Library settings

4.  Once the values are set up, click OK to create the shared library.

5.  WebSphere Application Server settings are never complete until you save the settings to the Master configuration. Click the Save link (see Figure 4.8) to record your changes to the Master configuration. Notice that the shared library is now set up within the console.

Image

Figure 4.8  Save shared library settings

Making the Library Visible

Creating the shared library is only half the battle. Now you have to make the library visible to other applications within the environment. I mentioned earlier that you could do this at a server-wide level or for specific applications. For this example, you set the class loading at the server-wide level. Later in this chapter I show you how to make the library visible at an application level. To make the shared library visible at a server-wide level, follow these steps:

1.  Click on Servers, Application Servers, server1 (see Figure 4.9). The configuration screen for server1 appears. In your environment it might not actually be server1, but in many environments this is a default setup.

2.  Under Server Infrastructure, click Java and Process Management then Class loader (see Figure 4.10).

Image

Figure 4.9  Choosing the server

Image

Figure 4.10  Server1 class loaders

3.  In some cases you may already have a class loader defined within the server environment. If not you will have to create a new class loader. To create a new class loader click New, as shown in Figure 4.11.

Image

Figure 4.11  Creating a new class loader

Two options or modes are available for class loading:

Classes loaded with parent class loader first. This is also known as the Parent First form of class loading.

Classes loaded with application class loader first. This is also sometimes called the Parent Last form of class loading.

4.  For this example you need Parent first, which is the default form of class loading for the application server. Choose this option and then click OK (see Figure 4.12).

5.  Once again save the configuration of the new class loader by clicking the Save link (see Figure 4.13).

The two pieces are now in place: the shared library and a class loader to apply it to. The next step is to map the two, which allows your application to find the classes within the shared library.

Image

Figure 4.12  Parent first class loading

Image

Figure 4.13  Saving the class loader

Mapping Shared Libraries to Class Loaders

Mapping shared libraries to the class loader takes just a few steps, as follow:

1.  Return to the class loader that you created in the last step in the preceding section. Notice that the ID of the class loader was defined for you by the server. This ensures that the server class loader instance is unique. Click on the Class loader ID (see Figure 4.14).

Image

Figure 4.14  Identify the class loader

2.  After the class loader configuration screen appears, under Additional Properties, click Shared library references (see Figure 4.15).

Image

Figure 4.15  Reference shared libraries

3.  In the screen that appears, click the Add button to create a new shared library reference (see Figure 4.16).

Image

Figure 4.16  Add a new shared library

4.  From the Library name drop-down list in the Configuration pane, choose the Classic Models shared library that you created earlier and then click OK (see Figure 4.17).

Image

Figure 4.17  Choose Classic Models library

5.  Finally, save your changes by clicking on the save link at the top of the screen.

That's it! I know it seems like a lot of steps but you can see how the different pieces fit together to provide you with a flexible way to provide access to shared libraries.

Testing the Business Layer

The whole point of this exercise is to provide a separate business layer that is accessible to the web application or presentation layer. With that in mind this chapter provides two separate web applications. Both of them access the shared library and use the HelloWorld service that it provides. I have stripped away much of the code from the BizLayerWebApp1 Servlet. This servlet uses the BizLayerDAO to get an instance of the Hello object and connect to the provided services.

package com.ibmpress.web.biztest1;

//import stuff


public class BizLayerWebApp1Servlet extends HttpServlet {       protected void doGet(HttpServletRequest request, HttpServletResponse
      response) throws ServletException, IOException {


    PrintWriter writer = response.getWriter();
    response.setContentType(“text/html”);


    writer.println(“BizLayerWebApp1Servlet<BR>”);

    //get an instance of the singleton
    BizLayerDAO dao = BizLayerDAO.getInstance();
    //now request the helloBean that will be passed to Spring.
    Hello helloBean = (Hello) dao.getBean(“helloBean”);


    //exercise the methods in the helloBean.
    writer.println(helloBean.helloWorld(“Joey”)+ “<BR>”);


    writer.println(helloBean.getWhosBeenHere()+“<BR>”);

    //let us know you used this instance.
    helloBean.setWhosBeenHere(“webapp1”);

  }
}

Both of the web applications have the same set of code, but by switching between the two you can see that each servlet sets a new value in the helloBean to identify that it has used this bean.

Controlling Shared Libraries

I mentioned earlier that you can also set up shared libraries in the class loader of a specific web application. Understanding the order for class loading can be important in debugging application problems. The dreaded “class not found” error can be difficult to diagnose, especially when you are behind in a deliverable. WebSphere provides some additional information that can help in this matter. Clicking on Troubleshooting, Class Loader Viewer and then drilling down into a specific server can provide a view of the class loading hierarchy.

Figure 4.18 shows the structure for this example. Notice that the shared library JAR files are loaded by the WAS Jar Extension Class Loader while the web application is loaded by the WAS Module – Compound Class Loader. You have a clear view of where specific classes are exposed within the server.

Image

Figure 4.18  Class loader viewer

I don't talk a lot in this book about packaging your applications. I'm more worried about some of the larger design concepts. But it is important to point out that class loading troubles have caused a lot of problems with application deployments. This situation is especially true when conflicts occur between dependencies that are required for an application and similar libraries that are already available within the WebSphere runtime. Often a team declares that it needs a different version of a specific library because of required features within a new version. This question is one that your standards and governance model should address, having an exception process available if necessary. But in addition to having multiple versions of the same libraries strewn across your environment, it can become a very real class loading problem.

I mentioned earlier that you could also map shared libraries at the web application level rather than across the entire server. You do so via the configuration screen for the web application itself. Follow these steps:

1.  Under References choose the Shared library references option (see Figure 4.19).

    You can map libraries at the application level or at the specific module level. For example, a single EAR file can contain several web modules, leading to mapping at the EAR level.

2.  In the screen that appears, click the check box next to the level you require and then click the Reference shared libraries button (see Figure 4.20).

Image

Figure 4.19  Application scope shared library references

Image

Figure 4.20  Choosing installed applications

3.  The final step is to map the available shared libraries to the module. Select the right modules, and click OK (see Figure 4.21).

Image

Figure 4.21  Mapping shared library references

In many cases mapping the shared library at the server level is sufficient, and it cuts down on management of the various libraries used within the application. In those cases where you don't want applications to access shared library functionality, then mapping at the application level is a very good way of managing those situations.

Implementation Options

One issue I have not discussed is how to determine the separation between the persistence layer and business logic. This example was purposefully contrived to not raise that question, but any real application is going to have to address this scenario. Many of the books available today on persistence and POJO type of development also ignore this separation.

Do we really care as long as we have a nicely crafted design that takes advantage of the best known practices? Probably not; but again, unless you outline clear rules to the development team (and follow up on the implementation) a nicely crafted design might not be what you end up with at the end of the project. In this enforced-rules type of effort the design becomes more a matter of discipline than of technical decisions. You determine what logic is needed within your application and business domain and how that logic is separated within appropriate layers.

The reality is this will probably never be perfect but if I can get you to consider this issue while designing your application then much of the battle will be won. The physical implementation of these layers helps to confuse the matter. Many of the frameworks that are used in persistence layers can also be used to provide business logic components: EJBs and Spring are two main culprits.

Another item that should be on your design agenda is whether to use Spring, as in the implementation of this example. I could have easily done without it, but I thought it was important to show some usage considering the growing popularity of Spring. Spring fills an obvious gap in the management of business objects within an application. Custom singleton and factory patterns can be difficult to create and manage, but Spring can provide this basic functionality in a robust framework. Now add in some true business object management value with dependency injection, aspects, and other features, and you begin to have an architecture that allows you to build business objects that are wrapped in a standard package.

Unfortunately one downside to using Spring is that it requires the development team to learn and understand more technology. In some cases there is no escaping this fact, but you are looking for a shared success, not to dazzle everyone with your technical brilliance. There is more to gain by delivering on time and under budget. Cases exist where development teams have dove headfirst into using Spring and encountered problems closer toward the release of the application. Spring can be doubly troublesome when coupled with a persistence framework such as Hibernate. The framework, the team, or the design is not to blame; it is simply the fact that the more complicated the design the higher the chance for problems.

Take a look at Figure 4.22 to get an idea of the potential complexity of Spring. Obviously the development team does not have to use all the packages available. In the last two chapters I have barely scratched the surface. But, do the development team members know which ones they can and can't use? Can you as the architect outline which packages are necessary and why you are requiring their use? All I request is that you look beyond the hype and understand the impact of the decisions you make in defining the architecture.

Image

Figure 4.22  Spring framework

Business Process Layers

Understand that as your application and organizational complexity grows so does the demand for managing and delivering advanced capability. In Chapter 1, “Application Architecture,” I outlined business process layers in addition to or alongside business logic functionality. It can be fairly confusing trying to distinguish between business process, business logic, and persistence logic within your application.

Business process or rather, workflow, is the idea of taking tasks and bringing them together to perform some business function. These tasks are usually tied together using some type of language with the standard being the Business Process Execution Language (BPEL). BPEL allows you to formally define the relationship between tasks and the flow of data between them. You can see where things can quickly get complicated if you were trying to build a custom process engine yourself. Because of that your organization will probably decide to use an available process engine such as WebSphere Process Server for this effort.

So where does this fit within the overall architecture? Figure 4.23 gives you a good idea of one approach that an application might take when incorporating a process layer. I call this a process layer even though it sits within its own container on a separate tier. From a logical point of view it is still a layer within the application architecture, albeit a fully distributed layer, that should be incorporated much like the other layers are used.

Image

Figure 4.23  Business logic and process layers

Notice that there is still a local service layer or service façade to provide services to the presentation layer. There is still the possibility that this layer could service multiple enterprise or web applications. In the case of WebSphere Process Server, this local interface could be provided by the WPS client that can be installed on the client server, or a custom interface could be provided on top of this client to help drive the application design.

In either case you can see how complex the environment is about to become and hopefully you can understand my insistence on your trying to keep things as disciplined and as simple as possible, although in many cases neither goal is possible to achieve. This book focuses solely on building custom WebSphere applications and cannot begin to explain the workings of WebSphere Process Server in sufficient detail. Fortunately, there is a book that focuses on this layer called WebSphere Business Integration Primer: Process Server, BPEL, SCA, and SOA by IBM Press (1. Iyengar, et. al. 2008).

Conclusion

I admit we have just scratched the surface in this chapter. The options are numerous in determining which approach you want to take with the middle layers. Leveraging the EJB layer as was discussed in Chapter 3 is a viable option. If you are looking for something more local or perhaps lightweight, then the POJO model with or without a framework like Spring may be appropriate. This is especially true when layers are deployed within the same package structure and not on separate tiers of the infrastructure. The singleton model, while the subject of much debate, can still provide value when used correctly. In any case, hopefully you understand more of the options available to you. It's not just EJBs or servlets anymore; middle layers can be supported by frameworks or full-blown application servers such as WebSphere Process Server.

Links to developerWorks Articles

A4.1 Designing the Business Service Layer Jul 2004 by Nalla Senthilnathanhttp://www.ibm.com/developerworks/web/library/wa-bsvlayer/

References

Iyengar, Ashok, Vinod Jessani, Michele Chilanti. (March 2008) WebSphere Business Integration Primer: Process Server, BPEL, SCA, and SOA. IBM Press.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.167.114