7.4 Application structure


7.4 Application structure

In this section, we explain the Design patterns to develop good object-oriented projects. The topics cover theory and practical samples. We do not discuss the samples in detail; if you need more information, refer to Chapter 8, "Application development" on page 157.

7.4.1 Device-specific content

Before we get into the Model-View-Controller (MVC) design concept, we need to take a look at the options and how the device-specific content can be processed .

There are two fundamental methods to providing device-specific content:

  • Generating the content in the code in a programmatic way. It is a direct solution using either different presentation pages or stylesheets.

  • Using an intermediary component, like a transcoding engine, that takes care of the content transformation. It is a configurable, intelligent engine that is capable of recognizing the device and transform the content as required on the fly.

For more information about the options described above, refer to the redbook Mobile Applications with IBM WebSphere Everyplace Access Design and Development , SG24-6259.

7.4.2 Model View Controller (MVC)

In the MVC paradigm, the user input, the modeling of the external components , and the visual feedback to the user are explicitly separated and handled by three types of object, each specialized for its task.

The View manages the graphical and/or textual output to the portion of the "bitmapped" display that is available for the application.

The Controller interprets the user inputs, commanding the model and/or the view to change as appropriate.

Finally, the Model manages the behavior and data of the application domain, responds to requests for information about its state (usually from the View), and responds to instructions to change state (usually from the Controller).

The MVC behavior is then inherited, added to, and modified as necessary to provide a flexible and powerful system.

To use the MVC paradigm effectively, you must understand the division of labor within the MVC tier. You also must understand how the three parts of the tier communicate with each other and with other active views and controllers; the sharing of a single mouse, keyboard and display screen among several applications demands communication and cooperation. To make the best use of the MVC paradigm, you also need to learn about the available subclasses of View and Controller which provide ready-made starting points for your applications.

In a general application, the input can be a specific hardware device or some specific data that identifies a client. For example, in the mobile realm, a piece of hardware can be a wireless phone or a PDA. These are different hardware devices that need differently supported presentations. The same output has a different presentation on a wireless phone and on a PDA. The important fact to remember is that an application should be client-independent.

An application that is only designed to support a specific type of client can be considered a "bad" application. For example, consider information that is requested by a mobile phone and by a PDA. The same information is being requested by the two different hardware devices. Why should applications be differently designed and implemented if they use the same business logic? Having two applications serving the same information results in duplicate components, duplicate maintenance and duplicate costs. How to avoid this problem will be explained later.

The best way to learn MVC is to understand the concept very well and practice in architecture design. In this project, the portlet development uses the MVC pattern.

It will be presented one component example that was applied the MVC pattern.

The first step is to design the components and put them in the right tier. To do this, some name convention were created. Take a look at the sequence diagram shown in Figure 7-6.

click to expand
Figure 7-6: Sequence diagram with MVC design

SearchProblem.jsp is one View component; this is a JavaServer Page and is responsible for viewing the data. The Controller in this diagram is the PortSearchKm , which is one portlet. This class has no business process and its responsibility is to interact with the Service Controller Singleton to get the references from EJB and call the business methods.

KmService is a stateless session bean that has the business methods. This bean works as a Session Facade and it is recommended that in a pervasive project, the portlets have no access to entity beans. Category and KM class are entity beans and they are responsible for interacting with the database records. There are other classes and applied patterns in this diagram. Refer to 7.4.4, "Applying the Design patterns" on page 135 for more information about the patterns that were applied.

In order to understand the physical implementation of this diagram, part of the code for each tier is shown.

The first sample code is a JSP. This code is responsible for viewing the data and sending it to the user.

