persistence framework

49
Designing a Persistence Framework with Patterns

Upload: nicholas-johnson

Post on 18-Jul-2016

31 views

Category:

Documents


1 download

DESCRIPTION

ssss

TRANSCRIPT

Designing a Persistence Framework

with Patterns

Persistent Objects

• Storage mechanisms:

– Object databases

– Relational databases

– Other – flat files, XML structures, hierarchical

databases, etc.

• Object-Relational (O-R) mapping service:

maps an object to a relational record.

Persistence Frameworks

• Persistence framework: general-purpose,

reusable, extendable set of types that

provides functionality to support persistent

objects.

– Persistence service: subsystem created by

persistence framework.

• In technical services layer.

• Called an O-R mapping service for RDB’s.

Materialization

• Transforming a non-object representation

of data from a persistent store into objects.

– Lazy materialization: an instance is only

materialized on demand, when needed.

• Implemented by a Virtual Proxy

– Caching: materialized objects are typically

cached for performance.

• Dematerialization (passivation):

– The reverse transformation.

Representing Objects as Tables

• Pattern: define a table in an RDB for each

persistent object class.

– Primitive object attributes map to columns.

– Attributes that refer to other complex objects

is more complicated.

Key Ideas

• Mapping between a class and its persistent store and between object attributes and the fields in a record

• Object identity – to easily relate records to objects and ensure there are no inappropriate duplicates, records and objects have a unique identifier

• Database mapper – pure fabrication object responsible for materialization and dematerialization

6

Key Ideas

• Caches – persistence services cache

materialized for performance

• Transaction state of object – State of

objects in relation to the current

transaction. Which objects are dirty?

• Transaction operations – Commit and

Rollback

7

Key Ideas

• Lazy materialization – not all objects are

materialized at once; materialization on

demand

• Virtual proxies – Lazy materialization can

be implemented using a smart reference

known as a virtual proxy

8

Mapping

Between a class and its persistent store

Between object attributes and fields in a record

Mapping objects and tables

Manufacturer

name

city

...

...

name city

Now&Zen Mumbai

MANUFACTURER TABLE

: Manufacturer

name = Now&Zen

city = Mumbai

Celestial

ShorteningSan Ramon

Object Identifier

Object Identifier Pattern

• Assign an object identifier (OID) to each

record and object (or proxy of an object).

– Relates records to objects.

– Avoids duplicates.

– Usually alphanumeric value.

– In object-land, represented by an OID

interface or class.

– In RDB, usually a fixed-length char value.

• Every table has an OID as primary key.

• Maps every object to some row in some table.

Fig. 37.3 OIDs link objects and records

OID

xyz123

abc345

This is a simplified design.

In reality, the OID may be

placed in a Proxy class.

primary key

Manufacturer

city

name

oid : OID

...

...

name city

Now&Zen Mumbai

MANUFACTURER TABLE

: Manufacturer

city = Mumbai

name = Now&Zen

oid = xyz123

Celestial

ShorteningSan Ramon

Accessing a Persistence Service with a Façade

• Façade provides a unified interface to a

subsystem.

– Operation to retrieve an object given OID.

• Type of object to materialize is also needed.

– Operation to store an object (dematerialize).

• Façade delegates requests to subsystem

objects.

Fig. 37.4 The Persistence Façade

1

PersistenceFacade

...

getInstance() : PersistenceFacade

get( OID, Class ) : Object

put( OID, Object )

...

: DBProductsAdapter1

: PersistenceFacade

pd = get(...)

// example use of the facade

OID oid = new OID("XYZ123");

ProductDescription pd = (ProductDescription) PersistenceFacade.getInstance().get( oid, ProductDescription.class );

Database Mapper

Database Mapper Pattern

• Direct mapping: persistent object class

defines the code to save itself in a DB.

– Strong coupling to persistent storage.

– Reduced cohesion: technical services mixed

with application logic.

• Indirect mapping: create a class that is

responsible for materialization,

dematerialization and object caching.

– Database Mapper or Database Broker.

– Different mapper class for each persistent

object class.

Fig. 37.5 Database Mappers

each mapper gets and puts objects in its own unique way,

depending on the kind of data store and format

1

PersistenceFacade

getInstance() : PersistenceFacade

get( OID, Class ) : Object

put( OID, Object )

...

ProductSpecification

RDBMapper

...

get( OID) : Object

put( OID, Object )

...

ProductSpecification

FlatFileMapper

