0% found this document useful (0 votes)
273 views115 pages

Design Pattrens1

This document discusses the Factory Method design pattern. It begins by describing the problem of not knowing which class to instantiate at runtime. The solution is to use a factory method that delegates instantiation to subclasses. An example is provided where a SalutationFactory returns either a Male or Female object depending on the gender passed to it. Factories promote loose coupling by eliminating hard-coded class references. The document then provides a more detailed code example of a NameFactory that splits a name string into first and last names depending on whether it contains a comma.

Uploaded by

Ravikumarmaddi
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
273 views115 pages

Design Pattrens1

This document discusses the Factory Method design pattern. It begins by describing the problem of not knowing which class to instantiate at runtime. The solution is to use a factory method that delegates instantiation to subclasses. An example is provided where a SalutationFactory returns either a Male or Female object depending on the gender passed to it. Factories promote loose coupling by eliminating hard-coded class references. The document then provides a more detailed code example of a NameFactory that splits a name string into first and last names depending on whether it contains a comma.

Uploaded by

Ravikumarmaddi
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
You are on page 1/ 115

DesignPatterns 1

DESIGN
PATTERNS

1. The Factory Method (Creational) Design


Pattern
2. THE ABSTRACT FACTORY PATTERN
3. THE SINGLETON PATTERN
4. Delegation pattern
5. Observer Pattern
6. Struts Patterns
Front Controller
Command Pattern
7. Data Access Object pattern (DAO)
8. Session Façade
9. Service Locator
DesignPatterns 2

1.The Factory Method (Creational) Design


Pattern
The Problem
One of the goals of object-oriented
design is to delegate responsibility
among different objects. This kind of
partitioning is good since it encourages
Encapsulation and Delegation.
 Sometimes, an Application (or
framework) at runtime, cannot
anticipate the class of object that it
must create. The Application (or
framework) may know that it has to
instantiate classes, but it may only
know about abstract classes (or
interfaces), which it cannot
instantiate. Thus the Application
class may only know when it has to
instantiate a new Object of a class,
not what kind of subclass to create.
 a class may want it's subclasses to
specify the objects to be created.
 a class may delegate responsibility
to one of several helper subclasses
DesignPatterns 3

so that knowledge can be localized


to specific helper subclasses.
The Solution
Factory Method is a creational pattern.
This pattern helps to model an interface
for creating an object which at creation
time can let its subclasses decide which
class to instantiate. We call this a
Factory Pattern since it is responsible for
"Manufacturing" an Object. It helps
instantiate the appropriate Subclass by
creating the right Object from a group
of related classes. The Factory Pattern
promotes loose coupling by eliminating
the need to bind application- specific
classes into the code.
Factories have a simple function: Churn
out objects.
Obviously, a factory is not needed to
make an object. A simple call to new
will do it for you. However, the use of
factories gives the programmer the
opportunity to abstract the specific
DesignPatterns 4

attributes of an Object into specific


subclasses which create them.
The Factory Pattern is all about "Define
an interface for creating an object, but
let the subclasses decide which class to
instantiate. The Factory method lets a
class defer instantiation to subclasses"
Thus, as defined by Gamma et al, "The
Factory Method lets a class defer
instantiation to subclasses".
Figure 1 below illustrates the roles of
the Factory Pattern.

Figure 1: The roles of the Factory


Pattern
As shown in the figure, the Factory
Pattern has a couple of roles - a
Creator and a Concrete Creator. This
pattern is used when a class (the
Creator) does not know beforehand all
the subclasses that it will create.
Instead, each subclass (the Concrete
Creator) is left with the responsibility of
creating the actual object instances.
DesignPatterns 5

Let’s take an example to understand


this pattern.
Example: Let’s suppose an application
asks for entering the name and sex of a
person. If the sex is Male (M), it
displays welcome message saying Hello
Mr. <Name> and if the sex is Female
(F), it displays message saying Hello Ms
<Name>.

The skeleton of the code can be given


here.
public class Person {
// name string
public String name;
// gender : M or F
private String gender;
public String getName() {
return name;
}

public String getGender() {


return gender;
}
}// End of class
DesignPatterns 6

This is a simple class Person having


