Reference counting
The following pattern is another example that you can use to to keep a count of how many clients are using a particular service object, which in turn can be used to determine the lifetime of these service objects. The example subscription management mechanism is fairly sophisticated, possibly too sophisticated, but it provides the big advantage of separating the concerns by using two monitors. If you decide to change the subscription mechanism, you can do so simply by changing the ServiceManager monitor. There is no impact at all on the ServiceItem monitor.
The events:
package com.apamax.service;
event Subscribe {
string toWhat;
string originator;
}
event Unsubscribe {
string fromWhat;
string originator;
}
event CreateServiceItem {
string what;
}
event DestroyServiceItem {
string what;
}
The monitors:
monitor ServiceManager {
dictionary < string, dictionary < string, integer > > items;
action onload() {
Subscribe s;
Unsubscribe u;
on all Subscribe():s subscribe(s);
on all Unsubscribe():u unsubscribe(u);
}
action subscribe(Subscribe s){
if items.hasKey(s.toWhat) then {
dictionary < string, integer > subscriptions :=
items[s.toWhat];
if subscriptions.hasKey(s.originator) then {
subscriptions[s.originator] :=
subscriptions[s.originator] + 1;
}
else {
subscriptions[s.originator] := 1;
}
}
else {
items[s.toWhat] := subscriptions;
route CreateServiceItem(s.toWhat);
}
}
action unsubscribe(Unsubscribe u) {
if items.hasKey(u.fromWhat) then {
dictionary < string, integer > subscriptions :=
items[u.fromWhat];
if subscriptions.hasKey(u.originator) then {
if subscriptions[u.originator] <= 1 then {
subscriptions.remove(u.originator);
if subscriptions.size() = 0 then {
items.remove(u.fromWhat);
route DestroyServiceItem(u.fromWhat);
}
}
else {
subscriptions[u.originator] :=
subscriptions[u.originator] - 1;
}
}
else {
print "Unsubscribe failed: no originator: " +
u.toString();
}
}
else {
print "Unsubscribe failed: no item: " + u.toString();
}
}
}
monitor ServiceItem {
//...
action onload() {
CreateServiceItem c;
on all CreateServiceItem():c spawn createServiceItem(c);
}
action createServiceItem(CreateServiceItem c) {
//...
DestroyServiceItem d;
on all DestroyServiceItem():d destroyServiceItem(d);
}
action destroyServiceItem(DestroyServiceItem d) {
//...die;
}
}