Monday, March 24, 2008

Simplify Your Web Services Development with JSR 181

Source

By Ayyappan Gandhirajan

Go to page: 1 2 3 Next

Web Services are a true interoperable technology that enables disparate systems talk to each other using a common protocol. After realizing the potentials of Web Services in Application Integration and Service Oriented Architecture (SOA), the list of companies that embraces Web Services to gain edge over competitors is growing steadily. For the standardization of Web Service description, invocation and management, there are several specifications and standards available from Consortiums like W3C and OASIS. However, there are still issues in developing portable Web Services, which could run in any J2EE runtime environment. Though J2EE 1.4 tried to standardize the Web Service deployment process, the developers still have to create the deployment configuration files, create the WSDL from the Java class and package them together.

In order to trim down the complexities involved in the configuration and deployment of Web Services, the Java Specification Request (JSR) community endeavors to solve the problem by presenting us two JSRs:

  • JSR 181 — Web Services Metadata for the JavaTM Platform
    • Standardize the development of Web Service interfaces
  • JSR 921 — Implementing Enterprise Web Services 1.1
    • Standardize the vendor implementation of Web Services

This article is an attempt to highlight the features of JSR 181 specification and show you how easily you can build and deploy JSR 181 Web Services in WebLogic application server.

JSR 181 Web Services

JSR 181 or Web Services Metadata for the Java Platform is a Java Specification Request that defines an annotated Java format that uses Java Language Metadata (JSR 175) to enable easy definition of Java Web Services in a J2EE container. To put simply, JSR 181 enables developers to create portable Java Web Services from a simple Plain Old Java Object (POJO) class by adding annotations.

This Web Service development model may be related to JSP model where a JSP file is translated into a Servlet that gets in turn compiled to a class file that finally runs inside the container. The JSP model frees the developers from manual compilation and deployment of Servlets into container. Similarly in this model too, Web Service developers defines only the annotated Java Web Service (JWS) file and leave the job of creating necessary deployment and configuration files to the vendor (who actually implements Web Services based on JSR 921 specification). For example, WebLogic application server provides an Ant task called jwsc to create the JSR 921 compliant Web Service implementations. As the generation of JSR 921 compliant Web Services is hidden to developers, they can focus on developing core business services rather than worrying on learning and implementing generalized APIs and deployment descriptors.

The annotated Web Service development model also provides fine-grained control over exposing the Web Services. It enables the developers to expose the entire class or only the selected methods as the Web Service. This feature may be of great help when the Java class contains core business methods bundled along with non-business methods and/or data service methods, which the developer might not want to expose as services. In this scenario, the developer may take advantage of the annotations to specify how a Web Service should be exposed to outside world.

Putting simply, JSR 181 is a specification to define standard and portable Web Services. It offers the following benefits:

  • Provide a simplified model for developing Web Services
  • Abstract the implementation details
  • Achieve robustness, easy maintenance, and high interoperability

Sample Web Service Development

This section adopts the incremental development approach to guide you through developing a sample JSR 181 Web Service and deploying in WebLogic application server 10.0.

In the example, you will build a "Zip Code Finder" Web Service that has a single operation namely getZipCode. For a given pair of city and state, the getZipCode operation will return the corresponding zip code. Following are the step-by-step instructions:

Step 1 — Service end point object

The service end point object here is a simple POJO class that is going to be exposed as Web Service. This POJO class is a mock implementation of Zip Code Finder Service that returns 08817 (i.e., the zip code for "Edison, NJ") for any input pair of city and state. Listing 1 shows the complete code implementation.

Listing 1: Service end point object

package service;

public class ZipCodeFinderService {
public String getZipCode( String city, String state ) {
return "08817";
}
}

Step 2 — Declare POJO as Web Service

JSR 181 API provides an annotation type called @WebService to mark the Java class as Web Service. The @WebService annotation type has five attributes, which can be optionally used to define the port type and service name of the Web Service. Some of the important attributes are given below:

  • Name — Maps to wsdl:portType in WSDL 1.1
  • Service name — Maps to wsdl:service in WSDL 1.1
  • Target name space — Maps to targetNamespace in WSDL 1.1

Listing 2 shows the complete code implementation with @WebService annotation type:

Listing 2: Declaring WebService

package service;
import javax.jws.WebService;

@WebService ( name = "ZipCodeFinder",
serviceName="ZipCodeFinder",
targetNamespace = "http://sampleweb.com/services")


public class ZipCodeFinderService {
public String getZipCode( String city, String state ) {
return "08817";
}
}

The highlighted lines in Listing 2 (and the highlighted lines in rest of the listings in this article) will show you the incremental change that is done to the code displayed in Listing 1.

Step 3 — Declare SOAP Binding

This @SOAPBinding annotation type is used to define the Web Service binding. The Web Service developer may assign proper values for message encoding and format. This annotation type has following important attributes:

  • Messaging Style
    • Encoding style for message that is transported in the wire
    • Possible values: RPC or DOCUMENT
    • Default: DOCUMENT
  • Messaging Use
    • Formatting style for message that is transported in the wire
    • Possible values: ENCODED or LITERAL
    • Default: LITERAL
  • Parameter Style
    • Decides whether operation name needs to be part of the SOAP body
    • Possible values: BARE or WRAPPED
    • Default: WRAPPED

Listing 3 shows the code implementation along with @SOAPBinding annotation type:

Listing 3: Define SOAP Binding

package service;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;

@WebService( name = "ZipCodeFinder",
serviceName="ZipCodeFinder",
targetNamespace = "http://sampleweb.com/services")

@SOAPBinding( style = SOAPBinding.Style.DOCUMENT,
use = SOAPBinding.Use.LITERAL,
parameterStyle = SOAPBinding.ParameterStyle.WRAPPED )


public class ZipCodeFinderService {
public String getZipCode( String city, String state ) {
return "08817";
}
}

Step 4 — Optional Transport Declaration

You can use an optional WebLogic annotation type (not a standard) to refine the Web Service further. The @WLHttpTransport annotation type helps you change the context and service URI of the Web Service. The important attributes are:

  • Context Path — The context path of the Web Service URL
  • Service URI — Information next to context path in the Web Service URL

Listing 4 shows the implementation of the optional transport declaration:

Listing 4: Defining optional transport

package service;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import weblogic.jws.WLHttpTransport;

@WebService( name = "ZipCodeFinder",
serviceName="ZipCodeFinder",
targetNamespace = "http://sampleweb.com/services")

@SOAPBinding( style = SOAPBinding.Style.DOCUMENT,
use = SOAPBinding.Use.LITERAL,
parameterStyle = SOAPBinding.ParameterStyle.WRAPPED )

@WLHttpTransport( contextPath = "ZipCodeServices",
serviceUri = "ZipCodeFinderService" )


public class ZipCodeFinderService {
public String getZipCode( String city, String state ) {
return "08817";
}
}

Step 5 — Declare Web Method

This section will help you how to expose selectively the operations in the POJO class. For some scenario, you might want only to expose business operations and bar data operations in the Java class. In that scenario, you may find @WebMethod annotation type useful.

The @WebMethod has the following attributes:

  • Operation name — Name of the Java method that needs to be exposed as operation
  • Action — SOAP action

Listing 5 shows the implementation of the Web method:

Listing 5: Define WebMethod

package service;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import weblogic.jws.WLHttpTransport;

@WebService( name = "ZipCodeFinder",
serviceName="ZipCodeFinder",
targetNamespace = "http://sampleweb.com/services")

@SOAPBinding( style = SOAPBinding.Style.DOCUMENT,
use = SOAPBinding.Use.LITERAL,
parameterStyle = SOAPBinding.ParameterStyle.WRAPPED )

@WLHttpTransport( contextPath = "ZipCodeServices",
serviceUri = "ZipCodeFinderService" )

@WebMethod( operationName = "getZipCode" )
public class ZipCodeFinderService {
public String getZipCode( String city, String state ) {
return "08817";
}
}

Step 6 — Build file

To reiterate, the Web Service developer needs only to define the Web Service interfaces using JSR 181 annotation but does not need to worry about the remaining deployment process. The corresponding vendor platform, in our case WebLogic, will take care of implementing (or generating) necessary classes and configuration files, which are JSR 921 compliant.

As mentioned earlier, WebLogic application server provides an ant task namely jwsc. The ant task will take a few inputs like name of the annotated Web Service file name and build directory and then create the necessary files in EAR format, which can be deployed into WebLogic application server using a separate ant task (wldeploy) or manual deployment via administration console.

