@c $Id: concepts.tim,v 1.20 1996/05/17 21:44:52 janssen Exp $
@setfilename ilu-concepts.info
@settitle ILU Concepts
@ifclear largerdoc
@setfilename ilu-concepts.info
@titlepage
@title ILU Concepts
@author Bill Janssen @code{<janssen@@parc.xerox.com>}
@author Mike Spreitzer @code{<spreitzer.parc@@xerox.com>}
@sp
@today{}
@sp
Copyright @copyright{} 1993 Xerox Corporation@*
All Rights Reserved.
@end titlepage
@ifinfo
@node Top, ,(dir),(dir)
@top ILU Concepts
@end ifinfo
@end ifclear

@section What ILU Does

@system{ILU} is primarily about interfaces between units of program
structure; we call these units @dfn{modules}.
The notion is that each module enscapsulates some logical part
of a program, that has high `cohesiveness' internally, and low `coupling' to
other parts of the program.  @system{ILU} provides
you with a way of writing down an object-oriented @dfn{interface} to the module;
that is, a set of object types and other types, constants, and exceptions that another
module would use to communicate with it.  This interface can then be processed
by various @system{ILU} tools to implement that communication.

@system{ILU} allows many different binding relationships between modules.
The modules can be parts of one program instance, all written in the same language;
they can be parts written in different languages, sharing runtime
support in one memory image; they can be parts running in different
program instances on different machines (on different sides of the planet).
A module could even be a distributed system implemented by many program instances
on many machines.  A particular module might be part of several
different program instances at the same time.  @system{ILU} does all the translating
and communicating necessary to use all these kinds of modules in a single program.
It optimizes calls across module
interfaces to involve only as much mechanism as necessary for the
calling and called modules to interact.  In particular, when the two
modules are in the same memory image and use the same data
representations, the calls are direct local procedure calls --- no stubs
or other RPC mechanisms are involved.  The notion of a `module' should
not be confused with the independent concept of a @dfn{program instance};
by which we mean the combination of code and data running in one memory
image.  A UNIX process is (modulo the possibilities introduced by the
ability, in some UNIX sytems, to share memory between processes) an
example of a program instance.

Because @system{ILU} standardizes many of the issues involved in
providing proper inter-module independence, such as memory management
and error detection and recovery strategies, it can be used to
build language-independent @dfn{class libraries}, collections of
re-usable object definitions and implementations.
Because one of the design goals of @system{ILU} was to use existing
standards for various pieces, rather than inventing anything new,
@system{ILU} can be used to implement @system{ONC RPC} or @system{Xerox Courier}
services, or clients for existing @system{ONC RPC} or @system{Xerox Courier}
services.  @system{ILU} also includes an implementation of the
Object Management Group's @system{CORBA} Internet Inter-Orb Protocol (@dfn{IIOP}),
and can be used to write @system{CORBA} services or clients, as well.

@section How ILU Works

The approach used by @system{ILU} is one common to standard RPC systems such
as Sun's ONC RPC, Xerox's Courier, and most implementations of OMG's CORBA.
An interface is described once in some `language-neutral' interface specification language.
Types and exceptions are described; exported functionality is specified by defining @dfn{methods} on object types.
Tools are then run against the interface description to produce @dfn{stubs}
for particular programming languages; these stubs can bind to, call, and be called from stubs
generated from the same interface description for a different
programming language.
The stub code is then linked with the application code, some language-specific
code containing any necessary @system{ILU} support for that programming language,
and the @dfn{ILU kernel library}, which is code written in @language{ANSI C}.
The following diagram illustrates the process:

@picture two-ilu-modules.idraw

Several modules may be linked together, for a standalone use.
@system{ILU} stubs are generated in such a way that
applications which link a caller and callee written in the same
language directly together suffer
no calling overhead.  This makes @system{ILU} useful for defining
interfaces between modules even in programs that do not use RPC.

Different modules of the program may be written in different programming languages.
These can either be linked together in the same address space, if the runtimes
of the different languages allow that, or they
can be used to make separate network servers and clients.  In the case of
a network service, the memory layout for the program would be something like

@picture ilu-addr-space.idraw

@section Core ILU Concepts

@subsection Objects

