-- AlpInstanceImpl.mesa
-- Last edited by
--   Kolling on May 3, 1983 3:20 pm
DIRECTORY
      AlpineEnvironment
        USING[Conversation, FileStore, LockFailure, NeededAccess, OperationFailure, Principal,
           UnknownType],
      AlpineFile
        USING[AccessFailed, Close, Create, Delete, GetAccessRights, GetFileID, GetLockOption,
           GetRecoveryOption, GetReferencePattern, GetSize, GetTransID, GetVolumeID,
           IncrementVersion, LockFailed, LockPages, Open, OperationFailed, PossiblyDamaged,
           ReadPages, ReadProperties, SetLockOption, SetReferencePattern, SetSize,
           StaticallyInvalid, UnlockPages, Unknown, UnlockVersion, WritePages, WriteProperties],
      AlpineFileRpcControl
        USING[ImportNewInterface, NewInterfaceRecord],
      AlpineOwner
        USING[AccessFailed, Create, Destroy, LockFailed, OperationFailed, ReadDBProperties,
           ReadNext, ReadProperties, ReorganizeDB, StaticallyInvalid, Unknown,
           WriteProperties],
      AlpineOwnerRpcControl
        USING[ImportNewInterface, NewInterfaceRecord],
      AlpineTransaction
        USING[AssertAlpineWheel, Create, CreateWorker, Finish, OperationFailed, Unknown],
      AlpineTransactionRpcControl
        USING[ImportNewInterface, NewInterfaceRecord],
      AlpineVolume
         USING[AccessFailed, GetEnclosingGroup, GetGroup, GetNextGroup, StaticallyInvalid,
            Unknown],
      AlpineVolumeRpcControl
         USING[ImportNewInterface, NewInterfaceRecord],
      AlpInstance
        USING[Failure, Handle, Object],
      AlpPrivate
         USING[InterfaceCreatorProc],
      ClientMap
        USING[Register],
      Rope
        USING[Equal, ROPE],
      RPC
        USING[AuthenticateFailed, CallFailed, EncryptionKey, GenerateConversation,
           GetCaller, ImportFailed, MakeKey, StartConversation, VersionRange],
      SafeStorage
          USING[GetSystemZone],
      UserCredentials
          USING[GetUserCredentials];
AlpInstanceImpl: MONITOR
   IMPORTS AE: AlpineEnvironment, AF: AlpineFile, AlpineFileRpcControl, AO: AlpineOwner,
      AlpineOwnerRpcControl, AT: AlpineTransaction, AlpineTransactionRpcControl, AV:
      AlpineVolume, AlpineVolumeRpcControl, AlpI: AlpInstance, ClientMap,
      Rope, RPC, SafeStorage, UserCredentials
   EXPORTS AlpInstance, AlpPrivate
   SHARES AlpineFileRpcControl, AlpineOwnerRpcControl, AlpineTransactionRpcControl,
      AlpineVolumeRpcControl =