Example 7-1: View tier - JSP
start example
 <%@ taglib uri="/WEB-INF/tld/portlet.tld" prefix="portletAPI" %> <%@ page import="com.ibm.itso.pervasive.model.CategoryVO" %> <%@ page import="com.ibm.itso.pervasive.model.KmVO" %> <%@ page session="false" %> <jsp:useBean id="categoryList" class="java.util.ArrayList" scope="request"/> <jsp:useBean id="solutionList" class="java.util.ArrayList" scope="request"/> <form name="<portletAPI:encodeNamespace value='frmSearchProblemJsp'/>" method="post" action="<portletAPI:createURI><portletAPI:URIAction name='select'/></portletAPI:createURI>"> <TABLE border="0"> <TR> <TD>Select Category Of Problem</TD> <TD><SELECT name="selCategoryID"> <% for(int x=0; x < categoryList.size(); x++) { CategoryVO category = (CategoryVO)categoryList.get(x); out.println("<OPTION value="); out.println(">" + category.getDescription() + "</OPTION>"); } %> </SELECT></TD> </TR> </TABLE> <INPUT type="submit" name="ok" value="OK"> <HR> <TABLE border="1"> <TR><TD>Problem</TD> <TD>Solution</TD> </TR> <% for(int y=0; y < solutionList.size(); y++) { KmVO solution = (KmVO)solutionList.get(y); %> <TR> <TD><%= solution.getProblem() %></TD> <TD><%= solution.getSolution() %></TD> </TR> <% } %> </TABLE> 
end example
 

In this code, you can see the data from other tiers and also HTML. This mix of Java and HTML code makes it unstructured and difficult to maintain. This code does not contain any transaction or business process and represents the View in the MVC pattern.

The next class is the Controller. This tier has no business process because it is responsible for calling the business methods. This code is more structured than the JSP code.

Example 7-2 shows a Controller in the MVC pattern; it is responsible for handling the requests.

