3. Changes in GemStone Smalltalk

Previous chapter

Next chapter

This chapter describes changes and new features important for programmers using GemStone Smalltalk, including:

Changes in Classes, Compilation, and Code Management

Customer-defined Special Classes

Multithreaded Instance Migration

FileSystem

Support for ssh and sftp using OpenSSL

GsSecureSocket Additional Features

Data Encryption using Azure Key Vault

Changes in Magnitude Classes

String and Stream-related Changes

JsonParser and JsonPetitParser

External Session Changes

Other Changes and Enhancements

Deprecated and Removed Classes and Methods

3.1  Changes in Classes, Compilation, and Code Management

ClassOrganizer >> newExcludingGlobals

This method allows you to perform ClassOrganizer queries that do not return results exclusive to Globals. This can be used, for example, to find application methods that reference GsHostProcess or JsonParser classes (which may need to be recompiled; see the Installation Guide upgrade instructions), without including kernel methods that do not need recompiling.

ClassOrganizer >> newExcludingGlobals replaces the private method _newExcludingGlobals, which was available in some recent releases. Note that _newExcludingGlobals did not reliably exclude methods on classes in Globals.

GsNMethod >> recompileFromSource

This method has been added for convenient recompilation of a method from source code, such as the recompile needed for GsHostProcess and JsonParser. Existing recompile methods were designed for recompiling after bytecode changes; since they relied on the existing literal references, they did not update references to the obsolete class.

Note that if the symbolList of the user that is executing the recompile resolves literal names to different objects than the original compile, this may result in unexpected changes in behavior. Depending on the complexity of your application’s use of users’ symbolLists, you may wish to examine the source code before recompiling.

Added method Behavior >> compileMethod:category:environmentId:

The following method has been added, allowing you to compile a method using the current symbol list:

Behavior >> compileMethod: sourceString category:  aCategoryString environmentId: environmentId

#logCreation and logging class creation

The option #logCreation can be included in the options: of a class creation message, which results in the class creation being logged (using GsFile gciLogServer:). The primary purpose was for tracking class creation during build/upgrade filein. This option is not persistent and not printed (reported by Class >> definition), and thus was not retained if a class was filed out and in.

Now, you may set the key #GsClass_logCreation in SessionTemps, to force logging of all class creations for the lifetime of the session, using an expression such as:

SessionTemps current at: #GsClass_logCreation put: true

In the absence of this setting, the behavior is unchanged.

Improvements to filein using GsFileIn

GemStone supports filein of topaz-format source code using the class GsFileIn. This provides a functionality similar to topaz input, but permits only a subset of the full set of topaz commands. GsFileIn allows you to filein GemStone code programmatically, entirely from within GemStone code.

GsFileIn has been extensively revised. With v3.7, GsFileIn now supports source files that include extended characters encoded as Utf8; and performance has been greatly improved.

While instances of GsFileIn are not normally persisted, on upgrade, any existing instances become instances of ObsoleteGsFileIn.

The GsFileIn Class >> from*: API has been streamlined. While fromServerPath: and fromClientPath: may be used, the preferred methods (methods whose names are more accurate) are fromGemHostPath: and fromGciHostPath:, respectively. The method GsFileIn >> fromStream: has been added, to allow filein from streams.

For more details on GsFileIn, see the class comment, and methods in the image.

SystemUser SymbolList Changes

In v3.6.x, SystemUser’s SymbolList (visible when logged in as SystemUser), included a number of additional SymbolDictionaries, including GsCompilerClasses, ObsoleteClasses, RowanKernel, and in some versions GemStone_Portable_Streams and GemStone_Legacy_Streams. This facilitated work, or were artifacts of, the transition to Rowan-based code management.

For 3.7, all these dictionaries have been removed; the classes are located in subdictionaries within Globals, as needed.

3.2  Customer-defined Special Classes

GemStone now provides 16 predefined, customizable Special classes. Each can encode 56 bits of data.

These classes are named Special56bitN, and include Special56bit0 through Special56bit15.

To create an application Special class, you will modify one of the Special56bitN classes. You may change the superclass, rename the class, add methods, and if desired, change its security policy to allow other users to modify the class.

It is legal to create an association to this class from the same or another SymbolDictionary, but you should leave the association with the original name in the Globals dictionary, for upgrade.

The Special classes include a number of methods that invoke primitives. These and other support methods are in a category ’Base Methods’ and should not be modified. You may add all necessary methods to other categories within the class to support the specific functions you need.

For example, to setup a special class in a different SymbolDictionary, with the name classNameString, and allow users other than SystemUser to edit methods on the class:

1. Create an association in the target SymbolDictionary to the target name classNameString.

2. As SystemUser, implement Special56bitN class >> name to return classNameString, and execute specialClass >> changeNameTo: classNameString.

3. To allow developers other than SystemUser to edit this class, change its securityPolicy using:

specialClass objectSecurityPolicy: anObjectSecurityPolicy

4. It is allowed to change the superclass of a Special class, since the required primitive methods are defined in each class, rather than inherited. The new superclass (and each superclass up through Object) must be created with the #selfCanBeSpecial class creation option.

5. Bit-encode the specific data for your special into the 56 available bits, invoking the Class method value: to create an instance, and the instance method value to read and decode into your specific data type/s.

Note that care must be taken for fileout and filein, since the base class methods are a mix of GemStone methods and your own application methods. There are a number of ways to manage this, depending on your source management tools. The Money example shows a workaround using a customization of base image fileout.

Money example

An example of using this feature is the example at:

$GEMSTONE/examples/smalltalk/Money.gs

This example demonstrates using Special56bit0 to implement a Special Money class encoding an amount and an integer currency ID, to support US and Canadian Dollars, Euro and Yen. Note that this is a trivial example class, and does not provide the necessary currency support for a real-world application.

This example must be filed in as SystemUser. It creates the Money class in the Published dictionary. Methods on the resulting Money class can be edited by a user with access to the DataCuratorObjectSecurityPolicy.

3.3  Multithreaded Instance Migration

Faster instance migration is now possible using the new migration API. This allows you to specify up to 2000 classes; for each of these classes, every instance in the repository is migrated in a single operation within C code. Only simple migration operations on non-collection classes is supported. The primitive that performs this operation commits if successful, so this should be done when no other users would be committing, to avoid concurrency conflicts.

Multithreaded migration requires the MigrateObjects privilege; see MigrateObjects privilege.

This initial version of multi-threaded migration supports a limited set of migration pathways.

Supported:

Not supported:

For migrations that are not supported by the multi-threaded migration function, you can continue to use the object based message-send migration options.

Multi-threaded migration is configured using the class InstVarMappingArray, which was previously a support class for instance migration that was not directly used. An instance of this class is the input to the multi-threaded migration operations.

