!=========================================================================
! Copyright (C) VMware, Inc. 1986-2011.  All Rights Reserved.
!
! $Id: gssession.gs,v 1.7 2008-01-09 22:50:11 stever Exp $
!
! Superclass Hierarchy:
!   GsSession, AbstractSession, Object
!=========================================================================
expectvalue %String
run
^ AbstractSession _newKernelSubclass: 'GsSession'
        instVarNames: #( 'sessionSerialNum' 'userProfile' )
        classVars: #()
        classInstVars: #()
        poolDictionaries: #[]
        inDictionary: Globals
        constraints: #[ #[ #sessionSerialNum, SmallInteger],
                        #[ #userProfile, UserProfile] ]
        instancesInvariant: false
        isModifiable: false
        reservedOop: 811
%

removeallmethods  GsSession
removeallclassmethods  GsSession

category: 'For Documentation Installation only'
classmethod: GsSession
installDocumentation

| doc txt |

doc := GsClassDocumentation newForClass: self.

txt := (GsDocText new) details:
'A GsSession represents a user session on the GemStone server where the
 instance exists.  It is a transient object that is useful only as long
 as the user remains logged in to GemStone.

 A GsSession can access the UserProfile of the user who is logged in to
 GemStone, can provide some minimal control over session execution, and
 can send and receive signals with other sessions.

 The current session is represented by a GsCurrentSession, a special
 subclass of GsSession.  Instances of GsSession typically represent
 other concurrent GemStone sessions in the same server.' .
doc documentClassWith: txt.

txt := (GsDocText new) details:
'A SmallInteger that identifies the session uniquely within the GemStone
 server.' .
doc documentInstVar: #sessionSerialNum with: txt.

txt := (GsDocText new) details:
'The UserProfile of the user who is logged in to the session.' .
doc documentInstVar: #userProfile with: txt.

self description: doc.
%

category: 'Instance Creation'
classmethod: GsSession
currentSession

"Returns the sole instance of GsCurrentSession that represents this login
 session."

<primitive: 311>
self _primitiveFailed: #currentSession
%

category: 'Private Symbol Access'
classmethod: GsSession
_newSymbolsDictionary

"Returns the session-private dictionary that is a cache of symbols
  that this session has had to the Symbol Creation Session for."

<protected primitive: 152>
self _primitiveFailed: #_newSymbolsDictionary
%

category: 'Private Symbol Access'
classmethod: GsSession
_newSymbolsAsArray

"Returns an Array containing the enumeration of all Symbols
 in   GsSession _newSymbolsDictionary ."

<primitive: 901>  "enter protected mode"
| dict res |
dict := self _newSymbolsDictionary .
res := Array new .
dict doKeys:[:aSym | res add: aSym ].
System _disableProtectedMode. "exit protected mode"
^ res
%

category: 'Private Symbol Access'
classmethod: GsSession
_newSymbolsSize

"Returns the number of Symbols in
    GsSession _newSymbolsDictionary ."

<primitive: 901>  "enter protected mode"
| dict res |
dict := self _newSymbolsDictionary .
res := dict size .
System _disableProtectedMode. "exit protected mode"
^ res
%

category: 'Instance Creation'
classmethod: GsSession
sessionWithSerialNumber: anInteger

"Returns an instance of a kind of GsSession that represents the GemStone session
 on the same repository, whose serial number is anInteger.  Returns nil if no
 logged-in session has that serial number.

 Requires SessionAccess privilege if the session described by anInteger is
 not the current session."

| dict aSess currSess descr systm |
currSess := GsSession currentSession.
anInteger == currSess sessionSerialNum ifTrue:[ ^ currSess ].
systm := System .
dict := systm _sessionStateAt: 9 .
dict == nil ifTrue:[
  dict := IdentityKeyValueDictionary new .
  dict at: (currSess sessionSerialNum) put: currSess .
  systm _sessionStateAt: 9 put: dict .
  ].
descr := systm _descriptionOfSessionSerialNum: anInteger sessionId: -1 .
(descr at: 1 "UserProfile" ) == nil ifTrue:[ 
  dict removeKey: anInteger ifAbsent:[] .
  ^ nil .
  ].
aSess := dict at: anInteger otherwise: nil .
aSess ~~ nil ifTrue:[ ^ aSess ].
aSess := super new _initFromSessionDescription: descr .
dict at: anInteger put: aSess.
^ aSess 
%

category: 'Private'
method: GsSession
_initFromSessionDescription: anArray