...

get( OID) : Object

put( OID, Object )

...

Manufacturer

RDBMapper

...

get( OID) : Object

put( OID, Object )

...

note that the Class as a

parameter is no longer

needed in this version of

get, as the class is

"hardwired" for a particular

persistent type

1

«interface»

IMapper

get(OID) : Object

put( OID, Object )

...

Class

UML notation: This is a qualified assocation. It means:

1. There is a 1-M association from PersistenceFacade to IMapper objects.

2. With a key of type Class, an IMapper is found (e.g., via a HashMap lookup)

Template Method Pattern (GoF)

• Define a method in a superclass that

defines the skeleton of an algorithm, with

its varying and unvarying parts.

– Invokes other methods (“hook” methods),

some of which may be overridden in a

subclass to provide unique behavior at points

of variability.

– Template method is typically public, hook

methods protected.

Fig. 37.7 Template Method for mapper objects

Abstract

PersistenceMapper

+ get( OID) : Object {leaf}

# getObjectFromStorage(OID) : Object {abstract}

...

«interface»

IMapper

get(OID) : Object

put( OID, Object )

...

// template method

public final Object get( OID oid )

{

obj := cachedObjects.get(oid);

if (obj == null )

{

// hook method

obj = getObjectFromStorage( oid );

cachedObjects.put( oid, obj );

}

return obj;

} HOOK

TEMPLATE

Fig. 37.8 Overriding the hook method

ProductDescription

RDBMapper

# getObjectFromStorage(OID) : Object

Abstract

PersistenceMapper

+ get( OID) : Object {leaf}

# getObjectFromStorage(OID) : Object {abstract}

...

// template method

public final Object get( OID oid )

{

obj := cachedObjects.get(oid);

if (obj == null )

{

// hook method

obj = getObjectFromStorage( oid );

cachedObjects.put( oid, obj )

}

return obj

}

// hook method override

protected Object getObjectFromStorage( OID oid )

{

String key = oid.toString();

dbRec = SQL execution result of:

"Select * from PROD_DESC where key =" + key

ProductDescription pd = new ProductDescription();

pd.setOID( oid );

pd.setPrice( dbRec.getColumn("PRICE") );

pd.setItemID( dbRec.getColumn("ITEM_ID") );

pd.setDescrip( dbRec.getColumn("DESC") );

return pd;

}

IMapper

Fig. 37.9 Template Method twice to factor common code for RDB

Abstract

RDBMapper

tableName : String

+ «constructor» AbstractRDBMapper( tableName )

# getObjectFromStorage(OID) : Object {leaf}

# getObjectFromRecord(OID, DBRecord) : Object {abstract}

- getDBRecord(OID) : DBRecord

Abstract

PersistenceMapper

+ get( OID) : Object {leaf}

# getObjectFromStorage(OID) : Object {abstract}

...protected final Object

getObjectFromStorage( OID oid )

{

dbRec = getDBRecord( oid );

// hook method

return getObjectFromRecord( oid, dbRec );

}

IMapper

ProductDescription

RDBMapper

+ «constructor» ProductDescriptionRDBMapper(tabName)

# getObjectFromRecord(OID, DBRecord) : Object

// hook method override

protected Object

getObjectFromRecord( OID oid, DBRecord dbRec )

{

ProductDescription pd = new ProductDescription();

pd.setOID( oid );

pd.setPrice( dbRec.getColumn("PRICE") );

pd.setItemID( dbRec.getColumn("ITEM_ID") );

pd.setDescrip( dbRec.getColumn("DESC") );

return pd;

}

private DBRecord getDBRecord OID oid )

{

String key = oid.toString();

dbRec = SQL execution result of:

"Select * from "+ tableName + " where key =" + key

return dbRec;

}

Persistence Framework for NextGen POS

• NextGen-specific classes are in a different

package from general technical services

Persistence package.

– IMapper, AbstractPersistenceMapper, and

AbstractRDBMapper are part of framework.

– ProductDescriptionRDBMapper is a subclass

added by application programmer.

– ProductDescriptionInMemoryTestDataMapper

produces hard-coded objects for testing

without accessing an external DB.

Fig. 37.10 The persistence framework

1

«interface»

IMapper

get(OID) : Object

put( OID, Object )

...

Class

1

+ PersistenceFacade

getInstance() : PersistenceFacade

get( OID, Class ) : Object

put( OID, Object )

...

Abstract

PersistenceMapper