BEGIN
objectCache: LIST OF AlpI.Object ← NIL;
FindObjectInCache: INTERNAL PROCEDURE[fileStore: AE.FileStore, caller: AE.Principal, key:
 RPC.EncryptionKey, zone: ZONE] RETURNS[handle: AlpI.Handle] =
   BEGIN
   conversation: AE.Conversation;
   FOR list: LIST OF AlpI.Object ← objectCache, list.rest
   UNTIL list = NIL
      DO
      IF list.first.fileStore = fileStore
         THEN BEGIN
                   conversation ← (IF Rope.Equal[RPC.GetCaller[list.first.conversation], caller, FALSE]
                      THEN list.first.conversation
                            ELSE RPC.StartConversation[caller, key, fileStore, authOnly]);
                 handle ← zone.NEW[AlpI.Object ← [
                    trans: list.first.trans,
                    file: list.first.file,
                    owner: list.first.owner,
                    volume: list.first.volume,
                    otherInterfaces: list.first.otherInterfaces,
                    conversation: conversation,
                    fileStore: fileStore]];
                 RETURN;
                     END;
      ENDLOOP;
   conversation ← RPC.StartConversation[caller, key, fileStore, authOnly];
   handle ← zone.NEW[AlpI.Object ← [
      trans: AlpineTransactionRpcControl.ImportNewInterface[[type:
         "AlpineTransaction.alpine", instance: fileStore, version: version], [NIL, NIL,
         NIL]],
      file: AlpineFileRpcControl.ImportNewInterface[[type: "AlpineFile.alpine", instance:
         fileStore, version: version], [NIL, NIL, NIL]],
      owner: AlpineOwnerRpcControl.ImportNewInterface[[type: "AlpineOwner.alpine",
         instance: fileStore, version: version], [NIL, NIL, NIL]],
      volume: AlpineVolumeRpcControl.ImportNewInterface[[type:
         "AlpineVolume.alpine", instance: fileStore, version: version], [NIL, NIL, NIL]],
      otherInterfaces: NIL,
      conversation: conversation,
      fileStore: fileStore]];
   FOR list: LIST OF AlpPrivate.InterfaceCreatorProc ← interfaceCreators, list.rest
   UNTIL list = NIL
      DO
      handle.otherInterfaces ← CONS[list.first[fileStore, version], handle.otherInterfaces];
      ENDLOOP;
   objectCache ← CONS[handle^, objectCache];
   END;
Create: PUBLIC ENTRY PROCEDURE[fileStore: AE.FileStore, caller: AE.Principal, key:
 RPC.EncryptionKey, zone: ZONE] RETURNS [handle: AlpI.Handle] =
  -- non system-fatal errors:
  --    Failed[authenticateFailed, other, unbound].
  -- caller = NIL means the logged-in user.
   BEGIN
   ENABLE UNWIND => NULL;
   startedAlready ← TRUE;
   IF zone = NIL THEN zone ← SafeStorage.GetSystemZone[];
   IF caller = NIL
      THEN BEGIN psw: Rope.ROPE;
            [caller, psw] ← UserCredentials.GetUserCredentials[];
            key ← RPC.MakeKey[psw];
            END;
   IF Rope.Equal[fileStore, "Local.alpine", FALSE]
      THEN BEGIN
              conversation: AE.Conversation ← RPC.GenerateConversation[
                 ! RPC.AuthenticateFailed => SELECT why FROM
                          badCaller, badKey => GOTO noAuthenticate;
                       ENDCASE => GOTO otherError];
              ClientMap.Register[conversation, caller];
              handle ← zone.NEW[AlpI.Object ← [
                 trans: AlpineTransactionRpcControl.NewInterfaceRecord[],
                 file: AlpineFileRpcControl.NewInterfaceRecord[],
                 owner: AlpineOwnerRpcControl.NewInterfaceRecord[],
                 volume: AlpineVolumeRpcControl.NewInterfaceRecord[],
                 otherInterfaces: NIL,
                 conversation: conversation,
                 fileStore: fileStore]];
              handle.trans^ ← [Create: AT.Create, CreateWorker: AT.CreateWorker,
                 AssertAlpineWheel: AT.AssertAlpineWheel, Finish: AT.Finish, Unknown:
                 AT.Unknown, OperationFailed: AT.OperationFailed, lupineDetails: ];
              handle.file^ ← [Open: AF.Open, Create: AF.Create, Close: AF.Close, Delete:
                 AF.Delete, GetVolumeID: AF.GetVolumeID, GetFileID: AF.GetFileID, GetTransID:
                 AF.GetTransID, GetAccessRights: AF.GetAccessRights, GetLockOption:
                 AF.GetLockOption, SetLockOption: AF.SetLockOption, GetRecoveryOption:
                 AF.GetRecoveryOption, GetReferencePattern: AF.GetReferencePattern,
                 SetReferencePattern: AF.SetReferencePattern, ReadPages: AF.ReadPages,
                 WritePages: AF.WritePages, LockPages: AF.LockPages, UnlockPages:
                 AF.UnlockPages, ReadProperties: AF.ReadProperties, WriteProperties:
                 AF.WriteProperties, UnlockVersion: AF.UnlockVersion, IncrementVersion:
                 AF.IncrementVersion, GetSize: AF.GetSize, SetSize: AF.SetSize, AccessFailed:
                 AF.AccessFailed, LockFailed: AF.LockFailed, OperationFailed:
                 AF.OperationFailed, StaticallyInvalid: AF.StaticallyInvalid, Unknown:
                 AF.Unknown, PossiblyDamaged: AF.PossiblyDamaged, lupineDetails: ];
              handle.owner^ ← [ReadProperties: AO.ReadProperties, WriteProperties:
                 AO.WriteProperties, Create: AO.Create, Destroy: AO.Destroy, ReadNext:
                 AO.ReadNext, ReadDBProperties: AO.ReadDBProperties, ReorganizeDB:
                 AO.ReorganizeDB, AccessFailed: AO.AccessFailed, LockFailed: AO.LockFailed,
                 OperationFailed: AO.OperationFailed, StaticallyInvalid: AO.StaticallyInvalid,
                 Unknown: AO.Unknown, lupineDetails: ];
              handle.volume^ ← [GetNextGroup: AV.GetNextGroup, GetGroup: AV.GetGroup,
                 GetEnclosingGroup: AV.GetEnclosingGroup, AccessFailed: AV.AccessFailed,
                 Unknown: AV.Unknown, StaticallyInvalid: AV.StaticallyInvalid, lupineDetails: ];
                 FOR list: LIST OF AlpPrivate.InterfaceCreatorProc ← interfaceCreators, list.rest
                UNTIL list = NIL
                   DO
                 handle.otherInterfaces ← zone.CONS[list.first[fileStore, version],
                    handle.otherInterfaces];
                   ENDLOOP;
                END
      ELSE handle ← FindObjectInCache[fileStore, caller, key, zone !
                 RPC.AuthenticateFailed => SELECT why FROM
                          badCaller, badKey => GOTO noAuthenticate;
                       ENDCASE => GOTO otherError;
                 RPC.CallFailed => GOTO otherError;
                 RPC.ImportFailed => SELECT why FROM badVersion, wrongVersion, unbound =>
                     GOTO unbound; ENDCASE => GOTO otherError;];
   EXITS
      noAuthenticate => RETURN WITH ERROR Failed[authenticateFailed];
      unbound => RETURN WITH ERROR Failed[unbound];
      otherError => RETURN WITH ERROR Failed[other];
   END;