To ensure that your migration produces the results you expect and there are no unforeseen issues, it is recommended that prior to the actual migration, you test the migration with a more limited number of test objects. Repository >> testMigrateMt:with: allows you to perform the same migration as Repository >> migrateMt:, on a limited set of objects, and does not commit; after running this method commits are disallowed, so you must abort after running this test.

The following methods have been added:

Repository >> migrateMt: arrayOfMappings
Performs a multi threaded scan of the repository migrating instances of the classes found in the arrayOfMappings to their corresponding new classes. Up to 2000 classes can be migrated in a single operation. The classes must be committed. An error is generated if there are any modified persistent objects in the temporary object memory at the time it is executed.

The method will commit all of the migrated objects before it returns. It is possible that the commit may fail due to concurrency conflicts, so to avoid that the operation should be performed while there is no other activity on the system.

The arrayOfMappings is Array of instances of InstVarMappingArray which defines the classes that are to be migrated. For example:

SystemRepository migrateMt: 
   {(InstVarMappingArray mappingFrom: oldClass to: newClass)}

Before executing this method you may wish to execute testMigrageMt:with: to validate that the migration does what is intended.

Repository >> fastMigrateMt: arrayOfMappings
Like Repository >> migrateMt:, but performs the migration aggressively, using more system resources, in order to complete more quickly.

Repository >> testMigrateMt: arrayOfMappings with: testObjs
This method is similar to migrateMt: and can be used to test the migrateMt: operation on a limited number of objects before performing a full repository scan and migrating all objects.

It performs a multi threaded scan of only the objects listed in the test array, migrating the objects in the same way that migrateMt: would, but it does NOT commit them. The session is left in a state with commits disallowed. Once the objects have been inspected and have been verified that the migration performed as expected the user should abort the current transaction.

InstVarMappingArray

The existing InstVarMappingArray class has been modified and updated, and an instance can be created and customized directly for use by multi-threaded migration. An instance of InstVarMapping is defined for a single specific class, and specifies migratation of instance variables defined on that class and inherited instance variables in the same way.

Note that ordinary object based migration continues to use instances of InstVarMappingArray without specific customization.

The following methods have been added:

InstVarMappingArray >> mapInstVarNamed: oldName to: newName
The value at the instance variable named oldName in the old class should be migrated to the instance variable named newName in the new class.

InstVarMappingArray >> mapInstVarToNil: newName
The migration should not retain the value of any instance variable newName present in the instance of the old class. After migration; the object will have a nil value at this instance variable.

The origin and target classes are now in instance variables, and methods have been added to access these:

InstVarMappingArray >> oldClass

InstVarMappingArray >> newClass

Example

For example, to create a mapping from OrigClass to NewClass that moves the value of the instance variable oldName to the location of the instance variable newName in the NewClass:

| im |
im := InstVarMappingArray mappingFrom: OrigClass to: NewClass.
im mapInstVarNamed: #oldName to: #newName.
im mapInstVarToNil: #oldName.
im preserveDynamic: false.
SystemRepository migrateMt: { im }

Note that if you do not specify to set #oldName to nil, the value at oldName will be retained in the migrated instance (now a NewClass) in #oldName, as well as being set in the instance variable #newName.

3.4  FileSystem

FileSystem is a set of classes, ported and adapted from Pharo, that support operations on files and directories. FileSystem provides a much more flexible and feature-rich environment than GsFile. FileSystem performance is comparable to GsFile.

In these notes, the term ’FileSystem’ can be used to refer to the entire set of classes that support file and directory operations, or to the specific class named FileSystem. The specific class FileSystem represents the underlying file environment. Most operations within the general File System environment use the class FileReference, which represents a file or directory.

FileSystem is still under refinement, and may be missing features or contain unexpected behavior. The low level support classes in particular may be refactored and/or have protocol modifications.

Differences from GsFile

FileSystem supports a superset of the functions provided by GsFile for server files, and the API is significantly different.

Some differences:

  • FileSystem is implemented using multiple classes to provide a flexible and portable API, while GsFile is implemented as a single class with fixed behaviors.
  • FileSystem is implemented based on an FFI interface to the OS file system functions, while GsFile is implemented with user actions (for historic reasons) and C primitives.
  • On error, FileSystem signals an appropriate error; GsFile functions return nil and require you to query for the error details.
  • FileSystem does not support operations on the GCI client (for example, reading files on a Windows client), while GsFile does.

FileSystem is supported with Linux on x86 and ARM, and macOs on x86 and Apple Silicon. FileSystem is not supported on AIX; on AIX, you must continue to use GsFile.

Primary API classes

There are a few main entry points for FileSystem.

  • FileReference

FileReference is the primary entry point for file and directory operations. You may create files using FileReference >> / , FileReference >> @, aString asFileReference, or by using FileSystem class protocol. FileReferences can also be created from another instance of FileReference. The following are all equivalent:

'/gshost/test/foo.txt' asFileReference
FileReference / '/gshost/test/foo.txt'
FileReference / 'gshost' / 'test' / 'foo.txt'
FileReference disk @ '/gshost/test/foo.txt'
FileSystem disk / '/gshost/test/foo.txt'
'/gshost/test/' asFileReference / 'foo.txt'

The FileReference that is created prints as:

FileReference disk @ '/gshost/test/foo.txt'

There are a great many supported operations, including both information about the file or directory, and operations on that file or directory. Note that much of the API is on the superclass, AbstractFileReference. The methods include:

  • report if the receiver is a file or directory, and for directories, report details on the contained children (files or directories).
  • return details of the path, filename, and extension
  • return information about a file, such as size, permissions, modificationTime, etc.
  • open a read or write stream on the contents, including encoded and binary streams.

Operations on the contents of a FileReference will normally use streams. Methods such as readStream and writeStream return instances of Zinc-based streams, in this case ZnCharacterReadStream or ZnCharacterWriteStream. For example:

rdStream := 'gshost/test/foo.txt' asFileReference readStream.
[rdStream atEnd] whileFalse: 
     [report add: rdStream nextLine; lf.].
rdStream close. 

Variants such as readStreamDo: and writeStreamDo: automatically close the file after performing the block operation.

By default, these streams provide automatic UTF-8 encoding, although method variants allow you to specify an encoder to support legacy 8-bit encoding.

Binary read and write streams created using binaryReadStream and binaryWriteStream create instance of FsBinaryFileStream, allowing byte-based operations with no encoding.

  • FileLocator

FileLocator provides similar file operations to FileReference, but the file or directory does not need to have an explicit full path. The location for a FileLocator instance can be relative to your environment; for example, the working directory, the directory containing the extent files, or the directory containing gem logs. This allows you to move code between environments without requiring explicit management of the paths. For example the following code does not need to be changed if executed in different environment:

outFile := FileLocator home / 'output.txt'.
outFile 
writeStreamDo: [:stream | stream nextPutAll: 'test results'] 
ifPresent: [FileAlreadyExistsException signalWith: outFile]

