站内搜索: 请输入搜索关键词
当前页面: 图书首页 > Servlets and JavaServer Pages: The J2EE Technology Web Tier

Servlets and JavaServer Pages: The J2EE Technology Web Tier

[ directory ]Common Design Patterns Abstracting DHTML via Custom Tags

Jakarta Struts

The Struts Framework is often called "The Framework" for developing Model 2 Web Applications with Servlets and JSP. The Struts framework originated from the Apache Jakarta project, http://jakarta.apache.org, alongside Tomcat. Thanks to the dedication and support of many Jakarta developers, Struts quickly became a good framework for developing Model 2 Web Applications.

Struts is still a good framework to use for building Model 2 Web Applications. The Struts framework provides a project with a generic Control Servlet, a supporting tag library for creating forms, and other features such as internationalization support. The Struts framework comes with a full set of user and developer documentation, and Struts has one of the most active user communities around. For all of these reasons Struts is an excellent framework to both understand and use as a Servlet and JSP developer. To finish our discussion on design patterns, we will take a look at the Struts framework and some tips for using the framework to get a project off to a quick start.

Installing Struts

The Struts framework is available in both binary and source code distributions under the Apache Software Foundation license. The project can be used free for both commercial and non-commercial projects, but if you are unfamiliar with the Apache license, be sure to take the time to read and understand it. The Apache group has supported the development of some fantastic software, and the least you can do is spend the time to properly understand the page-long license.

Struts is being covered in this chapter because it is a helpful framework for developing Model 2 Web Applications. Leaving off discussion with a few simple Model 2 examples is no way to get you started on a real-world project. For the Struts discussion you will need to download the latest release of Struts. The specific version used by this book is the binary release of Struts 1.0.2. The release can be downloaded at http://jakarta.apache.org/struts. If you do not have this code, download it now.

What Is in Struts 1.0.2?

Included with Struts 1.0.2 are quite a few things including: Struts, documentation, examples, and a quick start Web Application. The Struts download explains all of this in its included documentation and the online version of the same. There is no point in this book providing a rehash of all of this excellent documentation, especially when the material covered here has the potential to be outdated by new releases of Struts. Instead, this chapter provides only a quick overview of Struts in an attempt to complement the documentation. You are wholeheartedly recommended to read the official, current documentation if you would like to use Struts with a project outside the scope of this book.

The only thing this chapter can do better than the Struts' documentation is give an objective view of Struts 1.0.2 functionality and explain how it works with all of the other concepts we have covered in this book. This is the approach that will be taken, but first you need to understand what comes with the Struts download.

Decompress the binary installation of Struts into a convenient directory. The following files are present:

In this chapter only a few of the included Struts files are examined. Installation of Struts with an existing and a new application are covered along with using the Struts controller Servlet. The example application, documentation, template, and tag library WAR files are not covered.

Creating a New Struts Web Application

Creating a new Struts-based Web Application from scratch is simple. The struts-blank.war file is a WAR that automatically deploys an empty Web Application with Struts pre-installed. Simply deploy the WAR file with a container to have a Web Application ready to go with Struts already installed. With Tomcat the Web Application can be deployed by copying struts-blank.war to the /webapps directory of Tomcat. Restart Tomcat and the WAR file is deployed to a sub-directory of the same name. Rename the WAR file before deploying the Web Application to get a custom-named directory.

After deploying the struts-blank.war file, the Web Application is ready to go. For the later examples of this chapter an example application is required. Copy struts-blank.war to the /webapps directory of your Tomcat installation. Restart Tomcat and the application is deployed. Browse to http://127.0.0.1/struts-blank to test if the new Web Application is correctly installed. If it is, the screen that is shown in Figure 11-12 should be displayed.

Figure 11-12. Deployment of Struts Blank Web Application

graphics/11fig12.gif


