persistence framework
DESCRIPTION
ssssTRANSCRIPT
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 objects and tables
Manufacturer
name
city
...
...
name city
Now&Zen Mumbai
MANUFACTURER TABLE
: Manufacturer
name = Now&Zen
city = Mumbai
Celestial
ShorteningSan Ramon
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 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 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;
}
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() ) }
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
• 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
• 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
• Interlayer collaboration
(UI,DOMAIN,TECHNICAL SERVICE
layer)
• Apply façade, observer and controller
pattern.