Listing 6 shows a sample ant configuration file with two important tasks:

  1. Build
    1. Clean directories and files generated as part of previous build (if any)
    2. Use jwsc to generate Web Service deployment files in EAR format
  2. Deploy
    1. Use wldeploy ant task to deploy the ear into WebLogic application server

Listing 6: Build file for building and deploying Web Service






jwsc"
classname="weblogic.wsee.tools.anttasks.JwscTask" />
all" depends="build, deploy" />
build" depends="clean, server" />
clean">


server">

srcdir="${basedir}/src/service"
destdir="${ear.dir}"
classpath="${java.class.path}"
fork="true"
keepGenerated="true"
deprecation="${deprecation}"
debug="${debug}"
verbose="false">



deploy">
<wldeploy action="deploy"
source="${ear.dir}" user="weblogic"
password="weblogic" verbose="true"
adminurl="t3://localhost:7001"
targets="AdminServer" />


Step 7 — Running build file

In order to run ant build and deploy targets, you will need to do the following steps:

  1. Open command prompt
  2. Call %WL_HOME%\server\bin\setWLSEnv.cmd
    1. This will set up all necessary path and classpath
  3. Now, run "ant build deploy"
    1. The build target will create necessary classes in a proper layout
    2. The deploy target will deploy the ear into application server

Step 8 — Testing

Now all dirty jobs of creating Java class, build files, running ant tasks are over. It is time to test the Web Service that was deployed in the previous steps.

If you strictly followed the steps mentioned above, the Web Service would be deployed with a URL http://localhost:7001/ZipCodeServices/ZipCodeFinderService and its WSDL can be accessed from http://localhost:7001/ZipCodeServices/ZipCodeFinderService?WSDL

This article does not create or attempt to create the Web Service client that can consume the deployed Web Services as nothing has fundamentally changed in the way the Web Service client works. You are encouraged to use whatever implementation you are comfortable to create Web Service clients.

I used Apache Axis 1.4 to create Web Service stubs to consume the deployed Web Service. The following listings (Listing 7 and Listing 8) capture the incoming and outgoing SOAP messages respectively.

Listing 7: Request SOAP message for Zip Code Finder Service





Edison
NJ



Listing 8: Response SOAP message for Zip Code Finder Service





08817



Comparison with conventional Web Services

The conventional Web Services development required developers to spend extra time in configuration and deployment whenever the underlying SOAP container was changed. The annotated Java Web services will save developers not to worry too much about deployment but concentrate on the core business areas.

The source level configuration of JSR 181 Web Services will also help the developers achieving uniform configuration and development process where the deployment of Web Service will be taken care by JSR 921 specification.

Conclusion

Web Service technology is one of those areas which evolves rapidly towards maturity. JSR 181 is an attempt to standardize and simplify the Web Service development, which will free you as a developer from the underlying implementation details and you concentrate on core business areas. Apart from standardization, they also help Web Service to achieve robustness, easy maintenance and interoperability.

Reference

About the author

Ayyappan Gandhirajan holds a Master's degree in Software Systems from BITS, Pilani, India and a Bachelor's degree in Electronics & Communication Engineering from MK University, India. He has 10 years of profound software experience in Travel, Telecom/Mobility, and e-commerce domains using technologies such as SOA, ESB, Web Service, Web Service Security, Spring, AOP and J2EE. He is currently working for Perot Systems, Bangalore, India. Before joining Perot Systems, he worked for good five years with Hewlett-Packard ISO, Bangalore, India. He can be reached at G_Ayyapparaj@yahoo.com / ayyappan.gandhirajan@ps.net

Working With Design Patterns: Facade

Source

By Jeff Langr

Go to page: 1 2 Next

Introduction

A software system is never a perfect thing. Developers almost always must balance system quality with demand. The software must be shipped; therefore, developers must proceed with what they think is the most appropriate design.

Developers also know much more about the actual use of the software once it ships. This effect is highly evident when they build a system that requires publicly exposed programmatic interfaces, or APIs (application programming interfaces). The primary goal of an API is to allow multiple parties to re-use the software product.

If only one party intends on ever using software modules, developers don't talk about a "public API" so much, and they don't spend a lot of time ensuring that it's as well-defined and forward thinking as possible. Things are still within their control, and thus easy to change. But, once an API is out of the bag—once other developers have begun to consume it—developers lose a lot of the ability to control it.

Case in point: the unfortunate design of the Java date and calendar classes. The getter methods (getMonth, getYear, and so forth) on the java.util.Date class, introduced in Java 1.0, have been marked as deprecated since version 1.1. I recall some mumbling from Sun about an internationalized date solution, and how the Date class wasn't it.

Sun couldn't change the Date class without breaking many applications, as it was already in heavy use. So, it introduced the heavyweight Calendar class to help resolve the problem, adding support for international applications. The resulting design is difficult at best. I've encountered countless shops that created a simpler solution by building a wrapper classes around Java's date-related library classes.

The wrapper classes these teams built are facades (also typed as façades, but the former is easier to type on a US keyboard). A facade, in software design terms, is an interface intended to simplify a more complex API. Introducing a facade simplifies conceptual understanding within a system, and thus helps keep maintenance costs low. It also allows increased flexibility by encapsulating the specific APIs that hide behind the facade.

The ProcessBuilder API, introduced in Java 2 SE 1.5, is another Sun solution that often promotes the introduction of a facade. (The ProcessBuilder class provides capabilities similar to the Runtime class that's always been a part of the Java class libraries.) Obtaining output from a command line application that writes to the console requires creating a separate thread, and two threads to obtain stderr output in addition to stdout.

As a programmer who simply wants to execute a command and grab its output, I find the API for ProcessBuilder too involved. Still, the design choice for ProcessBuilder is appropriate, because it supports ultimate flexibility. For example, I might want to do something special with the stdout thread for a command that produces voluminous output. But, most of the time, I want to bury all of that thread complexity behind a facade.

The Command class (see Listing 1) is a facade that simplifies interaction with a ProcessBuilder object and the Process objects it creates.

Listing 1: Command.

import java.io.*;

public class Command {
private String[] command;
private Process process;
private StringBuilder output = new StringBuilder();
private StringBuilder errorOutput = new StringBuilder();

public Command(String... command) {
this.command = command;
}

public void execute() throws Exception {
ProcessBuilder processBuilder =
new ProcessBuilder(command);
process = processBuilder.start();
collectOutput();
collectErrorOutput();
process.waitFor();
}

private void collectErrorOutput() {
Runnable runnable = new Runnable() {
public void run() {
try {
collectOutput(process.getErrorStream(),
errorOutput);
}
catch (IOException e) {
errorOutput.append(e.getMessage());
}
}
};
new Thread(runnable).start();
}

private void collectOutput() {
Runnable runnable = new Runnable() {
public void run() {
try {
collectOutput(process.getInputStream(), output);
}
catch (IOException e) {
output.append(e.getMessage());
}
}
};
new Thread(runnable).start();
}

private void collectOutput(InputStream inputStream,
StringBuilder collector) throws IOException {
BufferedReader reader = null;
try {
reader =
new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null)
collector.append(line);
}
finally {
reader.close();
}
}

public String getOutput() throws IOException {
return output.toString();
}

public String getErrorOutput() throws IOException {
return errorOutput.toString();
}
}

The ProcessBuilder-related code in the Command class isn't terribly complex. Still, to execute a single command and capture output, it's a bit more effort than I want to deal with. Using the Command class is much simpler:

   Command command = new Command("dir", "/");
command.execute();
System.out.println(command.getOutput());
System.out.println(command.getErrorOutput());
Note: The constructor for Command takes each command-line parameter as a separate string in a string array.)

Facades go to the core of the notion of information hiding in OO design. The ProcessBuilder and Process classes represent implementation details. The Command class interface reduces these details to a small set of abstractions: execute a command and get its output.

Testing and Facades

A test-driven approach will likely result in the creation of facades. Test-driven development (TDD) involves designing a system by writing tests to demonstrate exercising a class through its public interface. A developer looking to succinctly express a concept or policy in a unit test may find that it needs translation—a facade—to map to an underlying API.

The tests for the Command class appear in Listing 2. An interesting aspect of the CommandTest class is that it uses itself as the command-line application to test. This "self shunt" eliminates dependency on an external application or OS.

