Skip to main content

Web services programming tips and tricks: Learn simple, practical Web services design patterns, Part 2

Encapsulate business logic with a command facade pattern

James Snell (jasnell@us.ibm.com), Software Engineer, IBM, Software Group
Author photo
James Snell is a member of the IBM Emerging Technologies Toolkit team and has spent the past few years focusing on emerging Web services technologies and standards. He maintains a weblog on developerWorks focused on emerging technologies.

Summary:  Part 2 of this series continues a discussion focusing on the application of well-defined and proven Web application design strategies to the world of Web services with an introductory look at the Command Facade Pattern.

Date:  26 Oct 2004
Level:  Intermediate
Activity:  2991 views

In the previous installment of this series, I discussed the application of a programming strategy leveraging the Java Messaging Service to implement an asynchronous programming model for a Web service. Here, I continue to focus on the use of simple, proven design patterns within a Web services environment. My goal is to provide practical examples that offer you alternative ways of coding service implementations to meet specific operational goals.

The command facade pattern

Two patterns that are very familiar to Web application developers are the facade and command patterns. The command facade pattern is a combination of these two designed specifically for a service-oriented environment. As such, it incorporates the fundamental aspects of both of the source patterns, yet does so in a way that makes sense to developers implementing Web services interfaces described using WSDL and made accessible through SOAP messages.

The command pattern is distinguished by the encapsulation of distinct activities into reusable objects whose behavior can be parameterized per request.


Figure 1. The Command Pattern
The Command Pattern

Command objects can be either stateful or stateless. A stateful command maintains the internal state of its data and variables specific to each individual use. Stateful command instances are generally used only once, or are pooled and recycled once the client is done with it. The assignment of parameters to stateful commands occurs either when the object instance is created or immediately prior to command invocation through the setting of attributes. Stateless command instances maintain no internal state, and multiple clients can use them concurrently without requiring pooling or recycling. The assignment of parameters to stateless commands occurs as input to that command's invocation method.

The facade pattern uses a single high-level application component that serves to encapsulate interactions with subordinate components with the goal of simplifying interactions with the system. In other words, a facade can simplify a more complicated interface between the client and the service provider (or even multiple subordinate components).


Figure 2. The facade pattern
The facade pattern

Like Commands, Facades may be stateful or stateless. A stateful Facade maintains an internal state in between client calls to operations defined on the facade. A stateless Facade maintains no internal memory of previous operations, therefore relying on necessary state to be passed in with each method invocation.

The command facade pattern combines these two approaches by introducing a facade interface that sits in front of one or more command objects. The goal of the pattern is to achieve the same kind of business logic encapsulation achieved by the command pattern while presenting a less complicated, more user-friendly interface to potential clients.


Figure 3. The command facade pattern
The command facade pattern

In a Web services world, the facade component of the command facade pattern correlates with the WSDL-described portType, with a one-to-one relationship between the methods defined on the facade and the operations defined on the port type. Each method can, in turn, invoke one or more encapsulated command objects in order to carry out the specific operation. Given a typical Java Web service, in which a single Java class backs a single WSDL portType, the primary goal of this pattern is to move business logic out of the service implementation class and into distinct business objects that are more easily managed and evolved over time.


Implement the example commands

The command facade pattern consists of two distinct types of objects: the Command and the Facade. The design of the Facade is directly related to the Commands to which it will delegate, including the various parameterization options that each type of Command exposes. Therefore, the key to properly designing a command facade implementation is to first design the commands and, from there, define an appropriate facade interface.

This simple example application defines two eminently useful operations that convert input strings either to upper or lower case. Each of these highly complex and computationally intensive operations are encapsulated into two stateless command objects.

Before you begin, however, you need to define the base Command interface.


Listing 1. Command.java
package com.ibm.developerworks.wspattern.two;

public interface Command {
  public CommandModel execute(CommandModel model);
}

The Command interface defines only a single method, called execute, that accepts a single parameter, called CommandModel. CommandModel is essentially a placeholder interface that specific command implementations implement for the purpose of allowing the command objects' users to pass-in parameters that are specific to that command implementation.


Listing 2. CommandModel.java
package com.ibm.developerworks.wspattern.two;

public abstract class CommandModel {}

Because each of the business operations accept as input a single text string, both operations use the same CommandModel implementation shown in Listing 3.


Listing 3. CaseCommandModel.java
package com.ibm.developerworks.wspattern.two.commands;

import com.ibm.developerworks.wspattern.two.CommandModel;

public class CaseCommandModel 
  extends CommandModel {

  private String string;

  public String getString() {
    return string;  
  }
  
  public void setString(String string) {
    this.string = string;
  }
}


Listing 4. UppercaseCommand.java
package com.ibm.developerworks.wspattern.two.commands;

import com.ibm.developerworks.wspattern.two.Command;
import com.ibm.developerworks.wspattern.two.CommandModel;

public class UppercaseCommand 
  implements Command {

  public CommandModel execute(CommandModel model) {  
    if (!(model instanceof CaseCommandModel)) {
      throw new IllegalArgumentException("Invalid command model");
    } else {
      CaseCommandModel umodel = (CaseCommandModel)model;
      if (umodel.getString() == null) {
        throw new IllegalArgumentException("Invalid command model");
      } else {
        umodel.setString(umodel.getString().toUpperCase());
      }
      return umodel; 
    }
  }
}


