Using the Network Service
Given that someone has exported a module as a network service, by publishing the
location of a well-known instance of an object type, a potential client of that
module can then use the module by binding to that well-known instance.
A D V E R T I S E M E N T
It does
this by calling the standard ILU routine ilu.LookupObject(), which
takes the name and type of an instance, and attempts to find that instance on
the net. The name of the object is specified as a pair of strings, the server
ID of the object's kernel server, and the instance handle of
the object on that kernel server.
So, in our first example, we could replace the call to
Create_Tutorial_Calculator with a routine that calls
ilu.LookupObject() to find the factory, then creates an instance of a
Calculator. The full code of the revised example, `simple3.py',
is available as section, but here's what the new code for obtaining an instance of a
Calculator looks like:
def Get_Tutorial_Calculator (factoryObjectSID, factoryObjectIH):
# We have to call ilu.LookupObject() with the object ID of
# the factory object, and the "type" of the object we're looking
# for, which is always available as MODULE.TYPENAME
f = ilu.LookupObject (factoryObjectSID, factoryObjectIH, Tutorial.Factory)
if not f:
print "Can't find Tutorial.Factory instance " + factoryObjectSID + factoryObjectIH
sys.exit(1)
c = f.CreateCalculator()
return (c)
We then can use the simple3 program:
% python simple3.py Tutorial.dept.company.com theFactory 1 2 3 4 5 6
the sum is 2.10000
%
Subtyping and Other ISL Types
ILU ISL contains support for a number of types other than object types and
REAL. The primitive ISL types include 16, 32, and 64 bit signed and
unsigned integers, bytes, 8 and 16 bit characters, a boolean type, and 32, 64,
and 128 bit floating point types. A number of type constructors allow
specification of arrays, sequences, records, unions, and enumerations, as well
as object types. The ISL OPTIONAL type constructor provides an
implicit union of some type with NULL, which is useful for building
recursive data structures such as linked lists or binary trees.
To illustrate some of these types, we'll extend the Tutorial.Calculator
type. Many real-world desktop calculators include a register tape, a
printed listing of all the operations that have been performed, with a display
of what the value of the calculator was after each operation. We'll add a
register tape to Tutorial.Calculator.
We could do it by adding a new method to Tutorial.Calculator,
called GetTape. Unfortunately, this would break our existing code,
because it would change the Tutorial.Calculator object type, and
existing compiled clients wouldn't be able to recognize the new object type.
Instead, we'll extend the object type by subtyping; that is, by creating
a new object type which uses Tutorial.Calculator as a supertype,
but adds new methods of its own. This subtype will actually have two types; both
its own new type, and Tutorial.Calculator. We'll also define a
subtype of the Tutorial.Factory type, to allow us to create new
instances of the new Calculator subtype. Finally, we'll define a
new module interface for the new types, so that we don't have to modify the
Tutorial interface.
First, let's define the necessary type to represent the operations performed
on the calculator:
INTERFACE Tutorial2 IMPORTS Tutorial END;
TYPE OpType = ENUMERATION
SetValue, Add, Subtract, Multiply, Divide END;
TYPE Operation = RECORD
op : OpType,
value : REAL,
accumulator : REAL
END;
TYPE RegisterTape = SEQUENCE OF Operation;
The enumerated type OpType defines an abstract type with five
possible values. The type Operation defines a record type (in
Python, a dictionary) with 3 fields: the op field, which tells us
which of the five possible calculator operations was performed, the value
field, which tells us the value of the operand for the operation, and the
accumulator field, which tells us what the value of the calculator was
after the operation had been performed. Finally, the Operation type
is a simple sequence, or list, of Operation. Note that
Tutorial2 imports Tutorial; that is, it allows the
use of the Tutorial types, exceptions, and constants, in the
specifications in Tutorial2.
Now we define the new object types (in the same file):
TYPE TapeCalculator = OBJECT COLLECTIBLE
SUPERTYPES Tutorial.Calculator END
DOCUMENTATION "4 function calculator with register tape"
METHODS
GetTape () : RegisterTape
END;
TYPE Factory = OBJECT SUPERTYPES Tutorial.Factory END
METHODS
CreateTapeCalculator () : TapeCalculator
END;
The SUPERTYPES attribute of an object type may take multiple object
type names, so ISL supports multiple inheritance. The
Tutorial2.TapeCalculator type will now support the six methods of
Tutorial.Calculator, as well as its own method, GetTape.
We then need to provide an implementation for Tutorial2. . We modify each method on the
TapeCalculator object to record its invocation, and add a slot to
hold the contents of the `tape'. We also provide an implementation for
Tutorial2.Factory:
import Tutorial2, Tutorial2__skel, TapeCalculatorImpl
class Factory (Tutorial2__skel.Factory):
# have the __init__ method take handle and server args
# so that we can control which ILU kernel server is used,
# and what the instance handle of the Factory object on
# that server is. This allows us to control the object ID
# of the new Factory instance.
def __init__(self, handle=None, server=None):
self.IluInstHandle = handle
self.IluServer = server
def CreateCalculator (self):
return (TapeCalculatorImpl.TapeCalculator())
CreateTapeCalculator = CreateCalculator
Note that both the Tutorial2.Factory.CreateCalculator and
Tutorial2.Factory.CreateTapeCalculator methods create and return
instances of Tutorial2.TapeCalculator. This is valid, because
instances of Tutorial2.TapeCalculator are also instances of
Tutorial.Calculator.
Now we modify `server.py' to create an instance of
Tutorial2.Factory, instead of Tutorial.Factory, and to
initialize the Tutorial2 true-side code
Note that one nice result of this approach to versioning is that old clients,
which know nothing about the new TapeCalculator class, or about the
whole Tutorial2 interface in general, will continue to function,
since every instance of Tutorial2.TapeCalculator is also an
instance of Tutorial.Calculator, and every instance of
Tutorial2.Factory is also an instance of Tutorial.Factory.
|