<<>> <> <> <> <> DIRECTORY Customize, Rope, Xl, XlDB, XlPredefinedAtoms; XlDBImpl: CEDAR MONITOR LOCKS mr USING mr: REF MyRec IMPORTS Customize, Rope, Xl EXPORTS XlDB SHARES Customize ~ BEGIN MyRec: TYPE = MONITORED RECORD [ val: Rope.ROPE ¬ NIL, db: Customize.DB ¬ NIL, errors: Rope.ROPE, invalidation: LIST OF InvalidationRec ¬ NIL ]; myKey: REF ATOM ¬ NEW[ATOM ¬ $XlDB]; propertyEvents: Xl.EventFilter = Xl.CreateEventFilter[propertyNotify]; ResetProc: Xl.EventProcType = { <<--Flushes the cached shared data base>> WITH event SELECT FROM pne: Xl.PropertyNotifyEvent => IF pne.atom=XlPredefinedAtoms.resourceManager THEN { mr: REF MyRec ¬ NARROW[clientData]; mr.val ¬ NIL; mr.db ¬ NIL; FOR l: LIST OF InvalidationRec ¬ mr.invalidation, l.rest WHILE l#NIL DO Xl.Enqueue[l.first.tq, l.first.proc, l.first.data, event]; ENDLOOP; }; ENDCASE => {}; }; InitializeProp: Xl.InitializeProcType = { <<--Set up connection so that shared data base is flushed from cache >> <<--when the corresponding property value is set.>> rootWindow: Xl.Window ¬ Xl.FirstRoot[c]; mr: REF MyRec ¬ NEW[MyRec]; match: Xl.Match ¬ NEW[Xl.MatchRep ¬ [proc: ResetProc, handles: propertyEvents, tq: Xl.CreateTQ[], data: mr]]; Xl.AddDispatch[c, rootWindow, match, [propertyChange: TRUE]]; RETURN [mr]; }; ReloadDBCache: ENTRY PROC [c: Xl.Connection, mr: REF MyRec, readonly: BOOL] RETURNS [db: Customize.DB ¬ NIL] = { <<--Reread the database; if not readonly put it into the cache atomically>> db ¬ mr.db; IF ~readonly OR db=NIL THEN { val: Rope.ROPE ¬ mr.val; IF val=NIL THEN { pr: Xl.PropertyReturnRec; pr ¬ Xl.GetProperty[c: c, w: Xl.FirstRoot[c], property: XlPredefinedAtoms.resourceManager ! Xl.XError => { mr.errors ¬ Rope.Concat["failed reading resource_manager property: ", err.explanation]; GOTO Oops; }]; IF pr.type = XlPredefinedAtoms.string AND ISTYPE[pr.value, Rope.ROPE] THEN mr.val ¬ val ¬ NARROW[pr.value] ELSE mr.errors ¬ "bad resource_manager property"; EXITS Oops => {}; }; db ¬ Customize.CreateDB[]; IF val#NIL THEN mr.errors ¬ Customize.UpdateDBString[db, val]; IF readonly THEN mr.db ¬ db; }; }; GetStandardDBReadWrite: PUBLIC PROC [c: Xl.Connection] RETURNS [db: Customize.DB] = { <<--Returns a modifiable copy of the default data base of the connection>> WITH Xl.GetConnectionPropAndInit[c, myKey, InitializeProp] SELECT FROM mr: REF MyRec => { db ¬ ReloadDBCache[c, mr, FALSE]; }; ENDCASE => ERROR; }; GetStandardDB: PUBLIC PROC [c: Xl.Connection] RETURNS [db: Customize.DBreadonly] = { <<--Returns the shared default data base of the connection>> WITH Xl.GetConnectionPropAndInit[c, myKey, InitializeProp] SELECT FROM mr: REF MyRec => { db ¬ mr.db; IF db=NIL THEN db ¬ ReloadDBCache[c, mr, TRUE]; }; ENDCASE => ERROR; }; InvalidationRec: TYPE = RECORD [proc: Xl.EventProcType, tq: Xl.TQ, data: REF]; ConsInvalidator: ENTRY PROC [mr: REF MyRec, ir: InvalidationRec] = { mr.invalidation ¬ CONS[ir, mr.invalidation]; }; RegisterDBInvalidator: PUBLIC PROC [c: Xl.Connection, proc: Xl.EventProcType, tq: Xl.TQ, data: REF ¬ NIL] = { WITH Xl.GetConnectionPropAndInit[c, myKey, InitializeProp] SELECT FROM mr: REF MyRec => { IF proc=NIL THEN RETURN; IF tq=NIL THEN tq ¬ Xl.CreateTQ[]; ConsInvalidator[mr, [proc, tq, data]]; }; ENDCASE => ERROR; }; QueryStandardDB: PUBLIC PROC [c: Xl.Connection, query: Rope.ROPE] RETURNS [answer: Rope.ROPE] = { db: Customize.DBreadonly = GetStandardDB[c]; WITH Customize.DoQueryString[db, query] SELECT FROM r: Rope.ROPE => RETURN [r]; ENDCASE => RETURN [NIL]; }; END.