Listing 2: CommandTest.

import static org.junit.Assert.*;

import org.junit.*;

public class CommandTest {
enum TestName {
testSingleLine("a short line of text"),
testMultipleLines("line 1\\nline2\\n"),
testLotsOfLines("") {
String outputText() {
final int lots = 1024;
StringBuilder lotsBuffer = new StringBuilder();
for (int i = 0; i < lots; i++)
lotsBuffer.append("" + i);
return lotsBuffer.toString();
}
};

private String outputText;

TestName(String outputText) {
this.outputText = outputText;
}

String outputText() {
return outputText;
}
}

private Command command;

public static void main(String[] args) {
TestName testName = TestName.valueOf(args[0]);
System.out.println(output(testName));
System.err.println(syserrOutput(testName));
}

private static String syserrOutput(TestName testName) {
return testName.outputText.toUpperCase();
}

private static String output(TestName testName) {
return testName.outputText();
}

@Test
public void successfullyExecutesSingleLine()
throws Exception {
executeCommand(TestName.testSingleLine);
verifyOutput(TestName.testSingleLine);
}

@Test
public void successfullyExecutesMultipleLines()
throws Exception {
executeCommand(TestName.testMultipleLines);
verifyOutput(TestName.testMultipleLines);
}

@Test
public void successfullyExecutesLotsOfLines()
throws Exception {
executeCommand(TestName.testLotsOfLines);
verifyOutput(TestName.testLotsOfLines);
}

private void executeCommand(TestName testName)
throws Exception {
command = new Command(commandString(testName));
command.execute();
}

private void verifyOutput(TestName testName)
throws Exception {
assertEquals(output(testName), command.getOutput());
assertEquals(syserrOutput(testName),
command.getErrorOutput());
}

private String[] commandString(TestName testName) {
return new String[] { "java", "-classpath",
"\"" + System.getProperty("java.class.path")
+ "\"", "CommandTest",
testName.toString() };
}
}

Figure 1: Facade

About the Author

Jeff Langr is a veteran software developer with over a quarter century of professional software development experience. He's written two books, including Agile Java: Crafting Code With Test-Driven Development (Prentice Hall) in 2005. Jeff is contributing a chapter to Uncle Bob Martin's upcoming book, Clean Code. Jeff has written over 75 articles on software development, with over thirty appearing at Developer.com. You can find out more about Jeff at his site, http://langrsoft.com, or you can contact him via email at jeff at langrsoft dot com.

Working With Design Patterns: Bridge

Source

By Jeff Langr

Go to page: 1 2 3 Next

Design patterns exist for some of the most simple, fundamental object-oriented concepts. "These aren't patterns, these are things I've always used just as a regular part of doing OO," you might argue. The bridge pattern falls into this category of a concept so fundamental to OO that it seems to be overkill to consider it a pattern. But, understanding the bridge pattern in its simplest form allows you to understand its value in more complex circumstances.

The Design Patterns book provides a simple summary for the bridge pattern: "Decouple an abstraction from its implementation so that the two can vary independently." To construct code using the bridge pattern in Java, you define an interface and classes that implement the interface. That's it! The interface provides a consistent abstraction with which clients can interact. The interface also isolates the client from any knowledge of the specific type of implementation and from any implementation details.

The collections class framework in the Java API provides several examples of use of the bridge pattern. Both the ArrayList and LinkedList concrete classes implement the List interface. The List interface provides common, abstract concepts, such as the abilities to add to a list and to ask for its size. The implementation details vary between ArrayList and LinkedList, mostly with respect to when memory is allocated for elements in the list.

Your application can take advantage of this common interface: Wherever you would have a reference variable of either ArrayList or LinkedList type, replace the variable's type with the List interface type:

public void find(List patrons, Patron requested) {
for (Patron patron: patrons)
if (patron.equals(requested))
return patron;
return null;
}

The logic in the find method doesn't care if the list of patrons is implemented as an array or a linked list. This use of the bridge pattern improves the maintainability of your code. If all of your code is structured this way, you can change your code from using an ArrayList to a LinkedList, or vice versa, in one place.

If you do test-driven development (TDD), the bridge pattern is indispensible when it comes down to implementing mocks. If your test targets a class whose collaborator is giving you testing headaches, the bridge pattern can be of assistance. You extract an interface from the troublesome collaborator. You then can build a test double (aka a mock) for the collaborator. This test double is a class that implements the same interface and thus emulates, or mocks, the collaborator. Your unit test can inject the test double into the target, thus "fixing" the collaborator for purposes of testing. The test target is none the wiser!

Listing 1 shows two classes that represent another potential application of the bridge pattern. Each of BookHtmlFormatter and BookPrintFormatter provides a print method. The job of this method is to return a nicely formatted string for a book in a library system, with the formatting dependent upon whether the book information is going to be printed on a receipt or as part of a web page.

Listing 1: Simple implementations.

