When you install GemBuilder, your Smalltalk image becomes “GemStone-enabled,” meaning that your image is equipped with additional classes and methods that allow it to work with shared, persistent objects through a multi-user GemStone object server. Your Smalltalk image remains a single-user application, however, until you connect to the object server. To do so, your application must log in to a GemStone object server in much the same way that you log in to a user account in order to work on a networked computer system.
This chapter explains how to communicate with the GemStone object server by initiating and managing GemStone sessions.
Client Libraries
explains how to setup to use the correct client shared libraries.
GemStone Sessions
introduces sessions and explains the difference between RPC and linked sessions.
Session Control in GemBuilder
explains how to use the classes GbsSession, GbsSessionManager, and GbsSessionParameters to manage GemBuilder sessions.
Logging In to and Logging Out of GemStone
describes how to log in and out of GemStone sessions programmatically.
Session Dependents
explains how to use the Smalltalk dependency mechanism to coordinate the effects of session management actions on multiple application components.
Before you can log in to a GemStone object server, in addition to having GBS loaded in your image, you must have the client libraries available for loading into your image. The client libraries are provided with the GemStone object server product release. You must use the correct client libraries for the particular version of the object server you wish to connect to, and for the platform that the client Smalltalk image is running on. If you update to a new version of GBS, but continue to use the same version of the GemStone server, the same client libraries will be used.
There are a number of options for where to put your client libraries to they can be accessed by GBS, and options on how to set the library names in GBS. These options, as well as the correct client library name to use for your GemStone/S server product and version, are described in the GemBuilder for Smalltalk Installation Guide.
The current client library name is stored in the GbsConfiguration setting “libraryName”. This can be viewed or set using the Settings dialog, or you may execute:
GbsConfiguration current libraryName
GbsConfiguration current libraryName: ‘libraryName’
For more information on this setting, see Chapter 10, “GemBuilder Configuration Parameters”.
An application connects to the GemStone object server by logging in to the server and disconnects by logging out. Each logged-in connection is known as a session and is supported by one Gem process. The Gem reads objects from the repository, executes GemStone Smalltalk methods, and propagates changes from the application to the repository.
Each session presents a single-user view of a multiuser GemStone repository. Most applications use a single session per client; but an application can create multiple sessions from the same client, one of which is the current session at any given time. You can manage GemStone sessions either through your application code or through the GemStone Launcher.
A Gem can run as a separate operating system process and respond to Remote Procedure Calls (RPCs) from its client, in which case the session it supports is called an RPC session.
On platforms that host the GemStone object server and its runtime libraries, one Gem can be integrated with the application into a single operating system process. That Gem is called a linked session. When running linked, an application and its Gem must run on the same machine and the runtime code requires additional memory.
An RPC session offers more flexibility because the application and its Gem are separate processes that can run on different hosts in a network. Any GemBuilder client can create RPC sessions. Where a linked session is supported, an application can create multiple sessions, but only one can be linked. To suppress linked sessions, forcing all Gems to run as RPC processes, you can load the RPC-only version of the shared libraries.
Figure 2.1 shows an application with two logged-in sessions. Gem A is an RPC session running as a separate process, while Gem B is a linked session, sharing the client Smalltalk application's process space.
Managing GemStone sessions involves many of the same activities required to manage user sessions on a multi-user computer network. To manage GemStone sessions, you need to do various operations:
Three GemBuilder classes provide these session control capabilities: GbsSession, GbsSessionParameters, and GbsSessionManager.
GbsSession
An instance of GbsSession represents a GemStone session connection. A successful login returns a new instance of GbsSession. You can send messages to an active GbsSession to execute GemStone code, control GemStone transactions, compile GemStone methods, and access named server objects.
GbsSessionParameters
Instances of GbsSessionParameters store information needed to log in to GemStone. This information includes the Stone name, your user name, passwords, and the set of connectors to be connected at login.
GbsSessionManager
There is a single instance of GbsSessionManager, named GBSM. Its job is to manage all GbsSessions logged in from this client, support the notion of a current session (explained in the following section), and handle other miscellaneous GemBuilder matters. Whenever a new GbsSession is created, it is registered with GBSM. GBSM shuts down any server connections before the client Smalltalk quits.
To initiate a GemStone session, you must first identify the object server and user account to which you wish to connect. This information is stored in an instance of GbsSessionParameters and added to a list maintained by GBSM. You can provide the information through window-based tools or programmatically. Both methods are described in later sections. In either case, you must supply these items:
!@pelican!gs64stone
You can specify that the gem is to run on a remote host by using an NRS for the Gem service name For example:
!@pelican!gemnetobject
You do not need to supply a Gem Service name if you are starting a linked Gem process.
Once defined, an instance of GbsSessionParameters can be used for more than one session. Thus, a session description that includes the RPC-required parameters can be used for both linked and RPC logins.
The instance creation method for a full set of RPC parameters is:
GbsSessionParameters newWithGemStoneName: aGemStoneName
username: aUsername
password: aPassword
hostUsername: aHostUsername
hostPassword: aHostPassword
gemService: aGemServiceName
For a shorter set of parameters that supports only linked logins, you can use a shorter creation method:
GbsSessionParameters newWithGemStoneName: aGemStoneName
username: aUsername
password: aPassword
If you want the GemBuilder session manager to retain a copy of your newly-created session description for future use, you must register it with GBSM:
GBSM addParameters: aGbsSessionParameters
Once registered with GBSM and saved with the image, the parameters are available for use in future invocations of the image. In addition, the GemStone Launcher and other login prompters make use of GBSM’s list of session parameters.
Executing the expression GBSM knownParameters returns an array of all GbsSessionParameters instances registered with GBSM.
To delete a registered session parameters object, send removeParameters: to GBSM:
GBSM removeParameters: aGbsSessionParameters
You can control the degree of security that GemBuilder applies to the passwords in a session parameters object. For example, when you create the parameters object, you can specify the passwords as empty strings. When the parameters object is subsequently used in a login message, GemBuilder will prompt the user for the passwords.
mySessionParameters := GbsSessionParameters
newWithGemStoneName: '!@pelican!gs64stone'
username: 'DataCurator'
password: ''
hostUsername: 'lisam'
hostPassword: ''
gemService: '!@pelican!gemnetobject'
If convenience is more important than security, you can fill in the passwords and then instruct the parameters object to retain the password information for future use:
mySessionParameters rememberPassword: true;
rememberHostPassword: true
The default “remember” setting for both passwords is false, which causes the stored passwords to be erased after login.
Before you can start a GemStone session, you need to have a Stone process and, for an RPC session, a NetLDI (network long distance information) process running.
Depending on the terms of your GemStone license, you can have many sessions logged in at once from the same GemBuilder client. These sessions can all be attached to the same GemStone repository, or they can be attached to different repositories.
The protocol for logging in is understood both by GBSM and by instances of GbsSessionParameters. To log in using a specific session parameters object, send a login message to the parameters object itself:
mySession := aGbsSessionParameters login
To start multiple sessions with the same parameters, simply repeat these login messages.
An application can also send a generic login message to GBSM:
mySession := GBSM login
This message invokes an interactive utility that allows you to select among known GbsSessionParameters or to create a new session parameters object using the Session Parameters Editor.
A successful login returns a unique instance of GbsSession. (An unsuccessful login attempt returns nil.) Each instance of GbsSession maintains a reference to that session’s parameters, which you can retrieve by sending:
myGbsSessionParameters := aGbsSession parameters
GBSM maintains a collection of currently logged in GbsSessions. You can determine if any sessions are logged in with GBSM isLoggedIn and you can execute GBSM loggedInSessions to return an array of currently logged in GbsSessions.
When a new GbsSession is created, it is registered with GBSM, which maintains a variable that represents the current session. When a session logs in, it becomes the current session. If you execute code in a GemStone tool, the code is evaluated in the current session, or in the session that was current when you opened that tool. If you send a message to GBSM that is intended for a session, the message is forwarded to the current session.
You can send a message directly to any logged-in GbsSession, even when it is not the current session. If you send a specific session a message that executes code, that code is evaluated in the receiving session, regardless of whether it is the current session.
Most applications have only one session logged in at a time. In this case, that session will always be the current session, and it is safe to send messages to GBSM for forwarding to the session.
However, if your application concurrently logs in more than one session, your application should send messages directly to each session. If your application client uses multiple Smalltalk processes it is very difficult to accurately coordinate the changing of the current session.
Sending the message GBSM currentSession returns the current GbsSession. You can change the current session in a workspace by executing an expression of the following form:
GBSM currentSession: aGbsSession.
Your application can make another session the current session by executing code like that shown in Example 2.1:
|s1 s2|
s1 := GBSM login.
s2 := GBSM login.
GBSM currentSession: s1. "Make s1 current"
.
. "Do some work"
.
GBSM currentSession: s2. Make s2 current"
Each GemStone browser, inspector, debugger, and breakpoint browser is attached to the instance of GbsSession that was the current session when it opened. For example, you can have two browsers open in two different sessions, such that operations performed in each browser are applied only to the session to which that browser is attached.
Workspaces, however, are not session-specific. Executing a GS-Do it in a workspace will execute in the current session.
To instruct a session to log itself out, send logout to the session object:
aGbsSession logout
Or, you can execute the more generic instruction:
GBSM logout
This message prompts you with a list of currently logged-in sessions from which to choose.
Before logging out, GemBuilder prompts you to commit your changes, if the GbsConfiguration setting confirm is true (it is true by default). If you log out after performing work and do not commit it to the permanent repository, the uncommitted work you have done will be lost.
If you have been working in several sessions, be sure to commit only those sessions whose changes you wish to save.
An application can create several related components during a single GemBuilder session. When one of the components commits, aborts, or logs out, the other components can be affected and so may need to coordinate their responses with each other. In the GemBuilder development environment, for example, you can commit by clicking on a button in the GemStone Launcher. But before the commit takes place, all other session-dependent components are notified that a commit is about to occur. So a related application component, such as an open browser containing modified text, prompts you for permission to discard its changes before allowing the commit to proceed.
Through the Smalltalk dependency mechanism, any object can be registered as a dependent of a session. In practice, a session dependent is often a user-visible application component, such as a browser or a workspace. When one application component asks to abort, commit, or log out, the session asks all of its registered dependents to approve before it performs the operation. If any registered dependent vetos the operation, the operation is not performed and the method (commitTransaction, abortTransaction, etc.) returns nil.
To make an object a dependent of a GbsSession, send:
mySession addDependent: myObj
To remove an object from the list of dependents, send the following message:
mySession removeDependent: myObj
So, for example, a browser object might include code similar to Example 2.2 in its initialization method:
| mySession |
mySession := self session.
"Add this browser to the sessions dependents list"
(session dependents includes: self)
ifFalse: [session addDependent: self]
...
When a session receives a commit, abort, or logout request, it sends an updateRequest: message to each of its dependents, with an argument describing the nature of the request. Each registered object should be prepared to receive the updateRequest: message with any one of the following aspect symbols as its argument:
#queryCommit
The session with which this object is registered has received a request to commit. Return true to allow the commit to take place or false to prevent it.
#queryAbort
The session with which this object is registered has received a request to abort. Return true to allow the abort to take place or false to prevent it.
#queryEndSession
The session with which this object is registered has received a request to terminate the session. Return true to allow the logout to take place or false to prevent it.
Example 2.3 shows how a session dependent might implement an updateRequest: method.
updateRequest: aspect
"The session I am attached to wants to do something.
Return a boolean granting or denying the request."
^(#(queryAbort queryCommit queryEndSession)
includes: aspect)
ifTrue: [ self askUserForPermission ]
ifFalse: ["Let any other action occur."
true]
After the action is performed, the session sends self changed: with a parameter indicating the type of action performed. This causes the session to send an update: message to each of the registered dependents with one of the following aspect symbols:
#committed
All registered objects have approved the request to commit, and the transaction has been successfully committed.
#aborted
All registered objects have approved the request to abort, and the transaction has been aborted.
#sessionTerminated
The request to log out has been approved and the session has logged out.
Each registered dependent should be prepared to receive an update: message with one of the above aspect symbols as its argument. Example 2.4 shows how a session dependent might implement an update: method.
update: aSymbol
"The session I am attached to just did something.
I might need to respond."
(aSymbol = #sessionTerminated) ifTrue: [
"The session this tool is attached to has logged out
- close ourself."
self builder notNil ifTrue:
[self closeWindow]]
Figure 2.2 summarizes the sequence of events that occurs when a session queries a dependent before committing. In the figure, the GemStone Launcher sends a commit request (commitTransaction) to a session (1). The session sends updateRequest: #queryCommit to each of its dependents (2). If every dependent approves (returns true), the commit proceeds (4). Following a successful commit, the session notifies its dependents that the action has occurred by sending update: #committed to each (5).