97
Software Architecture Design Architectural Patterns Matthew Dailey Computer Science and Information Management Asian Institute of Technology Matthew Dailey (CSIM-AIT) Patterns 1 / 193 Readings Readings for these lecture notes: - Fowler (2002), Patterns of Enterprise Application Architecture, Addison-Wesley, Ch. 1–3, 9–11. Some material c Fowler (2002). Matthew Dailey (CSIM-AIT) Patterns 2 / 193

Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

  • Upload
    ngonhi

  • View
    217

  • Download
    4

Embed Size (px)

Citation preview

Page 1: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Software Architecture DesignArchitectural Patterns

Matthew Dailey

Computer Science and Information ManagementAsian Institute of Technology

Matthew Dailey (CSIM-AIT) Patterns 1 / 193

Readings

Readings for these lecture notes:

- Fowler (2002), Patterns of Enterprise Application Architecture,Addison-Wesley, Ch. 1–3, 9–11.

Some material c© Fowler (2002).

Matthew Dailey (CSIM-AIT) Patterns 2 / 193

Page 2: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Outline

1 Introduction

2 Domain logic patterns

3 Mapping to relational databases

4 Web presentation

5 Concurrency

6 Session state

7 Distribution strategies

Matthew Dailey (CSIM-AIT) Patterns 3 / 193

Introduction

Fowler (2002) opens with a quote from Christopher Alexander:

Each pattern describes a problem which occurs over and overagain in our environment, then describes the core of the solutionto that problem, in such a way that you can use this solution amillion times over, without ever doing it the same way twice.

Alexander was actually a (building) architect, but the same idea is relevantin software system architecture. Patterns represent best practices we canapply to ensure we don’t make the same mistakes the pioneers did.

Matthew Dailey (CSIM-AIT) Patterns 4 / 193

Page 3: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Introduction

In software architecture as in building architecture, patterns are referencesforming a common vocabulary for design.

Patterns are not recipes! You can never blindly apply them, since they arealways incomplete to some degree.

Matthew Dailey (CSIM-AIT) Patterns 5 / 193

Introduction

We begin with Fowler’s (2002) patterns, which share a common structure:

Each pattern has a carefully chosen name.

Each pattern has an intent summing up the pattern in a sentence ortwo.

Each pattern has a sketch representing it visually, in UML orotherwise.

Each pattern has a motivating problem as an example of what kind ofproblems this pattern solves.

Each pattern has a detailed how it works section including adiscussion of implementation issues and variations on the theme.

Each pattern has a when to use it section describing when it shouldbe used. There will often be multiple patterns applicable in aparticular situation.

There may be further reading for more information.

Example code gives the idea of how to apply the pattern in Java orC#. The code is not to be plugged in but adapted to the situation.

Matthew Dailey (CSIM-AIT) Patterns 6 / 193

Page 4: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Outline

1 Introduction

2 Domain logic patterns

3 Mapping to relational databases

4 Web presentation

5 Concurrency

6 Session state

7 Distribution strategies

Matthew Dailey (CSIM-AIT) Patterns 7 / 193

Domain logic patterns

Within the domain logic or business logic layer, how can we organize thelogic?

There are three main patterns:

Transaction Scripts

Domain Model

Table Module

We might also add a Service Layer on top of the domain model.

We consider the basic idea of each pattern, then the details.

Matthew Dailey (CSIM-AIT) Patterns 8 / 193

Page 5: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Domain logic patternsTransaction Scripts

Transaction Script organizes business logic by procedures where eachprocedure handles a single request from the presentation.

Transaction Scripts are the simplest way to organize domain logic. ATransaction Script:

Takes input data from the presentation layer;

Processes the data with validations and calculations;

Updates the database;

Invokes operations from other systems;

Replies to the presentation layer with data to display.

We write a single procedure for each use case or transaction.

Matthew Dailey (CSIM-AIT) Patterns 9 / 193

Domain logic patternsRationale for Transaction Scripts

Most business applications are just a series of database transactions.

Each transaction contains a bit of business logic, usually simple, such asselecting what information to display, validating input, doing calculations,and so on.

With Transaction Scripts, common functionality can be broken intosubroutines, but each transaction gets its own function or method.

Matthew Dailey (CSIM-AIT) Patterns 10 / 193

Page 6: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Domain logic patternsStructuring Transaction Scripts

Scripts should be in classes separate from the presentation and datasource, either one class per script or multiple scripts grouped functionallyinto classes.

Example of one class per script with GoF Command pattern (Fowler 2002, Fig. 9.1).

Use transaction scripts for simple problems that don’t need fancy objectmodels.

Matthew Dailey (CSIM-AIT) Patterns 11 / 193

Domain logic patternsTransaction Scripts

Advantages:

Simplicity, with an easy-to-understand procedural model

It works very well with simple data sources using a Row Data Gatewayor a Table Data Gateway (see the database mapping patterns)

The transaction boundaries are obvious (start a transaction at thebeginning and commit the transaction at the end of each procedure).

Disadvantages:

Duplication across multiple actions eventually creates a tangle ofroutines with no structure.

Matthew Dailey (CSIM-AIT) Patterns 12 / 193

Page 7: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Domain logic patternsExample application

Now we’ll look at a Transaction Script implementation in Java for a simpleexample application.

When can a business book revenue? The rules are complex and depend onregulations, corporate policy, and many other factors.

One way to handle this is to model the RevenueRecogntions for everyContract we sign.

Conceptual model for revenue recognitions on a contract (Fowler 2002, Fig. 9.2)

Matthew Dailey (CSIM-AIT) Patterns 13 / 193

Domain logic patternsTransaction Script example code

Suppose we use the data model:

CREATE TABLE products (ID int primary key, name varchar, type varchar)

CREATE TABLE contracts (ID int primary key, product int,

revenue decimal, dateSigned date)

CREATE TABLE revenueRecognitions (contract int, amount decimal,

recognizedOn date,

PRIMARY KEY (contract, recognizedOn))

Matthew Dailey (CSIM-AIT) Patterns 14 / 193

Page 8: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Domain logic patternsTransaction Script example code

Here’s how we might map to the data source using the Table DataGateway pattern to wrap SQL queries (more on data source mappinglater):

class Gateway...

public ResultSet findRecognitionsFor(long contractID, MfDate asof)

throws SQLException {

PreparedStatement stmt = db.prepareStatement(findRecognitionsStatement);

stmt.setLong(1, contractID);

stmt.setDate(2, asof.toSqlDate());

ResultSet result = stmt.executeQuery();

return result;

}

private static final String findRecognitionsStatement =

"SELECT amount " +

"FROM revenueRecognitions " +

"WHERE contract = ? AND recognizedOn <= ?";

private Connection db;

This uses MfDate (Martin Fowler date!) and JDBC prepared statements.

Matthew Dailey (CSIM-AIT) Patterns 15 / 193

Domain logic patternsTransaction Script example code

Transaction Script to get the sum of recognitions up to some date for acontract:

class RecognitionService...

public Money recognizedRevenue(long contractNumber, MfDate asOf) {

Money result = Money.dollars(0);

try {

ResultSet rs = db.findRecognitionsFor(contractNumber, asOf);

while (rs.next()) {

result = result.add(Money.dollars(rs.getBigDecimal("amount")));

}

return result;

}catch (SQLException e) {throw new ApplicationException (e);

}

}

Matthew Dailey (CSIM-AIT) Patterns 16 / 193

Page 9: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Domain logic patternsTransaction Script example code

Some notes of interest in the previous TS:

db is the database gateway object.

Money is a PEAA Base Pattern.

We see iteration over a JDBC ResultSet and getBigDecimal() beingused to extract the SQL decimal field as an arbitrary-precisiondecimal number.

This script could be implemented with an SQL aggregate procedure— the point is to understand how it could be done in a TS.

Matthew Dailey (CSIM-AIT) Patterns 17 / 193

Domain logic patternsTransaction Script example code

Next, calcuateRevenueRecognitions is a TS that adds the appropriaterevenue recognitions to the database based on the product type.

class RecognitionService...

public void calculateRevenueRecognitions(long contractNumber) {

try {

ResultSet contracts = db.findContract(contractNumber);

contracts.next();

Money totalRevenue = Money.dollars(contracts.getBigDecimal("revenue"));

MfDate recognitionDate = new MfDate(contracts.getDate("dateSigned"));

String type = contracts.getString("type");

if (type.equals("S")){

Money[] allocation = totalRevenue.allocate(3);

db.insertRecognition

(contractNumber, allocation[0], recognitionDate);

db.insertRecognition

(contractNumber, allocation[1], recognitionDate.addDays(60));

db.insertRecognition

(contractNumber, allocation[2], recognitionDate.addDays(90));

Matthew Dailey (CSIM-AIT) Patterns 18 / 193

Page 10: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Domain logic patternsTransaction Script example code

}else if (type.equals("W")){

db.insertRecognition(contractNumber, totalRevenue, recognitionDate);

}else if (type.equals("D")) {

Money[] allocation = totalRevenue.allocate(3);

db.insertRecognition

(contractNumber, allocation[0], recognitionDate);

db.insertRecognition

(contractNumber, allocation[1], recognitionDate.addDays(30));

db.insertRecognition

(contractNumber, allocation[2], recognitionDate.addDays(60));

}

}catch (SQLException e) {throw new ApplicationException (e);

}

Some notes of interest:

allocate() is a Money method that doesn’t lose pennies.

The TS needs to know about all the possible types of products (Wordprocessors, Spreadsheets, and Databases).

Matthew Dailey (CSIM-AIT) Patterns 19 / 193

Domain logic patternsTransaction Script example code

The gateway needs appropriate finders and inserters:

class Gateway...

public ResultSet findContract (long contractID) throws SQLException{

PreparedStatement stmt = db.prepareStatement(findContractStatement);

stmt.setLong(1, contractID);

ResultSet result = stmt.executeQuery();

return result;

}

private static final String findContractStatement =

"SELECT * FROM contracts c, products p " +

"WHERE ID = ? AND c.product = p.ID";

public void insertRecognition (long contractID, Money amount, MfDate asof)

throws SQLException {

PreparedStatement stmt = db.prepareStatement(insertRecognitionStatement);

stmt.setLong(1, contractID);

stmt.setBigDecimal(2, amount.amount());

stmt.setDate(3, asof.toSqlDate());

stmt.executeUpdate();

}

private static final String insertRecognitionStatement =

"INSERT INTO revenueRecognitions VALUES (?, ?, ?)";

The RecognitionService class could be normal Java class or a session bean(one instance-one client). Obviously this gets unmaintainable as thecomplexity of the business logic increases.

Matthew Dailey (CSIM-AIT) Patterns 20 / 193

Page 11: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Domain logic patternsTransaction Script interaction

Fowler (2002), Fig. 2.1

Matthew Dailey (CSIM-AIT) Patterns 21 / 193

Domain logic patternsDomain model

A Domain Model is an object model of the domain that incorporates bothbehavior and data.

We use OOAD to build a model of the domain, organized around thenouns in the domain.

Domain objects normally encapsulate both data and behavior, and come intwo main kinds:

Objects mimicking the data the business deals with

Objects encapsulating the rules running the business.

Matthew Dailey (CSIM-AIT) Patterns 22 / 193

Page 12: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Domain logic patternsDomain model

There tend to be two kinds of domain model:

Simple models look like the database design, with one domain objectfor each database table, and can use the straightforward ActiveRecord database mapping pattern.

More complex models are better for complex logic but are harder tomap, requiring the Data Mapper pattern.

Notes of interest for more complex domain models:

Break up the logic and put it in the classes it naturally belongs to.

In J2EE, Fowler recommends POJOs (Plain Old Java Objects) for thedomain model, not entity beans as recommended by EJB folks. Thisdecouples the domain model from the implementation environment.

Read GoF for useful patterns for organizing the domain classes.

Use a Data Mapper for the data source mapping and (maybe)implement a Service Layer interface to the presentation layer.

Matthew Dailey (CSIM-AIT) Patterns 23 / 193

Domain logic patternsDomain model

Advantages:

The logic is organized, with each type of object handling its ownvalidation, calculations, and so on.

Domain models can scale well as the data source gets more complex.

Disadvantages:

It can be difficult to trace the behavior for one action

Transaction boundaries might be more difficult to determine. Youwouldn’t want one domain object starting a transaction and anothercommitting it.

According to Fowler, it takes developers a long time to get used tothe approach.

Matthew Dailey (CSIM-AIT) Patterns 24 / 193

Page 13: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Domain logic patternsDomain Model example code

We use the same revenue recognition system even though the logic is notreally complex enough to merit a Domain Model.

Domain Model for revenue recognition using GoF Strategy pattern (Fowler, 2002, Fig. 9.3)

Matthew Dailey (CSIM-AIT) Patterns 25 / 193

Domain logic patternsDomain Model example code

class RevenueRecognition...

private Money amount;

private MfDate date;

public RevenueRecognition(Money amount, MfDate date) {

this.amount = amount;

this.date = date;

}

public Money getAmount() {

return amount;

}

boolean isRecognizableBy(MfDate asOf) {

return asOf.after(date) || asOf.equals(date);

}

Matthew Dailey (CSIM-AIT) Patterns 26 / 193

Page 14: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Domain logic patternsDomain Model example code

Now, calculating the revenue recognized on a particular date involvesContract and RevenueRecognition, by iterating over the currentrevenueRecognitions.

class Contract...

private List revenueRecognitions = new ArrayList();

public Money recognizedRevenue(MfDate asOf) {

Money result = Money.dollars(0);

Iterator it = revenueRecognitions.iterator();

while (it.hasNext()) {

RevenueRecognition r = (RevenueRecognition) it.next();

if (r.isRecognizableBy(asOf))

result = result.add(r.getAmount());

}

return result;

}

The complexity is higher than the TS because multiple objects areinvolved. But associating behavior only with the objects that “need toknow” scales well and reduces coupling.

Matthew Dailey (CSIM-AIT) Patterns 27 / 193

Domain logic patternsDomain Model example code

class Contract...

private Product product;

private Money revenue;

private MfDate whenSigned;

private Long id;

public Contract(Product product, Money revenue, MfDate whenSigned) {

this.product = product;

this.revenue = revenue;

this.whenSigned = whenSigned;

}

Matthew Dailey (CSIM-AIT) Patterns 28 / 193

Page 15: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Domain logic patternsDomain Model example code

class Product...

private String name;

private RecognitionStrategy recognitionStrategy;

public Product(String name, RecognitionStrategy recognitionStrategy) {

this.name = name;

this.recognitionStrategy = recognitionStrategy;

}

public static Product newWordProcessor(String name) {

return new Product(name, new CompleteRecognitionStrategy());

}

public static Product newSpreadsheet(String name) {

return new Product(name, new ThreeWayRecognitionStrategy(60, 90));

}

public static Product newDatabase(String name) {

return new Product(name, new ThreeWayRecognitionStrategy(30, 60));

}

Matthew Dailey (CSIM-AIT) Patterns 29 / 193

Domain logic patternsDomain Model example code

class RecognitionStrategy...

abstract void calculateRevenueRecognitions(Contract contract);

class CompleteRecognitionStrategy...

void calculateRevenueRecognitions(Contract contract) {

contract.addRevenueRecognition(

new RevenueRecognition(contract.getRevenue(),

contract.getWhenSigned()));

}

Matthew Dailey (CSIM-AIT) Patterns 30 / 193

Page 16: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Domain logic patternsDomain Model example code

class ThreeWayRecognitionStrategy...

private int firstRecognitionOffset;

private int secondRecognitionOffset;

public ThreeWayRecognitionStrategy(int firstRecognitionOffset,

int secondRecognitionOffset) {

this.firstRecognitionOffset = firstRecognitionOffset;

this.secondRecognitionOffset = secondRecognitionOffset;

}

void calculateRevenueRecognitions(Contract contract) {

Money[] allocation = contract.getRevenue().allocate(3);

contract.addRevenueRecognition(

new RevenueRecognition(allocation[0], contract.getWhenSigned()));

contract.addRevenueRecognition(

new RevenueRecognition(allocation[1],

contract.getWhenSigned().addDays(firstRecognitionOffset)));

contract.addRevenueRecognition(

new RevenueRecognition(allocation[2],

contract.getWhenSigned().addDays(secondRecognitionOffset)));

}

Matthew Dailey (CSIM-AIT) Patterns 31 / 193

Domain logic patternsDomain Model example code

Here is some test code demonstrating use of the model:

class Tester...

private Product word = Product.newWordProcessor("Thinking Word");

private Product calc = Product.newSpreadsheet("Thinking Calc");

private Product db = Product.newDatabase("Thinking DB");

When we calculate recognitions on a contract, Contract doesn’t need toknow about the strategy subclasses.

class Contract...

public void calculateRecognitions() {

product.calculateRevenueRecognitions(this);

}

class Product...

void calculateRevenueRecognitions(Contract contract) {

recognitionStrategy.calculateRevenueRecognitions(contract);

}

Matthew Dailey (CSIM-AIT) Patterns 32 / 193

Page 17: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Domain Model example code

Some points about the example:

We see how a request gets forwarded from place to place until wereach an object qualified to handle it. This is typical for DomainModels (and in all OO systems).

The Strategy pattern is effective for refactoring procedural code fullof conditionals.

Matthew Dailey (CSIM-AIT) Patterns 33 / 193

Domain Model

Fowler (2002), Fig. 2.2

Matthew Dailey (CSIM-AIT) Patterns 34 / 193

Page 18: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Domain logic patternsTable Modules

A Table Module is a single instance that handles the business logic for allrows in a database table or view.

Table Modules are similar to domain classes in a domain model, but aremore closely tied to the database structure.

We have a one-to-one mapping between database tables and classes in thedomain logic layer, and clients only use one instance of the class for eachtable.

This simplifies the data source mapping at the cost of a less flexibleorganization of the domain logic.

Matthew Dailey (CSIM-AIT) Patterns 35 / 193

Domain logic patternsTable Modules

If we want to use data from a particular table as a client, we

Issue a query to the database;

Get the answer back as a Record Set;

Use the record set to instantiate a Table Module object;

Invoke operations on the Table Module object, passing an identifierwhen necessary to identify a particular row.

The Table Module might be a collection of static methods or an instance.Instances allow inheritance and initialization with a particular Record Set.

Matthew Dailey (CSIM-AIT) Patterns 36 / 193

Page 19: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Table Modules

Typical interaction with a Table Module (Fowler, 2002, Fig. 9.4)

Matthew Dailey (CSIM-AIT) Patterns 37 / 193

Domain logic patternsTable Modules

Layers of interaction with a Table Module (Fowler, 2002, Fig. 9.5)

Matthew Dailey (CSIM-AIT) Patterns 38 / 193

Page 20: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Domain logic patternsTable Modules

Advantages:

More structured than Transaction ScriptsEasier to understand the flow than with a Domain ModelLess complex data source mapping than a Domain ModelGUI environments often provide direct support for displaying RecordSets, so Table Modules in the domain logic layer provide simple,direct mappings between the presentation and data source layers,with room for additional manipulation and validation of the data as itflows through. .NET works this way.

Disadvantages:

For extremely simple applications, Transaction Scripts are easier toimplement.For complex applications, Table Modules are not as flexible as aDomain Model

For an implementation in the revenue recognition example, see text.Matthew Dailey (CSIM-AIT) Patterns 39 / 193

Domain logic patternsYour choice

The proper choice of domain logic organization depends on the complexityof the domain logic and the tool support available for a particularparadigm.

A mixture of the three patterns is often used in the same application.

Matthew Dailey (CSIM-AIT) Patterns 40 / 193

Page 21: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Domain logic patternsService layer

A Service Layer defines an application’s boundary with a layer of servicesthat establishes a set of available operations and coordinates theapplication’s response in each operation.

We provide an API decoupling presentation from the domain logic, makingit easy to support multiple interfaces.

Fowler, 2002, p. 133

Besides decoupling, the servicelayer can be a good place to dothings that cut across domainobjects in use cases:

Transaction control

Security

Matthew Dailey (CSIM-AIT) Patterns 41 / 193

Domain logic patternsRationale for a Service Layer

Enterprise applications often have different interfaces to the samefunctionality, for example:

A rich client GUI

An integration gateway for other applications

In these cases we might break business logic into two parts:

Domain logic, which is purely about the problem domain (e.g.revenue recognition strategies);

Application logic or workflow logic.

A Service Layer might factor some or all application logic into the servicelayer, making the domain logic layer more reusable across differentapplications.

Matthew Dailey (CSIM-AIT) Patterns 42 / 193

Page 22: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Domain logic patternsService layer

How much business logic to put in the service layer?

At one extreme, we have transaction scripts with a simple ActiveRecord domain model.

At the other extreme, the service layer is a facade.

More commonly, application logic is implemented by operation scriptsin the service layer and domain logic is implemented in the domainobjects.

Matthew Dailey (CSIM-AIT) Patterns 43 / 193

Domain logic patternsDesigning services

We must group the external operations into service layer classesthemselves called services, usually ending with the name Service.

Keep services coarse grained, minimizing the number of calls.

This will make it possible to allow remote access later.

To find services, start with the use case model and/or user interfacespecification. Usually there is a 1-to-1 correspondence between CRUD usecases and Service Layer operations.

For Java implementation, Fowler recommends EJB stateless session beansto implement application logic in operation scripts in the service layer,which then delegate to POJO domain objects for the domain logic.

Don’t use a service layer if you think your business logic will only have oneclient (the UI) forever, but if you might have more than one client, aservice layer is worthwhile.

Matthew Dailey (CSIM-AIT) Patterns 44 / 193

Page 23: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Domain logic patternsService Layer example code

First we do a POJO Service Layer.

To make it interesting, we add some application logic to the revenuerecogntion application. When revenue recognitions are calculated, we needto

Send an email to a contract administrator;

Publish a message to any other integrated applications.

Now RecognitionService extends a Layer Supertype for our service layerand use an EmailGateway and an IntegrationGateway.

Matthew Dailey (CSIM-AIT) Patterns 45 / 193

Domain logic patternsService Layer example code

POJO class diagram for a revenue recognition service (Fowler, 2002, Fig. 9.7)

Matthew Dailey (CSIM-AIT) Patterns 46 / 193

Page 24: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Domain logic patternsService Layer example code

Ignoring persistence, here is example code:

public class ApplicationService {

protected EmailGateway getEmailGateway() {

//return an instance of EmailGateway

}

protected IntegrationGateway getIntegrationGateway() {

//return an instance of IntegrationGateway

}

}

public interface EmailGateway {

void sendEmailMessage(String toAddress, String subject, String body);

}

public interface IntegrationGateway {

void publishRevenueRecognitionCalculation(Contract contract);

}

Matthew Dailey (CSIM-AIT) Patterns 47 / 193

Domain logic patternsService Layer example code

public class RecognitionService extends ApplicationService {

public void calculateRevenueRecognitions(long contractNumber) {

Contract contract = Contract.readForUpdate(contractNumber);

contract.calculateRecognitions();

getEmailGateway().sendEmailMessage(

contract.getAdministratorEmailAddress(),

"RE: Contract #" + contractNumber,

contract + " has had revenue recognitions calculated.");

getIntegrationGateway().publishRevenueRecognitionCalculation(contract);

}

public Money recognizedRevenue(long contractNumber, Date asOf) {

return Contract.read(contractNumber).recognizedRevenue(asOf);

}

}

We’re assuming that the contract class has methods to read contractsfrom the data source layer by ID.

Matthew Dailey (CSIM-AIT) Patterns 48 / 193

Page 25: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Domain logic patternsService Layer example code

We’re also ignoring transactions for now — in fact, thecalculateRevenueRecognitions() operation needs to be atomic.

EJB has built-in support for container-managed transactions. If statelesssession beans are used, the transactional methods could be declared as so,with little change to the existing methods.

Matthew Dailey (CSIM-AIT) Patterns 49 / 193

Domain logic patternsConclusion

So we’ve seen the major architectural design choices for the business logiclayer.

Thus far we’ve mostly ignored persistence mechanisms for the domainobjects.

That’s the next topic.

Matthew Dailey (CSIM-AIT) Patterns 50 / 193

Page 26: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Outline

1 Introduction

2 Domain logic patterns

3 Mapping to relational databases

4 Web presentation

5 Concurrency

6 Session state

7 Distribution strategies

Matthew Dailey (CSIM-AIT) Patterns 51 / 193

Mapping to relational databases

The data source layer needs to communicate with various pieces ofinfrastructure, usually including a database.

Object database technology is getting more mature:

Open source frameworks like Zope, based on an object database, areincreasing in popularity and market share

They seem to save developer time compared to RDBMS mapping byup to 1/3

But most applications are still based on RDBMS technology.

SQL is (almost) standard and well-understood by most developers

RDBMSs have the backing of the big companies

Matthew Dailey (CSIM-AIT) Patterns 52 / 193

Page 27: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesBasic choices

First, you should separate the SQL from the domain logic, putting it inseparate classes.

Oftentimes we have one class per database table. The classes fromGateways to the tables. We have two Gateway patterns:

The Row Data Gateway has one instance for each row returned by aquery

The Table Data Gateway returns a Record Set (a generic datastructure provided by the development environment)

Matthew Dailey (CSIM-AIT) Patterns 53 / 193

Mapping to relational databasesRow Data Gateway

Fowler (2002), Fig. 3.1

Matthew Dailey (CSIM-AIT) Patterns 54 / 193

Page 28: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesTable Data Gateway

Fowler (2002), Fig. 3.2

Matthew Dailey (CSIM-AIT) Patterns 55 / 193

Mapping to relational databasesWhen to use gateways

The Table Data Gateway

Works best when you have a Table Module for the domain logic.

Works fine when we have a views or other arbitrary queries on thedatabase.

The Row Data Gateway

Works best with a simple Domain Model where domain classescorrespond well to the database structure.

Are not so good for large applications with complex domain models,where we want to decouple the domain class structure from thedatabase structure, and we may want inheritance (especially when weapply GoF and other domain logic patterns).

Matthew Dailey (CSIM-AIT) Patterns 56 / 193

Page 29: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesActive Record

For simple Domain Models where Row Data Gateways are appropriate, weoften combine the domain logic with the Row Data Gateways to obtainActive Records.

The Active Record pattern works well in MVC frameworks like Ruby onRails.

Fowler (2002), Fig. 3.3

Matthew Dailey (CSIM-AIT) Patterns 57 / 193

Mapping to relational databasesData mapper

For complex decoupled Domain Models we need a Data Mapper:

Fowler (2002), Fig. 3.4

Fowler recommends never using separate Gateways with Domain Models.He either uses Active Records or a Data Mapper.

Matthew Dailey (CSIM-AIT) Patterns 58 / 193

Page 30: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesBuilding a data mapper

To implement Data Mapper you can:

Roll your own!

Use a third party object-relational (O/R) mapping package.

For Java, consider Java Persistence API (JPA) implementations likeHibernate EntityManager.

Here we discuss how to roll your own, so you can understand the genericO/R mapping solutions.

Matthew Dailey (CSIM-AIT) Patterns 59 / 193

Mapping to relational databasesBehavior: Unit of Work

How do we get objects to load and save themselves to the database?

First, we add load() and save() methods to each object. But you must

Ensure that the database and object state are consistent

Ensure that updates in one process don’t affect reads in anotherprocess.

The pattern to solve the problems is Unit of Work.

A Unit of Work object:

Acts as a controller for a transaction

Keeps track of the objects that have been loaded and modified

Ensures that updated objects are properly committed to the database

Matthew Dailey (CSIM-AIT) Patterns 60 / 193

Page 31: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesBehavior: Unit of Work

Approach 1: client is responsible for registering each dirty entity:

Fowler (2002), Fig. 11.1

Matthew Dailey (CSIM-AIT) Patterns 61 / 193

Mapping to relational databasesBehavior: Unit of Work

Approach 2: entity is responsible for registering itself as dirty in eachupdate method:

Fowler (2002), Fig. 11.2

Matthew Dailey (CSIM-AIT) Patterns 62 / 193

Page 32: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesBehavior: Unit of Work

Approach 3: unit of work copies each object on load and compares atcommit time to determine dirty status

Fowler (2002), Fig. 11.3

Matthew Dailey (CSIM-AIT) Patterns 63 / 193

Mapping to relational databasesBehavior: Identity Map

What happens if you read the same object twice?

You will have two in-memory objects corresponding to one databaserow.

If you make updates the copies become inconsistent.

The Identity Map pattern solves this problem by:

Keeping a record of every row that’s currently in memory

Returning a reference rather than reading the object if it is already inmemory

An Identity Map is like a database cache but it is really for correctness,not performance.

Matthew Dailey (CSIM-AIT) Patterns 64 / 193

Page 33: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesBehavior: Lazy Load

When you load an object having links to to other objects, what to do? Ifwe read linked objects also, we might need too many unnecessary queries.

The Lazy Load pattern solves this problem:

When a read object has links, we point them to placeholder objects

We load the referenced object later, only when necessary.

Matthew Dailey (CSIM-AIT) Patterns 65 / 193

Mapping to relational databasesReading data

Read data in finder methods that wrap SQL select statements, e.g.,find(id) or findForCustomer(customer).

A Table Data Gateway approach lets you put finders in the sameclasses with the related insert and update methods.

For a Row Data Gateway or Data Mapper you could make the findersstatic methods, but that would couple your domain objects to thedatabase solution.

A better solution: completely separate pluggable finder objectsimplementing a “finder” interface that could be talking to anydatabase or a mock service.

Finder methods work on the database, not on objects in memory, soit’s best to do all the finding before you start any creations, updates,and deletes in memory.

Matthew Dailey (CSIM-AIT) Patterns 66 / 193

Page 34: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesReading data

Other tips about reading data:

Avoid issuing multiple SQL queries to get multiple rows from thesame table!

Large applications will eventually run into database performanceissues. Then the queries have to be examined, profiled, and tuned.

Matthew Dailey (CSIM-AIT) Patterns 67 / 193

Mapping to relational databasesStructural mapping patterns

If you’re using Row Data Gateway, Active Record, or Data Mapper, youneed to know the common methods for mapping between objects andtables.

The main problem is links:

Objects use a reference or memory address (pointer)

Relational databases use a key into another table

Objects use collections for many-valued fields but databases arenormalized to be single-valued

Example: an order object would have a collection of line items that don’trefer back to the order. The database would have a table of line items,each with a foreign key reference to the containing order.

Matthew Dailey (CSIM-AIT) Patterns 68 / 193

Page 35: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesStructural mapping patterns

To solve the backward reference problem:

We keep the relational identity of each object as an Identity Field

We look up the Identity Field values when needed to map back andforth between object references and relational keys.

For a read:

We use an Identity Map as a lookup table from relational keys toobjects

Then we use a Foreign Key Mapping to connect the inter-objectreference

Matthew Dailey (CSIM-AIT) Patterns 69 / 193

Mapping to relational databasesStructural mapping patterns: Foreign Key Reference

Simple example of using the Foreign Key Reference pattern for amany-to-one relationship:

Fowler (2002), Fig. 3.5

When you need an object and its key is not in the Identity Map, we do adatabase access or Lazy Load, and when an object is saved, we use itsIdentity Field to update the row with the right key.

Matthew Dailey (CSIM-AIT) Patterns 70 / 193

Page 36: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesStructural mapping patterns: Foreign Key Reference

For 1-to-many, there is a collection on the “1” side in the domain modeland the reference pattern is reversed in the data model:

Fowler (2002), Fig. 3.6

On a read we issue a query to find all rows linking to the ID of the sourceobject, then for each returned row we create an object and add it to thecollection (Lazy Load is also possible here).

Matthew Dailey (CSIM-AIT) Patterns 71 / 193

Mapping to relational databasesStructural mapping patterns: Association Table Mapping

For many-to-many relationships, we know we need a separate DB table forthe mapping:

Fowler (2002), Fig. 3.7

This is the Association Table Mapping pattern.

Matthew Dailey (CSIM-AIT) Patterns 72 / 193

Page 37: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesStructural mapping patterns: More tips

More O/R mapping tips:

OO languages normally use arrays or lists, but relations are unordered.So it’s best to use unordered collections (sets) in the domain layerwhenever possible.

Small objects like DateRange and Money don’t need to be stored intheir own tables. In the Value Objects pattern, when reading anobject containing a small object, we get the fields of the small objectdirectly from the row for the containing object, and store them in thecontaining object as an Embedded Value. When writing, we just getthe relevant fields from the Value Object and put them directly intothe table.

This approach can be taken further by storing complex objectnetworks as LOBs (Large Objects) if we don’t care about structuredqueries or in XML if we do.

Matthew Dailey (CSIM-AIT) Patterns 73 / 193

Mapping to relational databasesStructural mapping patterns: Inheritance

For inheritance, there are 3 options:

One table for all classes in the hierarchy (Single Table Inheritance)

One table per concrete class in the hierarchy (Concrete TableInheritance)

One table for each class (Class Table Inheritance).

Matthew Dailey (CSIM-AIT) Patterns 74 / 193

Page 38: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesStructural mapping patterns: Inheritance

Single Table Inheritance is convenient but wastes space and could createhuge tables:

Fowler (2002), Fig. 3.8

Matthew Dailey (CSIM-AIT) Patterns 75 / 193

Mapping to relational databasesStructural mapping patterns: Inheritance

Concrete Table Inheritance avoids waste of space but is brittle to change:

Fowler (2002), Fig. 3.9

Matthew Dailey (CSIM-AIT) Patterns 76 / 193

Page 39: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesStructural mapping patterns: Inheritance

Class Table Inheritance needs joins for a single object, but is a simplemapping:

Fowler (2002), Fig. 3.10

Matthew Dailey (CSIM-AIT) Patterns 77 / 193

Mapping to relational databasesStructural mapping patterns: Inheritance

The inheritance patterns can be mixed even within one hierarchy.

You might start with Single Table Inheritance but start to refactor whenperformance or wasted space becomes a problem.

There are variations for multiple inheritance or interfaces.

Matthew Dailey (CSIM-AIT) Patterns 78 / 193

Page 40: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesBuilding the mapping

When you begin building your O/R mapper, you’ll encounter one of threecases:

You get to choose the DB schema

You have to map to an existing schema and aren’t allowed to changethat schema

You have to map to an existing schema, but changes might bepossible

Matthew Dailey (CSIM-AIT) Patterns 79 / 193

Mapping to relational databasesBuilding the mapping

Some tips for case 1 (you choose the DB schema):

Avoid making your domain model look like the database — build itwithout worrying about the DB, so you can focus on keeping thedomain logic simple.

If it turns out that the domain model looks like a database design,then you can use Active Record.

Build the database gradually, with each iteration, no more than 6weeks in length, and preferably shorter.

Design the Domain Model pieces first, then worry about thedatabase, but do map to the database on every iteration.

Matthew Dailey (CSIM-AIT) Patterns 80 / 193

Page 41: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesUsing metadata

For large applications with a Data Mapper you’ll end up repeating a lot ofcode.

Eventually you might refactor with Metadata Mapping. In this pattern wedescribe the mapping between object fields and database columns.Example:

<field name="customer" targetClass="Customer" dbColumn="custID"

targetTable="customers" lowerBound="1" upperBound ="999999"

setter="loadCustomer" />

If you go far enough in using metadata to abstract the database, you havea Repository using Query Objects in which developers don’t know or carewhether their data is coming from the database or memory or both. Themetadata approach is what’s used by generic object-relational mappingsystems.

Matthew Dailey (CSIM-AIT) Patterns 81 / 193

Mapping to relational databasesDatabase connections

Some tips on dealing with database connections:

Use connection pooling. Try to explicitly close connections whenyou’re done with them, or they might sit around forever or stay openuntil the garbage collector collects them.The best way to manage a connection is inside a Unit of Work — getthe database connection when you start the transaction and release itwhen you commit or roll back.For quick things like read-only access to data outside a transaction,you can open a new connection for each command and close itimmediately.

Other points:

Don’t use select *Use column names not numeric indices to reference columns in aRecord SetUse precompiled SQL queries then supply parametersGet optimization help from the project’s database expert

Matthew Dailey (CSIM-AIT) Patterns 82 / 193

Page 42: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesMore on Active Record

Active Record is an object that wraps a row in a database table or view,encapsulates the database access, and adds domain logic on that data.

Typical methods:

Construct an instance of Active Record from a SQL result row set

Construct a new instance for later insertion into the table

Static finder methods to wrap commonly-used SQL queries and returnActive Record objects (separating finders into another class is goodfor testing, however)

Update the database and insert into it the data in the Active Record

Get and set the fields (these might transform SQL data types to morereasonable types)

Implement some pieces of the business logic

Matthew Dailey (CSIM-AIT) Patterns 83 / 193

Mapping to relational databasesMore on Active Record

Example Active Record code for a Person class:

class Person...

private String lastName;

private String firstName;

private int numberOfDependents;

An ID field goes in the superclass, and the database has the samestructure:

create table people (ID int primary key, lastname varchar,

firstname varchar, number_of_dependents int)

Loading an object requires finding it first (in our case with a staticmethod)...

Matthew Dailey (CSIM-AIT) Patterns 84 / 193

Page 43: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesMore on Active Record

class Person...

private final static String findStatementString =

"SELECT id, lastname, firstname, number_of_dependents" +

" FROM people" +

" WHERE id = ?";

public static Person find(Long id) {

Person result = (Person) Registry.getPerson(id);

if (result != null) return result;

PreparedStatement findStatement = null;

ResultSet rs = null;

try {

findStatement = DB.prepare(findStatementString);

findStatement.setLong(1, id.longValue());

rs = findStatement.executeQuery();

rs.next();

result = load(rs);

return result;

} catch (SQLException e) {

throw new ApplicationException(e);

} finally {

DB.cleanUp(findStatement, rs);

}

}Matthew Dailey (CSIM-AIT) Patterns 85 / 193

Mapping to relational databasesMore on Active Record

public static Person find(long id) {

return find(new Long(id));

}

public static Person load(ResultSet rs) throws SQLException {

Long id = new Long(rs.getLong(1));

Person result = (Person) Registry.getPerson(id);

if (result != null) return result;

String lastNameArg = rs.getString(2);

String firstNameArg = rs.getString(3);

int numDependentsArg = rs.getInt(4);

result = new Person(id, lastNameArg, firstNameArg, numDependentsArg);

Registry.addPerson(result);

return result;

}

Note that we use an Identity Map (the Registry class in the code) to makesure we don’t load the same object twice.

Matthew Dailey (CSIM-AIT) Patterns 86 / 193

Page 44: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesMore on Active Record

Updating an object is a simple instance method:

class Person...

private final static String updateStatementString =

"UPDATE people" +

" set lastname = ?, firstname = ?, number_of_dependents = ?" +

" where id = ?";

public void update() {

PreparedStatement updateStatement = null;

try {

updateStatement = DB.prepare(updateStatementString);

updateStatement.setString(1, lastName);

updateStatement.setString(2, firstName);

updateStatement.setInt(3, numberOfDependents);

updateStatement.setInt(4, getID().intValue());

updateStatement.execute();

} catch (Exception e) {

throw new ApplicationException(e);

} finally {

DB.cleanUp(updateStatement);

}

}Matthew Dailey (CSIM-AIT) Patterns 87 / 193

Mapping to relational databasesMore on Active Record

Insertion is also straightforward:

class Person...

private final static String insertStatementString =

"INSERT INTO people VALUES (?, ?, ?, ?)";

public Long insert() {

PreparedStatement insertStatement = null;

try {

insertStatement = DB.prepare(insertStatementString);

setID(findNextDatabaseId());

insertStatement.setInt(1, getID().intValue());

insertStatement.setString(2, lastName);

insertStatement.setString(3, firstName);

insertStatement.setInt(4, numberOfDependents);

insertStatement.execute();

Registry.addPerson(this);

return getID();

} catch (Exception e) {

throw new ApplicationException(e);

} finally {

DB.cleanUp(insertStatement);

}

}Matthew Dailey (CSIM-AIT) Patterns 88 / 193

Page 45: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesMore on Active Record

Finally the business logic goes right in the Active Record class:

class Person...

public Money getExemption() {

Money baseExemption = Money.dollars(1500);

Money dependentExemption = Money.dollars(750);

return baseExemption.add(dependentExemption.multiply(this.getNumberOfDependents()));

}

Matthew Dailey (CSIM-AIT) Patterns 89 / 193

Mapping to relational databasesMore on Data Mapper

A Data Mapper is a layer of Mappers that moves data between objectsand a database while keeping them independent of each other and themapper itself.

The Data Mapper pattern becomes necessary when you want persistentobjects that contain collections, use inheritance, and so on.

The Data Mapper is a layer completely separate from the domain objects;the domain objects don’t need to know about the database schema orSQL.

We consider a simple example in which the Data Mapper is not reallynecessary, just to get the idea.

Matthew Dailey (CSIM-AIT) Patterns 90 / 193

Page 46: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesMore on Data Mapper

A simple version of a load with Data Mapper using an Identity Map:

Fowler (2002), Fig. 10.3

Matthew Dailey (CSIM-AIT) Patterns 91 / 193

Mapping to relational databasesMore on Data Mapper

A simple version of an update with Data Mapper:

Fowler (2002), Fig. 10.4

Matthew Dailey (CSIM-AIT) Patterns 92 / 193

Page 47: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesMore on Data Mapper

In the load example, there was just one SQL query, but in reality a loadwill cause several interconnected objects to be loaded using more than onequery.

Simple example: loading an order. We would probably execute a secondquery to load the line items for an order after the order data is loaded.

Matthew Dailey (CSIM-AIT) Patterns 93 / 193

Mapping to relational databasesMore on Data Mapper

Another issue is the mapping of the domain fields. The mapper will be ina different class and different package from the domain object.

For save(), we need special public getters for all fields that return the rawattributes. These should only be called in the context of a databaseoperation.

Similarly, for load(), we need a rich constructor that sets all fields, orspecial public setters for all fields.

Matthew Dailey (CSIM-AIT) Patterns 94 / 193

Page 48: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesMore on Data Mapper

As a simple example in Java, we use Person again, noting that a DataMapper is not really necessary for such a simple case:

class Person...

private String lastName;

private String firstName;

private int numberOfDependents;

The database schema is the same as before:

create table people (ID int primary key, lastname varchar,

firstname varchar, number_of_dependents int)

Matthew Dailey (CSIM-AIT) Patterns 95 / 193

Mapping to relational databasesMore on Data Mapper

Person-specific code is placed in PersonMapper:

class PersonMapper...

protected String findStatement() {

return "SELECT " + COLUMNS +

" FROM people" +

" WHERE id = ?";

}

public static final String COLUMNS = " id, lastname, firstname, number_of_dependents ";

public Person find(Long id) {

return (Person) abstractFind(id);

}

public Person find(long id) {

return find(new Long(id));

}

Matthew Dailey (CSIM-AIT) Patterns 96 / 193

Page 49: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesMore on Data Mapper

Code common to all mappers goes in an abstract superclass:class AbstractMapper...

protected Map loadedMap = new HashMap();

abstract protected String findStatement();

protected DomainObject abstractFind(Long id) {

DomainObject result = (DomainObject) loadedMap.get(id);

if (result != null) return result;

PreparedStatement findStatement = null;

try {

findStatement = DB.prepare(findStatement());

findStatement.setLong(1, id.longValue());

ResultSet rs = findStatement.executeQuery();

rs.next();

result = load(rs);

return result;

} catch (SQLException e) {

throw new ApplicationException(e);

} finally {

DB.cleanUp(findStatement);

}

}

Matthew Dailey (CSIM-AIT) Patterns 97 / 193

Mapping to relational databasesMore on Data Mapper

Load behavior is split between the concrete mapper and the superclass:

class AbstractMapper...

protected DomainObject load(ResultSet rs) throws SQLException {

Long id = new Long(rs.getLong(1));

if (loadedMap.containsKey(id)) return (DomainObject) loadedMap.get(id);

DomainObject result = doLoad(id, rs);

loadedMap.put(id, result);

return result;

}

abstract protected DomainObject doLoad(Long id, ResultSet rs) throws SQLException;

class PersonMapper...

protected DomainObject doLoad(Long id, ResultSet rs) throws SQLException {

String lastNameArg = rs.getString(2);

String firstNameArg = rs.getString(3);

int numDependentsArg = rs.getInt(4);

return new Person(id, lastNameArg, firstNameArg, numDependentsArg);

}

Matthew Dailey (CSIM-AIT) Patterns 98 / 193

Page 50: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesMore on Data Mapper

Finding people by last name:

class PersonMapper...

private static String findLastNameStatement =

"SELECT " + COLUMNS +

" FROM people " +

" WHERE UPPER(lastname) like UPPER(?)" +

" ORDER BY lastname";

public List findByLastName(String name) {

PreparedStatement stmt = null;

ResultSet rs = null;

try {

stmt = DB.prepare(findLastNameStatement);

stmt.setString(1, name);

rs = stmt.executeQuery();

return loadAll(rs);

} catch (SQLException e) {

throw new ApplicationException(e);

} finally {

DB.cleanUp(stmt, rs);

}

}

Matthew Dailey (CSIM-AIT) Patterns 99 / 193

Mapping to relational databasesMore on Data Mapper

class AbstractMapper...

protected List loadAll(ResultSet rs) throws SQLException {

List result = new ArrayList();

while (rs.next())

result.add(load(rs));

return result;

}

Actually this method should also check the Identity Map for each personin the result set.

Matthew Dailey (CSIM-AIT) Patterns 100 / 193

Page 51: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesMore on Data Mapper

Instead of duplicating the find code across every mapper, we can make ageneric finder:

class AbstractMapper...

public List findMany(StatementSource source) {

PreparedStatement stmt = null;

ResultSet rs = null;

try {

stmt = DB.prepare(source.sql());

for (int i = 0; i < source.parameters().length; i++)

stmt.setObject(i+1, source.parameters()[i]);

rs = stmt.executeQuery();

return loadAll(rs);

} catch (SQLException e) {

throw new ApplicationException(e);

} finally {

DB.cleanUp(stmt, rs);

}

}

Matthew Dailey (CSIM-AIT) Patterns 101 / 193

Mapping to relational databasesMore on Data Mapper

The generic finder requires a wrapper for the SQL query and itsparameters:

interface StatementSource...

String sql();

Object[] parameters();

The implementation of the StatementSource interface can be an innerclass (next page)...

Matthew Dailey (CSIM-AIT) Patterns 102 / 193

Page 52: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesMore on Data Mapper

class PersonMapper...

public List findByLastName2(String pattern) {

return findMany(new FindByLastName(pattern));

}

static class FindByLastName implements StatementSource {

private String lastName;

public FindByLastName(String lastName) {

this.lastName = lastName;

}

public String sql() {

return

"SELECT " + COLUMNS +

" FROM people " +

" WHERE UPPER(lastname) like UPPER(?)" +

" ORDER BY lastname";

}

public Object[] parameters() {

Object[] result = {lastName};

return result;

}

}

Matthew Dailey (CSIM-AIT) Patterns 103 / 193

Mapping to relational databasesMore on Data Mapper

Updates are specific to the object we’re mapping:

class PersonMapper...

private static final String updateStatementString =

"UPDATE people " +

" SET lastname = ?, firstname = ?, number_of_dependents = ? " +

" WHERE id = ?";

public void update(Person subject) {

PreparedStatement updateStatement = null;

try {

updateStatement = DB.prepare(updateStatementString);

updateStatement.setString(1, subject.getLastName());

updateStatement.setString(2, subject.getFirstName());

updateStatement.setInt(3, subject.getNumberOfDependents());

updateStatement.setInt(4, subject.getID().intValue());

updateStatement.execute();

} catch (Exception e) {

throw new ApplicationException(e);

} finally {

DB.cleanUp(updateStatement);

}

}

Matthew Dailey (CSIM-AIT) Patterns 104 / 193

Page 53: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesMore on Data Mapper

Inserts are partly generic:

class AbstractMapper...

public Long insert(DomainObject subject) {

PreparedStatement insertStatement = null;

try {

insertStatement = DB.prepare(insertStatement());

subject.setID(findNextDatabaseId());

insertStatement.setInt(1, subject.getID().intValue());

doInsert(subject, insertStatement);

insertStatement.execute();

loadedMap.put(subject.getID(), subject);

return subject.getID();

} catch (SQLException e) {

throw new ApplicationException(e);

} finally {

DB.cleanUp(insertStatement);

}

}

abstract protected String insertStatement();

abstract protected void doInsert(DomainObject subject,

PreparedStatement insertStatement)

throws SQLException;Matthew Dailey (CSIM-AIT) Patterns 105 / 193

Mapping to relational databasesMore on Data Mapper

... and partly object-specific:

class PersonMapper...

protected String insertStatement() {

return "INSERT INTO people VALUES (?, ?, ?, ?)";

}

protected void doInsert(

DomainObject abstractSubject,

PreparedStatement stmt)

throws SQLException

{

Person subject = (Person) abstractSubject;

stmt.setString(2, subject.getLastName());

stmt.setString(3, subject.getFirstName());

stmt.setInt(4, subject.getNumberOfDependents());

}

Matthew Dailey (CSIM-AIT) Patterns 106 / 193

Page 54: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesMore on Lazy Load

A Lazy Load is an object that doesn’t contain all of the data you need butknows how to get it.

Lazy Load stops loading linked objects at some point in the graph, leavinga marker in the object structure.

There are four main implementation styles:

Lazy initialization

Virtual proxy

Value holder

Ghost

Matthew Dailey (CSIM-AIT) Patterns 107 / 193

Mapping to relational databasesMore on Lazy Load

The simplest Lazy Load implementation is lazy initialization:

Unloaded fields a are left as null

Every time we read a field, we first check its value, and if it is null, weload it.

This method is simple, but couples the object and the database schema.

Matthew Dailey (CSIM-AIT) Patterns 108 / 193

Page 55: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Mapping to relational databasesMore on Lazy Load

The virtual proxy (a GoF pattern) adds a layer of indirection:

The non-loaded object is replaced with a placeholder (the virtualproxy) that looks like the desired object but doesn’t contain any data.

When any method on the virtual proxy is called, it realizes it doesn’texist and loads itself from the database.

If identity of the virtual proxy object is important, then bookkeepingbecomes difficult. Thus it’s recommended to only use virtual proxies forcomplex value objects like collections where identity is not important.

Matthew Dailey (CSIM-AIT) Patterns 109 / 193

Mapping to relational databasesMore on Lazy Load

Another approach to Lazy Load is to use a value holder in which oneobject wraps another, which isn’t loaded until necessary.

The last approach is to use a ghost:

We create the real object itself, but only fill in the ID.

Whenever a field is accessed, we load the state of the whole object.

The ghost can be placed in the Identity Map, avoiding identityproblems.

Advanced lazy loaders load just the right subset of the object graph forthe active use case.

Matthew Dailey (CSIM-AIT) Patterns 110 / 193

Page 56: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Outline

1 Introduction

2 Domain logic patterns

3 Mapping to relational databases

4 Web presentation

5 Concurrency

6 Session state

7 Distribution strategies

Matthew Dailey (CSIM-AIT) Patterns 111 / 193

Web presentationUse Web interfaces!

Web-based interfaces are now almost universal for enterprise applications:

They eliminate the need for client software installations

They provide a uniform, universal, cross-platform, well-understoodframework for building UIs

They are getting easier to build as development environments improvetheir support for them

You should use a Web interface whenever you can get away with it.

With AJAX technology we can now build pretty sophisticated Webinterfaces.

Sometimes requirements will dictate a rich client instead. Consider across-platform rich client framework like Eclipse in this case.

Matthew Dailey (CSIM-AIT) Patterns 112 / 193

Page 57: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Web presentationScripts vs. server pages

Web interfaces operate on a request-response basis.

When the Web server receives a request, it interprets the request anddecides what program should be invoked to handle it.

Up to the mid-1990s, we only had scripts that would parse request,execute the logic, and output HTML to a stream. Perl CGI is an example.

More recent technology provides server pages in which we write pages inHTML and insert code for the dynamic parts. PHP, ASP, and JSP takethe server page approach.

Matthew Dailey (CSIM-AIT) Patterns 113 / 193

Web presentationScripts + server pages → MVC

It was clear early on that scripts are good for processing the request andserver pages are good for displaying the result.

When we combine these two ideas with the crucial separation ofnon-presentation logic from presentation logic, we get the Model ViewController (MVC).

MVC has been around in object-oriented user interfaces since the late1970s!

Matthew Dailey (CSIM-AIT) Patterns 114 / 193

Page 58: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Web presentationMVC

The MVC pattern splits user interface interaction into three distinct roles:

Fowler (2002), p. 330

Matthew Dailey (CSIM-AIT) Patterns 115 / 193

Web presentationMVC

The basic flow in MVC:

The controller (called an input controller by Fowler) necessaryinformation from the incoming request and forwards it to the businesslogic which is encapsulated in the model.

The model talks to the data source, transforms and validates data,and gathers all the information necessary for the response. It thenreturns the response data to the controller.

The controller (possibly with the help of an application controller)then invokes a view.

The view renders the model data for display.

MVC’s main advantage is separation of the presentation logic from themodel, making it easier to modify the presentation.

The controller-view separation is not as crucial but still useful.

Matthew Dailey (CSIM-AIT) Patterns 116 / 193

Page 59: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Web presentationMVC

A sequence diagram giving the essence of MVC:

Fowler (2002), Fig. 4.1

MVC is a good idea for any Web presentation. You might use a frameworklike Spring for Java, Rails for Ruby, one of dozens of PHP MVCframeworks, or roll your own.

Matthew Dailey (CSIM-AIT) Patterns 117 / 193

Web presentationApplication controllers

Web interfaces often use a layer of Application Controllers between thepresentation and model.

Application controllers are responsible for application flow (choosing whatscreen to display when).

Web presentations only need application controllers if the navigation iscomplex and under control of the system.

Matthew Dailey (CSIM-AIT) Patterns 118 / 193

Page 60: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Web presentationView patterns

For the view, we use either the Transform View pattern or the TemplateView pattern, either of which can be single stage or have the variationTwo-step View.

Template Views:

The presentation is written as a set of template HTML pages withmarkers indicating where the dynamic content needs to go.

Examples are ASP, JSP, and PHP.

Convenient and flexible, but difficult to maintain.

Template engines (like Smarty for PHP) help increase maintainabilityby forcing separation of business logic from the template.

Matthew Dailey (CSIM-AIT) Patterns 119 / 193

Web presentationView patterns

Transform views:

The model outputs domain data in some intermediate representationsuch as XML.

The view is a transformation program like XSLT that converts thedomain data into HTML.

Initial development takes more time than a template view, butmaintenance and testing is easier.

Matthew Dailey (CSIM-AIT) Patterns 120 / 193

Page 61: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Web presentationView patterns

Templates and transforms can be single stage or two-stage:

A single-stage view has one separate template or transform for eachscreen in the application.

A two-stage view creates a logical screen from the domain data instage 1 then renders the logical screen with the stage 2 for each view.

A popular approach is to use HTML for the logical screen andCascading Style Sheets (CSS) for the stage 2 rendering.

Two-stage views are useful when you have different display devices (e.g.desktop and mobile devices) to handle or when you want to easily changethe global look and feel of the application.

Matthew Dailey (CSIM-AIT) Patterns 121 / 193

Web presentationView patterns

Single-stage views:

Fowler (2002), Fig. 4.2

Matthew Dailey (CSIM-AIT) Patterns 122 / 193

Page 62: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Web presentationView patterns

Two-stage views:

Fowler (2002), Fig. 4.3

Matthew Dailey (CSIM-AIT) Patterns 123 / 193

Web presentationInput controller patterns

There are two main approaches for the input controller:

Page Controllers assign one controller to each page or user action.

A Front Controller handles all user actions for the application in asingle controller.

Matthew Dailey (CSIM-AIT) Patterns 124 / 193

Page 63: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Web presentationInput controller patterns

Page controller structure:

Fowler (2002), p. 333

Matthew Dailey (CSIM-AIT) Patterns 125 / 193

Web presentationInput controller patterns

Front controller structure:

Fowler (2002), p. 344

Matthew Dailey (CSIM-AIT) Patterns 126 / 193

Page 64: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Web presentationInput controller patterns

Page controllers:

See Fowler Ch. 14 for an example of a Tomcat application serverconfiguration, a servlet for a page controller, and a JSP for the view.

Also see the example combining the page contoller with the JSP view.This is common for simple page controllers that almost alwaysforward to the same view. This is also common in PHP.

Front controllers:

A front controller is good for reusing code related to security,internationalization, and per-user customization of the view.

See Ch 14 for an example servlet implementation of a front controller.

Code reuse is maximized, especially for complex interfaces.

Front controllers get big and unweildy for apps with many screens.

Matthew Dailey (CSIM-AIT) Patterns 127 / 193

Outline

1 Introduction

2 Domain logic patterns

3 Mapping to relational databases

4 Web presentation

5 Concurrency

6 Session state

7 Distribution strategies

Matthew Dailey (CSIM-AIT) Patterns 128 / 193

Page 65: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

ConcurrencyThe issues

Concurrency is problematic because it is difficult to test.

Everything depends on the relative order of events within different threadsor processes.

In many cases, enterprise developers don’t have to worry aboutconcurrency, because our RDBMS gives us transactions.

However, when a business transaction doesn’t fit into a DB or systemtransaction, we need to worry about offline concurrency (concurrencycontrol for data manipulated over multiple system transactions).

In addition to multi-request business transactions, we sometimes have toworry about concurrency in a multi-threaded application server.

As a running example, we consider a source code control system. Thesame concepts apply to any enterprise system.

Matthew Dailey (CSIM-AIT) Patterns 129 / 193

ConcurrencyEssential problems

For enterprise applications, we have two essential problems:

Lost updates occur, for example, when 1) one user grabs a file forediting, 2) another user grabs the same file, makes an update, andsubmits the new version, then 3) the first user completes theirmodification and commits. The result is that the second user’supdate is lost.

Inconsistent reads occur when you read two correct pieces ofinformation that are not correct at the same time. For examplesuppose you’re opening a list of files, and while you’re in the middleof reading, someone else does an update to some of the files. You getsome versions from before the update and some versions from afterthe update, and these might not be consistent with each other.

Matthew Dailey (CSIM-AIT) Patterns 130 / 193

Page 66: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

ConcurrencyEssential problems

Correctness or safety means that results should always be the same as ifthere weren’t two people working on the data at the same time.

Correctness is guaranteed by only allowing one person to work on the dataat the same time (locking everyone else out) but that reduces liveness, orhow much concurrency is allowed.

Matthew Dailey (CSIM-AIT) Patterns 131 / 193

ConcurrencyExecution contexts

Processing always occurs in some context.

One important part of the context is the particular request we are workingon.

Usually we think of requests in isolation, but they could be related. Anexample: a client places an order then cancels.

A session is an execution context tying together related requests. Asession is a long-running interaction between the client and server possiblyinvolving more than one request.

Matthew Dailey (CSIM-AIT) Patterns 132 / 193

Page 67: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

ConcurrencyExecution contexts

A process is an execution context that has its own dedicated memoryaddress space.

A thread is an execution context in which some resources (usually thememory address space) can be shared with other execution contexts.

An isolated thread is one that doesn’t share memory with other threads(but still shares other resources, making it more efficient).

It would be nice if we could have one unique process for every session forthe lifetime of the session, but more typically we have to actively associaterequests with new processes or threads then with sessions.

Matthew Dailey (CSIM-AIT) Patterns 133 / 193

ConcurrencyExecution contexts

A transaction is an execution context containing a series of requestsshould be treated as one request.

We have transactions on both “sides” of the application server:

The user interacts with the application to form business transactions.

The application interacts with the database to form systemtransactions.

Matthew Dailey (CSIM-AIT) Patterns 134 / 193

Page 68: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

ConcurrencyIsolation and immutability

The two methods for overcoming concurrency problems in enterpriseapplications (mainly lost updates and inconsistent reads) are isolation andimmutability:

Isolation allows a process to enter an isolated zone in whichconcurrency isn’t a problem. Conceptually, we work in a memoryaddress space separate from all other processes, and lock all externalresources.

Immutability means recognizing data that cannot be modified. Allconcurrency problems involve updates, and immutable data cannot beupdated, so immutability eliminates concurrency problems.

Matthew Dailey (CSIM-AIT) Patterns 135 / 193

ConcurrencyOptimistic and pessimistic concurrency control

When we have data that we can’t isolate, we use either optimistic orpessimistic concurrency control.

Optimistic locking is when we allow reads and writes and only generate anexception when we see a conflict.

Example: A and B check out a file at the same time. A commits first, andhis commit goes through, but when B tries to commit there will be aconflict, and B will be responsible for fixing it.

Pessimistic locking means once a resource is read, nobody else is allowedto edit it until the transaction is finished.

When A checks a file out, B can’t check out until A commits.

Optimistic locking means conflict detection; pessimistic locking meansconflict prevention.

Matthew Dailey (CSIM-AIT) Patterns 136 / 193

Page 69: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

ConcurrencyOptimistic and pessimistic concurrency control

In source code control, for a variety of reasons, optimistic locking is thenorm (c.f. CVS and Subversion). In this case automated tools can helpresolve conflicts. For business data it’s usually too difficult and we justthrow everything out and start again.

The choice depends on how difficult conflict resolution is for users.

Matthew Dailey (CSIM-AIT) Patterns 137 / 193

ConcurrencyPreventing inconsistent reads

Solving inconsistent reads with pessimistic techniques:

To read data, we say we need a read lock.

To write data, we say we need a write lock.

Any number of clients can obtain a read lock simultaneously.

If anyone has a read lock, nobody can get a write lock.

If anyone has the write lock, nobody else is allowed any lock.

Matthew Dailey (CSIM-AIT) Patterns 138 / 193

Page 70: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

ConcurrencyPreventing inconsistent reads

Optimistic systems use versioning to prevent inconsistent reads. Whenreading, we make sure that every piece of data read has the same versionnumber.

Related concept: temporal reads, where a timestamp on each data itemensures consistent reads.

This technique is feasible in source control, where the updates areinfrequent and the version history needs to be kept anyway.

The version history feature is almost nonexistent in databases, whereupdates are frequent and history maintenance would be too expensive.(That aside, sometimes you do need precise logging of your businesstransactions, but normally you have to design that yourself.)

Matthew Dailey (CSIM-AIT) Patterns 139 / 193

ConcurrencyDeadlocks

A deadlock occurs when there is a cyclic wait for a set of locks andnobody can proceed until they get the lock they’re waiting for.

Techniques to address a deadlock:

Detection and recovery: choose a victim and force it to roll back(difficult and drastic), or put a timeout on every lock request (makingyou a victim when your request times out — simple but more drastic).

Prevention: force all processes to get all their locks at once in thebeginning before they can continue, or put an ordering on the locksand force each process to grab them in order.

The advice is to use simple conservative schemes for enterpriseapplications, even if it causes unnecessary victimization.

Matthew Dailey (CSIM-AIT) Patterns 140 / 193

Page 71: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

ConcurrencyACID Transactions

Our main tool is the transaction. A transaction is a bounded sequence ofwork with start points and end points well defined.

Software transactions are described in terms of ACID properties:

Atomicity (all-or-none): every step must complete successfully, or allthe steps must roll back. Partial completion is not allowed. If there’sa system crash in the middle of a bank transfer we must go back tothe original state.

Consistency: the resources must be consistent and noncorrupt at boththe beginning and end of the transaction.

Isolation: the result of a transaction must not be visibile until it hascompleted successfully.

Durability: any result of a committed transaction must be permanent,i.e., survive any kind of crash.

Matthew Dailey (CSIM-AIT) Patterns 141 / 193

ConcurrencyTransactional resources

We are most familiar with transactions in databases, but they are alsocommon in many other places. Some terms:

A transactional resource is anything using transactions to controlconcurrency. “Transactional resource” and “database” can be usedinterchangeably.

Transactions spanning multiple requests are called long transactions.

A request transaction is one started when a request is received andcompleted at the end of request processing.

Whenever possible, use request transactions, not long transactions.This maximizes throughput.

A late transaction isn’t opened until all reads are complete. Thisimproves efficiency but allows inconsistent reads.

Some development environments allow us to tag a method astransactional, so that a transaction is automatically begun at thebeginning and completed at the end.

Matthew Dailey (CSIM-AIT) Patterns 142 / 193

Page 72: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

ConcurrencyIsolation ↔ liveness tradeoff

Oftentimes a strong isolation model leads to a system that is not very live.

Serializable isolation means the transactions can be executed concurrentlywith a result guaranteed to correspond to one of the serialized results.This is the strongest form of isolation. You can get more concurrency ifyou go to weaker models of isolation.

Repeatable read isolation means that you may see some but not all newitems being inserted while you do a read. Repeatable means you’ll alwaysget the same result, however, if you repeat the read within the sametransaction.

Matthew Dailey (CSIM-AIT) Patterns 143 / 193

ConcurrencyIsolation ↔ liveness tradeoff

Read committed means you may see some but not all of the new itemsbeing inserted, but the reads can be unrepeatable, meaning the same readperformed twice within the same transaction can return different elements.

Read uncommitted means you can see data from another transaction thathasn’t been committed yet. This is also called dirty read. If there is a rollback, we’ll see data that was never really there at all.

The advice is to always use serializable isolation unless performance is anissue, in which case you might weaken the isolation for some or alltransactions.

Matthew Dailey (CSIM-AIT) Patterns 144 / 193

Page 73: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

ConcurrencyBusiness vs. system transactions

Usually folks talk about SYSTEM TRANSACTIONS supported by aRDBMS. When we commit, if there is a consistency failure, the partialtransaction is rolled back and the application is notified of the problem.

A BUSINESS TRANSACTION is a transaction executed by a user. E.g., abank user might log in, set up some bill payments, and click OK to pay. Abusiness transaction requires the same ACID properties as a systemtransaction.

One solution is to execute the entire business transaction within a systemtransaction, but then we would have a lot of long transactions. This issometimes OK but more often, to support ACID properties for businesstransactions we need to implement OFFLINE CONCURRENCY. We use aseries of system transactions with some GLUE between the systemtransactions.

Matthew Dailey (CSIM-AIT) Patterns 145 / 193

ConcurrencyBusiness vs. system transactions

The idea is the user begins the commit of the business transaction whenhitting SAVE or whatever. We begin a system transaction, determine thechange set using Unit of Work, do the updates, then commit the systemtransaction.

Isolation is difficult to enfore for business transactions. We have to makesure that our changes don’t step on other sessions’ changes. We also haveto ensure that inconsistent reads don’t occur.

[Think of some examples here!]

Normally we design so that every business transaction occurs in a session.Sessions then become sequences of business transactions, from the user’spoint of view.

Matthew Dailey (CSIM-AIT) Patterns 146 / 193

Page 74: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

ConcurrencyOffline concurrency control patterns

Wherever possible, let the transaction system deal with concurrency.

When there’s a mismatch between the system transactions and businesstransactions, then you have to roll your own. The patterns include

Optimistic Offline Lock: use optimistic concurrency control across thebusiness transactions. Easiest to program and high liveness.Limitation is you don’t know the transaction will fail until you try tocommit. This can decrease user confidence in your system.

Pessimistic Offline Lock: lock everything in advance. More difficult toprogram, less liveness, earlier detection of trouble.

Coarse-Grained Lock: works with either basic approach, reducingcomplexity by managing a group of objects together rather thanindividual locks.

Implicit Lock: developers don’t have to worry about locking; theobjects do it themselves.

Matthew Dailey (CSIM-AIT) Patterns 147 / 193

ConcurrencyOptimistic offline lock

Prevents conflicts between concurrent business transactions by detecting aconflict and rolling back the transaction.

Fowler (2002), p. 416

If the chance of a conflict is pretty low, this is a good pattern forimplementing your business transactions.

The idea is during the BUSINESS TRANSACTION, the last step will be toupdate the database in a single system transaction. At the beginning ofthat system transaction, we acquire a lock on each record we’re updating,simply by checking that each one hasn’t been altered since we read it.

The lock is normally implemented by associating a version number witheach record, and incrementing that version number on each update.

If we’re using a RDBMS, we can check the version number in the samequery as the update, inspecting the version number in the WHERE clauseand checking the number of rows updated on query execution. 1 meanssuccess, 0 means failure.

Matthew Dailey (CSIM-AIT) Patterns 148 / 193

Page 75: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

ConcurrencyPessimistic offline lock

Prevents conflicts between concurrent business transactions by allowingonly one business transaction at a time to access data.

Fowler (2002), p. 426

Matthew Dailey (CSIM-AIT) Patterns 149 / 193

ConcurrencyPessimistic offline lock

If optimistic locking is not appropriate for your application, you have toroll your own pessimistic lock.

For each resource you want to lock, that becomes a row in a table oflocks. Each lock has an owner. A lock manager is written to acquire locksand release locks. Normally you lock everything at the beginning of thebusiness transaction then release the locks at the end of the businesstransaction.

See Chapter 16 for more details.

Matthew Dailey (CSIM-AIT) Patterns 150 / 193

Page 76: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

ConcurrencyApplication server concurrency

How do we handle simultaneous requests to the application server?Database transactions can’t help us. Hopefully the application serverenvironment will.

Process per session has each session running in its own process, isolatedfrom others. This is great but uses a lot of resources.

Pooled process per request means we allocate an existing idle process toeach new request. Session information can be saved at the end of eachrequest and restored at the beginning of the request. Isolation is good, butwe have to worry about releasing resources at the end of each request.

Thread per request means each request is handled by a single threadwithin one process. More requests with less hardware, but dangerous.

Fowler recommends process per request due to the increased isolation andequal scalability with thread per request.

Matthew Dailey (CSIM-AIT) Patterns 151 / 193

ConcurrencyApplication server concurrency

You can also get good isolation even with threads if using an environmentlike EJB that gives your threads a private playground. The thread needs toallocate all objects locally so as not to affect other threads. Avoid static orglobal variables so you don’t have to synchronize them.

For global memory, use the REGISTRY pattern, not global variables in theapplication development environment. This will scale without trouble tomultiple application servers.

Matthew Dailey (CSIM-AIT) Patterns 152 / 193

Page 77: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Outline

1 Introduction

2 Domain logic patterns

3 Mapping to relational databases

4 Web presentation

5 Concurrency

6 Session state

7 Distribution strategies

Matthew Dailey (CSIM-AIT) Patterns 153 / 193

Session stateWhat is session state?

On the one hand, if you have more than a few objects without state, youprobably have a bad design.

However, statelessness for the application server is a good thing. It meansno state is retained between requests — all the state is in the database.

Query objects are the sorts of objects that can be stateless. However, youmight want to do things like keep a history of queries, in which casestatelessness would no longer do the trick for you.

If you can keep your application server stateless that’s good, because itdoesn’t matter which object serves an incoming request, and this mapswell onto HTTP (a stateless protocol).

Problem: some interactions are inherently stateful. Example: a shoppingcart in an e-commerce application. If we don’t have it we can’t makemoney!

Matthew Dailey (CSIM-AIT) Patterns 154 / 193

Page 78: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Session stateSession state and business transactions

Things like shopping carts are (normally) what we call SESSION STATE –state info only related to a single session. Session state is manipulatedwithin business transactions.

RECORD DATA is the long-term persistent data held in the database andvisible to all sessions. If we want to turn session state into record data, wehave to COMMIT it.

Matthew Dailey (CSIM-AIT) Patterns 155 / 193

Session stateSession state and business transactions

Since session state is part of a business transaction, it should have ACIDproperties just like any other transactional resource. However, things get abit weird.

One example is consistency: while you’re working on something like a loanapplication, the intermediate data won’t be consistent according to thebusiness logic. You often need to come up with new consistency rules forthe session state.

Isolation is another tricky thing. It means that during the businesstransaction, related record data should not change due to othertransactions.

Matthew Dailey (CSIM-AIT) Patterns 156 / 193

Page 79: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Session statePatterns for session state

CLIENT SESSION STATE stores the session data on the client. For aWeb presentation, it could be encoded in the URL, put inside cookies,serialized in a hidden field in a Web form, and so on. For a rich clientpresentation, it would be stored in objects and passed with each request.

SERVER SESSION STATE means the application server stores the data,either in memory, or in some persistent form on the file system or in itsown database.

DATABASE SESSION STATE means breaking the session data into tablesand storing it just like normal persistent data.

Matthew Dailey (CSIM-AIT) Patterns 157 / 193

Session stateChoosing a pattern for session state

The decision depends on many factors. First, how much data is there? Ifit’s a lot, this would rule out client session state. If it needs protection,then it’s better if it’s not stored on the client.

Moving in the other direction, isolation is tricky if you’re using databasesession data. One session should not affect another, so we need to makesure the different sessions are carefully separated in the database.

Another factor is clustering. As your application scales, you want to addapplication servers and a router to route each request to the actual serverthat will handle the request. This is more effective if we allow SESSIONMIGRATION (allowing any request to be handled by any server) ratherthan SERVER AFFINITY or STICKY SESSIONS (forcing each request ina session to be handled by the same application server). If we’re usingServer Session State, then we need to use sticky sessions, or actuallytransfer session state between application servers. This gets nasty too.

Matthew Dailey (CSIM-AIT) Patterns 158 / 193

Page 80: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Session stateChoosing a pattern for session state

Each pattern affects the responsiveness of the syste too. Client sessiondata needs to be transformed into objects. Server session data isimmediately available. Database session data requires a database query.

Database session state is pretty decent for retail systems and such, withinfrequent requests with little data from a large number of users. Serversession state is better for highly interactive systems like leasing systems,where a lot of data is being used on each request, and the time periodbetween requests in a session is relatively small.

In B2C and other systems we have the additional problem of users justdisappearing, and we don’t know if they’re taking a break or ending thebusiness transaction prematurely. In this case Client Session State is thewinner because we don’t have to do anything about it. Server SessionState is also OK since most frameworks have an automatic timeout. Butwith Database Session State we have to do the cleanup ourselves.

Matthew Dailey (CSIM-AIT) Patterns 159 / 193

Session stateChoosing a pattern for session state

Other issues include crashes. Database Session State is the most robust.Server Session State is sensitive to server crashes (unless the frameworkuses backing store of some kind). Client Session State is normally lostwhen the browser is closed or crashes. Surviving various crash incidentsshould be part of the non-functional requirements.

You can mix the approaches for different kinds of data. But you willalways need at least a session ID stored client side.

Fowler prefers Server Session State, with a session ID stored client side, formost applications. But you might choose Client Session State when thedata is very small or Database Client Session if you need the extrareliability and don’t worry about isolating sessions.

Matthew Dailey (CSIM-AIT) Patterns 160 / 193

Page 81: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Outline

1 Introduction

2 Domain logic patterns

3 Mapping to relational databases

4 Web presentation

5 Concurrency

6 Session state

7 Distribution strategies

Matthew Dailey (CSIM-AIT) Patterns 161 / 193

Distribution strategiesFirst law of distributed objects

Fowler’s First Law of Distributed Objects: don’t distribute objects! Here isan example bad design:

Fowler (2002), Fig. 7.1

Why? Because the distribution is based on domain classes, andperformance is going to be terrible.

Matthew Dailey (CSIM-AIT) Patterns 162 / 193

Page 82: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Distribution strategiesLocal vs. remote interfaces

Some rules of thumb:

A procedure call is fast.

A procedure call between two separate processes is orders ofmagnitude slower.

A call between separate processes on separate machines is anotherorder of magnitude slower.

Local interfaces are best when they are fine-grained. This is veryconsistent with the OO philosophy where we have many small objectsresponsible for their own small operations.

When we take an interface and make it remote, fine-grainedness is notgood. Rather than 3 calls to fetch three attributes of an object, we’dbetter get all three attributes in one call, to avoid tripling the networkoverhead.

Matthew Dailey (CSIM-AIT) Patterns 163 / 193

Distribution strategiesCoarse-grained interfaces and clustering

So any object that can be invoked over the network must have acoarse-grained interface. Any object with a fine-grained interface shouldnever be invoked over the network.

Fowler (2002), Fig. 7.2

Here is a better design based on clustering. We can do fine-grainedinterfaces between domain classes which is what we like, at the small costof having the entire application replicated at each node.

Matthew Dailey (CSIM-AIT) Patterns 164 / 193

Page 83: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Distribution strategiesWhen must you distribute?

Clustering can only take you so far. We do have to separate processessometimes. Here are the common reasons:

Clients and servers: it’s impractical to replicate the entire shared datastore across every PC in the enterprise. If we don’t want to usemainframes, we must have clients connecting to the data store over anetwork.

Application server/Database server: not absolutely required buttypical. For sure in an enterprise system the DB will be a separateprocess, and that gives most of the performance gap. Luckily SQL iscoarse-grained by design, to allow remote access.

Matthew Dailey (CSIM-AIT) Patterns 165 / 193

Distribution strategiesWhen must you distribute?

Other times when distribution may be necessary:

Web server/application server: try to run the application in the sameprocess as the server, but sometimes it’s not possible.

Vendor differences: any third-party application you’re using willnormally run in its own process. This will normally be acoarse-grained interface, though, so it should be OK.

Split application server software: avoid this at all costs! If it cannotbe avoided, you have to divide your software into coarse-grainedcomponents with remote interfaces.

Matthew Dailey (CSIM-AIT) Patterns 166 / 193

Page 84: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Distribution strategiesThe distribution boundary

Some rules of thumb for the boundary between two components with aremote interface:

At the boundaries, use coarse-grained objects that, if necessary, havea lot of attributes and operations doing a lot.

Inside each component, stick with normal fine-grained objects.

The coarse-grained boundary object should simply act as a facade forthe fine-grained objects inside.

Clients that know they’re making local calls to your component canuse the fine-grained interface directly.

The Remote Facade pattern formalizes this approach.

Data Transfer Objects go hand-in-hand with Remote Facades. Theybundle together all the data from the relevant domain objects that need tobe transferred over the remote interface.

Matthew Dailey (CSIM-AIT) Patterns 167 / 193

Distribution strategiesInterfaces for distribution

XML over HTTP is currently the most flexible method we have fortransfer of complex objects, remote procedure calls, and asynchronousmessaging over a network. SOAP is the standard.

XML has a lot of processing overhead, though. If you know that yourinterface is direct, and there are no issues with firewalls and so on, and youdon’t think you will ever want to expose an operation to otherapplications, it is best to use the direct interface, for example Java RMI.

Don’t get stuck with synchronous remote calls. Wherever possible, useasynchronous calls.

Matthew Dailey (CSIM-AIT) Patterns 168 / 193

Page 85: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Distribution strategiesRemote facade pattern

The Remote Facade pattern provides a coarse-grained facade onfine-grained objects to improve efficiency over a network.

Fowler (2002), p. 388

This pattern is based on GoF’s coarse-grained facade.

The facade contains no business logic – it just translates thecoarse-grained methods to underlying fine-grained objects.

Matthew Dailey (CSIM-AIT) Patterns 169 / 193

Distribution strategiesRemote facade pattern

The facade replaces individual getters and setters with bulk accessors:

Fowler (2002), Fig. 15.1

Matthew Dailey (CSIM-AIT) Patterns 170 / 193

Page 86: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Distribution strategiesRemote facade pattern

The facade will often be an interface to a complex web of fine-grainedobjects — on one client call, it might interact with and integrate datafrom multiple fine-grained objects.

For data transfer, if the classes are identical on both ends, and they areserializable, then we can simply serialize and transfer them.

Any remote facade can be stateful or stateless. One of the three mainsession state patterns will be needed in this stateful case.

Remote facades are good places to apply security (authentication andauthorization) and transaction control.

Remote Facade has no domain logic!! A good way to tell if you’ve violatedthis law is to see if the application can run entirely locally without theremote facade.

Matthew Dailey (CSIM-AIT) Patterns 171 / 193

Distribution strategiesRemote facade pattern example

Example: Using a Java Session Bean as a Remote Facade

EJB session beans are remote objects that can be stateful or stateless.The example has POJOs running inside an EJB container being accessedremotely through a session bean designed as a Remote Facade.

Matthew Dailey (CSIM-AIT) Patterns 172 / 193

Page 87: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Distribution strategiesRemote facade pattern example

Fowler (2002), Fig. 15.2

We have a decoupled Domain Model, Data Transfer Objects (package dto)to move data over the network, and remote objects (package remote) tomove data between the domain and data transfer objects. The remoteclient deals with these objects through the classes in package api.