-- If a object in our cache has an InterfaceRecord matching an InterfaceRecord in this handle, throw out the object.  I think one interface matching means all match.....
NoticeUnboundInstance: PUBLIC ENTRY PROCEDURE[handle: AlpI.Handle] =
  -- non system-fatal errors:
  --    none.
   BEGIN
   prevEntry: LIST OF AlpI.Object ← NIL;
   list: LIST OF AlpI.Object ← objectCache;
    DO
    IF list = NIL THEN EXIT;
    IF list.first.trans = handle.trans
       THEN BEGIN
                 IF prevEntry = NIL
                     THEN objectCache ← list.rest
                     ELSE prevEntry.rest ← list.rest;
                 END
       ELSE prevEntry ← list;
   list ← list.rest;
    ENDLOOP;
   END;
RegisterInterfaceCreator: PUBLIC ENTRY PROCEDURE[proc: AlpPrivate.InterfaceCreatorProc] =
  -- non system-fatal errors:
  --    none.
   BEGIN
   IF startedAlready THEN ERROR;
   interfaceCreators ← CONS[proc, interfaceCreators];
   END;
interfaceCreators: LIST OF AlpPrivate.InterfaceCreatorProc ← NIL;
startedAlready: BOOLEAN ← FALSE;
Failed: PUBLIC ERROR [why: AlpInstance.Failure] = CODE;
version: RPC.VersionRange = [1, 1];
END.
                                                                      Edit Log
Initial: Kolling:  February 15, 1983 2:58 pm.