GvNsMapImpl.mesa
Copyright Ó 1986, 1988, 1990, 1991 by Xerox Corporation. All rights reserved.
John Larson, May 26, 1986 5:23:35 pm PDT
Wes Irish, December 20, 1988 5:01:20 pm PST
Willie-Sue, December 23, 1988 6:19:43 pm PST
Bill Jackson (bj) January 19, 1990 10:23:21 pm PST
There is a special group in the NS world called "Translations:...:..." (yes, the name of both the domain and organization really is "...", three periods!). This group holds the mappings between GV regitries and NS domains (including organizations). Each member of this group is a ficticious NS name such that the object field represents the GV registry and the domain and organization fields represent the NS domain and organization. A typical entry looks like "sbderx:SBD-E:RX", meaning that the GV foreign registry "sbderx" maps to the NS domain and organization "SBD-E:RX". To determine what direction the mapping is for you have to check if the GV registry part is a valid GV registry or not. If it is valid then the mapping is from NS to GV, else GV to NS.
"Direction" controls which of the two mapping lists are used. gvToNs is the list with GV foreign registries and valid NS domains. nsToGv is the list with NS psuedo domains and valid GV registries. In all cases the returned ROPE will be NIL if no mapping is found.
This package may be included in a Checkpoint. The map will be reinitialized on Rollback.
Willie-s, December 27, 1991 2:32 pm PST
DIRECTORY
BasicTime USING [GMT, Now],
CHEntriesP0V0 USING [members],
GVNames USING [CheckStamp],
GvNsMap,
Process USING [Detach, Pause, SecondsToTicks],
Rope,
SymTab USING [Create, Erase, Fetch, Ref, Store],
XNSCH USING [Conversation, Error, InitiateConversation, ListMembers, Name, TerminateConversation],
XNSCHName USING [Name, NameFromRope];
GvNsMapImpl: CEDAR MONITOR
IMPORTS BasicTime, Process, Rope, SymTab, XNSCH, XNSCHName
EXPORTS GvNsMap = {
ROPE: TYPE = Rope.ROPE;
Name: TYPE = XNSCHName.Name;
Direction: TYPE = GvNsMap.Direction;
Syntax: TYPE = GvNsMap.Syntax;
Map: TYPE = SymTab.Ref;
tableSize: INT = 157;
gvToNsMap: Map;
nsToGvMap: Map;
StampInfo: TYPE = NameType[noChange..allDown];
NameType: TYPE = Outcome[noChange..badPwd]; -- outcomes for enquiries
Outcome: TYPE = { -- possible outcomes of RS operations
noChange, -- updates and timestamped enquiries
group, individual, notFound, -- any
protocolError, wrongServer, allDown, -- any
badPwd, -- authentication and updates
outOfDate, notAllowed -- updates
};
CheckStamp: PROC [ name: ROPE ] RETURNS [ info: StampInfo ] ~ {
info ¬ allDown;
};
stats: GvNsMap.Stats;
MapFromDir: PROC[dir: Direction] RETURNS[Map] = {
SELECT dir FROM
gvToNs => {stats.gvToNs ¬ stats.gvToNs + 1; RETURN[gvToNsMap]};
nsToGv => {stats.nsToGv ¬ stats.nsToGv + 1; RETURN[nsToGvMap]};
ENDCASE => ERROR;
};
DomainFromRegistry: PUBLIC ENTRY PROC[reg: ROPE, dir: Direction ¬ gvToNs] RETURNS[domain: ROPE] = {
RETURN[NARROW[SymTab.Fetch[MapFromDir[dir], reg].val]];
};
StripOffQuotes: PROC[r: ROPE] RETURNS[ROPE] = {
len: INT ¬ Rope.Length[r];
IF len >= 2 AND Rope.Fetch[r, 0] = '" AND Rope.Fetch[r, len-1] = '"
THEN RETURN[Rope.Substr[r, 1, len-2]]
ELSE RETURN[r];
};
SyntaxOf: PUBLIC PROC[name: ROPE] RETURNS[syntax: Syntax] = {
figure out what syntax this name is in
len: INT = Rope.Length[name];
syntax ¬ ns;
IF (Rope.SkipTo[name, 0, "."] < len
AND (NOT(Rope.SkipTo[name, 0, ":"] < len) OR Rope.Index[name, 1, "\".", FALSE] < len))
THEN syntax ¬ gv;
};
NativeSyntax: PUBLIC PROC[name: ROPE, inSyntax: Syntax ¬ unknown] RETURNS[native: ROPE, syntax: Syntax] = {
The incoming name can have the syntax of either world BUT it's only going to refer to a "valid" name in one. What we do here is figure out what world the name really in and then put it into the correct syntax.
native ¬ GvSyntax[name];
IF NsFromGvName[native] = NIL
THEN { -- it's really a GV name
syntax ¬ gv;
}
ELSE { -- it's really an NS name
native ¬ NsSyntax[name];
syntax ¬ ns;
};
};
NsSyntax: PUBLIC PROC[name: ROPE, inSyntax: Syntax ¬ unknown] RETURNS [nsSyntax: ROPE] = {
Returns the NS syntax for name
IF inSyntax = unknown THEN inSyntax ¬ SyntaxOf[name];
IF inSyntax = ns THEN RETURN[name];
nsSyntax ¬ NsFromGvName[name];
IF nsSyntax = NIL THEN nsSyntax ¬ NsFromGvName[name, nsToGv];
};
GvSyntax: PUBLIC PROC[name: ROPE, inSyntax: Syntax ¬ unknown, quoteIfNeeded: BOOL ¬ TRUE] RETURNS [gvSyntax: ROPE] = {
Returns the GV syntax for name
If quoteIfNeeded then, if needed, wrap quotes around the name portion of the returning name.
IF inSyntax = unknown THEN inSyntax ¬ SyntaxOf[name];
IF inSyntax = gv THEN RETURN[IF quoteIfNeeded THEN QuoteIfNeeded[name] ELSE name];
gvSyntax ¬ GvFromNsName[name];
IF gvSyntax = NIL THEN gvSyntax ¬ GvFromNsName[name, gvToNs];
IF quoteIfNeeded THEN gvSyntax ¬ QuoteIfNeeded[gvSyntax];
};
QuoteIfNeeded: PUBLIC PROC [gvName: ROPE] RETURNS [ROPE] = {
Puts quotes around the name portion of a GV name if needed (ie, there is a space in it and it's not already quoted)
namePart: ROPE;
regPart: ROPE;
[namePart, regPart] ¬ BreakName[gvName];
namePart ¬ QuoteRopeIfNeeded[namePart];
RETURN[Rope.Cat[namePart, ".", regPart]];
};
NeedsQuotes: PROC [r: ROPE] RETURNS [BOOL] = {
Decides if quotes are needed around a rope (ie, there is a space in it)
IF Rope.Length[r] = 0
OR (Rope.Find[r, "\""] < 0 AND Rope.Find[r, " "] >= 0)
THEN RETURN [TRUE];
RETURN[FALSE];
};
QuoteRopeIfNeeded: PROC [r: ROPE] RETURNS [ROPE] = {
IF NeedsQuotes[r] THEN RETURN [Rope.Cat["\"", r, "\""]];
RETURN[r];
};
NsFromGvName: PUBLIC PROC[gvName: ROPE, dir: Direction ¬ gvToNs] RETURNS[nsName: ROPE] = {
sn, reg, domain: Rope.ROPE;
[sn, reg] ¬ BreakName[gvName];
IF sn = NIL THEN RETURN[NIL];
domain ¬ DomainFromRegistry[reg, dir];
IF domain = NIL THEN RETURN[NIL];
RETURN[Rope.Cat[StripOffQuotes[sn], ":", domain]];
};
RegistryFromDomain: PUBLIC ENTRY PROC[domain: ROPE, org: ROPE ¬ NIL, dir: Direction ¬ nsToGv] RETURNS[reg: ROPE] = {
IF org = NIL THEN {
name: Name ¬ XNSCHName.NameFromRope[Rope.Concat["x:", domain]];
domain ¬ name.domain;
org ¬ name.organization;
};
RETURN[NARROW[SymTab.Fetch[MapFromDir[dir], Rope.Cat[domain, ":", org]].val]];
};
GvFromNsName: PUBLIC PROC[nsName: ROPE, dir: Direction ¬ nsToGv] RETURNS[gvName: ROPE] = {
name: Name ¬ XNSCHName.NameFromRope[nsName];
gvReg: ROPE ¬ RegistryFromDomain[name.domain, name.organization, dir];
IF gvReg = NIL THEN RETURN[NIL];
RETURN[Rope.Cat[name.object, ".", gvReg]];
};
GetStats: PUBLIC ENTRY PROC RETURNS[GvNsMap.Stats] = {
RETURN[stats];
};
BreakName: PUBLIC PROC[name: Rope.ROPE] RETURNS[sn, reg: Rope.ROPE] = {
length: INT = name.Length[];
FOR i: INT DECREASING IN [0..length) DO
IF name.Fetch[i] = '. THEN RETURN[
sn: name.Substr[start: 0, len: i],
reg: name.Substr[start: i+1, len: length-(i+1)] ];
ENDLOOP;
RETURN[sn: NIL, reg: name];
};
UpdateMap: PUBLIC ENTRY PROC ~ {
translationGroup: Rope.ROPE ¬ "Translations:...:...";
pattern: XNSCH.Name ¬ XNSCHName.NameFromRope[translationGroup];
distingName: XNSCH.Name;
AddThisMapping: PROC [it: XNSCH.Name] ~ {
domOrg: ROPE = Rope.Cat[it.domain, ":", it.organization];
reg: ROPE = it.object;
IF ValidGVReg[it.object] THEN {
[] ¬ SymTab.Store[nsToGvMap, domOrg, reg];
[] ¬ SymTab.Store[nsToGvMap, reg, domOrg];
stats.nsToGvMaps ¬ stats.nsToGvMaps + 1;
}
ELSE {
[] ¬ SymTab.Store[gvToNsMap, reg, domOrg];
[] ¬ SymTab.Store[gvToNsMap, domOrg, reg];
stats.gvToNsMaps ¬ stats.gvToNsMaps + 1;
};
};
ValidGVReg: PROC [reg: ROPE] RETURNS [BOOL] = {
SELECT CheckStamp[Rope.Concat[reg, ".gv"]] FROM
group => RETURN[TRUE];
notFound, individual => RETURN[FALSE];
ENDCASE => {stats.troubleOnLastUpdate ¬ TRUE; RETURN[FALSE];};
};
c: XNSCH.Conversation ¬ XNSCH.InitiateConversation[];
IF gvToNsMap = NIL
THEN gvToNsMap ¬ SymTab.Create[tableSize, FALSE]
ELSE SymTab.Erase[gvToNsMap];
IF nsToGvMap = NIL
THEN nsToGvMap ¬ SymTab.Create[tableSize, FALSE]
ELSE SymTab.Erase[nsToGvMap];
stats ¬ [BasicTime.Now[], FALSE, stats.updates+1, 0, 0, 0, 0];
distingName ¬ XNSCH.ListMembers[c, pattern, CHEntriesP0V0.members, AddThisMapping
! XNSCH.Error => {
stats.troubleOnLastUpdate ¬ TRUE;
CONTINUE}];
XNSCH.TerminateConversation[c];
};
InitializeMapDetached: PROC ~ {
TRUSTED {Process.Detach[FORK InitializeMap[]]};
};
InitializeMap: PROC ~ {
stats ¬ [BasicTime.Now[], FALSE, 0, 0, 0, 0, 0];
DO
UpdateMap[];
IF ~GetStats[].troubleOnLastUpdate THEN EXIT;
Process.Pause[Process.SecondsToTicks[5*60]];
ENDLOOP;
};
InitializeMapDetached[];
}.