@system{ILU} is @dfn{object-oriented}.  By this, we mean that
object types serve as the primary encapsulation mechanism in @system{ILU}.
All functionality is exported from a module as methods that can be
invoked on an instance of some object type, rather than as simple
procedures.  The object instance provides
the context within which methods are executed.  The object type system provides
subtyping (`inheritance' of interfaces (@system{ILU} does not address object implementation)), to aid in structuring of interfaces.

With respect to a particular @system{ILU} object instance,
a module is called the @dfn{server}
@cindex server
if it implements the methods of that object, or a @dfn{client}
@cindex client
if it calls, but does not implement, the methods of that object.  One
module can thus be a client of one object, and the server of another.
An @system{ILU} object can be passed as a parameter to or result of a
method call, and can be (in) the parameter to an exception.  An object
may be passed from its server to a client, from a client to its server,
or between two clients, in any of the above three kinds of position.
Unlike some RPC systems, there can be multiple @system{ILU} objects of
the same type, even on one machine, even within one program instance.

For a given @system{ILU} object, there will, in general, be multiple @dfn{language-specific objects};
each is an ``object'' in one of the
programming languages used in the system.  One language-specific object,
designated the @dfn{true object},
@cindex true object
actually provides the implementation of the @system{ILU} object; it is
thus part of the server module.  The true object's methods are written
by the programmer, not generated by @system{ILU}.  The other
language-specific objects are @dfn{surrogate objects};
@cindex surrogate object
their methods are actually RPC stubs (generated by @system{ILU}) that
call on the true object.  A surrogate object is used by a client module
when the server module is in a different program instance or uses
different data representations.

@subsubsection Subtyping (interface inheritance)

The object model specified here provides for multiple interface inheritance.  It is
intended that the subtype provide all the methods described by its
supertypes, plus possibly other methods described directly in the subtype
description.  It is expected that in languages which support
multiple-inheritance object models,
that an @system{ILU} inheritance tree
will be reflected in the language-specific inheritance tree.  In a single-inheritance language, an @system{ILU}-specific multiple-(interface-)inheritance object system must be embedded.

@subsubsection Subtype Relationships

In the @system{ILU} type system, the only subtyping questions that arise
are between two object types.  This is because @system{ILU} employs only
those OOP features common to all languages supported.

Subtyping in @system{ILU} is based on structure and name;
we include the names in the structure, and thus need only talk about
structure.  An object type declaration of
the form defined later constructs a structure of the form

@display
(OBJTYPE
     SINGLETON: @metavar{singleton-protocol-info}
     OPTIONAL: @type{Boolean}
     COLLECTIBLE: @type{Boolean}
     AUTHENTICATION: @metavar{authentication-type}
     SUPERTYPES: @metavar{supertype-structure, ...}
     METHODS: @metavar{method-structure, ...}
     LEVEL-BRANDS: (@metavar{interface-name}, @metavar{interface-brand},
                @metavar{type-name}, @metavar{type-brand}))
@end display

Structure A is a subtype of structure B iff either (1) A and B are equal
structures, or (2) one member of A's @metavar{supertype-structure}s
is a subtype of B.

Note that the level-brands include the interface name and (optional)
brand, as well as the name and (optional) brand of the type being
declared.  Thus, two declarations of subtypes of the same type
normally create distinct subtypes, because they would declare types of
different names, or in interfaces with different names.  When the
interface name and the type name are the same, this does not cause a
distinction, although other structural differences might.  If the
programmer wants to indicate that there's a semantic distinction, even
though it doesn't otherwise show up in the structure, s/he can use
different interface brands and/or different type brands.
These distinctions can be made between
declarations in different files, or between successive versions of a
declaration in a file that's been edited.

@subsubsection Singleton Object Types

Many existing RPC protocols and servers do not have the notion of
multiple instances of a type co-existing at the same server, so cannot
use the instance discrimination information passed in @system{ILU}
procedure calls.  To support the use of these protocols and servers, we
introduce the notion of a @dfn{singleton}
@cindex singleton
object type, of which there is only one instance (of each singleton
type) at a kernel server.  Note that because a single address space may
support multiple kernel servers, this means that in a single address
space, there may be multiple instances of the same singleton type.  When
a method is being called on an instance of a singleton type, no instance
discrimination information is passed.  Singleton types may not be
subclassed.

@subsubsection Instantiation

To use (e.g., call the methods of) an @system{ILU} object, a client must
first obtain a language-specific object for that @system{ILU} object.
This can be done in one of two ways: (1) the client can call on a
language-specific object of a different @system{ILU} object to return
the object in question (or receive the object in a call made on the
client, or in the parameter of an exception caught and handled by the
client); or (2) certain standard facilities can be used to acquire a
language-specific object given either addressing or naming information
about the @system{ILU} object.  The addressing information is called a @dfn{string binding handle}
@cindex string binding handle (SBH)
(SBH), and the @system{ILU} runtime library includes a procedure to
acquire a language-specific object given a string binding handle for an
@system{ILU} object (in strongly-typed languages, this procedure is
typed to return an object of the base type common to all @system{ILU}
objects in that language).

Every creation of a surrogate instance
implies communication with the server module,
and binding of the surrogate instance to the true instance.
@system{ILU} may attempt to perform this communication when it is actually
necessary, rather than immediately on surrogate instance creation.

The process of creating an instance may bootstrapped via a @dfn{name
service}, such as the PARC Name-and-Maintenance-Server
(@program{NMS}), which allows servers to register instances on a
net-wide basis.  A server registers a mapping from naming information to
a string binding handle.  The client-side stubs for an interface include
a procedure that takes naming information, looks up the corresponding
string binding handle in the name service, and calls the above-mentioned
library routine to map the SBH to a language-specific object.
Alternatively, a client can do those steps itself, using an @system{ILU}
runtime library procedure to acquire a language-specific object for the
name service.

@subsubsection String Binding Handle

In @system{ILU}, there is a string-based representation for a reference to an object.
That representation consists of a single string, called a @dfn{string binding handle}.  @system{ILU} uses string binding handles when marshalling object references for RPC.
@system{ILU} also allows applications to interconvert between objects and string binding handles.
This is necessary when dealing with name services, and useful in other circumstances.

A string binding handle contains several different
pieces of information:

@itemize @bullet

@item The @dfn{server ID}, a string which identifies
the particular @dfn{kernel server} that the object belongs to;
any program can separate its objects into one or more groups, each
group associated with a different kernel server.  Two objects
from the same kernel server are called @dfn{sibling} objects.
@item The @dfn{instance handle}, identifies which object on the
particular kernel server is being specified.
@item The @dfn{most specific type ID} (also called the @dfn{MSTID}),
a type fingerprint for the most specific type of the object.
@item The @dfn{contact info}, specifies one or more of the ways
by which a client of the object can communicate with it.

@end itemize

@noindent
The server ID, instance handle, and MSTID may each contain any ASCII character other than NUL.
They are composed into the string binding handle according the the IETF rules for URLs, but the precise
form of the URL is not specified here.  (In versions of @system{ILU} before 2.0, string binding handles had a completely different syntax.)

The pair @code{(@metavar{server ID}, @metavar{instance handle})} are also
known as the @dfn{object ID} (or @dfn{OID}) of the object, because together they form
a universally unique ID for the object.

The @metavar{contact info} part contains one or more contact info sequences,
each describing one particular way of communicating with the object's kernel server.
Each contact info sequence consists of a series of fields.
The first field is known as the @dfn{protocol info}, and names a particular RPC protocol, and any
parameters that might influence the way in which this protocol would be used.
Each of the succeeding fields specifies @dfn{transport info}, which defines
a way of transforming or communicating data, and any parameters which might influence
that transport method.  There may be many sequences of contact info in any one string
binding handle (but @system{ILU} currently ignores all but the first).

@subsubsection Siblings

Some @system{ILU} object instances may have implementation
dependencies on private communication with other instances.  For
example, imagine an object type @code{time-share-system}, which
provides the method @method{ListUsers()}, which returns a list of
``user'' instances.  Imagine that @code{time-share-system} also
provides the method @method{SetUserPriority(u : user, priority : integer)}.
We would like to be able to provide some assurance that
the user instance used as a parameter to @method{SetUserPriority} is an
instance returned from a call to @method{ListUsers} on the same instance
of a @type{time-share-system}, because the way in which
@method{SetUserPriority} is implemented relies on the user being a user
of that particular @type{time-share-system}.

The @system{ILU} model provides the notion of a @dfn{sibling object}.
@cindex sibling
Two instances are siblings if their methods are handled by the same kernel server.
Instances that are non-discriminator parameters to methods may be specified
in @language{ISL} as having to be siblings of the discriminator.

@subsection Garbage Collection

A simple form of @dfn{garbage collection}
@cindex garbage collection
is defined for @system{ILU} objects.  If an object type is tagged as
being collectible, a server that implements objects of that type expects
clients holding surrogate instances to register with it, passing an
instance of a callback object.  When a client finishes with the
surrogate, the client unregisters itself.  Thus the server may maintain
a list of clients that hold surrogate instances.  If no client is
registered for an object, and the object has been dormant (had no
methods called on it) for a period of time @metavar{T1}, the server may
feel free to garbage collect the instance.  @metavar{T1} is determined
by human concerns, not network performance: @metavar{T1} is set long
enough to allow useful debugging of a client.

To deal with possible failure of a client process, we introduce another
time-out parameter.  If an instance with registered clients has been dormant
for a period of time @metavar{T2}, the server uses the callback instance
associated with each client to see if the client still exists.
If the client cannot be
contacted for the callback, the server may remove it from the list of
registered clients for that instance.

If a client calls a method on a surrogate instance of a true instance which
has been garbage-collected (typically because of partitioning), it will
receive the @exception{ilu.ProtocolError} exception, with detail code
@code{ilu.NoSuchInstanceAtServer}.

@subsection Connections

@system{ILU}, when used to construct distributed systems,
has no notion of ``connections''.  That is, the called module has no pointer
back to the caller, and no notion of how to do anything with the caller aside from returning
a result message.  Credentials passed in the request message can identify the caller, but
not necessarily the location the call is made from.  Protocols that need such information should
pass it explicitly as an argument (an instance of a object type with methods
defined on it) to the method.

@subsection Simple Binding

This release of @system{ILU} includes an experimental simple binding/naming facility.  It allows a module to @dfn{publish} an object, so that another module can import that object knowing only its object ID (as defined in @ref{ILU Concepts}).  The interface to this facility is deliberately quite simple; one reason is to allow various implementations.

The interface consists of three operations: @dfn{Publish}, @dfn{Withdraw}, and @dfn{Lookup}.  @fn{Publish} takes one argument, an @system{ILU} object.  @fn{Publish} returns a string that is needed to successfully invoke @fn{Withdraw}.  @fn{Withdraw} undoes the effects of @fn{Publish}, and takes two arguments: (1) the object in question, and (2) the string returned from @fn{Publish}.  In some langauge mappings, the string is not explicitly passed, but conveyed in the language mapping's representation of @system{ILU} objects.  @fn{Lookup} takes two arguments: an object ID and a type the identified object should have.  If the object with that ID is currently being published, and has the given type (among others), @fn{Lookup} returns that object.

The implementation shipped with this release of @system{ILU} can use either an @system{ILU} service, or a shared filesystem directory, to store information on the currently published objects.  This choice must be specified at system configuration time.  If the shared filesystem approach is used, this directory must be available by the same name, on all machines which wish to interoperate.  The way in which clients interact with binding is the same, regardless of which approach is selected.

@subsubsection Listing the Registered Objects

The simple program @program{ilusbls} will list the currently registered objects.  It may be invoked with an argument, in which case only those objects with string binding handles containing the argument as a substring will be listed.

@subsubsection Using Shared Files for Simple Binding

If simple binding is to be done with shared files, a default directory is compiled into the @system{ILU} library.  This directory may be explicitly specified at system configuration time with the @code{--with-binding-dir=@metavar{DIRECTORY}} switch to @program{configure}.  (The compiled-in setting may also be overridden at run time, by setting the environment variable @var{ILU_BINDING_DIRECTORY} to a different directory.)  @system{ILU} creates a file in this directory for each published object.  The name of the file is an 8-digit hex string, formed by taking the CRC-32 hash of the server ID and instance handle of the object.  The file contains the string binding handle of the object and a random string, which serves as the `proof' that has to be provided when withdrawing a registration.  Note that when using the shared file approach, the protection state of the directory must be such that programs calling @fn{Publish} can remove files and create new files, and programs calling @fn{Lookup} must be able to read files in the directory.

@subsubsection Using an ILU Service for Simple Binding

If an @system{ILU} service is used, the situation is a bit more flexible.  The idea is that a program called @program{ilusb} is run on some machine, and exports the binding service via a specified port.  All clients have compiled-in knowledge as to which machine and port the binding service is running on, and they contact the service to perform @fn{Publish}, @fn{Withdraw}, and @fn{Lookup} calls.  Each binding service is given a name, called a @dfn{binding realm}, which is the name of the `space' for which it provides simple binding services.  There may therefore be many instances of the @program{ilusb} server running, even on a single machine, each one serving a different binding realm.  It is often useful to establish multiple binding realms for different purposes.  For instance, one might be used for everyday registration of services, another for testing, still another for experimenting.

To start the binding service, run the program @program{@metavar{ILUHOME}/bin/ilusb}.  It takes the following options:
@itemize @bullet
@item @code{-r @metavar{REALM-NAME}} -- this allows specification of the @metavar{REALM-NAME} which the server will serve.  The default is the compiled-in realm name.
@item @code{-h @metavar{IP-ADDRESS}} -- this allows overriding the compiled in IP address for the machine.  This switch is mainly for multi-ported machines (machines which have two or more different IP addresses).
@item @code{-p @metavar{PORT}} -- this allows overriding the compiled in @metavar{PORT} specification.  This is the port on which the server listens for connections.
@item @code{-f @metavar{FILENAME}} -- this allows you to specify the name of a file in which the server will store a backup of the various registrations currently active.  If the server is restarted, and this file already exists, the server will read this file, and use the registrations in it as the current set of registrations.  This file should be in a directory which can be read and written by the user identity under which the @program{ilusb} program is running.  The default is a file called @file{/tmp/ILUSimpleBindingService.@metavar{REALM-NAME}}.
@item @code{-s} -- this option enables `protected' operation.  This prevents active registrations from being overridden; @fn{Withdraw} must be called first, to remove the current registration, before a new registration for the same object can be made.  This is useful in an environment which only wants to permit certain users to change certain registrations.  However, without secure communications, this operation is not truly secure, and enabling it is often clumsy for casual use of the simple binding service.  The default is unprotected operation.
@end itemize

By default, @system{ILU} programs use the compiled-in binding realm, host, and port.  However, they can be directed to use a different combination of these three, by defining the environment variable @var{ILU_BINDING_SERVICE} to a string of the form @code{"@metavar{REALM}:@metavar{HOST}:@metavar{PORT}"}, before running the program.  If you want only to override one or two of the compiled-in defaults, use a string with empty fields for the other parts.  For example, if you just wanted to redirect to a particular host, you could use a string of the form @code{":foo.bar.company.com:"}, with empty strings for @metavar{REALM} and @metavar{PORT}.

The program @program{ilusbls} will list all the currently registered objects.  It takes an optional string argument.  If the argument is specified, only objects which have that string in their string binding handles will be listed.

@subsection Error Signalling

@system{ILU} uses the notion of an @dfn{exception} to signal errors
between modules.
@cindex exception
An exception
is a way of passing control outside the normal flow of control.
It is typically used for handling of errors.  The routine which detects the
error signals an exception, which is caught by some error-handling mechanism.
The exception type supported in @system{ILU} is a termination-model
exception, in
which the calling stack is unrolled back to the frame which defined the
exception handler.  Exceptions are signalled and caught using the native
exception mechanisms for the servers and clients.  A raised exception may
carry a single parameter value, which is typed.

@section ILU and OMG CORBA

The type and exception model used by @system{ILU} is quite similar
to that used by the Object Management Group's Common Object Request
Broker Architecture (@system{CORBA}).  We have in fact changed @system{ILU}
in some ways to more closely match @system{CORBA}.  Our tools will
optionally parse the OMG's Interface Definition Language (@language{OMG IDL})
as well as @system{ILU}'s @language{ISL}.

@system{ILU}
also attempts to address issues that are already upon us, but
are not addressed in @system{CORBA 2.0}:  64-bit architectures,
UNICODE characters, a uniform way of indicating optional values, and garbage collection.

@system{ILU} provides two different interface definition languages, @language{OMG IDL} and @language{ILU ISL}
to enhance portability of @system{ILU} modules.  The @language{OMG IDL} subset understood by @system{ILU}
is a strict subset of @language{OMG IDL}; this means that any @system{ILU} modules developed
using @language{OMG IDL} interfaces should be interoperable with any other @system{CORBA}
system.  Any non-@system{CORBA} extensions may only be expressed in @language{ILU ISL},
so that any modules which use these extensions must use @language{ILU ISL} to express
their interfaces, thereby underlining the fact that these modules are not @system{CORBA}-compliant.
We feel that this dual-interface-language approach will tend to enhance
both portability and @system{CORBA}-compliance of @system{ILU} modules.

@system{ILU} does not yet provide some of the features required
by a full @system{CORBA} implementation.  Notably it does not
provide a Dynamic Invocation Interface, or implementations of
either Interface Repository or Implementation Repository.  It does
not provide the Basic Object Adapter interface, either, but does provide
an object adapter with most of the BOA's capabilities, except for
those connected with the Interface Repository and/or Implementation
Repository.

A number of concepts in @system{CORBA} that seem to require further
thought are not yet directly supported in @system{ILU}: the use of
@code{#include} (@system{ILU} uses a more limited notion of ``import'');
the notion of using an @language{IDL} ``interface'' as both an object
type and a name space (this seems to be a ``tramp idea'' from the
language @language{C++}; in @system{ILU} the ``interface'' defines a
name space, and the object type defines a type); the notion that all BOA
objects are persistent (in @system{ILU}, the question of whether an
object is persistent is left up to that object's implementation); the
notion that type definitions can exist outside the scope of any module
or namespace (in @system{ILU}, all definitions occur in some interface).
Currently, there is no support in @system{ILU} for @system{CORBA}
@code{context}s, the @language{OMG IDL} type @code{any}, or the
@language{OMG IDL} type @code{Object}.  We feel that all three of these
notions tend to weaken interface descriptions.

