VisualAge Smalltalk

Server Smalltalk Guide Version 5.5

򔻐򗗠򙳰

Note Before using this document, read the general information under “Notices” on page v.

May 2001 This edition applies to Version 5.5 of the VisualAge Smalltalk products, and to all subsequent releases and modifications until otherwise indicated in new editions. Make sure you are using the correct edition for the level of the product. The term “VisualAge,” as used in this publication, refers to the VisualAge Smalltalk product set. Portions of this book describe materials developed by Object Technology International Inc. of Ottawa, Ontario, Canada. Object Technology International Inc. is a subsidiary of the IBM Corporation. If you have comments about the product or this document, address them to: IBM Corporation, Attn: IBM Smalltalk Group, 621-107 Hutton Street, Raleigh, NC 27606-6324. You can fax comments to (919) 828-9633. When you send information to IBM, you grant IBM a nonexclusive right to use or distribute the information in any way it believes appropriate without incurring any obligation to you. © Copyright International Business Machines Corporation 1997, 2000. All rights reserved. US Government Users Restricted Rights – Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.

Contents Notices . . . . . . . . . . . . . . . v Trademarks.

.

.

.

.

.

.

.

.

.

.

.

.

.

. v

About this book . . . . . . . . . . . vii What this book includes . . . Who this book is for . . . . About this product or feature . Conventions used in this book. Tell us what you think . . . .

. .

. .

. .

. .

. .

. .

. vii . vii . . . . . . . viii . . . . . . . viii . . . . . . . ix

What’s New . . . . . . . . . . . . . xi What’s new in SST . . . What’s new in this book .

. .

. .

. .

. .

. .

. .

. .

. .

. xi . xi

Chapter 1. Getting started with SST . . . 1 Supported infrastructure . Transports and protocols Dispatchers . . . . . Marshalers . . . . . Spaces, contexts, URLs . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

3 3 3 3 3

Chapter 2. Concepts helpful for understanding SST . . . . . . . . . . 5 Connection-oriented design . . . . . . . . . 5 Remote references and proxies . . . . . . . . 6 Transient references . . . . . . . . . . . 7 Symbolic references . . . . . . . . . . . 7 Object spaces . . . . . . . . . . . . . 8 Application contexts . . . . . . . . . . . 8 Message passing . . . . . . . . . . . . 8 Logical processes . . . . . . . . . . . . 9 Multithreading and multiprocessing . . . . . 10 Actors . . . . . . . . . . . . . . . 11 Transactions . . . . . . . . . . . . . 12

Chapter 3. Building server applications 15 Categorization and Interfaces . . . . . . Configurations . . . . . . . . . . . Callbacks . . . . . . . . . . . . Startup and shutdown . . . . . . . . . Putting your application together . . . . . RPC-style applications . . . . . . . . Object invocation applications . . . . . An illustration: Ping-Pong examples . . . . Setting up the examples . . . . . . . Running the examples . . . . . . . . Summary . . . . . . . . . . . . Ping-Pong examples . . . . . . . . . Programming thin clients using communications SstHttpClientExample . . . . . . . . Server programming using invocation handlers SstHttpServerExample . . . . . . . . HTTP implementation notes . . . . . . Distributed objects using application contexts . © Copyright IBM Corp. 1997, 2000

. . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . .

15 16 16 17 17 17 19 20 20 21 22 23 25 25 26 27 27 28

Chapter 4. Inspecting and debugging SST applications . . . . . . . . . . 31 The SST menu . . . Inspectors . . . . . System objects . . . Distributed debugging. Using the Distributed Potential problems . Remote administration

. . . . . . . . . . . . . . . . Debugger . . . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

31 31 32 32 33 33 34

Chapter 5. Distributed garbage collection . . . . . . . . . . . . . 37 Requirements for using DGC . . . . Installation, startup and shutdown . . The DGC Object . . . . . . . . . DGC configuration . . . . . . . . Restrictions and side-effects . . . . . Good practice and bad practice . . . . Sending e-mail from code . . . . . Sending SMTP/Internet e-mail . . . Packaging notes for SST applications . . Direct packaging . . . . . . . Packaging through Server Workbench Packaging RMI applications . . . . Common packaging problems . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

37 37 38 38 39 40 40 40 41 41 41 41 42

Chapter 6. Constructing new SST configurations . . . . . . . . . . . 45 Chapter 7. Startup, shutdown, and restart . . . . . . . . . . . . . . . 47 Chapter 8. Configurations . . . . . . 49 Chapter 9. Communications Endpoints . . . . . . . . . . Equivalence between endpoints. . URLs . . . . . . . . . . . Transports . . . . . . . . . . Transport configurations . . . . Transport configuration registry . Connective transports . . . . . TCP transports . . . . . . . . TCP transport configuration . . . ‘tcp’ and ‘tcpl’ URLs . . . . . MQ transports . . . . . . . . MQ transport configuration . . . ‘mq’ URLs . . . . . . . . . Email transports (SMTP and IMAP4) . SMTP transport . . . . . . . IMAP4 transport . . . . . . Message tunneling . . . . . . . Communication messages . . . .

. . . . . 51 . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . .

51 52 52 54 54 55 55 56 56 58 59 59 59 60 60 60 61 62

iii

Message assemblers

.

.

.

.

.

.

.

.

.

.

. 63

Chapter 10. Method invocation . . . . 65 Requests . . . . . . . . . Invocation handlers. . . . . . Dispatchers . . . . . . . . Logical process invocation . . . Error and exception handling . UI handlers . . . . . . . Invocation handler configurations . Invocation handler callbacks. . Invocation handler restart modes Handler configuration registry .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

65 66 68 69 70 70 71 72 73 74

Chapter 11. Marshaling . . . . . . . . 75 By-value marshaling . . . . . . . By-reference marshaling . . . . . . Marshaling wrappers . . . . . . Marshaling with Swapper . . . . . Advanced Swapper-based marshaling Lightweight marshaling . . . . . . Advanced lightweight marshaling . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

76 76 77 78 79 80 80

Chapter 12. Remote object model . . . 83 Object spaces . . . . . . . . . . Space activations . . . . . . . Remote references . . . . . . . . Managing access to remote references Addressing objects with naming interfaces Space configurations . . . . . . . Object space callbacks . . . . . . Object space restart modes . . . . Application contexts . . . . . . . Context restart modes . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

83 84 85 86 88 89 90 90 91 92

Chapter 13. Server infrastructure . . . 93 Servers and servlets . Session management .

. .

. .

. .

. .

. .

. .

. .

. .

. .

. 93 . 93

Chapter 14. Java RMI support . . . . . 95

|

Java type information . . . . . . . com.ibm.sst.JavaTypeRepository . . SstRmiTools . . . . . . . . . Java type definitions . . . . . . Examples of Java RMI support . . . . Programming with RMI support . . . Configuring and starting RMI support Using JDK 1.2 . . . . . . . . Enabling Smalltalk objects . . . . Java client objects . . . . . . . Exceptions . . . . . . . . . Limitations . . . . . . . . .

iv

. . . . . . . . . . . .

VisualAge Smalltalk: Server Smalltalk Guide

. . . . . . . . . . . .

. . . . . . . . . . . .

. 96 . 96 . 97 . 97 . 99 . 99 . 99 . 101 . 102 . 103 . 103 . 104

| | | | | | | | | | | | | | | | | | | | | | |

Chapter 15. Using the Java/Smalltalk RMI Mapping Wizard . . . . . . . . 107 Setting up the VisualAge for Java Remote Access Tool to API and tool servlet interface . . . . RMI Wizard Java Interface Settings . . . . . Mapping a Smalltalk class to a Java class . . . Welcome page . . . . . . . . . . . Mapping Information page . . . . . . . Interface mapping page . . . . . . . . Field mapping page . . . . . . . . . Method mapping page . . . . . . . . Generate Mapping page . . . . . . . . Mapping a Java interface . . . . . . . . Welcome page . . . . . . . . . . . Interface Mapping page . . . . . . . . Method Mapping page . . . . . . . . Generate Mapping Definitions . . . . . . Mapping a Smalltalk class to a Java exception . Welcome page . . . . . . . . . . . Mapping Information page . . . . . . . Field Mapping page . . . . . . . . . Method Mapping page . . . . . . . . Generate Mapping Definitions . . . . . .

. . . . . . . . . . . . . . . . . . . .

107 108 108 108 108 109 110 110 111 112 112 113 113 114 115 115 115 116 116 118

Chapter 16. CORBA IIOP support . . . 119 IIOP transports . . . . . . . . . . Invoking methods using IIOP . . . . . IDL repositories . . . . . . . . Configurations and starting IIOP . . . Helper methods for creating application contexts . . . . . . . . . . . Contexts for method invocation . . . IIOP marshaling . . . . . . . . . Remote object model . . . . . . . . IORs . . . . . . . . . . . . Remote references . . . . . . . . CORBA object services . . . . . . . Naming Service . . . . . . . . Other information on CORBA IIOP support Repository cache operations . . . . Constants . . . . . . . . . . Exceptions . . . . . . . . . . Unions . . . . . . . . . . . Named value lookups . . . . . . Extensions to Kernel . . . . . . . Known limitations. . . . . . . .

. . . .

. . . .

. . . .

119 119 120 120

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

122 122 123 124 124 125 125 125 126 126 127 127 128 128 128 132

Chapter 17. Exceptions . . . . . . . 133 *.ini file processing

.

.

.

.

.

.

.

.

.

.

. 133

Index . . . . . . . . . . . . . . . 135

Notices References in this publication to IBM products, programs, or services do not imply that IBM intends to make these available in all countries in which IBM operates. Any reference to an IBM product, program, or service is not intended to state or imply that only that IBM product, program, or service may be used. Any functionally equivalent product, program, or service that does not infringe any of the intellectual property rights of IBM may be used instead of the IBM product, program, or service. The evaluation and verification of operation in conjunction with other products, except those expressly designated by IBM, are the responsibility of the user. IBM may have patents or pending patent applications covering subject matter in this document. The furnishing of this document does not give you any license to these patents. You can send license inquiries, in writing, to the IBM Director of Licensing, IBM Corporation, 500 Columbus Avenue, Thornwood, NY, USA 10594. IBM may change this publication, the product described herein, or both.

Trademarks The following terms are trademarks of the IBM Corporation in the United States or other countries or both: AIX C/MVS CICS/ESA IMS MQ MVS/ESA

AS/400 C++/MVS DB2 IMS/ESA MQSeries OS/2

C/370 CICS IBM OS/390 MVS VisualAge

The following terms are trademarks of other companies: Microsoft Windows UNIX

Microsoft Corporation Microsoft Corporation X/Open Company Limited

Windows is a trademark of Microsoft Corporation. UNIX is a registered trademark in the United States and other countries licensed exclusively through X/Open Company Limited.

© Copyright IBM Corp. 1997, 2000

v

vi

VisualAge Smalltalk: Server Smalltalk Guide

About this book This section provides information specific to this book.

What this book includes This book includes information about the VisualAge Smalltalk Server Workbench. The Server Workbench feature has the following components: v Server Workbench, Base v Server, CICS v Server, Database v Server, IMS v Server, MVS Native v Server, SST The Server Workbench, Base component is the core of the Server Workbench feature and provides cross-platform development support for servers. The other components provide runtime classes that support CICS, database, and so on. The Server feature provides redistributable files needed to run your packaged applications in server environments. This book also has information about other features that help you build applications that run in a server environment: v Server Workbench, CPIC for Interactive Debug v Server, OS/400 These products are collectively referred to throughout this book as “VisualAge Smalltalk Server” or “Smalltalk Server.” This book helps you use the VisualAge Smalltalk Server products. It gives both guidance and reference information needed to prepare Smalltalk applications for processing in a server environment. It covers how to create applications in the workstation development environment, package those applications for a target runtime platform, run the applications in a server environment, and perform many other tasks. Throughout this book, the term “workstation” applies generically to Windows NT, Windows 98, Windows 95, OS/2, Sun Solaris, and AIX development environments unless otherwise noted. Information applicable to specific development environments is noted accordingly.

Who this book is for This book is for programmers interested in developing applications for server environments such as Windows NT, OS/2, AIX, Sun Solaris, CICS for Windows NT, CICS for UNIX, CICS/ESA, IMS/ESA, and MVS/ESA (or OS/390), and including Lotus Domino Go. This book assumes that you are familiar with Smalltalk programming and the VisualAge Smalltalk development environments.

© Copyright IBM Corp. 1997, 2000

vii

About this product or feature Smalltalk Server enables you to write applications in a workstation environment that will ultimately run in a server environment. Smalltalk Server provides you with a full-scale client-server environment; you can write and run applications using one encapsulated object-oriented technology. The VisualAge Server Workbench feature contains a distributed object-oriented framework that you can use to develop client-server applications. The framework is called Server Smalltalk (SST) and is provided in Server, SST. SST supports distributed object-oriented messaging on TCP/IP, HTTP, SMTP, and IMAP4. Further, SST permits distributed Smalltalk messaging and Smalltalk interoperability with Java RMI and IIOP. SST attempts to integrate with external services seamlessly without affecting expected or standard behavior. Internally, SST is a framework of components, each representing major distributed system elements, such as middleware interfaces. These components are composed to build a distributed object architecture which is in turn used to build end-user applications. SST also attempts to integrate existing standard services, capabilities, and mechanisms rather than re-implement or invent new ones. Thus, many of the components used in SST may already be familiar to you. SST is supported on OS/2, Windows NT, AIX, Sun Solaris, and Windows 98/95 (client only). This book covers SST in two main topics: v Information for the occasional user of SST “Chapter 1. Getting started with SST” on page 1 “Chapter 2. Concepts helpful for understanding SST” on page 5 “Chapter 3. Building server applications” on page 15 “Chapter 4. Inspecting and debugging SST applications” on page 31 “Chapter 5. Distributed garbage collection” on page 37 v Information for the advanced user of SST “Chapter 6. Constructing new SST configurations” on page 45

Conventions used in this book This book uses several conventions that you might not have seen in other product manuals. Tips and environment-specific information are flagged with icons: Shortcut techniques and other tips VisualAge for OS/2 VisualAge for Windows

viii

VisualAge Smalltalk: Server Smalltalk Guide

VisualAge for UNIX platforms

These highlighting conventions are used in the text: Highlight style Boldface

Italics

Used for

Example

New terms the first time they are used

VisualAge uses construction from parts to develop software by assembling and connecting reusable components called parts.

Items you can select, such as push buttons and menu choices

Select Add Part from the Options pull-down. Type the part’s class and select OK.

Special emphasis

Do not save the image.

Titles of publications

Refer to the VisualAge Smalltalk User’s Guide.

Text that the product displays

The status area displays Category: Data Entry.

VisualAge programming objects, such Connect the window’s as attributes, actions, events, composite aboutToOpenWidget event to the parts, and script names initializeWhereClause script. Monospace font

VisualAge scripts and other examples doSomething of Smalltalk code | aNumber aString | aNumber := 5 * 10. aString := 'abc'. Text you can enter

For the customer name, type John Doe

Tell us what you think The VisualAge Smalltalk web page has a comment form. Please take a few moments to tell us what you think about this book. The only way for us to know if you are satisfied with our books or if we can improve their quality is through feedback from customers like you.

About this book

ix

x

VisualAge Smalltalk: Server Smalltalk Guide

What’s New This section provides information on updates and changes to Server Smalltalk as well as changes and updates to this book.

What’s new in SST Server Smalltalk has been enhanced significantly in this release. Changes include the following: v RMI Wizard has been enhanced to include the new RMI Interface settings, RMI Class Wizard, RMI Interface Wizard, and RMI Exception Wizard. v JAVA RMI has been updated to enable the use of JDK 1.2. v INI file support for OS/390 platforms, including CICS and IMS.

What’s new in this book This book has been separated out from the VisualAge Smalltalk Server Guide and updated with clarifications and to reflect product changes. v v v v

Clarified the introduction and explanations of the Ping Pong examples. Added information on using a configuration (INI) file on OS/390. Added information deploying a server application. The information has been restructured to make retrieval easier.

© Copyright IBM Corp. 1997, 2000

xi

xii

VisualAge Smalltalk: Server Smalltalk Guide

Chapter 1. Getting started with SST Most object-oriented languages use message passing as the basis for object interaction. Message passing is also used for distributed computing. SST combines these to enable remote messages to be sent between Smalltalk images or other components of a distributed system. In that sense, SST is similar to systems such as CORBA and Java RMI. SST differs in that it addresses distributed architectures which vary more widely as to the following: v Communications mechanisms (for example, HTTP, TCP, SMTP, IMAP4) v Message content (for example, custom bytes, Smalltalk objects, remote references, IIOP, Serialized objects) v Message processing strategies (for example, serialized, thread pools, thread-per-request, distributed logical processes) v Concurrency control SST enables all of these capabilities within a common coding infrastructure or framework. The key components of the framework include— v Invocation handlers v Dispatchers v Marshalers v Transports The figure below shows the roles of these components in message passing. In the figure, a message is being sent from the upper system to an object in the lower system. On detecting an attempt to send a message to a remote system, SST asks an invocation handler to invoke the desired method on the desired machine. The handler asks its associated dispatcher for the best way to send the message. Having determined this the handler passes the message to its marshaler which converts the objects into a series of bytes. During marshaling the object space is used to manage such things as object identity. The marshaled bytes are then passed by the handler to be sent by its transport to the system hosting the ultimate receiver of the Smalltalk message. A similar algorithm is followed on the receiving side. When the receiving system detects the arrival of an incoming message it passes the received bytes to an invocation handler for processing. The handler asks its marshaler to convert the bytes to objects (that is, a Smalltalk message object) in conjunction with its object space. The dispatcher is used to find the best process for handling the message. Having made all the correct preparations, the received message is sent to the intended receiver within the handler’s running image and a result is obtained. The interactions for sending a reply are similar, but with the direction of the arrows

© Copyright IBM Corp. 1997, 2000

1

reversed.

The invocation handler is the core of the framework. It ties the SST mechanism together, and coordinates the activities of the marshaler, transport and dispatcher components. You implement varying behaviors by plugging different components into the framework. For example, using a marshaler which dumps whole object graphs (for example, the Swapper) effects a pass-by-value system. In contrast, a different marshaler might trim the object graph replacing subgraphs with remote references. Using such a marshaler results in a pass-by-reference messaging system. SST supports a number of different communications mechanisms or transports for transmitting and receiving messages. These are typically orthogonal to the other components and so can be mixed and matched freely. For example by-reference messaging over TCP is one such communications mechanisms. This high degree of flexibility makes SST useful, but more challenging to use. To address this, SST provides explicit configuration objects which manage combinations of components and parameter settings (configuration options). Major SST components such as spaces and invocation handlers have corresponding specialized configuration objects. SST provides examples and defaults for these configurations so the burden on you is limited. In fact, most users will never have to deal directly with the configuration settings but rather will simply use pre-built configurations.

2

VisualAge Smalltalk: Server Smalltalk Guide

Supported infrastructure SST supplies the following components and supports their use in conjunction with the framework. Note, however, that not all combinations of components are allowable.

Transports and protocols v v v v v

TCP HTTP 1.0 SMTP IMAP4 MQSeries

Dispatchers v v v v

Fully serialized New thread per request Pooled thread per request Logical process model

Marshalers v v v v

Swapper (by-value and by-reference) Custom lightweight (by-value and by-reference) Java RMI compatible (object serialization) CORBA IIOP

Spaces, contexts, URLs All objects in a distributed system need some notion of location. In SST, object spaces fill this role. All objects live within an object space. At their simplest an object space corresponds to a running Smalltalk image. The space itself has a name and all objects within it have an identifier that is unique within the space. These together form a unique object identifier. Object spaces use these identifiers to manage object identity between multiple running images. Quite often distributed systems consist of a number of mostly distinct subsystems working together. In Smalltalk, it is often convenient to have these subsystems share the same running image. With one object space per image, the objects from one subsystem are managed together with those from another. This can cause problems if they share the infrastructure which makes distributed computing possible. Imagine, for example, one subsystem deciding that it has to restart its transport just as another was trying to send a message! The solution is to have application-specific sets of infrastructure (object spaces, invocation handlers, and so on). In SST, application contexts provide a separate operating environment for distinct applications in the same image. Each context manages a single local object space and a list of perhaps many representations of remote spaces. It also manages all of the local communications mechanisms available to the application. Therefore, applications use contexts to manage and keep separate the SST resources they use. While not strictly controlled, communication between application contexts is not permitted. Object spaces are known to each other by their accessible URLs. That is, the URLs identify the location of invocation handlers to which messages can be transmitted for processing. A URL is a combination of an invocation scheme configuration name, a transport name, and a transport-specific address. Chapter 1. Getting started with SST

3

The invocation scheme configuration name identifies an agreed upon high-level protocol which will be used to send and handle requests. The name identifies, for example, the type of marshaler used, the way requests are dispatched, and the like. The name is commonly application-specific. The transport used is identified by a unique name (for example, tcp) which matches a known transport configuration. This configuration specifies both the mechanism and the wire-format of exchanged messages. The form of a URL’s address portion depends entirely on the requirements of the transport specified. The general form of a URL is: scheme:/transport/address. The ping-pong examples mentioned in this guide use schemes such as pingPongRef and tcp transports with standard host:port IP addresses. So a full URL looks like: pingPongRef:/tcp/foo.com:4567

Further sections provide more detail on these concepts but this is sufficient to allow you to set up SST and run the examples.

4

VisualAge Smalltalk: Server Smalltalk Guide

Chapter 2. Concepts helpful for understanding SST SST can be used at two major levels of abstraction, remote procedure call and remote object invocation. Using the procedure call approach, you send remote messages and interact directly with the messaging infrastructure. Some of the machines in the system may not be running Smalltalk or the data exchanged may not be objects. This model is typically found in strictly client-server systems. The object invocation approach presents you with an implicit model of remote objects to which you send messages. Using proxies and remote references, remote objects are largely indistinguishable from local objects. Polymorphism can be fully exploited and the same application code is used to manipulate local and remote objects. SST extends this to the point where Smalltalk process semantics can be extended across multiple machines. The SST framework is layered such that the object invocation model uses the infrastructure which implements the procedure call model. To integrate the two and fully utilize Smalltalk itself, SST uses the following approach: wherever non-object entities (local or remote) are encountered, they are converted to objects as soon as possible. Once they look like objects, their origins are transparent. For example, when the SST HTTP server receives a request, its transport reads the bytes from the client (an HTTP request) and immediately converts them into a Smalltalk message like— processRequest:

This approach isolates the rest of the system from the fact that the request came through a byte-wise HTTP transport. The server’s implementor deals only with objects and thinks in terms of normal Smalltalk programming. The same server object can be used in both the procedure call and object invocation models (or local computing). In the following sections, you explore a number of concepts SST supplies in support of this approach. The emphasis here is on using these concepts rather than the details of how they work. Depending on the kind of distributed application you are developing, some of these concepts may be exactly what you require. If some of the concepts do not appear relevant to your application, skip to the next one.

Connection-oriented design Many applications are inherently connection-oriented. It is important however to distinguish those which are connection-oriented at the application level from those which require connection-oriented communications. In essence, very few applications actually require that the communicating entities be physically connected by some transport media at all times. Rather, at the application level they have the notion of a session or connection which gives context to data transmitted through various transports. An example of this is a Web shopping system using cookies. When a user first contacts the server it is given a cookie or unique key. Even though HTTP is a

© Copyright IBM Corp. 1997, 2000

5

connection-less protocol, the web server can maintain a list of the items in your shopping basket using the cookie which is automatically supplied by the web browser with every request to that server. SST is not inherently connection-oriented. It supports both connected and non-connected transports and does not demand that there be a higher-level notion of session. SST does however expose the behavior of the underlying mechanisms it uses. So, for example, if your application uses a connection-oriented transport such as TCP, SST exposes the TCP notion of connection to you. This notion is supplied in the form of an endpoint. The endpoint is used internally to maintain a table of connections so you can use it to uniquely identify application-level sessions which are closely coupled to transport-level connections. SST also provides a set of callbacks which give you hooks to various communications-level connect and disconnect events. To assist you in building and maintaining application-level sessions, SST provides a user-programmable session manager and session object. You define the contents of the session and semantics of session opening and closing. The HTTP server example uses the session manager to generate and manage its cookies. Separating the issues of whether a transport is connected from whether the application design is logically connected is an important part of building applications which are transport-independent. This separation gives designers more freedom to set the communications and interaction characteristics of their applications.

Remote references and proxies Integral to the representation of ″everything as an object″ is the concept of proxies. A proxy is an object which stands in for something else. It may take the form of a remote reference to a remote object, a CORBA- style stub, or the conceptualization of CICS server data and CICS transaction programs as an object. It may represent a remote object, an object in a different language, or even a persistent object. Regardless, from the proxy holder’s viewpoint, the proxy is the object and can be stored in variables, passed as arguments and sent the messages specified in its related interface. Remote references are proxies which identify particular objects in particular object spaces (location) and explain (indirectly) how to get a message to that object. While you can treat them as you would normal objects, the increased message latency will make users aware of which references are local and which are remote. When tuning a distributed application you can test whether an object reference is local or remote using the sstIsRemote protocol. Remote references (and other instances of subclasses of nil) should never be put directly in the Smalltalk dictionary or in class or pool variables. While this may appear to work while your distributed system is up and running, various parts of the normal Smalltalk infrastructure scans these objects and sends them messages such as isClass which are not appropriate for general implementation on remote references. For the most part, the differences among reference types supported in SST are hidden from you. However, with respect to object identity, differences are exposed. Smalltalk is a referential language. Other than a few objects (for example, SmallIntegers, Booleans) all objects are accessed by reference and even some

6

VisualAge Smalltalk: Server Smalltalk Guide

referenced objects are truly values in that they cannot be modified (for example, Floats). SST attempts to maintain these semantics as much as possible but in some cases it is impossible. There are two kinds of references you are likely to encounter: transient references and symbolic references.

Transient references Transient remote references are managed by object spaces and have strong identity semantics. A transient remote reference is automatically generated by the system when a local object is passed out of its containing space (for example, as an argument or return value). As the name implies, transient references are only valid for the duration of that run of the exporting object space. During that time, however, object identity is strictly maintained and object spaces importing a transient remote reference ensure that all local uses of that reference use the exact same remote reference object. That is, passing the same local object to a remote space twice creates only one remote reference object in the remote space.