You can see the available environment-dependent origins using FileLocator class >> supportedOrigins; class methods are available for all, including home, cache, temp, userData, tranlog, preferences, extent1Directory, extent1, documents, desktop, and workingDirectory.

To find the resolved value of the FileLocator, you can send the message absolutePath; this returns an instance of a kind of Path.

FileLocator extent1 absolutePath printString
%
Path / 'gshost' / 'GemStone3.7' / 'data' / 'extent0.dbf'

FileLocator understands most of the methods available for FileReference.

  • FileSystem

While the primary entry point is FileReference, the class FileSystem can provide a way to define a FileReference. FileSystem supports ordinary disk based file systems and in-memory file systems.

FileSystem has a number of useful methods for defining FileReferences. For example:

FileSystem disk
returns a disk-based FileSystem, which can be used with @ or / to create a FileReference, e.g. FileSystem disk / '/gshost/test/foo.txt'.

FileSystem memory
returns an in memory-based FileSystem, which can be used with @ or / to create a FileReference, e.g. FileSystem memory / 'foo' / 'bar'.

FileSystem workingDirectory
creates a FileReference to the current working directory (disk-based).

FileSystem includes instance methods that allow you to perform a number of file and directory operations, but these methods are subject to change or removal in later releases. Use instances of FileReference to perform file and directory operations other than creating references and setting the working directory.

  • FsFileDescriptor

FsFileDescriptor represents the file itself. FileReference open: methods return an instance of this class, which can be used to perform basic file operations.

FsFileDescriptors read and write ByteArrays rather than strings.

Supporting Classes

Zinc Stream Classes

Subclasses of ZnStream, including ZnBuffed*Stream, ZnEncoded*Stream, and Zn*Encoder, provide read and write streams for FileSystem. Zn*Encoder streams handle the encoding/decoding from UTF-8 and 8-bit (GemStone legacy) encoded files, and the creation of Legacy or Unicode String instances.

Opening options

FsFileOpeningOptions provide the operating-system specific options for opening files.

Error Classes

FsError and its subclasses represent FileSystem errors; FileException and its subclases represent FileReference/FileLocator errors. Other errors such as FsUnixError and its subclasses represent low level UNIX file errors, which are generally handled by public API.

Path classes

Path, RelativePath, and Absolute Path encapsulate a path. A Path can be obtained from a FileReference and vice versa. While Path is an abstract class, you can use it to create instances, e.g. Path from: '/gshost/test/' will return an instance of AbsolutePath.

Store classes

FileSystemStore and subclasses represent the OS file system or memory file system, with differences for specific operating systems.

Resolver classes

FileSystemResolver and subclasses support resolving various FileLocator origin options, which vary between operating systems.

FFI support classes

FsLibcInterface and FsCStruct and their subclasses provide the FFI interface to the operating system file commands.

3.5  Support for ssh and sftp using OpenSSL

The libssh libraries include support for ssh and sftp. These commonly used functions are now available programmatically using GemStone classes.

The following classes have been added:

GsSshSocket

GsSftpSocket

GsSftpRemoteFile

SshSocketError (error 2759)

Examples of using these classes are provided in class side methods.

SSH with GsSshSocket

Creating the SSH connection

To create a SSH connection, create a client socket using methods inherited from GsSocket, and connect using sshConnect.

For example, the following code connects to the host hostnameOrIP:

sshSock := GsSshSocket newClient.
sshSock connectToHost: hostnameOrIP timeoutMs: 2000.
sshSock userId: userName; password: userPassword.
sshSock disableHostAuthentication.
sshSock sshConnect.

As with all sockets, you should close the socket when you no longer need the connection.

sshSock close
SSH operations

Commands are executed using executeRemoteCommand:. For example,

result := sshSock executeRemoteCommand: 'uptime'.

The commands can be executed non-blocking using the following methods:

nbExecuteRemoteCommand:
hasCommandInProgress
nbRemoteCommandResult
nbRemoteCommandResultReady

SFTP with GsSftpSocket

Creating Sftp connection

Creating an SFPT connection is just like creating an SSH connection. To create a SFTP connection, create a client GsSftpSocket using methods inherited from GsSocket, and connect using the method sshConnect.

For example, the following code connects to the host hostnameOrIP:

sshSftpSock := GsSftpSocket newClient.
sshSftpSock connectToHost: hostnameOrIP timeoutMs: 2000.
sshSftpSock userId: userName; password: userPassword.
sshSftpSock disableHostAuthentication.
sshSftpSock sshConnect.

As with all sockets, you should close the socket when you no longer need the connection.

sshFtpSock close
Sftp operations

Once the GsSftpSocket instance is created and connected, there are a number of methods supported, including:

GsSftpSocket >> remoteFileExists: aFileOrDirectory 
GsSftpSocket >> currentRemoteDirectory  
GsSftpSocket >> createRemoteDirectory: dirname 
GsSftpSocket >> createRemoteDirectory: dirname mode: modeInt  
GsSftpSocket >> contentsOfRemoteDirectory: dirname 
GsSftpSocket >> contentsOfRemoteDirectory: dirname matchPattern: aString  
GsSftpSocket >> renameRemoteFile: oldName to: newName 
GsSftpSocket >> removeRemoteFile: filename 
GsSftpSocket >> removeRemoteDirectory: dirname 
GsSftpRemoteFile for operations on remote files

The class GsSftpRemoteFile represents an instance of a remote file that can be used for reading and writing. You must have an established GsSftpSocket connection, which is an argument to the instance creation methods.

GsSftpRemoteFile class >> openRemoteFile: fileName mode:  openMode permissions: permInt errorIfExists: aBoolean withSftpSocket:  aGsSftpSocket

GsSftpRemoteFile class >> openRemoteFileAppend: fileName withSftpSocket:  aGsSftpSocket

GsSftpRemoteFile class >> openRemoteFileReadOnly: fileName withSftpSocket:  aGsSftpSocket

GsSftpRemoteFile class >> createNewRemoteFile: fileName withSftpSocket:  aGsSftpSocket

GsSftpRemoteFile class >> createOrOverwriteRemoteFile: fileName withSftpSocket:  aGsSftpSocket

Once an instance of GsSftpRemoteFile has been created, use the instance protocol to read, write, and fetch information about the remote file. See the image for specific methods.

For example, to download a remote file using SFTP:

sshSftpSock := GsSftpSocket newClient.
sshSftpSock connectToHost: hostnameOrIP timeoutMs: 2000.
sshSftpSock userId: userName; password: userPassword.
sshSftpSock disableHostAuthentication.
sshSftpSock sshConnect.
remoteSftpFile := GsSftpRemoteFile 
openRemoteFileReadOnly: remoteFileName 
withSftpSocket: sshSftpSock.
localFile := GsFile openWriteOnServer: localFileName.
bytes := remoteSftpFile readAllInto: localFile.
localFile close.
sftpFile close.

