Você está na página 1de 31

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 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
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.
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
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 {
DesignPatterns 3

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[]) {
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?
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 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
}
DesignPatterns 4

public String getLast() {


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


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) {
//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)
return new LastFirst(entry) ; //return one class
else
return new FirstFirst(entry) ; //or the other
}}
DesignPatterns 5

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.

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( ));
}

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.

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.
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;
DesignPatterns 6

/**
* This method returns the singleton instance of this class.
* @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-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.
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 get Ins tance ( )


{
if (instance == null)
{
synchronized(PerdiemDAO. c l ass )
{
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
DesignPatterns 7

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 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. 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 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.,
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:

• 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.
DesignPatterns 8

• 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 );
}
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 {

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;
}
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( );
DesignPatterns 9

while( i.hasNext() ) {
Observer o = ( Observer ) i.next();
o.update( this );
}
}
}
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 o ) {


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

import java.util.Iterator;

public class IntegerPrinter implements Observer {

private IntegerDataBag bag;

public IntegerPrinter( IntegerDataBag bag ) {


this.bag = bag;
bag.addObserver( this );
}

public void update( Subject o ) {


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

}
DesignPatterns 10

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 );

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 );
}
}
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 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,
DesignPatterns 11

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 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 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 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
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 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.
DesignPatterns 12

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 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 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() 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
* 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 {


DesignPatterns 13

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";

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) {
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

// ************ ********* ********* ********* ********* ********* *********


******
/**
* 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();

// ============ ========= ========= ========= ========= =========


========= =
public ExampleServlet( ) {
//-- Initialize HashMap of possible ActionType concrete objects
commandMap.put( "create", new ActionTypeCreate( ));
commandMap.put( "replace" , new ActionTypeReplace( ));
commandMap.put( "update", new ActionTypeUpdate( ));
DesignPatterns 14

commandMap.put( "delete", new ActionTypeDelete( ));


} //endmain

// ============ ========= ========= ========= ========= =========


========= =
public void doPost(int approachSolution, String action) {
switch (approachSolution) {
case 1:
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

} //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... ");
} 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) {
//-- 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
cmd.execute( );
DesignPatterns 15

} //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 {
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,
"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() {
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
DesignPatterns 16

Switchs with the appropriate command. Obviously, the Switch connected to the Light will
have a different command 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");
}
}
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
UpCommand . execute ( ) ;

}
void flipDown( ) {
DownCommand . 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;
}
public void execute( ) {
myLight . turnOff( );
}
}
class FanOnCommand implements Command {
private Fan myFan;
DesignPatterns 17

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( ) {
myFan . stopRotate( );
}
}
public class TestCommand {
public static void main(String[ ] args) {
Light testLight = new Light( );
LightOnCommand testLOC = new LightOnCommand( testLight)
;
LightOffCommand testLFC = new LightOffCommand(
testLight) ;
Switch testSwitch = new Switch( testLOC,testLFC) ;

testSwitch.flipUp( );
testSwitch.flipDown ( );
Fan testFan = new Fan( );
FanOnCommand foc = new FanOnCommand( testFan);
FanOffCommand ffc = new FanOffCommand( testFan);
Switch ts = new Switch( foc,ffc);
ts.flipUp( );
ts.flipDown( );
}
}
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.

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."
DesignPatterns 18

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 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 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;
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;

public SampleModel( long id, String name, String data ) {


this.id = id;
this.name = name;
this.data = data;
DesignPatterns 19

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;
}
}

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
• 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 =
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 ) {
DesignPatterns 20

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 =
?
}

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 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


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 {
DesignPatterns 21

InitialContext ic = new InitialContext( );


String className = ( String )ic.lookup( "SAMPLEDAO.Impl" );
dao = ( SampleDAO )Class.forName( className ).newInstance( );
}
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() 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>
<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>
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
DesignPatterns 22

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.
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 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 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).

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
DesignPatterns 23

method 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 "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;

// 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 {

try {
// locate and connect to entity beans
connectToEntities( resourceId, projectId, ...);
} catch(...) {
// Handle exceptions
}
}
DesignPatterns 24

// 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 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


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
}
}

// 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 25

// 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


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


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(


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

public Collection getResourceCommitme nts()


DesignPatterns 26

throws RemoteException, ResourceException {


...
}

// Methods working with ProjectEntity


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

// Update Project Entity Bean


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

// 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)
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 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
}
DesignPatterns 27

...

public void ejbActivate( ) {


...
}

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. 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 ;

...

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 28

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, 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 {

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 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.
DesignPatterns 29

Among other things, J2EE application servers provide a collection of services, 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."
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” )

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
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).

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.
DesignPatterns 30

Pattern Details

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) {
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 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()
• 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
DesignPatterns 31

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)


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);
}

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.

.
__,_._,___

Você também pode gostar