You now have a Struts-ready Web Application. As an example of how to use Struts we will re-implement the example Model 2 application with the Struts framework. Not all parts of the application need to be rebuilt. The JSP View pages can remain exactly as they are. Copy header.jsp, footer.jsp, index.jsp, about.jsp, news.xml, and addnews.jsp from the /webapps/jspbook/model2 directory to the /webapps/struts-blank directory of your Tomcat installation. For the View pages the JSTL is required. Copy over jstl.jar and standard.jar from the /webapps/jspbook/WEB-INF/lib directory to the /webapps/struts-blank/WEB-INF/lib directory of your Tomcat installation. The News JavaBean previously created is also re-used in the Struts version of the application. Copy News.java from the jspbook Web Application to the /WEB-INF/classes/com/jspbook directory of the struts-blank Web Application.

The Vew components are the only ones that seamlessly work with the new Struts-based Web Application. In the next few sections we will rebuild the Model and Control components to take advantage of Struts.

Installing Struts with an Existing Web Application

A Web Application can start using Struts at any time by installing and configuring the needed Struts resources. Compared to using the struts-blank.war file, manually installing Struts is slightly more difficult. Complete instructions for installation of Struts with an existing Web Application can be found in the Struts User Guide.

Struts Control Servlet

The core of the Struts framework is the pre-built Control Servlet. The Control Servlet is a configurable Model 2 Control component that allows for pluggable Model components and easy interaction with forms. We can take advantage of the Struts Control Servlet to provide a robust mechanism for the Model components of our Model 2 application. Recall this was the largest caveat of the previous Model 2 example. Struts provides a more appealing alternative to hard coding Model logic into ControlFilter.java.

Struts was built around the JSP 1.1 and Servlet 2.2 specifications. What this means is Struts does not currently take advantage of Filter functionality. Instead, the Struts framework relies on all requests ending with a fictitious extension, usually .do[3]. The control Servlet intercepts all requests with the fictitious extension and forwards them to the appropriate JSP or Servlet. The specific configuration for the Struts Control Servlet is an entry in web.xml, the same as any other Servlet. The struts-blank.war file automatically has the Servlet deployed. If you look in web.xml of the struts-blank Web Application, you should find the code in Listing 11-18.

[3] The .do extension is commonly used because it is what the Struts examples use, but any extension can be used.

Listing 11-18. Default Struts web.xml Entry
...
  <servlet>
    <servlet-name>action</servlet-name>
    <servlet-class>org.apache.struts.action.ActionServlet</servlet-
class>
...
  </servlet>

  <servlet-mapping>
    <servlet-name>action</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>
...

The Struts Control Servlet intercepts all requests ending in .do. Cut out from the preceding entry are the specific initialization parameters for the Control Servlet. All of these parameters are explained further by the Struts documentation. The default entry for the Control Servlet suffices for most situations including this example.

An important point to understand about the Control Servlet is how it differs from the previous Model 2 example's Filter. With the Filter, requests could go directly to a concrete endpointfor example, the URL for index.jsp is http://127.0.0.1/struts-blank/index.jsp. With the Struts Redirection Servlet all requests need to go to the fictitious .do endpoint. While the fictitious endpoint can be redirected to any concrete endpoint, the difference is usually just exchanging .jsp for .dofor example, a request to index.jsp would be done in Struts by requesting http://127.0.0.1/struts-blank/index.do. The difference is minor and only due to how Struts implements the Model 2 Control component.

There are pros and cons to implementing a Model 2 design with a Control component as either a Servlet or Filter. The general consensus is a Filter is the best approach. Seamlessly and cleanly stacking layers of Filters on top of a concrete endpoint is usually much more intuitive and requires less configuration. However, using the Struts approach is helpful because it keeps a layer of abstraction between all requests and the endpoints they link to. The abstraction is helpful in situations where the underlying endpoints need to change. However, the abstraction creates the classic Struts problem of ensuring potentially malicious users do not try to directly browse .jsp files instead of abstract .do mappings[4].