3.6  GsSecureSocket Additional Features

Note that while the term SSL (Secure Socket Layer) is commonly used within GemStone for clarity, specifically the protocol is TLS (Transport Layer Security), using OpenSSL.

Support for pre-shared keys

Pre-shared keys are symmetric keys shared in advance among the communicating parties. Support has been added to GsSecureSocket for pre-shared keys. The callback protocols are dependent on the TLS version; methods have been added to define and manage the version, see TLS Version handling.

GsSecureSocket >> setPreSharedKey: aByteArray
Sets the Pre-Shared Key (psk) for the connection to be the bytes contained in aByteArray. Raises an exception if the receiver is already connected or listening for a connection. aByteArray must have a size of at least 8 bytes, not more than 64 bytes and be a multiple of 8 (16, 24, 32 etc). A key size of at least 16 bytes is recommended.

Invoking this method an additional time overwrites any previously stored PSK. To clear a the previously set PSK, invoke this method with an argument of nil. Returns true on success.

Example in image

preSharedKeyTlsClientExample: logToGciClient usingPort: portNum on: host
Pre-shared key transport layer security (PSK-TLS) requires the client and server to both know a pre-shared secret key before the connection is initiated. The key must be at least 8 bytes in size (16 hex digits) and be stored in a ByteArray.

GsSecureSocket class >> preSharedKeyTlsServerExample: logToGciClient usingPort: portNum on: host
Pre-shared key transport layer security (PSK-TLS) requires the client and server to both know a pre-shared secret key before the connection is initiated. The key must be at least 8 bytes in size (16 hex digits) and be stored in a ByteArray.

Anonymous TLS

Anonymous TLS connections are exposed to man-in-the-middle attacks and are therefore NOT recommended for most applications.

Example in image

GsSecureSocket class >> anonymousTlsClientExample: logToGciClient usingPort: portNum on: host
Client side of Anonymous TLS example. Anonymous TLS means encrypting data over the socket connection without verifying the client or the server's identity. Because identities are not verified, certificates are not required to establish a connection.

GsSecureSocket class >> anonymousTlsServerExample: logToGciClient usingPort: portNum on: host
Server side of Anonymous TLS example. Anonymous TLS means encrypting data over the socket connection without verifying the client or the server's identity. Because identities are not verified, certificates are not required to establish a connection.

TLS Version handling

The added methods to set and get actual, maximum and minimum TLS version accept the following argument symbols for tlsVersionStringOrSymbol:

  • #TLS_VERSION_DEFAULT = use any supported TLS protocol. This is the default behavior.
  • #TLS1_VERSION = TLS version 1.0
  • #TLS1_1_VERSION = TLS version 1.1
  • #TLS1_2_VERSION = TLS version 1.2
  • #TLS1_3_VERSION = TLS version 1.3

Instance methods for the TLS version

GsSecureSocket >> tlsActualVersion
Answers a Symbol indicating the actual TLS protocol version used by the receiver. The TLS protocol version for the connection is negotiated by the receiver and its peer during the TLS handshake. This method returns the actual version symbol, not #TLS_VERSION_DEFAULT. Raises an exception if the receiver has not completed the TLS handshake with its peer. For server sockets, the TLS handshake is complete after the #secureAccept succeeds. For client sockets, the TLS handshake is complete after the #secureConnect method succeeds.

GsSecureSocket >> tlsMaxVersion
Gets the maximum TLS protocol version for the receiver.

GsSecureSocket >> tlsMaxVersion: tlsVersionStringOrSymbol
Sets the maximum TLS protocol version for the receiver. Returns true on success or raises an exception if the argument is invalid. Raises an exception if the argument would set the maximum TLS protocol version to be less than a previously set minimum TLS protocol version.

GsSecureSocket >> tlsMinVersion
Gets the minimum TLS protocol version for the receiver.

GsSecureSocket >> tlsMinVersion: tlsVersionStringOrSymbol
Sets the minimum TLS protocol version for the receiver. Returns true on success or raises an exception if the argument is invalid. Raises an exception if the argument would set the minimum TLS protocol version to be greater than a previously set maximum TLS protocol version.

Class methods for maximum and minimum TLS version

GsSecureSocket class >> tlsClientMaxVersion
Gets the maximum TLS protocol version for client sockets created by the receiver.

GsSecureSocket class >> tlsClientMaxVersion: tlsVersionStringOrSymbol
Sets the maximum TLS protocol version for client sockets created by the receiver. Returns true on success or raises an exception if the argument is invalid. Raises an exception if the argument would set the maximum TLS protocol version to be less than a previously set minimum TLS protocol version.

GsSecureSocket class >> tlsClientMinVersion
Gets the minimum TLS protocol version for client sockets created by the receiver.

GsSecureSocket class >> tlsClientMinVersion: tlsVersionStringOrSymbol
Sets the minimum TLS protocol version for client sockets created by the receiver. Returns true on success or raises an exception if the argument is invalid. Raises an exception if the argument would set the minimum TLS protocol version to be greater than a previously set maximum TLS protocol version.

GsSecureSocket class >> tlsServerMaxVersion
Gets the maximum TLS protocol version for server sockets created by the receiver.

GsSecureSocket class >> tlsServerMaxVersion: tlsVersionStringOrSymbol
Sets the maximum TLS protocol version for server sockets created by the receiver. Returns true on success or raises an exception if the argument is invalid. Raises an exception if the argument would set the maximum TLS protocol version to be less than a previously set minimum TLS protocol version.

GsSecureSocket class >> tlsServerMinVersion
Gets the minimum TLS protocol version for server sockets created by the receiver.

GsSecureSocket class >> tlsServerMinVersion: tlsVersionStringOrSymbol
Sets the minimum TLS protocol version for server sockets created by the receiver. Returns true on success or raises an exception if the argument is invalid. Raises an exception if the argument would set the minimum TLS protocol version to be greater than a previously set maximum TLS protocol version.

Modified SNI example code in image

To support running the SNI example on RedHat compatible Linux as well as Ubuntu, the method:

GsSecureSocket class >> httpsClientExampleForHost:certificateDirectory:withSniName:

has been removed; it is replaced by the new method:

GsSecureSocket class >> httpsClientExampleForHost:withSniName:

which invokes the added method:

GsSecureSocket class >> setCaCertLocation
Certificate verification for the example is designed to Ubuntu and RedHat-compatible Linux. Look for the trusted CA cert file on the current host. If we find it, use it. If we do not, disable cert verification so the examples work correctly.

Ubuntu: /etc/ssl/certs/ca-certificates.crt

Red Hat-compatible: /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem

Returns the CA cert file used or nil if no file was found and certificate verification has been disabled.

3.7  Data Encryption using Azure Key Vault

GemStone now supports key management using Microsoft Azure Key Vault, on Linux on Intel. This is similar to the support for AWS (Amazon Web Services) key management added in previous releases.