+ get( OID) : Object {leaf}

# getObjectFromStorage(OID) : Object

...

Abstract

RDBMapper

+ AbstractRDBMapper(tableName)

# getObjectFromStorage(OID) : Object {leaf}

# getObjectFromRecord(OID, DBRecord) : Object

- getDBRecord(OID) : DBRecord

Persistence

NextGen Persistence

ProductDescription

RDBMapper

+ ProductDescriptionRDBMapper(tableName)

# getObjectFromRecord(OID, DBRecord) : Object

ProductDescription

FileWithXMLMapper

# getObjectFromStorage(OID) : Object

Sale

RDBMapper

...

# getObjectFromRecord(OID, DBRecord) : Object

ProductDescription

InMemoryTestDataMapper

# getObjectFromStorage(OID) : Object

Cache

Cache Management

• Pattern: Make the Database Mappers

responsible for maintaining a local cache

of materialized objects to improve

performance.

– When objects are materialized, they are

cached, with their OID as key.

– Subsequent requests to the mapper for an

object will be satisfied from the cache if the

object has already been materialized.

A Class for SQL Statements

• Consolidate all SQL operations in a Pure

Fabrication singleton.

– SQL operations: SELECT, INSERT, . . .

– RDB mapper classes collaborate with SQL-

statements class to obtain a DB record or

ResultSet (Java).

– This is preferable to hard-coding SQL

statements into the different RDB mapper

classes.

Example of a SQL-statements Class

• Interface:class RDBOperations

{

public ResultSet getProductDescriptionData(OID oid){…}

Public ResultSet getSaleData( OID oid ) { … }

}

• Mapper:class ProductDescriptionRDBMapper

extends AbstractPersistenceMapper