Listing 5. LowercaseCommand.java
package com.ibm.developerworks.wspattern.two.commands;

import com.ibm.developerworks.wspattern.two.Command;
import com.ibm.developerworks.wspattern.two.CommandModel;

public class LowercaseCommand 
  implements Command {

  public CommandModel execute(CommandModel model) {  
    if (!(model instanceof CaseCommandModel)) {
      throw new IllegalArgumentException("Invalid command model");
    } else {
      CaseCommandModel umodel = (CaseCommandModel)model;
      if (umodel.getString() == null) {
        throw new IllegalArgumentException("Invalid command model");
      } else {
        umodel.setString(umodel.getString().toLowerCase());
      }
      return umodel; 
    }
  }
}

Note that both the LowercaseCommand and UppercaseCommand objects store no internal state. Rather, everything each command needs to execute is passed in as part of the CommandModel parameter. Also note that the execute method returns a CommandModel. A command may return any CommandModel implementation it wishes. In the case of the examples above, the same CommandModel object that is passed into the command is updated and returned back to the calling application. This behavior is not required, however.


Implement the facade

The goal of the facade is to simplify and centralize access to the underlying command objects in order to make those commands more accessible as a WSDL-described Web service. To achieve this goal, methods are defined on the Facade interface that allow the various parameterization options exposed by the underlying commands to be passed in as parameters to the facade methods. A single method on the Facade interface can execute one or more command objects, so the facade input parameters and the method return value need to be well chosen.

For this example, the facade interface exposes one public method for each command, as illustrated in Listing 6.


Listing 6. CommandFacadeService_SEI.java
package com.ibm.developerworks.wspattern.two;

public interface CommandFacadeService_SEI extends java.rmi.Remote {
   public java.lang.String toUpper(java.lang.String string);
   public java.lang.String toLower(java.lang.String string);
}

The implementation of this interface involves having each of the toUpper and toLower operations delegate to the appropriate command objects.


Listing 7. CommandFacadeService.java
package com.ibm.developerworks.wspattern.two;

import com.ibm.developerworks.wspattern.two.commands.LowercaseCommand;
import com.ibm.developerworks.wspattern.two.commands.UppercaseCommand;
import com.ibm.developerworks.wspattern.two.commands.CaseCommandModel;

public class CommandFacadeService {

  private static final String CMD_TOUPPER = "toUpper";
  private static final String CMD_TOLOWER = "toLower";

  private static java.util.HashMap commands = 
    new java.util.HashMap();
  static {
    commands.put(CMD_TOUPPER, new UppercaseCommand());
    commands.put(CMD_TOLOWER, new LowercaseCommand()); 
  }

  private static Command getCommand(String name) {
    return (Command)commands.get(name);
  }

  public String toUpper(String string) {
    CaseCommandModel model = new CaseCommandModel();
    model.setString(string);
    model = (CaseCommandModel)getCommand(CMD_TOUPPER).execute(model);
    return model.getString();
  }

  public String toLower(String string) {
    CaseCommandModel model = new CaseCommandModel();
    model.setString(string);
    model = (CaseCommandModel)getCommand(CMD_TOLOWER).execute(model);
    return model.getString();   
  }
}

Note that because the UppercaseCommand and LowercaseCommand objects are stateless, you create a static cache of instances that are invoked rather than invoking a new instance every time each of the toUpper and toLower methods is invoked.

Once the facade interface has been implemented, the final step is to expose it as a Web service. Assuming the class is being exposed as a JSR-109-compliant Web service, I highly recommend the use of a tool such as IBM® WebSphere® Studio Application Developer (Application Developer) to generate all of the necessary deployment artifacts. To make things easier for you, I have included for download a ZIP file containing full source in the form of Application Developer projects and an EAR file containing the compiled source of the example application. You can download the files by clicking the Code icon at the top or bottom of this tip.


Wrap-up

The key advantage of the command facade pattern is that it allows the business logic behind a Web service implementation to be encapsulated into distinct objects that are more easily managed and evolved over time. As long as the inputs and outputs of the command implementations remain constant, changes in business logic do not need to impact the Web services implementation layer. Further, implementing command objects in this way allows business logic to be reused in other areas of your Web application.

The example given in this article focused exclusively on a stateless facade using stateless commands. Using mechanisms such as those provided by HTTP Sessions or those defined in the WS-Resource Framework, you could easily extend this model to support the use of stateful facades, allowing for some very interesting possibilities.



Downloads

DescriptionNameSizeDownload method
WebSphere deployable EAR filews-tip-altdesign2ear.ear701 KB HTTP
Example program source filesws-tip-altdesign2code.zip719 KB HTTP

Information about download methods


Resources

About the author

Author photo

James Snell is a member of the IBM Emerging Technologies Toolkit team and has spent the past few years focusing on emerging Web services technologies and standards. He maintains a weblog on developerWorks focused on emerging technologies.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=SOA and Web services
ArticleID=23255
ArticleTitle=Web services programming tips and tricks: Learn simple, practical Web services design patterns, Part 2
publish-date=10262004
author1-email=jasnell@us.ibm.com
author1-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers