Title: Nested Collaborations
1Nested Collaborations
2Collaboration reuse
- We want to reuse collaborations at two levels
- Refined collaborations
- similar to is-a relationship between classes
- Nested collaborations
- similar to has-a relationship between classes
- This idea was already in contracts (Helm, Holland
et al.) and in Hollands thesis.
3Boolean Collaborations
- Collaboration is trivial only one participant
- Example is realistic because we want to record
the result history. - Example indicates that each subcollaboration
should be represented by an object. - Only in special cases can collaborations be
implemented by code insertion only.
4Recording And Collaboration
collaboration And participant D boolean
res public Vector r new Vector()// result
history public boolean andR() res
input1() and input2() r.append(new
Boolean(res) return res expect
boolean input1() expect boolean input2()
Each time andR() is called, return value will
be stored in a vector local to participant D.
5Recording Or Collaboration
collaboration Or participant D boolean
res public Vector r new Vector()// result
history public boolean orR() res
input1() or input2() r.append(new
Boolean(res) return res expect
boolean input1() expect boolean input2()
Each time orR() is called, return value will
be stored in a vector local to participant D.
6Compose Collaborations
collaboration
AndOr
instances
And
And
AndInstance
Or
Or
OrInstance
7collaboration AndOr participant D
expect boolean input1() expect boolean
input2() expect boolean input3() public
boolean andOrR() return AndAdapter.D.andR()
public void andOrStatistics()
System.out.println(AndAdapter.D.r(true)
System.out.println(AndAdapter.D.r(false)
System.out.println(OrAdapter.D.r(true)
System.out.println(OrAdapter.D.r(false)
adapter AndAdapter AndOr.D plays And.D
boolean input1() return AndOr.D.input1()
boolean input2() return OrAdapter.D.orR()
adapter OrAdapter AndOr.D plays Or.D
boolean input1() return AndOr.D.input2()
boolean input2() return AndOr.D.input3()
8with Pengcheng 1
collaboration AndOr participant D
expect boolean input1() expect boolean
input2() expect boolean input3() public
boolean andOrR() return AndInstance.D.andR()
public void andOrStatistics()
System.out.println(AndInstance.D.r(true)
System.out.println(AndInstance.D.r(false)
System.out.println(OrInstance.D.r(true)
System.out.println(OrInstance.D.r(false)
adapter for And creating AndInstance
AndOr.D plays And.D boolean input1()
return AndOr.D.input1() boolean input2()
return OrInstance.D.orR() adapter for Or
creating OrInstance AndOr.D plays Or.D
boolean input1() return AndOr.D.input2()
boolean input2() return AndOr.D.input3()
9with Pengcheng 2
collaboration AndOr participant D
expect boolean input1() expect boolean
input2() expect boolean input3() public
boolean andOrR() Or.D d new Or.D()
boolean res1 d.orR() return (new
And.D.andR() public void andOrStatistics()
System.out.println(AndInstance.D.r(true)
System.out.println(AndInstance.D.r(false)
System.out.println(OrInstance.D.r(true)
System.out.println(OrInstance.D.r(false)
adapter creating AndInstance AndOr.D
plays And.D boolean input1() return
AndOr.D.input1() boolean input2() return
OrInstance.D.orR() adapter creating
OrInstance AndOr.D plays Or.D
boolean input1() return AndOr.D.input2()
boolean input2() return AndOr.D.input3()
10Conflict with Result Vector?
- No each adapter has its own
11Hardware-style Components
- Can be expressed with nested collaborations
- Adapters are used to instantiate components
- It is important to name adapters
- How should collaborations be implemented? Adapted
collaborations should be represented as objects.
12Methods versus Signals
- The model we use uses methods for input.
- An alternative model would be to use signals on
ports.
13Counting Collaboration
- Have CountingAdapter.BusRoute
- Adapter creates adapter object
- When count() is invoked, count() on adapter
object is invoked? BusRoute.count() calls
CountingAdapter.BusRoute.count(). But we might
have another adapter. Need to rename count in
adapter in that case.
14Better example
- Pricing and Summing add Order participant to
participant graph of Pricing. - Call it OrderPricing because it computes the cost
of an order not just of a line item. Both
negotiated and regular price. - Mapping for Pricing is identity? Mapping for
Summing is Source -gt Order, Target -gt LineItem.
15LineItemPricing example
collaboration LineItemPricing private
int qty private float unitPrice
participant LineItem //OrderUnit
abstract Product getProduct() // abstract
instead of expect abstract Pricer
getPricer() abstract Customer
getCustomer() abstract int
getQuantity() public float price()
qty getQuantity()
prod getProduct() k
getCustomer() unitPrice
getPricer().unitPrice(prod, k)
float price unitPrice getProduct().extraCos
ts() return price
Expected Interface
Provided Interface
LineItem Product Pricer Customer ltquantitygt
int. Product List(ExtraCost). Customer .
Pricer . ExtraCost .
16 participant Product abstract
ExtraCost getExtraCosts() private
float extraCosts() float total 0
while (getExtraCosts().hasElement())
total getExtraCosts().next().getAmount(qt
y, unitPrice, this) return total
participant Pricer abstract float
getBasicPrice(Product prod) abstract
float getDiscount(Product prod, Customer k)
private float unitPrice(Product prod, Customer
k) float basicPr
getBasicPrice(prod) return basicPr
- (getDiscount(prod, k) basicPr)
participant ExtraCost abstract float
getAmount(int qty, float unitPrice, Product
prod)
17OfficeProduct. basicPrice
Fig 1a OrderPricing
PriceForLineItem SumForPrice
Order
Tax
Source
sum
Order. price
ProductCategory
Summing
LineItem
Target
toSum
price
OfficeProduct
LineItemPricing
LineItem
Pricer
Product
Customer
ExtraCost
18RPriceForLineItem SumForRPrice NPriceForLineItem S
umForNPrice
OrderPricing
sum
rprice
Order
sum
nprice
Source
ProductCategory
Source
Summing
Summing
LineItem
toSum
toSum
Target
Target
price
OfficeProduct
price
LineItemPricing
LineItem
LineItemPricing
LineItem
Pricer
Product
Customer
Pricer
Product
Customer
19Summing Collaboration
collaboration Summing participant
Source expect TraversalGraph getT()
public int sum () // traversal/visitor weaving
getT().traverse(this, new Visitor() int r
public void before(Target host)
rrhost.toSum() public void start()
r 0 ) participant Target expect
int toSum()
Base regular Meta variable bold Keywords
underscore
20Composed collaboration OrderPricing
- // Participant graph first only for negotiated
price, followed by regular - // price
- Order ltproductCategoriesgt List(ProductCategory)
Customer. - ProductCategory Name List(LineItem).
- LineItem OfficeProduct Pricer Customer
ltquantitygt int. - OfficeProduct ltextraCostsgt List(Tax).
- Tax .
- Customer .
- Pricer .
- // Customer in Order is transported to Customer
in LineItem
21Adapter SumForPrice
- adapter SumForPrice
- Order is Summing.Source
- with
- TraversalGraph getT()
- ClassGraph classGraph1 new
ClassGraph() - return new TraversalGraph(classGraph1,
- new Strategy(from Order to
LineItem)) -
- LineItem is Summing.Target with
- int toSum NegPriceForOrder.LineItem.price()
-
-
22Adapter NegPriceForLineItem
- adapter NegPriceForLineItem
- LineItem is LineItemPricing.LineItem
- OfficeProduct is LineItemPricing.Product
- Customer is LineItemPricing.Pricer with
- float getBasicPrice (Product p)
- return negotiatedPrice(p)
- float getDiscount(Product p, Customer c)
- return negotiatedDiscount(p)
- Tax is ExtraCost
- with
-
-
23NegOrderPricing Aspect Pattern
collaboration NegOrderPricing
participant Order public int negPrice ()
SumForPrice.Order.sum() // participant graph
and the adapters SumForPrice and //
NegPriceForOrder seen earlier
Base regular Meta variable bold Keywords
underscore
24Now add regular price computation
- Need a new adapter for summing regular prices
notice need to parameterize adapters - Need a new adapter for computing regular price
- Need to distinguish between two price methods
regPrice and negPrice.
25Adapter SumRegForPrice
- adapter SumForRegPrice
- Order is Summing.Source
- with
- TraversalGraph getT()
- ClassGraph classGraph1 new
ClassGraph() - return new TraversalGraph(classGraph1,
- new Strategy(from Order to
LineItem)) -
- LineItem is Summing.Target with
- int toSum RegPriceForLineItem.LineItem.pric
e() -
-
26Adapter RegPriceForOrder
- adapter RegPriceForOrder
- LineItem is LineItemPricing.LineItem
- OfficeProduct is LineItemPricing.Product
- OfficeProduct is LineItemPricing.Pricer with
- float getBasicPrice (Product p)
- return p.regPrice()
- float getDiscount(Product p, Customer c)
- return p.regDiscount()
- Tax is ExtraCost
- with
-
-
27OrderPricing Aspect Pattern
collaboration OrderPricing
participant Order public int negPrice ()
SumForPrice.Order.sum() // participant graph
and the adapters SumForPrice and //
NegPriceForOrder seen earlier public int
regPrice () SumForRegPrice.Order.sum() //
participant graph and the adapters SumRegForPrice
and // RegPriceForOrder seen earlier
Base regular Meta variable bold Keywords
underscore
28connector RegularPrice Bestellung is
LineItemParty Büromaterial is Pricer with
float getBasicPrice(Product p)
return p.regPreis() float
getDiscount(Product p, Customer c)
return p.regDiscount(c)
Büromaterial is Product with
ExtraCost extraCosts() ... Steuer is
ExtraCost with float getAmount (...)
...
Role of Pricer is once played by Kunde and once
by Büromaterial
29Need for collaboration composition
- Need two instances of the summing collaboration.
- Need to instances of the line item cost
collaboration.
30Collaborations
- Collaboration
- Participant graph for each participant a
provided and required interface - Set C of reused collaboration names and the
corresponding adapters
31Tim Sheard
- Mark meta variables
- express meta code
- show how base code can become meta code
32Example Count Aspect Pattern
aspect pattern Counting participant
Source expect TraversalGraph getT()
public int count () // traversal/visitor
weaving getT().traverse(this, new
Visitor() int r public void
before(Target host) r public void
start() r 0 ) participant Target
Base Meta variable bold Keywords underscore
33Adapter 1
classGraph1 is fixed and therefore the traversal
is fixed
- adapter CountingForBusRoute1
- BusRoute is Counting.Source
- with
- TraversalGraph getT()
- ClassGraph classGraph1 new
ClassGraph() - return
- new TraversalGraph(classGraph1,
- new Strategy(from BusRoute via
BusStop to Person)) -
- Person is Counting.Target
-
-
34Aspect Pattern Partial Evaluation
- Because the class graph is fixed for
CountingForBusRoute1, it can be frozen and a more
efficient specialization can be produced. - aspect specialization
- CountingForBusRoute1
- freeze getT() in
- getT().traverse()
Visitor constant too!
35Aspect pattern example
aspect pattern Pricing private int qty
private float unitPrice
participant LineItemParty //OrderUnit
abstract Product getProduct() // abstract
instead of expect abstract Pricer
getPricer() abstract Customer
getCustomer() abstract int
getQuantity() public float price()
qty getQuantity()
prod getProduct() k
getCustomer() unitPrice
getPricer().unitPrice(prod, k)
float price unitPrice getProduct().extraCos
ts() return price
Expected Interface
Provided Interface
LineItemParty Product Pricer Customer
ltquantitygt int. Product List(ExtraCost). Custome
r . ? Pricer .
36 participant Product abstract
ExtraCost getExtraCosts() private
float extraCosts() float total 0
while (getExtraCosts().hasElement())
total getExtraCosts().next().getAmount(qt
y, unitPrice, this) return total
participant Pricer abstract float
getBasicPrice(Product prod) abstract
float getDiscount(Product prod, Customer k)
private float unitPrice(Product prod, Customer
k) float basicPr
getBasicPrice(prod) return basicPr
- (getDiscount(prod, k) basicPr)
participant ExtraCost abstract float
getAmount(int qty, float unitPrice, Product
prod)
37Aspect Patterns Adapters
Price computation
Office material vendor
Java code
38adapter RegularPrice Bestellung is
LineItemParty Büromaterial is Pricer with
float getBasicPrice(Product p)
return p.regPreis() float
getDiscount(Product p, Customer c)
return p.regDiscount(c)
Büromaterial is Product with
ExtraCost extraCosts() ... Steuer is
ExtraCost with float getAmount (...)
...
Role of Pricer is once played by Kunde and once
by Büromaterial
39(No Transcript)
40Example Feature-oriented Programming
- Dependent aspects
- Order of deployment is relevant
41DataWithCounter pairwise interaction
Data/Counter
- aspect pattern DataWithCounter
- private participant Counter int i0
- void reset()i0 void inc() void
dec() - participant DataStructure
- protected Counter counter
- expect void initCounter()
- expect void make_empty()
- expect void push(Object a)
- expect void pop()
- replace void make_empty()counter.reset()e
xpected() - replace void push(Object a)counter.inc()
expected(a) - replace void pop() counter.dec()expected(
) -
-
42DataWithCounter pairwise interaction
Data/Counter
DataWithCounter
make_empty push pop
make_empty push pop
43DataWithLock Patternpairwise interaction
Data/Lock
- aspect pattern DataWithLock
- participant Data
- Lock lock
- expect void initLock()
- expect AnyType method_to_wrap(Object
args) - replace AnyType method_to_wrap(Object
args) - if (lock.is_unlocked())
- lock.lock()
- expected(Object args)
- lock.unlock()
- private participant Lock boolean l true
- void lock()
- void unlock()
- boolean is_unlocked()return l
-
44DataWithLock Patternpairwise interaction
Data/Lock
DataWithLock
method_to_wrap
method_to_wrap
45DataWithCounter
StackImpl
Counter
QueueImpl
Lock
DataWithLock
46First adapter
- adapter addCounterAndLock
- StackImpl is DataWithCounter.DataStructure
- with
- void initCounter() counter new Counter()
- void push(Object obj) push(obj)) // use
name map instead - Object top() return top()
- ...
-
- StackImpl is DataWithLock.Data
- with
- method_to_wrap pop, push, top,
make_empty, initCounter -
- QueueImpl is DataWithCounter.DataStructure with
- ... is DataWithLock.Data with ...
-
47DataWithCounter
DataWithLock
DataWithCounterAndLock
48DataWithCounter pairwise interaction
Data/Counter
DataWithCounter
make_empty push pop
make_empty push pop
49DataWithLock Patternpairwise interaction
Data/Lock
DataWithLock
method_to_wrap
method_to_wrap
50DataWithCounterAndLockpattern composition
make_empty push pop
make_empty push pop
DataWithCounter
DataWithLock
make_empty push pop
to-wrap
Name stays the same, but behavior changes Should
composed component have its interface computed?
Yes?
51Method flow diagram
- Composition of aspect patterns defines method
flow - Methods come in and out of patterns
- Patterns may create new methods and absorb
methods - Graph nodes are pattern, edges are methods
- What about participant graph? Participant name
part of method name. - Should nodes have ports?
- Multiple edges in, multiple edges out
52Create composed aspects prior to deployment
- aspect pattern DataWithCounterAndLock
- uses DataWithCounter, DataWithLock
- participant Data
- expect void make_empty()
- expect void push(Object a)
- expect void pop()
-
- adapter DataWithCounterA
- Data is DataWithCounter.DataStructure //
identity name map - adapter DataWithLockA
- Data plays DataWithLock.Data with
- method-to-wrap replaced methods of
DataWithCounterA -
- // ordering of adapters is relevant
53Create composed aspects prior to deployment
- Do we need this nested adapter syntax?
- aspect pattern DataWithCounterAndLock
- participant Data
- DataWithCounter.DataStructure is
- DataWithLock.Data with
- method-to-wrap
- make_empty, pop, push
-
54Create composed aspects prior to deployment
- aspect pattern DataWithCounterAndLock
- participant Data
- DataWithCounter.DataStructure is
- DataWithLock.Data with
- method-to-wrap
- make_empty, pop, top, push
-
Instantiate DataWithCounter and DataWithLock
55Second connector Deploy composed component
- connector addCounterLock
- StackImpl is DataWithCounterAndLock.Data with
- void make_empty() empty()
- void initCounter()
- counter new Counter()
- void push(Object obj) push(obj)
- ...
-
- QueueImpl is DataWithCounterAndLock.Data with
... -
56Doug Schmidt
- Apply collaborations and adapters to express
middleware Namingserver, EventChannel - Express basic patterns, compose them to core
functionality. Add synchronization, persistence,
and later real-time aspects. Compare handwritten
code with generated code.