{ protected Object getObjectFromStorage( OID oid )

{ ResultSet rs = RDBOperations.getInstance().

getProductDescriptionData(oid);

ProductDescription ps = new ProductDescription();

ps.setPrice( rs.getDouble( “PRICE” ) );

ps.setOID( oid );

return ps;

}

Transaction state of Object

Transactional States and the State Pattern

• Assume:

– Persistent objects can be inserted, deleted, or

modified.

– Modifying a persistent object does not cause

an immediate DB update – an explicit commit

operation must be performed.

– The response of an operation depends on the

transactional state of the object:

• An “old dirty” object was modified after retrieval.

• An “old clean” object need not be updated in DB.

• Delete or save causes state change, not commit.

Fig. 37.12 Statechart for PersistentObject

OldClean OldDirty

OldDelete

commit / delete

delete

New

[ from DB][new (not from DB)]

save

commit / update

delete

rollback / reload

rollback / reloadcommit / insert

State chart: PersistentObject

Legend:

New--newly created; not in DB

Old--retrieved from DB

Clean--unmodified

Dirty--modified

Deleted

Fig. 37.13 Persistent object classes extend PersistentObject

PersistenceDomain

ProductDescription

...

PersistentObject

oid : OID

timeStamp:

DateTime

commit()

delete()

rollback()

save()

...

• PersistentObject provides common technical

services for persistence

The State Pattern (GoF)

• Problem: An object’s behavior is

dependent on its state, and its methods

contain case logic reflecting conditional

state-dependent actions.

• Solution: Create state classes for each

state, implementing a common interface.

Delegate state-depended operations from

the context object to its current state obj.

– Ensure the context object always points to a

state object reflecting its current state.

Fig. 37.14 Applying the State pattern

PersistentObject

oid : OID

state : PObjectState

commit()

delete()

rollback()

save()

setState(PObjectState)

...

PObjectState

commit(obj : PersistentObject)

delete(obj : PersistentObject)

rollback(obj : PersistentObject)

save(obj : PersistentObject)

OldDirty

State

commit(...)

delete(...)

rollback(...)

1

OldClean

State

delete(...)

save(...)

New

State

commit(...)

OldDelete

State

commit(...)

rollback(...)

Product

Specification

...

...

Sale

...

...

*

{ state.delete( this ) }

{

// default no-op

// bodies for

// each method

}

{ // delete

obj.setState( OldDeleteState.getInstance() ) }

{ // save

obj.setState( OldDirtyState.getInstance() ) }

{ // rollback

PersistenceFacade.getInstance().reload( obj )

obj.setState( OldCleanState.getInstance() ) }

{ // commit

PersistenceFacade.getInstance().update( obj )

obj.setState( OldCleanState.getInstance() ) }

{ state.rollback( this ) }{ state.commit( this ) }

{ state.save( this ) }

{ // commit

PersistenceFacade.getInstance().insert( obj )

obj.setState( OldCleanState.getInstance() ) }

{ // commit

PersistenceFacade.getInstance().delete( obj )

obj.setState( DeletedState.getInstance() ) }

Transaction Operations

Database Transactions

• Transaction: a unit of work whose tasks

must all complete successfully or none

must be completed.

– Completion is atomic.

– Represent the set of tasks to be done with a

Transaction class.

– The order of database tasks within a

transaction can affect its success and

performance.

• Ordering database tasks can help: generally,

inserts first, then updates, then deletes.

The Command Pattern (GoF)

• Problem: How to handle requests or tasks

that need functions such as prioritizing,

queueing, delaying, logging, or undoing.

• Solution: Make each task a class that

implements a common interface.

– Actions become objects that can be sorted,

logged, queued, etc.

– Each has a polymorphic execute method.

– E.g., command objects can be kept in a

history stack to enable “undo”.

Fig. 37.15 Commands for database operations

«interface»

ICommand

execute( )

undo()

DBInsertCommand

execute()

DBUpdateCommand

execute()

DBDeleteCommand

execute()

Transaction

commands : List

commit()

addDelete(obj:PersistentObject)

addInsert( obj:PersistentObject)

addUpdate( obj:PersistentObject)

sort()

...

1..*

DBCommand

object : PersistentObject

execute() {abstract}

undo() {leaf}

undo is a no-op for

this example, but a

more complex

solution adds a

polymorphic undo

to each subclass

which uniquely

knows how to undo

an operation

PersistentObject

commit()

...1{

commands.add( new DBUpdateCommand(obj) );

}

use SortStrategy objects to allow

different sort algorithms to order the

Commands

perhaps simply

object.commit()

but each Command can

perform its own unique

actions

{

sort()

for each ICommand cmd

cmd.execute()

}

Lazy Materialization with a Virtual

Proxy

Lazy Materialization with a Virtual Proxy

• Virtual Proxy (GoF): a proxy for another

object (the real subject) that materializes

the real subject when it is first referenced.

– A lightweight object that stands for the real

object that may or may not be materialized.

• E.g., a Manufacturer object is rarely used, but a

ProductDescription has attribute visibility to an

IManufacturer instance.

• When ProductDescription sends a getAddress

message to the ManufacturerProxy, it materializes

the real Manufacturer, using its OID.

Fig. 37.16 Manufacturer Virtual Proxy

Manufacturer

Proxy

realSubject : IManufacturer

- getRealSubject() : IManufacturer

+ getAddress()

...

Manufacturer

address

getAddress()

...

«interface»

IManufacturer

getAddress()

...

Proxy-for 1

realSubject

{

return getRealSubject().getAddress()

}

ProductSpecification

manufacturer : IManufacturer

...

getManufacturerAddress() : Address

1

{

if ( realSubject == null )

realSubject = PersistenceFacade.get(oid, Manufacturer.class);

return realSubject;

}

PersistentObject

oid

...

1

{

return manufacturer.getAddress()

}

actually references an

instance of

ManufacturerProxy

1

23

Representing Relationships in Tables

• Representing Object Relationships as

Tables pattern:

– One-to-one associations

• Place an OID foreign key in one or both tables

representing the objects in a relationship, or treat

as a one-to-many association, as below.

– One-to-many associations (a collection) or

many-to-many associations:

• Create an associative table that records the OIDs

of each object in relationship.

Architectural Analysis

Architectural Analysis

• Focus on requirements that strongly

influence the architecture.

– e.g Secure system.

• Focus on Non-Functional requirements.

• Identify variation points(e.g third party

services) and evolution points(in future).

Architectural Analysis

• Steps in Architectural Analysis.

– Identify and analyze the non-functional

requirements

– Analyze alternatives

• Remove requirement, Hire an expert etc

• Architectural design principles

– High cohesion

– Low coupling

– Protected variations

Logical architecture refinement

Logical architecture refinement

• Interlayer collaboration

(UI,DOMAIN,TECHNICAL SERVICE

layer)

• Apply façade, observer and controller

pattern.

Package design

Package design

• Organize packages to reduce the impact

of changes.

• Relational Cohesion(RC)

RC= pesNumberofty

ionernalrelatnumberof int

Low RC=>package contain unrelated thing