Lessons Learned in Java Web Development

Designing web interfaces to achieve maintainable and extensible applications requires discipline. The best motivation for achieving this discipline is awareness of the consequences of failing to achieve it. The following brief discussion of the history of Java web development serves to illustrate the dangers that we must avoid.

The Shortcomings of Servlet-only Solutions

The first Java web technology was servlets. The first release of the Servlet API back in 1997 was an improvement on the dominant existing technology, the primitive Common Gateway Interface (CGI) standard for server-side script invocation. Instead of scripts written in languages such as C or Perl, which usually caused a new process to be created to handle each request, servlets allowed dynamic content to be generated by reusable Java objects. Servlets had full access to the power of the Java language, including JDBC and the Java object model, and so elevated web development to true OO development.

At least in theory - the Servlet specification was a big step forward, but developers soon ran into problems building real applications. Servlets proved very good at invoking business objects. However, generating complex markup from Java code is awkward. If markup strings are embedded in servlet and helper classes, changes to the presentation of web content always require modification of Java code and recompilation; Java developers must always be involved. Furthermore, it can be very difficult to see how a complete page is assembled from markup littered throughout Java objects, making sites very difficult to maintain. Servlets proved much more effective at generating binary content. However, this is a rarer requirement.

Important 

Generating markup from Java objects such as servlets is clumsy and leads to unmaintainable web applications. The servlet specification alone is not enough to meet the challenges of most web applications.

It was clear that additional infrastructure was needed. Many developers used templating approaches, in which markup was held outside Java code, with servlets responsible for generating only the dynamic content. However, there was no widely adopted standard.

JSP: Promise and Temptation

Thus the release of the JSP 0.92 specification in 1998 created widespread excitement. JSP was a standard templating solution, endorsed by Sun. Although JSP pages are transparently compiled into servlets by a web container, JSP pages use a very different approach from servlets. While servlets are Java objects capable of generating markup, JSP pages are markup components that permit escaping into Java as necessary to initiate processing.

JSP was soon in wide use, and overenthusiastic adoption led to a host of new problems. Experience quickly demonstrated that a model based on escaping into Java as necessary to generate dynamic content was a new evil in place of the old need to generate markup from Java code. The release of JSP 1.0 in 1999 was a significant improvement on JSP 0.92, but did not change the underlying model or address these problems.

"JSP Model 1" Architecture

To understand these problems, let's consider the simplest and most obvious architecture for a J2EE web application's interface. Imagine that we use JSP pages to implement the entire web interface. Each JSP handles incoming requests, creating domain objects from request parameters and using them to invoke business objects. Each JSP then renders the result of the business processing. The JSP infrastructure makes it easy to implement this approach, using JSP pages with a mix of markup and embedded Java code. The standard JSP infrastructure allows JSP pages:

  • To automatically populate JavaBeans declared on them with request parameter values, using the <jsp:useBean> standard action

  • To access and manipulate session attributes and application-wide ServletContext attributes

  • To perform any kind of logic using scriptlets (blocks of Java code embedded in JSP pages)

This kind of web application architecture is often termed the JSP Model 1 architecture. Core J2EE Patterns uses the more meaningful, but rather overblown, term, Physical Resource Mapping Strategy. I'll use the older term, JSP Model 1, in this chapter.

This approach is simple to implement. All we need to do is write the JSP pages and provide the support classes. There is no need to write servlets or define URL-to-servlet mappings in the web.xml deployment descriptor. Development-deployment cycles are often short, as JSP pages can be recompiled automatically by the web container as they are modified.

However, this approach mostly produces very poor results in practice. Applications built using this approach (and far too many are, even today), face the following severe problems:

  • Each JSP must either know how to handle all possible paths resulting from a request (for example, the path on invalid or missing parameters), resulting in complex conditionals; or must forward to another JSP as necessary, making application workflow hard to follow. It's a mistake to commit to one JSP when it's too early to predict what content we'll need to display.

  • Broken error handling. What if, halfway down the JSP, after the buffer has been flushed so it's too late to forward to another page, we encounter an exception? Although the standard JSP error page mechanism works well enough for trivial Model 1 systems, it won't help us in this plausible scenario.

  • The web interface is tied to JSP. In fact, JSP is just one view technology available to J2EE applications. JSP pages are unsuited to presenting binary data, and other technologies such as XSLT are superior at tackling some problems.

  • Java code in JSP scriptlets is hard to test and cannot be reused. Not only is this approach not object-oriented, it fails to deliver even the code reuse we would achieve in a well-written procedural application.

  • JSP pages will contain a mish-mash of markup and Java code, making them hard for either Java developers or markup experts to maintain.

  • JSP pages will bear little resemblance to the markup they generate. This defeats the point of using JSP pages, which are essentially markup components.