// BookHtmlFormatter.java
public class BookHtmlFormatter {
public String print(Book book) {
StringBuilder builder = new StringBuilder();
builder.append(book.getClassification() + "
");
builder.append("");
builder.append("
");
builder.append("");
builder.append("");
builder.append("");
builder.append("");
builder.append("");
builder.append("
AuthorTitle Year
" + book.getAuthor() + "" + book.getTitle() + "" + book.getYear() + "
");
return builder.toString();
}
}

// BookPrintFormatter.java
import static util.StringUtil.*;

public class BookPrintFormatter {
public String print(Book book) {
StringBuilder builder = new StringBuilder();
builder.append(book.getClassification() + EOL);
builder.append("Author: " + book.getAuthor() + EOL);
builder.append("Title: " + book.getTitle() + EOL);
builder.append(book.getYear() + EOL);
return builder.toString();
}

}

You can extract a common interface, and have each of the two formatter classes implement this interface (see Listing 2).

Listing 2: A simple bridge.

public interface Formatter {
String print(Book book);
}

public class BookPrintFormatter implements Formatter {
// ...
}

public class BookHtmlFormatter implements Formatter {
// ...
}

The predominance of client code now can work with a Formatter reference. If you design your application carefully, you'll need only instantiate the concrete formatter types in one place.

Formatter formatter = new BookHtmlFormatter();
String text = formatter.print(book);

Simplifying Class Combinations

Now, suppose you also need to print movie information in a slightly different format on both the web and on receipts. In fact, you probably also want to print similar information for other media types in the library, such as audio tapes. Further, you may need to start printing onto different media in a different format, such as microfiche. These new requirements could require you to create an explosion of combinations: BookFicheFormatter, TapeHtmlFormatter, TapeFicheFormatter, and so on. Instead, the strength of the bridge pattern will help you keep some sanity in class organization.

The path to deriving an improved solution through use of the bridge pattern is recognizing two things. First, the code BookHtmlFormatter and BookPrintFormatter violates the single responsibility principle. The print method combines formatting information with the data (and organization of such) to be formatted. Second, any new combined derivative (for example, TapeHtmlFormatter) will necessarily need to introduce redundancies with the existing implementation, something you really want to avoid.

By using the bridge pattern, you separate the two SRP-violating concerns into two separate hierarchies. A Printer hierarchy represents the client's abstract need to extract information and organize a printout. The need to format elements properly, depending on the output medium (HTML or printer), is abstracted into a separate Formatter hierarchy. See Figure 1 for the UML.

Listing 3 shows the code for the abstractions, derived by a number of simple refactorings against the current implementation. Note the introduction of a new class, Detail. The Detail class is a simple structure that holds onto a label and the corresponding value for that label.

Listing 3: Abstractions for the bridge.

public abstract class Printer {
public String print(Formatter formatter) {
return formatter.format(getHeader(), getDetails());
}

abstract protected Detail[] getDetails();
abstract protected String getHeader();
}

public interface Formatter {
String format(String header, Detail[] details);
}

public class Detail {
private String label;
private String value;

public Detail(String label, String value) {
this.label = label;
this.value = value;
}

public String getLabel() {
return label;
}

public String getValue() {
return value;
}

}

Th BookPrintere class (see Listing 4) is a derivative of the Printer abstract class. It fills in the holes in the template method print, defined in Printer, by supplying code for the getHeader and getDetails abstract methods. These methods take specific Book information and organize them for the report. The Printer method print simply delegates this captured information over to the Formatter object. Listings 5 and 6 provide the code for the two formatter implementations.

Listing 4: BookPrinter.

public class BookPrinter extends Printer {
private Book book;

public BookPrinter(Book book) {
this.book = book;
}

protected String getHeader() {
return book.getClassification();
}

protected Detail[] getDetails() {
return new Detail[] {
new Detail("Author", book.getAuthor()),
new Detail("Title", book.getTitle()),
new Detail("Year", book.getYear()) };
}
}

The formatter classes hide all of the ugliness and detail behind making a report look nice, whether HTML tags or appropriate space padding is required.

Listing 5: The HTML formatter class.

public class HtmlFormatter implements Formatter {
@Override
public String format(String header, Detail[] details) {
StringBuilder builder = new StringBuilder();
builder.append(header + "
");

builder.append("");
appendDetailHeader(builder, details);
appendDetail(builder, details);
builder.append("
");

return builder.toString();
}

private void appendDetail(StringBuilder builder,
Detail[] details) {
builder.append("");
for (int i = 0; i < details.length; i++)
builder.append("" + details[i].getValue() +
"");
builder.append("");
}

private void appendDetailHeader(StringBuilder builder,
Detail[] details) {
builder.append("");
for (int i = 0; i < details.length; i++)
builder.append("" + details[i].getLabel() +
"");
builder.append("");
}
}

Listing 6: The plain print formatter class.

import static util.StringUtil.*;

public class PrintFormatter implements Formatter {

@Override
public String format(String header, Detail[] details) {
StringBuilder builder = new StringBuilder();
builder.append(header + EOL);
int longest = getLongestSize(details);
for (int i = 0; i < details.length; i++) {
int length = details[i].getLabel().length();
String pad = spaces(longest - length + 1);
builder.append(details[i].getLabel() + ":" + pad +
details[i].getValue() + EOL);
}
return builder.toString();
}

private String spaces(int number) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < number; i++)
builder.append(' ');
return builder.toString();
}

private int getLongestSize(Detail[] details) {
int longest = 0;
for (int i = 0; i < details.length; i++)
if (details[i].getLabel().length() > longest)
longest = details[i].getLabel().length();
return longest;
}
}

The client code changes to take advantage of the bridge pattern:

Formatter formatter = new HtmlFormatter();
String result = new BookPrinter(book).print(formatter);

Short-term, implementing the bridge pattern can be overkill. Sometimes, the separation isn't worth it: A couple of classes in a couple of potentially related hierarchies might be more simply stated as four combined subclasses. But, imagine the work behind half a dozen media types and another half a dozen print formats. Look for frequency of change and common sense to be your guide.



Click here for a larger image.

Figure 1: Bridge

About the Author

Jeff Langr is a veteran software developer with over a quarter century of professional software development experience. He's written two books, including Agile Java: Crafting Code With Test-Driven Development (Prentice Hall) in 2005. Jeff is contributing a chapter to Uncle Bob Martin's upcoming book, Clean Code. Jeff has written over 75 articles on software development, with over thirty appearing at Developer.com. You can find out more about Jeff at his site, http://langrsoft.com, or you can contact him via email at jeff at langrsoft dot com.

Working With Design Patterns: Singleton

Source


By Jeff Langr

Go to page: 1 2 Next

The singleton is perhaps the most maligned software design pattern out there. It's right up there with the visitor pattern, which is often denigrated by developers as too complex. Yet, the notion behind singleton is simple: ensure that only one instance of a specific type exists during application execution.

The default Java behavior, as with most languages, allows you to create as many instances of a given class as you want. Up until J2SE 5, Java allowed no direct way to impose a restriction on the number of instances. In J2SE 5 and later versions, you can use the enum construct to constrain how many objects of a given type exist. You can also provide a unique name for each of these known instances.

In languages such as C and C++, an enum ("enumeration") is simply a series of integral values, where each element in the series maps to a unique symbol. The use of enums allows you to craft more expressive code. In Java, the enum is better viewed as a class like any other, except for a few key differences. An enum can have constructors, methods, and fields, but it cannot be subclassed. An enum definition first supplies the names of the known instances; no other instances can be created by any means.

From a simplistic standpoint, you could consider the catalog in a library system a candidate for a singleton. After all, you don't want to have to know what books were added to what catalog. Listing 1 shows how you might implement the catalog singleton using the enum construct.

Listing 1: The catalog singleton, expressed as an enum.

import java.util.*;

public enum Catalog {
soleInstance;

private Map books = new HashMap();

public void add(Book book) {
books.put(book.getClassification(), book);
}

public Book get(String classification) {
return books.get(classification);
}
}

Not much to it, is there? Client code must refer to the single known object, soleInstance (see Listing 2).

Listing 2: Accessing the enum singleton.

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

public class CatalogTest {
@Test
public void singleBook() {
Book book = new Book("QA123", "Schmidt", "Bugs", "2005");
Catalog.soleInstance.add(book);
assertSame(book, Catalog.soleInstance.get("QA123"));
}
}

If you attempt to directly instantiate another Catalog object:

   new Catalog();    // this won't compile!

...your code will not even compile, as the comment states.

Is this really a design pattern? Well, yes, it's an implementation of a design pattern, one that the Java language makes very simple.

Most developers are probably more familiar with the concept of "rolling their own" singleton. In Java, this means supplying a static-side creation method and making the constructor private. See Listing 3.

Listing 3: Hand-grown catalog singleton.

import java.util.*;

public class Catalog {
private static final Catalog soleInstance = new Catalog();
private Map books = new HashMap();

public static Catalog soleInstance() {
return soleInstance;
}

private Catalog() {
// enforce singularity
}

public void add(Book book) {
books.put(book.getClassification(), book);
}

public Book get(String classification) {
return books.get(classification);
}
}

The private constructor ensures that no other clients can create a Catalog object. From the client standpoint, things don't look very different (see Listing 4).

Listing 4: Accessing the hand-grown singleton.

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

public class CatalogTest {
@Test
public void singleBook() {
Book book = new Book("QA123", "Schmidt", "Bugs", "2005");
Catalog.soleInstance().add(book);
assertSame(book, Catalog.soleInstance().get("QA123"));
}
}

Seems like a simple, harmless pattern. So what's all the fuss?

Well, a single is simply object-oriented speak for a global variable. The software development community has long known about problems that global variables introduce. Primarily, global variables can become a sinkhole for things that introduce tight coupling across your application.

The first thing to consider is that maybe you don't need a global variable or singleton. What would be the true harm if you created multiple instances of the potential singleton? What if you instead redesigned it to allow multiple instances? Sure, semantically there's only one master catalog in real life. But, you can design the Catalog class to encapsulate the books hash map as a static field. Your clients can create all the Catalog instances they want, but all of them point to the same static field. (This is a pattern known as monostate, by the way.)

For all the negativity about global variables and singletons, it's still a potentially legitimate construct. So, how do you know if your singleton is ill-conceived? The answer as always is testing!

You won't know whether your singleton is a problem until you try to test one of its clients. Suppose you are building a library API that interacts with the catalog, among other domain objects. Right now, such interactions probably aren't a problem, because the Catalog class is a simple hash map. But, what if the Catalog class interacted with a real database (see Listing 5)?

Listing 5: A dependency challenge.

import java.sql.*;
import java.util.*;

public class Catalog {
private static final Catalog soleInstance = new Catalog();

public static Catalog soleInstance() {
return soleInstance;
}

private Catalog() {
// enforce singularity
}

public void add(Book book) {
try {
Connection connection = ConnectionPool.get();
Statement statement = connection.createStatement();
statement.execute("insert into book // ...
// ...
}
}
//
}

Databases are always big headaches for testing. Of course, you want to verify that your Catalog class correctly interacts with Oracle and that all of your DDL is aligned with the Java code. But, you also want to verify the rest of the business logic in your application. You can do that using live interactions with the database, but such tests are very slow. They're also very painful to construct and maintain, for several reasons.

To test the rest of the classes in the system—the clients of Catalog—what you'd really like to do is to emulate the behavior of the Catalog class in what's known as a test double. At an abstract level, Catalog supports the ability to store and retrieve books associated with a specific classification. You want to mock that persistence behavior. Maybe all you really need is the map implementation above.

Unfortunately, the singleton construct says that you're stuck with the version of Catalog that mucks with JDBC. This is the chief problem with singleton: It prohibits you from creating a test double.

If you can't or won't redesign your singleton so that creating multiple instances is not harmful, there's another, better solution: Don't enforce the singleton. Right in the class file, add a comment (yes, a wonderful use of comments) to the constructor of Catalog:

public Catalog() {    // create only one, except for testing!
}

The reactions to this solution are sometimes very poor. "What if someone does create an instance?" Well, then, you have a bigger problems than the singleton. If developers won't read how to properly use a class, and heed the advice, why produce all that Javadoc that your shop no doubt requires? What's the point of code reviews, if they can't catch problems like this?

In fact, all sorts of conventions can easily be circumvented by a nefarious developer. Java even allows external access to private fields through reflection tricks! Sometimes, the best solution is to simply say, "don't do that."

You still can model the Catalog class similar to a singleton but provide hooks to allow it to cough up test doubles. You remove the private constructor from the Catalog class (see Listing 6). You provide a setInstance method to allow replacing the true, production singleton with a Catalog test double. Note the comment! You also can provide a reset method that tells the Catalog to begin using the production instance again. The reset ensures that your test doesn't gum up any other tests that expect to use the production Catalog instance.

import java.util.*;

public class Catalog {
private static final Catalog DEFAULT = new Catalog();
private static Catalog soleInstance = DEFAULT;

private Map books = new HashMap();

public static Catalog soleInstance() {
return soleInstance;
}

// use for testing
public static void setInstance(Catalog catalog) {
soleInstance = catalog;
}

public static void reset() {
soleInstance = DEFAULT;
}
// ...
}

In summary, don't throw away your singletons! Just make sure that they don't cause any unit testing challenges.

About the Author

Jeff Langr is a veteran software developer with over a quarter century of professional software development experience. He's written two books, including Agile Java: Crafting Code With Test-Driven Development (Prentice Hall) in 2005. Jeff is contributing a chapter to Uncle Bob Martin's upcoming book, Clean Code. Jeff has written over 75 articles on software development, with over thirty appearing at Developer.com. You can find out more about Jeff at his site, http://langrsoft.com, or you can contact him via email at jeff at langrsoft dot com.

Sunday, March 23, 2008

Redirect after Post

Redirect After Post

August 2004

Source



All interactive programs provide two basic functions: obtaining user input and displaying the results. Web applications implement this behavior using two HTTP methods: POST and GET respectively. This simple protocol gets broken when application returns web page in response to POST request. Peculiarities of POST method combined with idiosyncrasies of different browsers often lead to unpleasant user experience and may produce incorrect state of server application. This article shows how to design a well-behaved web application using redirection.

Double Submit problem

Two most frequently used HTTP request methods are GET and POST. GET method retrieves resource from a web server. Resource is identified by base location and optional query parameters. Generally, parameters of GET request are used to narrow the result and do not change server state. The same GET request can be sent to the server as many times as needed.

On the contrary, parameters of POST request usually contain input data, which can change state of server application. Same data submitted twice may produce unwanted results, like double withdrawal from a bank account or storing two identical items in a shopping cart of an online store. Submission of the same data more than once in a POST request is undesirable and got its own name: Double Submit problem.

Take the standard use case with HTML FORM submitted to the server. Form data is processed and stored in the database, then server replies with a page containing results of operation.

In the above use case the same POST request can be resubmitted using three methods:

  • reloading result page using Refresh/Reload browser button (explicit page reload, implicit resubmit of request);
  • clicking Back and then Forward browser buttons (implicit page reload and implicit resubmit of request);
  • returning back to HTML FORM after submission, and clicking Submit button on the form again (explicit resubmit of request)

Considering the importance of POST data, browsers display a warning when the same POST request is about to be resent to the server. But the message is too technical and obscure for an average user. Also, some browsers do not ask for confirmation at all. Because of that many web sites show their own warnings. How often do you see messages like "Please do not click Back button or refresh this page" after you made an online payment?

The warning messages and confirmation dialogs clutter the interface and make a user feel nervous and uneasy, always afraid to make a mistake. If a web site relies on browser warnings but does not really check for double submit, the server database may become incorrect, while a user would lose confidence in internet transactions.

Is it possible to get rid of irritating warnings? Yes. HTML FORM submission method can be changed from POST to GET. Browsers are not required to ask confirmation when GET request is resubmitted, so this change makes user interface friendlier. But this "solution" breaks the semantic of GET method. It does not prevent resubmitting, it just hides the problem from a user.

The PRG pattern

The answer to double submit problem is redirection. This is a known technique, but it has not become a standard for "after-POST" results yet. As far as I know it does not have a well-known name. I suggest calling it PRG pattern for POST-REDIRECT-GET.

PRG pattern splits one request into two. Instead of returning a result page immediately in response to POST request, server responds with redirect to result page. Browser loads the result page as if it were an separate resource. After all, there are two different tasks to be done. First is to POST input data to the server. Second is to GET output to the client.

This approach provides a clean Model-View-Controller solution. All input data is stored, permanently or temporarily, in the Model on the server during the first step. The second step loads a View reflecting current Model state. When a user tries to refresh the result page, browser resends an "empty" GET request to the server. This request does not contain any input data and does not change server status. It only loads the View again. If server state was not changed by other processes/users, server responds with the same page as before refresh.

Loading resources using GET method is the cornerstone of suggested approach. Page loaded with GET request can be refreshed safely and transparently. Safely, because no input data is sent to the server. Transparently, because browser does not show warning message. The vehicle which makes transition from POST to GET possible is redirection.

With this technique user experience improves tremendously. No more scary messages with hard to decipher warnings. No trepidation to click Back, Forward or Refresh buttons. No fear to damage server data. Refresh button reloads result page with simple GET request. Back button returns a user to the page with the form. Following click on Forward button reloads the result page using GET again. Absolute freedom of browsing.

But wait, what about clicking on Submit button after returning back to the form page? The form would be resubmitted again, would not it? So all the trouble with redirection just to prevent inadvertent resubmit caused by page refresh?

Keep View Alive

Browsers did not always cache web pages. In the stone ages they were simple. Given the same address they pulled the same resource from the server again and again. Modern browsers are more intelligent. Based on different factors they try to determine should a page be reloaded from a server or not. If not, they can retrieving the page from a cache. For those still using dialup connection this is an instant save in terms of both traffic and time.

But the convenience of caching affects standard behavior. Here is the question: what would a user see if after submitting a form he clicks Back browser button? Did you say that he would see the same form he just submitted with the same values filled in? Why? Because the browser saved the page in the cache in case it would be needed again?

Well, forget smart browsers and caching. How this is for you: each window or page in an interactive application is a View representing an application Model. In order for the View to be correct and consistent with the Model it must be rendered anew each time it is presented to the user.

In plain English: caching must be prohibited for web applications. Online books, dictionaries, pictures can be cached. But please dear browser, do not save snapshots of a live program, because they may not represent actual Model state anymore. It is bad if the saved View is just looked at (you'd rather cache images of naked chicks), but it is tenfold worse when a stale View is used to modify the Model.

Now I ask the same question again: what would a user see if he clicks Back button after submitting a form? You know the correct answer already: the user of a well-designed web application would see a View which represents current Model state. This View would be presented in a way that resubmitting of the same data would be impossible.

New trick for old FORM

Let us take a closer look at the standard use case of an HTML FORM and a result page. The form can be used to edit an existing business entity or a new one. After form is submitted, its data is stored in the database and result of operation is displayed.

According to the PRG pattern, result page must not be returned in response to POST request, because attempt to reload it would cause double submit problem. Instead, browser must load result page separately, using GET method.

We can define the following processing modules (actions in Struts-speak) for this use case: Create Item, Display Item, Store Item and Display Stored.

These modules are combined in input/output pairs:

  • Create Item/Display Item - creates new empty item, then shows new item using Item Page HTML form and allows to enter item value;
  • Store Item/Display Stored - stores item, then shows persisted item from database in read-only mode on Stored Result page.
  • Store Item/Display Item - if fails to store, shows invalid item along with errors using the same HTML form;
  • Display Item is used separately to show and update item which already exists in the database.

(1) Create Item is called from a link on some other web page when a new object should be created. This action constructs empty business object and stores it in the temporary area called Current Items, which itself can be stored in the database or in the session; then redirects to Display Item.

(2-1) Display Item loads constructed business object from the Current Items and shows it on the Item Page, which is HTML form. The form can be refreshed at any time, browser would just ask Display Item action to obtain and show business object again.

(2-2) User fills out object value and submits HTML form to the Store Item action. If object is not accepted, it is kept in the Current Items area, server redirects back to Display Item action, which reads invalid object along with error messages from the Current Items and redisplays it in the form. If Item Page needs to be is refreshed, it loads the same object from Current Items again.

(3) If the object is accepted by Store Item action, it is persisted in the database and removed from temporary area. After that browser is redirected to Display Stored action which shows the Stored Result page. It can display the object which was just persisted. The result page can be safely refreshed, it would load the object from the database again.

If a user clicks Back button on result page (3) after successfully creating and storing new object, he returns to Display Item action (2). The temporary object has been already removed from the temporary area. Display Item has nothing to show and displays an error page instead of the item form, notifying the user that the object cannot be shown simply because it does not exist anymore. Thus a user cannot resubmit the object again.

Similar situation should happen if during creation of a new object the user leaves the form page (2) to a page preceding it (1). For application that means that the user decided to discard the new object. New object is removed from the Current Items. When the user clicks Forward button and returns to Display Item (2), he would see an "Object not found" error.

Instead of displaying an error page when an object is gone from the temporary area, we can do smarter. Create Item generates unique object ID and redirects to Display Item with object ID as request parameter. Display Item action reads object from the session and compares its ID with the one passed in the argument, then shows object to the user. After the user entered object value and submitted it to the Store Item, object ID becomes the primary key of the object.

Now, when the user returns back from result page (3) after submitting an object, browser invokes Display Item action passing it the same request, which contains object ID (2). Object was removed from the session, but it was stored in the database. Display Item action reads the object from the database, copies it to the Current Items and shows it to the user. Depending on business rules, this object may become read-only, so the form would change to a simple page, showing object content, but not allowing submitting it again. Or, conversely, the form would allow to edit it and submit changes. In the latter case the title of the form would change from "Create New Object" to "Edit Existing Object". If the user submits this object, this is not considered as double submit case. It is an intentional update of existing object.

Editing of existing object is simple, this case is basically already covered. We just need to make sure that Display Item makes no difference between new and existing object. Display Item takes object ID as request parameter, then looks up business object in the Current Items first. If object is not found, it is looked up in the database, copied to temporary area and then displayed (2). After object is updated and submitted, it is stored in the database. When the user clicks Back button from the result page (3), the item form reloads object from the database again (2) so it can be modified and submitted once again. Is this a double submit case? No. It is a deliberate modification of the same object by a user. Of course, you can create all the business rules you want, for example prohibit modification of the same object within certain timeframe.

Let us complete the use case and take a look at how the object is deleted.

Deletion is simple. Get ID as request parameter, pass it to Delete Item action (4), it deletes object in the Model and redirects to result page (5) which verifies with the database that particular object does not exist anymore. Result page can be safely refreshed without producing another delete request and without warning messages. When Back button is clicked on result page (5), browser returns to the page which invokes Delete Item action (4). If this action is called again with the same object ID, then apply it to the Model, get "object not found" exception, show error page. Again this is not a double submit, this is an explicit attempt to delete the same object again. Big deal, it was already deleted.

I think you got the idea. Just another quick example: an online store.

Storing several identical items in the shopping basket is not a problem while a user is still shopping. It is enough to show the basket content and the quantity of each item. What is really important is to ensure that the payment is processed only once. It may look something like this:

  • A shopping basket is created, the unique basket ID is assigned to the basket.
  • If a user clicks on Back button after adding an item to the basket, browser reloads up-to-date basket information from the server and shows to the user that the item is already in the basket. It is up to the user to add another identical item.
  • When the basket is submitted, its content is sent to a purchasing subsystem; the basket is invalidated; its transaction number is saved in history table if needed and destroyed from application context.
  • When a user clicks Back button after purchase was made, browser attempts to load the basket and fails because the basket, its ID and its content already have been destroyed. Browser shows error message instead of the basket. Submitting the same basket twice is impossible.
  • In case of caching browser or proxy a user who clicked Back button would see the same basket which was already submitted to purchasing subsystem. User's attempt to resubmit the basket would fail because basket tracking ID has been already destroyed along with the basket itself. As a courtesy for users of caching browsers the server can reply with error stating that the submitted basket does not exist any longer.

The Mantra

PRG pattern can be rephrased like this:

Never show pages in response to POST
Always load pages using GET
Navigate from POST to GET using REDIRECT

Repeat these lines before going to bed.

Think in terms of resources

Desktop applications are presentation-centric. When you select menu item you pretty much know which window would be displayed and how it would look like. Depending on Model state the window may display different information, but the overall window layout would be the same. Desktop user interface is relatively static and is largely defined at development stage.

Web applications should be resource-centric. They can attain greater presentation flexibility instead of fixating on delivering a particular page. Browser should request from a server a resource, a business entity, not a page. Depending on resource availability and state server would generate different presentation for that resource. It can be a regular "read-only" web page, or a form with input controls, or a message that resource is not available or it was permanently removed. Think in terms of resources, not pages.

Work with objects

When you obtain input data, you should know which objects it belongs to. When you display data, you should know content of which object is shown. At any time you must know which object you are working with. Use object ID to load, display and store an object. Pass object ID as request parameter.

Use the session or other short-term server storage as a buffer for currently edited or viewed objects. Ensure that your Views always represent current Model state.

Protect the Model

A web page is only a wrapper of what lies beneath: the Model, the business objects, the database. What is displayed to a user is important, but more important is what is stored in the Model. Protect your Model, nurture it, build all kind of error handling around it. After all, inconsistent user interface is just a nuisance; the chaos begins when the Model blows up.

Model should be accessed and updated using few well-defined ways. Generally, Model should not allow concurrent updates by the same client. Keeping Model valid and up-to-date is the best guarantee from inconsistency between presentation and business/persistence layers.

Define clear business/persistence rules, do not rely on web layer to validate input data. Data can come from anywhere: from a user of your web page, from web-service, from third-party application or from aliens, and all of them cannot be trusted. Validate input data directly in the heart of the application, in the Model.

Prevent resubmits

Include object ID and modification timestamp in a form page, provide time of modification for all business objects in the Model. Use ID to look up business object in the persistent storage, and timestamp to distinguish double submit from a cached page.

Consider applicability of tokens. A token allows to detect a double submit from a stale form page. Token is stored in the session before the form submitted for the first time; the same token value is planted on the HTTP form. When the form is submitted, the token value submitted as well. Application verifies that the token is present in the session, accepts input data, and removes token from the session. If a stale form is resubmitted, the form token would not have its session counterpart anymore. Tokens can be used as a pure web layer solution, Struts have built-in support for tokens.

Model can deal with resubmission more reliably than tokens. If a form is used to add or delete data, apply input values to the Model directly. Properly designed Model would throw insert or delete exception. If a form is used for editing of existing object, compare timestamp on the form with timestamp in the database and do not accept input with timestamp earlier than persisted data.

Controlling data with Model makes things easy. You can notify a user that the data being resubmitted is already in the database. "Thank you, stop clicking that button and refresh the page. The original input form has gone long ago, but your browser still keeps it in the cache."

Prohibit caching of application pages. Insert

and

in your pages. A page would be considered expired right after it loaded from the server.

Separate input from output

Use different classes to process input and output. If you use Struts, create separate input and output form classes, this works very well with two-stage PRG pattern:

  • POST request is received by the server
  • Struts populates input form class with request parameters
  • Input form class validates input data
  • Model is updated, information related to current operation is saved in the session for use by consequent GET requests
  • Browser is redirected to output action and loads the result page using GET
  • Server looks up current object in the session and/or in the Model and fills an output form
  • View is created using output form data and is sent back to the browser

You can define only setters in the input form, and only getters in the output form to make form classes easier to read and to ensure that Struts would not populate output form fields with request parameters.

You may want to split large action classes into input an output actions as well.

Use session-scoped UI objects

PRG pattern implies roundtrip to a browser, so the request data is lost. There are two choices to keep POST data: either to transfer it a redirecting response and the in a GET request, or to store it on the server. The first approach is bulky and is non-idempotent. You would have two different kinds of GET request, one to redisplay the HTML form with all its previous data, another to display business object from the database, using just its ID.

Thus, the proper way is to store temporary data on the server and provide GET request with object ID only. That way output action would not even know, was the object just created or loaded from database.

Temporary data corresponds to currently edited or viewed object, and includes both business and presentation data, like:

  • object value;
  • error messages related to this object;
  • page title.

Because this temporary object defines presentation of business object, I call it UI object. If you use Struts, you can use form classes with session scope as UI objects. It is the easiest way to convert regular "forwarding" application into "redirecting" one.

Apparently, the same form class would be used in both input and output actions, so the output action could get access to values set in the input action. The attractiveness of session-scoped form classes is undermined by the fact, that Struts repopulates form fields with each request. This is undesirable, so the mutators would need to verify the name of current action mapping and do not update field values for output action. Struts calls reset method before populating the form, and validate after that. If these methods are used for both input and output, current mapping name should be verified, so the appropriate code could be used.

Session-scoped form classes are kept in memory during client session, which may become an issue. If your form class have references to large objects, you may need to release these objects manually.

Another issue arises when more that one form instance is needed to be created. How this can be done from application code, if form classes are maintained by Struts?

So, despite of the certain convenience of session-scoped form classes I suggest to create your own UI objects. You can have better control over them, you can decide do you want to store them in the session or in database. You will have better abstraction from Struts framework, and porting to other frameworks would be easier.

Form classes are intended for two simple things: deliver input data from HTML form, and render output data on web page. Form classes are just value objects, enhanced with additional functionality like validation. Keep them in request scope, do not use them to store UI or business data.

Struts: use ForwardAction class in output actions

If you have separate input and output form classes, you have got two sets of reset and validate methods. These methods are called by Struts before passing control to an action class. You can use validate in the input form for its original purpose: to verify input data. Output form, on the other hand, does not have much to validate, it is used just to build the result page. So, you can move code from execute method of action class to validate method of output form class and to get rid of custom action class altogether.

Struts: do not expose Views

Views, which are usually JSP pages, must not be available for direct access from a browser. Forget that JSP can process the request. Regard JSP as HTML with data access, use it for output only. Always pass control through action class and/or form class. This ensures clean separation between components and allows Controller to monitor all requests. Hide web pages in WEB-INF directory and display them from their respective actions.

Configure caching

Browsers are not required to process cache control tags on the web pages, but they usually obey HTTP response header fields. Add to your struts-config.xml file. Struts would modify each response header as follows:

response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 1);

Corresponding HTTP header fields produced by Tomcat 4.0.6 looks like this:

"Pragma: No-cache"
"Cache-Control: no-cache"
"Expires: Thu, 01 Jan 1970 00:00:00 GMT"

Use better browsers

Despite efforts to prohibit caching some web browsers like Firefox just do not care. Caching works great with simple forwarding applications, preventing implicit resubmits. But caching a page which supposed to reflect current sever state breaks the user experience and introduces the double submit problem again.

Other browsers like Opera can resubmit POST request without confirmation message. This may invalidate state of an application which does not check for double submit, and a user would not even know about it.

Old Netscape Navigator works fine for me, but for some reason it freezes for several seconds when submitting a POST request on Tomcat server. Other browsers do not inhibit this strange behavior.

Internet Explorer does almost everything right, but is very annoying. When you resubmit POST request, it shows you a "Page expired" window first and a dialog box next before allowing to proceed. And if you decide not to, it loses your current page. But because your application would not have resubmit problems, your customers would not suffer much.

Why redirect works

It is interesting that PRG pattern exploits non-standard behavior of browsers and web servers. HTTP 1.1 defines several redirect response codes in 3xx range. Some of these codes require browser to use the same request type, some require to change POST to GET, some require to obtain user confirmation when request is redirected. Turns out that many of these requirements are not implemented by popular browsers. Instead, they have common de-facto behavior, like redirecting POST to GET without confirmation if received 302 code. This feature is used by PRG pattern.

This behavior is wrong for 302 ("Found") code, but is absolutely correct for 303 ("See Other") code. Still, few servers return 303 when redirect with GET method is required. HttpResponse.sendRedirect method does not allow to set response code, it always returns 302. It is possible to emulate sendRedirect(url) behavior using the following methods:

res.setStatus(res.SC_SEE_OTHER);
res.setHeader("Location",url);

where SC_SEE_OTHER is the proper 303 code, but sendRedirect provides some additional service like resolving relative addresses, so this is not a direct snap-in. The discrepancy between browser behavior and HTTP standard can be resolved, if 302 and 303 codes considered equal, and another code for proper 302 behavior were created.

In any case, I doubt that browser vendors will change implementation of 302 response code, because too many applications relay on it. The good thing is that modern browsers understand and correctly process 303 code, so if you want to be sure, return 303 instead of 302.

References

About the Author

Michael Jouravlev - I hold MS in Computer Science from Moscow Aviation Institute (technical university), Moscow, Russia. I have more than 10 years of experience developing applications for MS-DOS, Windows and Java platform. I devoted last 5 years to server-side Java applications. Curently I am employed as a software engineer at International Lottery and Totalizator, Inc., www.ilts.com

Making a HTML select readonly

Source

For some time ago I needed to make a single select <select> element readonly. This meant that the user should be able to see all values in the list and not be able to select a new value. There is no readonly attribute available for the <select> element and disabling the field was not an option since we needed the value on the serverside. Some simple javascript did the job:


<select name="theselect" onchange="this.selectedIndex = 1;">
<option value="Red">Red</option>
<option value="Green" selected="selected">Green</option>
<option value="Blue">Blue</option>
</select>

Initial value is green and it should continue to be. This solution rely on the possibility to apply the correct onchange eventlistener during the page rendition - in this case through a taglib. I have created a simple test page for myself here.


Saturday, March 22, 2008

Load-balancing Tomcat with Apache

Load-balancing Tomcat with Apache

February 2008

Discussion


Introduction

Tomcat is a popular application server used to host web applications. Apache is a popular web server which provides services like https encryption and decryption, URL rewriting etc. Apache can also be used a load balancer to balance load between several Tomcat application servers.

This article briefly discusses some alternatives for load balancing an application server. It discusses implementation details for setting up load balancing with Apache using ‘mod_proxy’ module. It also looks at some of the features provided by apache such as ‘server affinity’ and safe removal of node.

Downloadable web application is provided which can be used to test load balancing with Apache. Jmeter script is also provided for load testing Apache.

Setting up Apache and load balancing is the role of the System Administrator. Unless a java developer works in a small team or is setting up a test environment, he wont get involved in setting up load balancing. However, it is good to understand the principles behind load balancing. The knowledge might help a developer to fix issues in live environment.

This article discusses load balancing in the context of a web application. The application is accessed using https, requires a user to login and some user specific information is stored in session.

Background knowledge

It is assumed that the reader is familiar with the following concepts and technologies:

  • Apache (Version 2.2)
  • Tomcat (version 5.5.23)
  • Jmeter for load testing web applications
Some important terms

Load balancing – user requests are processed by more than one server with all servers sharing the load ‘equally’
Server affinity (sticky session) – With server affinity, multiple requests from a user are processed by the same server. This is required for non clustered servers as the user session data is held on one server only and all requests from that user have to go to the server which has the session data for the user.
Transparent failover – User is not aware of a server crash. Transparent failover can be request level or session level. Transparent failover can be achieved by clustering application servers. With clustering, all the servers are the same and so the loss of a server does not interrupt the service. With load balancing alone, the user has to login again when server crashes.
Server Cluster – A group of servers which appear to be a single server to the user. Loss of a server is transparent to the user. User data is held on all servers in the cluster group. Any server can process any user request and loss of any server does not lead to interruption of service. The user does not have to login after a server failure. Since the user session data is replicated over the network to more than one server, there is a performance overhead. So clustering should be avoided unless transparent failover is required.
Scalability – measure of the ability of a system to handle increasing load without reducing response time
Response time – time taken to process a user request
Real workers – Term used by apache to refer to servers which are components of a load balanced system. The real workers do the actual work and the real worker is usually a remote host.
Virtual worker – In Apache, the load balancer is referred to as the virtual worker which delegates processing to real workers.

Load balancing algorithms

  • Round robin – requests are Reduced likelihood of version conflicts
  • Weighted round robin – servers of different capacity are assigned requests in proportion to their capacity (as defined by a load factor). Apache as 2 versions of this:
    • Request counting algorithm – requests are delegated in round robin manner irrespective of the nature of the request
    • Weighted traffic counting algorithm – Apache delegates traffic to real worker based on the number of bytes in the request

Compare Load balancing with Clustering

Both Load balancing and clustering aim to improve scalability by spreading load over more than one server. They both aim to provide horizontal scalability.

Load balancing

Clustering

User has to login after server crash

User does not have to login after server crash. So failover is transparent to the user

Load balancing is done by the web server or using DNS or using hardware load balancer or using Tomcat balancer web application

Clustering capability is provided by the application server. Clustering also requires load balancing

The application servers (e.g. Tomcat) do not communicate with each other

The application servers (e.g. Tomcat) communicate with each other.

There is minimal effect on response time when moving up from a single server to load balanced servers under the same load

Response times could deteriorate when moving to a clustered system from a single server as the session data is now replicated over the network to other servers.

More the session data, more is the deterioration in performance compared to a single server.

Response time also depends on number of nodes in the cluster. More the number of nodes, more is the deterioration in performance as data is replicated using TCP to every single node in cluster. This can be reduced by using UDP to replicate session data. With UDP, session data could be lost during session replication. So a user might have to login again if a server crashes

Load balancing can be used independently of clustering

Clustering also requires load balancing but makes ‘server affinity’ redundant. It provides ‘transparent failover’ capability over load balancing at cost of decreased response time and more complex configuration

Usually no changes are required to move an application from a single server to a load balanced set of servers

Application must meet certain criteria for it to work in a clustered environment. The user variables stored in the session must be ‘serializable’. To get good response time, only small objects must be stored in the session.

Choices for implementing Load balancing

Hardware based load balancing

  • Pros
    • Fast
  • Cons
    • Expensive
    • Proprietary
    • Less flexible

Software based load balancing (e.g. Apache or Tomcat balancer)

  • Pros
    • Open source and free to implement with Apache and Tomcat balancer application
    • Easy to configure
    • More flexib
  • Cons
    • Lower performance compared to hardware based solution

Alternatives for software based load balancing

  • Apache ‘mod_proxy’ module or ‘mod_jk’ module. However ‘mod_proxy’ is easier to configure and newer than ‘mod-jk’ module.
  • Using Tomcat balancer application
  • Linux virtual server
  • Using DNS for load balancing

The rest of this article discusses load balancing using Apache ‘mod_proxy’ module.

Load balancing with server affinity

A simple load balanced setup which does not provide ‘server affinity’ is not suitable for stateful web applications. In stateful web applications, user state (session data) is held on one server. All further requests from that user must be processed by the same server. Hence server affinity (sticky sessions) is necessary for stateful web applications which don’t use clustering. The minimum load balanced setup is with 2 application servers and one web server (load balancer). If https decryption is required, then the same Apache server can also be used for https decryption.In a load balanced system with server affinity, all requests from user 1 go to Tomcat instance 1. This is shown below:

Apache implements server affinity by rewriting the ‘jsessionid’ sent by Tomcat to the browser. The Tomcat worker name is added to the end of ‘jsessionid’ before the ‘jsessionid’ is sent to the browser. In the next request from the same user, the Tomcat worker name is read from the ‘jsessionid’ and the request delegated to this Tomcat real worker.The ‘jsessionid’ stored as a cookie in the browser has the tomcat worker name as shown in screenshot below:

The Apache configuration (in httpd.conf) to setup Apache as a load balancer for 2 application servers is shown below:

ProxyPass /apache-load-balancing-1.0 balancer://mycluster stickysession=JSESSIONID


BalancerMember ajp://tomcat1:8009/apache-load-balancing-1.0 route=tomcat1 loadfactor=50
BalancerMember ajp://tomcat2:8009/apache-load-balancing-1.0 route=tomcat2 loadfactor=50

The above setup requires ‘mod_proxy’ module to be loaded.The first line sets up a reverse proxy for request ‘/apache-load-balancing-1.0’ and delegates all requests to load balancer (virtual worker) with name ‘mycluster’. Sticky sessions are enabled and implemented using cookie ‘JSESSIONID’.The ‘Proxy’ section lists all the servers (real workers) which the load balancer can use. For each participant in load balancing, we define the url (using http, ftp or ajp protocol) and give it a name which matches the name of the Tomcat engine defined in the Tomcat ‘server.xml’. The ‘loadfactor’ can be a number between 1 and 100. Set it to 50 so it can be increased or decreased dynamically later on.The tomcat ‘server.xml’ in ‘TOMCAT_FOLDER/conf’ folder should have this configuration:
....

...

With 2 browser sessions, the Tomcat server console and the server response show that all requests from the same user are processed by the same server.

Load balancing manager and safe removal of server node

Apache load balancing manager Apache includes a ‘balancer manager’ which can be used to check the status of the servers used for load balancing and to prepare for safe removal of a node. To enable balancer manager, add this section to Apache ‘httpd.conf’ file:

SetHandler balancer-manager

Balancer manager requires ‘mod_proxy’ and ‘mod_proxy_balancer’ modules to be loaded.

Balancer manager will now be accessible at the url ‘/balancer-manager’.

Screenshot of this is shown below:

Safe removal of a server node When an application server (real worker) has to be taken offline for maintenance, set a very low load factor for the server due to be taken offline. Few new users will be served by that server. All existing users ‘sticking’ to this real worker will continue to be processed by this real worker. This will help reduce the number of users who will have to login again when the real worker is taken offline.After some time, the real worker is disabled and taken offline. Once it is ready to come online, the worker is enabled again in balancer manager.

Tests

About the attached web application and JMeter scriptThe attached web application contains a single servlet and 3 JSP pages. The servlet has hard coded usernames and passwords for 10 users and is used to authenticate the user and store the username in the session. The servlet also prints the username and server name of server. The login JSP (index.jsp) is used to login and the second JSP (greeting.jsp) is used to print a greeting after the user logs in. This JSP also prints the username and server name in the response. The third JSP (user_details.jsp) is used to print user details and the server name and IP address of the server name used to process the request. This JSP also prints the username and server name of the server to the console. The name of the server is setup as a context parameter in the web.xml. Change it before deploying it so that the 2 web applications have different names to make it easier to identify them
 
serverName
Tomcat instance 1

The attached JMeter script sets up 10 threads with each thread being used to login 1 user and request user details. Login is done once per thread/user and all subsequent requests from the user are requests to get user details.Manual test with 2 browser windows to show server affinityOpen 2 browser windows and login using different usernames. The server consoles in Tomcat will show that requests from one user will always go to a particular Tomcat instance demonstrating server affinity. See screenshot below:

Load testing with JMeterThe attached JMeter script is used to simulate a load of 10 users. The attached JMeter script has been setup to record the response. Comparing the response from the server and the server console, we can see that the load of 10 users is shared equally between 2 servers and all requests from one user are processed by the same server.

Sudden loss of one server and then restoring the serverThis can be simulated with either shutting down tomcat to simulate a server crash. This is best simulated using JMeter as a client to simulate a load of 10 users continuously requesting pages from the servers.Run the attached JMeter script and once the load test is running, take one server down. Any subsequent requests to the offline server will be redirected to the second server. When one server goes down, the user session data is lost and so all the users who have ‘affinity’ to that server will have to login again.

Reducing single point of failure

Load balancer can become the single point of failure. This can be reduced by using round robin DNS to delegate user requests to more than one load balancer. The load balancer delegates requests to more than one application server. In this scenario, if the load balancer and/or the application server goes down, the other load balancer and application servers can still provide some level of service. This is illustrated in the diagram below

:

Conclusion

Apache can be used to load balance Tomcat servers. This setup provides other useful features such as ‘Server affinity’ and safe removal of nodes for scheduled maintenance. Load balancing is recommended if transparent failover is not required. It is easy to setup load balancing and ‘server affinity’ with Apache.JMeter can be used to load test the configuration and to test the behaviour in case of a server crash.The load balancer can become the single point of failure. This can be reduced by using 2 load balancer and using round robin DNS to delegate request to more than one server.

Source Files

web application.zip
apache load balance load test script.jmx

Biography

Avneet Mangat 6 years experience in Java/J2EE. Currently working as Lead developer at Active Health Partners ( www.ahp.co.uk ). Bachelors degree in Software Engineering, Sun Certified Web developer and Java programmer, Adobe certified Flash Designer and Prince2 certified (foundation). Lead developer of open source tool DBBrowser, please see http://databasebrowser.sourceforge.net/ Outside interests include photography and travelling. Please contact me at avneet.mangat@ahp.co.uk or avneet.mangat@gmail.com for more information.