DIRECTORY
BasicTime USING [ GMT],
DB USING[ Entity, Attribute, Aborted, Value, Version, DeclareEntity, Eq, GMT, B2V, I2V, T2V, S2V, MarkTransaction, TransactionOf, Relship, DeclareRelship, SetF, GetF, RelshipSet, RelationSubset, NextRelship, V2E, ReleaseRelshipSet, V2I, V2B, V2S, V2T, EntitySet, DomainSubset, NextEntity, ReleaseEntitySet, AttributeValue, AttributeValueList, NameOf, DestroyEntity],
Hickory USING [ Event, Property, Error, PropertySet],
HickoryNotify USING [ NotifyClients],
HickoryProp,
HickoryStorage USING [ protData, PropertyRel, PropertyTypes],
HickorySupport USING [ RestartTransaction, StartTransaction],
Rope USING [ ROPE],
RopeSets USING [ InsertValueIntoSet, DeleteValueFromSet, IsSetEmpty, Union]
;
Action routines dealing with properties, all public entry points
SetProperty:
PUBLIC
ENTRY
PROCEDURE [ ev: Event, name: Property, value:
REF
ANY] =
BEGIN
to set the named property of the given event to the value.
ENABLE UNWIND => NULL;
MyRope: TYPE = Rope.ROPE;
type: Entity ← GetType[ value];
propEnt: Entity;
evEnt: Entity;
propType: Entity;
val: Value;
success: BOOLEAN ← FALSE;
IF NOT owner THEN ERROR Error[ NotOwner, NIL];
IF value = NIL THEN ERROR Hickory.Error[ BadValue, NIL];
WHILE NOT success DO
ENABLE Aborted => { HickorySupport.RestartTransaction; success ← FALSE; LOOP };
HickorySupport.StartTransaction[];
propEnt ← DeclareEntity[ propertyDomain, name, OldOnly];
IF propEnt = NIL THEN propEnt ← DeclareAProperty[ name, type];
evEnt ← DeclareEntity [ eventDomain, ev, OldOnly];
IF evEnt = NIL THEN ERROR Hickory.Error[ NoSuchEvent, ev];
propType ← GetPropertyDescriptor[ propEnt];
IF NOT Eq[ type, propType] THEN ERROR Hickory.Error[ MismatchedPropertyType, NIL];
SELECT
TRUE
FROM
Eq[ type, IntegerEntity] =>
BEGIN
i: REF INTEGER ← NARROW[ value];
val ← I2V[ i^];
StoreAValue[ val, Int, evEnt, propEnt];
END; -- IntegerEntity
Eq[ type, BooleanEntity] =>
BEGIN
b: REF BOOLEAN ← NARROW[ value];
val ← B2V[ b^];
StoreAValue[ val, Bool, evEnt, propEnt];
END; -- BooleanEntity
Eq[ type, TimeEntity] =>
BEGIN
time: REF GMT ← NARROW[ value]; -- REF BasicTime.GMT!
val ← T2V[ LOOPHOLE[ time]];
StoreAValue[ val, Time, evEnt, propEnt];
END; -- TimeEntity
Eq[ type, RopeEntity] =>
BEGIN
r: REF MyRope ← NARROW[ value];
val ← S2V[ r^];
StoreAValue[ val, String, evEnt, propEnt];
END; -- RopeEntity
ENDCASE;
MarkTransaction[ TransactionOf[ $Hickory]];
success ← TRUE;
ENDLOOP; -- Transaction
HickoryNotify.NotifyClients[ AddProperty, ev, RopeSets.InsertValueIntoSet[ name, [ NIL, NIL]]];
END; -- SetProperty
StoreAValue:
INTERNAL
PROCEDURE [ val: Value, where: HickoryStorage.PropertyTypes, evEnt, propEnt: Entity] =
BEGIN
to store the supplied value in the appropriate property relation
OPEN propertyRels[ where];
av: AttributeValue;
avl: AttributeValueList ← NIL;
tuple: Relship;
av ← [ attribute: Event, hi: evEnt, lo: evEnt];
avl ← CONS[ av, avl];
av ← [ attribute: Property, hi: propEnt, lo: propEnt];
avl ← CONS[ av, avl];
tuple ← DeclareRelship[ Rel, avl]; -- to avoid duplicates...
SetF[ tuple, PropValue, val];
GetType:
INTERNAL
PROCEDURE [ val:
REF
ANY]
RETURNS [ type: Entity] =
BEGIN
to find out the type of the value
IF ISTYPE[ val, REF INTEGER] THEN RETURN[ IntegerEntity];
IF ISTYPE[ val, REF BOOLEAN] THEN RETURN[ BooleanEntity];
IF ISTYPE[ val, REF GMT] THEN RETURN[ TimeEntity];
IF ISTYPE[ val, REF Rope.ROPE] THEN RETURN[ RopeEntity];
ERROR Hickory.Error[ BadValueType, NIL];
END; -- GetType
DeclareAProperty:
INTERNAL
PROCEDURE [ name: Property, type: Entity]
RETURNS [ pEnt: Entity] =
BEGIN
makes an entry into the propertyDescriptorRel after declaring a new property
in propertyDomain
OPEN propertyDescriptorRel;
propEnt: Entity ← DeclareEntity[ propertyDomain, name, NewOnly];
tuple: Relship ← DeclareRelship[ Rel]; -- in propertyDescriptorRel
propertyCache ← RopeSets.InsertValueIntoSet[ name, propertyCache];
SetF[ tuple, Property, propEnt];
SetF[ tuple, Type, type];
MarkTransaction[ TransactionOf[ $Hickory]];
HickoryNotify.NotifyClients[ NewProperty, NIL, RopeSets.InsertValueIntoSet[ name, [ NIL, NIL]]];
RETURN[ propEnt];
END; -- DeclareAProperty
GetPropertyDescriptor:
INTERNAL
PROCEDURE [ propEnt: Entity]
RETURNS [ type: Entity] =
BEGIN
to find the type of a property
OPEN propertyDescriptorRel;
relSet: RelshipSet;
av: AttributeValue;
tuple: Relship;
av ← [ attribute: Property, lo: propEnt, hi: propEnt];
relSet ← RelationSubset[ Rel, LIST[ av]];
tuple ← NextRelship[ relSet];
IF tuple = NIL THEN ERROR;
type ← V2E[ GetF[ tuple, Type]];
ReleaseRelshipSet[ relSet];
RETURN[ type];
END; -- GetPropertyDescriptor
GetProperty:
PUBLIC
ENTRY
PROCEDURE [ ev: Event, name: Property]
RETURNS [ value:
REF
ANY] =
BEGIN
to find the property value of the event.
ENABLE UNWIND => NULL;
evEnt, propEnt: Entity;
val: Value;
type: Entity;
success: BOOLEAN ← FALSE;
WHILE
NOT success
DO
ENABLE Aborted => { HickorySupport.RestartTransaction; success ← FALSE; LOOP };
HickorySupport.StartTransaction[];
evEnt ← DeclareEntity[ eventDomain, ev, OldOnly];
IF evEnt = NIL THEN ERROR Hickory.Error[ NoSuchEvent, ev];
propEnt ← DeclareEntity[ propertyDomain, name, OldOnly];
IF propEnt = NIL THEN ERROR Hickory.Error[ NoSuchProperty, name];
type ← GetPropertyDescriptor[ propEnt];
SELECT
TRUE
FROM
Eq[ type, BooleanEntity] =>
BEGIN
b: BOOLEAN;
val ← GetAValue[ evEnt, Bool];
IF val = NIL THEN RETURN[ NIL];
b ← V2B[ val];
value ← NEW[ BOOLEAN ← b];
END; -- Boolean
Eq[ type, IntegerEntity] =>
BEGIN
i: INTEGER;
val ← GetAValue[ evEnt, Int];
IF val = NIL THEN RETURN[ NIL];
i ← V2I[ val];
value ← NEW[ INTEGER ← i];
END ;-- integer
Eq[ type, RopeEntity] =>
BEGIN
r: Rope.ROPE;
val ← GetAValue[ evEnt, String];
IF val = NIL THEN RETURN[ NIL];
r ← V2S[ val];
value ← NEW[ Rope.ROPE ← r];
END; -- Rope
Eq[ type, TimeEntity] =>
BEGIN
t: BasicTime.GMT;
val ← GetAValue[ evEnt, Time];
IF val = NIL THEN RETURN[ NIL];
t ← LOOPHOLE[ V2T[ val]];
value ← NEW[ BasicTime.GMT ← t];
END; -- Time
ENDCASE;
MarkTransaction[ TransactionOf[ $Hickory]];
success ← TRUE;
ENDLOOP;
RETURN[ value];
END; -- GetProperty
GetAValue:
INTERNAL
PROCEDURE [ evEnt: Entity, where: HickoryStorage.PropertyTypes]
RETURNS [ val: Value] =
BEGIN
to retrieve the value of the event entity
OPEN propertyRels[ where];
av: AttributeValue ← [ attribute: Event, lo: evEnt, hi: evEnt];
relSet: RelshipSet ← RelationSubset[ Rel, LIST[ av]];
tuple: Relship ← NextRelship[ relSet];
IF tuple = NIL THEN val ← NIL
ELSE val ← GetF[ tuple, PropValue];
ReleaseRelshipSet[ relSet];
RETURN[ val];
END; -- GetAValue
ListProperties:
PUBLIC
ENTRY
PROCEDURE [ ev: Hickory.Event ←
NIL]
RETURNS [ pSet: PropertySet] =
BEGIN
enumerates all property names in increasing order.
ENABLE UNWIND => NULL;
entSet: EntitySet;
ent: Entity;
success: BOOLEAN ← FALSE;
pSet.Head ← NIL; pSet.Tail ← NIL;
WHILE NOT success DO
ENABLE Aborted => { HickorySupport.RestartTransaction; success ← FALSE; LOOP };
HickorySupport.StartTransaction[];
IF ev =
NIL
THEN
BEGIN
IF RopeSets.IsSetEmpty[ propertyCache]
THEN
BEGIN
entSet ← DomainSubset[ d: propertyDomain];
WHILE ( ent ← NextEntity[ entSet]) #
NIL
DO
name: Rope.ROPE ← NameOf[ ent];
propertyCache ← RopeSets.InsertValueIntoSet[ name, propertyCache];
ENDLOOP;
ReleaseEntitySet[ entSet];
END;
pSet ← RopeSets.Union[ propertyCache, [NIL, NIL]];
END
ELSE pSet ← GetPropertiesOfEvent[ ev];
MarkTransaction[ TransactionOf[ $Hickory]];
success ← TRUE;
ENDLOOP; -- Transaction
RETURN[ pSet];
END; -- ListProperties
GetPropertiesOfEvent:
INTERNAL
PROCEDURE [ ev: Hickory.Event]
RETURNS [ pSet: PropertySet] =
BEGIN
here we look into all the different propertyRels and find the names of properties
that the event has.
evEnt: Entity ← DeclareEntity[ eventDomain, ev, OldOnly];
IF evEnt = NIL THEN ERROR Error[ NoSuchEvent, ev];
FOR typ: HickoryStorage.PropertyTypes
IN HickoryStorage.PropertyTypes
DO
OPEN propertyRels[ typ];
av: AttributeValue ← [ attribute: Event, lo: evEnt, hi: evEnt];
relSet: RelshipSet ← RelationSubset[ Rel, LIST[ av]];
tuple: Relship;
WHILE ( tuple ← NextRelship[ relSet]) #
NIL
DO
pSet ← RopeSets.InsertValueIntoSet[ NameOf[ V2E[ GetF[ tuple, Property]]], pSet];
ENDLOOP;
ReleaseRelshipSet[ relSet];
ENDLOOP;
RETURN[ pSet];
END; -- GetPropertiesOfEvent
RemoveProperty:
PUBLIC
ENTRY
PROCEDURE [ property: Property] =
BEGIN
to destroy one property and remove it from all events that have the named property
OPEN propertyDescriptorRel;
ENABLE UNWIND => NULL;
propEnt: Entity;
success: BOOLEAN ← FALSE;
IF NOT owner THEN ERROR Error[ NotOwner, NIL];
WHILE NOT success DO
ENABLE Aborted => { HickorySupport.RestartTransaction; success ← FALSE; LOOP };
HickorySupport.StartTransaction[];
propEnt ← DeclareEntity[ propertyDomain, property, OldOnly];
IF propEnt = NIL THEN ERROR Error[ NoSuchProperty, property];
DestroyEntity[ propEnt]; -- destroys all relships using the entity
MarkTransaction[ TransactionOf[ $Hickory]];
success ← TRUE;
ENDLOOP; -- TRansaction
propertyCache ← RopeSets.DeleteValueFromSet[ property, propertyCache];
HickoryNotify.NotifyClients[ PropertyDestroy, NIL, RopeSets.InsertValueIntoSet[ property, [NIL, NIL]]];
END; -- RemoveProperty
InvalidateCache:
PUBLIC
INTERNAL
PROCEDURE =
BEGIN
propertyCache.Head ← NIL; propertyCache.Tail ← NIL;
END; -- InvalidateCache
InitializeCache:
PUBLIC
INTERNAL
PROCEDURE =
BEGIN
to initialize the cache of HickoryProp
entSet: EntitySet;
ent: Entity;
propertyCache.Head ← NIL; propertyCache.Tail ← NIL;
entSet ← DomainSubset[ d: propertyDomain];
WHILE ( ent ← NextEntity[ entSet]) #
NIL
DO
prop: Property ← NameOf[ ent];
propertyCache ← RopeSets.InsertValueIntoSet[ prop, propertyCache];
ENDLOOP;
ReleaseEntitySet[ entSet];
END;
Initially
propertyCache.Head ← NIL; propertyCache.Tail ← NIL;
END.