methods for name and gender. Now, we
will have two sub-classes, Male and
Female which will print the welcome
message on the screen.
public class Male extends Person {
public Male(String fullName) {
System.out.println( "Hello Mr.
"+fullName);
}
}// End of class
Also, the class Female
public class Female extends Person {
public Female(String fullNname) {
System.out.println( "Hello Ms.
"+fullNname) ;
}
}// End of class
Now, we have to create a client, or a
SalutationFactory which will return the
welcome message depending on the
data provided.
public class SalutationFactory {
public static void main(String args[])
{
DesignPatterns 7

SalutationFactory factory = new


SalutationFactory( );
factory.getPerson( args[0], args[1]);
}
public Person getPerson(String
name, String gender) {
if (gender.equals( "M"))
return new Male(name);
else if(gender.equals( "F"))
return new Female(name) ;
else
return null;
}
}// End of class
This class accepts two arguments from
the system at runtime and prints the
names.
Running the program:
After compiling and running the code on
my computer with the arguments
Prashant and M:
java Prashant M
The result returned is: “Hello Mr.
Prashant”.
When to use a Factory Pattern?
DesignPatterns 8

The Factory patterns can be used in


following cases:
1. When a class does not know which
class of objects it must create.
2. A class specifies its sub-classes to
specify which objects to create.
3. In programmer’s language (very raw
form), you can use factory pattern
where you have to create an object of
any one of sub-classes depending on
the data provided
By using a factory in RMI, you can
reduce the number of objects that you
need to register with the RMI registry.
Sample Code

Let's consider a simple case where we


could use a Factory class. Suppose we
have an entry form and we want to
allow the user to enter his name either
as “firstname lastname” or as
“lastname, firstname”. We’ll make the
further simplifying assumption that we
will always be able to decide the name
DesignPatterns 9

order by whether there is a comma


between the last and first name.

This is a pretty simple sort of decision to


make, and you could make it with a
simple if statement in a single class, but
let’s use it here to illustrate how a
factory works and what it can produce.
We’ll start by defining a simple base
class that takes a String and splits it
(somehow) into two names:

class Namer {

//a simple class to take a string apart


into two names

protected String last; //store last name


here
protected String first; //store first name
here
public String getFirst() {
return first; //return first name
}
public String getLast() {
DesignPatterns 10

return last; //return last name


}
}

In this base class we don’t actually do


anything, but we do provide
implementations of the getFirst and
getLast methods. We’ll store the split
first and last names in the Strings first
and last, and, since the derived classes
will need access to these variables, we’ll
make them protected.

The Two Derived Classes

Now we can write two very simple


derived classes that split the name into
two parts in the constructor. In the
FirstFirst class, we assume that
everything before the last space is part
of the first name:

class FirstFirst extends Namer { //split


first last
DesignPatterns 11

public FirstFirst(String s) {
int i = s.lastIndexOf( " "); //find sep
space
if (i > 0) {
//left is first name
first = s.substring( 0, i).trim();
//right is last name
last =s.substring( i+1).trim( );
}
else {
first = “”; // put all in last name
last = s; // if no space
}}}

And, in the LastFirst class, we assume


that a comma delimits the last name. In
both classes, we also provide error
recovery in case the space or comma
does not exist.

class LastFirst extends Namer { //split


last, first
public LastFirst(String s) {
int i = s.indexOf(", "); //find comma
if (i > 0) {
DesignPatterns 12

//left is last name


last = s.substring( 0, i).trim();
//right is first name
first = s.substring( i + 1).trim();
}
else {
last = s; // put all in last name
first = ""; // if no comma
}}}
Building the Factory
Now our Factory class is extremely
simple. We just test for the existence of
a comma and then return an instance of
one class or the other:

class NameFactory {
//returns an instance of LastFirst
or FirstFirst
//depending on whether a comma is
found
public Namer getNamer(String
entry) {
int i = entry.indexOf( ",");
//comma determines name order
if (i>0)
DesignPatterns 13

return new
LastFirst(entry) ; //return one
class
else
return new
FirstFirst(entry) ; //or the other
}}

Using the Factory

Let’s see how we put this together. We


have constructed a simple Java user
interface that allows you to enter the
names in either order and see the two
names separately displayed. You can
see this program below.

You type in a name and then click on


the Compute button, and the divided
name appears in the text fields below.
The crux of this program is the compute
method that fetches the text, obtains an
instance of a Namer class and displays
the results.
DesignPatterns 14

In our constructor for the program, we


initialize an instance of the factory class
with

NameFactory nfactory = new


NameFactory( );

Then, when we process the button


action event, we call the
computeName method, which calls the
getNamer factory method and then
calls the first and last name methods of
the class instance it returns:
private void computeName( ) {
//send the text to the factory and
get a class back
namer =
nfactory.getNamer( entryField.
getText() );
//compute the first and last names
//using the returned class
txFirstName. setText(namer.
getFirst( ));
txLastName.setText( namer.getLast(
));
}
DesignPatterns 15

And that’s the fundamental principle of


Factory patterns. You create an
abstraction which decides which of
several possible classes to return and
returns one. Then you call the methods
of that class instance without ever
knowing which derived class you are
actually using. This approach keeps the
issues of data dependence separated
from the classes’ useful methods

2. THE ABSTRACT FACTORY PATTERN

The Abstract Factory pattern is one level


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

One classic application of the abstract


factory is the case where your system
needs to support multiple “look-and-
feel” user interfaces, such as Windows-
9x, Motif or Macintosh. You tell the
factory that you want your program to
look like Windows and it returns a GUI
factory which returns Windows-like
objects. Then when you request specific
objects such as buttons, check boxes
and windows, the GUI factory returns
Windows instances of these visual
interface components.

3. THE SINGLETON PATTERN

The Singleton pattern is one of the


simpler design .This pattern is effective
for limiting the maximum number of
instances of a class to exactly one. In
this case, if more than one object needs
to use an instance of the Singleton
class, those objects share the same
Singleton class instance.
DesignPatterns 17

The singleton pattern is implemented by


creating a class with a method that
creates a new instance of the object if
one does not exist. If an instance
already exists, it simply returns a
reference to that object. To make sure
that the object cannot be instantiated
any other way, the constructor is made
either private or protected. Note the
distinction between a simple static
instance of a class and a singleton.
Although a singleton can be
implemented as a static instance, it can
also be lazily constructed, requiring no
memory or resources until needed.

public class PerdiemDAO implements


IPerdiemDAO
{
private static final PerdiemDAO
INSTANCE;

/**
* This method returns the singleton
instance of this class.
DesignPatterns 18

* @return PerdiemDAO
*/

public static PerdiemDAO


getInstance( )
{
If(INSTANCE= =NULL)
INSTANCE=new PerdiemDAO() ;

return INSTANCE;
}
}

You can call the instance of this class


using PerdiemDAO.getInsta nce(),
where ever you want.
The design of this class ensures that
only one Singleton object is ever
created. The constructor is declared
private and the getInstance( )
method creates only one object. This
implementation is fine for a single-
DesignPatterns 19

threaded program. However, when


multiple threads are introduced, you
must protect the getInstance( )
method through synchronization. If the
getInstance( ) method is not
protected, it is possible to return two
different instances of the Singleton
object. Consider two threads calling the
getInstance( ) method concurrently
and the following sequence of events:
1. Thread 1 calls the getInstance(
) method and determines that instance
is null at //1.
2. Thread 1 enters the if block, but
is preempted by thread 2 before
executing the line at //2.
3. Thread 2 calls the getInstance(
) method and determines that instance
is null at //1.
4. Thread 2 enters the if block and
creates a new Singleton object and
assigns the variable instance to this
new object at //2.
DesignPatterns 20

5. Thread 2 returns the Singleton


object reference at //3.
6. Thread 2 is preempted by thread
1.
7. Thread 1 starts where it left off
and executes line //2 which results in
another Singleton object being
created.
8. Thread 1 returns this object
at //3.
The result is that the getInstance( )
method created two Singleton objects
when it was supposed to create only
one. This problem is corrected by
synchronizing the getInstance( )
method to allow only one thread to
execute the code at a time, as shown in
Listing 2:

public static PerdiemDAO getInstance( )


{
if (instance == null)
{
synchronized(PerdiemDAO.class)
{
DesignPatterns 21

instance = new PerdiemDAO ();


}
}
return instance;
}

4. Delegation pattern

Delegation can be viewed as a


relationship between objects where one
object forwards certain method calls to
another object, called its delegate.
Delegation can also a powerful
design/reuse technique. The primary
advantage of delegation is run-time
flexibility – the delegate can easily be
changed at run-time. But unlike
inheritance, delegation is not directly
supported by most popular object-
oriented languages, and it doesn’t
facilitate dynamic polymorphism.

As a simple example, consider the


relationship between a Rectangle class
DesignPatterns 22

and a Window class. With inheritance, a


Window class would inherit its
rectangular properties from class
Rectangle. With delegation, a Window
object would maintain a reference or
pointer to a Rectangle object, and calls
to rectangle-like methods of the Window
object would be delegated to
corresponding methods of the Rectangle
object.

Now let’s consider a slightly more


complex example. Suppose employees
can classified based on how they are
paid; e.g., hourly or salaried. Using
inheritance, we might design three
classes: an Employee class which
encapsulates the functionality common
to all employees, and two subclasses
HourlyEmployee and SalariedEmployee
which encapsulates pay-specific details.
While this design might be suitable for
some applications, we would encounter
problems in a scenario where a person
changes, say from hourly to salaried.
DesignPatterns 23

The class of an object and the


inheritance relationship are both static,
and objects can’t change their class
easily (but see the State pattern for tips
on how to fake it).

A more flexible design would involve


delegation – an Employee object could
delegate pay-related method calls to an
object whose responsibilities focused
solely on how the employee is paid. In
fact, we might still use inheritance here
in a slightly different manner by
creating an abstract class (or interface)
called PayClassification with two
subclasses HourlyPayClassifica tion and
SalariedPayClassifi cation which
implement classification- specific
computations. Using delegation as
shown, it would be much easier to
change the pay classification of an
existing Employee object.

This second example illustrates an


important point: In implementing
DesignPatterns 24

delegation, we often want the capability


to replace the delegate with another
object, possibly of a different class.
Therefore delegation will often use
inheritance and polymorphism, with
classes of potential delegates being
subclasses of an abstract class which
encapsulates general delegate
responsibilities.

One final point. Sometimes, the choice


between delegation and inheritance is
driven by external factors such as
programming language support for
multiple inheritance or design
constraints requiring polymorphism.
Consider threads in Java. You can
associate a class with a thread in one of
two ways: either by extending
(inheriting) directly from class Thread,
or by implementing the Runnable
interface and then delegating to a
Thread object. Often the approach taken
is based on the restriction in Java that a
class can only extend one class (i.e.,
DesignPatterns 25

Java does not support multiple


inheritance) . If the class you want to
associate with a thread already extends
some other class in the design, then you
would have to use delegation;
otherwise, extending class Thread would
usually be the simpler approach.

5. Observer Pattern
Simply, the Observer pattern allows one
object (the observer) to watch another
(the subject). The Observer pattern
allows the subject and observer to form
a publish-subscribe relationship.
Through the Observer pattern,
observers can register to receive events
from the subject. When the subject
needs to inform its observers of an
event, it simply sends the event to each
observer.
Use the Observer pattern in any of the
following situations:
DesignPatterns 26