Example 7-2: Controller tier - Java class
start example
 import com.ibm.itso.pervasive.ejb.*; import com.ibm.itso.pervasive.exception.*; import com.ibm.itso.pervasive.model.*; import com.ibm.itso.pervasive.foundation.*; public class PortSearchKm extends AbstractPortlet implements ActionListener {    //* Constants with pages to redirect    private final static String ERROR_PAGE = "GeneralErrorJsp.jsp";    private final static String FORM_PAGE = "SearchProblemJsp.jsp";    public void doView(PortletRequest req, PortletResponse res) throws PortletException, IOException {       ArrayList listCategories = new ArrayList();       ArrayList listSolution = new ArrayList();       //* get all categories       try {          KmServiceHome kmServiceHome = (KmServiceHome)ServiceLocator.getInstance().getHome("ejb/KmService");          KmService kmService = kmServiceHome.create();          listCategories = kmService.searchAllCategories();          req.setAttribute("categoryList", listCategories);       } catch (Exception e) {          e.printStackTrace(System.out);          req.setAttribute("errorMessage", e.getMessage());           getPortletConfig().getContext().include(ERROR_PAGE, req, res);       }       if (req.getAttribute("errorMessage") == null)          getConfig().getContext().include(FORM_PAGE, req, res);       else          getConfig().getContext().include(ERROR_PAGE, req, res);    } } 
end example
 

Example 7-3 on page 126 shows a Model class which contains the business logic. The code is well-structured and shows the method createOrder .

Example 7-3: Model Tier - Java Class
start example
 import com.ibm.itso.pervasive.model.*; import com.ibm.itso.pervasive.exception.*; import com.ibm.itso.pervasive.foundation.*; public class DefectServiceBean implements javax.ejb.SessionBean {    public void createOrder(Long defectID, String comments) throws PervasiveException {       try {          OrderHome orderHome = (OrderHome)ServiceLocator.getInstance().getHome("ejb/Order");          DefectHome defectHome = (DefectHome)ServiceLocator.getInstance().getHome("ejb/Defect");          DefectKey defectKey = new DefectKey(defectID);          Defect defect = defectHome.findByPrimaryKey(defectKey);          DefectVO defectVO = defect.getDefectVO();          //* create an service order          orderHome.create(defectVO.getCustomerID(), defectVO.getDefectID(), comments);          //* change the status of defect          defect.setStatusProblem(DefectVO.PROBLEM_CLOSE);       } catch (ObjectNotFoundException onf) {          throw new DefectNotFoundException();       } catch (Exception ex) {          throw new PervasiveException("This is not possible create one order for client", ex.getMessage());       }    } } 
end example
 

In Chapter 8, "Application development" on page 157, this code is explained in detail.

The goal is to understand the tiers and have one practical view of what each class needs to do.

MVC and portlets

Portlets include both visual elements and processing logic. A typical portal can include class files, Web pages, images and some deployment files. All of these files are packaged together into a .jar file, called a Web archive file (WAR). When writing custom portlets, a Model-View-Controller design is recommended, as shown in Figure 7-7 on page 127.

click to expand
Figure 7-7: Model-View-Controller tiers
  • The Controller is the class responsible for interfacing with the Model and for rendering the portlet by calling upon the appropriate View. The portlet class is responsible for executing this function.

  • Views are usually implemented as JavaServer Pages. Portlets may have several different Views, including their standard View (which renders the portlet on the home page), a maximized View (which renders the portlet in its maximized state), and an edit View (which displays a page for changing the portlet settings).

  • Models are usually implemented outside of portlet applications. The best approach is to implement the business logic using EJBs and just call the methods from the portlets.

The key is to separate the user interface from the business model so the user interface can be used for different Views. Portlets, JSPs, servlets and desktop applications can use the same business Model.

Pervasive portlets

Now that we have a background for a modular approach to application development, let's apply it to the pervasive development.

It is easy to see how the Model remains the same regardless of the actual display that is rendered. The Controller will essentially remain the same between the Views, but may need to perform some special customization of data based on the intended View.

Example 7-4 and Example 7-5 show a base Controller that contains common function for both the HTML and WML Views. In SampleBaseController, the methods to call the business operations and to pass the values in the request to an specific Controller are implemented.

Example 7-4: Controller for WML implementation
start example
 public class SampleWMLController extends SampleBaseController {   public void doView(PortletRequest request, PortletResponse response)     throws PortletException, IOException {       getPortletConfig().getContext().include("jspWML.jsp", request, response);   } } 
end example
 
Example 7-5: Controller for HTML implementation
start example
 public class WeatherHTMLController extends WeatherBaseController {   public void doView(PortletRequest request, PortletResponse response)     throws PortletException, IOException {       getPortletConfig().getContext().include("jspHTML.jsp", request, response);   } } 
end example
 

When you compare the sample codes, the difference that you can see is the page that the Controller will use to forward the response.

The View component has the flexibility to render the data for a best fit on the destination display. For example, SmartPhones display content in WML (Wireless Markup Language) or another markup language developed for phones.

We can define a separate view JSP for each intended device: an HTML JSP for browsers and a WML JSP for cell phones. Look at the sample portlet in Example 7-6 and Example 7-7 on page 129, which uses this design scheme and the WebSphere Portal pervasive APIs.

Example 7-6: JSP for HTML
start example
 <%@ page contentType="text/html" errorPage="" %> <jsp:useBean id="valueVO"      class="com.ibm.itso.model.ValueVO"      scope="request"/> <p> Value is <%= valueVO.showData() %> 
end example
 
Example 7-7: JSP for WML
start example
 <%@ page contentType="text/wml" errorPage="" %> <jsp:useBean id="valueVO"      class="com.ibm.itso.model.ValueVO"      scope="request"/> <p> Value is <%= valueVO.showData() %> 
end example
 

Since the HTML view is intended for a rich content client, it can show appropriate design for one device (the browser for example), but omit it from the WML view since this is a more constrained client.

Up to now, we have only described how to provide views for a large categorization of devices, assuming that a broad range of devices will have the same capabilities. However, this is not usually appropriate, particularly when referring to mobile devices. For example, some cell phones support WML V1.1, others support a subset of WML 1.2 (for example: no table support), and still others support the entire WML 1.2 specification. How is it possible to provide a view that is intelligent enough to take into account all these device variations without resorting to one that supports only the least common denominator of capabilities?

The IBM WebSphere Portal API provides a mechanism for a portlet to query the capabilities of the device for which the portlet view is intended. Instead of requiring every portlet to understand the capabilities of all User-Agent types, the Portal provides an abstraction between the User-Agent and device capabilities.

How does the Portal determine device capabilities? When an HTTP request is made to the Portal, the requesting device sends a field called User-Agent in the HTTP header that contains information about the requesting device.

For example, a Nokia Communicator 9110 sends the following User-Agent field:

 Nokia-Communicator-WWW-browser/3.0 (Geos 3.0 Nokia-9110) 

The Portal internally maintains mapping from the User-Agent field to the expected capabilities of the device. Thus, the Portal can know the capabilities of a device and provide that information to a portlet. This provides scalability considering that new User-Agent mappings can be added to the Portal as new devices become available, but portlets does not need to change their behavior. Rather, they use the same device capabilities abstraction to know how a particular view should be rendered.

This capabilities abstraction class, appropriately called Capability , is a part of the org.apache.jetspeed.portlet package. It provides generic capability attributes, such as what level of markup is supported (for example WML 1.1 versus WML 1.2), as well as more specific capabilities, such as what specific type of function is supported (for example: JavaScript versus no JavaScript).

It can be modified in the WML JSP to take into account the capabilities of the WML client. If the client does not support WML tables, then we will output straight text.

Example 7-8: Selecting the capabilities for the device
start example
 <%@ page contentType="text/wml" errorPage="" %> <%@ page import="org.apache.jetspeed.portlet.*" %> <jsp:useBean id="weatherBean"      class="com.ibm.wps.samples.weather.WeatherBean"      scope="request"/> <%@ taglib uri="/WEB-INF/tld/portlet.tld" prefix="portletAPI" %> <portletAPI:init />   <% if (portletRequest.getClient().isCapableOf(Capability.WML_TABLE)) {    //show the tale with data      } else {    //show data without table   } %> 
end example
 

Instead of using the previously described approach, Transcoding Technology can be used to transform the content. In this case, nothing in the code needs to be changed, because the Transcoding Technology will do it for you. The advantage of this approach is that you can publish your portlet for more pervasive devices.

The sample in this book was done with this approach using Transcoding Technology. For more information about Transcoding Technology, refer to 7.6.1, "Transcoding guidelines" on page 146.

7.4.3 Object-oriented Design patterns

Design patterns are common strategies for developing reusable object-oriented components. Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice. This definition is by Christopher Alexander and show perfectly the idea of the patterns.

We will now be talking about patterns for components design. The patterns that we will show in this chapter can be used in other solutions and in other programming languages. Design patterns can exist at many levels from a very low level to specific solutions to broadly generalized system issues. There are now hundreds of patterns in the literature; they have been discussed in articles and in conferences at all levels of granularity.

It has become apparent that you do not just write a Design pattern off the top of your head. In fact, most such patterns are discovered rather than written. The process of looking for these patterns is called "pattern mining".

Design patterns began to be recognized more formally in the early 1990s by Helm (1990) and Erich Gamma (1992), who described patterns incorporated in the GUI application framework and published the book Design Patterns - Elements of Reusable Software , by Gamma, Helm, Johnson and Vlissides (1995). This book, commonly referred to as the Gang of Four or "GoF" book, has had a powerful impact on those seeking to understand how to use Design patterns and has become an all-time best seller.

The authors divided these patterns into three categories: creational, structural and behavioral.

  • Creational patterns are ones that create objects for you, rather than having you instantiate objects directly. This gives your program more flexibility in deciding which objects need to be created for a given case.

  • Structural patterns help you compose groups of objects into larger structures, such as complex user interfaces or accounting data.

  • Behavioral patterns help you define the communication between objects in your system and how the flow is controlled in a complex program.

It is not the intention of this book to explain in detail all twenty-three patterns from the GoF, but to explain the main ideas around the most common patterns that we can use in portlet development. The patterns described are:

  • Singleton

  • Factory

  • Abstract Factory

  • Proxy

  • Decorator

  • Command

  • Facade

Singleton

This is a creational pattern that is used to ensure that a class has only one instance, and provide a global point of access to it. This pattern is interesting when you want to keep track of a sole instance. You can use this in many ways, for example, when you want to load application variables from a file or control the access to components.

The easiest way to make a class that can have only one instance is to embed a static variable inside the class that we set on the first instance and check each time we enter the constructor. A static variable is one for which there is only one instance, no matter how many instances there are of the class.

 static boolean instance_flag = false; 

The problem is how to find out whether or not creating an instance was successful, since constructors do not return values. One way would be to call a method that checks for the success of creation, and which simply returns some value derived from the static variable.

Another approach, suggested by Design Patterns, is to create Singletons using a static method to issue and keep track of instances. To prevent instantiating the class more than once, we make the constructor private so an instance can only be created from within the static method of the class.

This approach was used in the sample application.

Example 7-9: Singleton pattern
start example
 public static ServiceLocator getInstance() throws ServiceLocatorException{      if (myServiceLocator == null) {         myServiceLocator = new ServiceLocator();      }      return myServiceLocator; } 
end example
 

Figure 7-8 represents the class diagram for the Singleton pattern.

click to expand
Figure 7-8: Class diagram for Singleton pattern

Factory

This is a creational pattern that is used to define an interface for creating an object, but lets subclasses decide which class to instantiate. The Factory method lets a class defer instantiation to subclasses. This approach can be found in EJB technology for home and remote classes.

A Factory pattern is one that returns an instance of one of several possible classes depending on the data provided to it. Usually, all of the classes it returns have a common parent class and common methods, but each of them performs a task differently and is optimized for different kinds of data.

Abstract Factory

This is a creational pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes. This approach can be found in EJB technology for home and remote classes.

The Abstract Factory pattern is one level of abstraction higher than the Factory pattern. You can use this pattern when you want to return one of several related classes of objects, each of which can return several different objects upon request. In other words, the Abstract Factory is a factory object that returns one of several Factories.

Proxy

This is a structural pattern that provides a surrogate or placeholder for another object to control access to it.

The Proxy pattern is used when you need to represent a complex object with a simpler one. If creating an object is expensive in terms of time or computer resources, Proxy allows you to postpone this creation until you need the actual object. A Proxy usually has the same methods as the object it represents, and once the object is loaded, it passes on the method calls from the Proxy to the actual object. This approach can be found in remote implementation of EJB technology.

Decorator

This is a structural pattern that attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

The Decorator pattern provides a way to modify the behavior of individual objects without having to create a new derived class. Suppose we have a program that uses eight objects, but three of them need an additional feature. You could create a derived class for each of these objects, and in many cases this would be a perfectly acceptable solution. However, if each of these three objects requires different modifications, this would mean creating three derived classes. Further, if one of the classes has features of both of the other classes, you begin to create a complexity that is both confusing and unnecessary.

We can see this applicability in the portlet API. We have one skin for each portlet and the skin has some functionality such as resizing the portlet, call edit mode for personalization issues and so on.

In a portlet development, you extend the AbstractPortlet and do not care how the engine implements this class. In other words, it is totally transparent for portlet developers.

Command

This is a behavioral pattern that encapsulates a request as an object, thereby letting you parameterize clients with different requests, queue or log requests.

The Command pattern forwards a request to a specific module. It encloses a request for a specific action inside an object and gives it a known public interface. It lets you give the client the ability to make requests without knowing anything about the actual action that will be performed, and allows you to change that action without affecting the client program in any way.

Facade

This is a structural pattern that provides a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.

Usually, as programs are developed, they grow in complexity. In fact, for all the excitement about using Design patterns, these patterns sometimes generate so many classes that it is difficult to understand the program's flow. Furthermore, there may be a number of complicated subsystems, each of which has its own complex interface.

The Facade pattern allows you to reduce this complexity by providing a simplified interface to these subsystems. This simplification may in some cases reduce the flexibility of the underlying classes.

The class diagram for the Facade pattern is shown in Figure 7-9 on page 135.

click to expand
Figure 7-9: Class diagram for Facade

In this diagram, the DefectService works as a Facade. This class is responsible for interacting with many classes and the client. In this case, the portlet needs to talk only with DefectService to execute the operations.

7.4.4 Applying the Design patterns

The MVC can help you structure the tier in the application, but when you are developing components, there are many design problems that other patterns can help you deal with.

There are patterns for different solutions, but in this book we choose the patterns that you should use when you are developing solutions to Pervasive with WebSphere Portal Solution.

Data communication between the portlets and business tier

The business tier has server-side business components (session beans and entity beans). Session beans represent the business services and maintain a one-to-one relationship with the client. Entity beans are multi-user, transactional objects representing persistent data with a data store.

Some of the service methods may return data to the client that invoked the methods. In such cases, the client must invoke the session bean methods multiple times until the client obtains values for all the attributes. Every method call made is remote and takes time to complete the operation.

Efficient transfer of remote, fine-grained data by sending a coarse-grained view of the data is the key to the Value Object Pattern. Instead of transferring fine-grained data in multiple remote calls, transferring a value object reduces network traffic and simplifies entity beans and remote interfaces.

The Value Object pattern is used to encapsulate the business data. A single method call is used to send and retrieve the object. When the client requests the enterprise bean for the business data, the enterprise bean can construct the Value Object, populate it with its attribute values, and pass it by value to the client.

Clients usually require a lot of value from an enterprise bean and to reduce the number of remote calls and avoid the associated overhead, it is best to use value objects to transport the data from the enterprise bean to the client.

When an enterprise bean uses a value object, the client makes a single remote method invocation to the enterprise bean to request the value object instead of numerous remote method calls to get individual attribute values. The enterprise bean then constructs a new value object instance and copies the attribute values from its attributes into the newly created value object. It then returns the value object to the client. The client receives the value object and can then invoke its accessor (or getter) methods to get the individual attribute values from the value object. The implementation of the value object may be such that all attributes are made public. Because the value object has been passed by value to the client, all calls to the value object instance are local calls instead of remote method invocations. We have one value object example, as shown in Example 7-10.

Example 7-10: Value object example
start example
 public class CategoryVO implements Serializable {    private int categoryID;    public int getCategoryID() {       return categoryID;    }    public void setCategoryID(int categoryID) {       this.categoryID = categoryID;    } } 
end example
 

Getting the references to the business component

The portlet requires a way to look up the service objects that provide access to distributed components. The business component infrastructure (EJB) uses Java Naming and Directory Interface (JNDI) to look up enterprise bean home interfaces, data sources, connections, and connection factories. The lookup code is used many times by the project.

Unnecessary JNDI initial context creation and service object lookups can cause performance problems. The Service Locator pattern can help you resolve this problem. It centralizes distributed service object lookups, provides a centralized point of control, and may act as a cache that eliminates redundant lookups. It also encapsulates any vendor-specific features of the lookup process.

Service Locator abstracts the complexity of the network operation and lookup of various services. It can also cache the service object so that the expensive lookup operation does not have to be performed every time.

Here is one example of getting the reference in the Service Locator class.

Example 7-11: Service Locator class
start example
 public EJBHome getHome(String name)throws ServiceLocatorException {    Object objref = context.lookup(name);    EJBHome home = (EJBHome)PortableRemoteObject.narrow(objref, EJBHome.class);    return (EJBHome)PortableRemoteObject.narrow(home, home.getEJBMetaData().getHomeInterfaceClass()); } 
end example
 

The context of this code involves the ServiceLocator class (using Singleton pattern) and getHome method returning the EJBHome object from the bean we want to use. This method works between the portlets, stateless beans and entity beans. You can use this method to get all home lookups.

Structuring the requests

Portlet Applications is a Controller in the MVC Model. The action in the form goes to a method that understands the request and redirects to the appropriate business component. Portlets can have multiple actions to perform, unlike the servlets.

In this case, you have some options; one idea is to implement the command pattern (GoF) to encapsulate a request as an object, thereby letting you parameterize the client with different requests.

Another option is to use Struts. Struts is an Apache Jakarta open source project that provides a framework based on the Model-View-Controller (MVC) that allows developers to efficiently implement their Web applications, keeping the business logic and presentation aspects separate.

In the Portal Server environment, the ability to use Struts is a logical extension. The portlets on a Portal page can be essentially thought of as servlet applications in their own right. For many of the same reasons one would use Struts to implement a Web application, using Struts in a portlet would be desirable.




Patterns. Pervasive Portals
Patterns: Pervasive Portals Patterns for E-Business Series
ISBN: 0738427772
EAN: 2147483647
Year: 2002
Pages: 83
Authors: IBM Redbooks

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net