"Initializes the receiver using  anArray, which must be a result from 
 System (C) | _descriptionOfSessionSerialNum:sessionId:."

sessionSerialNum := anArray at: 9 .
userProfile := anArray at: 1 
%

category: 'Private'
classmethod: GsSession
serialOfSession: aSessionId

"Returns a SmallInteger, the unique serial number of the session that is
 currently logged in as aSessionId, or -1 if that session is not logged in.

 Requires SessionAccess privilege if the session described by aSessionId is
 not the current session."

| descr |
descr := System _descriptionOfSessionSerialNum: 0 sessionId: aSessionId .
(descr at: 1 "UserProfile" ) == nil ifTrue:[ ^ -1 ].
^ descr at: 9
%

category: 'Private'
classmethod: GsSession
sessionIdOfSerial: aSerialNumber

"Returns the current session ID of the session uniquely identified by
 aSerialNumber, or -1 if that session is not logged in.

 Requires SessionAccess privilege if the session described by aSerialNumber is
 not the current session."

| descr |
descr := System _descriptionOfSessionSerialNum: aSerialNumber sessionId: -1 .
(descr at: 1 "UserProfile" ) == nil ifTrue:[ ^ -1 ].
^ descr at: 10
%

category: 'Accessing'
method: GsSession
sessionSerialNum

"Returns the value of the sessionSerialNum instance variable of the receiver."

^ sessionSerialNum
%

category: 'Accessing'
method: GsSession
userProfile

"Returns the UserProfile attached to the session."

^ userProfile
%

category: 'Accessing'
method: GsSession
remoteSessions

"Returns a collection of GsSession instances representing all the remote
 sessions spawned by the session represented by the receiver.  If the receiver
 has no remote sessions, the resulting collection is empty.  This list is
 maintained in the session transient state."

| sessionDict |

self == GsSession currentSession ifFalse:[ ^ nil "result is unknown" ].
" sessionDict maps parameters to sessions "
sessionDict := System _sessionStateAt: 8. "xxx not yet updated"
sessionDict == nil ifTrue:[ ^ #() ].
^ sessionDict values
%

category: 'Accessing'
method: GsSession
serialNumber

"Returns the serial number issued to the session represented by the receiver
 when that session logged in."

^ sessionSerialNum
%

category: 'Session Control'
method: GsSession
stop

"Aborts the current transaction and terminates the session.  If  the receiver is
 the current session, no operation is performed.  If the UserProfile of the
 current session lacks SystemControl privilege, an exception occurs."

self == GsSession currentSession ifTrue:[ ^ self "do nothing" ].

System _stopSession: sessionSerialNum
%

category: 'Signalling'
method: GsSession
enableInterSessionSignalling: aBoolean

"If aBoolean is true, enables receipt of intersession signals in the session
 represented by the receiver.  Otherwise, disables receipt of such signals."

System enableSignaledGemStoneSessionError
%

category: 'Signalling'
method: GsSession
sendSignalObject: aGsInterSessionSignal

"Sends the signal and message of aGsInterSessionSignal to the session
 represented by the receiver."

System _sendSignal: aGsInterSessionSignal signal
       toSess: sessionSerialNum 
       withMessage: aGsInterSessionSignal message
%

category: 'Testing'
method: GsSession
isRemote

"Returns true if the receiver represents a remote federated session."

^ self ~~ GsSession currentSession
%

category: 'Testing'
method: GsSession
hasRemoteSessions

"Returns true if the receiver has remote sessions, false otherwise.

 If the receiver is itself a remote session, returns nil."

| rsess |

rsess := self remoteSessions.
rsess == nil ifTrue:[ ^ nil "don't know the answer" ].
^ rsess size > 0
%

category: 'Testing'
method: GsSession
isCurrent

"Returns true if the receiver represents the current login session of this Gem;
 returns false otherwise."

^ self == GsSession currentSession
%

! fix 36822 , install final version of SymbolList>>_validatePrivilege now
category: 'Updating'
method: SymbolList
_validatePrivilege

"  
To modify your own SymbolList, you need #CodeModification.
To modify another's SymbolList, you need #OtherPassword.
"

| upro |
upro := System myUserProfile .
self == upro symbolList ifTrue:[
  upro _validateCodeModificationPrivilege
] ifFalse:[
  self == GsSession currentSession symbolList ifTrue:[
    upro _validateCodeModificationPrivilege
  ] ifFalse:[
    upro _validatePrivilegeName: #OtherPassword
  ].
].
%

