Enterprise application architecture
Download
Report
Transcript Enterprise application architecture
ENTERPRISE APPLICATION
ARCHITECTURE
Domain Logic Patterns
Transaction Script
Domain Model
Table Module
Service Layer
Transaction Script
Organizes business logic by procedures
where each procedure handles a single
request form the presentation
TS: How It Works
Each business transaction corresponds to one
transaction script
Business transaction: Book a hotel room
Tasks: check room availability, calculate rates, update
the database – all handled in one BookARoom script.
Transaction scripts access the database directly
Don’t call any logic in the presentation layer
Organization
Each script is a procedure
Related scripts are enclosed in one class
Each script is in one class.
TS: Architecture
TransactionScript
businessTransaction1()
businessTransaction2()
businessTransaction3()
Gateway
sql_query= “ SELECT * FROM table 1…”
sql_insert = “INSERT into tablei…”
sql_update = “ UPDATE tablei …”
sql_delete = “DELETE FROM …”
findDataForBusinessTransaction1(sql_query)
insertRecordsForBusinessTransaction1(sql_insert, items)
updateRecordsForBusinessTransaction2(sql_update, items)
…
DB
TS: When to use it
When the domain logic is very simple
When transactions do not have a lot of
overlap in functionality
Example Revenue Recognition
A contract is signed for one product
The revenue of a contract may not be recognized
right away.
Different types of product may have different
revenue recognition schedule
Three types of product
Word Processor: revenue recognized right away
Spreadsheet: 1/3 today, 1/3 in 60 days, 1/3 in 90 days.
Database: 1/3 today, 1/3 in 30 days, 1/3 in 60 days.
Product
Name
type
1 *
Contract
date _signed
revenue
1 *
RevenueRecognition
Amount
date
TS: Example
RecognitionService
calcRecognitions(contract#)
recognizedRevenue(contract#, date)
createContract(id, revenue, prod_id, date)
…
DatabaseGateway
Sql_findContract = “ SELECT * FROM Contract WHERE id = ?”
Sql_findRecogns = “select* from recog Where cid=? and date<?”
Sql_insertContract = “INSERT into contract…”
findContract(contract#)
findRecognitionsFor(contract#, date)
insertRecognition(contract#, revenue, date)
…
DB
Sequence Diagram: test cases
:Tester
:RecognitionService
:DatabaseGateway
:Database
createContract()
insertContract()
INSERT into contract …
calcRecognitions()
insertRecognition()
insertRecognition()
insertRecognition()
INSERT iinto Recog…
INSERT iinto Recog…
INSERT iinto Recog…
recognizedRevenue()
findRecognitionsFor()
SELECT * FROM …
TS: Example
class Gateway {
static String findRecogns = “SELECT * FROM
revenueRecognition WHERE contract = ? And date <= ?”;
static String findContract = “SELECT * FROM
contract c, product p WHERE c.id = ? And c.pid = p.id”;
public ResultSet findRecognitionsFor(int contrno, Date d)
{
PreparedStatement s = db.prepareStatement(findRecongs);
s.setInt(1, contrno);
s.setDate(2, d);
ResultSet result = s.executeQuery();
return result;
}
public ResultSet findContract(int contrno) {
PreparedStatement s = db.prepareStatement(findContract);
s.setInt(1, contrno);
ResultSet result = s.executeQuery();
return result;
}
}
TS: Example
class RecognitionService {
private Gateway gw = new Gateway();
public Money recognizedRevenue(int contrno, Date d) {
Money Result = Money.dollar(0);
ResultSet rs = gw.findRecognitionsFor(contrno, d);
while (rs.next()) {
result = result.add(rs.getBigDecimal(“amount”));
}
return result;
}
public void calculateRevenueRecognitions(int contrno) {
ResultSet contrs = gw.findContract(contrno);
totalRevenue = contrs.getBigDecimal(“revenue”);
dates = contrs.getDate(“date_signed”);
type = contrs.getChar(“type”);
if (type == ‘S’) {
db.insertRecognition(contrno, totalRevenue/3, date);
db.insertRecognition(contrno, totalRevenue/3, date+60);
db.insertRecognition(contrno, totalRevenue/3, date+90);
} else if (type = ‘W’) {
db.insertRecognition(contrno, totalRevenue, date);
} else if (type == ‘D’ {
...
}
...
Domain Model
An object model of the domain that
incorporates both behavior and data
DM: Revenue Recognition
Contract
date _signed
revenue
recognizedRevenue(date)
calculateRecognitions()
*
1
Product
Name
type
calcRecognitions(contrct)
*
1
RecognitionStrategy
calcRecognitions(contrct)
1
*
RevenueRecognition
Amount
date
isRecognizableBy(date)
DB
Three-way
RecognitionStrategy
Complete
RecognitionStrategy
DM: Example
class RevenueRecognition {
private Money amount;
private Date date;
public RevenueRecognition(Money amnt, Date d) {...}
public Money getAmount() {
return amount;
}
public boolean isRecognizableBy(Date date) {
return this.date.before(date) || this.date.equals(date);
}
...
}
class Contract {
private List revenueRecognitions = new ArrayList();
public Money recognizedRevenue(Date date) {
Money result = Money.dollar(0);
Iterator it = revenueRecognitions.iterator();
while (it.hasNext()} {
RevenueRecognition r = (RevenueRecognition)it.next();
if (r.isRecognizableBy(date))
result = result.add(r.getAmount());
}
return result;
}
...
DM: Example
class RevenueRecognition {
private Money amount;
private Date date;
public RevenueRecognition(Money amnt, Date d) {...}
public Money getAmount() {
return amount;
}
public boolean isRecognizableBy(Date date) {
return this.date.before(date) || this.date.equals(date);
}
...
}
class Contract {
private List revenueRecognitions = new ArrayList();
public Money recognizedRevenue(Date date) {
Money result = Money.dollar(0);
Iterator it = revenueRecognitions.iterator();
while (it.hasNext()} {
RevenueRecognition r = (RevenueRecognition)it.next();
if (r.isRecognizableBy(date))
result = result.add(r.getAmount());
}
return result;
}
...
DM: Example
class Contract {
private Product product;
private Money amount;
private Date dateSigned;
private long id;
public Contract(Product p, Money amnt, Date d) {...}
public void addRecognition(RevenueRecognition rr) {
revenueRecognitions.add(rr);
}
public Date getDateSigned() {
return dateSigned;
}
public void calcRecognitions() {
product.calcRecognitions(this);
}
...
}
interface RecognitionStrategy {
public void calcRevenueRecognitions(Contract c);
}
DM: Example
class CompleteRecognitionStrategy implements ... {
public void calcRevenueRecognitions(Contract c) {
c.addRecognition(new RevenueRecognition(
c.getAmount(), c.getDateSigned());
}
}
class ThreeWayRecognitionStrategy implements ... {
private int firstRecognitionOffset;
private int secondRecognitionOffset;
public ThreeWayRecognitionStrategy(int offset1, int offset2) {
this.firstRecognitionOffset = offset1;
this.secondRecognitionOffset = offset2;
}
public void calcRevenueRecognitions(Contract c) {
c.addRecognition(new RevenueRecognition(
c.getAmount()/3, c.getDateSigned());
c.addRecognition(new RevenueRecognition(
c.getAmount()/3, c.getDateSigned()+offset1);
c.addRecognition(new RevenueRecognition(
c.getAmount()/3, c.getDateSigned()+offset2);
}
... }
DM: Example
class Product {
private String name;
private RecognitionStrategy recogStrategy;
public Product(String name, RecognitionStrategy rs) {
this.name = name;
this.recogStrategy = rs;
}
public void calcRecognitions(Contract c) {
recogStrategy.calcRecognitions(c);
}
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));
}
}
DM: Example
class Tester {
public static void main(String[] args) {
Product word = Product.newWordProcessor(“IntelWord”);
Product calc = Product.newSpreadsheet(“calc II”);
Product db = Product.newDatabse(“DB IV”);
Date today = System.today();
Contract c1 = new Contract(word, 300000, today);
c1.calcRecognitions();
Contract c2 = new Contract(calc, 24000, today);
c2.calcRecognitions(); // sequence diagram – next slide
Contract c3 = new Contract(db, 540000, today);
c3.calcRecognitions();
System.out.println(c1.recognizedRevenue(today + 10));
System.out.println(c2.recognizedRevenue(today + 70));
System.out.println(c3.recognizedRevenue(today + 80));
}
}
DM: Sequence Diagram: c2.calcRecognitions()
:Tester
c2.:Contract
recogStrategy:RecognitionStrategy
product:Product
calcRecognitions()
calcRecognitions(c2)
calcRecognitions(c2)
Mount = getAmount()
date = getDateSigned()
(amount/3, date)
addRecognition(rr1)
(amount/3, date + 60)
addRecognition(rr2)
(amount/3, date + 90)
addRecognition(rr3)
rr1:RevenueRecognition
rr2:RevenueRecognition
rr3:RevenueRecognition
DM: Sequence Diagram: c2.recognizedRevenue()
:Tester
c2.:Contract
rr[0]:RevenueRecognition
recognizedRevenue(date)
isRecognizableBy(date)
getAmount()
isRecognizableBy(date)
getAmount()
isRecognizableBy(date)
return result
rr[1]:RevenueRecognition
rr[2]:RevenueRecognition
Table Module
A single instance that handles the business
logic for all rows in a database table or view
Each module is responsible for all the CRUD
operations on the corresponding table.
No other modules are supposed to CRUD directly
on the table
Each module also includes business logic that is
tightly related to the table.
TM: Architecture
TableModule_1
CRUD operations on Table_1
Business Logic related to Table_1
TableModule_2
CRUD operations on Table_2
Business Logic related to Table_2
Table_1
Attributes
Table_2
Attributes
Database
TableModule_n
CRUD operations on Table_n
Business Logic related to Table_n
Table_n
Attributes
TM: Example - Tables
Contract
Id:
dateSigned:
revenue:
prod_id:
Number
Date
Number
Number (FK)
RevenueRecognition
Id:
amount:
date:
c_id:
Product
Id:
Number
name: String
type:
String
Number
Number
Date
Number (FK)
TM: Example - Modules
Contract
RevenueRecognition
Insert(cid, revenue, prod_id, date)
calculateRecognitions(c_id)
Insert(c_id, amount, date)
recognizedRevenue(c_id, date)
Product
getProductType(prod_id)
DB
TM: Sequence Diagram: calcRecognitions()
:Tester
:RevenueRecognition
:Contract
:Product
calcRecognitions(cid)
getContract(id)
contract:ResultSet
DB
SELECT
getProductID()
getProductType(pid)
SELECT
getRevenue()
getDateSigned()
return result
insert(cid, revenue/3, date)
INSERT
insert(cid, revenue/3, date+60)
INSERT
insert(cid, revenue/3 date+90)
INSERT
TM: Sequence Diagram: recognizedRevenue()
:Tester
:RevenueRecognition
:Contract
recognizedRevenue(c_id, date)
getRecognitions(c_id, date)
recognitions:ResultSet
getAmount()
getAmount()
getAmount()
return result
DB
SELECT
Service Layer
Defines an application’s boundary with a
layer of services that establishes a set of
available operations and coordinates the
application’s response in each operation.
Two type of business logic
Domain logic: pure logic of the business domain
E.g., calculating revenue recognitions of a contract
Application logic: application responsibilities
E.g., notifying administrators and integrated
applications, of revenue recognition calculations
TM: Example - Modules
Data Loader
Integration
Gateways
Service Layer
Domain Model
DB
User Interfaces
SL: Architecture
Domain logic: Domain model layer
Application logic: Service layer
Service layer:
Operation Scripts – A set of classes that
implement application logic but delegate to
domain model classes for domain logic.
Clients interact with the operation scripts
Operation scripts for a subject area are
encapsulated in a class named SubjectService.
SL: Services and Operations
Determined by the needs of clients
Derived from use case models
Data validation
CRUD operations on domain objects
Notification of people or other integrated
applications
All responses must be coordinated and transacted
automatically by the service layer
SL: When to Use It
When there are many different kinds of
clients
When the response may involve application
logic that needs to be transacted across
multiple transactional resources
SL: Example
Revenue Recognition
New requirements: once revenue recognitions are
calculated, it must
Email a notification to contract administrators
Publish a message to notify other integrated
applications
SL: Example
ApplicationService
getEmailGateway(): EmailGateway
getIntegrationGateway(): IntegrationGateway
EmailGateway
IntegrationGateway
sendEmail(toAddr, subj, body)
publishRevenueRecogs(contract)
RecognitionService
calcRevenueRecogs(contr#)
recognizedRevenue(contr#, date)
Domain Model
Contract
RevenueRecognition
Product
SL: Example
class RecognitionService extends ApplicationService {
public void calcRevenueRecogs(contractNo) {
Transaction trans = Transaction.getNewTransaction();
trans.begin();
// delegate to domain objects
Contract contract = Contract.getContract(contractNo);
contract.calcRecognitions();
Contract c2 = new Contract(calc, 24000, today);
// interact with transactional sources
getEmailGateway().sendEmail(contract.getAdminEmail(),
“RE: contract revenue recognitions”,
contract.getId()
+”Recognitions calculated”);
getIntegrationGateway().publishRevenueRecogs(contract);
trans.commit();
}
}
Domain Logic: Summary
Transaction Script
One script per user request/action
Good for simple, no-overlapping business logic
Domain Model
A set of interrelated objects for business logic
Good for application with complex business logic
Table Module
A module for the CRUD operations and business logic for a table
in DB
Compromise between Transaction Script and Domain Model
Service Layer
Application logic is separated into a new layer from domain logic
Good for applications that have complex application logic –
interacting with multiple transactional resources