Matthew Dailey (CSIM-AIT) Patterns 173 / 193

Distribution strategiesRemote facade pattern example

An EJB 2.1 session bean has 2 Java interfaces (AlbumService,AlbumHome) and one implementation class (AlbumServiceBean). In EJB3.0 we only need the POJO.

class AlbumService...

String play(String id) throws RemoteException;

String getAlbumXml(String id) throws RemoteException;

AlbumDTO getAlbum(String id) throws RemoteException;

void createAlbum(String id, String xml) throws RemoteException;

void createAlbum(String id, AlbumDTO dto) throws RemoteException;

void updateAlbum(String id, String xml) throws RemoteException;

void updateAlbum(String id, AlbumDTO dto) throws RemoteException;

void addArtistNamed(String id, String name) throws RemoteException;

void addArtist(String id, String xml) throws RemoteException;

void addArtist(String id, ArtistDTO dto) throws RemoteException;

ArtistDTO getArtist(String id) throws RemoteException;

Note: albums and artists are appearing in the same interface, and thereare multiple versions of the same method (accessors working on XML orDTO representations of the domain objects).

Matthew Dailey (CSIM-AIT) Patterns 174 / 193

Page 88: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Distribution strategiesRemote facade pattern example

The methods in the facade are simple to implement — each just delegatesto another object. Note there is no domain logic!

class AlbumServiceBean...

public AlbumDTO getAlbum(String id) throws RemoteException {

return new AlbumAssembler().writeDTO(Registry.findAlbum(id));

}

public String getAlbumXml(String id) throws RemoteException {

AlbumDTO dto = new AlbumAssembler().writeDTO(Registry.findAlbum(id));

return dto.toXmlString();

}

public void createAlbum(String id, AlbumDTO dto) throws RemoteException {

new AlbumAssembler().createAlbum(id, dto);

}

public void createAlbum(String id, String xml) throws RemoteException {

AlbumDTO dto = AlbumDTO.readXmlString(xml);

new AlbumAssembler().createAlbum(id, dto);

}

Matthew Dailey (CSIM-AIT) Patterns 175 / 193

Distribution strategiesRemote facade pattern example

public void updateAlbum(String id, AlbumDTO dto) throws RemoteException {

new AlbumAssembler().updateAlbum(id, dto);

}

public void updateAlbum(String id, String xml) throws RemoteException {

AlbumDTO dto = AlbumDTO.readXmlString(xml);

new AlbumAssembler().updateAlbum(id, dto);

}

Matthew Dailey (CSIM-AIT) Patterns 176 / 193

Page 89: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Distribution strategiesRemote facade pattern example

Some test code using JUnit:

This case goes from domain object to DTO to XML back to DTO.

We don’t need to deploy to the EJB container — we instantiate thesession bean directly.

class XmlTester...

private AlbumDTO kob;

private AlbumDTO newkob;

private AlbumServiceBean facade = new AlbumServiceBean();

protected void setUp() throws Exception {

facade.initializeForTesting();

kob = facade.getAlbum("kob");

Writer buffer = new StringWriter();

kob.toXmlString(buffer);

newkob = AlbumDTO.readXmlString(new StringReader(buffer.toString()));

}

public void testArtist() {

assertEquals(kob.getArtist(), newkob.getArtist());

}

Matthew Dailey (CSIM-AIT) Patterns 177 / 193

Distribution strategiesData transfer object pattern

The Data Transfer Object pattern: an object that carries data betweenprocesses in order to reduce the number of method calls.

Fowler (2002), p. 401

Each call to a remote interface is expensive, so we try to minimize thenumber of needed calls by globbing data into one class.

Matthew Dailey (CSIM-AIT) Patterns 178 / 193

Page 90: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Distribution strategiesData transfer object pattern

Some properties/guidelines for a Data Transfer Object (DTO):

It should hold all the data for a call.

It must be serializable (not too complex).

It should only have attributes, getters, and setters.

It often wraps more data than is really needed: sending too muchdata in one call is better than multiple calls.

The attributes need not be cohesive: a DTO often combines morethan one domain object.

Matthew Dailey (CSIM-AIT) Patterns 179 / 193

Distribution strategiesData transfer object pattern

More properties of a DTO:

Attribute types should be primitives or other DTOs (but keep thegraph simple).

The DTO classes must be present on both sides of the channel.

The DTOs might be different for different clients even when they’retransferring the same objects (e.g. XML vs. binary serialization).

You might use the same DTO for several related requests.

Some folks prefer DTOs to be immutable but it’s not necessary. Amutable DTO is good when you want to build the object up gradually.

Matthew Dailey (CSIM-AIT) Patterns 180 / 193

Page 91: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Distribution strategiesData transfer object pattern

Record Set is a pretty common DTO. It’s the DTO for a SQL database,and as we saw it works well with Table Modules and frameworks like .NET.

XML serialization will usually be the best choice, unless performance is aproblem. Java has built-in binary serialization, and .NET has both binaryand XML serialization.

Use an assembler to decouple the domain objects from the DTOs:

Fowler (2002), Fig. 15.4

Matthew Dailey (CSIM-AIT) Patterns 181 / 193

Distribution strategiesData transfer object pattern example

Example: transferring information about albums. Suppose we have thisdomain model:

Fowler (2002), Fig. 15.5

We’ll transfer them using this scheme:

Fowler (2002), Fig. 15.6

Matthew Dailey (CSIM-AIT) Patterns 182 / 193

Page 92: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Distribution strategiesData transfer object pattern example

The Assembler code:

class AlbumAssembler...

public AlbumDTO writeDTO(Album subject) {

AlbumDTO result = new AlbumDTO();

result.setTitle(subject.getTitle());

result.setArtist(subject.getArtist().getName());

writeTracks(result, subject);

return result;

}

private void writeTracks(AlbumDTO result, Album subject) {

List newTracks = new ArrayList();

Iterator it = subject.getTracks().iterator();

while (it.hasNext()) {

TrackDTO newDTO = new TrackDTO();

Track thisTrack = (Track) it.next();

newDTO.setTitle(thisTrack.getTitle());

writePerformers(newDTO, thisTrack);

newTracks.add(newDTO);

}

result.setTracks((TrackDTO[]) newTracks.toArray(new TrackDTO[0]));

}Matthew Dailey (CSIM-AIT) Patterns 183 / 193

Distribution strategiesData transfer object pattern example

private void writePerformers(TrackDTO dto, Track subject) {

List result = new ArrayList();

Iterator it = subject.getPerformers().iterator();

while (it.hasNext()) {

Artist each = (Artist) it.next();

result.add(each.getName());

}

dto.setPerformers((String[]) result.toArray(new String[0]));

}

Matthew Dailey (CSIM-AIT) Patterns 184 / 193

Page 93: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Distribution strategiesData transfer object pattern example

To go the other way, to update a model item from the DTO, is moredifficult. If we’re creating new ones:

class AlbumAssembler...

public void createAlbum(String id, AlbumDTO source) {

Artist artist = Registry.findArtistNamed(source.getArtist());

if (artist == null)

throw new RuntimeException("No artist named " + source.getArtist());

Album album = new Album(source.getTitle(), artist);

createTracks(source.getTracks(), album);

Registry.addAlbum(id, album);

}

private void createTracks(TrackDTO[] tracks, Album album) {

for (int i = 0; i < tracks.length; i++) {

Track newTrack = new Track(tracks[i].getTitle());

album.addTrack(newTrack);

createPerformers(newTrack, tracks[i].getPerformers());

}

}

Matthew Dailey (CSIM-AIT) Patterns 185 / 193

Distribution strategiesData transfer object pattern example

private void createPerformers(Track newTrack, String[] performerArray) {

for (int i = 0; i < performerArray.length; i++) {

Artist performer = Registry.findArtistNamed(performerArray[i]);

if (performer == null)

throw new RuntimeException("No artist named " + performerArray[i]);

newTrack.addPerformer(performer);

}

}

Note that we assume the artists are already in the Registry.

Matthew Dailey (CSIM-AIT) Patterns 186 / 193

Page 94: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Distribution strategiesData transfer object pattern example

To update an existing album:

class AlbumAssembler...

public void updateAlbum(String id, AlbumDTO source) {

Album current = Registry.findAlbum(id);

if (current == null)

throw new RuntimeException("Album does not exist: " + source.getTitle());

if (source.getTitle() != current.getTitle())

current.setTitle(source.getTitle());

if (source.getArtist() != current.getArtist().getName()) {

Artist artist = Registry.findArtistNamed(source.getArtist());

if (artist == null)

throw new RuntimeException("No artist named " + source.getArtist());

current.setArtist(artist);

}

updateTracks(source, current);

}

Matthew Dailey (CSIM-AIT) Patterns 187 / 193

Distribution strategiesData transfer object pattern example

private void updateTracks(AlbumDTO source, Album current) {

for (int i = 0; i < source.getTracks().length; i++) {

current.getTrack(i).setTitle(source.getTrackDTO(i).getTitle());

current.getTrack(i).clearPerformers();

createPerformers(current.getTrack(i), source.getTrackDTO(i).getPerformers());

}

}

Matthew Dailey (CSIM-AIT) Patterns 188 / 193

Page 95: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Distribution strategiesData transfer object pattern example

The album object is updated, not replaced, but the artists and tracks aresimply replaced. The decision here depends on whether other objects referto the objects in question.

The serialization in this case is binary. To avoid problems when the DTOobject fields are changed or reodered, we can use a map:

class TrackDTO...

public Map writeMap() {

Map result = new HashMap();

result.put("title", title);

result.put("performers", performers);

return result;

}

public static TrackDTO readMap(Map arg) {

TrackDTO result = new TrackDTO();

result.title = (String) arg.get("title");

result.performers = (String[]) arg.get("performers");

return result;

}

Matthew Dailey (CSIM-AIT) Patterns 189 / 193

Distribution strategiesData transfer object pattern example

This can be handled automatically using a reflective routine in thesuperclass:

class DataTransferObject...

public Map writeMapReflect() {

Map result = null;

try {

Field[] fields = this.getClass().getDeclaredFields();

result = new HashMap();

for (int i = 0; i < fields.length; i++)

result.put(fields[i].getName(), fields[i].get(this));

}catch (Exception e) {throw new ApplicationException (e);

}

return result;

}

Matthew Dailey (CSIM-AIT) Patterns 190 / 193

Page 96: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Distribution strategiesData transfer object pattern example

public static TrackDTO readMapReflect(Map arg) {

TrackDTO result = new TrackDTO();

try {

Field[] fields = result.getClass().getDeclaredFields();

for (int i = 0; i < fields.length; i++)

fields[i].set(result, arg.get(fields[i].getName()));

}catch (Exception e) {throw new ApplicationException (e);

}

return result;

}

The text has an out-of-date example of XML serialization. Nowadays folksuse XStream or other tools.

Matthew Dailey (CSIM-AIT) Patterns 191 / 193

Distribution strategiesConclusion

Remember Fowler’s first law of distribution: don’t distribute!

When you must distribute, use coarse-grained interfaces.

Matthew Dailey (CSIM-AIT) Patterns 192 / 193

Page 97: Readings - Computer Science and Information …mdailey/class/sw-arch/07-Patternsx2.pdf · Readings Readings for these lecture notes: - Fowler (2002), ... always incomplete to some

Conclusion

As you begin to architect a complex system or design a component, it’scrucial to research appropriate patterns.

A novice architect with an understanding of patterns can get it right thefirst time.

An experienced architect moving into a new application area withoutexploring existing patterns may waste time or kill a project.

Avoid the NIH syndrome!

Matthew Dailey (CSIM-AIT) Patterns 193 / 193