 When an abstraction has two


aspects, one dependent on the
other. Encapsulating these aspects in
separate objects lets you vary and
reuse them independently.
 When a change to one object
requires changing others, and you
don't know how many objects need
to be changed.
 When an object should be able to
notify other objects without making
assumptions about who these
objects are. In other words, you
don't want these objects tightly
coupled.

Consider the following Java example:

public interface Subject {


public void
addObserver( Observer o );
public void
removeObserver( Observer o );
}
DesignPatterns 27

In the code above, the Subject


interface defines the methods that a
Subject must implement in order for
Observers to add and remove
themselves from the Subject.

public interface Observer {


public void update( Subject
o );
}
The Observer interface (above) lists the
methods that an Observer must
implement so that a Subject can send
an update notification to the Observer.
Let's consider a simple implementation
of Subject -- an IntegerDataBag:

import java.util.ArrayList ;
import java.util.Iterator;

public class IntegerDataBag


implements Subject {
DesignPatterns 28

private ArrayList list = new


ArrayList();
private ArrayList observers
= new ArrayList();

public void add( Integer i )


{
list.add( i );
notifyObservers( );
}

public Iterator iterator() {


return
list.iterator( );
}

public Integer remove( int


index ) {
if( index <
list.size() ) {
Integer i =
(Integer) list.remove( index );
notifyObservers(
);
return i;
}
DesignPatterns 29

return null;
}

public void
addObserver( Observer o ) {
observers.add( o );
}

public void
removeObserver( Observer o ) {
observers.remove( o );
}

private void
notifyObservers( ) {
// loop through and
notify each observer
Iterator i =
observers.iterator( );
while( i.hasNext() ) {
Observer o =
( Observer ) i.next();
o.update( this )
;
}
}
}
DesignPatterns 30

IntegerDataBag holds onto Integer


instances. The IntegerDataBag also
allows Observers to add and remove
themselves.
Consider these two implementations of
Observer -- IntegerAdder and
IntegerPrinter:

import java.util.Iterator;

public class IntegerAdder


implements Observer {

private IntegerDataBag bag;

public
IntegerAdder( IntegerDataBag bag )
{
this.bag =
bag;
bag.addObserver( this
);
}

public void update( Subject


DesignPatterns 31

o ) {
if( o == bag ) {
System.out.print
ln( "The contents of the
IntegerDataBag have changed." );
int counter = 0;
Iterator i =
bag.iterator( );
while( i.hasNext
() ) {
Integer
integer = ( Integer ) i.next();
counter+=i
nteger. intValue( );
}
System.out.print
ln( "The new sum of the integers
is: " + counter );
} }}

import java.util.Iterator;

public class IntegerPrinter


implements Observer {

private IntegerDataBag bag;


DesignPatterns 32

public
IntegerPrinter( IntegerDataBag bag
) {
this.bag =
bag;
bag.addObserver( this
);
}

public void update( Subject


o ) {
if( o == bag ) {
System.out.print
ln( "The contents of the
IntegerDataBag have changed." );
System.out.print
ln( "The new contents of the
IntegerDataBag contains:" );
Iterator i =
bag.iterator( );
while( i.hasNext
() ) {
System.out
.println( i.next() );
}
}
}
DesignPatterns 33

IntegerAdder and IntegerPrinter add


themselves to the integer bag as
observers. When an IntegerAdder
receives an update, it sums up the
Integer values held in the bag and
displays them. Likewise, when
IntegerPrinter receives an update, it
prints out the Integers held in the bag.
Here is a simple main() that exercises
these classes:

public class Driver {


Public static void
main( String [] args ) {
Integer i1 = new Integer( 1 );
Integer i2 = new Integer( 2 );
Integer i3 = new Integer( 3 );
Integer i4 = new Integer( 4 );
Integer i5 = new Integer( 5 );
Integer i6 = new Integer( 6 );
Integer i7 = new Integer( 7 );
Integer i8 = new Integer( 8 );
Integer i9 = new Integer( 9 );
DesignPatterns 34

IntegerDataBag bag = new


IntegerDataBag( );
bag.add( i1 );
bag.add( i2 ); bag.add( i3 );
bag.add( i4 );
bag.add( i5 );
bag.add( i6 ); bag.add( i7 );
bag.add( i8 );

IntegerAdder adder = new


IntegerAdder( bag );
IntegerPrinter printer = new
IntegerPrinter( bag );

// adder and printer add


themselves to the bag

System.out.println( "adding
another integer to the bag:" );
bag.add( i9 );
System.out.println( "");
System.out.println( "About
to remove an integer from the
bag:");
bag.remove( 0 );
DesignPatterns 35

}
}
The IntegerDataBag/ IntegerAdder/
IntegerPrinter is a simple example of
the Observer pattern. Within Java itself
there are a number of examples of the
Observer pattern: the AWT/Swing event
model, as well as the
java.util.Observer and
java.util.Observabl e interfaces
serve as examples.

6. Struts Patterns

The heart of Struts is the Controller.


Struts uses the Front Controller
Pattern and Command Pattern. A
single servlet takes a request,
translates HTTP parameters into
a Java ActionForm, and passes
DesignPatterns 36

the ActionForm into a Struts


Action class, which is a command.
The URI denotes which Action
class to go to. The Struts
framework has one single event
handler for the HTTP request.
Once the request is met, the
Action returns the result back to
the front controller, which then
uses it to choose where to
navigate next

Front Controller
The Front Controller pattern defines a
single component that is responsible for
processing application requests. A front
controller centralizes functions such as
view selection, security, and templating,
and applies them consistently across all
pages or views. Consequently, when the
behavior of these functions need to
change, only a small part of the
DesignPatterns 37

application needs to be changed: the


controller and its helper classes.
Introducing a controller as the initial
point of contact for handling a request.
The controller manages the handling of
the request, including invoking security
services such as authentication and
authorization, delegating business
processing, managing the choice of an
appropriate view, handling errors, and
managing the selection of content
creation strategies.

The controller provides a centralized


entry point that controls and manages
Web request handling. By centralizing
decision points and controls, the
controller also helps reduce the amount
of Java code, called scriptlets,
embedded in the JavaServer Pages
(JSP) page.

Centralizing control in the controller and


reducing business logic in the view
promotes code reuse across requests. It
DesignPatterns 38

is a preferable approach to the


alternative- embedding code in multiple
views-because that approach may lead
to a more error-prone, reuse-by-copy-
and-paste environment.

Typically, a controller coordinates with a


dispatcher component. Dispatchers are
responsible for view management and
navigation. Thus, a dispatcher chooses
the next view for the user and vectors
control to the resource. Dispatchers
may be encapsulated within the
controller directly or can be extracted
into a separate component.

The responsibilities of the components


participating in this patterns are :
Controller : The controller is the initial
contact point for handling all requests in
the system. The controller may delegate
DesignPatterns 39

to a helper to complete authentication


and authorization of a user or to initiate
contact retrieval.

Dispatcher : A dispatcher is
responsible for view management and
navigation, managing the choice of the
next view to present to the user, and
providing the mechanism for vectoring
control to this resource. A dispatcher
can be encapsulated within a controller
or can be a separate component
working in coordination. The dispatcher
provides either a static dispatching to
the view or a more sophisticated
dynamic dispatching mechanism. The
dispatcher uses the RequestDispatcher
object (supported in the servlet
specification) and encapsulates some
additional processing.
Helper : A helper is responsible for
helping a view or controller complete its
processing. Thus, helpers have
numerous responsibilities, including
gathering data required by the view and
DesignPatterns 40

storing this intermediate model, in


which case the helper is sometimes
referred to as a value bean.
Additionally, helpers may adapt this
data model for use by the view. Helpers
can service requests for data from the
view by simply providing access to the
raw data or by formatting the data as
Web content. A view may work with any
number of helpers, which are typically
implemented as JavaBeans components
(JSP 1.0+) and custom tags (JSP 1.1+).
Additionally, a helper may represent a
Command object, a delegate, or an XSL
Transformer, which is used in
combination with a stylesheet to adapt
and convert the model into the
appropriate form.

View
A view represents and displays
information to the client. The view
retrieves information from a model.
Helpers support views by encapsulating
and adapting the underlying data model
DesignPatterns 41

for use in the display.

Front Controller centralizes control. A


controller provides a central place to
handle system services and business
logic across multiple requests. A
controller manages business logic
processing and request handling.
Centralized access to an application
means that requests are easily tracked
and logged. Keep in mind, though, that
as control centralizes, it is possible to
introduce a single point of failure. In
practice, this rarely is a problem,
though, since multiple controllers
typically exist, either within a single
server or in a cluster.

Front Controller improves manageability


of security. A controller centralizes
control, providing a choke point for illicit
access attempts into the Web
application. In addition, auditing a
single entrance into the application
requires fewer resources than
DesignPatterns 42

distributing security checks across all


pages.

Front Controller improves reusability. A


controller promotes cleaner application
partitioning and encourages reuse, as
code that is common among
components moves into a controller or
is managed by a controller.

Command Pattern
A Command pattern is an object
behavioral pattern that allows us
to achieve complete decoupling
between the sender and the
receiver. (A sender is an object
that invokes an operation, and a
receiver is an object that receives
the request to execute a certain
operation. With decoupling, the
sender has no knowledge of the
Receiver's interface.) The term
request here refers to the
DesignPatterns 43

command that is to be executed.


The Command pattern also allows
us to vary when and how a
request is fulfilled. Therefore, a
Command pattern provides us
flexibility as well as extensibility.
How The Pattern Works

A simple example of a common problem the


Command Design Pattern is well suited to
solve is the evaluation and execution of an
incoming HttpServletRequest action
parameter command from a submit on a JSP
page.
In Struts terminology, this class is called an
action although you'll also see this general
pattern referred to as the command pattern. At
runtime, the Struts controller (a Java servlet)
maps the incoming request onto an action
class and calls the execute() method, which
contains the (business) logic required to
service the request.
Most servlets in the M-V-C Model 2 form (i.e.
Struts framework type) redirect both their
doGet() and doPost() methods to a perform()
DesignPatterns 44

or performTask( ) method after stripping out


the relevant data from the
HttpServletRequest. Thus, we can pass an
already constructed object graph the system
will then manipulate. To keep things simple,
we will just pass the performTask( ) method of
our servlet a String action parameter such as
"create", "replace", "update", etc.

// CommandExample. java

import java.util.HashMap;

// ************ *********
********* ********* *********
********* ********* ******
/**
* CommandExample. java
*
* Provides a simple Command
Design Pattern Example.
*
* The example will show how to
use the Command Design Pattern
* by replacing conditional
control logic in a simulated M-V-C
Model
DesignPatterns 45

* 2 servlet. So as not to need a


webserver to implement this
* example, a phamtom object will
be created and passed in for
* demonstration purposes.
*/
// ************ *********
********* ********* *********
********* ********* ******

public class CommandExample {


public static void
main(String[ ] args) {
CommandExample.
log(1,"Begin Command Design
Pattern example.");
ExampleServlet
exampleServlet = new
ExampleServlet( );
int maxApproaches =
3;
String
exampleActionReques t = "update";
DesignPatterns 46

CommandExample.
log(1,"Simulated servlet request
received is: " +

exampleActionReques t);
CommandExample.
log(1,"Code will show " +
maxApproaches +
"
approaches as to how such a
command can be processed.") ;
for(int i=1;
i<=maxApproaches; i++) {

exampleServlet. doPost(i,
exampleActionReq uest);
} //endfor
CommandExample.
log(1,"End Command Design Pattern
example.");
} //endmain

// ============ =========
========= ========= =========
========= ========= =
public static void log(int
aLevel, String aMsg) {
DesignPatterns 47

boolean
showLogTraceToSyste mOut = true;

if(showLogTraceToSy stemOut) {
String
prefix = "";
if(aLevel
== 1) {

prefix = " ---> ";


} else
if(aLevel == 2) {

prefix = " ---> ";


} else
if(aLevel == 3) {

prefix = " ---> ";


} //endif

System.out.println( prefix +
aMsg);
} //endif
} //endmethod: log
} //endclass: CommandExample. java
DesignPatterns 48

// ************ *********
********* ********* *********
********* ********* ******
/**
* ExampleServlet. java
*
* Simulates a servlet in an M-V-C
Model 2 environment.
*
* @param action the desired
action the servlet is to perform.
*/
// ************ *********
********* ********* *********
********* ********* ******

class ExampleServlet {
private HashMap commandMap
= new HashMap();

// ============ =========
========= ========= =========
========= ========= =
DesignPatterns 49

public ExampleServlet( ) {
//-- Initialize
HashMap of possible ActionType
concrete objects

commandMap.put( "create", new


ActionTypeCreate( ));

commandMap.put( "replace" , new


ActionTypeReplace( ));

commandMap.put( "update", new


ActionTypeUpdate( ));

commandMap.put( "delete", new


ActionTypeDelete( ));
} //endmain

// ============ =========
========= ========= =========
========= ========= =
public void doPost(int
approachSolution, String action) {
switch
(approachSolution) {
case 1:
DesignPatterns 50

CommandExample. log(2,

"Demonstrating from full


conditional processing." );

performTask1( action);
break;
case 2:

CommandExample. log(2,

"Demonstrating from abstracted


concrete class processing." );

performTask2( action);
break;
case 3:

CommandExample. log(2,

"Demonstrating from Command Design


Pattern processing." );

performTask3( action);
break;
} //endswitch
DesignPatterns 51

} //endmethod: doPost

// ============ =========
========= ========= =========
========= ========= =
private void performTask1(
String action) {
//-- Process
business logic within conditional
statements

if( action.equalsIgnore
Case("create" ) ) {

CommandExample. log(3,

"create business logic


executing... ");
} else
if( action.equalsIgnore
Case("replace" ) ) {

CommandExample. log(3,

"replace business logic


executing... ");
DesignPatterns 52

} else
if( action.equalsIgnore
Case("update" ) ) {

CommandExample. log(3,

"update business logic


executing... ");
} else
if( action.equalsIgnore
Case("delete" ) ) {

CommandExample. log(3,

"delete business logic


executing... ");
} //endif
} //endmethod:
performTask1

// ============ =========
========= ========= =========
========= ========= =
private void performTask2(
String action) {
DesignPatterns 53

//-- Abstracts out


all business logic into separate
classes
ActionType cmd =
null;

if( action.equalsIgnore
Case("create" ) ) {
cmd = new
ActionTypeCreate( );
} else
if( action.equalsIgnore
Case("replace" ) ) {
cmd = new
ActionTypeReplace( );
} else
if( action.equalsIgnore
Case("update" ) ) {
cmd = new
ActionTypeUpdate( );
} else
if( action.equalsIgnore
Case("delete" ) ) {
cmd = new
ActionTypeDelete( );
} //endif
DesignPatterns 54

cmd.execute( );
} //endmethod:
performTask2

// ============ =========
========= ========= =========
========= ========= =
private void performTask3(
String action) {
//-- Uses the
Command Design Pattern to
polymorphically
//-- execute
desired action
ActionType cmd =
(ActionType) commandMap.
get(action) ;
cmd.execute( );
} //endmethod:
performTask3
} //endclass: ExampleServlet

// ************ *********
********* ********* *********
********* ********* ******
abstract class ActionType {
DesignPatterns 55

abstract public void


execute();
} //endclass: ActionType

// ************ *********
********* ********* *********
********* ********* ******
class ActionTypeCreate extends
ActionType {
public void execute() {
CommandExample.
log(3,

"ActionTypeCreate business logic


executing... ");
} //endmethod: execute
} //endclass: ActionTypeCreate

// ************ *********
********* ********* *********
********* ********* ******
class ActionTypeReplace extends
ActionType {
public void execute() {
CommandExample.
log(3,
DesignPatterns 56

"ActionTypeReplace business logic


executing... ");
} //endmethod: execute
} //endclass: ActionTypeReplace

// ************ *********
********* ********* *********
********* ********* ******
class ActionTypeUpdate extends
ActionType {
public void execute() {
CommandExample.
log(3,

"ActionTypeUpdate business logic


executing... ");
} //endmethod: execute
} //endclass: ActionTypeUpdate

// ************ *********
********* ********* *********
********* ********* ******
class ActionTypeDelete extends
ActionType {
public void execute() {
DesignPatterns 57

CommandExample.
log(3,

"ActionTypeDelete business logic


executing... ");
} //endmethod: execute
} //endclass: ActionTypeDelete

Command pattern example code


Let's take a look at a simple example
illustrating the callback mechanism
achieved via the Command pattern.
The example shows a Fan and a Light.
Our objective is to develop a Switch
that can turn either object on or off. We
see that the Fan and the Light have
different interfaces, which means the
Switch has to be independent of the
Receiver interface or it has no
knowledge of the code>Receiver's
interface. To solve this problem, we
need to parameterize each of the
Switchs with the appropriate command.
Obviously, the Switch connected to the
Light will have a different command
DesignPatterns 58

than the Switch connected to the Fan.


The Command class has to be abstract or
an interface for this to work.
When the constructor for a Switch is
invoked, it is parameterized with the
appropriate set of commands. The
commands will be stored as private
variables of the Switch.
When the flipUp() and flipDown()
operations are called, they will simply
make the appropriate command to
execute( ). The Switch will have no
idea what happens as a result of
execute( ) being called.

TestCommand. java
class Fan {
public void startRotate( )
{
System.out.println
( "Fan is rotating");
}
public void stopRotate() {
System.out.println
( "Fan is not rotating");
DesignPatterns 59

}
}
class Light {
public void turnOn( ) {
System.out.println
( "Light is on ");
}
public void turnOff( ) {
System.out.println
( "Light is off");
}
}
class Switch {
private Command UpCommand,
DownCommand;
public Switch( Command Up,
Command Down) {
UpCommand = Up; //
concrete Command registers itself
with the invoker
DownCommand =
Down;
}
void flipUp( ) { //
invoker calls back concrete
Command, which executes the
Command on the receiver
DesignPatterns 60

UpCommand
. execute ( ) ;

}
void flipDown( ) {
DownComman
d . execute ( );
}
}
class LightOnCommand implements
Command {
private Light myLight;
public LightOnCommand
( Light L) {
myLight = L;
}
public void execute( ) {
myLight .
turnOn( );
}
}
class LightOffCommand implements
Command {
private Light myLight;
public LightOffCommand
( Light L) {
myLight = L;
DesignPatterns 61

}
public void execute( ) {
myLight . turnOff(
);
}
}
class FanOnCommand implements
Command {
private Fan myFan;
public FanOnCommand ( Fan
F) {
myFan = F;
}
public void execute( ) {
myFan .
startRotate( );
}
}
class FanOffCommand implements
Command {
private Fan myFan;

public FanOffCommand ( Fan


F) {
myFan = F;
}
public void execute( ) {
DesignPatterns 62

myFan .
stopRotate( );
}
}
public class TestCommand {
public static void
main(String[ ] args) {
Light tes
tLight = new Light( );
LightOnCom
mand testLOC = new LightOnCommand(
testLight) ;
LightOffCo
mmand testLFC = new
LightOffCommand( testLight) ;
Switch
testSwitch = new
Switch( testLOC,testLFC) ;
testSwitch
.flipUp( );
testSwitch
.flipDown ( );
Fan
testFan = new Fan( );
FanOnComma
nd foc = new
FanOnCommand( testFan);
DesignPatterns 63

FanOffComm
and ffc = new
FanOffCommand( testFan);
Switch ts
= new Switch( foc,ffc);
ts.flipUp(
);
ts.flipDow
n( );
}
}
Command.java
public interface Command {
public abstract void
execute ( );
}
Notice in the code example above that
the Command pattern completely
decouples the object that invokes the
operation -- (Switch ) -- from the ones
having the knowledge to perform it --
Light and Fan. This gives us a lot of
flexibility: the object issuing a request
must know only how to issue it; it
doesn't need to know how the request
will be carried out.
DesignPatterns 64

7. DAO
The Data Access Object Pattern, also known
as the DAO pattern, abstracts the retrieval of
data from a data resource such as a
database. The concept is to "separate a data
resource's client interface from its data access
mechanism."
J2EE developers use the Data Access Object
(DAO) design pattern to separate low-level
data access logic from high-level business
logic. Implementing the DAO pattern involves
more than just writing data access code.
The problem with accessing data directly is
that the source of the data can change.
Consider, for example, that your application is
deployed in an environment that accesses an
DesignPatterns 65

Oracle database. Then it is subsequently


deployed to an environment that uses
Microsoft SQL Server. If your application uses
stored procedures and database-specific code
(such as generating a number sequence),
how do you handle that in your application?
You have two options:
 Rewrite your application to use SQL
Server instead of Oracle (or add conditional
code to handle the differences) , or
 Create a layer inbetween your
application logic and the data access
The Data Access Object pattern does the
latter.
The benefits of the DAO pattern are obvious,
but the implementation is a little tricky. To
properly implement the DAO pattern you need
to generate the following components:
1. DAO Interface
2. DAO Factory
3. DAO Implementation classes
4. Deployment Descriptor Entry
The DAO pattern, in and of itself, does not
necessarily require a factory, but in practice
you will see the two patterns coupled. The
reason is that some mechanism needs to be
DesignPatterns 66

created to obtain the appropriate


implementation class and using a factory is
the cleanest implementation.
Example
DAO Interface
The DAO interface defines all the
methods that your data access objects
will provide. For a database, these
include things like inserting, deleting,
updating, and retrieving rows. Because
it is an interface, the methods will not
be implemented. Listing 1 shows a
sample DAO interface.
SampleDAO.java
package com.ks.myejb. dao;
public interface SampleDAO
{
public SampleModel create( long
id, String name, String data )
throws

SampleDAOException;
DesignPatterns 67

public void delete( long id )


throws SampleDAOException;
public void update( long id,
SampleModel model ) throws
SampleDAOException;
public SampleModel[ ] findByName(
String name ) throws
SampleDAOException;
public
SampleModel findById( long id )
throws SampleDAOException;
}
The SampleDAO interface presumes a
SampleModel object that represents one
unit of data. Listing 2 shows the
implementation of this hypothetical
class.
SampleModel. java
package com.ks.myejb. model;
public class SampleModel
{ private long id;
private String name;
private String data;
DesignPatterns 68

public SampleModel( long id,


String name, String data ) {
this.id = id;
this.name = name;
this.data = data;
}

public long getId() {


return id;
}

public String getName() {


return name;
}

public String getData() {


return data;
}

public void setName( String


name ) {
this.name = name;
}

public void setData( String


data ) {
this.data = data;
DesignPatterns 69

}
}

The class that eventually uses the


implementation of this interface will use
it via this interface, and not through the
implementation itself.
DAO Implementation
We need a class that performs the
actual data access; this will be the
function of the DAO implementation
class. Its job is to translate the general
request for information to a request
specific to the data source it represents.
For database access, I usually suggest
the following:
• JDBC Generic implementation:
this is an implementation that uses only
JDBC and standard SQL
• Database vendor specific
implementation number one: e.g.
Oracle
DesignPatterns 70

• Database vendor specific


implementation number two: e.g. SQL
Server
• Database vendor specific
implementation number ...
Below shows a sample implementation
of the DAO implementation class.
SampleDAOJDBCImpl. java
package com.ks.myejb. model;

import java.sql.*;

public class SampleDAOJDBCImpl


implements SampleDAO
{
public SampleModel create( long
id, String name, String data )
throws
SampleDAOException {
try {
Connection conn =
getConnection( );
PreparedStatement ps =
DesignPatterns 71

conn.prepareStateme
nt( "INSERT INTO sample VALUES( ?,
?, ? )" );
ps.setLong( 1, id );
ps.setString( 2, name );
ps.setString( 3, data );
ps.executeUpdate( );
return new SampleModel( id,
name, data );
}
catch( SQLException e ) {
throw new SampleDAOException( e
);
}
}

public void delete( long id )


throws SampleDAOException {
// Similar: DELETE FROM sample
WHERE id = ?
}

public void update( long id,


SampleModel model ) throws
sampleDAOException {
// Similar: UPDATE sample SET
name = ?, data = ? WHERE id =
DesignPatterns 72

?
}

public SampleModel[ ] findByName(


String name ) throws
SampleDAOException {
// Similar: SELECT
FROM sample WHERE name = ?
}

public SampleModel findById( long


id ) throws SampleDAOException {
// Similar: SELECT FROM sample
WHERE id = ?
}}
At runtime, this is the class that
will perform the data access on
our behalf.
DAO Factory
We need a mechanism for determining
what class to load at runtime and use in
DesignPatterns 73

our application. This is the job of the


DAO factory class.
The factory class is used in another
pattern, the Factory Pattern. The
purpose of the factory pattern is to
defer the choice of an implementation
class until runtime. You ask the factory
to create a class that implements a
specific interface and (given some piece
of additional environmental information)
, the factory creates the appropriate
class.
In the case of an EJB deployment, the
additional environmental information is
usually specified through the EJB's
deployment descriptor. In a stand-alone
environment, you can specify it with
Java system properties or a
configuration file (such as an XML file or
properties file).
SampleDAOFactory. java
package com.ks.myejb. dao;

// Import the JNDI classes


DesignPatterns 74

import javax.naming.
NamingException;
import javax.naming.
InitialContext;

public class SampleDAOFactory {

private static SampleDAO dao =


null;

public static SampleDAO getDAO()


throws
SampleDAOException
{
// If we already have loaded
the BookDAO, return it
if ( dao != null ) {
return dao;

try {
InitialContext ic = new
InitialContext( );
String className =
( String )
ic.lookup( "SAMPLEDAO.Impl" );
DesignPatterns 75

dao = ( SampleDAO )
Class.forName( className ).newInst
ance( );
}
catch( NamingException ne ) {
throw new
SampleDAOException( ne );
}
catch( Exception se ) {
throw new
SampleDAOException( se );
}
return dao; } }

The SampleDAOFactory class maintains


a static reference to the SampleDAO
class. The first time the DAO object is
requested, the factory looks up the fully
qualified class name of the
implementation class specified by the
deployment descriptor key:
"SAMPLEDAO.Impl" . It uses the
InitialContext class to access the
Java Naming and Directory Interface
(JNDI) and then calls its lookup()
DesignPatterns 76

method to find the String value. Finally,


it loads the class dynamically by calling
Class.forName( ) and casting it to
SampleDAO.
Deployment Descriptor Entry
The final piece of information to get into
the system is the association between
"SAMPLEDAO.Impl" and the actual class
that implements the SampleDAO
interface (com.ks.myejb.
dao.SampleDAOJDB CImpl). This is
accomplished by creating an <env-
entry> entry in the ejb-jar.xml file.
Below shows an excerpt from this file.
Excerpt from ejb-jar.xml
<ejb-jar>
<enterprise-beans>
<entity>
<description>Sample
Bean</description>
<ejb-name>SampleBean</ejb-name>
<home>com.ks.myejb.
ejb.SampleHome</home>
DesignPatterns 77

<remote>com.ks.myejb.
ejb.Sample</remote>
<ejb-class>com.ks.myejb.
ejb.SampleEJB</ejb-class>
<persistence-
type>Bean</persistence- type>
<prim-key-class>com.ks.myejb.
ejb.SamplePk</prim-key-class>
<reentrant>False</reentrant>

<env-entry>
<env-entry-
name>SAMPLEDAO.Impl</env-entry-
name>
<env-entry-
type>java.lang.String</env-entry-
type>
<env-entry-value>com.ks.myejb.
dao.SampleDAOJDB CImpl</env-
entry-value>
</env-entry>
...
</entry>
...
</enterprise- beans>
<ejb-jar>
DesignPatterns 78

In this case, we define a


java.lang.String key named
"SAMPLEDAO.Impl" to be
"com.ks.myejb. dao.SampleDAOJDB
CImpl". This will make a JNDI
entry into any class owned by the
SampleBean class.
8. Session Facade
Brief Description
Session facade is one design pattern
that is often used while developing
enterprise applications. It is
implemented as a higher level
component (i.e.: Session EJB), and it
contains all the iteractions between low
level components (i.e.: Entity EJB). It
then provides a single interface for the
functionality of an application or part of
it, and it decouples lower level
components simplifying the design.
Think of a bank situation, where you
have someone that would like to
transfer money from one account to
another.
DesignPatterns 79

In this type of scenario, the client has to


check that the user is authorized, get
the status of the two accounts, check
that there are enough money on the
first one, and then call the transfer. The
entire transfer has to be done in a single
transaction otherwise is something goes
south, the situation has to be restored.
As you can see, multiple server-side
objects need to be accessed and
possibly modified. Multiple fine-grained
invocations of Entity (or even Session)
Beans add the overhead of network
calls, even multiple transaction. In other
words, the risk is to have a solution that
has a high network overhead, high
coupling, poor reusability and
mantainability.
The best solution is then to wrap all the
calls inside a Session Bean, so the
clients will have a single point to access
(that is the session bean) that will take
care of handling all the rest.
Many business processes involve
complex manipulations of business
DesignPatterns 80

classes. Business classes often


participate in multiple business
processes or workflows. Complex
processes that involve multiple business
objects can lead to tight coupling
between those classes, with a resulting
decrease in flexibility and design clarity.
Complex relationships between low-level
business components make clients
difficult to write.
The Session Facade pattern defines a
higher-level business component that
contains and centralizes complex
interactions between lower-level
business components. A Session Facade
is implemented as a session enterprise
bean. It provides clients with a single
interface for the functionality of an
application or application subset. It also
decouples lower-level business
components from one another, making
designs more flexible and
comprehensible.
Fine-grained access through remote interfaces is inadvisable because
it increases network traffic and latency. The "before" diagram in Figure
1 below shows a sequence diagram of a client accessing fine-grained
business objects through a remote interface. The multiple fine-grained
DesignPatterns 81

calls create a great deal of network traffic, and performance suffers


because of the high latency of the remote calls.

Figure 1. Sequence diagram before


and after adding Session Facade

This FIRST approach features two main


drawbacks.
First, it doesn't scale. The client
application must make remote calls to
each enterprise bean. There are six
network calls in all, as shown in Figure
1's sequence diagram.
The second drawback: This approach
has poor concurrency. The transaction
will be stretched longer due to network
overhead, and as a result, this approach
inevitably increases the chances of
deadlock and reduces concurrency.
A commonly used J2EE pattern for EJBs is
called the Session Facade pattern. In this
pattern, a stateless session bean is used as a
facade to hide access to one or more entity
beans. Remote clients interact only with the
session bean and never directly with the entity
beans (see Figure 1).
DesignPatterns 82

The first important benefit of the Session


Facade pattern is that the client has a simpler
interface and doesn't need to know about the
details of which entity beans and which
methods to use. In my analogy, the session
bean is like the general contractor and the
entity beans are the subcontractors.

The Session Facade pattern improves


performance as only the calls between the
client and the session bean go across the
network, while calls from the session bean to
the entity beans are local to the EJB
container. Performance can be further
enhanced through the use of local interfaces,
introduced as part of the EJB specification
version 2.0. Local interfaces provide support
for "lightweight" access from within the EJB
container, avoiding the overhead associated
with a remote interface.

A third benefit of the Session Facade pattern


relates to transactions. With container-
managed transactions, the container begins a
transaction when a method starts to execute
and ends the transaction when the method
DesignPatterns 83

returns. By enclosing the entity beans calls in


the session bean method, the database
operations are automatically grouped together
as a transactional unit. To ensure that they
participate in the same transaction, the entity
bean methods should be assigned the
"Required" transaction attribute in ejb-jar.xml
(or by using the WebLogic Administration
Console).

Sample Code
Implementing the Session Facade
Consider a Professional Services
Application (PSA), where the workflow
related to entity beans (such as Project,
Resource) is encapsulated in
ProjectResourceMana gerSession,
implemented using the Session Facade
pattern. Example 8.15 shows the
interaction with Resource and Project
entity beans, as well as other business
components, like Value List Handlers
(see "Value List Handler" on page 354)
and Transfer Object Assemblers (see
DesignPatterns 84

"Transfer Object Assembler" on page


340).
Example 8.15 Implementing Session
Facade - Session Bean
package corepatterns. apps.psa.
ejb;

import java.util.*;
import java.rmi.RemoteExce ption;
import javax.ejb.*;
import javax.naming. *;
import corepatterns. apps.psa.
core.*;
import corepatterns.
util.ServiceLoca tor;
import corepatterns.
util.ServiceLoca torException;

// Note: all try/catch details not


shown for brevity.

public class ProjectResourceMana


gerSession
implements SessionBean {

private SessionContext context;


DesignPatterns 85

// Remote references for the


// entity Beans encapsulated by
this facade
private Resource resourceEntity
= null;
private Project projectEntity =
null;
...

// default create
public void ejbCreate()
throws CreateException {
}

// create method to create this


facade and to
// establish connections to the
required entity
// beans
// using primary key values
public void ejbCreate(
String resourceId, String
projectId, ...)
throws CreateException,
ResourceException {
DesignPatterns 86

try {
// locate and connect to
entity beans

connectToEntities( resourceId,
projectId, ...);
} catch(...) {
// Handle exceptions
}
}

// method to connect the session


facade to its
// entity beans using the
primary key values
private void connectToEntities (
String resourceId, String
projectId)
throws ResourceException {
resourceEntity =
getResourceEntity( resourceId) ;
projectEntity =
getProjectEntity( projectId) ;
...
}

// method to reconnect the


DesignPatterns 87

session facade to a
// different set of entity beans
using primary key
// values
public resetEntities( String
resourceId,
String projectId, ...)
throws PSAException {

connectToEntities( resourceId,
projectId, ...);
}

// private method to get Home


for Resource
private ResourceHome
getResourceHome( )
throws ServiceLocatorExcep tion
{
return ServiceLocator.
getInstance( ).getHome(
"ResourceEntity" ,
ResourceHome. class);
}

// private method to get Home


for Project
DesignPatterns 88

private ProjectHome
getProjectHome( )
throws ServiceLocatorExcep tion
{
return ServiceLocator.
getInstance( ).getHome(
"ProjectEntity" ,
ProjectHome. class);
}

// private method to get


Resource entity
private Resource
getResourceEntity(
String resourceId) throws
ResourceException {
try {
ResourceHome home =
getResourceHome( );
return (Resource)
home.findByPrimaryK
ey(resourceId) ;
} catch(...) {
// Handle exceptions
}
}
DesignPatterns 89

// private method to get Project


entity
private Project
getProjectEntity( String
projectId)
throws ProjectException {
// similar to
getResourceEntity
...
}

// Method to encapsulate
workflow related
// to assigning a resource to a
project.
// It deals with Project and
Resource Entity beans
public void assignResourceToPro
ject(int numHours)
throws PSAException {

try {
if ((projectEntity == null)
||
(resourceEntity ==
null)) {
DesignPatterns 90

// SessionFacade not
connected to entities
throw new
PSAException( ...);
}

// Get Resource data


ResourceTO resourceTO =
resourceEntity.
getResourceData( );

// Get Project data


ProjectTO projectTO =
projectEntity.
getProjectData( );
// first add Resource to
Project
projectEntity.
addResource( resourceTO) ;
// Create a new Commitment
for the Project
CommitmentTO commitment =
new
CommitmentTO( ...);

// add the commitment to the


Resource
DesignPatterns 91

projectEntity.
addCommitment( commitment) ;

} catch(...) {
// Handle exceptions
}
}

// Similarly implement other


business methods to
// facilitate various use
cases/interactions
public void unassignResourceFro
mProject( )
throws PSAException {
...
}

// Methods working with


ResourceEntity
public ResourceTO
getResourceData( )
throws ResourceException {
...
}

// Update Resource Entity Bean


DesignPatterns 92

public void
setResourceData( ResourceTO
resource)
throws ResourceException {
...
}

// Create new Resource Entity


bean
public ResourceTO
createNewResource( ResourceTO
resource) throws
ResourceException {
...
}

// Methods for managing


resource's blockout time
public void
addBlockoutTime( Collection
blockoutTime)
throws RemoteException,
BlockoutTimeExce ption {
...
}

public void updateBlockoutTime(


DesignPatterns 93

Collection blockoutTime)
throws RemoteException,
BlockoutTimeExcepti on {
...
}

public Collection
getResourceCommitme nts()
throws RemoteException,
ResourceException {
...
}

// Methods working with


ProjectEntity
public ProjectTO getProjectData(
)
throws ProjectException {
...
}

// Update Project Entity Bean


public void
setProjectData( ProjectTO project)
throws ProjectException {
...
}
DesignPatterns 94

// Create new Project Entity


bean
public ProjectTO
createNewProject( ProjectTO
project)
throws ProjectException {
...
}

...

// Other session facade method


examples

// This proxies a call to a


Transfer Object Assembler
// to obtain a composite
Transfer Object.
// See Transfer Object Assembler
pattern
public ProjectCTO
getProjectDetailsDa ta()
throws PSAException {
try {
ProjectTOAHome
projectTOAHome = (ProjectTOAHome)
DesignPatterns 95

ServiceLocator.
getInstance( ).getHome(
"ProjectTOA" ,
ProjectTOAHome. class);
// Transfer Object Assembler
session bean
ProjectTOA projectTOA =
projectTOAHome.
create(.. .);
return
projectTOA.getData( ...);
} catch (...) {
// Handle / throw
exceptions
}
}

// These method proxies a call


to a ValueListHandler
// to get a list of projects.
See Value List Handler
// pattern.
public Collection
getProjectsList( Date start,
Date end) throws PSAException {
try {
ProjectListHandlerH ome
DesignPatterns 96

projectVLHHome =
(ProjectVLHHome)
ServiceLocator.
getInstance( ).getHome(
"ProjectListHandler ",
ProjectVLHHome.
class);
// Value List Handler
session bean
ProjectListHandler
projectListHandler =
projectVLHHome. create();
return projectListHandler.
getProjects(
start, end);
} catch (...) {
// Handle / throw
exceptions
}
}

...

public void ejbActivate( ) {


...
}
DesignPatterns 97

public void ejbPassivate( ) {


context = null;
}

public void
setSessionContext( SessionContext
ctx) {
this.context = ctx;
}

public void ejbRemove() {


...
}
}

The remote interface for the Session


Facade is listed in Example 8.16.
Example 8.16 Implementing Session
Facade - Remote Interface

package corepatterns. apps.psa.


ejb;

import java.rmi.RemoteExce ption;


import javax.ejb.*;
import corepatterns. apps.psa.
DesignPatterns 98

core.*;

// Note: all try/catch details not


shown for brevity.

public interface
ProjectResourceMana ger
extends EJBObject {

public resetEntities( String


resourceId,
String projectId, ...)
throws RemoteException,
ResourceException ;

public void assignResourceToPro


ject(int numHours)
throws RemoteException,
ResourceException ;

public void unassignResourceFro


mProject( )
throws RemoteException,
ResourceException ;

...
DesignPatterns 99

public ResourceTO
getResourceData( )
throws RemoteException,
ResourceException ;

public void
setResourceData( ResourceTO
resource)
throws RemoteException,
ResourceException ;

public ResourceTO
createNewResource( ResourceTO
resource)
throws ResourceException ;

public void
addBlockoutTime( Collection
blockoutTime)
throws RemoteException,
BlockoutTimeExce ption ;

public void
updateBlockoutTime( Collection
blockoutTime)
throws RemoteException,
BlockoutTimeExce ption ;
DesignPatterns 100

public Collection
getResourceCommitme nts()
throws RemoteException,
ResourceException;

public ProjectTO getProjectData(


)
throws RemoteException,
ProjectException ;

public void
setProjectData( ProjectTO project)
throws RemoteException,
ProjectException ;

public ProjectTO
createNewProject( ProjectTO
project)
throws RemoteException,
ProjectException ;

...

public ProjectCTO
getProjectDetailsDa ta()
throws RemoteException,
DesignPatterns 101

PSAException ;

public Collection
getProjectsList( Date start,
Date end) throws
RemoteException, PSAException ;

...
}

The Home interface for the Session


Facade is shown in Example 8.17.
Example 8.17 Implementing Session
Facade - Home Interface
package corepatterns. apps.psa.
ejb;

import javax.ejb.EJBHome;
import java.rmi.RemoteExce ption;
import corepatterns. apps.psa.
core.ResourceExc eption;
import javax.ejb.*;

public interface
ProjectResourceMana gerHome
extends EJBHome {
DesignPatterns 102

public ProjectResourceMana ger


create()
throws
RemoteException, CreateException;
public ProjectResourceMana ger
create(String
resourceId, String
projectId, ...)
throws
RemoteException, CreateException;
}

9. Service Locator
Enterprise applications require a way to
look up the service objects that provide
access to distributed components.
JavaTM 2 Platform, Enterprise Edition
(J2EE) applications use Java Naming
and Directory Interface (JNDI) to look
up enterprise bean home interfaces,
Java Message Service (JMS)
components, data sources, connections,
and connection factories. Repetitious
lookup code makes code difficult to read
DesignPatterns 103

and maintain. Furthermore,


unnecessary JNDI initial context
creation and service object lookups can
can cause performance problems.
The Service Locator pattern
centralizes distributed service object
lookups, provides a centralized point of
control, and may act as a cache that
eliminates redundant lookups. It also
encapsulates any vendor-specific
features of the lookup process.
J2EE uses the JNDI tree to lookup,
access and invoke business services
on passing a unique registered JNDI
name. If the service is used by various
clients, then the code for looking up
the object gets duplicated in various
forms which makes it difficult to
maintain the application. This pattern
is used to address this issue by storing
the lookup values for all services in a
single place and provide it on request.
Among other things, J2EE application
servers provide a collection of services,
DesignPatterns 104

such as JMS Servers and JDBC


Connection Pools. They provide access
to these services through a Java Naming
and Directory Interface (JNDI) -- a
central repository to register services,
beans, and environment variables.
The key to accessing services and
loading beans is obtaining a reference to
the JNDI server. The only difficulty is
that locating the JNDI server involves
connecting to a specific port and URL
that are application server dependent.
Thus, all classes that need to locate
objects must be aware of the connection
information required to find the JNDI
server.
Sun defines the Service Locator Pattern
saying that it "centralizes distributed
service object lookups, provides a
centralized point of control, and may act
as a cache that eliminates redundant
lookups." And they further iterate that it
"encapsulates any vendor-specific
features of the lookup process."
DesignPatterns 105

Because I spend most of my days


concerned with the performance of J2EE
applications and application servers,
JNDI lookups are particularly important
to me. The core process in tuning Web-
based applications is to look at what
occurs during every request
JNDI lookups are expensive and thus
should only be made when necessary.
Some would argue that whenever your
code needs to access a service or
component that it is necessary to go
directly to the JNDI server, but unless
you know that the JNDI server entries
can change often, it is far better to look
up references once and then cache
them.
Client
This is the client of the Service Locator.
The client is an object that typically
requires
access to business objects such as a
Business Delegate (see “Business
Delegate” )
DesignPatterns 106

Service Locator
The Service Locator abstracts the API
lookup (naming) services, vendor
dependencies, lookup complexities, and
business object creation, and provides a
simple interface to clients. This reduces
the client's complexity. In addition, the
same client or other clients can reuse
the Service Locator.

InitialContext
The InitialContext object is the start
point in the lookup and creation
process.
Service providers provide the context
object, which varies depending on the
type of
business object provided by the Service
Locator's lookup and creation service. A
Service Locator that provides services
for multiple types of business objects
(such
as enterprise beans, JMS components,
and so forth) utilizes multiple types of
DesignPatterns 107

context objects, each obtained from a


different provider (e.g., context provider
for
an EJB application server may be
different from the context provider for
JMS
service).

ServiceFactory

The ServiceFactory object represents an


object that provides life cycle
management
for the BusinessService objects. The
ServiceFactory object for enterprise
beans is
an EJBHome object. The ServiceFactory
for JMS components can be a JMS
ConnectionFactory object, such as a
TopicConnectionFact ory (for
publish/subscribe
messaging model) or a
QueueConnectionFact ory (for point-to-
point messaging
model).
DesignPatterns 108

BusinessService

The BusinessService is a role that is


fulfilled by the service the client is
seeking to
access. The BusinessService object is
created or looked up or removed by the
ServiceFactory. The BusinessService
object in the context of an EJB
application is an
enterprise bean. The BusinessService
object in the context of a JMS
application can
be a TopicConnection or a
QueueConnection. The TopicConnection
and
QueueConnection can then be used to
produce a JMSSession object, such as
TopicSession or a QueueSession
respectively.

Pattern Details
DesignPatterns 109

The ServiceLocator is a singleton class


(meaning that there is only one defined
per virtual machine) that on loading
establishes a connection to the JNDI
server and creates a cache that will
maintain a mapping between requested
resource/component names at the
associated resource/component. Listing
1 shows an excerpt from the Petstore
code for the ServiceLocator. java
file.
Listing 1. ServiceLocator. java Excerpt
public class ServiceLocator {

private InitialContext ic;


private Map cache;

private static ServiceLocator me;

static {
try {
me = new ServiceLocator( );
} catch(ServiceLocato
rException se) {
DesignPatterns 110

System.err.println( se);

se.printStackTrace( System.err) ;
}
}
private ServiceLocator( ) throws
ServiceLocatorExcep tion {
try {
ic = new InitialContext( );
cache = Collections.
synchronizedMap( new HashMap());
} catch (NamingException ne) {
throw new
ServiceLocatorExcep tion(ne);
}
}

static public ServiceLocator


getInstance( ) {
return me;
}
...
}
The static block of code is executed as
the ServiceLocator is loaded and it
creates a new instance of itself using a
DesignPatterns 111

private constructor. This constructor


establishes a connection to the JNDI
server by creating an instance of the
InitialContext class (if there were
application specific properties they could
be set here). It saves the
InitialContext to a static variable
and then creates a new HashMap that
will act as the cache.
Classes that want to use the
ServiceLocator gain access to it by
calling its getInstance( ) method.
Other methods that the
ServiceLocator provides are:
• getRemoteHome( )
• getLocalHome( )
• getQueueConnectionF actory()
• getQueue()
• getTopicConnectionF actory()
• getTopic()
• getDataSource( )
• getUrl()
• getBoolean()
DesignPatterns 112

• getString()
The getRemoteHome( ) and
getLocalHome( ) are used to obtain an
EJBHome object for the specific object
either remotely or locally (in the same
JVM), respectively. The next four
methods are used for accessing JMS
resources and the getDataSource( )
method returns a JDBC Data Source.
The final three methods load
environment entries that are defined in
your deployment descriptors; this is a
mechanism that you can use to
customize the behavior of your J2EE
application at runtime.
Listing 2 shows the implementation of
the getRemoteHome( ) method.
Listing 2. ServiceLocator getRemoteHome( )
method implementation

public EJBHome
getRemoteHome( String
jndiHomeName, Class className)
DesignPatterns 113

throws ServiceLocatorExcep tion


{
EJBHome home = null;
try {
if
(cache.containsKey( jndiHomeName)
) {
home = (EJBHome)
cache.get(jndiHomeN ame);
} else {
Object objref =
ic.lookup(jndiHomeN ame);

Object obj = PortableRemoteObjec


t.narrow( objref, className);
home = (EJBHome)obj;
cache.put(jndiHomeN ame,
home);
}
} catch (NamingException ne) {
throw new
ServiceLocatorExcep tion(ne);
} catch (Exception e) {
throw new
ServiceLocatorExcep tion(e);
}
DesignPatterns 114

return home;
}
From listing 2 you can see the code first
checks to see if the requested EJBHome
has already been loaded into the cache;
if not it loads it through its cached
InitialContext instance and stores it
in the cache. The remaining methods
are similarly implemented, and I
encourage you to look through the Pet
Store source code for more details.
Summary
The Service Locator Pattern is used to
abstract application server details from
JNDI lookups, centralize all access to
JNDI resources, and improve
performance by caching resources and a
reference to the JNDI server itself. The
Java PetStore application makes use of
this pattern and should be referenced
for more implementation details.
DesignPatterns 115

.
__,_._,___

You might also like