[4] Silly or not, the solution to this problem is usually to move all JSP source code to a subdirectory of /WEB-INF. By doing this no direct requests to the JSP can be made by outside clients, but internal Servlet redirection still works.

Actions

The great part about using Struts is taking advantage of the pre-built Model 2 Control component. With this part of the Model 2 application automatically installed and ready to go, the only thing we need to worry about is creating Model and View components. In Struts, Model components are referred to as Actions. The Control Servlet allows for a subclass of org.apache.struts.action.Action to encapsulate the business logic required for a particular request. An Action class in Struts is analogous to the hard-coded business logic used in ControlFilter.java.

Struts' Actions are a good reason to use the Struts controller versus the simple ControlFilter.java used previously in this chapter. By using Struts' Action classes all of the business logic associated with a particular View page is completely encapsulated in one class. This allows for Action classes to be easily plugged in for use and debugged should something go wrong. It also prevents the controller component from becoming bloated with all of the Model code. ControlFilter.java would quickly bloat with code should it be implemented in a real Web Application. An approach such as the Action classes Struts uses is clearly a better option.

Using Action Classes

Using an Action class requires two things: a subclass of Action used to encapsulate all of the business logic for a given request, and an entry to the Struts configuration file to allow Struts to associate a given request or set of requests with a given action.

The Action class acts as a base class for Java classes. A new Struts action class needs to extend org.apache.struts.action.Action and override the perform() method. The perform() method is invoked by the Control Servlet before forwarding a request to a View page. By encapsulating business logic in the perform() method, it is guaranteed to be executed before the request reaches the appropriate View.

The perform() method looks like this:




ActionMapping perform(ActionMapping am, ActionForm form, HttpServletRequest request,
graphics/ccc.gif HttpServletResponse response)

The perform() method is passed the same parameters as the Servlet service methods with additional parameters of a Struts org.apache.struts.action.ActionMapping class and an org.apache.struts.action.ActionForm class. The ActionMapping class is a representation of the configuration mapping Struts used to determine the appropriate Action class. The ActionForm class is an optional class that may be used to represent an HTML form-based request. Returned from the perform() method is an instance of org.apache.action.ActionForward providing information about what the Control Servlet should next do with a request. If null is returned, it is assumed the request and response are completely handled by the current Action class.

The skeleton of a custom Action class is always the same. Extend Action and override the perform() method. Listing 11-19 shows how the skeleton class would look in code.

Listing 11-19. BlankAction.java
package com.jspbook;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.struts.action.*;

public final class BlankAction extends Action {

  public ActionForward perform(ActionMapping mapping,
                               ActionForm form,
                               HttpServletRequest request,
                               HttpServletResponse response)
  throws IOException, ServletException {

    //handle request and response...

    return null;

  }
}

The preceding class is an example of a custom Action class that does nothing. A more practical implementation of the class would involve placing business logic where the comment is. Because the perform() method's parameters include the current HttpServletRequest and HttpServletResponse, the same business logic a JSP or Servlet would use can be used. Take for instance the code used in ControlFilter.java for the index.jsp. The same code authored as a Struts Action is as follows. Save Listing 11-20 as IndexAction.java in the /WEB-INF/classes/com/jspbook directory of the struts-blank Web Application.

Listing 11-20. IndexAction.java
package com.jspbook;

import java.io.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.struts.action.*;
import java.util.*;

public final class IndexAction extends Action {

  public ActionForward perform(ActionMapping mapping,
                               ActionForm form,
                               HttpServletRequest request,
                               HttpServletResponse response)
  throws IOException, ServletException {


    ServletContext sc = getServlet().getServletContext();

    try {
      String dir = sc.getRealPath("/");
      File file = new File(dir+"/news.xml");
      DocumentBuilderFactory dbf =
        DocumentBuilderFactory.newInstance();
      DocumentBuilder db = dbf.newDocumentBuilder();
      Document doc= null;
      if (file.exists()) {
        doc = db.parse(file);
      }
      if (doc != null) {
        NodeList nodes = doc.getElementsByTagName("story");
        Properties[] ads = new Properties[nodes.getLength()];
        for (int i = 0; i < nodes.getLength();i++) {
          Element e = (Element)nodes.item(i);

          ads[i] = new Properties();
          ads[i].setProperty("link", e.getAttribute("link"));
          ads[i].setProperty("title", e.getAttribute("title"));
          ads[i].setProperty("story", e.getAttribute("story"));
        }
        request.setAttribute("news", ads);
      }
    } catch(SAXException e) {
      throw new ServletException(e.getMessage());
    }
    catch (ParserConfigurationException e) {
      throw new ServletException(e.getMessage());
    }

    // Forward control to the specified success URI
    return (mapping.findForward("success"));
  }
}

The preceding code has two changes from the code used in ControlFilter.java for index.jsp. The first change is how the class accesses the Web Application's ServletContext object. The second change is the object returned by the perform() method.

The Action class is not an instance of a Servlet or Filter. With all of the previous examples in this book we have used either the ServletConfig or FilterConfig objects to access the Web Application's ServletContext. In ControlFilter.java the ServletContext object is required in order to find the correct location of news.xml.



...
    ServletContext sc = fc.getServletContext();
...
          String dir = sc.getRealPath("/model2");
          File file = new File(dir+"/news.xml");
...

In IndexAction.java the ServletContext object is accessed slightly differently. Instead of getting a reference from a configuration object, the getServlet() method is used to reference the Control Servlet, which in turn provides the getServletContext() method.



...
    ServletContext sc = getServlet().getServletContext();
...
      String dir = sc.getRealPath("/");
      File file = new File(dir+"/news.xml");
...

The change is due to a difference in how subclasses of Action access the appropriate ServletContext.

The second change is much more important and is heavily related to the Struts configuration file. Note IndexAction.java returns an instance of ActionForward retrieved from the ActionMapping parameter passed to the perform() method.



...
  public ActionForward perform(ActionMapping mapping,
                               ActionForm form,
                               HttpServletRequest request,
                               HttpServletResponse response)
  throws IOException, ServletException {
...
    return (mapping.findForward("success"));
...

The returned object is telling the Control Servlet the business logic has successfully completed and the View resource identified as "success" should now handle the request and response. In BlankAction.java a null value is returned. The null value informs the Control Servlet the response is finished, which is the same as skipping the optional invocation of FilterChain doFilter() in a Filter's doFilter() method. By returning an ActionForward object, the Action class is doing the equivalent of invoking the FilterChain.doFilter() method.

Unlike a Filter chain, the resources invoked by the Struts Control Filter are dependent on the Struts configuration file. The Struts configuration file is an XML configuration file that is used in a similar fashion as web.xml. By default the Struts configuration file is struts-config.xml located in the /WEB-INF directory. The Struts configuration file contains four different root elements for the different functionality Struts provides:

Right now we are only interested in using the Struts configuration file to define some action mappings. Edit struts-config.xml file in the Struts blank Web Application to include the code in Listing 11-21.

Listing 11-21. An Action Mapping for the Struts Configuration File
...
  <action-mappings>
    <action
      path="/index"
      type="com.jspbook.IndexAction">
      <forward name="success" path="/index.jsp"/>
    </action>
...
  </action-mappings>
...

This entry adds an action mapping for the /index URL (i.e., index.do) and the custom IndexAction class. The path attribute defines the abstract URL, and the type attribute defines the custom action class to use. Additionally, the forward sub-element is used to define an action forward named "success" that goes to index.jsp.

All parts of Listing 11-21 should be intuitive to understand. The entry associates IndexAction.java with index.do. Additionally, a View page is defined for "success", indicating index.jsp is a possible endpoint to use after invoking the perform() method of IndexAction.java. Recall in IndexAction.java the ActionForward object identified by "success" is always returned at the end of the perform() method. The ActionForward object is nothing more than an object representation of the forward element in the action mapping.

With the preceding entry in struts-config.xml and the newly made action class, Struts is ready to show the index page of the example Model 2 application. Before trying the code, be sure to compile IndexAction.java and copy over the relevant files (index.jsp, news.xml, header.jsp, and footer.jsp) to the struts-blank Web Application. Reload the struts-blank Web Application for the changes to take effect. Browse to http://127.0.0.1/struts-blank/index.do to see the newly made action mapping. Figure 11-13 shows a browser rendering of the results.

Figure 11-13. Browser Rendering of index.do

graphics/11fig13.gif


Additional action-mapping elements can be added to the struts-config file for any number of actions. A complete reference for the action-mapping element and the forward sub-element can be found with the Struts documentation in the Struts User Guide. The important functionality to understand is that Struts provides a convenient method to encapsulate and implement Model logic. This nicely complements the JSP view components we have previously seen and makes Struts a helpful framework to use.

Another action is required for the Model logic corresponding to addnews.jsp. The Struts action is very similar to IndexAction.java, but it encapsulates the Model code for addnews.jsp. Save Listing 11-22 as AddNewsAction.java.

Listing 11-22. AddNewsAction.java
package com.jspbook;

import java.io.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import javax.xml.transform.dom.*;

import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.struts.action.*;

public final class AddNewsAction extends Action {

  public ActionForward perform(ActionMapping mapping,
                               ActionForm form,
                               HttpServletRequest request,
                               HttpServletResponse response)
  throws IOException, ServletException {

    ServletContext sc = getServlet().getServletContext();

    try {
      String title = request.getParameter("title");
      String link = request.getParameter("link");
      String story = request.getParameter("story");
      if (title == null || title.equals("") ||
          story == null || story.trim().equals("") ||
          link == null || link.equals("")) {
        News an = new News();
        an.setTitle(title);
        an.setLink(link);
        an.setStory(story);
        request.setAttribute("form",an);

        return (mapping.findForward("failure"));
      }

      String dir = sc.getRealPath("/");
      File file = new File(dir+"/news.xml");
      DocumentBuilderFactory dbf =
        DocumentBuilderFactory.newInstance();
      DocumentBuilder db = dbf.newDocumentBuilder();
      Document doc = null;
      if (file.exists()) {
        doc = db.parse(file);
      } else {
        doc = db.newDocument();
        Element root = doc.createElement("news");
        doc.appendChild(root);
      }
      Element news = doc.createElement("story");
      news.setAttribute("title",title);
      news.setAttribute("link",link);
      news.setAttribute("story",story);
      doc.getDocumentElement().appendChild(news);

      TransformerFactory tf =
        TransformerFactory.newInstance();
      Transformer t = tf.newTransformer();
      DOMSource source = new DOMSource(doc);
      StreamResult result =
        new StreamResult(new FileOutputStream(file));
      t.transform(source, result);

      return (mapping.findForward("success"));
    } catch (TransformerException e) {
      throw new IOException(e.getMessage());
    }
    catch (SAXException e) {
      throw new ServletException(e.getMessage());
    }
    catch (ParserConfigurationException e) {
      throw new ServletException(e.getMessage());
    }
  }
}

The preceding code is a Struts action that encapsulates all of the business logic needed for addnews.jsp. There are two major changes between this code and the code previously used with ControlFilter.java. The Struts action returns two different ActionForward objects depending if the information submitted by a user is valid. If the information is valid, the ActionForward object is returned corresponding to "success".



return (mapping.findForward("success"));

Should the validation fail, an ActionForward object is returned corresponding to "failure".



...
      String title = request.getParameter("title");
      String link = request.getParameter("link");
      String story = request.getParameter("story");
      if (title == null || title.equals("") ||
          story == null || story.trim().equals("") ||
          link == null || link.equals("")) {
        News an = new News();
        an.setTitle(title);
        an.setLink(link);
        an.setStory(story);
        request.setAttribute("form",an);

        return (mapping.findForward("failure"));
      }
...

The "success" and "failure" mappings provide a method of choosing between the two responses possible for the form. If valid information is given, a new entry is created in news.xml and a successful transaction is made. If bad information is given, the transaction is a failure. The "success" and "failure" mappings are just self-named mappings for the two respective outcomes of validating the form information. The endpoint associated with "success" and "failure" is declared in struts-config.xml as follows. Edit struts-config.xml in the /WEB-INF directory of the struts-blank Web Application to include the code in Listing 11-23.

Listing 11-23. Action Mapping for addnews.jsp
...
  <action-mappings>
    <action
      path="/index"
      type="com.jspbook.IndexAction">
      <forward name="success" path="/index.jsp"/>
    </action>


    <action
      path="/addnews"
      type="com.jspbook.AddNewsAction">
      <forward name="success" path="/addnews_thanks.jsp"/>
      <forward name="failure" path="/addnews.jsp"/>
    </action>
...
  </action-mappings>
...

The two endpoints are the same ones used in ControlFilter.java; addnews_thanks.jsp for "success" and addnews.jsp for "failure".

With the new entry in struts-config.xml the page for adding news is ready to be used. Before trying out the page, compile AddNewsAction.java and reload the struts-blank Web Application for the changes to take effect. After reloading the Web Application, browse to http://127.0.0.1/struts-blank/addnews.do. The new action is used and addnews.jsp displays an HTML form. Figure 11-14 shows a browser rendering of the results.

Figure 11-14. Browser Rendering of addnews.do

graphics/11fig14.gif


The page functions the same as it did in the other example applications. If a user correctly fills out the form, a news entry is added to news.xml and the confirmation page is shown. Should a user leave any of the form fields blank, the form is redisplayed with all of the previously filled values included.

Using Struts

The Jakarta Struts framework is designed to do many things, but the most helpful thing the framework provides is a pre-built Control component and a method to encapsulate business logic. With the about, index, and add-news pages we have seen how Struts can be used to create a Model 2 Web Application.

Actions are the only Struts functionality we are going to cover in this chapter, but any experienced Struts user will be quick to point out that Actions are not the only things Struts provides. Struts does in fact have much more functionality, including a few tag libraries and an enhanced version of JavaBeans for working with HTML forms. These extra features of Struts are not covered for a few reasons. First, they are not relevant to this chapter. The reason Struts was introduced was to show a good implementation of a system that allowed for modular Model components to complement View components. That is exactly what was covered in this chapter. The second reason the extra Struts functionalities are not fully covered is because they are quickly becoming dated. Many of the most helpful features of Struts such as logic and iteration tags have been officially implemented in the JSTL. Both solutions work, but this book recommends learning the standardized JSTL. Finally, the framework is nice, but there are many ways to implement what some of the "helpful" features are trying to do. Apply the concepts presented in this book and your good judgment to find the best solution for you.

Struts is a great choice for cleanly modularizing Model, View, and Control components. When building a Model 2 Web Application for production use, keep Struts in mind. It is a good way to get a quick start implementing a Model 2 design pattern.

Model 1½

So far two design patterns have been presented: Model 1 and Model 2. We would strongly recommend that you use the Model 2 design pattern when possible, but as you will quickly find, the Model 2 design pattern initially takes a while to become familiar with. Building various different components and then assembling them together can be tedious. It can also slow down the time it takes to test changes. In other words, if you change a JSP, it is recompiled and redeployed automatically; if you change a Java class, you need to compile and deploy it manually. If you are used to building lots of JSP and few Java classes, you will likely agree that JSP is much quicker to develop with. However, if you are used to developing Java classes and have a nice build tool, such as Ant, you will be able to build Model 2 applications just as quickly as Model 1.

Why Model 1½ is brought up in this chapter is because it is a very practical technique for rapidly develop Model 2(ish) code. If you dislike using a build tool, or are in a situation where no build tool is available, Model 1½ is a great way to rapidly develop a Model 2like page, only using JSP. Then later on the Model 2like code can easily be changed to be a clean JSP and business logic encapsulated by a Java class. Another tangential reason that Model 1½ is introduced is that it is how the majority of this book's JSP examples are demonstrated. If an example used earlier in the book is helpful, it should be easy for you to port into a Model 2 application.

How the Model 1½ design pattern is implemented is simple. First, develop a JSP as if it were going to be part of a Model 2 Web Applicationthat is, only responsible for the display logic. Next, create one scriptlet at the head of the JSP that encapsulates all the business logic. For instance:



<%
  String foo = "Hello World";
  request.setAttribute("foo",foo);
%>
<html>
 Today's message is ${foo}.
</html>

While simplistic, you should get the point. The first part of the page handles all the business logic relating to the JSP: directives and bits of Java code for loading JavaBeans or other scoped variables.



<%
  String foo = "Hello World";
  request.setAttribute("foo",foo);
%>

Note that leaving the variables in implicit page scope is bad because a Model 2 Control component will not share page scope with the JSP. Always using either request scope, session scope, or application scope ensures the variables will be in a proper scope for either a Model 1 or Model 2 JSP.

The second part of the JSP is all of the presentation logicthat is, exactly what the JSP would have if it was being used in a Model 2 Web Application.



<html>
 Today's message is ${foo}.
</html>

In practice the Model 1½ design pattern works as follows. Use JSP to quickly develop possibly volatile code. Once the code is adequately tested, port all the business logic into a separate Java class and delete it from the JSP. By doing this, development time can be kept efficient, due to the JSP, and future maintenance can be kept efficient due to a modular Java class. The only slight disadvantage to the Model 1½ approach is that a Java class will not have the implicit JSP variables available for use. This can be solved easily by either naming the respective class variables identically to the JSP implicit variables or by doing a search and replace.

Weaknesses of Model 1½

In general Model 1½ is a helpful concept to be aware of. Being an overzealous Model 2 developer can make life difficult and can result in alienating nonModel 2 developers. Model 1½ is an illustration that the concepts of Model 2 can be applied in a Model 1 environment, thus providing a nice gray area of functionality between Model 1 and Model 2 design patterns. However, the Model 1½ design pattern is not perfect and is not a replacement for Model 2. Model 1½ still allows for the serious Model 1 flaws that Model 2 was designed to eliminate. By allowing scripting elements in a JSP, all of the Model 1 weaknesses are present in Model 1½. With Model 2 it is practical to add the scripting-invalid JSP 2.0 configuration element[5], to ensure no scripting elements are present when a JSP is being translated by a container. With Model 1½ it is not. Unless you are developing alone, or with a very benevolent group of developers, is it unwise to assume a Model 1½ design is really working.

[5] You can create a custom Tag Library Validator class in JSP versions prior to 2.0.

Another significant weakness of the Model 1½ design pattern is that it does not ensure appropriate error handling. One of the nice advantages of Model 2 is that the business logic can take full advantage of Java try-catch blocks, and a compiler will enforce that checked errors are handled appropriately. Because of the implicit try-catch block, which scriptlets havefor example,



try {
<% //scriptlet code  %>
}
catch (Exception e) {//JSP error handling}

There is no similar enforcement that Model 1½ code provides appropriate error handling. Porting Model 1½ code to a Model 2 design is tedious if the code was implemented assuming JSP error handling exists.

[ directory ]Common Design Patterns Abstracting DHTML via Custom Tags