Azure Key Vault is a cloud service for securely storing and accessing secrets, such as encryption keys. GemStone classes allow you to use Azure Key Vault to hold keys for data encryption.

To use this feature, you must have an account with Azure, have created an Azure Key Vault, and obtained the client secret string. You must also have created one or more keys in that Key Vault. Consult the Azure documentation for more information.

The Azure SDK for C++ (see https://github.com/Azure/azure-sdk-for-cpp) is an open-source project that provides a C++ interface to Azure services. The GemStone distribution includes shared libraries based on the Azure toolkit. These libraries are included in the Linux/x86 distribution.

Version 3.7 of GemStone includes Azure SDK for C++ v1.9.0. In addition, the distribution includes a new external curl library, used to enable linking into the Azure shared library.

The following classes support this feature:

AzureCredentials - encapsulates the key information needed for authentication to the Azure Key Vault.

AzureDataKey - holds a local encryption key that can be used to encrypt and decrypt Strings and ByteArrays. This requires the Azure Key Vault URL and keyname, as well as the AzureCredentials needed to authenticate.

AzureError - signalled when errors occur in Azure API classes.

GemStone’s API allows you to authenticate a key name in a Key Vault, and use the resulting key instance to encrypt a String or ByteArray, which can be decrypted using that same key.

AzureDataKeys

A key is created using code such as:

cred := AzureCredentials
newWithClientId: '1234567890'
clientSecret: 'abcdefghij'
tenantId: '1a2b3c4d5e6f7g8h'.
key := AzureDataKey
createKeyUsingAzureCredentials: cred
keyVaultUrl: 'https://keyvaultname.vault.azure.net/'
keyName: 'keyname'.

This instance of AzureDataKey should be persisted in the database for ongoing use for encryption and decryption. If the key instance is lost, any data that was encrypted with that key cannot be decrypted, and is permanently inaccessible, even if the credentials are available.

AzureCredentials can be recreated as needed. Since a persisted instance of AzureDataKey is locked in newly logged in sessions, the same or a recreated instance of AzureCredentials will be needed to unlock a persisted instance of AzureDataKey.

Locking

An AzureDataKey may be in a locked or unlocked state. A newly created key is unlocked. The key can be explicitly locked, and is automatically locked when the creating session logs out. When it is saved to disk, it is saved in the locked state.

If a key is locked, it cannot be used to encrypt or decrypt data. Before it can be used, it must be unlocked using an instance of AzureCredentials that is valid to authenticate the AzureDataKey.

The following methods are available:

AzureDataKey >> lock
AzureDataKey >> unlockWithAzureCredentials: anAzureCredentials
AzureDataKey >> isLocked
AzureDataKey >> isUnlocked

Encryption/decryption

Encryption and decryption are done by sending a request to the (unlocked) AzureDataKey.

Encryption is performed using AES-OCB authenticated encryption, which ensures data that has been successfully decrypted has not been modified in any way.

AzureDataKey >> encrypt: srcByteObj into: destByteObj
Uses the receiver to encrypt srcByteObj and stores the resulting encrypted bytes into destByteObj as a Base64 string. srcByteObj must be a non-empty byte object. destByteObj must be a mutable byte object; any contents will be overwritten.

AzureDataKey >> encryptAndErase: srcByteObj into: destByteObj
Encrypt srcByteObj, erasing all data in srcByteObj, and store the resulting encrypted bytes into destByteObj as a Base64 string. srcByteObj must be a non-empty byte object. destByteObj must be a mutable byte object; any contents will be overwritten.

AzureDataKey >> decrypt: srcByteObj into: destByteObj
Uses the receiver to decrypt srcByteObj and stores the resulting decrypted bytes into destByteObj. srcByteObj must be a non-empty byte object containing Base64 encrypted text. destByteObj must be an mutable byte object.; any contents will be overwritten.

For example:

| credentials key data encryptedData decryptedData |
credentials := AzureCredentials
newWithClientId: '1234567890'
clientSecret: 'abcdefghij'
tenantId: '1a2b3c4d5e6f7g8h'.
key := AzureDataKey
createKeyUsingAzureCredentials: credentials
keyVaultUrl: 'https://keyvaultname.vault.azure.net/'
keyName: 'keyname'.
data := 'Please excuse my dear aunt Sally'.
encryptedData := String new.
decryptedData := String new.
key encrypt: data into: encryptedData.
key decrypt: encryptedData into: decryptedData.

Key rotation

Azure Key Vault provides the ability to do key rotation for improved security. You may update an instance of AzureDataKey to be associated with a new keyName, vault, and credentials, using the following method. To ensure that the change will be committed if successful, this method write locks the receiver and commits the session, so this requires that there are no uncommitted changes.

AzureDataKey >> changeKeyNameTo: newName inKeyVault: theVault usingCredentials: theCreds
Atomically update the receiver to use the key name newName, in the vault theVault, which is accessed with theCreds in a single operation, and commit. The receiver must be unlocked, the session must not have uncommitted changes, and the session must be able to write lock the receiver.

The key newName must already exist in the given vault. You may use the existing vault and credentials to rotate the key within the same vault, or use different parameters.

For example:

| key credentials data encryptedData decryptedData |
credentials := AzureCredentials
newWithClientId: '1234567890'
clientSecret: 'abcdefghij'
tenantId: '1a2b3c4d5e6f7g8h'.
key := AzureDataKey
createKeyUsingAzureCredentials: credentials
keyVaultUrl: 'https://keyvaultname.vault.azure.net/'
keyName: 'keyname'.
data := 'Please excuse my dear aunt Sally'.
encryptedData := String new.
decryptedData := String new.
key encrypt: data into: encryptedData.
key
changeKeyNameTo: 'key2' 
inKeyVault: 'https://keyvaultname.vault.azure.net/' 
usingCredentials: credentials.
key decrypt: encryptedData into: decryptedData.
data = decryptedData

Making a copy of a key

An AzureDataKey can be copied. The copy of an AzureDataKey has the same locked state as the original, and can be unlocked using the same credentials.

AzureDataKey >> copy
Answer a new object which is a deep copy of the receiver. The lock state of the receiver is preserved when copied, i.e.: if the receiver is unlocked the resulting copy will also be unlocked.

Key equality

AzureDataKey objects are considered equal (=) if they have the same vault, key name, and the same encrypted key string. Lock state does not affect equality.

Tracing Azure calls

The following environment variables can be defined in the client environment to print trace information on Azure calls. Setting these GemStone environment variables enables Azure environments variables to perform the debugging; note that the numeric values are defined by Azure, rather than conforming with GemStone’s other debugging environment variables.

GS_AZURE_LOG_DIR
A directory in which to create the azure log file

GS_AZURE_LOG_LEVEL
The level of logging. Valid values are 1, 2, 3, 4. The meanings of these values are:

1 – Verbose: Logging level for detailed troubleshooting scenarios

2 –Informational: Logging level when a function operates normally.

3 – Warning: Logging level when a function fails to perform its intended task.

4 – Error: Logging level for failures that the application is unlikely to recover from.

If both these environment variables are set to valid values, Azure creates a log file named

azure_sdk_YY-MM-DD-HH-mm-ss.log

where YY-MM-DD-HH-mm-ss are timestamp values, in the directory specified by $GS_AZURE_LOG_DIR.

3.8  Changes in Magnitude Classes

Float printing improvements

GemStone now includes the library double-conversion, which allows more control over floating point display. Float and SmallDoubles such as 9.45, that previously displayed as the technically correct, but not optimal, ’9.449999999999999’, now display as ’9.45’. (#47003)

In addition, Doubles may have up to 17 significant decimal digits, but the earlier code limited this to 16 decimal places. For example, a float created from ’7.6000000000000001’ was previously printed as 7.600000000000001, and is now 7.6000000000000005. (#46855)

Converting Non-specials in special range

A special object is one in which the OOP encodes the value, and thus requires no repository space; this is a canonical form of that value. A number of magnitude classes have subclasses with the prefix ’Small’, which provide a special/canonical form of a subset of that class’s potential values. While new values are created in canonical form, it is possible to have non-canonical instances that have an exactly equivalent canonical value. For example, an upgraded application may have an instance of Fraction with the value 1/3, rather than a SmallFraction with the value 1/3.

To convert a non-canonical to the canonical equivalent, the method asCanonicalForm has been added. This either returns self, or the canonical object exactly equivalent to the receiver. Specific implementations apply to Float, Date, DateAndTime, Time, Fraction, LargeInteger, and ScaledDecimal.

Note that this cannot perform a conversion in place; you must modify the object referring to the non-canonical value to refer to the canonical value.

highBit now ANSI-compliant

The method Integer, LargeInteger, and SmallInteger>>highBit previously returned nil for a zero receiver. Now, this method returns 0 for a zero receiver, as specified by the ANSI spec.

Other added method

The following method has been added:

SmallInteger >> minimum32bitInteger
Return the minimum value representable by a 32bit signed integer

3.9  String and Stream-related Changes

New ReadByteStream classes optimized for Strings

The class ReadByteStream, and the implementation classes ReadByteStreamPortable and ReadByteStringLegacy classes, have been added. This provides a ReadStream that is optimized for performance, and limited to holding kinds of String, MultiByteString, or ByteArray.

The API of ReadByteStream is largely the same as the existing ReadStream classes.

readStream reimplemented to return ReadByteStream

The method readStream, which was previously inherited from SequencableCollection to return an instance of ReadStream, has been reimplemented in MultiByteString, String, and ByteArray (and inherited by respective subclasses), to return an instance of ReadByteStream.

In Unicode mode, String auto-conversion to Unicode16

When the repository is in Unicode Comparison Mode, when an existing instance of String is modified such that it now includes a Character with any codePoint greater than 255, it is auto-converted to an instance of Unicode16. This includes when sending add:, addAll:, at:put:, and similar protocol.

Auto-conversion avoids subsequent performance impacts of comparisons using the ICU library, since strings must be converted for comparison.

Methods that operate on Bytes rather than Characters, such as String >> addAllBytes: and String class >> withBytes:, are not subject to this auto-conversion. Instance of DoubleByteString are not affected.

codePointAt:put: now performs auto-conversion if needed

Previously, sending codePointAt:put: to a String or DoubleByteString, with a codePoint that is out of range for that class, resulted in an OutOfRange error.

Now, the receiver will be transparently converted to the class that can contain the given codePoint; that is, converted from a String or DoubleByteString to a DoubleByteString or QuadByteString).

Empty Unicode7 string literals now canonicalized

In traditional String comparison mode, the string literal '' creates an instance of String, which is canonicalized (to the kernel OOP 233473). In Unicode comparison mode, in which '' creates an instance of Unicode7, these were previously not canonicalized. Now, these are canonicalized (to kernel OOP 165377).

Support for Lz4 encode/decode added to String and ByteArray classes

The following methods have been added, which allow Lz4 compression into a ByteArray, and decompression from Lz4-compressed data in a ByteArray into a byte-format object; normally but not necessarily a kind of String, MultiByteString, or ByteArray.

Compressing a multi-byte character object converts it to a little endian format before compressing, and decompression assumes the data is in little endian format.

You cannot compress, nor decompress into, a Symbol, DoubleByteSymbol or QuadByteSymbol.

Note that the compressed form does not distinguish the original class; for example, String or DoubleByteString; you must specify the correct class in the argument to the decompress method.

ByteArray, String, MultiByteString >> compressWithLz4: opCode
Compress the receiver with lz4 compression, and return an instance of ByteArray containing the compressed bytes. Compression modes include 0/frame mode and 1/blockmode; frame mode should normally be used.

ByteArray >> decompressWithLz4IntoNewInstanceOf: aClass decompressedSize: aSize
Decompress the receiver using lz4 and store the resulting bytes into a new instance of aClass. aClass must be a byte format Class. The lz4 compression mode (block or frame) used to compress the data is automatically detected by this method. aSize is a SmallInteger which indicates the size (in characters, not bytes) of the data when decompressed. If the contents were compressed using lz4 frame mode, aSize may be set to 0 indicating the decompressed size is not known. On success, returns a new instance of aClass containing the decompressed data.

ByteArray read/write of binary numbers in native format

The following methods have been added to allow you to read and write numeric values as raw bytes into a ByteArray in the current native byte order. Values are written in native format, and read as if in native format: no swizzling is done.

Note that there are existing methods in ByteArray to write and read numeric values; these methods read and write in big endian format, regardless of platforms.

ByteArray >> unsigned16AsNativeAt: startIndex
ByteArray >> unsigned32AsNativeAt: startIndex
ByteArray >> unsigned64AsNativeAt: startIndex
ByteArray >> signed16AsNativeAt: startIndex
ByteArray >> signed32AsNativeAt: startIndex
ByteArray >> signed64AsNativeAt: startIndex
ByteArray >> doubleAsNativeAt: startIndex
ByteArray >> floatAsNativeAt: startIndex
ByteArray >> signed16At: startIndex putAsNative: anInteger
ByteArray >> signed32At: startIndex putAsNative: anInteger
ByteArray >> signed64At: startIndex putAsNative: anInteger
ByteArray >> unsigned16At: startIndex putAsNative: anInteger
ByteArray >> unsigned32At: startIndex putAsNative: anInteger
ByteArray >> unsigned64At: startIndex putAsNative: anInteger
ByteArray >> doubleAt: startIndex putAsNative: aDouble
ByteArray >> floatAt: startIndex putAsNative: aFloat

The existing ByteArray methods at:put:signed:width: and at:signed:width: now accept additional width: arguments of 512, 1024, or 2048, which specify native format with 2, 4, or 8 bytes, respectively.

Added methods to return hashes as ByteArrays

The following methods have been added to CharacterCollection and ByteArray; these are similar to existing methods with the added "Bytes", and return the results in a ByteArray.

md5sumBytes
Return the 128 bit MD5 checksum of the receiver as a ByteArray. Computation is per RFC 1321 , http://www.ietf.org/rfc/rfc1321.txt, using L. Peter Deutsch's C implementation from: http://sourceforge.net/projects/libmd5-rfc/
For DoubleByteString and QuadByteString, the computation is based on viewing the string as a ByteArray holding big-endian characters.

sha1SumBytes
Return the 160 bit SHA1 checksum of the receiver as a ByteArray. Computation is per FIPS PUB 180-3: http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf.
For DoubleByteString and QuadByteString, the computation is based on viewing the string as a ByteArray holding big-endian characters.

sha256SumBytes
Return the 256 bit SHA256 checksum of the receiver as a ByteArray. Computation is per FIPS PUB 180-3: http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf.
For DoubleByteString and QuadByteString, the computation is based on viewing the string as a ByteArray holding big-endian characters.

sha3_224SumBytes
Return the SHA3 224 bit checksum of the receiver as a ByteArray. Computation is per FIPS PUB 202: https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf.
For DoubleByteString and QuadByteString, the computation is based on viewing the string as a ByteArray holding big-endian characters.

sha3_256SumBytes
Return the SHA3 256 bit checksum of the receiver as a ByteArray. Computation is per FIPS PUB 202: https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf.
For DoubleByteString and QuadByteString, the computation is based on viewing the string as a ByteArray holding big-endian characters.

sha3_384SumBytes
Return the SHA3 384 bit checksum of the receiver as a ByteArray. Computation is per FIPS PUB 202: https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf.
For DoubleByteString and QuadByteString, the computation is based on viewing the string as a ByteArray holding big-endian characters.

sha3_512SumBytes
Return the SHA3 512 bit checksum of the receiver as a ByteArray. Computation is per FIPS PUB 202: https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf.
For DoubleByteString and QuadByteString, the computation is based on viewing the string as a ByteArray holding big-endian characters.

sha512SumBytes
Return the 512 bit SHA512 checksum of the receiver as a ByteArray. Computation is per FIPS PUB 180-3: http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf.
For DoubleByteString and QuadByteString, the computation is based on viewing the string as a ByteArray holding big-endian characters.

Utf8 now disallows #readStream

The #readStream method, previously inherited from SequenceableCollection, has been disallowed in Utf8. Utf8 is intended to be only used in the encoded form; you should decode this prior to creating a readStream on it.

Other Changes

atOrNil: added

This method has been added to ByteArray, String and String’s subclasses DoubleByteString and QuadByteString, as part of the optimizations for ReadByteStream.

atOrNil: anIndex
Returns the Character at anIndex, or nil if anIndex is beyond end of the receiver

This is disallowed for Utf8 and Uft16.

Stream classes consistently return objects of their collection class

Previously, some methods could return an empty instance of String, rather than an instance of the collection class.

3.10  JsonParser and JsonPetitParser

Previous releases includes a PetitParser-based JSON Parser, which could read a JSON string and create the equivalent Smalltalk object structure. Using this class required some experience with PetitParser.

In this version, a new JSON parser has been added. This is a faster and simpler recursive descent parser, not related to PetitParser.

The class name 'JsonParser' is now applied to the new, simple JSON Parser. The old JSON parser, formerly 'JsonParser', is now 'JsonPetitParser'. JsonPetitParser is deprecated.

The API for the new JsonParser is much smaller; like JsonPetitParser, the new JsonParser is also accessed using the class method parse:. The new JsonParser signals errors on parse: of invalid JSON, unlike JsonPetitParser.

Upgrade impacts

Compiled methods that contain references to the JsonParser class in an earlier version, will refer to JsonPetitParser after upgrade and continue to work as before. Provided you are only using the JsonParser to parse JSON, it is optional to get the improved performance by recompiling methods that reference the JsonParser class by name.

If you are using JsonParser as part of a PetitParser customization, references to the class by name must be updated to refer to ‘JsonPetitParser’ instead of ‘JsonParser’. It is recommended to edit the source of methods that reference JsonParser class to reference JsonPetitParser, and edit the superclass of subclasses of JsonParser.

If you have subclasses of JsonParser that must be filed in, these will be compiled and refer to the new JsonParser class. If this subclass directly references inherited instance variables, compilation of those methods will fail; and depending on the specific modifications may or may not be functional. In most cases before filein, you should modify the code on disk to refer to JsonPetitParser.

See the Installation Guide for v3.7, Upgrade chapter, for recompilation details

3.11  External Session Changes

GsTsExternalSession no longer requires cpp/gcc/g++

Previously, GsTsExternalSessions computed the FFI calls for the GciTsLibrary on demand, using cpp to parse gcits.hf. This required cpp, and the gcc/g++ compilation environment; including for production use of GsTsExternalSessions.

Now, the FFI calls are precomputed for the current version, and provided in a new file that is loaded during upgrade, $GEMSTONE/upgrade/GciTsLibrary.dat.

Note that this applies to GsTsExternalSessions that login with the same GemStone version as the current Gem. For logins to Stones running a different version of GemStone/S 64 Bit, gcits.hf still must still be parsed, and cpp/gcc/g++ continues to be required.

Added methods for GsTsExternalSession

The following methods have been added:

GsTsExternalSession >> debugGem: processId token: anInteger
Use GciTsDebugConnectToGem instead of GciTsLogin to establish a connection. Arguments should be copied from the DEBUGGEM printout in a topaz .out file or log file. All normal login arguments are ignored.

GsTsExternalSession >> newUtf8String: aUtf8 toUnicode: aBoolean
Create a new instance of Utf8 (if aBoolean is false) or a Unicode7, Unicode16 or Unicode32 (if aBoolean is true), in the external session, containing the contents of aUtf8. Returns the oop of the object that was created in the external session.

GsTsExternalSession >> releaseOop: anOop
Queue anOop (an oop in the external session) to be released from the ExportSet of the remote session; once 100 oops have been released, the oops are releaseed, allowing the objects to be garbage collected.

GsTsExternalSession >> releaseOops: anArray
Release the oops in anArray (oops in the external session) from the ExportSet of the remote session, allowing the objects to be garbage collected.

GsTsExternalSession >> send: aSelector to: rcvrOop withOops: anArray
The same as send:to:withArguments:, but the arguments are already in the form of oops.

Return value from GsTsExternalSession >> waitForReadReadyTimeOut:

Previous, the method GsTsExternalSession >> waitForReadReadyTimeOut: msToWait returned self for success, and signaled an error if the timeout expired or an error occurred.

Now, this method returns true on success, false if there was a timeout, and signals an error if there was an error.

Easier to use GEM_HALT_ON_ERROR in external sessions

The default for haltOnErrNum has been changed to -1, to allow the Gem’s configuration file setting for GEM_HALT_ON_ERROR to be in effect for external sessions.

3.12  Other Changes and Enhancements

ProfMonitor improved formatting for object creation tree report

The tree report produced when doing object creation tracing in ProfMonitor or ProfMonitorTree has improved formatting for deeper trees.

GsSecureSocket example updates

The GsSecureSocket class method

httpsClientExampleForHost:certificateDirectory:withSniName: 

has been renamed to

httpsClientExampleForHost:withSniName:. 

The following methods has been added:

GsSecureSocket class >> setCaCertLocation
On linux: try to find the trusted CA cert file on this host. If we find it, use it. If we do not, disable cert verification so the examples work correctly.

isValidIdentifier, validateIsIdentifier optimized

The following methods are now implemented in primitives:

CharacterCollection >> isValidIdentifier
Object >> validateIsIdentifier

Other Added methods

GsFile >> beforeEnd
Answer true if the receiver is not positioned at the end, false otherwise

GsFile >> print: anObject
Writes the print representation of the argument to the GsFile receiver instance.

GsHostProcess >> readOutErr
Assuming both out and err are sockets, attempt to read from both and return combined result.

GsHostProcess >> redirectStderrToStdout
This should be used rather than stderrPath: if you want both stdout and stderr redirected to the same file.

GsNetworkResourceString >> gemConfig: aString
Include a -C configuration definition for the receiver. aString should be a valid -C argument; for example, 'GEM_TEMPOBJ_CACHE_SIZE=100MB;'.

Array >> copyNotNilFrom: startIndex to: stopIndex
Return an Array containing the non-nil elements that are within the specified offsets of the receiver.

Array >> indexOfNotNil: startOffset to: endOffset
If startOffset <= endOffset, returns the first offset within in the specified range of a non-nil element of the receiver. If startOffset > endOffset, returns the last offset within the specified range of a non-nil element of the receiver. Returns zero if all are nil. Intended for use only on Arrays of size <= 2000. Performance on larger arrays will be slow.

TestAsserter >> assert: anObject identical: otherObj
Assert that two objects are identical.

TestAsserter >> fail
Cause the test to report failure unconditionally

TestAsserter >> fail: descriptionString
Cause the test to report failure unconditionally, with the given description.

3.13  Deprecated and Removed Classes and Methods

See GciDirtyTrackedObjs functionality removed for additional removed methods related to the remove Tracked Dirty Objects set.

AbstractCharacter removed

The abstract class AbstractCharacter has been removed; Character superclass is now Magnitude. The AbstractCharacter definition is now in ObsoleteClasses.

Newly deprecated Methods

The following methods are newly deprecated. See the deprecation message for the replacement.

GsProcess >> stepIntoFromLevel:
GsProcess >> stepOverFromLevel:
GsProcess >> stepThroughFromLevel:
GsProcess >> terminateTimeoutMs:
GsProcess >> threadRubyEnvId
System >> sessionIdHoldingGcLock 

Obsolete Classes not in new images

In a new image, Globals will not include the long-obsolete placeholder classes:

GsfClassDefinitionInfo
GsfModificationLog

In a new image, (Globals at: #ObsoleteClasses) will not include the following classes:

ObsoleteConstrainedPathEvaluator
ObsoleteConstrainedPathTerm
ObsoleteEqualityIndexQueryEvaluator
ObsoleteIdentityIndexQueryEvaluator
ObsoleteIndexedQueryEvaluator
ObsoletePathEvaluator
ObsoletePathSorter
ObsoleteSetValuedPathEvaluator
ObsoleteSetValuedPathTerm

These will continue to exist in upgraded images.

Removed Public Methods

The following methods have been removed, associated with changes mentioned elsewhere in these release notes:

CPreprocessor >> defaultSparcSolarisDefinitions
CPreprocessor >> defaultX86SolarisDefinitions
Breakpoint class >> trappable:
GsSecureSocket class >> httpsClientExampleForHost:
   certificateDirectory:withSniName:
GsTestCase >> assert:isEquivalentTo:
Object >> removeObjectFromBtrees

Removed Previously-deprecated Methods

The following methods were previously deprecated, and have been removed:

ExecBlock >> valueNowOrOnUnwindDo:
Repository >> shrinkExtents
System class >> cacheStatisticsDescription

Removed Private Methods

AbstractException >> _signalAsync
AbstractException >> _signalFromPrimitive:
AbstractException >> _signalGcFinalize
AbstractException >> _signalTerminateProcess
AbstractException >> _signalTimeout
AbstractException >> _signalWith:
Behavior >> _transientSessionMethodBehaviorsCacheName
CCallout class >> _errno:
CharacterCollection >> _validIdentifier:
ClassOrganizer class >> _newExcludingGlobals
Delay >> _activate
ExecBlock >> _valueNowOrOnUnwindDo:
ExecBlock >> _valueNowOrOnUnwindDoPrim:
GsFileIn >> compileMethodIn:
GsFileIn >> fileStream:
GsFileIn class >> fromNestedClientPath:to:
GsFileIn class >> fromNestedPath:on:to:
GsFileIn class >> fromNestedServerPath:to:
GsFileIn class >> _fromStream:
GsFileIn class >> _fromStream:to:
GsNMethod >> _breakOperation:forStepPoint:
GsNMethod >> _setBreakAtIp:operation:frame:process:
GsNMethod >> __setBreakAtIp:operation:frame:process:
GsNMethod class >> _setBreakAtIp:operation:frame:process:
GsProcess >> _activate
GsProcess >> _continue
GsProcess >> _finishTermination
GsProcess >> _isRubyThread
GsProcess >> _serviceTerminationInterrupt
GsProcess >> _stepOverFromLevel:
GsProcess >> _stepOverInFrame:mode:replace:tos:
GsSocket >> _waitingProcessesInto:
GsSocket >> _waitingProcessesInto:inGroup:
GsTsExternalSession >> _getObjInfo:buffer:
IdentityBag >> _basicAdd:
IdentityBag >> _rcIncludes:
IdentityBag >> _rcIncludesValue:
IndexingErrorPreventingCommit >> _signalWith:
Integer >> _floatParts
Object >> addObjectToBtreesWithValues:
Object >> _respondsTo:private:flags:
Object >> _errorsDuringPreventCommit:
RcIdentityBag >> _thisSessionRemovalIndex
RcKeyValueDictionary >> _keyCollisionOk
SmallInteger >> _floatParts
System class >> _deprecatedCacheStatisticsDescription
System class >> _disallowSubsequentCommits:System class >> _primitiveAbort
System class >> _sessionsReportExcluding:
System class >> _hostWaitForDebuggerIfSlow

Previous chapter

Next chapter