Symbolic references Symbolic references allow object spaces to implement primitive naming services. You can export objects in a local space using a symbolic name and then reference the object remotely using just the object name and the space containing the object. With symbolic references, the identity of an indicated object is not known until the reference is resolved by the space holding the object. As a result, two consecutive messages sent to the same remote reference may actually go to two different objects, if the name/object binding was changed between the messages. Thus, the expression: (#ObjectName sstIn: aSpace) yourself == (#ObjectName sstIn: aSpace) yourself

may answer false because the remote references created by sstIn: are symbolic and do not preserve identity. That is, the object registered under the key #ObjectName in aSpace could change between sends of yourself, resulting in different objects being returned. (In some systems, the yourself message is never sent. This example assumes yourself is always sent.) Globals within an image can be addressed using code like— (#Compiler sstGlobalIn: aSpace)

This code returns a remote reference to the Compiler (Smalltalk at: #Compiler) in aSpace. Also, global remote references are symbolic and do not preserve identity. Further, the reference building constructs such as sstGlobalIn: and sstIn: do not cause remote messages to be sent. It is only when these references are message receivers do remote messages get sent. Symbolic global references are available when using native SST messaging only. Global references of this kind present a security risk as clients are able to find and manipulate objects in your server. You can disable the ability to resolve global references and disallow incoming global references by setting the allowGlobalReferences option in the space configuration you are using to false. The ping-pong examples contain both types of reference. When references are exported from object spaces, it means that they become accessible to other machines. The ping-pong objects returned from createPingAndPong are implicitly exported as transient references in all the by-reference hierarchy examples but are explicitly exported as symbolic references in the by-value example. Chapter 2. Concepts helpful for understanding SST

7

Object spaces As discussed above, object spaces form the basis of distributed objects by supplying the location. There are two main types of object space in SST: export sets and full object spaces. Export sets, defined in SstSimpleObjectSpace, maintain lists of objects exported by a space. Export sets cannot manage remote references effectively. Object spaces, defined in SstLocalSpace, maintain both an import and export set and can fully manage object identity and remote references. Importing an object makes a proxy to some remote object available locally. The kind of space you require depends on your application. In general, if you are programming directly with invocation handlers such as an HTTP server, you will find export sets to be sufficient. Direct use of invocation handlers is ideal for pass-by-value applications. Systems requiring transient remote objects and object identity (pass-by-reference) should use full object spaces. The kind of space used is specified in the invocation handler configuration associated with your application’s scheme. Again, the ping-pong examples contain samples of both approaches. Feel free to play with passing different values to see how the behavior varies. For example, try using a simple object such as aBoolean or Integer for the with: part of the start:with: operation, and then try using an Array or some other complex object.

Application contexts Application contexts are a means of organizing and managing the SST infrastructure components on a per user-application basis. They have an inherent notion of the local object space and its local handlers as well as lists of the known remote spaces and handlers. Contexts are dynamically extensible allowing existing components (other than their local space) to be added and removed after the context has been started. A context’s components (such as handlers and local space) and their elements (such as the space’s export set) are not accessible by other contexts. As such, contexts isolate user-applications from each other and limit interference. If you are using the object invocation model, contexts can provide a single point of control for all infrastructure related to an application. They allow all of their local components to be started and stopped as a whole.

Message passing As mentioned above there are two major forms of message passing, by-reference and by-value. The kind of message passing used is determined by the kind of marshaler used to convert requests into bytes (and vice versa). Straightforward client-server applications frequently do not require pass by-reference semantics as objects are relatively simple and do not have relevant identity. In such cases, pass by-value is sufficient. Examples of this are typical data-oriented servers such as databases and HTTP servers. Note that pass-by-value may result in large amounts of data being passed around as entire object graphs rooted in the request arguments are marshaled and sent. Passing by-reference is generally more efficient in terms of bytes transmitted but may require more remote message sends due to the cross-space references. On the

8

VisualAge Smalltalk: Server Smalltalk Guide

other hand, passing values means that during computation all arguments are local so the number of remote messages may be significantly reduced. References have some other, more subtle advantages. The most important is that they maintain object identity. At a purely pragmatic level, they also promote polymorphism as they enable implicit remote messaging. Regardless of whether a variable (foo) contains a local object or a remote reference, the code foo doSomething will execute. Without remote references you must explicitly code for remote objects. An illustration of this can be seen by comparing the sendPing:with: methods in the ping-pong example. There are of course disadvantages to this simplicity. Using implicit remote references it is very easy to explode the inter-space dependencies and create distributed garbage. Even though SST contains a distributed garbage collector, collecting garbage is not as good as not producing it. Execution semantics can be corrupted using remote references. For example, invoking value: on a remote reference to a block that performs an out-of-scope return will not have the intended effect. Overall, which message passing mechanism is best depends on the demands of your application and its computing characteristics.

Logical processes The Smalltalk execution model is dominated by synchronous message sending. An object sending a message waits for the result to be returned before processing the next expression. Normally this execution takes place in one Smalltalk process. With the introduction of remote references however, a message send can result in a remote message to a completely different Smalltalk image. As a result, the Smalltalk process running the request will necessarily be different from that of the sender. Assuming that the sender blocks waiting for the reply, this does not break the superficial execution semantics. However, difficulties do arise in situations involving user interface-driven code, exceptions, debugging, out-of-scope returns and transactions. In these cases, extra data is implicitly or explicitly attached to the process running the code. For example, an exception handler installed in the sending process would not be available for the remote process. SST addresses this using logical processes. Logical processes maintain typical process attributes (such as error handlers) across many actual (distributed) processes. When a process sends a remote message its relevant state, but not the stack itself, is captured and forwarded to the receiving process. This state is used to make the receiving process seem like the originating process. In addition, the Smalltalk execution model ensures that each logical process be implemented by at most one physical process per object space. That is, if some object O running in process P sends a message M to a remote object R and in the processing of M a message N is sent back to the space containing O, N will be executed by process P. Consider the ping-pong application—two objects, Ping and Pong, on different machines continually send messages back and forth. If you run the SstPingPongByReference example you will notice that the process information printed in the Transcript for each request is different. That is, each request is being handled by a different physical Smalltalk process even though they are part of the Chapter 2. Concepts helpful for understanding SST

9

same logical call chain (that is, Ping pings Pong, Pong pongs Ping, and so on). If you run the SstPingPongLP example, notice that the same process is being used to handle successive requests in the ping-pong chain. In the figure below, the black line running through the boxes represents a physical Smalltalk process on the different machines. The gray line represents the logical process, which combines the two physical processes to form a single logical process. Note that pong:with: is being executed in the same physical process as start:with:.

The examples in subclassses of SstPingPongLP demonstrate how logical processes maintain the normal Smalltalk process semantics with respect to termination, out-of-scope returns and error handling. For example, if ping:with: in the above figure had an ifCurtailed: statement and pong:with: terminated its local process, the ifCurtailed: block would run, according to Smalltalk execution semantics. But the block is defined in a different physical process on a different machine (see SstPingPongLPTerminate). The situation is similar for out-of-scope returns (see SstPingPongLPUnwind). Logical processes arrange for these semantics to be preserved. Logical processes also make it possible to build a distributed debugger which follows call chains as they hop from space to space. All operations such as step-into, step-over, and drop-to-frame are supported. The logical process model is independent of the interconnection mechanisms used to communicate but only works fully if all object spaces involved in an interaction are SST spaces with logical processing enabled. If some computation crosses into a space which does not support logical processes, the system does not fail. Rather system capabilities degrade gracefully to the level which is supported by that space. With the distributed debugger, for example, you will not be able to debug a computation once it crosses into a non-logical process space.

Multithreading and multiprocessing SST supports multithreading through user threads (Smalltalk processes) and asynchronous C callout (ACO) facilities using OS threads. Calls to blocking OS resources (for example, TCP Sockets) do not block the entire VM and all other running Smalltalk processes. Only the Smalltalk process initiating the OS call is blocked.

10

VisualAge Smalltalk: Server Smalltalk Guide

However, since the all Smalltalk code is run in one OS thread (and process), SST cannot take advantage of parallel processing resources such as SMP machines. As a result, a single VM running multiple server programs in the same Smalltalk image cannot be load balanced by the OS. Internally, however, SST is fully multithreaded. For instance, supplied dispatchers such as threaded or pooled dispatchers use several user threads (Smalltalk processes) to execute requests. All components are thread safe. SST supports multiprocessing to the same degree as normal Smalltalk. In the simplest case two servers simply run as two Smalltalk VMs running different images. Since objects cannot communicate or be shared between the images, it is as though they were on different machines. The normal SST communications infrastructure can be used. Running on the same machine, SST uses shared memory and ICs to reduce both the footprint and startup time of each server process. Multiprocessing configurations can take advantage of OS-level processing resources and load-balancing. The model you should choose for particular applications depends on their requirements. Multiprocessing is simpler to program and manage as the unit of concurrency is an OS process, which forms a high barrier of protection. A drawback of this is that communication and sharing between concurrent entities is more costly. Multithreading allows entities to pass data by simply passing a pointer and control access using quick and easy locking (for exmple, semaphores). Unfortunately, Smalltalk does not provide very many thread-safe classes in its library so you must be careful to avoid race conditions and other concurrency problems.

Actors SST provides several programming constructs which help you build concurrent systems. One of these is Actors. Actors are active objects—they encapsulate notions of concurrency within an object. Method invocation on normal Smalltalk objects is carried out according to passive uniprocessing, sequential semantics. The process sending a message also executes the related method’s code. In contrast, Actors use their own processing resources to satisfy requests. Each Actor thread has its own activity. The threads within an Actor need not have the same activity. A typical activity is to loop forever getting a request, processing it and returning a result. It is also valid for an Actor to simply start up, do some work and then die. Actors are often useful for managing resource sharing or for coordinating and performing concurrent tasks. Sharing is controlled since all objects internal to the Actor are accessible only though the Actor’s API. An Actor’s internal objects are only manipulated by its own threads. For example, wrapping a single-threaded Actor around a non-threadsafe object effectively make it thread-safe by serializing all operations. Actors can admit as much or as little concurrency as their internal structure can handle. Internally they can be strictly single-threaded or multiply threaded. An Actor’s threading policy (single-, multi-, pooled, and so on) is independently configurable. Chapter 2. Concepts helpful for understanding SST

11

To control some of that concurrency, SST supports explicit suspend and resume style operations. These operations affect all elements of the receiving Actor. Concurrency can be further managed by nesting Actors. Nested Actors, and thus all of their threads, can be started and shut down as atomic units.

Programming with Actors User Actors are built by subclassing the class SstActor and by implementing any required domain behavior. You use the concurrency control constructs (for example, join, suspend) set out in the API as needed. There are several ways of introducing concurrency into an Actor. Every Actor has at least one thread. In practice not every request needs to be executed in one of the Actor’s threads. Some are perfectly safe to be concurrently run by any number of external threads. The SST environment provides mechanisms for marking individual methods as Actor methods. Invocations of these methods will be executed only by one of the Actor’s own threads. The straightforward way to make a method into an Actor method is to add the following code at the beginning of the method: self

Processor sstCurrentActor ifTrue: [|self sstActorSend].

sstActorSend builds a message and queues it for the receiver (self) and then waits for a result. Therefore, any Actor methods prefixed by this code will run in one of the receiver’s processes. SST manages the concept of a current Actor (see the sstCurrentActor instance method of ProcessorScheduler). All Smalltalk processes have a defined defaultActor if they are not explicitly part of some other Actor.

Transactions SST supports different transaction systems, such as CICS and Encina. You can use the following when developing transactional systems with SST: v Transactions v Transactional code v Transactors

Transactions Transactions are objects which model the transactional concept from an underlying transaction service such as CICS or VAP. SST does not implement the middleware but rather enables its use from Smalltalk. As such, SST transactions wrapper the underlying mechanisms. They support the basic begin/commit/abort protocols but make no attempt to mask or modify the transactions server’s semantics. Where enhanced capabilities such as nested transactions are available, SST exposes them through platform-specific transaction classes. While transactions are uniquely associated with individual threads of control (for example, Smalltalk processes), they do not execute code themselves. They are maintainers of context, much the same as the CORBA OTS current object or the MS Transaction Server context object. As in these systems, SST maintains the notion of a current transaction and associates that with the currently executing thread/process (see the sstCurrentTransaction instance method of ProcessorScheduler).

Transactional code While transactions are explicitly available, you typically manipulate them implicitly through transactional code. Transactional code is code executed in the context of some transaction. Regions of code at different levels of granularity can be transactional:

12

VisualAge Smalltalk: Server Smalltalk Guide

Block The code within the scope of the block is transactional. Method The entire body of the method is transactional. Object All public methods for the marked object are transactional. Class All public methods of the indicated class are transactional for all instances of the class and its subclasses. Note that SST’s definition of the term transactional object differs from that of CORBA’s OTS. In CORBA a transactional object is simply one which inherits from TransactionalObject and so ensures that any existing transaction context is passed along when the object is invoked. SST’s transactional objects are objects whose methods are transactional and so manage the executing transaction context according to the code’s transaction mode. Whenever execution enters a section of transactional code, SST ensures that the current state of the transaction system conforms to the transaction mode specified for the code segment. For example, if a block of code is marked as soft transactional then on entering the code, SST automatically creates a new transaction if there is no current transaction. If there is a current transaction then it is used as the context for the transactional code. SST exposes the following transaction modes: Check Fail if there is no current transaction. Ensure If a current transaction is available then it is used as the context for the transactional code. Otherwise, create a new top-level transaction. TopLevel Create a new top-level transaction. Default Use the default mode specified by the current execution environment. First check any existing Transactor (see below), then consult the relevant transactions and transaction services.

Transactors Transactors are related to both transactions and Actors. You use them to model high-level application transactions as opposed to low-level data transactions. Typically an application transaction consists of a number of related operations (such as data transactions) glued together by domain logic. For example, allocating an order number, filling in an order and then submitting the order go together to model the “customer purchase” business transaction. In many cases, the operations in an application transaction can be carried out concurrently. In other cases, the operations must obey transactional rules. Transactors provide the mechanisms and infrastructure for managing collections of transactions and their explicit or inherent concurrency. Furthermore, since some application logic consists of combinations of high-level transactions, Transactors can be nested to form higher-level Transactors. This capability is derived from Actors. In general then, Transactors facilitate the description and control of high-level application transactions by supporting the coordination and management of a series of operations which may be concurrent or transactional.

Chapter 2. Concepts helpful for understanding SST

13

Transactors are both a kind of Actor and a manager of actual transactions as supplied by some transactional mechanism. That is, internally, they maintain their own processing resources (Smalltalk processes) which execute within real transactions. In this way the Transactor has complete control over concurrent accesses to local state while the transaction service manages shared external state. All Transactor methods are automatically transactional code. So not only is the code guaranteed to be executed by one of the Transactor’s processes but it will also be evaluated within a real transaction according to the code’s transaction mode. Transactors may themselves be transactional objects (for example, have transactional methods) or may simply execute some transactional code in some internal object or method. Transactors own all transactions executing on their active threads. Since transactions can only be associated with one thread at a time, they can only be associated with one Transactor. Just as with Actors, Transactors created during execution of some other Transactor must specify whether they are new top-level Transactors or are nested within the current Transactor. A transaction within one Transactor cannot migrate to another Transactor due to the restriction that transactions be associated with only one thread. The failure of individual operations within a business/application transaction (Transactor) does not imply the failure of the entire business transaction. Note that at any time the application logic may dictate that the business transaction should fail and that all current operations stop. There is however, no general requirement that completed operations (transactions) should be undone. If this is the case then you must encode this logic in the application code.

14

VisualAge Smalltalk: Server Smalltalk Guide

Chapter 3. Building server applications This section provides more information on developing distributed applications. Several examples show how to use the different programming model concepts discussed in the previous chapters.

Categorization and Interfaces SST uses method categories and interface specifications to document API. All methods categorized SST-API User or SST-API Developer are public API available to you. User APIs are intended for use by typically high-level users of SST while the Developer APIs are intended for programmers building or integrating new SST components. Methods categorized as SST-Internal, whether marked as public or private are not intended for general programmer use. Most of the major SST elements have interface specifications. SST interfaces are similar to those in Java and are used to represent an implementation independent specification of protocols. Methods implementing an interface are categorized in a category named using the following convention: @ I?Sst where the ? is either a u or d denoting user or developer API, respectively, and the is the common use name of the interface. For example, methods implementing parts of the Startable user-level interface are categorized as @ IuSstStartable. Implementation classes may implement methods from many categories (that is, they may have many @ categories). Interfaces themselves are implemented by a class bearing the same name as the category, but without the @. So the user-level Startable interface is defined in the class IuSstStartable. In some cases there are both IuSstFoo and IdSstFoo interface classes. That is, both user and developer sides of the Foo interface exist. The full developer interface is always a superset of the related user-level interface. Inheritance within an interface is represented by categories in the interface class whose names follow the same convention as above but begin with @@ rather than @. Note that @@ categories only appear in interface classes. Multiple inheritance within interfaces is achieved by adding several @@ categories. The interface classes are contained in separate applications and can be loaded independently of the code itself. The interface specifications for each component and its API are published within the Smalltalk environment and available when browsing the interface applications. Where SST implements API derived from an existing standard such as Java or CORBA, the API category uses the appropriate name from the standard. These names are preceded by a character unique to the standard. For example, the Java RMI remote object interface is specified in the class java.rmi.Remote. The SST methods implementing that interface are categorized as ! java.rmi.Remote where ! denotes Java. Similarly, CORBA API category names are preceded with a :. For more detail on methods in these categories, see the relevant standard documentation.

© Copyright IBM Corp. 1997, 2000

15

Configurations SST itself specifies little in terms of policy for distributed application behavior. Rather than hard-coding such concepts, SST uses collections of pre-defined or dynamically created configurations for the various components. As a user, creating new configurations will not be required. Instead you will use one that has already been created for you by a developer to match particular aspects of the design for your distributed application. Different configurations will provide you with different system behavior. Configurations are declarative descriptions of behavior. They can be likened to control blocks which give detailed descriptions of how an object is built and executed. They provide an easy way to manage frequently used setups. Configurations are especially useful in frameworks where component implementations (and thus parameters and settings) vary widely. The framework need only supply configure API where the implementation specific configuration objects are passed to the component being configured. The framework need know nothing of the actual number or content of the settings—it simply passes them along. Typical users need not know much about the configuration of standard SST infrastructure components. Infrastructure configurations (invocation handler, marshaler and space configurations) are mechanisms for harnessing flexibility rather than something which is frequently programmed. Once your application’s infrastructure requirements are encoded in configurations, they can largely be ignored. Several infrastructure components (invocation handlers and transports) manage repositories of pre-defined configurations which are automatically used by the system. For example, the scheme and transport elements of a URL are mapped onto sets of invocation and transport configurations. In this way, the specification of a complete set of SST infrastructure and its configuration is given by a URL such as: myScheme:/tcp/foo.com. Configurations for non-infrastructure elements of SST (such as Actors) are different. Typically, they are used more frequently and directly. In some cases, the use of configurations is the primary way of creating the objects they configure. To this end, all configurations support instantiation protocol of the form: instantiate, instantiateFor:, and so on. For example, the new class method of Actor is implemented as: |self defaultConfiguration instantiate which creates a single-threaded Actor according to the specifications of the default configuration. Different configurations are used to create Actors with different behaviors.

Callbacks Configurations which are used to control the runtime—as opposed to creation-time—behavior of objects often maintain a set of callbacks for which you can register. They are useful for getting access to internal system events such as the exporting of an object or the sending of a request. SST supports a wide range of callbacks all of which are listed in the SstConstants pool dictionary. The methods which fire the callbacks detail when they are fired and the call data supplied with each firing. You can register for callbacks using the standard addCallback* protocol which is part of standard Smalltalk.

16

VisualAge Smalltalk: Server Smalltalk Guide

Startup and shutdown Many objects within the system require a coordinated startup and shutdown procedure. To facilitate this, SST adopts a standard set of methods and defines when they are executed and what they should do. The startUp methods (in the IuSstStartable interface) are: startUp Starts the receiver. In general this means starting related processes, allocating resources and building interobject links. Once startUp has completed the receiver is ready to fulfill its prescribed role. shutDown Stops the receiver. In general this means stopping related processes, releasing allocated resources and removing some interobject links. An object which has been shutDown can typically be restarted using startUp though it may not restart with exactly the same behavior as before it was shutDown. clear

Ensures that the receiver is shutDown and then clear out its instance variables such that no dangling pointers to complex objects remain. startUp cannot be sent to the receiver once it has been cleared.

The startUp and shutDown methods are not related to the normal VisualAge Smalltalk application startup and shutdown protocol. That is, they are not called automatically on image startup and shutdown.

Putting your application together To see how the pieces of SST are put together to implement an application, re-examine the ping-pong example. Ping-pong contains examples of both the procedure call and object invocation models presented previously. The sections below cover setting up and running a remote procedure call style application (SstPingPongByValue) and then a remote object invocation application (SstPingPongByReference).

RPC-style applications RPC-style applications directly interact with the messaging infrastructure. In SST the main component of interest is the invocation handler (see SstInvocationHandler). Applications can create and manage invocation handlers exclusively for their own use or share them. Loosely-coupled applications probably should not share handlers to enable their independent creation and destruction. Invocation handlers are configured objects. Their configurations specify the kind of object space used, the way requests are sent and processed (the dispatcher used), the marshaler to use, and other lesser details. The default configuration has reasonable settings for most of these options but you must set up the marshaler and object space as a minimum. The invocation configuration for the SstPingPongByValue example is defined in the class method registerInvocationConfiguration shown below. This method runs when the application loads and it installs a configuration in the global scheme registry. In this case, whenever a URL with the scheme pingPongValue is used, it maps onto this configuration. Note that this code is largely the same for all examples.

Chapter 3. Building server applications

17

registerInvocationConfiguration SstInvocationHandler register: ( SstInvocationConfiguration byValueConfiguration marshaler: SstSwapperMarshaler byValueConfiguration) asScheme: self invocationScheme

As shown in “An illustration: Ping-Pong examples” on page 20, the setup* methods start the SST infrastructure running. Below is the setup code for SstPingPongByValue’s Pong machine. setupPong: pong ponging: ping LocalHandler := SstInvocationHandler on: (SstLocalEndpoint fromUrl: (self urlFor: pong)). LocalHandler startUp. RemoteHandler := SstRemoteInvocationHandler to: (SstRemoteEndpoint fromUrl: (self urlFor: ping)) using: LocalHandler. RemoteHandler startUp. LocalHandler space export: self as: self name

Given a URL string (from urlFor: and the user-supplied @pong) a local invocation handler is built. The act of building a handler automatically finds and uses the invocation and transport configurations registered with the system. The handler is then started. Starting the handler opens listening sockets (in the case of TCP), sets up internal data structures, and starts the server process which fetches and dispatches requests. Next a remote handler is created. This is a local representation of an invocation handler on a remote machine. It is used as a convenience mechanism to link the local handler with a particular destination, specified in this case by @ping. Once the local system is up and running, the setup code explicitly exports the class SstPingPongByValue under its own name. Exporting the class makes it available as the receiver of messages from other machines. After running similar code on Ping, you can bootstrap the application by establishing cross-machine links. The code below first creates an example object and then exports it as pingPong. It then does an RPC-style message send to Pong asking it to create an example object and link it to the local one. The local object is identified by its export key (pingPong). Pong returns the export key of the example object it created and explicitly exported. createPingAndPong | ping pong | ping := self new. LocalHandler space export: ping as: #pingPong. pong := RemoteHandler invoke: ( DirectedMessage receiver: self name selector: #createFor: arguments: #(pingPong)). ping remote: pong. |ping

With the application bootstrapped, you can run it by executing: start: 3 with: #(1 2)

where is the result of createPingAndPong. This code eventually runs the method shown below which does another explicit invoke using the export key of the remote object determined during bootstrapping as the message receiver. sendPing: count with: value |RemoteHandler invoke: ( DirectedMessage

18

VisualAge Smalltalk: Server Smalltalk Guide

receiver: remote selector: #ping:with: arguments: (Array with: count with: value))

When the application finishes running, the SST resources should be freed. This is done by sending either shutDown or clear to the invocation handlers in use. Clearing resources must be done on each machine in the system.

Object invocation applications Setting up an application using object invocation also must create and install the relevant configurations, and create an application context. As discussed above, application contexts manage all the resources related to a particular user application. They also provide a separation between object spaces. Consider the SstPingPongByReference example. To bootstrap the application, code similar to Pong’s code shown below must be run in each participating image. Setup code can be done as an explicit application boot step or automatically during image startup. setupPong: pong self context addSpace: addSpace: setupFor: startUp

ponging: ping #ping at: (Array with: (self urlFor: ping)); #pong at: (Array with: (self urlFor: pong)); #pong using: SstSpaceConfiguration proxyConfiguration;

This method lazily creates an application context and then adds two object spaces (#ping and #pong). When adding a space, you must supply a logical name for the image running the space and a set of URLs (or URL strings) describing how that space can be accessed. Each of these URLs represents an invocation handler as in the previous example. After adding the spaces, the application context is initialized using setupFor:using: and specifying which space is the local space as well as the kind of object space (its configuration) to use locally. Note that more spaces can be added dynamically but as a minimum the local space must be specified before doing setupFor:using:. Finally, the context is started, which performs any final setup and starts all local invocation handlers. There are some differences from the SstPingPongByValue worth noting. First, there is no need to explicitly export the example class. All Smalltalk globals are implictly exported. The bootstrap method below shows how to create a reference to a remote global (in this case, the example class) using the sstGlobalIn:context: API. Then an implicitly remote message is sent to the remote example class to create and cross-link the example objects. Note that the argument ping is automatically exported when it is passed to a remote space. createPingAndPong | remotePongClass ping pong | ping := self new. remotePongClass := (self name sstGlobalIn: #pong context: self context). pong := remotePongClass createFor: ping. ping remote: pong. |ping

Since implicit remote messaging can be used, ping and pong messages can be sent directly to the remote example objects. For example: sendPing: count with: value |remote ping: count with: value Chapter 3. Building server applications

19

An illustration: Ping-Pong examples The distributed programming equivalent of ’Hello World’ is to have two machines or two images on the same machine send a simple message between each other. This is known as Ping-Pong because it follows the same pattern as the game. To accomplish this, you create an object in one image that understands ping. Its couterpart is an object in the second image that understands pong. The Server Smalltalk examples make it a bit more interesting by passing a value along with each message and then returning a result. With each message sent, the value is decremented by one. Ping-ponging stops when the value reaches 0.

Setting up the examples Server Smalltalk is a highly configurable framework that allows users to leverage various protocols, transports, marshaling techniques, etc. In an effort to demonstrate typical distributed configurations, SST provides a suite of examples modeled after the Ping-Pong metaphor. The SST Ping-Pong examples should be viewed collectively and studied independently. That is, even though the examples are independent of each other (e.g. SstPingPongByReference and SstPingPongByValue), they still share code and implementation through a common super class (SstPingPong). To run the examples, you need two Smalltalk images with the SST example code loaded. You will tell one image to be Ping and the other to be Pong. When you are setting up the Ping and Pong images you will need to tell SST what communications resources to use. This is done using the transport portion of URLs as discussed in “Spaces, contexts, URLs” on page 3. Assuming that you are using a TCP transport, the transport portion will be tcp/host:port, for example, tcp/foo.com:1234). When you construct your own distributed applications, you will also need to perform this step. This is nothing more than describing how your image will communicate with the outside world. In most of the Ping-Pong examples, there are a number of helper methods that help you perform this task. For the most part, you can run the different ping-pong examples by replacing the class name SstPingPong* in the steps given below with that of the example you wish to run. Therefore if you want to run the by-reference example, you would use the corresponding class name SstPingPongByReference. 1. For the image that will be Ping, run the code below. SstPingPong* setupPing: 'tcp/ping.com:1234' pinging: 'tcp/pong.com:5678'

2. On the machine that will be Pong run: SstPingPong* setupPong: 'tcp/pong.com:5678' ponging: 'tcp/ping.com:1234'

Remember to substitute the name of the example for the ’*’! Note: As mentioned above, the Sst Ping Pong examples use a variety of helper methods to simplify the setup and configuration of the distributed infrastructure. Be aware that these are only partial URLs. The appropriate scheme is automatically added by the example code (SstPingPong>>registerInvocationConfiguration).

20

VisualAge Smalltalk: Server Smalltalk Guide

How each example is set up depends somewhat on its distribution semantics. For instance, the examples that use remote references are configured differently than those that pass objects around by value. It is worth exploring these methods to understand their differences.

Running the examples It is important to realize that code above did not create Ping and Pong for you, it simply configured and started the necessary Server Smalltalk infrastructure. To run your example you will need two objects that talk to each other, a Ping and a Pong. Both Ping and Pong are instances of SstPingPong*, however their behavior varies (i.e. what messages they send) depending on whether they are playing the role of Ping or the role of Pong. What role they play is determined by which machine they are on. Further, when a machine is set up as Pong, it will make available a factory object that is responsible for creating the actual Pong object. In most of the examples, the Pong Factory is the the class of your example, e.g. SstPingPongByValue. Now that the example’s infrastructure is ready, the next step is to create ping-pong objects on both machines. This could be done manually or, as a convenience to get you up and running faster, the Ping-Pong examples have provided a helper method which does all the work. You will want to send further messages to the ping-pong object on Ping; so you might like to open an inspector on the result of the following. On Ping you can evaluate: SstPingPong* createPingAndPong

This method sends a message to the well-known Pong Factory (on the Pong machine) that creates and exports a ping-pong object (known as Pong). A reference to the created object (Pong) is then returned and retained in the local ping-pong object (Ping) which is itself returned from the method. Therefore, by inpsecting the result of this code, you will be looking at an instance of SstPingPong* that represents Ping. It contains an instance variable named remote that holds onto either a reference to Pong (i.e. in the ByReference examples) or an identifier that can be used to look up Pong in the remote space (i.e. in the ByValue examples). This is how Ping knows about Pong and visa-versa. Since they are now known to each other, they can communicate via messages, just as though they were both resided in the same image. If you would like to see what goes on during setup, put a breakpoint in the setupPing:pinging and setupPong:ponging methods of the example you are running. Other interesting methods include createPingAndPong and createFor:. Having set things up and created the objects, the example can be run by sending start: 3 with: #(1 2 3 4 5) to the result of the createPingAndPong method on Ping. Alternatively, you can combine the two operations into one. For example, evaluate: SstPingPong* createPingAndPong start: 3 with: #(1 2 3 4 5)

Note that there is nothing unique about the values chosen for start:with:. The required arguments are an integer for the start: part and any object you like for the with: part of the operation.

Chapter 3. Building server applications

21

Running the example prints a series of messages on the Transcript of each image. Notice that the value received decreases with each message. The information about the process relates to the process which is running the current request. This will become more interesting as you begin to understand the different dispatching techniques used within Server Smalltalk. All of the ping-pong examples do exactly the same message sends but the requests are handled differently depending on how the system is configured. This request handling can be studied by looking at the process information in the Transcript output. While it is discussed in more detail below, the examples demonstrate, among other things, the ability to have each request run in a single process (SstPingPongByValue), in one of a pool of processes (SstPingPongByReference) or maintaining logical process identity across multiple remote processes (SstPingPongLP). Once you have played with an example be sure to clean up the related SST infrastructure and example objects for the example class you ran. Do this on both Ping and Pong using: SstPingPong* cleanUpPingPong

Summary Although there are many Ping-Pongs examples and all this might sound confusing, just remember there are three basic steps in the Ping-Pong examples: 1. Setup the SST Infrastructure on the machines that will represent Ping and the machine that will represent Pong. Remember, on the Pong machine, the Pong Factory is created and exported for you. The helper methods used here are SstPingPong*>>setupPing:pinging: and SstPingPong*>>setupPong:ponging:. 2. Create the instances of SstPingPong* representing Ping on one machine and Pong on the other. This is done through the helper mehtod SstPingPong*>>createPingAndPong. 3. Ask Ping to start sending messages to Pong. This is done by sending the messager start: @value with: @object to Ping. Remember, Ping is the instance of SstPingPong* that is returned to you from the SstPingPong*>>setupPing:pinging: message. The steps to be taken are summarized in the table below for the by-value example. When steps are shown in the same row of the table, the respective order is immaterial. However, you should complete both steps in a row before moving on to the next row. Ping (client machine)

Pong (server machine)

SstPingPongByValue setupPing: 'tcp/ping.com:4567' pinging: 'tcp/pong.com:4567'

SstPingPongByValue setupPong: 'tcp/pong.com:4567' ponging: 'tcp/ping.com:4567'

SstPingPongByValue createPingAndPong start: 3 with: #1 2) SstPingPongByValue cleanUpPingPong

SstPingPongByValue cleanUpPingPong

Note that the SstPingPong class comment has more details about what each example does and how it is run.

22

VisualAge Smalltalk: Server Smalltalk Guide

Ping-Pong examples The structure of the ping-pong examples highlights the setup, use and properties of various SST configurations. You are encouraged to compare the code for each and see how the various parts fit together and how configuration variations change behavior. Below is a brief description of each example and what you should expect to see when running it. Similar text can be found the class comment for SstPingPong. Note that the class SstPingPong is abstract and is not itself an example. | | | |

Additional information regarding the examples can be found in the Envy comment for the SstPingPong class. You can view the comment by selecting the button in the lower right of your Classes Browser. When the button is labeled Comment, you will see the Envy comments. SstPingPongByValue This example demonstrates by-value message passing. Regardless of the object you supply for @value, it will be passed as by-value and so will be local when printed. As such, it will print normally. SstPingPongByReference This example exercises by-reference message passing. The object supplied for @value will be passed as a value if it is immutable (for example, numbers, strings, and so on) but otherwise will go as a reference. The print-out should look the same as with by-value but more remote messages are required to get the printStrings. SstPingPongLocation Unlike the by-reference example, this example sends sstPrintString to @value rather than printString. sstPrintString never causes a remote message to be sent. If the receiver is a remote object, its object ID and home space are printed in {}s. Otherwise the object is printed normally. In one Transcript you should see @value printed normally and in the other it should come up as a reference shown in {}s. SstPingPongLP This example demonstrates logical processes. This concept is described in detail in the SST manuals. To summarize, the LP model maintains standard Smalltalk process semantics across a set of distributed processes. Things such as out-of-scope returns, ifCurtailed: and ensure: block and process termination are done correctly even though a call chain may have ping-ponged in and out of various object spaces several times. This first LP example shows that pings are always evaluated on the same process as are pongs. This may seem unsurprising but consider that when Ping pings Pong, it blocks waiting for a reply. In the meantime, Pong pongs Ping and yet this pong request is evaluated on the process which is blocked waiting for the reply. The contents of @value does not play a particular role in this example. SstPingPongLPTerminate This example demonstrates the termination of a logical process. In normal Smalltalk processes, an ifCurtailed: block is only run if the execution of the receiver block is aborted (for example, by an out of scope return or process termination). Here, when the ping-pong count runs out the current process is terminated causing the ping-pong chain to unwind but on the way back only the ifCurtailed: blocks are run. Notice that they are run in proper nested order. The contents of @value does not play a particular role in this example. Chapter 3. Building server applications

23

SstPingPongLPUnwind Like the terminate example above, this example exercises LPs and ifCurtailed: blocks. In this case an out-of-scope return is evaluated at the end of the ping-pong chain. To do this, the example takes the user-supplied @value and wraps it in a block containing a method return (|). This block is the object passed along as @value when pinging and ponging. The finalAction evaluates @value and causes the return and then the ifCurtailed: blocks along the chain are run. The Transcript output shows that the ifCurtailed: blocks were run as expected. SstPingPongLPHalt The halt example is a variation of the unwind example above. Rather than passing along a block containing an out-of-scope return however, the halt example executes a self halt when it gets to the end of the ping-pong chain. Depending on the settings of the debugger, this causes a distributed debugger to be opened by the UI Handler (typically Ping). You can step, drop-to-frame and otherwise use the debugger as usual. You will note that some of the frames have [pong] appended to the end of their description (assuming the debugger is on Ping). This indicates that the frame is on a remote machine. One point of note is that dropping to a frame does not run the ifCurtailed: blocks between the current top and the drop point. This is standard Smalltalk behavior. SstPingPongLPDgc This example demonstrates the installation of the distributed garbage collection (DGC) system. This example is the same as SstPingPongLP except that on setup, a DGC object is created in each space. The DGC coordinator is assigned to pong. Note that the DGC is started immediately; this associates it with the application context for later retrieval. The total number of DGC collections performed is reported in the Transcript. Try running the example in the normal way using mutable objects for start:with:. For example, start: 3 with: #(’a’ ’b’ ’c’). Run the example several times without doing cleanups. You will notice that the collection count slowly increases. SstPingPongNamingService This example shows how the naming service is used with SST. The example uses by-reference message passing as in SstPingPongByReference. The differences are in how Ping obtains the remote reference to the factory object which creates the Pong object. SstPingPongRmi This example shows how Server Smalltalk can interoperate with Java using Java’s Remote Method Invocation specification. In order to run this example you will need JDK 1.1.8 and the java code provide with the release. For more information on Java RMI support, please see section ::section goes here::. | | | | | | |

SstPingPongIiop The SstPingPongIiop examples demonstrate how to utilize the Iiop infrastructure provided with Server Smalltalk. To run these examples, you will need to insure the IDL for the ping pong examples is available. If you are using a full CORBA ORB implementation, than you can load the IDL directly into the interface repository. The IDL for ping pong is located in the Envy class comment of SstPingPong.

| | |

If you do not have an ORB you can still run the Ping Pong examples between two Server Smalltalk images. To do this, you will need to copy the file Ssidlicwpingpong.swp into your image directory on both Smalltalk

24

VisualAge Smalltalk: Server Smalltalk Guide

| | |

images and rename it in both places to Sstidlic.swp. This file will allow SST to prime the repository cache with the standard Smalltalk bindings and the ping pong bindings.

Programming thin clients using communications This section details the use of SST’s infrastructure to build your distributed applications. It builds on the previous chapters, which described two general approaches to building distributed applications with SST: remote procedure call and remote object invocation. The fundamental differences between these approaches is in what objects you manipulate and the degree to which you must build distributed applications as opposed to applications which run in a distributed environment. In the former case you deal primarily with invocation handlers and endpoints, in the latter with application contexts and remote references.

SstHttpClientExample This section describes SstHttpClientExample, which is a minimal HTTP client which you can use to bash your favorite web server and repeatedly fetch URLs. Try running the example using: SstHttpClientExample exampleWith: #('http://foo.com:80/index.htm' 'http://bar.com:80/us.htm')

You won’t see much but if you look at how the example works you can put in a breakpoint or two and see what is being returned. Or you can inspect (SstHttpClientExample on: 'http://') startUp and then execute: (self fetch: 'http://foo.com:80/index.htm') inspect

You will get an inspector on the contents of index.htm. Don’t forget to run shutDown on the example object when you are done. The SST communications infrastructure supports direct interaction with user applications. Users whose applications are inherently not based on method invocation or interact with non-object-oriented elements may find this useful. The HTTP client example does exactly this. It models a multithreaded application which is continuously fetching web pages from various servers. The application is strictly client-oriented as it will not accept and process incoming requests. The example has three major elements: 1. URL fetch mechanism 2. Request-reply mapping table 3. Background process waiting for replies The URL fetching code is shown below with error cases and comments removed: fetch: url | result endpoint request key | endpoint := SstRemoteEndpoint fromUrl: url sstAsUrl. [ request := self requestFor: endpoint. key := local send: request to: endpoint. result := (self registerFutureFor: key) touch] critical. self close: key. |result contents asString

Chapter 3. Building server applications

25

Given a URL, you construct an endpoint. This is the destination of your request in terms the underlying transport understands. You then build an HTTP request and sent it to the destination server. The HTTP transport returns a unique key for each connection it makes. Since SST currently supports HTTP/1.0, a new connection is made for every request so the key can be used as a request identifier. In the implementation this key is a modified copy of the destination endpoint but you should not rely on any properties of the key other than two different keys will not be #=. Using this key you can maintain a request-reply mapping table and value holder. The method below creates a future (a protected value holder) to hold the result and provide a location for the sending process to block. You then register this future in a table keyed by the key from the transport. Note that this is done in critical to protect the table from shared accesses. registerFutureFor: key |[| future | (future := SstExplicitFuture new) sstSource: key. requestTable at: key put: future. future] critical

After registering the key, the sending process touches the future. This causes it to block until there is a value for the future; that is, until the reply has come. Since the sender is blocked, there must be some other process receiving and handling incoming replies. When the example is started, such a process is forked using the code below. startReceiving workers := [| message | [true] whileTrue: [ (message := local receive) isSstError ifTrue: [self error: 'Could not receive on ' , local sstAsUrl printString]. self setResultFor: message]] fork

This code is an endless loop performing a blocking read on the client’s transport (endpoint). When a message comes in it has already been fully parsed by the HTTP transport so it appears as a communication message with an HTTP header and the data for the fetched URL as the contents. All messages received by transports are tagged with an indication of the sender of the message. This indication is the same value as was provided when the original request was sent (the key). Using the message sender you get the future out of the table and set its value to the contents of the message. This causes the original requestor to wake and continue executing in fetch:. This model is quite simple and easy to use. Furthermore, the code footprint is minimal. It does, however, depend on certain properties of the transport which may not be available on all transports.

Server programming using invocation handlers Looking at the other side of the HTTP client-server pair is useful to illustrate the use of invocation handlers for programming servers. Technically, a server is much the same as the client in that it reads requests, performs some processing and then sends some reply. The corresponding client behavior is to get a reply, return the result to the previous sender and send the next request.

26

VisualAge Smalltalk: Server Smalltalk Guide

However, the similarity ends about there. Servers have additional requirements of managing tables of connections, multiple requests, multithreading and facilitating a wider variety of processing. Invocation handlers and dispatchers provide infrastructure for satisfying all of these requirements.

SstHttpServerExample This section covers SstHttpServerExample, which is a servlet-based HTTP server which runs with a pooled dispatcher. You can specify the TCP address for the server as well as its root directory. The implementation of the server demonstrates many of the communications level features of SST such as message assemblers and hybrid marshaling and tunneling. Rather than doing a straightforward web server, SST supplies a servlet-based server architecture as described in “Chapter 13. Server infrastructure” on page 93. The HTTP server creates a server and installs some servlets as shown in the code below. at: urlString path: directoryPath | configuration context result | configuration := SstSessionManagerConfiguration new sessionClass: SstHttpSession; yourself. (context := SstServletContext new) setAttribute: 'path' to: directoryPath. (result := self using: context) addHandlerUrl: urlString sstAsUrl; sessionConfiguration: configuration. result servletManager defaultServlet: #SstHttpFileServlet; loadServlet: #SstHttpExampleServlet as: 'cgi'. |result

First, a session management configuration is built. Then you create a servlet context used for initializing servlets as needed. The using: instantiates a new server which executes according to the supplied context. To this you add an invocation handler based on the URL provided. This is the location at which the server looks for new requests. The server’s session management is also set up (see “Session management” on page 93 for more information). The server’s servletManager allows you to set the default behavior of the server. It discusses what to do with requests which no other servlet can handle. For HTTP, that is the file servlet which interprets the requested URL as a file path. In the example you also add a CGI servlet which is registered as cgi. As a result, URLs of the form: http://server.com:80/cgi/myCgiRequst?this=that&then=5

are mapped onto the CGI servlet. The current implemention of this servlet simply returns a summary of the variable settings it was provided.

HTTP implementation notes This section contains some brief notes on the HTTP server/servlet implementation.

Routing requests to a servlet In this model, a request is made of a server. The server navigates a servlet graph until a servlet is found willing to handle the request. At each node, the corresponding servlet can decide to process the request and end the traversal, or

Chapter 3. Building server applications

27

forward the request to another servlet and continue the traversal. Invoker servlets are special servlets that only forward requests. An error is returned if the next servlet cannot be determined. With HTTP, requests are to fetch the contents of a path. To aid navigating the servlet graph, the path is split into two parts: the servletPath (initially empty) and the servletPathInfo (initially set to the path). The special HTTP invoker servlets (subclasses of SstHttpInvoker) move the next component of the servletPathInfo to the servletPath and use it to identify the next servlet to try. If an invoker cannot find a matching servlet, the traversal ends in error. The navigation will otherwise end with a non-invoker servlet willing to service the request. The servletPathInfo can be used to convey further arguments, subcategories, and the like to that servlet. Thus, for any given servlet, the servletPath is the path components that were walked to reach this servlet and servletPathInfo is the remaining components from the initial path. This maps closely to a file system: invokers act very much like a directories, and non-invokers are files. There are some axioms for servletPath and servletPathInfo: 1. servletPath may be empty. This can happen if the chosen servlet is the default root servlet. 2. If servletPath is not empty, then it will begin with a /. 3. servletPathInfo will never be empty. It will always begin with a /. The servletPath and servletPathInfo together form the original path.

Distributed objects using application contexts To better understand this section, examine the sample SstPingPongByReference. The by-reference ping-pong classes provide several examples of using and setting up application contexts. The methods below summarize the steps needed to set up the application contexts for your application. context |SstApplicationContext contextNamed: 'PingPong' ifNone: [SstApplicationContext createContextNamed: 'PingPong'] setupPing: ping pinging: pong self context addSpace: #ping at: (Array with: (self urlFor: ping)); addSpace: #pong at: (Array with: (self urlFor: pong)); setupFor: #ping using: SstSpaceConfiguration proxyConfiguration; startUp cleanUpPingPong self context clear

First, a context is allocated. The system automatically manages the set of existing contexts by name. The context method looks up ping-pong’s context under the name PingPong and, if none is found, creates and installs one. This method is called from setupPing:pinging:. Once you have a context, you add the known spaces. The order of adding spaces is not important. Each space is defined to zero or more endpoints, specified as a collection of URLs. You can add additional remote spaces and URLs at any time.

28

VisualAge Smalltalk: Server Smalltalk Guide

After adding the desired spaces the context can be set up. Setup is done by specifying the name of the local space and a configuration object to use in building that space. The only restriction on this operation is that the space specified as the local space must have been added before the context is set up. A context which has been set up can then be started. Sending startUp to the context builds and initializes all the SST components and starts them running. Once this has completed the system is ready to run your application. Shutting down a context can be done either with shutDown or clear. Both operations stop all SST resources controlled by the context. shutDown leaves the context partially configured such that it can be restarted using startUp. clear completely wipes the context and all its contents clean. Components that have been sent clear cannot be restarted.

Chapter 3. Building server applications

29

30

VisualAge Smalltalk: Server Smalltalk Guide

Chapter 4. Inspecting and debugging SST applications This chapter covers tools available when you load the Server Workbench, SST feature.

The SST menu When you load the Server Workbench, SST feature or the SstToolsSupport application, the choice SST is added to the Tools menu of the Transcript. The SST menu choice offers the following: Shutdown Allows you to choose an application context to shut down using the shutDown protocol. Clear

Allows you to choose an application context to clear using the clear protocol.

Inspectors Are System Objects Opens an inspector that does not send remote messages. See “System objects” on page 32. Use Distributed Debugger Toggles the system so a distributed debugger is enabled. See “Distributed debugging” on page 32. Report Errors via UI Handler Toggles the system so it reports errors to remote object spaces. See “Distributed debugging” on page 32. Trap Exceptions Enables or disables the trapExceptions flag on invocation configurations. Forward Exceptions Enables or disables the forwardExceptions flag on invocation configurations. Trap Marshaling Exceptions Enables or disables the trapExceptions flag on marshaling configurations.

Inspectors Debugging and inspecting the low-level parts of a distributed system containing remote references can be troublesome because remote messages may be sent at unexpected or undesirable times. The SstToolsSupport application provides an SstInspector which does not send remote messages. If a remote reference is inspected, the inspector shows the reference’s local representation. You can inspect all objects, local or remote, can be inspected using this inspector by sending them the message sstInspect. Choosing Basic Inspect from a menu will not have a significant effect on the number of remote messages sent. The sstInspect message is the only way to eliminate such remote messages while inspecting objects.

© Copyright IBM Corp. 1997, 2000

31

System objects A system object is an object which may require direct access to local representations of remote objects. That is, objects for which the transparency of remote references is not always desirable. The method sstIsSystemObject defines whether or not the receiver is a system object. Objects such as inspectors and debuggers return true to this message. The value returned is used by operations such as printOn: to determine if they have been invoked as the result of some processing in a system object. If they have then the operation can choose to do a different calculation. For example, printOn:, when sent to a remote reference as part of a debugger operation will not send any remote messages. Instead, some suitable alternative is produced based on locally available information. While this capability is useful, it is statically defined. There may be situations in which you do not want your inspectors to be treated as system objects. To facilitate this, SST provides the inspectorsAreSystemObjects property in SstToolsSupport class. This option can be set from the SST menu or in code using the following expression: SstToolsSupport inspectorsAreSystemObjects: false

This option can also be set using the SST menu choice Inspectors Are System Objects.

Distributed debugging To better understand this section, examine the sample SstPingPongLPHalt. If the SST distributed architecture being used does not support logical processes, the normal debugger is provided. There are also facilities which support cross-system debugging in the manner of XD. If Logical Process (LP) distributed architectures are being used, then the appropriate debugging tool is the distributed debugger. The distributed debugger allows you to follow logical process execution as it travels across remote spaces. This ability presents a debugging view much like that seen during normal single image debugging. In particular, the distributed debugger supports the following features: v Full stack trimming: the entire distributed stack is displayed with all intervening system code trimmed out. v Support for all step operations: step into, step over, and step to return. v Out-of-context returns, process termination and drop-to-frame are handled correctly. v Distributed debugging of the UI process. All object spaces wishing to participate in distributed debugging must have the runtime support application (SstDebuggingSupport) loaded. Object spaces in which the distributed debugger UI is to be run must have the SstDebugging application loaded. Only processes having an associated logical process can participate in distributed debugging.

32

VisualAge Smalltalk: Server Smalltalk Guide

The distributed debugger assumes the underlying SST system is working correctly; that is, the debugger is being used to debug application problems, not SST problems.

Using the Distributed Debugger The distributed debugger adheres closely to the normal Smalltalk debugger interface. As such, you might look at the IBM Smalltalk User’s Guide or the VisualAge User’s Guide for more information on how to run debuggers. In spaces having debugger UI capabilities, the use of the distributed debugger can be enabled or disabled using the following expression: SstDebugging useDistributedDebugger: true (or false)

This option can also be set using the SST menu choice Use Distributed Debugger. With the distributed debugger enabled, a reported error process will be shown in the normal debugger UI but the debugger itself will attempt to find and display any remote stack frames. This behavior can present a problem when trying to debug your messaging infrastructure because the debugger will itself attempt to send remote messages. With the option disabled the debugger behaves as a standard Smalltalk debugger. SST also allows errors to be reported to remote object spaces. The logical process model maintains the notion of a UI Handler. If remote error reporting is enabled and an error occurs, the current UI Handler is asked to report the error to you, typically by opening a debugger. This behavior is controlled using the following expression: SstDebuggingSupport reportErrorsThroughUIHandler: true (or false)

This option can also be set using the SST menu choice Report Errors via UI Handler. Although the distributed debugger has behavior nearly identical to the normal Smalltalk debugger, the following differences have been noted: v Setting the attributes or instance variables of a process will affect only the local process. These changes are not propagated along the logical process chain. v Stack frames from remote spaces are marked with [spaceName] at the end of their entry in the frame list. v Currently, some Browse menu choices are not supported when remote frame is selected.

Potential problems There are some things you need to know about the debugger: v All spaces involved in a logical process chain being debugged must be reachable from and known by the space running the debugger UI. v Stepping the execution of a logical process which enters a space without SstDebuggingSupport loaded is not supported. In these cases, only the resume operation is allowed. If you attempt to step when not allowed, the operation will abort and a dialog box will appear.

Chapter 4. Inspecting and debugging SST applications

33

v It is not possible to debug a logical process whose execution spans any spaces without the SstDebuggingSupport application. In this situation, the process cannot even be resumed. You have a couple of options at this point: – Load SstDebuggingSupport in all relevant spaces, remove the process from the debugger and add it again. – Manually find the space containing the top of the logical process stack and either terminate or resume the process. v Walkbacks from within the debugger might occur if part of a logical process is abnormally terminated. You should avoid terminating any process which does not contain the top-most frames of the logical process. Terminating a process other than the top-most (the active process) may result in the debugger sending messages to remote objects which no longer exist. This situation cannot be detected by the debugger. v If the distributed debugger generates walkbacks while attempting to debug a process, disable distributed debugging and debug the process using the system debugger. To do this, note the process’ name, remove the process from the debugger with Processes → Remove From List, disable distributed debugging by setting SstDebugging useDistributedDebugger: false (or using the SST menu choice) and then add the process to the debugger with Processes → Debug Other.

Remote administration The SST Remote Administration facilities allow you to monitor and configure an SST infrastructure from any HTML-enabled desktop. This is done by embedding a lightweight HTTP server in the target application and registering application-defined SST components for remote administration. Remote administration as a whole is started by executing the following expression: SstAdministrationServer default startUp.

This starts an administration server on the local machine at port 9001 (by default). The server is then accessed by pointing your web browser at the URL 'http://hostname:9001/admin/'. The startUp method will return an SstError if the server fails to start for some reason. The administration server can only monitor components of SST which are pre-defined to be administrable. These include: SstApplicationContext, SstInvocationHandler, and SstLocalEndpoint. Note that administrable objects often contain components which can be monitored and configured (for example, transports). The behavior of a sub-component is monitored or controlled by administering its parent. SstAdministrationServer provides special protocol which, when given an administrable component, installs the component and all its sub-components into the adminstration system. Below is a code fragment which shows how to set up administration on a variety of components: SstAdministrationServer default administrateApplicationContext: Example context; administrateHandler: BankingExample invocationHandler as: 'bankHandler'; administrateEndpoint: SendmailExample localEndpoint as: 'sendmail replacement'

Using the above protocol, administrating an application context causes all its invocation handlers and endpoints to be administrated.

34

VisualAge Smalltalk: Server Smalltalk Guide

Likewise, administrating an invocation handler causes its endpoint to be administrated. The following code shuts down an administration server: SstAdministrationServer default shutDown

Administrators also respond to clear.

Chapter 4. Inspecting and debugging SST applications

35

36

VisualAge Smalltalk: Server Smalltalk Guide

Chapter 5. Distributed garbage collection To better understand this section, examine the sample SstPingPongLPDgc. The distributed garbage collection (DGC) system for SST is used to remove objects from the export set of an object space once they are no longer imported (referenced) by any other space participating in DGC. Once removed from the export set, they are subject to collection by the normal Smalltalk garbage collector. A typical distributed application is spread over a number of application contexts with the DGC system installed in each. The object space of one of these contexts is chosen as the coordinator space for the DGC. The DGC coordinator is responsible for initiating and detecting the termination of garbage collection iterations. The DGC system attempts to maintain a threshold on the size of the export set in each object space. Once the number of exported objects exceeds this threshold, the local DGC object asks the DGC coordinator to initiate a new collection iteration. Once the iteration is complete, each space is free to remove the objects which are no longer referenced by remote spaces. The DGC system has also been designed to gracefully handle incremental registration and deregistration of spaces and to accommodate failure scenarios.

Requirements for using DGC There are two applications for DGC: SstDistributedGC and SstDistributedGCCoordination. Both applications must be loaded in the DGC Coordinator’s image. All other images need only load SstDistributedGC. There are some additional requirements which must be met before DGC can be used in a particular system. v The passing of objects as references must be supported. A by-value system has no requirement for DGC as no remote references are created. v The local spaces should be configured to support proxy finalization. This prevents object spaces from hanging on to imported remote references even though they are not used locally. This option is controlled by the space’s configuration. Use either SstSpaceConfiguration finalizedProxyConfiguration or SstSpaceConfiguration finalizedProxyConfiguration. These must be specified before the configured object space is started. v The key used for manually exported objects (for example, using export:as:) must answer true to sstIsTransientKey if the exported object is to participate in DGC. By default, only SmallIntegers are transient keys. Objects exported using Symbols, for example, are not subject to DGC.

Installation, startup and shutdown The following is an example of DGC installation which works regardless of whether SstDistributedGCCoordination is loaded in the local image. Note, it must however be loaded in the space specified by coordinatorSpace. (SstDgcConfiguration new instantiateIn: context coordinatorSpace: coordinatorSpace) startUp

© Copyright IBM Corp. 1997, 2000

37

instantiateIn:coordinatorSpace: accepts either a space name or an actual space for the @coordinatorSpace and returns an instance of SstDgc. Note that instantiating an SstDgc is different from starting it. You must hold on to the SstDgc until ready to start it. Once a DGC has been started, it is shut down using shutDown as shown below. Once the DGC system has been started, SST maintains a reference to the created SstDgc but once it is shut down, this reference is removed. (SstDgc for: context) shutDown

The DGC Object Instances of SstDgc embody the bulk of the DGC system. SstDgcs which have been started are maintained by the system on a per context basis. They are accessed through the following API on the SstDgc class: for: context [ifAbsent: absentHandler] Answers the instance of the receiver which is currenly associated with @context. If there is no such object, evaluate @absentHandler whose default behavior is to return nil. An SstDgc can be configured to initiate iterations automatically or to leave this responsibility to you (using requestDgc). In either case, the DGC system must be started up, both in the local space and in the coordinator space, for an initiation to be successful. Note that any requests to initiate an iteration when one is already running are ignored. The code to initiate a DGC iteration is: (SstDgc for: context) requestDgc

DGC configuration SstDgcConfiguration objects are used to configure instances of SstDgc. As with other configuration objects, they are used to instantiate SstDgc. There are six aspects which may be configured: automaticInitiation Controls whether the DGC automatically requests iteration initiation once a threshold is passed. The default is true. initiationThreshold Specifies the amount by which the number of exports may grow after an iteration concludes before a new iteration is automatically requested. The default is 100. iterationTimeout Specifies the maximum number of seconds one DGC iteration can take. This is used to prevent iterations lasting indefinitely and to detect failure. If an iteration is not completed inside this time period, it is assumed to have failed and each participant enacts its failure recovery mechanisms. The setting of this parameter must allow for normal iteration completion times which depend on the number of participating spaces and the communications characteristics. The default setting is 120 seconds. Set the iterationTimeout well in excess of twice the messageArrivalDelay. If this is not done, iterations may timeout and fail while DGC objects are still delayed awaiting message arrival. It is your responsibility to ensure that these options are set correctly. messageArrivalDelay Specifies the time, in milliseconds, to wait for messages before going to the next phase of the DGC algorithm. Delaying in order to await message

38

VisualAge Smalltalk: Server Smalltalk Guide

arrival from other DGC participants at various points in the algorithm can reduce the number of messages required to complete the iteration. A rough heuristic to use in setting this parameter is: (average message time) * 5. Note that this delay is only an optimization, it does not affect the correctness or efficiency of the algorithm. The default is 1501 milliseconds, which has been determined by tests to be the optimum delay. registrationAttempts Specifies the number of times to try to register with the coordinator during startup. The value must be a positive integer. The default setting is 6. registrationInterval Specifies the total time, in seconds, allowed for each registration attempt. If registration succeeds then startup returns immediately. Otherwise, if a response has not been received in the time set by this option, the attempt is aborted and retried (if allowed by the registrationAttempts option). The integer value of this option must be >= 1. The default setting is 10 seconds. An example of using a SstDgcConfiguration object and instantiating the DGC system is given in the following code: | context coordinatorSpace configuration | context := "You supply this". coordinatorSpace := "You supply this too". (configuration := SstDgcConfiguration new) automaticInitiation: true; initiationThreshold: 50; messageArrivalDelay: 2000; iterationTimeout: 60; registrationAttempts: 2; registrationInterval: 30. configuration instantiateIn: context coordinatorSpace: coordinatorSpace.

Restrictions and side-effects There are a number of restrictions and side-effects to the operation of the DGC system which are important to note. v Note all of the requirements listed in “Requirements for using DGC” on page 37. v There is no requirement for DGC to be installed in all application contexts participating in some distributed application. Similarly, it is possible to have multiple DGC systems executing concurrently provided that the subset spaces of the participating contexts do not overlap. Spaces which do not participate in DGC but communicate with spaces which do may lose access to remote objects they reference if those objects are garbage collected. It is advisable to start up the DGC system in all participating spaces before any significant amount of inter-space communication occurs and to shut down the DGC system in a space only after it no longer needs any remote references it may have. v Distributed garbage cycles are not collected. For example, assume object foo in space A references object bar in space B, and vice versa. Even if there are no other references to either foo or bar, they form a distributed cycle and will not be detected as garbage. v A modifiable copy of the configuration is made when instantiating the SstDgcConfiguration object. Thus, modification of configuration options after the DGC object has been created must be performed on the configuration accessed from the SstDgc object, not the original.

Chapter 5. Distributed garbage collection

39

v DGC must be instantiated and started up in the application context which manages the DGC coordinator space. If this does not occur, registration attempts will eventually cease and no collection will be performed. v SST does not permit communication between spaces belonging to logically different distributed application contexts. Thus if application contexts C1 and C2 are installed in some SST image, DGC cannot be installed to operate across both C1 and C2. v The DGC system has not been tested with unordered network communications (those for which there is no guarantee that two communications between two machines are received in order). Although the design is reasonably resilient to asynchronicity, there may be unexpected behavior in the DGC system. v DGC impacts performance in two ways: 1. A small increase (about 50 bytes) in the size of each message due to some DGC context information; and 2. An increase in message traffic during collection iterations. Each iteration requires at least three coordinator-to-all messages plus at least one message between each space importing an object and the space hosting that object. Additionally, there are some minimal memory requirements for the DGC objects and processing overheads associated with the operation of the DGC system.

Good practice and bad practice While it is not a requirement that the coordinator space DGC be either started up first or shut down last, it is highly recommended. Doing so avoids unnecessary and doomed (if the coordinator has not been started up) attempts by the DGC to register for participation. Similarly, it is bad practice to start up the DGC in a process and perform communications with other participating spaces while assuming that initiating start up of the DGC is all that is required. Until the DGC has succeeded in its start up operation (thereby registering with the coordinator), any iterations that occur may collect objects that are referenced remotely by the local space.

Sending e-mail from code You can send e-mail from code using the sstEmailTo: instance method in String. The argument should be a URL which specifies the mail-delivering transport. The receiver should be a mail messenger adhering to the format specified by the mail-delivery service in the URL argument.

Sending SMTP/Internet e-mail To send SMTP e-mail, you use the ’mailto:user@host’ URL format with mail messages (the receiver) in the Internet mail standard defined in RFC822. A message is sent only to the receiver identified in the argument regardless of any To:, Cc:, or Bcc: header fields in the message. The SMTP transport supports sending mail through MX mail forwarders by redirecting messages through an SMTP smart host, normally a conventional mailing system. You can configure this using the following system-wide setting: SstSMTPCommunications smtpSmartHost: ''

Below is an example of sending a message using this mechanism:

40

VisualAge Smalltalk: Server Smalltalk Guide

'To: Johnny From: A Doit Subject: Look at the power of SST! This was sent to you courtesy of a Smalltalk doit and SST.' sstEmailTo: 'mailto:[email protected]'

You will have to discover for yourself how to send anonymous mail.

Packaging notes for SST applications Direct packaging When packaging directly from an image (not through Server Workbench), you must construct a set of packaging instructions specifying which transport, invocation, and URL configurations the image will use. For example, packaging an HTTP server requires the explicit inclusion of configurations for the ’http’ transport, ’http’ invocation, and the ’http’ URL. This is required as directly packaging an image does not include the loaded code which typically defines these configurations. SST provides some methods to help you explicitly include the required classes. To use these methods, add a method similar to the following to your application. packagingRulesFor: aRuleCollector aRuleCollector image isRunningImage ifTrue: [ SstUrl addPackagingRulesFor: 'http' to: aRuleCollector. SstInvocationHandler addPackagingRulesFor: 'http' to: aRuleCollector. SstTransport addPackagingRulesFor: 'http' to: aRuleCollector.]

This explicit style of packaging ensures that minimal classes are included. While the relevant SST applications (for example, SstHttpSupport) could automatically cause their respective configurations to be included, this may cause these configurations to be unnecessarily included. The SstPackagingExamples application has example packaging instructions for several SST examples.

Packaging through Server Workbench There are no special steps necessary to package with Server Workbench. Proceed as described in the packaging information in the VisualAge Smalltalk Server Guide.

Packaging RMI applications A Java RMI type repository is encoded as instance methods that are not normally packaged. SST provides two helpers, sstIncludeJavaClass:from: and sstIncludeAllJavaClassesFrom: that cause the appropriate field accessors and classes to be included in the packaged image. You should use the helpers for any application-provided type definitions. In nondistributed applications, methods that have no senders can usually be ignored and not dumped. This isn’t true in distributed applications as server objects generally provide interfaces which are invoked remotely and never sent from the local image. These methods should not be reduced! An easy way to accomplish this is to categorize these methods with a special category (for example, SST-Remote API) and use the Packager’s category inclusion rules: Chapter 5. Distributed garbage collection

41

includeAllMethodsInCategoryNamed:inClassNamed:*. These rules cause all methods defined in the given class with the given category to be included in a packaged image. Note that this does not include any such categorized methods in the class’s superclasses. SST provides two similar helper methods, sstIncludeAllMethodsInCategoryNamed:withSuperclassesOfClassNamed: and sstIncludeAllMethodsInCategoryNamed:withSubclassesOfClassNamed:, which include methods in the named category for all superclasses and subclasses of the named class. These helper methods are in SstPackagingInstructions and can be sent to the rule collector, the argument to packagingRulesFor:. Ensure that you load SstPackagingInstructions into the development image, which allows them to be used when packaging with the Server Workbench.

| | | |

Common packaging problems Packaging applications with logical process debugging To enable debugging of walkbacks in images packaged directly, you must install SstErrorReporter manually. This is normally done automatically when loading SstDebuggingSupport. It is removed when packaging directly from an image, however. To explicitly install the error reporter, execute the following expression before an error occurs: SstErrorReporter install

Packaged image exits Packaged images have the following cycle: 1. Do image startup. 2. Execute the startup code. 3. Exit image. If possible, it’s usually best to have your server application run in the starting process. But startup code commonly forks a new process to do the server processing. The starting process then resumes execution and exits the image. The solution is to terminate the starting process after starting the server. This is done by setting the startup code as follows: foo bar. Processor activeProcess basicTerminate

Use basicTerminate with headless images (images without a UI). Using terminate causes another UIProcess to be started. This causes a walkback as it attempts to start the UI message loop, which will not have been packaged. For headed images you should use terminate.

SstUndefinedTransportError or SstUndefinedSchemeError If SstUndefinedTransportError or SstUndefinedSchemeError errors occur in a walkback in your (directly) packaged image, it is likely that the source image has lost all of its configurations. You can re-register the configurations by running the loaded methods for the relevant SST applications. The errors might also occur if your packaging instructions are not properly set up as described above.

42

VisualAge Smalltalk: Server Smalltalk Guide

‘UndefinedObject does not understand resume’ You might get the UndefinedObject does not understand resume error when a packaged image starts, typically because the image was packaged with open sockets. SCI uses ACO which tries to terminate all outstanding futures on startup. The related resources are no longer valid and the image is in an inconsistent state. There are two solutions: 1. Add a packaging rule to nil the default SciSocketManager. aRuleCollector initializeToNilClassVariable: #Default inClassNamed: #SciSocketManager

2. Close all open sockets before packaging. SciSocketManager default closeAllSockets

Chapter 5. Distributed garbage collection

43

44

VisualAge Smalltalk: Server Smalltalk Guide

Chapter 6. Constructing new SST configurations Since server applications vary widely in terms of requirements and architecture, it is impossible to design and build one environment which satisfies all users. As such, SST has been designed as a highly configurable toolkit or framework of components which are commonly needed when building distributed and server applications. As a developer, constructing new configurations of these components to specialize SST for the particular requirements of distributed application designs is a requirement. These components fall in the following rough categories: Communications, Marshaling, Method Invocation and Remote Objects. The Communications components provide a transport-independent mechanism for the transfer of data from one machine to another. Marshaling describes the format of the transferred data and allows objects to be converted to bytes and vice versa. The Method Invocation classes provide functionality similar to remote procedure calls (RPC) and allow the specification of various message dispatch policies. SST’s Remote Object Model supports references to remote objects. SST also provides a number of tools or tool extensions to assist in composing, monitoring and debugging programs using these components. The basic execution model of SST involves invocation handlers, dispatchers, marshalers, and transports. These components are linked together in a manner that is depicted in the figure in “Chapter 1. Getting started with SST” on page 1. On detecting an attempt to send a message to a remote machine, the system asks an invocation handler to invoke the desired method on the desired machine. The handler asks its associated dispatcher for the best way to send the message. Having determined this the handler passes the message to its marshaler which converts the objects into a series of bytes. The handler then uses its transport to send the bytes to the machine hosting the object which is the receiver of the Smalltalk message. A similar algorithm is followed on the receiving side. When the receiving system detects the arrival of an incoming message it passes the received bytes to an invocation handler for processing. The handler has its marshaler convert the bytes to objects (a Smalltalk message object). It then asks its dispatcher for the best way of handling the message. Having made all the correct preparations, the received message is sent to the intended receiver within the handler’s running image and a result obtained. The procedure for handling the return of the result is very similar to that of the original send. The only difference is that the dispatchers on either end may use somewhat different ways of handling the outgoing and incoming reply. Each of the components involved in the handling of messages is implemented as a set of concrete Smalltalk classes. SST adopts a flexible configure-and-compose model in which you compose instances of these classes which are configured to satisfy a particular application’s distributed/server computing needs. An aim is to minimize the amount of unneeded functionality in particular situations. Rather than providing one monolithic distributed/server class library, SST is broken into a number of discrete chunks which are loaded and used only as needed.

© Copyright IBM Corp. 1997, 2000

45

For example, if you decide that you will only be requiring message passing by value you do not need to load the infrastructure for remote references. If at some point you find that you do need remote references, the relevant components can be loaded and used with a minimum of disruption. SST provides a number of commonly-used pre-configured components such as pass-by-reference/value marshalers, logical process invocation handlers, various transports, and object spaces which support transparent remote references. As a developer, you can start with these as a base and make incremental modifications to customize the distributed architectures you wish to create, rather than starting from scratch.

46

VisualAge Smalltalk: Server Smalltalk Guide

Chapter 7. Startup, shutdown, and restart SST provides a common interface for startup and shutdown as described in “Startup and shutdown” on page 17. The interface for components which support startup and shutdown is found in the IuSstStartable interface. The start up and shut down of parts of a running distributed system is difficult if not impossible to define in a general way. Each application has different requirements as to its execution state once an image is up and running. The problem is exacerbated by the fact that in Smalltalk, immediately after saving an image the virtual machine may exit or continue processing. That is, very little clean up work can be done at image save time. Note: SST does not require that any particular clean up be done at image shutdown time. It is assumed that underlying components such as transport subsystems perform all the correct clean up independently. To assist in the management of distributed applications, various SST components define options allowing you to control how the components are treated at image restart time. These controls are available on invocation handlers, object spaces, and application contexts. While the details of each component’s options can be found in the relevant section, in general they adhere to the following pattern. The configuration object associated with the component defines a restartMode. The setting of this mode determines the action taken at image restart time. Roughly speaking, the possible actions are: cleanup Ensures that any remaining component state does not interfere with the safe restart and running of the image. clear

Clears out all objects and resources related to the component.

restart Attempts to restart the component using startUp. Some components are restartable when an image is saved or started up afresh. Such components conform to the IdSstRestartable interface. The two methods that a component must provide are: cleanUpOnRestart Cleans up the receiver from a previous image save. This method is executed during image preStartUp. All you want to do is clear or end anything which might interfere with the image startUp sequence before SST gets a chance to actually start up. startUpOnRestart Starts the receiver (or its related component) according to its configured restartMode. This occurs on image restart (image load).

© Copyright IBM Corp. 1997, 2000

47

48

VisualAge Smalltalk: Server Smalltalk Guide

Chapter 8. Configurations To better understand this section, examine the sample SstPingPongByReference. In an effort to make SST useful in a broad range of situations with a minimum of end-user modification, SST has been made highly configurable. This capability is embodied in configuration objects which manage a collection of options. These options go together to define the desired behavior of some related object. Most of the major SST components (such as spaces, invocation handlers) have corresponding specialized configuration objects. It is assumed that for each option there are corresponding accessor methods for getting and setting the value. Configurations conform to the IuSstConfiguration interface. While the use of configurations provides great flexibility, they can also overwhelm you with innumerable options and combinations only some of which are relevant. The SstExamples application, particularly the ping-pong examples, contain a number of example configurations for various common interaction situations. Once you capture the desired behavior in a configuration, you can use the configuration as a template for instantiating the corresponding SST component. Transport and invocation configurations can be managed by the system. Configurations developed by programmers are registered with the configuraton managers using the transport identifier or invocation scheme. These configurations are then specified using URLs and automatically looked up and used when building communications and method invocation components based on these URLs. In addition to this management, components such as marshalers or dispatchers offer class methods which return configurations describing well-known behavior. For example, byReferenceConfiguration on some message marshalers. It is common practice to keep frequently-used configurations in the image and simply instantiate them as the corresponding components are required. If you do this, ensure that the configuration used in the instantiate call is copy. Failure to do this will result in components which share configuration objects or corruption of the reference configurations. This behavior is not generally acceptable as configurations are often specialized during instantiation of the relevant components.

© Copyright IBM Corp. 1997, 2000

49

50

VisualAge Smalltalk: Server Smalltalk Guide

Chapter 9. Communications The SST Communications components provide efficient communications in a transport-independent way. SST abstracts the notion of a message to cover the conventional collection-of-bytes definition as well as arbitrary user-specified objects or memory. For example, when interfacing to a C transport which maintains its own transport data structures, you might maintain pointers to those structures as part of your message. Other concepts introduced by the communications components are endpoints, URLs, configurations, and transports. The classes and methods related to communications are contained in the SstCommunications application and transport-related applications such as SstTcpCommunications.

Endpoints To better understand this section, examine the sample SstHttpClientExample. Endpoints are the basic element of location within SST. They also provide you an interface to the byte-wise messaging operations in SST. Endpoints are transport-independent and are either local or remote. Remote endpoints are representations of some remote location to which data can be sent and from which data can be received. They have an associated URL and transport specific address. Local endpoints also have a transport (see “Transports” on page 54) which is used for sending and receiving data. Endpoints provide you with a very small common ″initialization″ and ″runtime″ (as opposed to configuration time) API which is consistent across all transports. The semantics of the endpoint messaging operations (for example, send, receive, reply) depend entirely on the underlying transport used. No attempt is made to wrapper or otherwise hide transport semantics. Thus, if a transport supports security, then messages will be sent with the appropriate handshaking and tokens. If the transport guarantees delivery then the sender will receive an error when remote machines crash. Conversely, if the underlying transports do not support these facilities, no attempt is made to emulate them. In addition, SST does not enforce a synchronous or asynchronous messaging model but rather exposes the underlying transport semantics. Endpoints are not connection-oriented. For some transports which support connections (for example, TCP), endpoints might correspond to transport connections but this relationship is neither exposed nor guaranteed by SST. You should use caution if relying on transport-dependent properties as their code will be less portable and hence sensitive to changes in underlying transport implementation. Individual transport semantics and configuration options are exposed in an explicit way through transport-specific configuration objects (see “Transport configurations” on page 54) which you can manipulate.

© Copyright IBM Corp. 1997, 2000

51

The runtime API includes the following methods on instances of subclasses of SstLocalEndpoint: send: message to: target Sends the @message to @target. Blocks until all data has been sent. reply: message to: target Sends @message to @target as a reply. Block until all data has been sent. For transports which do not support a reply mechanism, this will be the equivalent of a send:to:. receive Blocks until a message is received from a peer. Answers the message on success, or an error should one occur. configuration Answers the receiver’s configuration. The configuration sets various transport-specific values to control the transport’s behavior. accessibleUrls Answers a collection of URLs that can be used to communicate with the receiver.

Equivalence between endpoints Local endpoints are quite different from remote endpoints. Remote endpoints are true locators: they uniquely identify some remote location to which messages can be sent or from which messages are received. Local endpoints, however, are used to identify the location at which to wait for incoming messages. This distinction is important: you must not use local endpoints in place of a remote endpoint. With some transports, it is possible for there to be multiple names which all identify the same endpoint. It is necessary to be able to generate all these true locators for a local endpoint. The locators are generated using accessibleUrls. The result of this method is a collection of all the exposed identifying names (as URLs) of a local endpoint. These URLs could be sent to other machines and used by them to build remote endpoints which can be then used to contact the local endpoint.

URLs To better understand this section, examine the sample SstHttpUrl. URLs are used to specify and build endpoints. While endpoints can be built programmatically, URLs are a convenient and familiar way of exposing addressing. The SST URL structure is similar to that found in HTTP applications. That is, scheme:/transport/address where the fields have the following meanings: scheme The policy or protocol of the data communicated through the endpoint corresponding to the URL. See “Chapter 10. Method invocation” on page 65 for examples. transport The underlying transport to use. The value of this field is used to look up transport classes in a transport table managed by SstTransport class (see “Transport configurations” on page 54). Example transport field values are tcp or cpic. By convention, transports prefixed with a c have client behavior in that they do not accept incoming connections. Client transport examples include ctcp and chttp.

52

VisualAge Smalltalk: Server Smalltalk Guide

address The address of the endpoint. The format of this field is transport-dependent. For example, if the transport were TCP, the address field would contain the IP address (name or number) and optional port separated by a colon (for example, foo.bar.com:80). The following are some example URLs. Refer to the relevant transport sections for more exact semantics on how the address fields are interpreted. See “Chapter 10. Method invocation” on page 65 for explanations of the schemes used. fooScheme:/tcp/foo.bar.com:80 Indicates TCP communications with server behavior to a machine called foo.bar.com. Connections to that endpoint can be made by connecting to port 80. The invocation configuration scheme is known as fooScheme. barScheme:/tcpl Indicates a client TCP endpoint. This endpoint can only be used to create new TCP connections. Such connections can be used for both send and receive. One client endpoint can be used to connect to many remote server endpoints. Since no address is given, the IP address will be INADDRANY, and a the port will be that specified as the transport configuration’s defaultPort. The invocation configuration scheme being used is known as barScheme. fooScheme/imap4/bob:secret@host:port Indicates an IMAP endpoint which manipulates mail for user bob with password secret on the server at the TCP addresshost:port. iiop://host:port Has an implicit transport of iiop. URLs are represented in Smalltalk by the class SstUrl and its subclasses. In addition to the typical accessor methods, SST provides the following API in support of URLs: fromString: urlString (SstUrl class) Answers a new instance of the receiver derived from @urlString parsed as a URL of the form scheme:. asUrl (String class) Answers the receiver parsed as a URL. The receiver should be of the form scheme:/transport/address where the address field is optional and in a transport-specific format. Since the format of a URL is scheme-specific, SST manages a table of URL parsers indexed by scheme. This object must understand the message buildUrlFromString:scheme:transport: and return a valid URL or nil. Note that address parsing is typically handled by the transport’s address class through the sstGenerateAddress:configuration: protocol. Parsers are (un)registered using the following protocol on SstUrl. register: urlScheme as: urlParser Registers @urlParser as the parser to use to interpret URL strings starting with @urlScheme. unregister: urlScheme Unregisters the parser for URL strings starting with @urlScheme.

Chapter 9. Communications

53

Transports Transports are wrappers on system-level communications resources such as TCP stacks and CPIC sockets. They provide an API which is identical to the endpoint API described in “Endpoints” on page 51. Typical SST users should not need to use Transports directly; only users wishing to use a previously unsupported communications resource such as UDP will need to program at this level. To enable this isolation but retain flexibility, transports provide a configuration object (see “Transport configurations”) which allows the declarative setting of various transport-specific parameters such as buffer sizes or delays. These configurations are exposed to application developers and attached to transports where they are used by the SST system code. For example, you can build a declarative configuration and then instantiate it on a particular endpoint. This action creates and configures all of the required low-level transport objects while hiding the details from you.

Transport configurations Transport configurations are a transport’s way of exposing relevant low-level detail without forcing the implementation of higher-level APIs. Typically transport configurations are simply containers for transport-specific options. All transport configurations specify at least the common set of options listed below. These typically relate to the classes of objects to use when setting up and using a particular communications mechanism or media. It is fully expected that particular transports will require more configuration information and so will provide subclasses of SstTransportConfiguration. See “Transport configuration registry” on page 55 for examples. The generic options are as follows: addressClass Specifies the class to use when creating address objects to represent destinations available to the associated communications mechanism. assemblerClass Specifies the class to be used as the message assembler. Assemblers are used to assemble messages from and disassemble messages into actual wire format. localEndpointClass Indicates the class of object to use when building local endpoints. messageClass Specifies the class of message object to use for messages sent over the associated communications mechanism. See “Communication messages” on page 62. remoteEndpointClass Indicates the class of object to create when building remote endpoints. streamClass Specifies the class of stream to be used when streaming over data in this transport. Most often used by message assemblers that require streaming behavior. transportClass Specifies the class of transport object to use for the associated communications mechanism.

54

VisualAge Smalltalk: Server Smalltalk Guide

transportIdentifier Defines the transport identifier for the associated communications mechanism. Examples are tcp or imap4.

Transport configuration registry As implied above, transports are not instantiated directly; rather, they are created while building an endpoint using a specifically tailored configuration. SST maintains a registry of transport configurations in the SstTransport class. The names under which configurations are registered correspond to the transport element of a URL. When an endpoint is built for a URL, the transport is looked up in the configuration registry and the associated configuration used to build the transport. The protocol for managing the registered names is: availableIdentifiers Answers a collection of available transport identifiers. configurationFor: url Answers a SstCommunicationConfiguration subclass that handles the transport for @url. Answers an error object if none is found. configurationForIdentifier: transportIdentifier Answers a SstCommunicationConfiguration subclass that handles the transport identified by @transportIdentifier, a string like tcp. Answers an error object if none is found. is: remoteIdentifier reachableBy: localIdentifier Answers true if remote endpoints using the transport @remoteIdentifier can be reached using a local endpoint using the transport @localIdentifier, or false otherwise. mark: transportIdentifier reachableBy: reachableIdentifiers Adds @reachableIdentifiers as reachable from @transportIdentifer. register: configuration reachableBy: reachableIdentifiers Registers @configuration as an available transport. This configuration can be reached by the transport identifiers given in the collection @reachableIdentifiers. register: configuration mutuallyReachableBy: reachableIdentifiers Registers @configuration as an available transport. This configuration is mutually reachable with each of the transport identifiers given in the collection @reachableIdentifiers. This means that the transport identified by @configuration can reach and be reached by a transport configured by any of the identifiers in @reachableIdentifiers. Note that transports described by @configuration must be explicitly referenced in @reachableIdentifiers to make them reachable by one another. removeReachabilitiesFor: transportIdentifier Removes any reachabilities for @transportIdentifier. This includes both transports that can reach @transportIdentifier and transports that are reachable from @transportIdentifier. unregister: transportIdentifier Unregisters and answers the configuration for the transport identified by @transportIdentifier. Answers nil if there is no such configuration.

Connective transports For connective transports, which maintain actual connections, SST defines two well understood behaviors: client and server. Their difference lies in how new Chapter 9. Communications

55

connections are obtained. Server behavior allows both active solicitation and initiation of new connections with other endpoints. Client behavior allows only the initiation of new connections. Thus, two endpoints with client transport behavior will not be able to communicate with one another. In the TCP world, for example, a server transport would have a listening socket waiting for incoming connect operations. A client TCP transport does not have a listening socket as it has no requirement to facilitate incoming connections. All transports which are not client transports are assumed to support server transport behavior. Connective transports provide the following callbacks: SstConnectCallback Sent when a transport has successfully connected to a remote peer. The owner given in the callback will be the local endpoint for which the connection was created, while the callData will be the remote endpoint to which the connection was created. SstDisconnectCallback Sent when the connection between a local and remote transport is closed either on request or due to some error. The owner will be the local endpoint, while the callData will be the remote endpoint to which the connection was connected. If the transport supports connection management, this event will not occur when connections are closed for reuse.

TCP transports TCP transports are a kind of connective transport and support both client and server modes. Server TCP transports create a listening socket at the address and port specified in their endpoint. They will accept connection attempts on that port and create and maintain a reusable socket connection. All messages sent to the connected peer will go through this socket. Many users of TCP find it convenient to derive their application-level notions of connection from TCP’s notion of connection. While this makes their applications somewhat more brittle with respect to transport portability, it is a prevalent approach. SST makes this possible by exposing the endpoints used by the transport itself to manage connections. You can obtain these endpoints through their message assemblers (see “Message assemblers” on page 63) when they send messages or through the communication message’s sender attribute when a message is received. The TCP transport is implemented over SCI, which uses asynchronous callout. This will impose a minor penalty on calls due to thread-switching overhead. As an effect of SCI’s non-blocking implementation, non-blocking SCI calls go directly through the stack and asynchronous callout is not required. If the messages being sent are small, it may be worth setting the nonBlocking TCP configuration option described below to true.

TCP transport configuration TCP transports support the configuration options shown below in addition to the configurations and callbacks described above. Option settings are transferred directly to the underlying TCP implementation (for example, SCI) with no

56

VisualAge Smalltalk: Server Smalltalk Guide

interpretation. Refer to the relevant transport mechanism documentation for descriptions of the valid option values and their meanings. || | | | |

You must have loopback enabled to use the TCP transport with SST. You can successfully ping the address 127.0.0.1 if loopback is enabled.

defaultPort Sets the default port to be used by local endpoints when a port is not specified. The provided tcp and ctcp configurations have their defaultPort set to 0, which will cause a random port to be assigned by the TCP stack. keepAlive Corresponds to the SO_KEEPALIVE socket option, which will cause an occasional ping packet to be sent on connections. This is a coarse-grained operation, affecting all sockets used by that particular instance of the transport. The value may be set to nil. listenBacklog In TCP terms, provides the argument to listen(2), the number of incoming connections to be queued pending being accepted. Its value is meaningless if allowIncomingConnections is false. noDelay Corresponds to the TCP_NODELAY socket option, which toggles whether the Nagle algorithm should be used. This is a coarse-grained operation, affecting all sockets used by that particular instance of the transport. The value may be set to nil. nonBlocking Corresponds to the FIONBIO input/output control (ioctl), which specifies whether operations should be blocking (if false) or non-blocking. This is a coarse-grained operation, affecting all sockets used by that particular instance of the transport. The value may be set to nil. receiveBufferSize Corresponds to the SO_RCVBUF socket option, allows specifying the size of the sockets’ receive buffers. This is a coarse-grained operation, affecting all sockets used by that particular instance of the transport. The value may be set to nil. reuseAddress Corresponds to the SO_REUSEADDR socket option, which toggles whether ports can be reused immediately. This is a coarse-grained operation, affecting all sockets used by that particular instance of the transport. The value may be set to nil. sendBufferSize Corresponds to the SO_SNDBUF socket option, allows specifying the size of the sockets’ send buffers. This is a coarse-grained operation, affecting all sockets used by that particular instance of the transport. The value may be set to nil. Configurations can be applied either when a transport is initialized or dynamically. To apply a configuration dynamically, the configuration should be passed to the endpoint’s configure: method. All non-nil settings are applied immediately. The options which can have nil values have different semantics depending on when they are applied. If set to nil at the Chapter 9. Communications

57

start, the default settings of the stack are used. Setting an option to nil after startup ensures that subsequent configure: operations will not alter the current setting of the option in the TCP stack.

‘tcp’ and ‘tcpl’ URLs Specifying tcp or tcpl in the transport field of a URL indicates a server or client, respectively, TCP transport as described in the URLs section above. For tcp transports, the URL indicates the listening socket on which to accept incoming connections. For tcpl transports the URL specifies the TCP address to use as a global identifier. For example, scheme:/tcp/[hostname][:port] scheme:/tcpl/[hostname][:port]

in which hostname can be any one of: v A domain name (such as foo.oti.com or localhost) v A dotted IP address (such as 192.230.48.9) v Empty, which represents INADDR_ANY (0.0.0.0) And port can be any one of: v Not specified, in which case a default specified by the transport’s configuration is used v A non-zero number, which is used directly (such as 25) v A well-known service name (such as smtp, ftp, or dst) usually found in the file /etc/services (UNIX) or \tcpip\etc\services (Windows/Novell). These must be TCP-style services. You can get varying levels of flexibility depending on how precisely they specify addresses. For example, a tcp transport on a machine with two IP addresses can be specified using a precise IP name (foo.oti.com) or number (128.43.87.123). This transport will only accept connections on the specified interface. If the host name is not specified (representing INADDR_ANY) then the transport will accept connections on any of the machine’s interfaces. Note that when connecting to a remote endpoint, you must always specify a host name or an error will be returned. If the port is 0 (zero), which may be either given explicitly or be configured as the default port in the configuration, then the stack will automatically allocate an unused port on which to listen. Doing this will not change the contents of the endpoint; its URL will not be updated with the new port. Rather, the set of URLs describing that particular endpoint can be obtained by sending accessibleUrls to the endpoint. While client TCP transports do not have a listening socket, they do bind with the socket corresponding to their URL. This feature allows the addresses which are not fully specified to be automatically completed with values which are guaranteed to be globally unique. It is by these values that the endpoint will be known on remote machines. As to URLs, keep the following in mind: v URLs supplied to a remote machine should always be as a result of an accessibleUrls operation. It is vital that the correct URLs be supplied as URLs are used to build endpoints which are used as the keys in the transport’s internal connection table. Mismatches in the peer’s view of

58

VisualAge Smalltalk: Server Smalltalk Guide

the same endpoint can result in duplicate connections or, in the case of a client transport, an inability of the server to send messages to the client. v It is highly recommended that TCP URLs not be specified using INADDR_ANY as the host. The SST TCP Transport does not currently handle connections with multiple interfaces. For example, if machine A is known as foo.com to machine B, and as bar.com to machine C, when it sends a message to B, it may go out as either foo.com or bar.com. However, if it goes out as the latter, B has no knowledge of a connection with that machine and the message is rejected. v The tcp and tcpl transport configurations are defined with the noDelay option set. As a result, they are not suitable for sending and receiving large amounts of data.

MQ transports MQ transports are a kind of connective transport supporting both clients and servers through MQSeries. With MQSeries, applications read and write data through queues, which are managed by queue managers. To send or receive data via MQSeries, an application must specify the queue manager and the queue. (The queue manager can be either on the local machine or remote.)

MQ transport configuration In addition to the the configuration options and callbacks described in “Transport configurations” on page 54, MQ transports support one additional option: timeoutPeriod Specifies the length of time (in milliseconds) to wait for an incoming message when receiving from a queue. If no message arrives within the specified time period, the call will return with an MQ “no message available” error. To wait indefinitely, specify MqwiUnlimited. This is the default value. Configurations can be applied either when a transport is initialized or dynamically. To apply a configuration dynamically, the configuration should be passed to the endpoint’s configuration: method. All non-nil settings are applied immediately. The options which can have nil values have different semantics depending on when they are applied. If set to nil at the start, the default settings of the stack are used. Setting an option to nil after startup ensures that subsequent configuration: operations will not alter the current setting of the option in the MQ stack.

‘mq’ URLs Specifying mq in the transport field of a URL indicates an MQSeries queue. The URL specifies the queue manager and queue to use for sending or receiving messages. For example, scheme:/mq/[qmanager]/[queue]

in which qmanager is a defined queue manager, either local or remote, and queue is a defined queue managed by the specified queue manager.

Chapter 9. Communications

59

You can also omit the queue manager from the URL, in which case the system default queue manager is used: scheme:/mq//[queue]

As to URLs, keep the following in mind: v URLs supplied to a remote machine should always be as a result of an accessibleUrls operation. It is vital that the correct URLs be supplied as URLs are used to build endpoints which are used as the keys in the transport’s internal connection table. Mismatches in the peer’s view of the same endpoint can result in duplicate connections or, in the case of a client transport, an inability of the server to send messages to the client.

Email transports (SMTP and IMAP4) The SST email transports provide a disconnected communications model over standard email systems. It is primarily intended for exchanging machine-based information rather than typical user email. Most SST messages can be tunneled over these transports.

SMTP transport The SMTP transport contains both client (send mail messages) and server capabilities (that is, it can both send and receive mail messages). An SMTP URL takes the following form: scheme:/smtp/user@host

The scheme and transport components have their standard meanings. The address consists of a user name and a host and port for the endpoint. The port is optional and defaults to the standard SMTP port (25). user is also optional but this makes sense only for local endpoints and will cause outgoing mail to have an anonymous return path. host, if not specified, defaults to the TCP address INADDRANY and also is only sensible for local endpoints. While the contents of an SMTP message can be any collection of bytes, the transport itself uses a special SMTP header. For example: | header body | header := SstSmtpHeader parseHeaderFrom: ‘From: briand\To: jeff\Subject: test’ addLineDelimiters. body := ‘This is a test’. |SstCommunicationMessage header: header contents: body

The parseHeaderFrom: class method in SstSmtpHeader takes a String or a . Given a stream, it parses the SMTP header and leaves the stream positioned on the first line of the message. For SMTP purposes, SstCommunicationMessage and SstByteMessage can be used interchangeably. The SMTP transport supports sending of mail through MX mail forwarders by redirecting messages through an SMTP smart host, usually a conventional mailing system. You configure it with the following system-wide setting: SstSMTPCommunications smtpSmartHost: ‘

IMAP4 transport The IMAP4 is largely a mail management system. It does not define a mechanism for sending mail but rather can receive mail in a number of forms, including

60

VisualAge Smalltalk: Server Smalltalk Guide

SMTP. As such, the SST IMAP4 transport can receive messages from an IMAP4-compliant server and uses a nested SMTP transport to send messages. An IMAP4 URL has the following format: scheme:/imap4/user:password@host:port

The :port field is optional and defaults to the standard IMAP4 port (143). Both user and host must be specified, and the :password field is required for local endpoints. (It is ignored for remote endpoints.) When sending a message, the remote endpoint’s IMAP URL is translated into an equivalent SMTP URL by dropping the password and port. This assumes that there is an SMTP server running on the same machine as the receiver’s IMAP server. The IMAP4 and SMTP transports use the same communication messages and IMAP messages must also be 8-bit protected. When using transports, keep in mind— v Do not redirect the transport to a personal mailbox! The IMAP4 transport will fetch the first available message from the INBOX and then delete it. This is not compatible behavior for a shared mailbox. v While the SST SMTP and IMAP transports are 8-bit clean internally (although field names in the header should strictly conform to RFC822), RFC822 and IMAP4 are not defined as being 8-bit clean. Hence any data should have their high-bit protected by a mechanism such as uuencoding or base64 encoding. Internally SST uses base64 encoding for tunneling binary messages over SMTP and IMAP. v The imap URL is not compliant with the IMAP URL format defined in RFC2192.

Message tunneling The Free On-Line Dictionary of Computing (FOLDOC) defines tunneling as “Encapsulation of protocol A within protocol B, such that A treats B as though it were a data link layer. Tunnelling is used to get data between administrative domains which use a protocol that is not supported by the internet connecting those domains.” SST Method Invocation supports similar tunneling to allow requests to be sent across transports not normally associated with method invocation; for example, HTTP. The key to this is using two marshalers. First, requests are marshaled as normal (using, for example, an SstSwapperMarshaler). The output of the first marshaler is then embedded into a communications message specific to the transport being used for tunneling (such as HTTP). The first marshaler is referred to as the nested marshaler, or sub-marshaler. SST supports tunneling across HTTP and RFC822 e-mail using either SMTP or IMAP transports. In both cases, the resultant message is specially tagged as a message passed via tunneling so that it is properly unmarshaled by the receiving side. For RFC822 tunneling, the marshaled form of the request must be specially encoded to protect the 8-th bit of each byte. Enabling tunneling is easy: it is only necessary to install the correct nesting marshaler for the particular transport. Consider the following method which creates an invocation configuration for a by-value Swapper-based marshaler.

Chapter 9. Communications

61

invocationConfiguration | configuration | (configuration := SstInvocationConfiguration baseConfiguration) marshaler: SstSwapperMarshaling byValueConfiguration; space: SstSimpleObjectSpace. |configuration

To set this up the configuration for tunneling through HTTP, you need carry out only two steps: 1. Change the endpoints representing the various machines to appropriate HTTP addresses. 2. Change the above method to something like: invocationConfiguration | configuration | (configuration := SstInvocationConfiguration baseConfiguration) marshaler: SstHttpMarshaler defaultConfiguration; space: SstSimpleObjectSpace. configuration marshaler subMarshaler: SstSwapperMarshaling byValueConfiguration. |configuration

Note that tunneling is not restricted to just the SstSwapperMarshaler, or by-value marshaling, it can be used for any marshaler which produces a set of bytes as its output. A working example can be found in SstPingPongLPTunneling class in SstExamples. See the class comment on SstPingPong for more information. Also note that the example could also have used RFC822 tunneling simply by using the SstRfc822Marshaler instead of the SstHttpMarshaler, and changing the addresses to appropriate SMTP/IMAP addresses.

Communication messages To better understand this section, examine the samples SstHttpClientExample and SstHttpServerExample. Communication messages are the basic element of sending and receiving for transports. All data supplied to and received from a transport must be in the form of communication messages. As such, their structure and format is highly transport-dependent. Typically messages are byte-based but transports which interface to system services such as external CORBA ORBs might be based on pointers to C memory. All communication messages support the following logical concepts though in some cases they may not be directly implemented by the transport being used: contents The message contents. header The message header information. sender The sender of the message. Typically only valid for received messages. flushAfterSend A flag to indicate whether the transport should ensure immediate transmission of the entire message. closeAfterSend A flag to indicate whether the transport should attempt to release the

62

VisualAge Smalltalk: Server Smalltalk Guide

resources used to send a message as soon as the message is sent. This typically incorporates a flush operation. The contents and header of a message can be in any format as long as that format is understood by the transport being used. For example, for the HTTP transport, the header slot contains an actual HTTP header object and the contents may be a collection of bytes or a deferred computation such as a Block. It is the transport’s job to convert communication messages into or from the so-called wire format/protocol required by the actual transport mechanism.

Message assemblers To better understand this section, examine the samples SstHttpClientExample and SstHttpServerExample. Message assemblers are pluggable transport elements which define the transport’s wire format and protocol. For example, rather than requiring you to hand build HTTP messages, the HTTP message assembler takes in an abstract description of an HTTP request and converts it to a series of bytes which it then sends using the transport’s mechanisms. Similarly, transports such as SMTP require several interactions between sender and receiver to transmit one logical message. Message assemblers encode this behavior. Assemblers can be used to coordinate with higher-level notions of sending and receiving. For example, the HTTP assembler allows the contents of an outgoing message to be a Block. When the assembler goes to output the contents, rather than writing it to the TCP socket it evaluates the block and supplies a stream as an argument. Using this mechanism, you can send large messages—such as files—efficiently and effect the lazy creation of message content. The basic protocol for message assemblers is outlined below: assembleFrom: input Assembles or retrieves a communication message from @input. This may require some protocol negotiation across the transport mechanism. @input may be streaming, in which case standard stream protocol can be used to send and receive bytes. disassembleReply: message onto: output Disassembles or breaks down @message, a communication message, into a form suitable to sent as a reply onto @output. This may require some protocol negotiation across the transport mechanism. @output may be streaming, in which case standard stream protocol can be used to send and receive bytes. disassembleSend: message onto: output Disassembles or breaks down @message, a communication message, into a form suitable to sent as onto @output. This may require some protocol negotiation across the transport mechanism. @output may be streaming, in which case standard stream protocol can be used to send and receive bytes.

Chapter 9. Communications

63

64

VisualAge Smalltalk: Server Smalltalk Guide

Chapter 10. Method invocation Method invocation is the object analog of Remote Procedure Call (RPC) in traditional systems. As discussed in “Actors” on page 11, it allows normal Smalltalk messages to be sent to objects outside of the current VM and image. SST preserves Smalltalk messaging semantics by implementing method invocation using a synchronous Request → Execute → Reply cycle: a request is sent to some object, the corresponding method is executed and the result replied to the requester. Method invocation is built on top of the communications components, discussed previously, and the marshaling component, which is discussed in “Chapter 11. Marshaling” on page 75. Requests and replies are represented explicitly by SstRequest and SstReply objects. Requests are marshaled into communication messages, and then converted into wire-format protocol by the message assembler and sent to a remote endpoint. The wire-format representation is retrieved at the destination, converted back to a communications message and unmarshaled, giving a Smalltalk request which is then executed. A similar mechanism is used to return the result as replies are really just requests to return a value to the original sender. For many applications, this level of capability is sufficient. In some cases, however, you need to control how and when requests are sent and satisfied, and their results returned. “Chapter 1. Getting started with SST” on page 1 briefly outlines the system components and how they fit together and interact. The fine details are covered in this and subsequent sections. In particular, this section details invocation handlers and dispatchers. The classes and methods directly related to method invocation are contained in the SstMethodInvocation and SstLPMethodInvocation applications.

Requests Within SST, normal Smalltalk message sends and replies are treated as instances of the classes SstRequest and SstReply (subclasses of SstAbstractRequest), respectively. Both requests and replies contain an indication of the message receiver, a selector, and the arguments for the message. Message objects also have an info table, which is used to tag messages with system and application-level information. The info table is much like a dictionary though it is recommended that only simple objects such as immediates or immutables be used as keys. The values may be any object but note that no special steps are taken during their marshaling. That is, if they are mutable, they may be passed as references. SstRequest objects embody a Smalltalk message being sent. In addition to the slots standard receiver, selector, arguments slots, they maintain a replyReceiver. When a request is sent, this field may have one of the following settings which define how the result of the request is handled. nil

Indicates that no reply is required so the sender need not wait.

0

The reply value is required but let the system automatically generate a location to hold the reply when it comes. The sender can wait at this location for the value. (This is the default.)

© Copyright IBM Corp. 1997, 2000

65

Non-zero number Use the reply location identified by the given number as the location to store the reply. The sender can wait at this location for the value. Replies are treated largely as requests to return a value to the sender. That is, they are much the same as requests but are somewhat under-the-hood. They are simply messages sent to the specified reply receiver where the selector is typically sstSetValue: and the single argument is the value being returned.

Invocation handlers To better understand this section, examine the sample SstPingPongByValue. For a request sender, invocation handlers coordinate the marshaling and transfer of the request as well as providing a mechanism for waiting for the result. For request receivers, invocation handlers provide a mechanism for waiting for messages and then coordinate their retrieval, reconstruction, execution and the subsequent replying of the return value as required. Application requirements in this area vary widely so SST partitions the behavior into two separate objects: invocation handlers and dispatchers. Invocation handlers define the details of how messages are moved from one place to another. That is, they manage the dispatchers, marshalers, transports and collections of reply locations. They also manage optional server processes which automatically fetch and process requests and replies. The following protocol controls the autonomous behavior of invocation handlers. makeActive Sets the receiver in active mode where it actively seeks out new work. If you detect that the transport cannot receive messages then ensure that the receiver is not running a server process. makePassive Sets the receiver in passive mode where it does not actively seek out new work. resume Resumes processing of requests if possible. If the receiver is in passive mode then it does nothing. If its endpoint cannot receive messages then it puts the receiver in passive mode. If the receiver is already running then it does nothing. suspend Stops the active processing of incoming messages. Answers true if the receiver was running at the time. Otherwise, answers false. Passive invocation handlers use user processes to fetch and handle requests and replies. Due to multithreading concerns, if you expect concurrent use of a handler, ensure that that handler is active. Making a handler passive usually terminates any server processes associated with the handler. These may be in the middle of processing a user request. Thus, use the makePassive operation carefully. Messages are invoked remotely using the invocation protocol shown below. The endpoint argument specifies the communications destination to which request should be sent. It is assumed that there will be a compatible invocation handler at or near endpoint to take care of processing the request. Note the receiver of request

66

VisualAge Smalltalk: Server Smalltalk Guide

is not endpoint but rather is embedded in request itself (that is, it is a directed message). Replies are returned through a similar mechanism. invoke: request at: endpoint Sends @request to @endpoint for processing and returns the result if one is required. It is assumed that @endpoint represents some remote location. Returns an error if one should occur. reply: value inResponseTo: request Sends @value in reply to @message. If an error occurs, replies an error value to @message’s sender and returns the error from this method. In the event that an error occurred while trying to send the error reply, simply returns an error from this method. If a reply of any sort is actually sent then @message is marked as having been answered. earlyReply: value inResponseTo: request continuation: continuation Sends @value as an early reply to @request. An early reply is defined as a reply done before the method invoked as a result of dispatching @request has returned. @continuation is a zero argument block containing the code which should be executed after @value is replied. If an error occurs, it replies an error value to the origin of @request (its sender) and returns the error from this method. In the event that an error occurs while trying to send the error reply, it simply returns an error from this method. If a reply of any sort is actually sent then @request is marked as having been answered. deferReply Marks the receiver as a deferred request. The value returned from the method processing a deferred request is ignored. The request (self) can be replied to at a later time using the lateReply: protocol. lateReply: value Sends @value in reply to the receiver which has been deferred. If an error occurs, replies an error value to the origin of the receiver (its sender) and returns the error from this method. If an error occurs while trying to send the error reply, returns an error from this method. If a reply of any sort is actually sent then the receiver is marked as having been answered. Normally invocation handlers map incoming requests onto Smalltalk messages which are executed locally. By default the value returned from that Smalltalk message is the value returned to the original sender of remote request. There are three situations which vary from this. The first is if the request was marked as asynchronous using the protocol markAsAsynchronous. Asynchronous messages do not require replies so the return value from the invoked method is simply ignored. Note that senders of asynchronous messages do not wait for replies as none will be coming. The second case is if the handling of the request resulted in an early reply using the protocol described above. In this case, the explicitly mentioned value is returned as the result of the request and the request is marked as answered (using markAsAnswered). Again, the value actually returned from the invoked method is discarded. Note that the DGC does not collect distributed garbage cycles. The third case is, if in the processing of the request, it is marked as deferred (using deferReply:). In this case, the value returned by this method is ignored. You are responsible for maintaining the request itself in some appropriate data structure so that a reply can eventually be sent (using lateReply:). This behavior is useful when Chapter 10. Method invocation

67

a request cannot be answered immediately, but the client should not be resumed until the reply value is available. After deferring the processing of a request, the handling process is free to service other requests for the invocation handler. While a handler’s invoke:at: protocol can be used directly, it is often convenient to have a local representation of a remote invocation handler. SstRemoteInvocationHandlers manage the correspondence between local invocation handlers and remote endpoints. Using this, the protocol for remote method invocation is simplified to: invoke: request Sends @request to the receiver’s % endpoint for processing and returns the result if one is required. It is assumed that @endpoint represents some remote location. Returns an error if one should occur.

Dispatchers In contrast to invocation handlers, which have rather fixed behaviors, dispatchers are pluggable policy objects which describe how messages are sent and processed by an invocation handler. Their major protocol includes the following methods: dispatchIncoming: request Dispatches the incoming @request to its intended receiver according to the policies of the receiver. It is expected that request processing includes sending any required responses. sendEarlyReply: value to: request continuation: continuation Sends @value as an early reply to @request. An early reply is defined as a reply done before the method invoked as a result of dispatching @request has returned. @continuation is a zero argument block containing the code which should be executed after @value is replied. Returns an error if one should occur. sendReply: value to: request Sends @value in reply to @request. If an error occurs, replies an error value to the origin of @request (its sender) and returns the error from this method. In the event that an error occurs while trying to send the error reply, simply returns an error from this method. If a reply of any sort is actually sent then @request is marked as having been answered. sendRequest: request to: endpoint Sends @request to @endpoint for processing and return the result if one is required. It is assumed that @endpoint represents some remote location. Returns an error if one should occur. You are free to build and use new kinds of dispatchers which override these methods to provide different behavior. As useful examples, SST provides a number of different dispatchers: SstImmediateDispatcher Incoming messages, both requests and replies, are processed using the active process (Processor activeProcess). If the invocation handler is active, the handler’s server process is used, otherwise the user’s process is used. This is the default dispatcher. SstThreadedDispatcher A new process is forked to handle each new request. Replies are handled by the active process.

68

VisualAge Smalltalk: Server Smalltalk Guide

SstPooledDispatcher A process is pulled from a pool of available processes and asked to handle the request. Replies are handled by the active process. Pooled dispatchers have a high and low water mark for the pool of processes they use to handle requests. They also support a strictness setting. When in strict mode they guarantee to ensure that the number of processes used will always be between the high and low marks. With non-strict dispatchers, the high and low marks control the number of processes managed. That is, the number of processes may temporarily go above the high mark but when handling of that request is completed, the process used is destroyed. In strict mode it is possible to deadlock the system if there are not enough processes to handle all messages in one dependency chain. Users with highly recursive algorithms should either not use strict mode or ensure that this upper bound is high enough for their use. SstLPDispatcher As part of the mechanisms for supporting Logical Processes, outgoing messages are tagged with an indication of the local process which caused the message to be sent (the active process). Incoming requests are checked for process tags and if found, the dispatcher attempts to process the message on the corresponding process. Replies are handled by the active process. For more information see “Logical process invocation”. Whether or not message senders block waiting for a reply depends on the setting in the sent request’s replyReceiver field. See “Requests” on page 65 for more information. Replies are normally executed on whichever process happened to ask the invocation handler to process the next request. If the handler is active, this process is the handler’s serverProcess. Otherwise, it is some application process.

Logical process invocation To better understand this section, examine the sample SstPingPongLP*. Logical processes are an extension of the standard Smalltalk process whose stack contents are distributed over multiple object spaces. Using a logical process, a message sent by Process A and handled by Process B will appear to be executed on the same logical stack. This effect is achieved by ensuring that whenever a message is sent, the sending Smalltalk process is associated with a logical process (LP) and attaching the LP to the outgoing message. When a message is loaded into a remote object space, the LP tag acts as a remote reference and is looked up in the receiving space’s import table. If no corresponding local logical process exists, one is created and installed in the import table. On creation of a Logical Process, a normal Smalltalk process is also created and attached to the LP. It is this Smalltalk process which is used to execute all messages for that LP. To use logical processes, you must be using by-reference marshaling (see “By-reference marshaling” on page 76) and specify that an SstLPDispatcher (or equivalent) be used. In addition, their handlers must be configured to use reply futures (the replyFutureClass configuration option) which are interruptable (for example, SstInterruptableReplyFuture). Chapter 10. Method invocation

69

Logical processes are discussed extensively in “Logical processes” on page 9; refer to that section for an expanded overview of their characteristics. Logical processes are particularly useful for debugging as they enable a distributed view of execution whereby debugging a program in one object space supports stepping into or over stack frames as they execute in other object spaces. The same Smalltalk process will not necessarily be used to handle two non-causally related sends to the same object space. That is, if A sends M1 to B, B answers and then A sends M2 to B, the Smalltalk process used to handle M2 will not necessarily be the same as that used to handle M1. Much of Smalltalk’s traditional behavior is possible with LP Invocation. In addition to maintaining the distributed stack, logical processes maintain distributed notions of error handlers and UI handlers. The use of asynchronous messages breaks any existing logical process chain. Under LP dispatching rules, if an early return is requested, any remaining execution must be done in a different local process since the logical process has returned to the requestor. This process management is handled automatically by the LP system but you should be careful to ensure that all remaining code is in the continuation supplied to the early return operation.

Error and exception handling Error handlers’ blocks are attached to processes and invoked when an error (such as self error: ...) occurs. This facility is the basis of the exception handling mechanism. As the logical process winds its way across various spaces, it may register error handlers using traditional mechanisms such as the when:do: instance method of Block. When invocation handlers are configured to forward exceptions (see the forwardExceptions configuration option), error handlers are propagated across spaces with the logical process. The propagated handler is installed as the error handler for the process which evaluates the request. When an exception occurs, the active process’ error handler is evaluated. If the handler is remote, a remote message is sent and the error is handled where the error handler was installed. This mechanism transparently implements remote exception handling. Note however that this mechanism only catches exceptions thrown in user code.

UI handlers Logical processes incorporate the concept of a current UI handler. This object provides UI services to the logical process. Currently, the only service available is debugging. That is, when an exception occurs and a debugger is needed, the current UI handler is asked to provide the UI for the debugger. Since the machine signaling the exception may not have UI facilities, this handler may be remote. UI handlers need only support the reportError:resumable:startBP: method. The reporting of errors via the UI handler is controlled using the following API: SstDebuggingSupport reportErrorsThroughUIHandler: true (or false)

This option can also be set using the menu choice SST → Report Errors via UI Handler of the Tools menu.

70

VisualAge Smalltalk: Server Smalltalk Guide

Logical process execution is such that the current, non-nil UI handler is passed with a logical process when messages are sent. That is, if the logical process does not already have a UI handler (it is nil) and the context’s default UI handler (context defaultUIHandler) is not nil, the default handler is attached to the outgoing message. When a message with a UI handler arrives in an object space, the newly arrived handler is made the UI handler for the process which processes the request. When execution of the request is completed, the UI handler is restored to its original setting. Note that you can install your own UI handlers on particular logical processes as they pass through their space. It is good form, however, to ensure that the original value is restored when leaving your domain.

Invocation handler configurations To better understand this section, examine the sample SstPingPong. There are many different execution semantics possible with method invocation. Although the basics of the request/reply operations remain the same, most details can be modified through the SstInvocationConfiguration associated with an invocation handler. Invocation configurations allow the specification of the following options: context The name of the application context in which the handler will execute. If this option is non-nil then the space option must be nil or an error will occur. dispatcher A dispatcher configuration or applicable dispatcher class. If the configured dispatcher is a class, a new instance of that class is used as the dispatcher for the invocation handler. If it is a configuration, the configuration is instantiated to build a dispatcher with the specified behavior. forwardExceptions A boolean stating whether or not exceptions raised in application code are trapped and handled by the associated invocation handler or passed on for normal system handling. The invocation handler will either invoke the error handler associated with the current logical process (if logical process dispatching is being used; see “Logical process invocation” on page 69) or pass the exception back to the relevant request sender. Note that if exceptions are trapped, useful debugging exceptions such as ExHalt will not appear on the machine where they occur. This behavior may effectively hide them from the user but maintains normal Smalltalk exception semantics. handlerClass The class of invocation handler to be used when instantiating the configuration. marshaler The marshaler, marshaler class or marshaler configuration to be used when an invocation handler is instantiated. If the configured marshaler is a class, a new instance of this class is used. If it is a configuration, the configuration is instantiated and the result used as the marshaler.

Chapter 10. Method invocation

71

replyClass The class of object to use when sending a reply (for example, SstReply). replyFutureClass The class of reply future to use internally. The kind of future used affects whether or not processes blocked waiting for message results can be interrupted. Example values are SstInterruptableReplyFuture and SstExplicitFuture. If the logical process model is being used, the replyFutureClass must be interruptable. requestClass The class of object to use when sending a request (for example, SstRequest). restartMode A description of what to do with the invocation handler and its associated components on image startup. See “Invocation handler restart modes” on page 73. space

An object space or the class of object space to use. If the option is a class, a new instance of that class is used. If the value is nil then the local space is found in the specified context (see the context option above) is used. If this option is non-nil then the context option must be nil or an error will occur.

trapExceptions A boolean stating whether or not exceptions raised in SST code while processing are trapped and ignored by the invocation handler or passed on for normal system handling. This option prevents the invocation handler from dying. A warning is displayed on the transcript if an exception is trapped. Note that if exceptions are trapped, useful debugging exceptions (such as, ExHalt) will also be trapped. Also note that if exceptions are trapped, but user exceptions are not forwarded (see forwardExceptions above), then exceptions occurring in user code executed by the server process will also be ignored. Invocation configurations support getter and setter accessors for each of these options in addition to the following API for instantiating invocation handlers: instantiateOn: endpoint Creates and answers a new instance of the receiver’s handlerClass on the local @endpoint. The new handler is set up to behave according to the receiver’s description.

Invocation handler callbacks Invocation handlers and dispatchers also provide the following callbacks related to significant invocation events. SstDispatchReplyCallback Sent when an invocation handler is about to dispatch a received reply to its rightful receiver. The callData is the reply about to be processed. SstDispatchRequestCallback Sent when an invocation handler is about to dispatch a received request to its rightful receiver. The callData is the request about to be processed. SstFirstIncomingCallback Sent when an invocation handler has received a request tagged with data indicating that this is the first request the sender has sent to the receiving object’s space through the endpoint used. This data is typically some

72

VisualAge Smalltalk: Server Smalltalk Guide

information about the sending object space and is stored in the request’s info slots under the key SstFirstContactInfoKey. The callData will contain the request about to be processed. SstFirstOutgoingCallback Sent when an invocation handler has detected a request being sent to a remote object space for the first time through the handler’s endpoint. A typical action would be to tag the outgoing request with information about the local space in the request’s SstFirstContactInfoKey info slot. The callData will contain the request about to be sent. SstSendReplyCallback Sent when an invocation handler is about to send a reply to a remote space. The callData will contain a two-element array where the first element is the reply being sent and the second is the original request to which this is a reply. SstSendRequestCallback Sent when an invocation handler is about to send a request to a remote space. The callData will contain a two-element array where the first element is the request being sent and the second is the endpoint to which it will be sent. The ordering of callbacks associated with peer-to-peer messaging is important to understand. The ordering is a consequence of the interactions between the components of the invocation handler and the object space. The object space callbacks involved are SstExportCallback and SstImportCallback. If a request message is sent involving newly exported objects to a peer for which these objects are also new imports, and this message is the first outgoing message from the sender and the first incoming message to the receiver, the following callbacks are generated in order: 1. At the request sender: SstFirstOutgoingCallback (once), SstSendRequestCallback (once), SstExportCallback (for each new export) 2. At the request receiver: SstImportCallback (for each new import), SstFirstIncomingCallback (once) and SstDispatchRequestCallback (once). If a reply is generated, which also involves new exports and imports, the callback order is as follows: 1. At the reply sender, SstSendReplyCallback (once), SstExportCallback (for each new export) 2. At the reply receiver, SstImportCallback (for each new import), SstDispatchReplyCallback (once).

Invocation handler restart modes Invocation handlers manage operating system resources—such as communications transports—and the active nature of the distributed system, whether or not the handler is running. On startup the handler must ensure that any OS resources are invalidated, and that, if desired, it be restarted in a running state. The following are the valid mode settings for invocation handler restart: SstCleanUpMode Stops the handler such that no information is lost but all related processes and OS resources are deleted. See basicShutDown. SstRemoveMode Runs SstTerminateMode but also removes the handler from the system. Chapter 10. Method invocation

73

SstRestartMode Runs SstCleanUpMode and restarst the handler using the normal startUp procedure. Processes waiting for replies are not killed. SstTerminateMode Runs SstCleanUpMode but also runs basicTerminate on any processes waiting for replies. See clearPendingRepliesWith:. SstTerminateRestartMode Runs SstTerminateMode and restarts the handler using the normal startUp procedure. If you are not using one of the terminate modes, you should ensure that any processes waiting for replies actually get replies. Otherwise, they will block forever. There may be application logic to justify this or you can use clearPendingRepliesWith: explicitly after image startup.

Handler configuration registry The system maintains a registry of invocation handler configurations. The keys in the registry correspond to valid URL schemes. Therefore, the URL myScheme:/tcp/foo.com:8096 indicates that there is a handler conforming to the handler configuration named myScheme running port 8096 of the machine named foo.com. Applications which define their own handler configurations should register them and use the registered name in their URLs to ensure that they communicate only with compatible invocation handlers. The configuration registry is managed by SstInvocationHandler class and is accessed through the following API: configurationFor: url Answers a configuration object which is suited for use on @url or nil if one cannot be found. register: configuration asScheme: scheme Adds the mapping @scheme → @configuration to the scheme mappings. unregisterScheme: scheme Removes the configuration corresponding to @scheme from the receiver’s list of configurations. Returns the configuration removed or nil if none was found. SST provides a number of standard configuration templates. The instance methods to generate them are in the SstInvocationConfiguration class with the name *Configuration. The prefix identifies a particular category of invocation handler. For example, byReferenceConfiguration returns a copy of the default by-reference invocation configuration scheme.

74

VisualAge Smalltalk: Server Smalltalk Guide

Chapter 11. Marshaling The SST marshaling framework supports the conversion of application objects into communication messages and vice versa. That is, the marshalers take in Smalltalk objects (requests) and output messages which a transport can manipulate (an instance of SstCommunicationMessage from “Communication messages” on page 62). Similarly they take in communication messages and output Smalltalk objects (requests). As with most parts of SST, you are free to plug in your own marshaler as long as it conforms to the API specified below. The classes and methods related to marshaling in general are contained in the SstMarshaling application. SST supplies two general purpose message marshalers: one based on the Swapper and the other designed specifically for SST and optimized for its typical use-cases. These marshalers are in the applications SstSwapperMarshaling and SstLightweightMarshaling respectively. The basic message marshaler API is defined as follows in the abstract class SstMessageMarshaler: messageForErrorReplyTo: requestId using: message error: error Builds and returns a communications level message suitable for use in sending a transport level reply. It uses the information and resources provided by @requestId (the ID of the request to which you are replying), @message, and @error (the error object). @message should be an empty communications message of the class indicated by the transport being used to send the reply. This method is intended to be used when you need to build a message and cannot tolerate errors in doing so. @error is typically converted to a string for inclusion in the reply. messageForReply: reply for: request using: message Builds and returns the communications level equivalent of @reply suitable for use in sending a transport level reply. It uses the information and resources provided by @request (the request to which @reply is the reply) and @message. @message should be an empty communications message of the class indicated by the transport being used to send the reply. If an error occurs, return the error. messageForRequest: request for: requestId using: message Builds and returns the communications level equivalent of @request (having ID @requestId) using the resources defined by @message. @message should be an empty communications message of the class indicated by the transport being used to send the reply. If an error occurs, return the error. loadRequestFrom: message Loads and returns the SST request represented by @message. If there is a problem loading the request, it returns a request as defined by either of the following methods on the receiver: replyForRemoteMarshalError:with: Uses if @message is an indication that a remote machine was not able to unmarshal a message. requestForLocalMarshalError:withHeader: Uses if the receiver was not able to understand the contents of @message. © Copyright IBM Corp. 1997, 2000

75

In some applications (such as mixed legacy and Smalltalk) more than one marshaling strategy is required. This requirement is easily implemented by implementing the marshaling methods to first consider which marshaling mechanism is best for a given message and then apply the corresponding marshaler. The exact nature of the different mechanisms and how they are discriminated is application-specific. An example of this is the HTTP marshaler (SstHttpMarshaler) which uses the standard HTTP content-type header field to determine the format of the request’s body. If the request contains a marshaled Smalltalk request then the body of the message is passed to another marshaler and the corresponding request object returned.

By-value marshaling Using a by-value marshaling scheme, all message arguments are passed as deep copies. This strategy is suitable for many server applications where object identity is not important. It has the drawback that message size is typically increased since all objects reachable from the message object are copied and transferred to the remote machine. It can also be an advantage since the message will be executed entirely local to the remote machine since there are no remote references. Whether or not this behavior is desired is specific to particular applications. Message marshalers which support by-value configurations (both of the standard SST marshaler do so) expose standard ones to the you through a class method as specified below: byValueConfiguration Answers a configuration object which represents the by-value configuration for instances of the receiver. All objects marshaled with marshalers instantiated through this configuration will do deep marshaling. The configuration returned by this method should be installed on an invocation handler configuration where it is used to build the relevant structures when the handler is started. If you use by-value marshaling, you must remember that object identity is maintained only within the scope of a single message send. That is, if the first and second arguments of a message are identical at the sender, they will be identical at the receiver. This property is not true if the same object were passed in a subsequent message send.

By-reference marshaling Applications which require object identity to be maintained across Smalltalk images or whose objects are too large to transfer by value should use by-reference marshaling. By-reference marshaling is based on a dynamic replacement of objects with remote references. Remote references are globally unique identifiers of a local object. These remote references are managed by object spaces as described in “Object spaces” on page 83. Message marshalers which support by-reference configurations (both of the standard SST marshalers do so) expose standard ones to you through a class method specified below:

76

VisualAge Smalltalk: Server Smalltalk Guide

byReferenceConfiguration Answers a configuration object which represents the by-reference configuration for instances of the receiver. Objects marshaled with marshalers instantiated through this configuration will be dumped as references unless they are immutable or otherwise specify that they should go as values. Again, the configuration returned by this method should be installed on an invocation handler configuration where it is used to build the relevant structures when the handler is started. Note that in the case of by-reference marshaling, the invocation handler’s space must be configured to handle remote references. By-reference marshaling is more complicated than by-value marshaling in that not all objects can or should be passed as references. For example, objects such as SmallIntegers are “immediate” values and only exist as values. Others are immutable in the sense that the system provides no (or little) API which changes the value of the object, for example, instances of Float. Still other objects, such as Strings and Points, while technically mutable, are immutable in common usage. SST defines a number of classes as immutable by defining a method sstIsImmutable to return true. You are free to define such methods on their classes but should keep in mind the issues raised in the by-value marshaling section. Note also that defining this method changes the marshaling for all instances of the class in which the method is defined as well as all of its subclasses (assuming they do not also override the method). Finer-grained control of by-value/reference marshaling can be had using the marshaling wrappers (see “Marshaling wrappers”). All objects which are mutable are passed by reference. SST can define a default remote reference for an object but allows users to specify their own by overriding the method sstExportObjectIn: in the desired classes. This message is sent to any mutable object found by the marshaler. The result is used as the exported value which is embedded in the message. The single argument is the object space related to the marshaler and in which the receiver is exported. Note that it is your responsibility to ensure that the appropriate exporting operations are carried out in this method. The default (Object) behavior of this method is shown below: sstExportObjectIn: space "Answer either a remote reference object to the receiver in @space or an object to use to identify the receiver in @space. Typically the latter is the space-unique export key but it could be, for example, the master object when exporting a replica." |space export: self

A simple example of varying this is given below. By overriding sstExportObjectIn: in Process you specify that reference to processes be exported as instances of a special “remote” process class (SstRemoteProcess), which is a remote reference having caching capabilities and other optimizations. sstExportObjectIn: space |(SstRemoteProcess export: self in: space) sstPrimeReferenceTo: self; yourself

Marshaling wrappers Marshaling wrappers are used to control the dumping technique used for individual objects during by-reference marshaling. SST provides three wrappers suitable for general use. Chapter 11. Marshaling

77

shallow Ensures that the wrapped object is dumped as a shallow copy. That is, the object is not exported and the objects in its slots are dumped according to their normal dumping rules. This wrapper is equivalent to defining the individual object as immutable. deep

Dumps the wrapped object using the by-value mode to copy the entire object graph starting at the object.

reference Ensures that the wrapped object is dumped as a reference even if it is normally defined as immutable. This wrapper cannot be applied to immediate objects such as Booleans and SmallIntegers. These wrappers are made available through extensions to Object: sstAsDeepValue Answers a deep value marshaling wrapper on the receiver. sstAsReference Answers a by reference marshaling wrapper on the receiver. sstAsShallowValue Answers a shallow value marshaling wrapper on the receiver. Wrappers are typically used for defining the marshaling of message arguments at the point of sending or of the return value at the point of return. For example, suppose anArray is to be passed as the argument in the foo: message to some remoteObject (for example, remoteObject foo: anArray). Normally, arrays are considered mutable and are passed by reference. If you want anArray to go as a shallow copy, simply wrap it in a shallow value wrapper (for example, remoteObject foo: anArray sstAsShallowValue). Wrappers can also be nested. It is important to note that wrappers make no attempt to imitate the objects they wrap. As such, a wrapped object will have a different identity and semantics to the original. It is good practice to only wrap objects when you know that they will be used only in a message send. This practice is especially relevant when nesting wrappers as this requires the modification of the object containing the object being wrapped. If you use value wrappers, also note that objects dumped by value do not maintain identity outside the object subgraph of which they are a part. In contrast to the by-value marshaling behavior where the same object passed as the first and second arguments are identical at the receiver, if both the first and second are wrapped with separate deep or shallow wrappers, they will not be identical at the receiver. Objects within a particular value wrapped subgraph do however maintain identity (assuming they are not further wrapped).

Marshaling with Swapper SST provides both by-value and by-reference marshaling capabilities using the Swapper. Both techniques are implemented by the class SstSwapperMarshaler which coordinates instances of the Swapper’s ObjectLoader and ObjectDumper. The behavior of these objects is controlled by strategies which are programmable.

78

VisualAge Smalltalk: Server Smalltalk Guide

SST by-value marshaling is implemented as a simple, thin wrapper on the Swapper. By-reference marshaling is implemented using more detailed variations of the swapping strategies. Advanced users may be interested to know that by-value marshalers use the standard ObjectLoader and ObjectDumper with no special replacers. You can use the normal the Swapper API to affect the way particular objects, classes and instance variables are marshaled. This is independent of the marshaling framework. The same is true of the by-reference marshaler but more care must be taken in changing the behavior of the replacers and loaders/dumpers. For more detailed information on the Swapper, refer to the IBM Smalltalk User’s Guide.

Advanced Swapper-based marshaling This section is an advanced topic and covers how to build your own marshalers or marshaling schemes. For the most part, you will not need to know about or use these capabilities unless you are optimizing performance or customizing behavior. Loading and dumping strategies define all aspects of SST marshaling with the Swapper. They are much like configurations in that you declaratively define the behavior they require and the strategies coordinate the loader or dumper activities accordingly. For example, when a dumper needs to calculate the object dumping replacement for a particular object, it typically sends dumpingReplacementForReplacer: to the object itself. Sending this method allows objects to play a role in deciding how they are dumped. Unfortunately, there can only be one definition of this method for a particular class. If two systems need to override this method, a fundamental conflict occurs. The Swapper routes all such messages through the strategy. This design gives you a centralize point of control over the messages sent to the objects being marshaled. For example, the standard SST by-reference marshaling strategy uses the method sstBRDumpingReplacementForReplacer: rather than dumpingReplacementForReplacer: to define their dumping behavior. This is programmed by overriding the standard strategy method as shown below: dumpingReplacementFor: anObject for: replacer |anObject sstBRDumpingReplacementForReplacer: replacer

Notice that this method simply redispatches the request but with a new, method selector (sstBR and so on) which is specific to the marshaling scheme. Similar methods defined on strategies are given below. definesClassBasedReplacementFor: aClass Answers true if @aClass defines class-based replacement for its instances. definesInstVarReplacementFor: aClass Answers true if @aClass defines instVar replacement for its instances. definesLoadingReplacementFor: aClass Answers true if @aClass defines a loading replacement for its instances. dumpingReplacementFor: anObject for: replacer Answers the replacement for @anObject when dumping within the scope of

Chapter 11. Marshaling

79

the SST BR marshaling scheme. This is used to replace instances of a given class by another object, perhaps of another class. dumpingReplacementForInstVar: anInteger ofObject: anObject for: replacer Returns a possibly new object that will replace the receiver’s instance variable number @anInteger when dumping within the scope of the SST BR marshaling scheme. This is useful when you want to replace “fields” of a given object by another object. loadingReplacementFor: anObject for: replacer Returns the object that will replace @anObject when loading within the scope of the SST BR marshaling scheme. Note that the BR marshaling scheme is layered on top of the standard the Swapper scheme. You should consider layering your marshaling requirements in this way to avoid conflicts when your systems must be used in concert with others’.

Lightweight marshaling The Swapper is optimized for loading and dumping bulk data. In SST it is often the case that messages contain only a few objects (for example, <100) and are less than 1KB in size. This characterization is particularly true of systems using by-reference marshaling as large data sets are often seen as mutable and so are passed by reference. To take advantage of these properties, SST contains a lightweight marshaler (SstLightweightMarshaler) which does both by-value and by- reference marshaling. The Swapper and lightweight marshalers are largely interchangeable (although their output is not). They can also co-exist. As the name implies, the lightweight marshaler is smaller and faster than Swapper marshaling for most use-cases encountered. Nonetheless, requirements vary from application to application; if one marshaler does not meet your needs, it is likely that the other will.

Advanced lightweight marshaling The following section is intended for advanced developers who are going beyond the default behavior the lightweight marshaler provides. Normally, you will not need to know about or use these capabilities unless you are optimizing performance or customizing behavior. The lightweight marshaler uses much the same infrastructure ideas (e.g., wrappers, strategies) as discussed above. As with the Swapper marshaler, the sending of messages to the objects being marshaled is controlled by a strategy object. The lightweight marshaler uses a custom stream for marshaling objects. The policies for marshaling objects onto this stream are defined for standard base classes. For user-defined objects, specific marshaling behavior can be altered when marshaling these objects onto the stream through the use of the following API on all objects: sstMarshalInstVarAt: index with: marshaler Answers the object to dump when @marshaler is trying to dump the index—the instance variable of the receiver. Typically the result is the object in that slot but you can override this method to filter out slots etc.

80

VisualAge Smalltalk: Server Smalltalk Guide

sstMarshalIterateOnto: stream Iterates over the receiver dumping each of its instance variables to @stream. See also sstMarshalInstVarAt:with: and sstLoadFrom:register:. sstMarshalMaintainIdentity Answers true if the marshaling mechanism must maintain identity for the receiver. Identity is maintained within the scope of the current object set (object graph reachable from the root). sstMarshalReferenceOnly Answers true if the receiver can only be marshaled as a reference. sstMarshalValueOnly Answers true if the receiver can only be marshaled as a (shallow) value. sstReplacementWith: marshaler Answers the object to dump when @marshaler is trying to dump the receiver. Typically, the result is the receiver itself but you can override this method to vary that behavior. Object loading behavior is defined by loaders. Typically, an object’s loader is its class. The default loading behavior is defined in the behavior specified below. You can override this method on particular classes as needed. sstLoadFrom: stream register: flag Loads and returns the next object from @stream according to the loading format defined by the receiver. Typically, the receiver will be a class and will be able to load instances of itself and its subclasses. If @flag is true then ensure that the resultant object is registered with @stream. Registering an object is required to maintain object identity within a particular marshaled object group. It is vital that the resultant be registered before any other sub-objects. As with the Swapper marshaler, the marshaling behavior is controlled by the strategy. By plugging in a by-reference strategy, the lightweight marshaler changes the messages it sends to objects (replace sst with sstBR in the above API list) and dumps mutable objects as references. Note: The behavior of the lightweight marshaler varies slightly from that of the Swapper marshaler in that the Swapper maintains various low-level flags of the objects dumped and loaded (for example, basicHash).

Chapter 11. Marshaling

81

82

VisualAge Smalltalk: Server Smalltalk Guide

Chapter 12. Remote object model The classes and methods related to the remote object model are contained in the SstObjectSpaces and SstProxies applications.

Object spaces Typically in Smalltalk, all objects are local; they live in one running image and are processed by one virtual machine. With the introduction of remote messaging comes the notion of remote objects and the need for an addressing alternative to the standard memory address used by the local virtual machines. Object spaces represent a home for objects. Essentially they manage a namespace and expose the names to objects in other object spaces thus allowing inter-space references. In the simplest case (with SstSimpleObjectSpace) the name assigned is just a simple key such as a number or symbol. Exporting an object is the act of assigning a key to an object. Objects used as export keys must conform to the IuSstExportKey interface, which defines the following protocol: sstIsExportKey Returns true to indicate that the receiver is a valid export key. Note that the receiver must be an immutable object. (See sstImmutable). Objects referenced using this simple key are not globally unique in and of themselves. In combination with an invocation handler, however, they do uniquely specify an object. If used as the receiver of a request, invocation handlers will correctly resolve the key and replace it with the associated object. This sort of export key is typically used in client-server applications. For example, a server would export its services by locally unique keys (such as DatabaseServer or http) and clients construct and send messages to these services specifying the export key as the message receiver. Objects spaces provide the following API for explicitly managing exported objects: export: object Ensures that @object is externally known. If @object is not already exported, automatically generates an export key. Returns the export key used. export: object as: objectId Makes @object externally known as @objectId. Overwrites any existing mapping for @objectId. Returns @object. exportIdFor: object Answers the ID under which @object is exported. Answers nil if @object has not been exported. objectExportedAs: key Returns the object which has been exported using @key in the receiver. If @key is not found, returns nil. objectExportedAs: key ifAbsent: absentHandler Returns the object which has been exported using @key in the receiver. If @key is not found, returns the result of evaluating @absentHandler.

© Copyright IBM Corp. 1997, 2000

83

resolve: key ifAbsent: absentHandler Returns the object exported by the receiver using @key. If @key is not found, returns the result of evaluating @absentHandler. unexportId: key Removes any mapping for @key from the export list of the receiver. Returns the object exported as @key or nil if none exists. unexportObject: object Removes any export mapping with @object as the value. Returns @object or nil if it cannot be found in the receiver. Object handles are a more general exporting mechanism where objects are exported as {object space, object ID} pairs. Assuming that the object space IDs are globally unique (within some application context) and the spaces manage their namespace such that each object has a locally unique name, these pairs are globally unique (within that application context). The object-to-object handle mapping is maintained by the export set of each object space. When an object is passed by reference out of a space, it is replaced in the outgoing message by its globally unique object handle. More sophisticated object spaces also have an import set which maintains a mapping from object handle to local representation (for example, proxy). This ability is essential for maintaining object identity. The same handle passed twice to the same object space will resolve to the same physical object in that space. Object spaces support the following API for managing the collection of imported objects: import: handle as: object Makes the external @object internally known as @handle. Overwrites any existing mapping for @handle. import: handle as: object for: importer Makes the external @object internally known as @handle. Overwrites any existing mapping for @handle. objectImportedAs: key Returns the object which has been imported using @key in the receiver. If @key is not found, returns nil. objectImportedAs: key ifAbsent: absentHandler Returns the object which has been imported using @key in the receiver. If @key is not found, returns the result of evaluating @absentHandler. resolve: key ifAbsent: absentHandler Returns the object imported by the receiver using @key. If @key is not found, returns the result of evaluating @absentHandler. unimportHandle: key Removes any import mapping with @key as the key. Returns the object imported as @key or nil if none exists. unimportObject: object Removes any import mapping with @object as the value. Returns @object or nil if it cannot be found in the receiver.

Space activations Each object space has an activation associated with it. This can be any immutable object, and defaults to nil.

84

VisualAge Smalltalk: Server Smalltalk Guide

When the activation of a marshaled representation of a space (the incoming activation) is different from that of the local representation of the space (the current activation), the SstDifferentSpaceActivationCallback fires. The callback can choose to ignore the difference (the default action if there is no callback), cause the message to fail by returning a marshalling error, or take some other action. For example, suppose the local context has space initiator with activation of 2. An incoming message is received which has initiator’s activation as 3. The difference will be detected and the SstDifferentSpaceActivationCallback callback will fire. The space-activation example provided in the SstExamples application uses the following algorithm in the callback: v If the current activation is not nil, and is either of a different class or is less than the incoming activation, then a marshalling error will be returned. v Otherwise the current representation is invalidated (which will invalidate any remote objects associated with that space), and then install a new representation of the space with the newer incoming activation. The SstDifferentSpaceActivationCallback callback is registered against the local space’s callbacks and is documented in “Space configurations” on page 89.

Remote references Object handles are useful as global identifiers of objects but do not present you with a transparent view of the referenced objects. Methods must be written with an explicit understanding that certain variables and arguments are remote objects and do not implicitly respond to normal protocols. Remote references, on the other hand, transparently forward all received messages to the remote objects indicated by their embedded object handle. You can use exactly the same message sends they would use if you were programming only with local objects. Since remote references are transparent, the issue of object identity is raised. To maintain the view that remote references are just like local objects each remote object is uniquely represented locally by one and only one remote reference object. This correspondence is maintained by the space’s import set. Once an object handle has been imported and a corresponding remote reference created, subsequent imports of the same remote object are replaced with the same local remote reference object—identity is maintained and operations such as == behave as expected. Since remote references are designed to forward all messages, there is little API required. Class methods for SstRemoteReference provided as API are: export: object in: space Answers an instance of the receiver which is the remote representation of @object in @space. @object can be either a import key or an object. If it is an object then its export key is looked up in @space. for: object in: space Builds and returns a new instance of the receiver for the object identified by @object in space @space. The following instance API methods are also provided: sstIn: space Answers a reference to the remote object in @space whose ID is the receiver. @space must be an actual space as opposed to just a space name. Chapter 12. Remote object model

85

sstIn: space context: context Answers a reference to the remote object in @space in @context whose ID is the receiver. If @context is nil then @space must be an actual space. If a real context is provided then @space can be either a space from that context or the name of a space in that context. sstIsRemote Returns true to indicate that the receiver is a reference to a remote object. sstIsValid Returns true if the receiver is a valid reference. That is, that the local representation of the space containing the receiver is still valid. sstSpace Returns the space which contains the object represented by the receiver. Despite their transparency, there are a few places remote references cannot be used. The most significant being as arguments to primitives which either directly access instance variables or the class slot of their arguments. Since remote references are only representations of the actual remote object, they will not have the format (slots and so on) expected by the primitive and the results could well be catastrophic. Do not change the shape of a remote reference while instances of that remote reference exist in the system! Remote references (and other instances of subclasses of nil) should never be put directly in the Smalltalk dictionary or in class or pool variables. While this may appear to work while your distributed system is up and running, various parts of the normal Smalltalk infrastructure scans these objects (Smalltalk compiled methods) and sends them messages such as isClass which are not appropriate for general implementation on remote references.

Managing access to remote references SST provides some infrastructure for managing access to objects in general and remote references in particular. The concept of a naming service is a familiar one, allowing you to associate arbitrary objects with names. File systems are a common example of a naming service, where the objects are files, within a hierarchical structure of named directories. The SST naming service facilities adopt the same API protocol as CORBA’s CosNaming services, using the standard IDL-to-Smalltalk mapping for operations. The benefit of using a naming service in a client-server environment is that only a single object—the naming service itself—needs to be made available by the server. Individual services the server supports are then bound to particular names within the naming service. Clients know either the name of the service in which they are interested or how to navigate the naming service itself. Given some name, the naming service resolves the name and answers the associated object. In SST, a naming service is an instance of SstNamingContext, which contains bindings from instances of SstName to arbitrary objects. Strings are mapped to an instance of SstName using the following protocol: from: value Creates an instance of the receiver from the structured string value. For example, foo/bar.type as an instance of the receiver is interpreted to mean

86

VisualAge Smalltalk: Server Smalltalk Guide

the object bound to a name bar or kind type within the naming context called foo which in turn will be bound within some other naming context. The same protocol is provided by the class method nameFrom: in SstNamingContext. The basic API of SstNamingContext is: bind: name obj: value Binds @value to @name within the receiver. If @value is an instance of the receiver, it will not participate in compound name resolution. If @name is a compound name, each component except the last identifies a naming context which must already exist. bindContext: name nc: value Binds @value to @name within the receiver. @value will participate in compound name resolution. If @name is a compound name, each component except the last identifies a naming context which must already exist. bindNewContext: name Creates a new instance of the receiver and binds it to @name within the receiver. destroy Prevents further participation of the receiver in any actions. There must be no existing bindings within the receiver when this operation is called. list: number bl: bindingListHolder bi: bindingIteratorHolder Reports a collection of at most @number bindings discovered in the receiver. These are placed in @bindingListHolder. If there were more bindings available, creates an SstNameBindingIterator which will iterate through the remaining bindings and place it in @bindingIteratorHolder. newContext Answers an instance of the receiver, not bound to any name. rebind: name obj: value Binds @value to @name within the receiver. If @value is an instance of the receiver, it will not participate in compound name resolution. If @name is a compound name, each component except the last identifies a naming context which must already exist. rebindContext: name nc: value Binds @value to @name within the receiver. @value will participate in compound name resolution. If @name is a compound name, each component except the last identifies a naming context which must already exist. resolve: name Retrieves the object bound to @name in the receiver. If the name is a compound name, each component except the last identifies a naming context which must already exist. unbind: name Removes a binding for @name within the receiver. If @name is a compound name, each component except the last identifies a naming context which must already exist. The list:bl:bi: operation sets the @bindingListHolder object value to collection of SstNameBinding objects, where each object contains both a name and a type, indicating whether the object bound to the name is a naming context or an actual object. The @bindingIteratorHolder object value is set to an instance of Chapter 12. Remote object model

87

SstNameBindingIterator if there are any more bindings left. This object supports API to progressively obtain more name bindings. The following code illustrates creating a naming service within SST, creating a name myNames for another naming service and binding a new naming context to that name in the naming service. Then another name example.txt is created, and a string bound to that name within the naming context myNames. Note that myNames/example.txt is an example of a compound name, where all components but the last are expected to refer to existing naming contexts discovered by navigating through the naming hierarchy of the naming service itself. The naming service is then asked to resolve the name myNames/example.txt, and finally to unbind the binding for that name. The doit returns the example text object previously bound within the naming service. | namingService serviceName name exampleText | namingService := SstNamingContext new. serviceName := SstName from: ‘myNames’. namingService bindNewContext: serviceName. name := SstName from: ‘myNames/example.txt’. namingService bind: name obj: ‘This is an object in myNames’. exampleText := namingService resolve: name. namingService unbind: name. |exampleText

Addressing objects with naming interfaces While you can use the naming service described above directly, SST also provides a mechanism for name manipulation through URLs. This is similar to the mechanisms found in Java RMI and Java JNDI. The general form of a naming URL is the following: namingService://machine/nameToLookup

namingService is replaced with one of rmi, sstName, or cosName, depending on the naming service you want to use. Given a naming URL, you ask the relevant application context for its naming interface object. For example, the following code gives the naming interface objects for RMI, SST, and COS naming services: rmiNaming naming cosNaming

Once you have the naming interface object, you can directly manipulate names and values using the naming URLs and the naming interface API. This API is like that of the naming services. The naming interface determines which naming service, protocols, and operations to use to carry out the desired operation. For example, the following code looks up the name CoolServer in the SST naming service running on the machine foo.com at port 4567: naming resolve: ‘sstName://foo.com/CoolServer’

Read the comments in the API methods of SstRmiNaming, SstNamingInterface, and SstCosNamingInterface for details on the operations available and their required arguments.

88

VisualAge Smalltalk: Server Smalltalk Guide

Space configurations Like most components of SST, objects spaces are configured by specifing the following options: exportSelector The one argument selector to send to an object when it has been determined that it will be exported (see sstExportObjectIn:). This allows the object itself to influence is external/remote representation. exportSize Sets the initial size of the associated space’s export set. firstExportId Specifies the first numeric ID to use when automatically generating export IDs for objects exported from the associated space. handleClass Sets the class of object handle to use when exporting objects. importSize Sets the initial size of the associated space’s import set. raiseExceptions A boolean flag which is true if the invocation handler should raise exceptions when significant errors occur or false if it should simply return error codes. remoteReferenceClass Specifies the default class of remote reference to use when exporting remote references to objects. This option can be overridden for classes of objects by defining methods corresponding to the value set in the exportSelector option. remoteSpaceClass Specifies the class of remote space to use in relation to spaces configured by the receiver. restartMode A description of what to do with the space and its associated components on image startup. See “Object space restart modes” on page 90. spaceClass On instantiation, creates a space of the given class. supportFinalization A boolean flag indicating whether or not the associated space should support finalization of imported objects. If set to true, the spaces will automatically drop imports of remote objects when that remote object is no longer reachable by objects in the local space. The SstFinalizeImportCallback is fired if required. Use the asProxyConfiguration and asFinalizedProxyConfiguration helper methods to mark object space configurations as supporting remote references and the discarding of unneeded remote references, respectively. Space configurations are only valid on instances of SstLocalSpace. All other spaces are not configurable. SstSimpleObjectSpaces support object exporting (using keys from classes such as Number and Symbol which support the IuSstExportKey interface) but not object importing nor do they provide callbacks.

Chapter 12. Remote object model

89

Object space callbacks Object spaces also support a number of callbacks dealing with the importing and exporting of objects. SstAddHandlerCallback Sent when a new handler is added to a local space. The callData is the handler that has just been added. SstDifferentSpaceActivationCallback Sent when an incoming marshaled representation of a space has a different activation from the local representation’s activation. The callData for the callback is a three-element array containing the local representation (from which the current activation can be obtained), the incoming activation and a block. Sending value to the block will cause a marshaling error to be returned to the sender. SstExportCallback Sent when an object is exported for the first time (either explicitly by the developer or automatically by the SST system when messages contain objects not previously exported). The callData for the callback is a two-element array containing the key under which the object was exported and object itself. SstFinalizeImportCallback Sent whenever an imported remote reference object in a local image is about to be collected by the local object space’s normal garbage collector. This callback is only generated if the space supports finalization (i.e., the supportFinalization option is set to true). The callData for the callback is a two-element array containing the handle under which the object was imported and the local remote reference object. SstImportCallback Sent when a new remote reference is imported (either the first time or the first time since it was last finalized). The callData for the callback is a three-element array containing the handle under which the object was imported, the local remote reference object, and the root of the message which contained the newly imported object (or nil if no message was involved). SstRemoveHandlerCallback Sent when an existing handler is removed from a local space. The callData is the handler being removed. SstUnexportCallback Sent when a previously exported object is removed from the export table. The callData for the callback is a two-element array containing the key under which the object was exported and the object itself. SstUnimportCallback Sent when a previously imported object is explicitly removed from the import table (as opposed to just being garbage collected). The callData for the callback is a two-element array containing the handle under which the object was imported and the local remote reference object.

Object space restart modes When a saved image is restarted, something must be done with the objects which were imported and exported at save time. The following are the valid mode settings for object space restart:

90

VisualAge Smalltalk: Server Smalltalk Guide

SstCleanUpMode The object space is cleaned up to ensure it does not interfere with the start up sequence but as much information (for example, imports and exports) as possible is retained. This is the default mode. SstClearMode The object space is cleared out completely using the normal clear operation. All imports and exports are invalidated and deleted. The space is no longer valid. SstRestartMode The space is restarted using the standard startUp operation. All imports and exports are invalidated and deleted. The space remains functional.

Application contexts When you use the remote object invocation model of distributed programming, you manage the SST infrastructure on an end-user application basis using application contexts. Application contexts maintain lists of the machines and spaces related to the developer’s application. Using this, your objects and distributed infrastructure is isolated from outside influence and can be controlled (for example, shutDown) separately. Application contexts adhere to the IuSstStartable interface. Application contexts also support the following API for managing the SST infrastructure: addRemoteSpace: spaceName at: urlList Adds a remote space named @spaceName to the receiver. The space is created so it can be contacted at the URLs given by @urlList. If the space already exists then it is modified to ensure that its location is the machine named @machineName. addSpace: spaceName at: urlList Adds to the receiver a specification for a space named @spaceName. The space’s location is described by @urlList. name

Answers the name of the receiver.

removeSpace: oldSpace Removes space @oldSpace from the receiver’s list of available spaces. Note that requests to remove the receiver’s space (the local space) are ignored. All transient references to objects in @oldSpace are invalidated and @oldSpace’s machine is also removed. setupFor: spaceName using: config Sets up the receiver to run in the object space named @spaceName configured according to @config. This method can only be called once and should be done after all statically known space/machine specifications have been added (see addSpace:*). Once this method has completed the receiver may be started up. Note that further remote spaces can be added using addRemoteSpace:*. spaceFor: id Answers the space registered under the name @id or nil if none. spaceFor: id ifNone: absentHandler Answers the space registered under the name @id. If there is none, answers the result of evaluating @absentHandler with no arguments. spaceHosting: endpoint Answers a remote object space which hosts @endpoint. That is, an object space in which messages sent to @endpoint will be executed. Chapter 12. Remote object model

91

Application contexts also give users access to the managed space components through the following API: space

Answers the space in which the receiver is running.

spaces

Answers a collection of all spaces managed by the receiver.

SST supports the association of a default naming service object with an application context. This naming service can be an instance of SstNamingContext (and its subclasses) or some other mechanism. The relevant SstApplicationContext API is as follows: defaultNamingService Answers the naming service object associated with the receiver. defaultNamingService: value Updates the default naming service object associated with the receiver to be @value. It automatically exports @value as the key SstNamingServiceKey. It answers @value. defaultNamingServiceFor: value Creates a remote reference to the default naming service residing at @value. The default naming service at @value may not exist, or be exported, at the time this operation is performed. You must ensure that this occurs prior to sending any requests to this service. If you provide the receiver’s local space instead, then any local default naming service is returned.

Context restart modes Application contexts provide a way of controlling end-user application specific control over the SST startup sequence. The following modes are valid settings for a context’s restartMode option: SstCleanUpMode Cleans up the context components according to each individual component’s restartMode configuration options. The default. SstClearMode Clears out the whole context using clear. This mode overrides any settings in the configurations of individual components. SstRestartMode Runs SstCleanUpMode then restarts the entire context using startUp.

92

VisualAge Smalltalk: Server Smalltalk Guide

Chapter 13. Server infrastructure Servers and servlets To better understand this section, examine the sample SstHttpServerExample. SST contains support for writing the server side of typical client-server applications. Client-server applications differ from peer-to-peer systems in that they have explicit notions for client and server. That is, there is an object in the server whose role is explicitly and solely to service client requests. SST adopts the Java approach of servlets. A servlet is analogous to applets but for servers as opposed to client applications. The basic architecture consists of a server and a collection of servlets. Clients send requests to the server which dispatches it to one or more servlets. The results of the servlet processing constitute the response to the request. Servlets adhere to a specific (and simple) API and are therefore pluggable—servlets added to a server are started, stopped, and executed by the server. Groups of servlets are organized into hierarchies using invoker servlets whose role is to re-dispatch requests it receives from the server (or other servlets above it in the hierarchy). The SST server facilities allow you to write the Smalltalk equivalent of Java servlets. The Smalltalk API is modeled after that of Java; you should refer to the Java documentation for details of programming idioms and use-case structuring. Some of the method and class names have been changed to better suit Smalltalk conventions but their origins remain recognizable. “Chapter 3. Building server applications” on page 15 discusses the application of these facilities to building an HTTP server. SST and Java servlets do not interoperate nor are they interchangeable. SST provides a Java servlet-like facility for Smalltalk.

Session management To better understand this section, examine the sample SstHttpServerExample. SST is not connection-oriented. It does not inherently supply application programmers with application-level notions of connected-ness. Connection-oriented transports such as TCP provide a sufficient basis of connection for some applications but not all. The HTTP client example explores this in more detail. The number of design requirements and variations prevents us from building in a notion of application connection into the workings of SST. Instead we provide an external, configurable session management facility which you can incorporate into their applications.

© Copyright IBM Corp. 1997, 2000

93

Since connection is a user-defined concept, it is the user who must tell the session manager when a session starts and ends. The session manager simply maintains a set of session data (sessions) for the user. By default, a session has a named collection of arbitrary (user-defined) data. Sessions know their manager and can be opened and closed. Given a set of information (for example, an incoming request), the session manager can resolve the session is it managing. The resolution strategy is defined by the class of session being used. For example, in the HTTP server example, the SstHttpSession resolution method does the following: resolveSessionFor: request using: manager | cookie session httpRequest | "If the request already has a session then return it." (session := request session) notNil ifTrue: [|session]. httpRequest := request arguments first. "Look for the cookie in the requests header and then search the session manager for the corresponding session." cookie := httpRequest header cookieFor: self cookieName. (cookie notNil and: [(session := manager sessionFor: cookie data) notNil]) ifTrue: [ request session: session. |session]. "No cookie found so if you can, auto generate a session and cookie." manager configuration autoGenerateSessions ifFalse: [|nil]. (cookie := SstHttpCookie generateNew) name: self cookieName]. (session := self for: manager) data: cookie; key: cookie data; open: request sender using: request remoteHandler. request header responseHeader at: HttpSetCookieKey add: cookie sstHttpString. manager open: session. request session: session. |session

Given the current request, check to see if it already has a session assigned to it. If not, look in the request’s header and see if there was a cookie supplied by the client. The cookie’s data is used as the session key. If the manager has a session associated with that key, it is returned. At this point all possible avenues of obtaining pre-existing keys have been exhausted so a new session must be allocated if the session manager is configured to do this. Since the session information is all user-defined, the HTTP cookie mechanism is used to generate a new cookie. Again, the cookie’s data is used as the session key. Having created a new cookie, you create and initialize a new session. If an HTTP server generates a cookie for a request which did not have one then the server should tag the request’s response with the generated cookie value. Since the response has not yet been generated, the new cookie information is logged in the session’s pending fields. These will be attached to the response when it is returned. Finally, the session is opened and attached to the current request. During the processing of the request, application code can get access to the session by sending session to the current request. For example: Processor sstCurrentRequest session.

Looking closely at the HTTP session you will note that it maintains a list of connections. These are the open connections related to the session. For example, a browser using frames will have a connection for each frame but all are part of the same session.

94

VisualAge Smalltalk: Server Smalltalk Guide

Chapter 14. Java RMI support To better understand this section, examine the sample SstPingPongRmi. The Java Remote Method Invocation (RMI) messaging model is similar to that of SST in that requests to remote objects are marshaled into bytes and sent across a transport for processing. The sender waits for the result which is returned via a similar mechanism. RMI differs significantly however in the implementation of this model. Below is a summary of the issues most relevant to Java and Smalltalk interoperation: Marshaling RMI uses Java Object Serialization to convert objects to bytes and vice versa. As noted elsewhere in this document, SST uses Swapper or an SST-specific marshaler. These formats are completely incompatible. Communications RMI communications is largely TCP-based. While this presents no particular problem, the use of the TCP connections is specific to RMI. For example, RMI maintains a pool of connections between any two machines. If there are no available (existing or free) connections, a new connection is created. Connections used for a request are marked as in-use for the duration of that send (until the reply and related DGC messages have been exchanged). Standard SST on the other hand uses a more loosely coupled model which requires just one connection between any two hosts. Object model Both Smalltalk and Java are class-based object-oriented languages. Java however contains notions such as interfaces and types. While Smalltalk objects are uniformly self-describing, Java language elements sometimes need the help of a type or interface specification to determine how they should be handled (for example, primitive types). For Smalltalk to interact with Java, this information must be made available in the Smalltalk environment. | | | | | | | | | | | | |

Remote references Given that Java is typed, transparent, generic remote references (in SST) are impossible. Instead, Java uses stubs and skeletons. A stub is a proxy similar to that of SST but is specific to a particular class. It defines all of the remote methods defined by the class’ remote interfaces. These methods in effect trap message sends, marshal the arguments and send a message to the remote object for which the stub is a proxy. The effect is the same, the implementation is different. Skeletons are the server-side version of stubs. In JDK versions prior to 1.2, the skeleton code was class-specific and contained the necessary code to receive requests, unmarshal the arguments and dispatch the message to the proxied object. In later versions of the JDK, class-specific skeletons have been replaced with a generic option and are no longer necessary. The RMI Wizard generates the proper runtime structures based upon the level of JDK you indicate. Distributed GC There are many possible DGC algorithms each with their own merits and short-comings. Java uses a DGC based on the Network Objects work by Birrel, et al, at Digital. SST uses a distributed mark/sweep algorithm

© Copyright IBM Corp. 1997, 2000

95

loosely based on work at University of Tokyo by Kamada, et al. These two algorithms are fundamentally incompatible. SST contains components which enable the interoperation of Java and Smalltalk through Java RMI and for the most part eliminate the limitations imposed by these differences. Users of SST can send to and receive messages from Java systems in a transparent way providing they meet certain requirements. The following sections detail the steps you must take to interoperate with Java RMI. Users keen to see how this works and try it for themselves are encouraged to look at the examples in SstPingPongRmi*.

Java type information Much of the difficulty in Smalltalk and Java interaction stems from the lack of Java type information in Smalltalk. In many cases, SST can dynamically create Smalltalk representations of Java classes. Unfortunately, this is only possible when the Java object will not be sent messages by Smalltalk. It is not possible for Smalltalk to automatically derive the required information from Java. SST provides a simple facility for producing and importing the Java type information required to serialize objects and transmit stubs. This support has two parts: a Java-based type repository (com.ibm.sst.JavaTypeRepository) and a Smalltalk-based type builder. When you use the RMI Wizard Interface, you can also access Java type information from the VisualAge for Java image. See “Setting up the VisualAge for Java Remote Access Tool to API and tool servlet interface” on page 107 and the VisualAge for Java documentation for more information on the RMI Wizard Interface and accessing information from VisualAge for Java.

| | | | |

com.ibm.sst.JavaTypeRepository On the Java side, users specify a set of Java types in which they are interested and a file name to the generateFor (filename, classNames) static method. The repository then produces and outputs a file containing the information required by SST, such as superclass, field names, file types, method specifications, class hash, and so on. This file is then loaded into Smalltalk. The repository can also be run as a stand-alone RMI-based server by running main(). This creates a repository object and installs it in the Naming service running on the host (for example, Naming.rebind (″JavaTypeRepository″, new JavaTypeRepository ()). The class path of the VM running this server should be such that all classes required by clients of the repository (such as the SST applications) are accessible. Once started, type definitions are looked-up by sending lookup(className) to the repository through RMI. This returns a string containing the class definition. For Java 1.2, the Java security manager must grant access to the ports that RMI uses. Otherwise, when you try to bind a remote object to the RMI Registry, an error is returned. An example java.policy file is as follows:

| | | | | | | | | |

grant { permission java.net.SocketPermission "*:1024-65535", "connect,accept"; permission java.net.SocketPermission "*:80", "connect"; permission java.lang.RuntimePermission "accessDeclaredMembers"; };

96

VisualAge Smalltalk: Server Smalltalk Guide

| |

Start Java with the —D option as follows:

| |

For more information, see http://java.sun.com/docs/books/tutorial/rmi/running.html

java -Djava.security.policy=java.policy

SstRmiTools SST provides tools for loading Java class information (the output of com.ibm.sst.JavaTypeRepository) into Smalltalk and creating Java code based on Smalltalk-based Java information. These capabilities are embodied in the SstRmiTypeBuilder. When loading Java class information (as generated by SstRmiTypingRepository) into Smalltalk, the builder stores Java class specifications in the image in VisualAge applications associated with your code and SST itself. As a convenience, the specs are stored in methods on the instance side of the application class. Loading from a definition file is done using the merge API: mergeDefinitionsFrom: filename Merges the Java class definitions from @filename into the receiver. If application is non-nil, the newly loaded definitions are stored in instance methods on the application class. For examples of these methods see the instance methods of SstRmiSupport. The file indicated by @filename should contain Java class descriptions in the form output by the com.ibm.sst.JavaClassRepository.generateFor() method (or the lookup() method of that class). Definitions can also be loaded directly from a remote Java repository using the following API: mergeRemoteDefinitionsFor: names from: server Merges the definitions for the Java classes in @name from the Java type repository @server into the receiver. If application is non-nil, the newly loaded definitions are stored in instance methods on the application class. For examples of these methods, see the instance methods of SstRmiSupport. @server should be a remote reference to the JavaTypeRepository server. Once a set of definitions has been merged and saved on an application, they can be loaded into a repository using the load API: loadDefinitionsFrom: application Loads the Java class definitions from @application. The definitions are found in instance methods on the application class. For examples of these methods see the instance methods of SstRmiSupport.

Java type definitions You will generally not be required to manipulated Java class definitions except in a few cases where it is impossible for the Java repository to calculate the correct information. These situations and the format of the definitions detailed below. The following is an example of a Java type definition as the Smalltalk repository would store it in an application method. | | | |

1 sun_rmi_registry_RegistryImpl 2 |#((#class ‘sun.rmi.registry.RegistryImpl’ ‘java.rmi.server.RemoteServer’ #SstRmiRegistry 4666870661827494597 4905912898345647071 (‘java.rmi.registry.Registry’ ‘java.rmi.Remote’)) Chapter 14. Java RMI support

97

3 4

| | | |

5

((‘bindings’ ‘Ljava.util.Hashtable;’ #bindings #bindings:)) (#bind:to: ‘bind(Ljava.lang.String;Ljava.rmi.Remote;)V’ (‘java.rmi.RemoteException’ ...) 7583982177005850366) ...)

The example illustrates the following: 1. The method selector is derived by replacing all ’.’ in the Java class name with ’_’. Make sure that the Java class is contained in a package. 2. (#class (...)) 3. (()()...) 4. ( (...))

| |

For Java 1.2, if you don’t use the method hash entry, the hash value is generated dynamically. Therefore, if you don’t use the method hash entry, there could be performance considerations. For Java 1.2, the method hash entry is optional. For Java 1.1, the method hash entry is not necessary. 5. More method definitions as required

| | | | |

The Java repository is able to output all information but that in the fields, which include the implementation class, method selectors, and field accessors. By default the elements of the definition are given as ##nil. In the case of the implementation class and method selector, these values must be replaced by you. This is done by editing the relevant files or methods. If a field accessor entry is ##nil, the default accessors derived from the field name (for example, name and name:) are used. You can redefine these to be the selector of your choice. Note that merging a new file from the Java repository into an existing repository or application will preserve the Smalltalk information previously specified. The method entries are only required if the class is not serializable (that is, remote). Serializable objects are copied and, once instantiated in Smalltalk, are normal Smalltalk objects. Do not reorganize the information in the Java class definitions. Java RMI depends on a specific ordering of class members (fields and methods) and the Smalltalk repository maintains the declaration order. The builder can also take minimal Java class and interface descriptions and generate both the SST specifications described above and Java files containing the corresponding Java source. This is done using the generate* builder protocols. For example: SstRmiTypeBuilder new generateClassesAndJavaFor: ‘java.class.name’ interfaces: #(‘interface.1’ ‘interface.2’ ...) methods: #( (‘method1(Ljava.lang.String;J)Z’(‘java.exception.1’ ‘java.exception.2’ ...)) ...)

98

VisualAge Smalltalk: Server Smalltalk Guide

| | | |

Note that there are several other related builder API methods. In addition, the output of the builder is controlled by setting the application, buildDirectoryStructure, stubVersion, and directory attributes. Detailed explanations are provided in the setter method comments.

Examples of Java RMI support To better understand this section, examine the sample SstPingPongRmi examples. SST provides a set of PingPong examples for RMI. The examples are structured such that Ping runs in SST and Pong runs in Java. Communication is through RMI. The SstPingPongRmi* classes are in the SstExamples application. You can find the Java source for Pong in \java. On the Java side you start the example by creating and registering a PingPong factory. This is an object which knows how to create PingPong objects. This is done by running com.ibm.sst.examples.PingPongFactory.main (). This starts the factory on the current host at the default port. The Smalltalk side is run in much the same way as the other examples: SstPingPongRmi setupPing: ‘rmi/:’pinging:nil. [(SstPingPongRmi createPingAndPong: ‘rmi://’) start: 5 with: ‘test’] fork.

where is the host and port of the Naming service on the machine running the Java PingPong factory. is the port of your local (Ping) machine used for the Smalltalk-based RMI support server. There is also an example which demonstrates the integration of Java and Smalltalk exceptions. This example is similar to the Halt example but rather than halting when the count reaches 0, an exception is thrown. This exception is propogated all the way back along the call chain to the originator of the example (Ping) printing things along the way.

Programming with RMI support Configuring and starting RMI support SstApplicationContext provides some methods for manipulating RMI-related objects. rmiRepository Answers the RMI typing repository associated with the receiver. rmiNaming Answers the RMI Naming service associated with the receiver. createRmiNamingServiceAt: url Creates, starts, and answers a context which runs an RMI naming service at the endpoint specified by @url. It is assumed that @url is local to the receiver. If a context/space related to @url already exists, that context is returned (unchanged). createRmiContextNamed: contextName Creates and sets up an instance of the receiver for RMI-based

Chapter 14. Java RMI support

99

communications at ‘rmi://’. The new context is called @contextName and contains a local space whose name is the printString of the endpoint started at ‘rmi://’. createRmiContextNamed: contextName at: location Creates and sets up an instance of the receiver for RMI-based communications at @location. The new context is called @contextName and contains a local space whose name is the printString of @location (or @location itself if it is a string). This space has one handler whose endpoint is at @location. shutDownRmiNamingServiceAt: location Shuts down any RMI naming service running at @location. rmiNaming returns a naming service object which responds to the standard Java naming (java.rmi.Naming) protocols. Creating a naming service (actually a class method) runs a Java-style naming service in your Smalltalk image. This service then is accessible to all hosts running RMI (those running Java or SST’s RMI Support). You can use any available RMI Naming service when using the SST RMI support facilities. Setting up an RMI-enabled application context is very much the same as setting up normal SST contexts. In fact, for RMI it is generally not necessary to define the remote spaces with which you interact. This is done automatically whenever a new space is detected. The major differences are highlighted by the following example code: self context addSpace: #ping on: ‘Ping’ at: #(‘rmi://foo.com:2345’); setupFor: #ping using: SstSpaceConfiguration rmiProxyConfiguration; rmiStartUpWith: self typeRepository

The code specifies a Java type repository and defines a space configuration which uses RMI remote references (rmiProxyConfiguration). This type repository must contain definitions for all the Java types you plan on using in your application. As discussed in “Java type information” on page 96, you can dynamically extend the repository if required. When setting up an RMI-enabled context, keep in mind the following: v RMI-enabled application contexts must be started using rmiStartUpWith: as opposed to startUp. The repository provided can be nil, however. v Do not mix standard SST, IIOP, or RMI-based invocation handlers in the same application context. Doing so will have unknown but generally subtle and hard to debug side-effects. v There can be at most one handler per RMI-enabled application context. The URL specified for the local space contains the host and port at which the RMI-enabled objects will appear to be living to other RMI-based systems. Typically SST does not contain predefined invocation configurations as it is nearly impossible to predict what users will want. In the case of RMI however, there is a reasonably well-defined behavior which satisfies most users. Accordingly, SST provides a standard RMI invocation scheme, named rmi, as well as a transport named rmi. The declaration of these is in the SstRmiSupport class.

100

VisualAge Smalltalk: Server Smalltalk Guide

SST’s RMI support also includes a new kind of URL which supports the format: ‘rmi://host:port/’. This is typically used in conjunction with the Naming service, where is the name on which to operate. |

Using JDK 1.2

| | |

In JDK 1.1, stub classes are assigned a hash value based on characteristics of the remote class, such as its name and the interfaces that it implements. In JDK 1.2, every stub class is assigned a hash value of 2.

| | |

In JDK 1.2, each method is also assigned a hash value based on the signature of that method. Remote calls pass this hash value to identify the correct method to call. Because the stub protocol has changed, the stub generation has also changed.

| |

The new RMIC stub generation program shipped with JDK 1.2 generates three different types of stubs:

| |

JDK 1.1 compliant stubs JDK 1.1 stubs do not contain the method hash values.

| | | |

JDK 1.2 compliant stubs JDK 1.2 stubs contain the method hash values. Also, JDK 1.2 has obsoleted some RMI API and the JDK 1.2 stubs do not reference the obsoleted RMI API.

| | | |

Hybrid stubs that can support both versions The hybrid stubs can act as either JDK 1.1 stubs or JDK 1.2 stubs. The hybrid stubs determine the correct stub protocol based on which version of Java the local VM is running.

| | | | |

In order to use JDK 1.2, you must change the stub protocol version. To use JDK 1.2 with RMI, you must change the security. It is also recommended that you migrate your existing mappings in order to add the method hash value. Smalltalk can generate this method hash value dynamically. However, if it is generated dynamically, there are performance considerations.

| | | | | |

Changing the stub protocol version for JDK 1.2

| | | | |

In order to use the same mappings for JDK 1.1 and JDK 1.2, set the stub mappings to the JDK 1.1 hash value. When marshalling a request, this hash value is used when the stubProtocolVersion of the marshaling configuration is SstRmiStubVersion1. When the stubProtocolVersion of the marshaling configuration is SstRmiVersion2, the stub mapping hash value for JDK 1.1 is ignored and the hash value of 2 is used.

| | | | | | |

Changing the security for JDK 1.2

The SstRmiMarshalingConfiguration now has a new attribute, stubProtocolVersion. The stubProtocolVersion attribute is used when marshalling a request or unmarshalling a request. Set this attribute to either SstRmiConstants::SstRmiStubVersion1, if you are using JDK 1.1, or SstRmiConstants::SstRmiStubVersion2, if you are using JDK 1.2. The default is SstRmiVersion1.

For Java 1.2, the Java security manager must grant access to the ports that RMI uses. Otherwise, when you try to bind a remote object to the RMI Registry, an error is returned. An example java.policy file is as follows: grant { permission java.net.SocketPermission "*:1024-65535", "connect,accept";

Chapter 14. Java RMI support

101

permission java.net.SocketPermission "*:80", "connect"; permission java.lang.RuntimePermission "accessDeclaredMembers"; };

| | | | | |

Start Java with the —D option as follows:

| |

For more information, see http://java.sun.com/docs/books/tutorial/rmi/running.html

| | |

Migrating method mappings to JDK 1.2

| | | | |

The mapping migration utility searches the image for existing JDK 1.1 mappings and gives the user an option to update these to the new JDK 1.2 mapping. Run the migration utility by loading the SstRmiMigration application and executing the following code:

java -Djava.security.policy=java.policy

In order for Smalltalk to use RMI with JDK 1.2, Smalltalk must know the method hash information. If you are using JDK 1.1, the method hash value is ignored.

SstRmiMigration runMigration

Enabling Smalltalk objects

|

Enabling a set of Smalltalk objects for use with SST’s RMI Support depends on how the objects are to be used. All objects, regardless of how they interact with Java must define their corresponding Java class using: sstRmiClassName Answers the name of the Java class corresponding to the class of the receiver (for example, java.lang.String). This is required if the receiver is to be passed to or from Java by value or by reference (using serialization or stubs). The classes named in such methods must be defined in the Java type repository for the current application context. (See “Java type information” on page 96.) Several Smalltalk classes can map to the same Java class but one Java class can only be mapped to one Smalltalk class. Objects which will be passed by value (serialized) must define the following method to answer true. sstIsRmiSerializable Answers true if the receiver is to be considered serializable according to the specification in Java. In general, this means that the object is passed by value rather than by reference. Answering true requires that there be a Java class mapping specified in the relevant JavaTypeRepository and that that mapping have the correct serialization ID and definitions for the object’s slots or types. If an object should be passed as an array it should implement the following method to return true. sstIsArray Answers true if the receiver is to be considered to be an Array according to the specification in Java. In general, this means that the object is passed by value rather than by reference. Serialized objects must also provide either instance variable accessors that correspond to their variable names (for example, a variable named foo must have

102

VisualAge Smalltalk: Server Smalltalk Guide

the accessors foo and foo:) or specify getter and setter selectors in the Java type repository specification as outlined in “Java type information” on page 96. Objects being represented remotely by stubs (passed by reference) must implement the following method to answer true. sstIsRmiRemotable Answers true if the receiver is to be considered to be “remotable” according to the specification in Java. In general this means that the object is passed by reference rather than by value. Answering true requires that there be a Java class mapping specified in the relevant JavaTypeRepository and that that mapping have the correct hash values for the class’ corresponding stub and skeleton. The mapping must also specify any methods which are to be invoked or serviced. Objects passed to SST as stubs (remote references from Smalltalk to Java) are represented in Smalltalk using generic stubs. That is, structurally all stubs look the same. It is only the remote object’s class information and object identifier which varies. For this reason, the Smalltalk type definitions for all remoteable Java types should specify SstRmiGenericStub as their Smalltalk implementation class.

Java client objects A popular use case of SST’s RMI support is to write a server in Smalltalk and clients in Java. This differs from typical Java-only uses of RMI in that there need not be an actual Java class, only a stub. That is, there is no point in having a my.package.Foo Java class corresponding to the Smalltalk Foo class since it will never be instantiated. Unfortunately, the standard way of constructing stubs (for example, my.package.Foo_Stub) is to create the class and then use the RMIC tool to generate the stub and skeleton. (Note that the skeleton is also not needed in the Java client case.) As to SST, you have two options for building the required stubs. The first is to build a dummy my.package.Foo (and attendant interfaces) and use RMIC as normal. The class must have implementations for the methods in its interfaces. These implementations will never be run, since the class will never be instantiated, and so can be empty. This approach is straightforward but leads to a number of extraneous classes (for example, my.package.Foo and my.package.Foo_Skel). The second option is to use the type builder as described above to generate Java stubs in Smalltalk. The builder takes a Java class definition as mentioned above and generates the required interface and stub classes. The advantage of this approach that only those Java classes actually required (the stubs) are generated and the generation can be done from within Smalltalk. However, the disadvantage is that you must manipulate the SST Java type descriptions more directly. Both approaches have the same result: a Java stub class for my.package.Foo is created allowing Smalltalk objects to be referenced remotely from Java clients.

Exceptions SST supports the catching and throwing of Java exceptions using the standard Smalltalk exception mechanism. All Java exceptions are represented in Smalltalk by a subclass of SstRmiThrowable. While there are many different Java exception classes, typically these can be represented by only a small number of Smalltalk classes. For example, the definition for the Java exception java.rmi.ServerError is as follows: Chapter 14. Java RMI support

103

java_rmi_ServerError |#((#class ‘java.rmi.ServerError’ ‘java.rmi.RemoteException’ #SstRmiRemoteException 8455284893909696482 ##nil) ())

Notice that the Smalltalk implementation class is specified as SstRmiRemoteException. This can be done because exceptions are serializable and typical exceptions have no additional slots. Instances of SstRmiThrowable simply remember the Java class of the exception they represent. Java remote exceptions (the only kind you can get using RMI) are caught using Smalltalk’s standard when:do: family of protocols. Exceptions are thrown using an API of the class SstRmiThrowable. The detailed variation should only be used for Java exceptions having a detail slot. kind: className message: message Builds and answers a new instance of the receiver representing a Java exception of class @className with @message as its detailMessage. The answered object can be sent throw to invoke the exception. throw: kind message: message [detail: detail] Throws an exception signalling a Java-style exception of Java class @kind (such as java.io.IOException) with @message as the detailMessage and @detail as the detail of the exception. Such exceptions will be forwarded or returned to Java as instances of @kind. The actual exception thrown is SstRmiConstants::ExSstRmiException. The receiver of these methods must be the implementation class that corresponds to the Java exception class (for example, @kind). This ensures proper serialization of the exception. To ensure that these exceptions are propogated back to any calling RMI system, the invocation handlers in SST must be running with the forwardExceptions configuration option set to true. This is the default setting so typically you can safely ignore this issue.

Limitations Not all conflicts listed at the beginning of this section can be completely overcome. Below is a summary of the remaining restrictions and incompatibilities. DGC

As mentioned, the SST and RMI distributed GC algorithms are radically different, thus incompatible. As a result, SST must take a conservative approach to collecting exported objects. That is, they are not collected. SST ensures that leases for imported objects are kept up to date and that references no longer needed are cleaned. The net effect of this is that your exporting objects must manage their unexporting explicitly; even if the object was implicitly exported. This may seem a bit much to ask, since in a typical client-server environment only the service objects are exported and they become garbage only when the service is shut down. However, this approach is technically correct in that no non-garbage object will ever be incorrectly collected. Note that because SST adheres to RMI’s notion of client behavior with respect to DGC, objects exported by a Java server will be correctly garbage collected.

Type discovery Java is a typed language and Smalltalk is not. To interact with Java, Smalltalk must have access to certain type information. There is some

104

VisualAge Smalltalk: Server Smalltalk Guide

information about this mapping which simply cannot be computed (for example, the mapping between Java classes and Smalltalk classes or Java method signatures and Smalltalk method selectors). You must provide this information. As such, it is not possible to implement a dynamic type discovery mechanism similar to that of CORBA. You must pre-build your Java type repository with the Java types encountered when running your programs. | | | | |

When mapping objects between Java and Smalltalk, you are typically mapping instances. However, it is possible to map a Smalltalk class to an instance of a Java object. SST provides an example of this technique in the SstPingPongRmi example. Notice that the sstRmiClassName method appears on both the class and instance side of SstPingPongRmi example.

Chapter 14. Java RMI support

105

106

VisualAge Smalltalk: Server Smalltalk Guide

|

|

Chapter 15. Using the Java/Smalltalk RMI Mapping Wizard

| | | |

SST provides a wizard to help generate the Smalltalk and Java code necessary for mapping between a Smalltalk class and a Java class for the RMI transport. You can use this wizard to create mappings between a Smalltalk class and a Java class or exception; you can also create Smalltalk mappings for Java interfaces.

| | | |

The RMI wizard can retrieve information from either the JavaTypeRepository, exposed through RMI, or from VisualAge for Java running the servlet interface for RMI wizard. See the VisualAge for Java documentation for more information on the VisualAge Remote Tool Access to Tool API and tool servlets.

| | |

Setting up the VisualAge for Java Remote Access Tool to API and tool servlet interface

| |

The VisualAge for Java Remote Access to Tool API allows you to retrieve Java information from the servlet interface for the RMI wizard.

| | | | | |

To set up the VisualAge for Java Remote Access to Tool API servlet interface, follow these steps: 1. Install VisualAge for Java. 2. Start the VisualAge for Java Workbench.

| | | | | | | | | | | | | | | | | | | | |

3. Select Windows→Options from the menu bar in the VisualAge for Java Workbench window. The Options dialog appears. 4. In the left-hand column of the Options dialog, click Remote Access to Tool API. The Remote Access to Tool API page of the Options dialog appears. 5. Select Start Remote Access to Tool API . 6. Click OK. To prevent Remote Access from starting automatically, deselect the Start Remote Access to Tool API checkbox. 7. In the left-hand column of the Options dialog, click Resources. The Resources page of the Options dialog appears. 8. Click Edit... to add directories to the Workspace class path. Adding directories to your class path allows VisualAge for Java servlet interface to find Java classes in those directories. v Select Add Directories... to add a directory from which you will need to access Java classes. v Click OK. Add all the directories from which you will need to access Java classes. 9. Copy the RmiWizardServlet.class, RmiWizardServletStrings.class, and JavaTypeGenerator.class files from the \vast\java\sstjava.zip file to the following path: IBMVJavaRoot\ide\TOOLS\com-ibm-ivj-toolserver\servlets\com\ibm\sst

where IBMVJavaRoot is the directory where VisualAge for Java is installed. Once the RMIWizardServlet is in the servlets directory, it is available to the Remote Access to Tool API.

© Copyright IBM Corp. 1997, 2000

107

| |

RMI Wizard Java Interface Settings

| | | | | | | |

To select settings for the Java Interface of the RMI Wizard, follow these steps: 1. Select SST→RMI Wizard Java Interface Settings from the menu bar in the System Transcript window. 2. Select either the JavaTypeRepository, exposed through RMI, or from VisualAge for Java running the servlet interface for the RMI wizard. v Select Use the RMI type repository interface to use the JavaTypeRepository. Type either the hostname or the dotted address of your rmiregistry for the server name. The default port number for an rmiregistry is 1099.

| | | | | | | | | |

Note: If you choose this interface, you will not be able to browse for Java types. v Select Use VisualAge for Java interface to use the VisualAge for Java servlet interface. You must have VisualAge for Java installed and running on this machine in order to use this interface. Choose the port number you specified when you started the Remote Access to Tool API. See “Setting up the VisualAge for Java Remote Access Tool to API and tool servlet interface” on page 107 for more information on the Java interface settings.

| |

v Choose Test Connection to test the connection to the interface. v Click OK.

Mapping a Smalltalk class to a Java class To create a mapping between a Smalltalk class and a Java class, follow these steps: 1. Select SST→RMI Class Wizard from the menu bar in the System Transcript window. 2. Specify the required information in the wizard. The pages of the wizard are described below.

| | | | |

Welcome page

|

| | | |

Choose how you would like to build your mapping: v Build a new mapping from scratch. In the Java class name field, specify the name of the Java class. v Work with a mapping from this Smalltalk image. In the Java class name field, you can edit the field directly or select Browse to select from Smalltalk mapping definitions in this Smalltalk image. v Work with information imported from Java. In the Java class name field, you can edit the field directly or select Browse to select from classes in the VisualAge for Java image. You must have the Java interface installed and running in order to use this option.

| |

You may select Registry Settings to set the Java Interface Settings. See “RMI Wizard Java Interface Settings” for more information on the Java interface settings.

| | | | | |

Mapping Information page

|

On the Mapping Information page, specify the basic identifying information about the Smalltalk and Java classes you are mapping to one another. If a mapping already exists for the specified class, the fields show the current values, which you can edit. Specify the following information: v Specify the superclass of the Java class in the What is the superclass of this Java class field. You can either enter a name directly or you can import Java type

| | | | | |

108

VisualAge Smalltalk: Server Smalltalk Guide

| |

information from the Smalltalk image or from the VisualAge for Java image. All Java classes should be contained in a package.

| | | |

to import Java type information from the Java repository of this – Select Smalltalk image. A window appears with a list of Java classes. (See “Java type information” on page 96 for more information about the repository.) Select a class and click OK.

| | | | | |

to import Java type information from the VisualAge for Java servlet – Select interface. A window appears with a list of Java classes. Select a class and click OK. v Specify the name of the Smalltalk class in the What Smalltalk class do you want to use field. You can edit the field directly or select Browse to select from classes in the image.

| |

When you have finished specifying the class information, select Next to continue to the next page.

|

Interface mapping page

| |

Select By Value or By Reference for whether you would like your class to be pass-by-value or pass-by-reference.

| | |

On the Interfaces part of the page, specify the interfaces you want to implement in the Java class. You can only specify interfaces for which Smalltalk mappings exist. For remote classes, you need only specify the remote interfaces.

| |

The left side of list shows all of the interfaces specified for the Java class. To add interfaces to the list, follow these steps:

| |

1. In the left-hand list, select all of the interfaces you want to add. 2. Select Add> to add the selected interfaces to the right-hand list.

| | |

The right side of list shows all of the interfaces for which Smalltalk mappings will be created or for which Smalltalk mappings exist. To remove interfaces from the list, follow these steps:

| |

1. In the right-hand list, select all of the interfaces you want to remove. 2. Select Remove> to remove the selected interfaces to the right-hand list.

| |

If an interface you want to use is not listed, this means that it does not yet have a Smalltalk mapping.

| | | | |

To create a new interface, select New... on the Interfaces page. Type a fully-qualified interface name and click OK. When you have finished mapping the Smalltalk class to a Java class, the RMI Interface wizard will open and you can create a mapping for the interface. See “Mapping a Java interface” on page 112 for more information on creating an interface mapping.

| | |

To import an interface, select Import... on the Interfaces page to import an interface. You must have the VisualAge for Java servlet interface installed and running in order to import interfaces.

| |

When you have finished specifying interfaces, select Next to continue to the next page.

Chapter 15. Using the Java/Smalltalk RMI Mapping Wizard

109

Field mapping page

| | | |

On the Variables page, specify the serialization UID and the instance variables you want to be passed via RMI. The Variables page appears only if the class is serializable (it implements the java.io.Serializable interface).

| | |

To get a serialization UID, ask your compiled Java class for its UID by entering the following from a command line: serialver

|

For example, if your Java class has the name MyClass, enter serialver MyClass.

| |

If you later recompile your serialized Java class, you must update your Smalltalk code with the new UID.

|

To add an instance variable to the list, follow these steps:

| | |

1. Select Add.... A window appears prompting you for details about the instance variable. 2. Specify the variable name, Smalltalk getter and setter methods, and Java type, of the instance variable. Select types.

| |

or

to choose from a list of available Java

|

3. Click OK to add the variable to the list.

| | | |

Once you have added the variable to the list, you can select the fields in the list and select Edit... to edit them. To remove an instance variable from the list, select the variable you want to remove and then select Remove. You can also move the variables up and down in the field list by selecting Move up or Move down.

| |

When you have finished specifying variables, select Next to continue to the next page.

Method mapping page

| | | |

On the Method mapping page, specify the methods of the Java class you are mapping to. This page appears only if the class is remote (it implements the java.rmi.Remote interface).

| |

To add a method to the list, select New. The Method Definition Window appears prompting you for details about the method. Specify the following information:

| |

Smalltalk name The Smalltalk method name.

| |

Java name The Java method name.

| | | |

Return Type The Java type returned by the method. You can enter the type directly in the field or import the Java types from the repository of this Smalltalk image or VisualAge for Java servlet interface.

| | | | |

Input Parameters The types of the parameters passed to the method. To add parameters to the list, follow these steps: 1. Select Add.... A window appears prompting you for the type of the parameter.

110

VisualAge Smalltalk: Server Smalltalk Guide

| | |

2. Enter the parameter name or select or to choose from a list of available Java types imported from the Java Repository of this Smalltalk image or from the VisualAge for Java servlet interface.

|

3. Select OK to add the parameter to the list

|

To remove a parameter from the list, select it and then select Remove.

| | | |

Note: The number of parameters defined for the Java method must equal the number of parameters defined by the corresponding Smalltalk method. If the two methods do not match, an error message appears when you attempt to add the method to the class mapping.

| | | | |

Exceptions The exceptions thrown by the method. To add exceptions to the list, follow these steps: 1. Select Add.... A window appears prompting you for the Java exception that this method can throw.

| | | | | | | | | |

or to choose from a list of available 2. Enter the exception or select exceptions imported from the Java Repository of this Smalltalk image or from the VisualAge for Java servlet interface. If the exception you want is not listed, this means no Smalltalk mapping exists for it. You may enter the exception name and when you have finished mapping the Java class, you will be prompted to map the exception using the RMI Exception Wizard. See “Mapping a Smalltalk class to a Java exception” on page 115 for more information on creating mapping exceptions. 3. When you have finished adding exceptions, select OK.

|

To remove an exception from the list, select it and then select Remove.

| | |

When you have finished editing the method, you can select New to create a new method and repeat the process for additional methods or select Next to continue to the next page.

| | |

If you want to change a method you have already added, follow these steps: 1. Select the method on the Method mapping page. The details of the selected method are shown. 2. Make your changes.

| | |

3. Select another method to edit, select New to create a new method, or select Next to continue to the next page.

|

To remove a method to the list, select the method and select Remove.

| |

If you are finished specifying methods for the class, select Next to continue to the next page.

| | | | | |

Generate Mapping page On the Generate Mapping Definitions page, specify the generation options to generate the Smalltalk code necessary to complete the mapping. This page includes the following fields: v Generate Smalltalk Required mapping information method specifies whether Smalltalk mapping methods will be generated. Chapter 15. Using the Java/Smalltalk RMI Mapping Wizard

111

| | | | | | | | | | | | | | | |

Application specifies the location where the Smalltalk mapping methods will be stored. Select Browse to select from a list of available applications. (The default is to store the mapping methods in the same application as the mapped Smalltalk class.) v Generate SST required methods specifies whether SST mapping methods will be generated. You must select this option in order to complete the mapping operation. Application specifies the location where the SST mapping methods will be stored. Select Browse to select from a list of available applications. (The default is to store the mapping methods in the same application as the mapped SST class.) v Generate Java code – Generate Java code appears if you are using the RMI type repository interface. This option specifies which RMI stub to generate. Path specifies the location where the Java stub file will be stored. Specify a valid location on your system.

| | | |

– Generate Java code to VisualAge for Java workspace appears if you are using the VisualAge for Java interface. This option specifies which RMI stub to generate. This option also exports code directly to the VisualAge for Java image.

| |

This option appears only if the interface is remote (it extends the java.rmi.Remote interface).

| |

JDK 1.1 stub Generates a JDK 1.1 compliant stub.

| |

JDK 1.2 stub Generates a JDK 1.2 compliant stub. Hybrid stub Generates a hybrid stub that is compliant with JDK 1.1 and JDK 1.2. v Generate report of activities to Transcript specifies whether to report activities in the System Transcript window.

| | | | | |

Mapping a Java interface To create a Smalltalk mapping for a Java interface, follow these steps: 1. Select SST→RMI Interface Wizard from the menu bar of the System Transcript. 2. Specify the required information in the wizard. The pages of the wizard are described below.

| | | |

Welcome page

|

| | |

Choose how you would like to build your mapping: v Build a new mapping from scratch. In the Java class name field, specify the name of the Java class. v Work with a mapping from this Smalltalk image. In the Java class name field, you can edit the field directly or select Browse to select from Smalltalk mapping definitions in this Smalltalk image.

| | | |

v Work with information imported from Java. In the Java class name field, you can edit the field directly or select Browse to select from classes in the VisualAge for Java image. You must have the Java interface installed and running in order to use this option.

| | |

112

VisualAge Smalltalk: Server Smalltalk Guide

| | | |

You may select Registry Settings to set the Java Interface Settings. See “RMI Wizard Java Interface Settings” on page 108 for more information on the Java interface settings.

Interface Mapping page

| | |

On the Interface Mapping page, specify the interfaces extended by the interface you are mapping. You can only specify interfaces for which Smalltalk mappings exist. For remote classes, you need only specify the remote interfaces.

| | | |

The left side of list shows all of the interfaces specified for the Java class. To add interfaces to the list, follow these steps: 1. In the left-hand list, select all of the interfaces you want to add. 2. Select Add> to add the selected interfaces to the right-hand list.

| | | | |

The right side of list shows all of the interfaces for which Smalltalk mappings will be created or for which Smalltalk mappings exist. To remove interfaces from the list, follow these steps:

| |

If an interface you want to use is not listed, this means that it does not yet have a Smalltalk mapping.

| | | | |

To create a new interface, select New... on the Interfaces page. Type a fully-qualified interface name and click OK. When you have finished mapping the interface, the RMI Interface wizard will open and you can create a mapping for the interface. See “Mapping a Java interface” on page 112 for more information on creating an interface mapping.

| | |

To import an interface, select Import... on the Interfaces page to import an interface. You must have the VisualAge for Java servlet interface installed and running in order to import interfaces.

| |

When you have finished specifying interfaces, select Next to continue to the next page.

|

1. In the right-hand list, select all of the interfaces you want to remove. 2. Select Remove> to remove the selected interfaces to the right-hand list.

Method Mapping page

| | |

On the Method mapping page, specify the methods of the interface you are mapping. This page appears only if the interface is remote (it extends the java.rmi.Remote interface).

| |

To add a method to the list, select Add. The Method Definition Window appears prompting you for details about the method. Specify the following information:

| |

Java name The Java method name.

| | | |

Return Type The Java type returned by the method. You can enter the type directly in the field or select from a drop-down list showing the available Java types from the repository.

| | |

Input Parameters The types of the parameters passed to the method. To add parameters to the list, follow these steps: Chapter 15. Using the Java/Smalltalk RMI Mapping Wizard

113

| |

1. Select Add.... A window appears prompting you for the type of the parameter.

| | | |

2. Enter the parameter name or select or to choose from a list of available exceptions imported from the Java Repository of this Smalltalk image or from the VisualAge for Java servlet interface. 3. Select OK to add the parameter to the list

|

To remove a parameter from the list, select it and then select Remove.

| | | |

Note: The number of parameters defined for the Java method must equal the number of parameters defined by the corresponding Smalltalk method. If the two methods do not match, an error message appears when you attempt to add the method to the class mapping.

| | | | |

Exceptions The exceptions thrown by the method. To add exceptions to the list, follow these steps: 1. Select Add.... A window appears prompting you for the Java exception that this method can throw.

| | | | | | | | | |

or to choose from a list of 2. Enter the exception name or select available exceptions imported from the Java Repository of this Smalltalk image or from the VisualAge for Java servlet interface. If the exception you want is not listed, this means no Smalltalk mapping exists for it. You may enter the exception name and when you have finished mapping the Java class, you will be prompted to map the exception using the RMI Exception Wizard. See “Mapping a Smalltalk class to a Java exception” on page 115 for more information on creating mapping exceptions. 3. When you have finished adding exceptions, select OK.

|

To remove an exception from the list, select it and then select Remove.

| | |

When you have finished editing the method, you can select New to create a new method and repeat the process for additional methods or select Next to continue to the next page.

| | | | | |

If you want to change a method you have already added, follow these steps: 1. Select the method on the Method mapping page. The details of the selected method are shown. 2. Make your changes. 3. Select another method to edit, select New to create a new method, or select Next to continue to the next page.

|

To remove a method to the list, select the method and select Remove.

| |

If you are finished specifying methods for the class, select Next to continue to the next page.

Generate Mapping Definitions

|

On the Generate Mapping Definitions page, specify the generation options to generate the Smalltalk code necessary to complete the mapping. This page includes the following fields:

| | |

114

VisualAge Smalltalk: Server Smalltalk Guide

| | |

v Generate Smalltalk Required mapping information method specifies whether Smalltalk mapping methods will be generated. You must select this option in order to complete the mapping operation.

| | | | | | | | |

Application specifies the location where the Smalltalk mapping methods will be stored. Select Browse to select from a list of available applications. (The default is to store the mapping methods in the same application as the mapped Smalltalk class.) v Generate Java code – Generate Java code appears if you are using the RMI type repository interface. This option specifies which RMI stub to generate. Path specifies the location where the Java interface file will be stored. Specify a valid location on your system.

| | | |

– Generate Java code to VisualAge for Java workspace appears if you are using the VisualAge for Java interface. This option specifies which RMI stub to generate. This option also exports code directly to the VisualAge for Java image.

| | | |

This option appears only if the interface is remote (it extends the java.rmi.Remote interface). v Generate report of activities to Transcript specifies whether to report activities in the System Transcript window.

| |

When you have finished specifying generation options, select Finish to generate the mapping code and close the wizard.

| | | | | | | | |

Mapping a Smalltalk class to a Java exception To create a mapping between a Smalltalk class and a Java exception, follow these steps: 1. Select SST→RMI Exception Wizard from the menu bar of the System Transcript windows. 2. Specify the required information in the wizard. The pages of the wizard are described below.

Welcome page

| | | |

Choose how you would like to build your mapping: v Build a new mapping from scratch. In the Java class name field, specify the name of the Java class. v Work with a mapping from this Smalltalk image. In the Java class name field, you can edit the field directly or select Browse to select from Smalltalk mapping definitions in this Smalltalk image. v Work with information imported from Java. In the Java class name field, you can edit the field directly or select Browse to select from classes in the VisualAge for Java image. You must have the Java interface installed and running in order to use this option.

| |

Select Registry Settings to set the Java Interface Settings. See “RMI Wizard Java Interface Settings” on page 108 for more information on the Java interface settings.

| | | | | |

| | |

Mapping Information page On the Exception Mapping Information page, specify the basic identifying information about the Smalltalk class and Java exception you are mapping to one Chapter 15. Using the Java/Smalltalk RMI Mapping Wizard

115

| | |

another. If a mapping already exists for the specified class, the fields show the current values, which you can edit. Specify the following information: v Specify the superclass of the Java class in the What is the superclass of this Java

| | | | | |

class field. You can either enter a name directly or browse by selecting or to show available choices from the Java repository in the Smalltalk image or the VisualAge for Java image. All Java classes should be contained in a package. v Specify the name of the Smalltalk class in the What Smalltalk class do you want to use field. You can edit the field directly or select Browse to select from classes in the image.

| |

When you have finished specifying the class information, select Next to continue to the next page.

Field Mapping page

| | | |

On the Variables page, specify the serialization UID and the instance variables you want to be passed via RMI. The Variables page appears only if the class is serializable (it implements the java.io.Serializable interface).

| | |

To get a serialization UID, ask your compiled Java class for its UID by entering the following from a command line: serialver

|

For example, if your Java class has the name MyClass, enter serialver MyClass.

| |

If you later recompile your serialized Java class, you must update your Smalltalk code with the new UID.

| | | |

To add an instance variable to the list, follow these steps: 1. Select Add. A window appears prompting you for details about the instance variable. 2. Specify the variable name, Smalltalk getter and setter methods, and Java type

|

or to choose from a list of available Java of the instance variable. Select types imported from the Java repository of the Smalltalk image or the VisualAge for Java servlet interface. 3. Select OK to add the variable to the list.

| | | |

Once you have added the variable to the list, you can select the fields in the list and select Edit to edit them. To remove an instance variable from the list, select the variable you want to remove and then select Remove. You can also move the variables up and down in the field list by selecting Move up or Move down.

| |

When you have finished specifying variables, select Next to continue to the next page.

| | |

Method Mapping page

| | | |

On the Method Mapping page, specify the methods of the Java class you are mapping to. This page appears only if the class is remote (it implements the java.rmi.Remote interface).

| |

To add a method to the list, select Add. The Method Definition Window appears prompting you for details about the method. Specify the following information:

116

VisualAge Smalltalk: Server Smalltalk Guide

| |

Java method The Java method name.

| |

Smalltalk method The Smalltalk method name.

| | | |

Return Type The Java type returned by the method. You can enter the type directly in the field or select from a drop-down list showing the available Java types from the repository.

| | | | |

Input Parameters The types of the parameters passed to the method. To add parameters to the list, follow these steps: 1. Select Add. A window appears prompting you for the type of the parameter.

|

or to choose from a list of 2. Enter the parameter name or select available Java types imported from the Java Repository of this Smalltalk image or from the VisualAge for Java servlet interface. 3. Select OK to add the parameter to the list

|

To remove a parameter from the list, select it and then select Remove.

| | | |

Note: The number of parameters defined for the Java method must equal the number of parameters defined by the corresponding Smalltalk method. If the two methods do not match, an error message appears when you attempt to add the method to the class mapping.

| | | | |

Exceptions The exceptions thrown by the method. To add exceptions to the list, follow these steps: 1. Select Add. A window appears prompting you for the Java exception that this method can throw.

| | | | | | | | | |

or to choose from a list of 2. Enter the exception name or select available exceptions imported from the Java Repository of this Smalltalk image or from the VisualAge for Java servlet interface . If the exception you want is not listed, this means no Smalltalk mapping exists for it. You may enter the exception name and when you have finished mapping the Java class, you will be prompted to map the exception using the RMI Exception Wizard. See “Mapping a Smalltalk class to a Java exception” on page 115 for more information on creating mapping exceptions. 3. When you have finished adding exceptions, select OK.

|

To remove an exception from the list, select it and then select Remove.

| | |

| | |

When you have finished editing the method, you can select New to create a new method and repeat the process for additional methods or select Next to continue to the next page.

| | | |

If you want to change a method you have already added, follow these steps: 1. Select the method on the Method mapping page. The details of the selected method are shown. 2. Make your changes. Chapter 15. Using the Java/Smalltalk RMI Mapping Wizard

117

| |

3. Select another method to edit, select New to create a new method, or select Next to continue to the next page.

|

To remove a method to the list, select the method and select Remove.

| |

If you are finished specifying methods for the class, select Next to continue to the next page.

Generate Mapping Definitions

| | | | | | | | | | | | | | | | | |

On the Generate Mapping Definitions page, specify generation options before generating the Smalltalk code necessary to complete the mapping. This page includes the following fields:

| |

v Generate report of activities to Transcript specifies whether to report activities in the System Transcript window.

| |

When you have finished specifying generation options, select Finish to generate the mapping code and close the wizard.

v Generate Smalltalk Required Mapping Information Method specifies whether Smalltalk mapping methods will be generated. You must select this option in order to complete the mapping operation.Application specifies the location where the Smalltalk mapping methods will be stored. Select Browse to select from a list of available applications. (The default is to store the mapping methods in the same application as the mapped Smalltalk class.) v Generate SST required methods specifies whether SST mapping methods will be generated. You must select this option in order to complete the mapping operation. Application specifies the location where the SST mapping methods will be stored. Select Browse to select from a list of available applications. (The default is to store the mapping methods in the same application as the mapped SST class.)

118

VisualAge Smalltalk: Server Smalltalk Guide

Chapter 16. CORBA IIOP support To better understand this section, examine the sample SstPingPongIiop. This section describes the IIOP facilities provided by SST. These facilities do not constitute a full CORBA ORB but they support interactions with ORBs. In particular, you can send and receive IIOP messages, construct or parse IORs, handle CORBA exceptions, and load or manipulate IDL definitions from external IDL repositories. SST’s IIOP support conforms where possible to the standard IDL-to-Smalltalk mapping. Any exceptions are documented. SST’s IIOP support does not include: an IDL repository or an IDL parser. SST supports the following versions of major components: v CORBA 2.0 v IOP 1.0 v GIOP 1.0 v IIOP 1.0 You will find this section easier to understand if you are familiar with CORBA terminology and programming conventions, particularly the IDL-to-Smalltalk mappings. This document is not an introduction to programming with CORBA.

IIOP transports IIOP transports are connective transports which support both client and server modes on top of TCP/IP. SST provides a predefined transport configuration scheme called iiop. This configuration is much the same as standard TCP transport configurations except that it specifies that you use an IIOP-specific connection class. You can ignore client-side handling of disconnects where requests are not yet satisfied or you can handle them by resending the request, if allowed, or signaling a COMM_FAILURE exception if not. To obtain this behavior, send iiopHandleDisconnects to an application context on creation. This is done automatically for you in the automated IIOP application context creation methods.

Invoking methods using IIOP Method invocation using IIOP is the same as most other method invocation techniques. IIOP primarily defines the marshaling and transport semantics of method invocation. The OMG has defined a standard IDL-to-Smalltalk selector mapping to which SST conforms. Incoming IIOP requests are unmarshaled, their receiver identified and their operation name converted to a Smalltalk selector. Then the resulting request is forwarded as a normal Smalltalk message. Most of SST request dispatching models (such as Threaded and Pooled) are applicable with IIOP. The one exception is the Logical Process model. In general, IIOP is used in heterogeneous environments involving different programming languages. The LP model depends on having SST running at all points in the system. As such, IIOP and the LP model are incompatible.

© Copyright IBM Corp. 1997, 2000

119

IDL repositories To better understand this section, examine the sample SstPingPongIiop. IDL definitions play a central role in the marshaling of CORBA requests. Typically, a collection of parsed IDL definitions are maintained by an ORB in a repository which is accessed as needed (either statically or dynamically). SST does not, however, provide an IDL repository. Instead, it relies on the existence of an external third-party repository and simply caches locally the information found remotely. When setting up an application context for use with IIOP, you can optionally specify either (or both) the path to a swapped out repository cache and an IOR for an external repository. For example: idlRepository: iorString cache: cache Sets the object reference for the IDL repository to @iorString, an IOR in string form. Sets the location for constructing the repository cache to @cache. @cache should be a file name or a zero argument bolck. If the cache location is a file name, then the file should contain a swapped-out cache file (@cache). The swapped-out cache file is generated by dumping a primed repository cache to disk using the Swapper. SST includes a file (sstidlic.swp) which contains a swapped out repository cache primed with the GIOP, IOP, IIOP, and CORBA modules, together with CosNaming, CosLifeCycle, and CosTransactions. Alternatively, you can specify a block which, when sent value, will generate an appropriate repository cache. If the cache location is not provided then a limited repository cache is supplied by the system. The repository IOR (@iorString) is a string that you can use an argument to the fromString: instance method of SstIor. Thus, it can be the output of CORBA::object_to_string() in the repository’s native environment, the name of a file containing the IOR string, or an HTTP URL indicating the location of a page containing the IOR string. If the IOR is not provided then the definitions available in the primed cache file are the only definitions which will be available to you since there is no external repository in which to find more definitions. If both the IOR and cache path are omitted, the system will still function but only in a limited way. The default IDL-Smalltalk mapping specifies that IDL structures map to instances of Dictionary. In some situations, you might prefer to represent structures by objects outside of the Dictionary hierarchy. SST provides support for this by allowing you to map a repository type ID (for a particular IDL struct definition) to a Smalltalk class. You establish this mapping using the type:matches: method in SstIdlRepository. The specified Smalltalk class must implement setter and getter methods for each of the attributes of the IDL structure definition.

Configurations and starting IIOP To better understand this section, examine the sample SstPingPongIiop. The GIOP marshaler is configured by an SstGiopMarshalerConfiguration. There are a number of configuration options:

120

VisualAge Smalltalk: Server Smalltalk Guide

alwaysCheckLocation In certain circumstances it is expensive to resend large requests and better to send GIOP locate messages before actually sending their request. Setting this option to true enables this behavior in SST. It should be noted that between the receipt of the locate reply and the actual sending of the real request the target may move, requiring you to resend the request. defaultBufferSize Sets the amount of space pre-allocated by the marshaler. You use this option to optimize memory management. endianOutput Controls the endianness of the GIOP marshaler’s output. By default, the GIOP marshaler’s configuration uses the endianness of the host platform. It can be set to big or little endian (SstBigEndian or SstLittleEndian). This option is required as some commercial ORBs use only big or little endian. trapException Traps marshaling exceptions and converts them into CORBA system exceptions when set to true. When set to false, the underlying exception handles the error. This usually results in a walkback in a debugger and can be useful while debugging. When setting up a local space for use with IIOP, the space configuration must use SstGiopRemoteReference for its remoteReferenceClass setting. You can use the instance method giopProxyConfiguration in SstSpaceConfiguration to create and return a suitable space configuration. Additionally, you can use the iiopConfiguration method in SstInvocationConfiguration to get a copy of the default configuration settings for IIOP method invocation. You modify the result of this method, rather than build invocation configurations explicitly. You can modify most of the invocation configuration options. There are, however, two options which must have IIOP-specific settings: marshaler and replyFutureClass. The marshaler option must be set to SstGiopMarshalerConfiguration (for example, SstGiopMarshaler defaultConfiguration) and the replyFutureClass option set to SstGiopReplyFuture. You will rarely need to alter the default settings for IIOP invocation. SST provides a pre-defined invocation configuration scheme called iiop. You can vary the settings for an option in this configuration, but you should always use the SstGiopReplyFuture setting as an SstGiopMarshalerConfiguration. In certain situations, SST needs a configuration scheme while building references to remote CORBA objects. There are cases in which the system knows very little about the machine hosting the remote object (when there is no existing connection to, or space definition for, the machine). In such cases, SST uses information supplied in the application context. In particular, the IIOP infrastructure needs to know the scheme name to use when building a URL to the remote machine. You can specify the default scheme using the SstApplicationContext protocol shown below. If the value is not set then the default of iiop is used. iiopInvocationScheme: value Sets the name of the default invocation scheme to be used when building remote references to CORBA objects within the receiver. If the default IIOP configuration settings are not appropriate in your environment, you can overwrite them in the scheme registry by storing your own IIOP

Chapter 16. CORBA IIOP support

121

invocation configuration. Be careful, however, as all users use this default IIOP scheme if they do not specify an iiopInvocationScheme setting for their application context. See SstPingPongIiop for example configurations.

Helper methods for creating application contexts Instead of hand-constructing application contexts for use with IIOP, you an use one of the helper class methods in SstApplicationContext shown below. The methods must be sent startUp before they can be used. createIiopContextNamed: contextName at: location idlRepository: repository cache: cache Answers an instance of the receiver for IIOP-based communications named @contextName. The context is located at @location, if you want to specify the host:port on which messages will be serviced. You specify the third-party IDL repository IOR in @repository as a file name, an IOR string, or an HTTP URL. And the initial repository cache resides in @cache. createIiopContextNamed: contextName cache: cache Answers an instance of the receiver for IIOP-based communications named @contextName. You specify the third-party IDL repository IOR in @repository as a file name, an IOR string, or an HTTP URL. The initial repository cache resides in @cache. The answer is established at the default URL @‘iiop://’, which allocates an available port automatically.

Contexts for method invocation CORBA permits the specification of operations in IDL with associated contexts. These contexts are essentially collections of string-to-string mappings. Contexts can be nested in a single-inheritance hierarchy so that mappings in a child context can override those in a parent context. SST provides support for these objects through the SstIdlContext class, and operations that implement the CORBAContext protocol. The SstIdlContext class provides the essential facilities available in the CORBA::Context interface. A context object is set initially by— | context | context := SstIdlContext new. "User-specifed operations to set string-to-string mappings go here" Processor activeProcess corbaContext: context

When marshaling an operation to be performed on some object, if the operation requires context information to be transmitted, SST expects to find a context object containing bindings for the given mapping keys. When executing the body of a method for which context information was specified in the IDL definition, you can find the context mappings by finding the context object and then using the lookup operations provided. This context object is found by executing— Processor activeProcess corbaContext.

An example of the use of contexts is given in SstPingPongIiopContext. Note that the CORBA documentation remarks, though use of context information is supported still, its use is deprecated.

122

VisualAge Smalltalk: Server Smalltalk Guide

IIOP marshaling The IIOP marshaling specifications are an instance of the GIOP marshaling specifications, specialized for use with IIOP transports. In particular, the manipulated IORs typically support an IIOP profile, which specifies a TCP/IP address. Those aspects of IIOP marshaling that are independent of IIOP are contained in SstGiopMarshaling. This includes the type codes and Common Data Representation (CDR) streams. The IIOP-specific aspects are contained in SstIiopSupport. In general, since a CORBA object is of a particular type (specified by an interface in the IDL repository), every operation that can be performed on the object is well-typed. As such, the type of each parameter and the result type of the operation is known. This information is used in the marshaling and unmarshaling of requests and replies. IDL allows parameters to be specified as in, out, or inout parameters. Since standard Smalltalk semantics allow for only a single operation result (reply object), out and inout parameters must be passed such that they can be destructively modified and thus their values implicitly returned. The Smalltalk language binding specifies that this be done by wrapping parameters in a CORBAParameter object. The parameter wrapper holds the current parameter value and responds to value and value:. SST fully supports this and, on method invocation, any out or inout parameters are automatically wrapped (if not already wrapped). You can manually wrap parameters using asCORBAParameter, which is supported by all objects. Marshaling of most objects proceeds directly according to the type specification for the operation being performed. Before each object is marshaled, it is sent the sstGiopMarshalingValue: method. This operation allows the object to declare an alternative representation of itself to be marshaled. For example, IDL struct types are required to be instances of Dictionary. However, if a user object knows that it is to be marshaled as an IDL struct, it can create a Dictionary instance of itself. At present, there is no mechanism to automatically create the required user class object from an object defined to be an IDL struct. In certain circumstances, however, it is impossible for SST to automatically determine how an object should be marshaled. For example, when marshaling an IDL any value, the type of the object is unknown. In order to manage these situations, SST requires that the method sstIdlTypeId be defined for all objects that may be passed as parameters or return values. The method should answer the repository ID of the interface to which the object conforms in the IDL repository specified for the context. When an object is marshaled, it is converted into an IOR with an IIOP profile, such that the typeId field of the IOR is set to the object’s sstIdlTypeId value. This conversion is performed by the sstAsIorInContext: method. Most unmarshaling proceeds directly according to the IDL-to-Smalltalk mapping definition and the type specification for the operation performed. However, IORs are converted automatically into instances of SstGiopRemoteReference, with an associated SstIor instance, to allow for seamless integration with SST’s normal mechanisms for method invocation.

Chapter 16. CORBA IIOP support

123

Remote object model IORs The notion of a remote object in CORBA is represented by an Interoperable Object Reference (IOR). An IOR contains type information and a sequence of tagged profiles. SST currently supports only IIOP so all IORs must have an IIOP profile which contains the TCP/IP address of the object’s server location. While standard IDL-to-Smalltalk mapping represents IORs as dictionaries, SST provides IOR objects which respond to Dictionary protocol as well as several helper methods. SstIor objects can be created from object references in string form, using the following protocol: fromString: value Converts an IOR in string form into an SstIor according to the CORBA conversion specifications for ORB::string_to_object. @value indicates the IOR in the form of the output of CORBA::object_to_string() in the repository’s native environment, the name of a file containing such a string, or an HTTP URL indicating the location of a page containing the IOR string. When acting as an object server, it is often necessary to create SstIor objects to represent some other object residing locally. SstIor’s can be created explicitly by you, or automatically created by the marshaler if a normal object is encountered when marshaling a request using sstAsIorInContext. The protocols for explicit creation of an SstIor are as follows: for: anObject context: context Answers a Smalltalk form of an ::IOP::IOR, representing @anObject with no type information. for: anObject context: context key: exportKey Answers a Smalltalk form of an ::IOP::IOR, representing @anObject. Type information is not given. The key used in exporting @anObject is @exportKey. for:: anObject type: typeId context: context Answers a Smalltalk form of an ::IOP::IOR, representing @anObject with whatever type information is provided by @typeId. To determine an appropriate object key for @anObject, @context is used to find a local space. If the context is not capable of exporting an object, an exception is thrown. for: anObject type: typeId context: context key: exportKey Answers a Smalltalk form of an ::IOP::IOR, representing @anObject with whatever type information is provided by @typeId. The key used in exporting @anObject is @exportKey. If the context is not capable of exporting an object, an exception is thrown. nullIor Answers a Smalltalk form of an ::IOP::IOR, representing a null object reference. When interacting with an ORB from a particular vendor running on a particular machine, you might want to forge an IOR directly rather than use a naming service or a common file system. Note that this is not a safe or approved mechanism for general CORBA interactions and relies on vendor-specific details of how they construct their object keys in IORs. If you really require this facility, the following API in the SstIor class might help:

124

VisualAge Smalltalk: Server Smalltalk Guide

at: location key: key typeId: typeId Answers an instance of the receiver with the type ID information set to @typeId. The profile information for the answer is contructed from the @location information identifying the machine location and the @key information specifying the object’s unique ID at that location.

Remote references GIOP remote references present you with a transparent view of the referenced CORBA objects. GIOP remote references transparently forward all received messages to the remote objects indicated by their embedded SstIor object. You can use exactly the same message sends you would use if you were programming with local objects or with some other SST by-reference invocation architecture. Remote references are automatically created and managed by SST. The following instance API method is provided in addition to the usual remote reference methods inherited from SstRemoteReference: sstInterfaceDef Ensures the interface definition has been cached locally in the context’s IDL repository cache. You can create GIOP remote references explicitly from an SstIor object. The operation that does this takes the following form: remoteReferenceInContext: context Creates a remote reference to the object identified by the receiver. The remote reference searches for spaces in @context. The type ID information associated with an IOR may be empty or only partially accurate. In certain circumstances, you might want to perform operations on an object that are not currently known to be supported from the limited type information available. In other systems and language bindings, this is supported by operations to narrow the type information—effectively a form of safe type casting. SST provides support for a similar action with the following API method on SstGiopRemoteReference instances. sstCast: typeId Attempts to make the type information of the receiver more specific by establishing whether the receiver is also of type @typeId. Answers true if the operation succeeds, false otherwise. For example, if the current type information says that the receiver is of type Foo, and @typeId is Bar, and Bar inherits from Foo, then update the type information of the receiver so that it knows it is a Bar. Since CORBA supports multiple inheritance of interfaces, GIOP remote references might have more than one type ID associated with them at any one time. Where possible, the most specific type ID information is used when marshaling object references.

CORBA object services SST provides the Naming service CORBA object service.

Naming Service The general naming service provided by SST conforms to the specifications for the naming service facilities within CORBA. Chapter 16. CORBA IIOP support

125

The API for CORBA’s CosNaming module is thus reflected in the SST implementation of its generic naming service. However, in order to generate appropriate CORBA exceptions under error conditions, each of the various classes in the SstNamingService application is subclassed in the SstCosNaming application. You must therefore specify an instance of SstCosNamingContext when setting the default naming service. Similarly, creating names is done using the from: method on SstCosName, not SstName. In all other respects, the SST CosNaming facilities mimic those of the general naming service facilities in SST. (See “Managing access to remote references” on page 86.) The following code illustrates creating a CORBA-compliant CosNamingService facility within SST. This example is almost identical to the example given earlier in “Managing access to remote references” on page 86; however, the class names must use the SstCos prefix to support CORBA exceptions being generated. | namingService serviceName name exampleText| namingService := SstCosNamingContext new. serviceName := SstCosName from: ‘myNames’. namingService bindNewContext: serviceName. name := SstCosName from: ‘myNames/example.txt’. namingService bind: name obj: ‘This is an object in myNames’. exampleText := namingService resolve: name. namingService unbind: name. |exampleText

Comprehensive specification of CORBA’s naming service is available in the CORBAServices document from the OMG. An example of the use of the naming service is given in SstPingPongIiopNamingService. The defaultNamingServiceFor: protocol in SstApplicationContext does not generate an IOR for a naming service object on a CORBA Orb. IORs must be obtained in some other fashion, and made available within SST. Typically, this involves using the fromString: API protocol on SstIor.

Other information on CORBA IIOP support Repository cache operations In general, SST seamlessly loads local representations of IDL interface definitions when required. However, in some circumstances, you might want to pre-load the cache with particular interface and module definitions. There are three mechanisms for doing this, defined as SstIdlRepository class methods: buildOn: original into: destination with: elements from: repository Creates a new instance of the receiver based on @original with the new containers whose repository IDs in @repository are given in @elements. The resulting cache is dumped out to @destination. For example, to create a cache pre-loaded with the ping-pong IDL which has been loaded into a third-party interface repository whose IOR is in the file ifr.ior, you use this method as follows: SstIdlRepository buildOn: ‘sstidlic.swp’ into: ‘sstpingpong.swp’ with: #(#‘IDL:PingPong:1.0’) from: ‘ifr.ior’

126

VisualAge Smalltalk: Server Smalltalk Guide

Note that to use this cache, your IIOP application context must be established to use it with the idlRepository:cache: instance method of SstApplicationContext. If you have existing examples which use an alternative cache name, you can change the name of the destination cache to match your examples. loadCacheWith: containers context: context Attempts to download the contents of each container specified in the collection of repository IDs in @containers. The remote repository is found in the usual way from @context. The definitions are loaded into the context’s IDL repository cache. load: cache with: containers context: context Attempts to download the contents of each container specified in the collection of repository IDs in @containers. The remote repository is found in the usual way from @context. The definitions are loaded into @cache. In particular, you might want to use definitions for the CORBA module which differ from those supplied the Swapper file sstidlic.swp. This is done by first creating a minimal cache and then priming it with the modules desired as the following example demonstrates: | context cache | context := SstApplicationContext contextNamed: ‘’. cache := SstIdlRepository minimal. SstIdlRepository load: cache with: (Array with: #‘IDL:omg.org/CORBA:1.0’) context: context. |cache

When starting with a minimal cache, you must always download at least the CORBA module. If the CORBA interface respository you are using does not provide access to the CORBA module definitions, you should make a copy of the Swapper file sstidlic.swp, set the context’s repository cache location to the new file name, and use it as the cache to load with the loadCacheWith: context: operation instead. Once the cache is primed, the Swapper can then be used as per normal to dump the new cache to a file for future use. The IOP, GIOP, and IIOP modules are always pre-loaded into every cache since SST relies on their exact definitions. These definitions cannot be overwritten.

Constants Because SST is not an ORB, the standard IDL-to-Smalltalk mapping is not appropriate. To access values that should appear in the CORBAConstants global dictionary, you can either interrogate the repository directly or use the local cache. The protocol on the local cache is corbaConstants, which returns a keyed collection corresponding to the IDL-to-Smalltalk mapping specifications. Naturally, this will only include those values which have been cached locally.

Exceptions SST fully supports the CORBA Smalltalk binding specification for exceptions. Smalltalk exceptions and the IDL exceptions are mapped according to the CORBAExceptionEvent and CORBAExceptionValue protocols. The CORBAExceptionEvent protocol is implemented by SstIdlExceptionDef (namely

Chapter 16. CORBA IIOP support

127

corbaHandle and corbaRaise*), and the CORBAExceptionValue protocol is defined on Signal (namely corbaExceptionValue). These are fully integrated with the Smalltalk exception handling mechanism.

Unions Unions are supported in SST only with the explicit binding mapping. This is required so that marshaling can select the appropriate discriminator type when there are possibilities of non-determinism in dynamically deciding the IDL type of a Smalltalk object. The explicit binding is supported by the SstIdlUnion class, which supports the CORBAUnion protocol.

Named value lookups You can use one of three methods in SstApplicationContext to obtain local copies of CORBA objects. They work only if you are using an IIOP application context with a repository cache which is valid. The methods include the following: constantNamed: value Answers the constant value associated with the fully qualified name @value of an IDL constant definition. corbaConstants Answers the constants from the interface repository cache, where these objects are associated with keys which are their absolute names within the interface repository. The objects responding to CORBAExceptionEvent protocol are also present in the answer. exceptionNamed: value Answers the object that responds to CORBAExceptionEvent protocol corresponding to the fully qualified name @value of an IDL exception.

Extensions to Kernel The following classes that contain extensions to Kernel might be of use to you: v “SstSharedQueue” v “SstPool” v “SstWorkerManager” on page 129 v “SstRegistry and SstDualRegistry” on page 129 v “SstDate” on page 130 v “SstCron” on page 130

SstSharedQueue Shared queues are synchronized queues, useful for passing objects between concurrent processes. They support standard queue protocol (add:, remove, and so on).

SstPool Pools are a resource-management aid. A pool is configured with high and low watermarks and creation and destruction blocks. Objects ask a pool for one of its managed resources, and return the resource when finished. The pool creates and destroys resources as required. If set to strict the pool will strictly adhere to its configured watermarks, causing the request for the next available resource to return nil. Otherwise the pool allocates new resources as necessary, discarding surplus resources when returned. The creation block takes no arguments and should answer a resource; the destruction block takes a resource as an argument and should dispose of it.

| |

128

VisualAge Smalltalk: Server Smalltalk Guide

SstPool conforms to the IuSstStartable interface and thus you must explictly start and stop it. Its operations are the following: | |

next

Answers a resouce. If no resources are available and the pool is strict, then answers nil.

return: Returns a resource to the pool. size

Answers the number of known resources.

SstWorkerManager Worker-managers are similar to pools, but manage dispatching units of work. Managers maintain a list of worker processes for executing arbitrary blocks. A worker-manager has similar high and low watermarks, controlling the number of workers. If set to strict then blocks will be queued until a worker becomes available, otherwise a worker will be created as needed. SstWorkerManager conforms to the IuSstStartable interface and thus you must explictly start and stop it. Its operations are the following: dispatch: Causes a block to be dispatched to a worker. If no workers are available, the block is queued to be executed when one becomes available. workerName Answers the name template given to worker processes. workerName: Sets the name template given to worker processes. A ‘%1’ is replaced with the process’ ID. workerPriority Answers the priority assigned to new worker processes. workerPriority: Sets the priority assigned to new worker processes.

SstRegistry and SstDualRegistry Registries are a form of . Registries maintain dual mappings between a key and object, also known as a bijection: a key maps to one object, and each object is mapped to by only one key. Thus an object can be looked up to find its unique key. Registries also allow artibtrary objects to be “added”, allocating new keys as necessary and preserving existing mappings for objects already added. SstDualRegistry are more efficient for situations requiring frequent key lookup given its object. Registries are created giving a keyClass and objectClass, which should adhere to . The objectClass is used to map keys to their objects while the keyClass is used to map objects to their keys. The choice of these classes is very important to preserve the bijections maintained by the registry; the wrong choice of class will dramatically affect the behavior of the registry. These classes are usually either a LookupTable/Dictionary or an IdentityDictionary. A rule of thumb for choosing the appropriate class is as follows: if the destination object (the object used as the value of the class) supports equivalence, then the class must be an IdentityDictionary. For example, if the keys of a registry are Symbols (which do not support equivalence) and the objects are Strings, then the keyClass must be an IdentityDictionary and the objectClass can be a LookupTable. Consider if the registry was asked to map ‘foo’ to foo and ‘foo’ copy to bar. Since String supports equivalence, then ‘foo’ and ‘foo’ copy will be equivalent. And if Chapter 16. CORBA IIOP support

129

the keyClass (used to map the objects to their respective key) isn’t identity-based, then ‘foo’ and ‘foo’ copy will map to same symbol and thus not preserving bijections. Thus, the keyClass must be an IdentityDictionary. But since Symbol does not support equivalence, the objectClass (mapping keys to their object) can be a LookupTable. If this confuses you, then a safe heuristic is: if both the keys and objects support equivalence, then use LookupTable. Otherwise use IdentityDictionary. Registries mostly adhere to protocol and provides some additional protocol for determining reverse mappings.

SstDate SstDate represents a moment in time, a combination of Smalltalk’s Date and Time. SstDate supports a subset of Date and Time creation protocol, and most of their normal protocol. SstDate has two possible representations. A relative date represents the time as a number of seconds since an epoch, an arbitrarily chosen fixed moment in time. As a result, only the local representation of the time changes with the local timezone, while the actual moment in time remains the same. For example, while 19:00 in Sydney may be 05:00 in Ottawa, it is only the local representation of the moment that is different: the actual moment in time is the same. An absolute date, on the other hand, represents time in local time. Thus, 19:00 remains 19:00 even if the local timezone shifts to daylight savings. This is the traditional representation of Smalltalk’s Date and Time. A date can also be rooted to a particular timezone. SstDate’s printString gives the date in the standard internet format as defined by RFC1123. There is protocol to determine whether a date is absolute or relative, and to answer a converted representation, and to answer the number of seconds/milliseconds from several popular epochs. Because Smalltalk does not have any inherent concept of the local timezone, SST provides a workaround with the class method sstMinutesFromUTC: in Date. This method is given the number of minutes that the local timezone is from UTC; if ahead, the number should be positive, if behind UTC, then negative. The current offset can be queried with the class method sstMinutesFromUTC in Date. This mechanism does not adjust for daylight-savings and the like. If unset, then it is assumed that the system is in UTC.

SstCron SstCron is a Smalltalk equivalent of Unix cron(1). SstCron allows automatic, repetitve scheduling of events, such as on the first of the month, or every Sunday, or every 5 seconds, or every 5 seconds when the first of the month is a Sunday. It also supports scheduling events to be run at a given moment such as 3:05 p.m. on Jan 1, 2004. A cron entry (SstCronEntry) has a block (the unit of work), and a set of scheduling time constraints on months, days, days of the week, hours, minutes, and seconds, which are all relative to the local time zone. These constraints can have three possible types of values: nil

130

The constraint is true for any possible value (the default).

VisualAge Smalltalk: Server Smalltalk Guide

collection true for any values in the collection integer Shortcut for all multiples of the integer An entry is considered ready-to-run when all of its constraints are met. Entries are scheduled by adding a cron entry to the SstCron object (obtained with SstCron default) with add:, and stopped by removing the entry with remove:. Entries are automatically requeued to run at the next time satisfying its constraints. The entry is requeued only after it has finished executing. Thus an entry registered to execute every second taking takes five seconds to run will only be run every five seconds; there will not be multiple simulaneous executions. It’s easiest to show how to use SstCron with some examples: "Primitive clock on the Transcript’s title bar, updating every 5 seconds. Inspecting the entry will show %seconds was expanded to (0 5 10 15 20 25 30 35 40 45 50 55) In Smalltalk terms this is (0 to: 59 by: 5). So specifying a single number really means: (minValue to: maxValue by: number)." SstCron default add: (SstCronEntry new workBlock: [Transcript shell title: SstDate now printString]; seconds: 5; yourself) "Run a backup every Sunday at midnight. Note that midnight (00:00:00) is regarded to be morning. Also note that it’s important to specify the hours, minutes and seconds: otherwise they default to nil which means match every possible value. So without them explicitly specified you’d be running this event repeatedly all day! We don’t set the month or day cause we want them to always match." SstCron default add: (SstCronEntry new workBlock: ["perform backup"]; daysOfWeek: #(1); hours: #(0); minutes: #(0); seconds: #(0); yourself) "Run this on the first Monday of the month. There can only be one day from the 1st to the 7th that’s a Sunday." SstCron default add: (SstCronEntry new workBlock: [foo]; days: (1 to: 7); daysOfWeek: #(2); hours: #(0); minutes: #(0); seconds: #(0); yourself) "This should be obvious" SstCron default add: (SstCronEntry at: (SstDate newYear: 2000 monthIndex: 1 day: 1 hours: 0 minutes: 0 seconds: 0 milliseconds: 0) do: [Transcript shell title: ‘Happy New Year!’])

Chapter 16. CORBA IIOP support

131

Known limitations The CORBA IIOP support has some limitations: v LOCATION_FORWARD replies to asynchronous messages (i.e., OP_ONEWAY) will fail as the current system does not generate reply futures, and thus the original request is not stashed anywhere to be re-dispatched on receipt of the FORWARD reply. v LOCATION_FORWARD and sstUpdateLocation (LOCATE_REQUEST/REPLY) messages may result in destructive modification of the original remote reference and loss of the IOR. It is not clear from CORBA 2.1 Standard, Section 12.6 Object Location whether it should be the client-side SST responsibility to maintain the original IOR and space information through successive forwardings after connection closures. If it is, this is not done currently. You should hold onto original IOR strings or the SstIor object so they can revert to an original. v Implicit binding for IDL union types is not supported by SST. The explicit binding (with classes conforming to the CORBAUnion protocol) must be used. v Marshaling of IDL any values is currently limited for some of the base types. At present, only the most generic type information is supported. For example, an object that might be represented as an IDL short is always marshaled as an IDL long.

132

VisualAge Smalltalk: Server Smalltalk Guide

Chapter 17. Exceptions When dealing with higher-level abstractions, such as object spaces and remote object models, passing error objects becomes unmanageable. SST defines five exceptions to deal with these broad cases. The parent-child relationship is as follows: (ExAll) ExSstFatalError (ExError) ExSstInvocationError ExSstNonFatalError ExSstSetupError ExSstUnknownException These exceptions are raised in different situations, and have different meanings. Each will have a string describing the cause of the exception as the first element of the arguments to the signal. Any further arguments may contain objects related to the error. The exceptions are as follows: ExSstFatalError Raised when a situation occurs that cannot be handled or fixed in any way by the SST system. It is usually raised from extremely low levels within the system.It indicates that the system has become unstable, and results may be suspect. This exception is a child of ExAll, so that it will not be caught by normal exception handlers. This exception may occur in Communications activities. ExSstInvocationError Raised by spaces when a message invocation returns an SstError. It is raised only if the space’s configuration has raiseExceptions set to true. This exception will only occur when dealing with object spaces. ExSstNonFatalError Indicates that some error condition occurred that affected the current operation, although the overall system integrity remains unaffected. This usually occurs if some internals are incorrectly adjusted, such as wrongly setting the logical process on requests. ExSstSetupError Raised only during system start up. It indicates that the system description is either flawed, or some resource is not available. For example, a space which was setup as the local space does not match the actual local machine. This exception may occur in Communications activities. ExSstUnknownException Thrown when processing remote exceptions, as described in “Logical process invocation” on page 69. Non-system exceptions destined for remote spaces are converted to an ExSstUnknownException.

*.ini file processing VisualAge Smalltalk Server for AS/400 does not support *.ini file processing

© Copyright IBM Corp. 1997, 2000

133

134

VisualAge Smalltalk: Server Smalltalk Guide

Index A

I

P

activations 84 actors 11 application context getting local copies of CORBA objects 128 application contexts 3, 8, 91 creating 122 AS/400 no support for .ini file processing 133

IdSstLwMarshalable 80 IdSstRestartable 47 IIOP transports 119 ini file processing 133 inspectors 31 Internet e-mail 40 invocation handlers 17, 66 callbacks 72 configurations 71, 74 restart modes 73 IORs 124 IuSstConfiguration 49 IuSstStartable 17, 47

packaging RMI applications 41 pools 128 proxy 6

B building server applications 15 by-reference marshaling 76 by-value marshaling 76

C com.ibm.sst.JavaTypeRepository 96 communication messages 62 configurations 16 connective transports 55 CORBA IIOP limitations 132 object services 125 CORBA IIOP support for SST 119 creating SST application contexts 122

D debugging 31 dispatchers 68 distributed applications viii, 25 debugging 32 garbage collection 37, 38

E email transports 60 email using SST 40 endpoints 51 error handling 70 exception handling 70 exceptions for SST 133 export sets 8 extensions to Kernel 128

G GIOP remote references 125

H HTTP 27 © Copyright IBM Corp. 1997, 2000

J Java 1.2 security 96 Java Remote Method Invocation (RMI) 95 JDK 1.2 migration 102

K Kernel extensions 128

L lightweight marshaling 80 local copies of CORBA objects 128 local endpoints 52 logical processes 9, 69 lookups for named values 128

M marshaling wrappers 77 message assemblers 63 tunneling 61 method invocation 65 migration JDK 1.2 102 MQ transports 59 multithreading and multiprocessing 10

N named value lookups 128 naming through URLs 88

O object spaces 3, 8, 83 callbacks 90 restart modes 90

R registries 129 remote object invocation 5 procedure call 5 Remote Access to Tool API tool servlet interface 107 VisualAge for Java 107 remote endpoints 52 remote object model 83, 124 remote references 6, 85 RMI Class Wizard 108 RMI Exception Wizard 115 RMI Interface Wizard 112 RMI support for SST 99 RMI Wizard servlet interface settings 108

S serialization UID 110, 116 shared queues 128 SMTP/Internet e-mail 40 space activations 84 space configurations 89 SST building server applications 15 concepts 5 CORBA IIOP support 119 debugging 31 distributed applications 25 examples 20, 23 exceptions 133 getting started 1 HTTP 27 introduction viii invocation handlers 26 multithreading and multiprocessing 10 naming through URLs 88 remote adminisatration 34 remote references and proxies 6 RMI support 99 sending e-mail 40 SST menu 31 SstAbstractRequest 65 SstActors 11 SstApplicationContext 3, 17, 91, 120, 122 getting local copies of CORBA objects 128 SstBigEndian 121 SstCommunicationMessage 62 SstConfiguration 16

135

SstCosNaming 125 SstCosNamingInterface 88 SstCron 130 SstDate 130 SstDispatcher 68 SstDualRegistry 129 SstDumpingStrategy 79 SstEndpoint 51 SstGiopMarshaler 121 SstGiopMarshalerConfiguration 121 SstGiopMarshaling 119, 123 SstGiopRemoteReference 121, 125 SstHttpClientExample 25, 51, 62 SstHttpServerExample 26, 62, 93 SstHttpUrl 52 SstIdlContext 122 SstIdlRepository 120, 126 SstIdlSupport 119 SstIiopConfiguration 119 SstIiopConnection 119 SstIiopSupport 119, 123 SstImap4Communications 60 SstInterfaces 15 SstInvocationConfiguration 71, 74, 120, 121 SstInvocationHandler 66 SstIor 124 SstLightweightBRMarshaling 76, 80 SstLightweightBRStrategy 80 SstLightweightMarshaler 76 SstLightweightMarshaling 80 SstLittleEndian 121 SstLoadingStrategy 79 SstLogicalProcess 9 SstLPMethodInvocation 69 SstMarshalingWrapper 77 SstMessageAssembler 63 SstMQTransport 59 SstNamingInterface 88 SstNamingService 86, 125

136

SstObjectSpace 3, 8, 83 SstPackagingInstructions 42 SstPingPong 20, 23 SstPingPongByReference 19, 28, 49 SstPingPongByValue 17, 66 SstPingPongIiop 119, 120 SstPingPongIiopContext 122 SstPingPongIiopNamingService 125 SstPingPongLP* 69 SstPingPongLPDgc 37 SstPingPongLPHalt 32 SstPingPongNamingService 86 SstPingPongRmi 95, 99 SstPool 128 SstProxies 6, 85 SstRegistry 129 SstRemoteInvocationHandler 66 SstRemoteReference 85 SstRmiNaming 88 SstRmiSupport 95 SstRmiTools 97 SstRmiTypingRepository 96 SstServerSupport 93 SstSessionManagement 5, 93 SstSharedQueue 128 SstSimpleObjectSpace 8, 83 SstSMTPCommunications 40, 60 SstSpaceConfiguration 17, 89, 121 SstSwapperBRMarshaling 76, 78 SstSwapperMarshaler 76 SstSwapperMarshaling 78 SstTcpTransport 56, 119 SstToolsSupport 31 SstTransactions 12 SstTransactors 12 SstTransport 54 SstTransportConfiguration 54 SstUIHandler 70 SstUrl 3, 52 SstWorkerManager 129

VisualAge Smalltalk: Server Smalltalk Guide

Swapper-based marshaling 78 symbolic references 7 system objects 32

T TCP transports 56 tool servlet interface VisualAge for Java 107 transactional code 12 object 13 transactions 12 transactors 13 transient remote references 7 transports 54 configuration registry 55 configurations 54 connective 55 email 60 IIOP 119 MQ 59 TCP 56 tunneling 61

U UI handlers 70 URL 3

V VisualAge for Java 96 servlet interface 107

W worker-managers 129

VA-Server-55.pdf

modifications until otherwise indicated in new editions. ... Object Technology International Inc. is a subsidiary of the IBM Corporation. ..... VA-Server-55.pdf.

646KB Sizes 20 Downloads 248 Views

Recommend Documents

No documents