Important 

The JSP Model 1 architecture, in which JSP pages handle incoming requests, results in non-maintainable applications. JSP Model 1 should never be used in real applications: its only use is in prototyping.

The Temptation of the JSP Standard Infrastructure

Hopefully you're already convinced that JSP pages are not the ultimate answer to J2EE web interfaces. In case you aren't, let's consider some of the shortcomings of the JSP standard infrastructure, which makes it easy to attempt many things that subvert good design, and makes the JSP Model 1 architecture plausible on first impression.

Request parameters can be mapped onto JSP beans in two ways. Individual request parameters can be mapped onto a bean property using a <jsp:setProperty> action like this:

    <jsp:setProperty name="bean" property="propertyName" param="paramName" /> 

Alternatively, all request properties can be mapped onto a bean in a single <jsp:setProperty> action like this:

    <jsp:setProperty name="bean" property="*" /> 

The JSP mechanism for mapping request parameters onto bean properties is an unrealistically naÏve approach to data binding (a problem we'll discuss in detail later). Problems include the following:

  • There is no mechanism for handling type mismatches. For example, if the value of a parameter corresponding to an int property is non-numeric, the mapping will fail silently. The int property on the bean will be left with its default value. The bean isn't capable of holding the invalid value the user supplied on any resubmission page. Without checking the request parameter directly, we can't distinguish between a missing parameter and a type mismatch.

  • The only way to establish whether a parameter was supplied is to set the default to an out-of-band value. This may not always be possible.

  • There's no mechanism for handling any exceptions thrown by the bean's property setters.

  • There's no way to specify which properties are required and which are optional.

  • We can't resolve these problems by intercepting the handling of the fields: we have no control over how the mapping is performed.

We'll end up needing to write our own request handling code in the JSP to address these shortcomings, which defeats the purpose of the property mapping infrastructure.

Important 

The standard JSP infrastructure for mapping request parameters onto JSP beans is primitive and next to useless in real applications.

Another tempting feature of the JSP standard architecture, which encourages Model 1 architectures, but shouldn't be used in real applications, is the ability to define methods and even classes in JSP pages. Normally code in scriptlets ends up in the JSP's_jspService() method. By using <%! syntax instead of <% we can ensure that embedded Java code goes outside this method, defining methods, variables, and classes in the generated class itself.

JSP is very powerful, but its powerful, but its power creates as much danger as benefit. JSP lets us do anything we might legitimately want to do in a view, and a lot of things that we're best not to attempt. Since its initial release, JSP has gained new capabilities: most significantly, the addition of custom tags, which enable Java helper code to be concealed behind markup. However, the basic model hasn't changed, and nor has the fact that JSP pages are excellent at displaying data, and ill-suited to request processing and initiating business logic.

Striking a Balance

Both the approaches discussed so far – servlet-only and JSP Model 1 – have severe disadvantages and make it impossible to achieve separation of responsibility between Java developer and markup developer roles. Such separation is essential on complex web sites.

However, by using the two technologies together – servlets to handle control flow, and JSP pages or another view technology to render content – we can avoid the problems I've described.

A so-called JSP Model 2 architecture introduces a controller servlet as the central entry point, rather than individual JSP pages. The controller is responsible for request processing, and chooses a JSP to render content depending on request parameters and the result of the necessary business operations. In fact, as we'll see, there are many refinements to this model: it's important to avoid having a single "God" servlet, but ensure that the servlet works with a number of sub-controllers.

I won't refer to this as JSP Model 2 architecture, as in fact this architecture isn't dependent on JSP: it works with any templating technology. Its basis is servlets - by far the more important of J2EE web technologies. I'll use the term Front Controller pattern, which is used by Core J2EE Patterns. This is an attempt to apply the MVC architectural pattern (which we'll discuss further below) to web applications.

This pattern, which we'll discuss in detail below, is the key to designing maintainable J2EE web applications, and the central point of this chapter.

Important 

Both servlets and view technologies (such as JSP) are required for building maintainable J2EE web applications. Servlets and helper classes should be used to handle control flow and initiate business operations; JSP should only be used to render content.



Expert One-on-One J2EE Design and Development
Microsoft Office PowerPoint 2007 On Demand
ISBN: B0085SG5O4
EAN: 2147483647
Year: 2005
Pages: 183

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