| Recent product releases |
|
| Sirius Mods Version 6.7 |
May, 2005 |
| Sirius Mods Version 6.6 |
August, 2004 |
| Sirius Mods Version 6.5 |
May, 2004 |
| Fast/Unload Version 4.2 |
March, 2004 |
| Fast/Unload Version 4.1 |
September, 2003 |
| Sirius Mods Version 6.4 |
May, 2003 |
| Sirius Mods Version 6.3 |
October, 2002 |
| Sirius Mods Version 6.2 |
May, 2002 |
| SirAud Version 1.04 |
May, 2002 |
| Sirius Mods Version 6.1 |
July, 2001 |
| Sirius Mods Version 6.0 |
December, 2000 |
| SirAud Version 1.02 |
April, 2000 |
| Fast/Unload Version 4.0 |
January, 2000 |
Sirius Mods Version 6.7
Version 6.7 of the Sirius Mods was released in May, 2005.
The major enhancements are summarized below.
Please refer to the
Notes for Sirius Mods Version 6.7 for more detailed information.
Support for Model 204 V6R1
Sirius Mods Version 6.7 fully supports Model 204 V6R1, with the following qualifications
concerning Large Object fields (LOBs):
- Fast/Backup Version 6.7 is required to dump a file created by V6R1.
While a Model 204 file created under V6R1 cannot be opened by
a previous version of Model 204, Fast/Backup Version 6.7 can restore a file
created under V6R1 to a file created prior to V6R1, as long as the dumped file was created with a
TABLEE size of 0.
- Sir2000 Field Migration Facility doesn't let you establish a date format for a LOB field.
- A $FUNLOAD request that "accesses" LOB fields requires Fast/Unload 4.3, otherwise
Fast/Unload 4.2 with ZAP4210 may be used.
- Fast/Reload supports the loading of files processed under Model 204
V6R1, including files that contain LOBs.
The Fast/Reload D statement will process PAI output from a file that has LOB fields defined.
LAI supports files with LOBs, but Fast/Unload 4.3 is required for UAI to support LOB fields.
- In User Language, you can move data between LOBs and longstrings
via $lstr_set_userBuffer, $lstr_get_userBuffer, and $lstr_add_userBuffer.
All or Multiple Products
Sdaemon performance enhancements
The new system parameter, SDMOPT, enables certain sdaemon performance enhancements
for Janus Web and Janus Server requests as well as requests run by Daemon objects.
SCREENS Stat and Connect*
The SCREENS statistic is now set to 1 at the completion of a
Model 204 Connect* request.
This can be useful in SirMon and SirAud statistics calculations.
MSGCTL NOCAN prevented for some error messages
Certain error messages should not be changed to NOCAN; doing so
will cause unpredictable results.
In general, you should not change an MSIR message to NOCAN unless there
is explicit documentation explaining the circumstances for doing so.
In order to prevent some unsafe MSGCTL NOCAN commands, certain error messages
reject a MSGCTL NOCAN and instead produce an MSIR.0885 cancelling error message.
Object swapping statistic
A new system and user (login and since-last) statistic, OBJSWAP, reports on the
swapping of Janus SOAP ULI objects into and out of CCATEMP.
The object swapping statistic displays on CCAAUDIT and can be displayed by SirScan, SirMon and
the Model 204 T REQUEST and MONITOR commands.
User of AUDIT204 need a Sirius zap, else the user and since-last statistic name for OBJSWAP will be
formated as eight blanks and the system statistic name will be eight blanks for Version 5.3 and 6.1
or TCON under Model 204 Version 5.1.
Fast/Reload
The following are new or changed features in
Fast/Reload in this release:
- A new keyword, ERRCONT, is added to the OPTIONS statement.
ERRCONT lets you complete a reload despite errors that would
normally cause a MSIR.0316 user restart.
ERRCONT can be useful, for example, in a case where you know you have some
input data that will cause an error, but you
want to use a reload for reformatting purposes despite the problematic fields.
- Support for Model 204 Version 6.1 files
Fast/Reload now supports Model 204 V6R1 files, including
loading of LOB fields, either in PAI or UAI format.
This support requires Model 204 V6R1 and for table E space to be defined in
the target file.
Only Fast/Unload Version 4.3 and later is capable of unloading a LOB field in
UAI format so that it could be then loaded by Fast/Reload.
- Validation of input record buffer offsets
Fast/Reload now checks references to the input record buffer to detect attempts to
look “off the end” of the current record.
This avoids addressing exceptions or correpted data when references based upon a
constant or index-register value are invalid.
There is a slight performance cost to doing this check, so if there is
no chance the checks would ever detect an error, you can turn off the checking
with the new NOVALIDATE option on the Fast/Reload OPTIONS statement.
Fast/Unload User Language Interface
New Messages
Messages are now sent to the Model 204 journal/audit trail on every
Fast/Unload request made and completed by the Fast/Unload User Language Interface.
The message when the requests are started look like:
MSIR.0890: Asynchronous request 2 made by $funload
And the message when the requests are completed look like:
MSIR.0891: Asynchronous request 2 completed, RC = 0
These messages make it much easier to diagnose problems where Fast/Unload User Language Interface
is involved.
FUNPARM System Parameter
The new system parameter FUNPARM is a standard Model 204 bitmask-style parameter.
The X'01' setting, the only bit currently available, indicates that a synchronous
Fast/Unload request is not to be allowed while an updating transaction is active.
This is to prevent a Fast/Unload request that might take a long time to
complete from being run while a user has resources enqueued for an updating
transaction.
These resources would, of course, include the blocking of checkpoints.
FUNMAXT System Parameter
The new system parameter FUNMAXT is a numeric parameter (with valid values from 0 to 36000)
that indicates the maximum amount of time, in seconds, a Fast/Unload User Language Interface
request is to be given to complete.
The timer starts from the initiation of the request, either via $Funload,
or the new FastUnload and FastUnloadTask methods
in the RecordSet class.
The default value of FUNMAXT, 0, means that there will be no time limit
placed on Fast/Unload User Language Interface requests.
The purpose of FUNMAXT is to prevent user requests being “hung up”
indefinitely while queuing for busy Fast/Unload tasks or for unintentionally
long running requests.
RecordSet Methods for Fast/Unload
There are two new methods now available as an alternative to $Funload for
unloading data using the Fast/Unload User Language Interface.
Both of these methods are in the RecordSet class, and both unload the data in
the RecordSet object against which they are invoked.
These methods are FastUnload and FastUnloadTask, and
they are only available to customers licensed for both “Fast/Unload User
Language Interface” and Janus SOAP.
The FastUnload Method
The FastUnload method can be used to perform synchronous or asynchronous unloads.
FastUnload has four NameAllowed parameters and three NameRequired parameters.
For asynchronous requests, the FastUnload method returns the request number.
Request numbers are assigned serially, starting at 1,
to $Funload and to the RecordSet FastUnload and FastUnloadTask methods.
For synchronous requests, the FastUnload method returns the return code
from Fast/Unload.
If the request is cancelled because the timeout period (MaxTime parameter,
or FUNMAXT system parameter) is exceeded, the return code is 32.
Any errors in the method parameter list, or any environmental errors that
would prevent the request from being run, result in the request being
cancelled.
The FastUnloadTask Method
The FastUnloadTask method can be used to perform unloads using Fast/Unload where
the Fast/Unload output is processed programmatically as it is received.
The advantage of the FastUnloadTask approach over the FastUnload method
with a StringList
output is that it avoids potentially large quantities of data from being
moved to and from CCATEMP.
The disadvantage of this approach is that User Language processing is likely to be
slower than Fast/Unload processing, so using FastUnloadTask is likely to tie
up a Fast/Unload task much longer than using FastUnload, which sends its output to
a StringList.
The FastUnloadTask method has two NameAllowed parameters and three NameRequired
parameters.
FastUnloadTask returns a FastUnloadTask object which can be used to retrieve output from Fast/Unload.
The FastUnloadTask Class
The FastUnloadTask class is used for retrieving data from a Fast/Unload task
as it is output.
The only way to instantiate a FastUnloadTask object is via the FastUnloadTask
method of the RecordSet class.
FastUnloadTask objects always have one of three states, as described
by values of the FastUnloadTaskState enumeration:
- Started
- This is the initial state of a FastUnloadtask object, and it indicates that
no GetNextRecord methods have yet been called.
- HaveRecord
- Indicates that GetNextRecord has been called, and that the call did, indeed,
retrieve another record from Fast/Unload.
- Done
- Indicates that GetNextRecord has been called, and that the call
discovered that
there where no more records to retrieve, that is, Fast/Unload had terminated.
The FastUnloadTask class has the following methods:
- CurrentRecord Method
- This function returns the contents of the current record as a longstring.
It has no parameters, and it can only be called when the FastUnloadTask object
is in the HaveRecord state.
If called in any other state, the request is cancelled.
- GetNextRecord Method
- This function requests the next record from the Fast/Unload task, and it returns the
new state of the FastUnloadTask object as a FastUnloadTaskState enumeration value.
It has no parameters, and it can only be called when the FastUnloadTask object
is in the Started or HaveRecord state.
If called in the Done state, the request is cancelled.
- Report Method
- This function returns a StringList with the Fast/Unload report data.
It has no parameters, and it can only be called when the FastUnloadTask object
is in the Done state.
If called in any other state, the request is cancelled.
This function can only be called if ReportToStringList is set to True in
the RecordSet class FastUnloadTask method that created the method object.
Otherwise, the request is cancelled.
- ReturnCode Method
- This function returns the Fast/Unload numeric return code.
It has no parameters, and it can only be called when the FastUnloadTask object
is in the Done state.
If called in any other state, the request is cancelled.
- State Method
- This function returns the current state of the FastUnloadTask object as a
FastUnloadTaskState enumeration value.
It has no parameters, and it can be called when the FastUnloadTask object
is in any state.
Janus SOAP ULI
The object-oriented extensions supported by the Janus SOAP User Language Interface
have been significantly enhanced with Version 6.7.
The Notes for Sirius Mods Version 6.7 discuss
these changes in more detail.
For examples of how to use the Janus SOAP ULI and more in-depth documentation, please
refer to the Janus SOAP Reference Manual.
The following discussion just presentst the highlights of changes in 6.7.
Inheritance and Polymorphism
Janus SOAP ULI support for inheritance and polymorphism was added in
Version 6.7.
Inheritance and polymorphism are two closely related but subtly different
concepts that are often considered cornerstones of object-oriented programming.
Inheritance allows a programmer to create an object class that has
all the characteristics of another object class (or that inherits all
that classes attributes) and that has additional characteristics or attributes.
Such a class is often called an extension class, because
it extends the capabilities of what is often called a base class.
Polymorphism allows objects of different classes to be used
interchangeably.
Since the classes that can be used interchangeably are almost
always a base class and one of its extension classes, or are
extension classes of the same base class, polymorphism is
strongly related to inheritance.
To create an extension class of a base class, simply include
the Extends phrase in the first Class statement for the class:
class ropeList extends stringList
...
end class
As this example illustrates, it is possible to extend many system classes
as well as User Language classes.
There are exceptions, however.
It is not possible to extend the following types of system classes:
- Collections, that is, ArrayLists and NamedArrayLists
- Enumerations, such as the Boolean class
- File classes, such as the RecordSet class, the Record class, and the
RecordSetCursor class
- The XmlNode class
When one class extends another class, members of the base class can
be accessed via variables of the extension class.
For example, if RopeList extends the system StringList class,
and %rope is of the RopeList class, any StringList class member
can be accessed by preceding the member name with the StringList
class name in parentheses:
%rope:(stringList)add('Added item')
If the creator of the RopeList class wants users of the class
to be able to use StringList class members without specifying the class
name on each invocation, the Inherit keyword can be specified after
the class name in the Extends clause on the Class statement:
class ropeList extends stringList inherit
...
end class
If Inherit is specified on the Class statement, the Add method in the previous
example can be accessed without specifying the StringList class:
%rope:add('Added item')
Since the main reason to use extension classes is to add functionality to the base class, you
may define Public, Private, Public Shared, and Private Shared members in an extension class,
and you may access these members like any other member of any other class:
class ropeList extends stringList inherit
public
property first is longstring
property last is longstring
subroutine print
variable name is string len 32
end public
...
end class
A member of an extension class may have the same name as a member of a base class.
In the example above, the RopeList class has a Print subroutine that
has the same name as a StringList class method.
In such a case, an unqualified reference to the member such as
the following refers to the member in the extension class:
%rope:print
This is called member hiding, because a member in the base
class is hidden by a member in the extension class.
In such cases, however, it is always possible to access the base class
member by indicating the class name in parentheses, before the member
name:
%rope:(stringList)print
This accessibility means someone writing an extension class should never assume
that a base class member with the same name as an extension class member
will never be accessed.
Another way to access a base class member instead of using an extension
class member with the same name is to use polymorphism.
With polymorphism, one can always assign an extension class variable
to a base class variable:
%rope is object ropeList
%string is object stringList
...
%rope = new
%rope:name = 'Percy'
%string = %rope
%string:print
This assignment is possible because an object of an extension class is also
considered to be an object of the base class.
Many object-oriented programming textbooks use animals to illustrate this point: if an object is of class
Otter, it is also of class Mammal, so there is nothing wrong with assigning it to a Mammal object variable.
Once assigned to a base class variable, all member name references access the base class member of
that name, even if the extension class has an eponymous member name.
If this were not so, someone referencing a member via a base class variable might access a member
of a class they didn't even know about.
In addition to allowing unqualified access to base class members (via
the Inherit keyword in the Extends clause of the Class statement), it is
possible to selectively allow unqualified access to individual base class
members.
In the following class, any reference to the Print member via a RopeList
class variable accesses the StringList member of that name:
class ropeList extends stringList
public
property first is longstring
property last is longstring
inherit print from stringList
variable name is string len 32
end public
...
end class
The Inherit declaration can also be used to map a base class
method to a different extension class name:
class ropeList extends stringList inherit
public
property first is longstring
property last is longstring
subroutine print
inherit display from stringList print
variable name is string len 32
end public
...
end class
In this example, a reference to the Display member of the RopeList
class actually accesses the Print method of the StringList base
class.
This can be useful if, as in this example, there is a conflict between
a base class member name and an extension class member name.
Multiple Inheritance
Janus SOAP ULI allows a class to extend more than a single class.
This seems reasonable, as many objects in the real world can be thought of
as extensions to more than one base class.
For example, one might think of a dog as an extension to a Mammals class
and to a Pets class.
Or a person's car can be thought of as an extension to an Automobile
class and to a Property class.
To extend multiple classes with Janus SOAP ULI, you separate the extended classes
with the And keyword in the Class statement Extends clause:
class pet extends animal and property
The Inherit keyword can follow any or all of the extended class names:
class pet extends animal inherit and property
or
class pet extends animal inherit and property inherit
In general, having Inherit keywords on more than one extended class
is not recommended,
unless those classes are maintained to avoid name collisions.
A name collision is generally treated as a compilation error.
In the above example, if the Animal and Property classes both had members
called Weight, the class declaration would result in a compilation error.
You can prevent name collision errors
by specifying the IgnoreDuplicates keyword
after the Inherit keyword for a base class for which duplicates are to be ignored:
class pet extends animal inherit and -
property inherit ignoreDuplicates
When IgnoreDuplicates is specified for an Inherit base class, any member
names in that class that match an earlier Inherit base class member name
will not be accessible without qualification, if they are being accessed
via extension class variables.
For example, a class has the following declaration:
class pet extends animal inherit and -
property inherit ignoreDuplicates
If both the Animal and Property classes have a member called Weight,
the following call references the Weight member of the Animal class
(assuming the Pet class has no Weight member that hides Animal's Weight member):
%tinky is object pet
...
print %tinky:weight
In this case, the Property class's Weight member is accessible
by qualifying it with the class name:
%tinky is object pet
...
print %tinky:(property)weight
Repeat inheritance
With multiple inheritance, it is possible to define an extension class
where the same base class appears more than once in the inheritance
chain.
For example, if the class MaleDriver extends the Driver class and the
class AmericanDriver extends the Driver class, it might seem logical
to create a MaleAmericanDriver class that extends both the MaleDriver
and the AmericanDriver class.
If this were done, however, the MaleAmericanDriver would end up with
the Driver class as a base class twice — once via the MaleDriver
class, and once via the AmericanDriver class.
This is an example of repeat inheritance.
Repeat inheritance is not currently allowed by the Janus SOAP ULI.
Because there are some special cases where repeat inheritance does
make sense, Janus SOAP ULI will probably add support for some limited forms
of repeat inheritance in a future release.
Inheritance and constructors
An extension class might or might not have any constructors.
If an extension class has no constructors, the default (New) constructors
for the base classes are called in sequence with no parameters.
However, if any of the base class constructors require parameters or
don't have the default New constructor, a constructor is required
for the extension class.
Of course, even if a constructor is not required for an extension
class, one can be provided as needed.
In any case, if an extension class has a constructor, that constructor
is required to complete the construction of the object for all base
classes.
This is accomplished with the Construct statement, which is
followed by an invocation of the shared New method or by invocation of
any other constructor.
The Construct statement must be followed by the class name (using the
shared method invocation syntax), followed by the constructor name,
followed by any constructor parameters.
There are several restrictions concerning extension class constructors.
While the rules for extension class constructors might seem complex,
they probably will not come into play outside of fairly complicated
constructors.
Furthermore, any violation of the rules is detected at compile-time
with a clear error message indicating the problem.
Restrictions on the placement of Construct statements are intended to ensure that exactly one Construct
statement is executed for each base class in an extension class constructor.
In addition, there are also some limitations on references to base or extension class
members inside the extension class constructor.
These restrictions are intended to prevent references to members of
classes that are “incomplete” because the relevant constructor
has not been run for the object yet.
The final restrictions on extension class constructors are that the
%this variable cannot be assigned to a variable.
All of the various restrictions on constructors are detected at compile-time, so
if an extension class constructor compiles successfully, you can be sure
that all the rules have been observed.
Polymorphism
Polymorphism is the ability of an object variable
to refer to objects of the variable's class, or to objects of an extension
class of the variable's class.
For example, if there is a Mammal class and the Otter class extends
the Mammal class, an object variable of the Mammal class could refer
to a Mammal object or an Otter object (since all Otters are Mammals).
An Otter object variable can always be assigned to a Mammal variable:
%tarka is object otter
%fuzzy is object mammal
...
%tarka = new
...
%fuzzy = %tarka
After the assignment, the %fuzzy variable can be used as any other Mammal
object variable, even though the referenced object is actually an Otter —
again, all Otters are Mammals.
Note, however, that the %fuzzy variable cannot be used to invoke Otter-specific
methods, because the determination of which method is to be run for a method
invocation is done at compile-time, and the compiler has no way of
knowing that %fuzzy would end up referencing an Otter object.
Polymorphism can also be used in cases of implied assignments.
For example, if there is a method in class Zoo that takes a Mammal
input object:
class zoo
subroutine brushFur(%animal is object mammal)
end class
It is possible to invoke this method passing an Otter variable
as the input parameter:
%tarka is object otter
%bronx is object zoo
...
%tarka = new
...
%bronx:brushFur(%tarka)
This is logically equivalent to assigning %tarka to the %animal input
parameter.
A slight variant on this is when a base class method is called
via an extension class variable, either via the Inherit keyword
in the Extends clause, an Inherit statement in the extension class
Public or Private block, or an explicit base class reference on
the invocation.
For example, if the Otter class is defined as follows:
class otter extends mammal inherit
And if there is a LiveBirth method in the Mammal class, the following
code calls that method:
%tarka is object otter
...
%tarka = new
...
%tarka:LiveBirth
Part of this call is equivalent to polymorphic assignment of the
%tarka variable of class Otter to the %this variable of class Mammal
in the LiveBirth method.
Exactly the same kind of implied assignment would be done if the
method invocation was via an explicit class specification:
%tarka is object otter
...
%tarka = new
...
%tarka:(mammal)liveBirth
All the examples discussed here are explicit or implicit assignments from
extension class variables to base class variables.
This kind of assignment is sometimes called a widening assignment:
an extension class is considered to be a subset of the base class
(again, think Otter and Mammal), and assignment from an extension class
variable to a base class variable is from a more specific
class to a more general class, hence a widening assignment.
Some object-oriented languages also allow what are called narrowing assignments
— assignments from a base class variable to an extension class variable.
Janus SOAP ULI does not allow such assignments.
That is, the following assignment from %fuzzy to %tarka is not allowed and
results in a compilation error:
%tarka is object otter
%fuzzy is object mammal
...
%fuzzy = %(otter):new
%tarka = %fuzzy
While initially this might seem like a rather arbitrary and
problematic limitation on polymorphism, there are some good reasons
why this is not the case:
- It is exceedingly rare that one would
even knowingly try such an assignment, much less need to do such an
assignment.
- Such an assignment might fail.
In the above example, it's clear from the code that %fuzzy would
reference an Otter object.
But, suppose %fuzzy actually contained a reference to a Kangaroo
object, which is also a Mammal but is most definitely neither a
base nor an extension class of Otter.
It would seem clear that the assignment should fail and that, in
the general case, the failure of the assignment could only be
determined at run-time.
Languages that allow narrowing assignments simply compile the
assignments, and if the assignment fails, produce a run-time
error.
Such languages make it
the programmer's job to write code in such a way as to
avoid such errors, not the language's job to present arbitrary
restrictions to prevent the programmer from doing so.
Unfortunately, in the case of narrowing assignments, almost anything
a programmer is likely to do to prevent narrowing assignment errors
is likely to have bad code maintainability implications.
Dynamic Dispatch
While inheritance and polymorphism can be useful in and of themselves,
they are relatively limited and incapable of dealing with truly complex
relationships between base and extension classes.
More specifically, they provide no way of having extension-class
specific processing performed when needed.
Version 6.7 of the Janus SOAP ULI adds support for dynamic dispatch, frequently
refered to as Dynamic Dispatch According to Object Type (DDATOT).
Using dynamic dispatch you can declare a function in the Animal class
as overridable:
class animal
public
...
function nextFeeding is float overridable
...
end public
...
The actual implementation of this overridable method then
provides a default NextFeeding method for all Animal class objects.
For example, the following implementation makes the rather silly
assumption that most animals need to be fed every eight hours (with
seconds as the time units):
function nextFeeding is float overridable
return %this:lastFeeding + 8 * 60 * 60
end function
Now, any class that extends the Animal class could provide an alternative
NextFeeding function:
class bat extends animal
public
...
function nextFeeding is float -
implements nextFeeding in animal
...
end public
function nextFeeding is float -
implements nextFeeding in animal
... bat specific next feeding calculations
end function
...
But how does one invoke the appropriate NextFeeding method for a particular
object?
The answer is, by simply invoking the NextFeeding method in the Animal
class:
%creature is object animal
...
print %creature:nextFeeding
When the Nextfeeding method is invoked in the above example, Janus SOAP ULI
determines the true class (remember, %creature can reference something
of the Animal class, or of any extension class of Animal) of the object
referenced by %creature, and it calls the appropriate NextFeeding method
for that object.
Note that this actually achieves a narrowing assignment (assignment of
a base class variable to an extension class variable), because the
object reference from the base class variable is assigned to the %this
variable, which is of the extension class, in the extension class method.
This is a very structured and specialized narrowing assignment that
avoids many of the problems and pitfalls generally associated with
narrowing assignments.
For example, in the following code, the Bat class NextFeeding method
will be called, because %creature will reference a Bat object:
%creature is object animal
...
%creature = %(bat):new
print %creature:nextFeeding
Any extension class of the Animal class that doesn't implement the
NextFeeding method will simply have the Animal class's NextFeeding
method run on its behalf.
Suppose there were no sensible default behavior for a method (as is the
case, really, for the Nextfeeding function).
Suppose it was expected that extension classes would always provide
a class-specific implementation of such a method.
Then, instead of declaring the method Overridable, the base class
could declare the method as Abstract:
public
...
function nextFeeding is float abstract
...
end public
The term Abstract here means that the containing class provides no
implementation of the indicated method, but instead, it expects an extension
class to do so.
Now, if a base class has at least one Abstract method declared,
what if the method is invoked on an object
of the base class only, that is, not for an extension class?
The answer is that there is no sensible thing to do, so you are not
allowed to create an instance of an object of the base class only.
Declaring an Abstract method for a class
makes the class itself an abstract class.
This must be indicated on at least the first declaration for the class,
by specifying the Abstract keyword following the class name:
class animal abstract
...
public
...
function nextFeeding is float abstract
...
end public
...
If a class is abstract, you can declare variables of that class:
%sickAnimal is object animal
But you cannot create an object instance of that class.
That is, if class Animal is abstract, both of the following two New
invocations are invalid:
%sickAnimal is object animal
...
%sickAnimal = new
...
%sickAnimal = %(animal):new
However, if a class extends the base class and implements all
its abstract methods, an object instance of that class can be assigned
to an abstract class variable.
For example, if the Bat class implemented all the Animal class
abstract methods, the following would be perfectly valid:
%sickAnimal is object animal
...
%sickAnimal = %(bat):new
Note that it is possible to declare a class as Abstract even if it has
no Abstract methods.
You might do this to leave open the possibility of
adding abstract methods to the class in the future.
Or you might do this if, for
whatever reason, it does not make sense to have an instance
of a base class — the class only makes sense when extended.
An abstract class can be extended by another abstract class,
and an abstract method can be implemented by another abstract
method:
class nocturnalAnimal extends animal
public
...
function nextFeeding is float -
implements nextFeeding in animal abstract
...
end public
...
In the case of the preceding example, an extension class
of the nocturnalAnimal extension presumably
implements the Nextfeeding method.
Sometimes, you may want a method that implements an overridable method
to augment rather than replace the overridden method's processing,
that is, to do some extra processing before or after the
overridden method.
An apparent way to accomplish this is
to simply invoke the overridden method from inside the implementing
method:
function nextFeeding is float implements nextFeeding in animal
... stuff before base method processing
%foo = %this:(animal)nextFeeding
... stuff after base method processing
end function
Unfortunately, the above syntax would simply result in the recursive calling
of the extension class's implementing method — %this
references an object of the extension class, so via dynamic dispatch,
the extension class's NextFeeding method would be called.
To get around this, a special member name, Super, is provided.
The Super member exists only in methods that implement an overridable
method, and it refers to the overridden method without dynamic
dispatch.
To call an overridden method from an implementing method, you
use the Super member like this:
function nextFeeding is float implements nextFeeding in animal
... stuff before base method processing
%foo = %this:super
... stuff after base method processing
end function
Note that, as usual, the this: can be left off,
so %this:super can be written simply as %super.
If the method had parameters, they could be included after the Super,
as if the Super was the overridden method name.
Note also that Super makes no sense for methods that
implement abstract
methods, since with abstract methods, there is no base class method for the
Super member to reference.
For programmers familiar with other object-oriented programming languages, it is
worth pointing out that most of the facilities provided for dynamic
dispatch by Janus SOAP ULI are no different than those provided by those
other languages.
However, some of the defaults in some other languages are different.
For example:
These differences are present in Janus SOAP ULI to facilitate its support for
multiple inheritance, and also, independent of multiple inheritance,
to improve the maintainability of Janus SOAP ULI code.
A final point: in many programming languages, the use of dynamic dispatch has a severe
performance penalty.
This is not the case for Janus SOAP ULI.
While there is an exceedingly small performance penalty for using
dynamic dispatch, this penalty is so small as to be unmeasurable in most cases.
Performance cost should not be a consideration when trying to determine whether
dynamic dispatch should be used.
Daemon objects
Sirius Mods 6.7 introduces Daemon objects,which provide a facility for issuing Model 204
commands from inside a User Language request, simulating the calling of programs as if they were subroutines.
Daemon objects are much like an object-oriented version of the Sirius $COMMxx $functions, which use
Sirius sdaemons to run a command on another thread on behalf of the issuing user.
Unlike the $COMMxx $functions, however, Daemon objects offer the advantage that
they can execute multiple calls per sdaemon login/logout sequence.
The term “daemon” or “daemon thread” is often used to mean “the
sdaemon thread that is activated or involved when you employ or operate on a Daemon object.”
The user or thread that invokes a daemon is the “master”
or “master thread.”
A daemon thread runs a command on behalf of the issuing user,
and the thread is only available to that master user.
The thread does not, for example, maintain some context
and accept requests from different users.
To pass a command to a daemon, you use the Run method with the command as argument.
Two examples follow for the %foo Daemon object:
%foo:Run('OPEN FILE MYPROC')
%list = %foo:Run('I REPORT')
To have a daemon thread run multiple commands,
you can specify multiple Run method calls, or you can
define the commands as items in a Stringlist, and then specify the StringList
as the argument in the Run method.
The StringList is fed to the daemon as terminal input
and executed item by item until that input runs out.
For example, if
the commands from the examples above were defined in that order
as the items in
StringList %testproc, the following statement would include
the procedure REPORT from the MYPROC file:
%foo:run(%testproc)
You use a StringList argument in this way to pass a User Language request
to a daemon.
Although a daemon thread is request-specific,
Daemon objects do have persistence.
The daemon thread waits
for work as long as the Daemon object exists.
Since the Daemon object can
be Global or Session as well as not, its span of existence can be arbitrarily
long or short, depending on how it is being used.
A daemon thread does not share record locks or transactions
with its master thread.
Commits and Backouts apply only to the thread that issues them.
If a daemon thread does a user restart, the
calling thread does not also restart.
However,
subsequent Runs and other calls to the restarted daemon
result in request cancellation.
If the calling thread is logged off or restarted, its associated
daemon threads are deleted.
A daemon is not automatically restarted if the master restarts.
The daemon does a user restart
if it is processing a User Language request that calls for terminal input, and
no Run method input follows the end of request.
The Daemon methods
Daemon objects provide support for the following methods:
- Methods to create (New constructor and delete (Discard
function) a Daemon object.
The New constructor creates a new instance, assigning an sdaemon thread to
the new object.
The Discard function frees the assigned sdaemon thread (possibly via a BUMP) and
deletes the Daemon object.
Note: any Daemon objects will be discarded and their sdaemon threads released if
the master thread is logged off or restarted.
- Properties for a master to retrieve information about the sdaemon thread associated
with a Daemon object instance (HaveDaemon, UserNumber, and
LastCommandErrorCount).
- A property for any program to determine if it is running on a thread associated
with a Daemon object (AmDaemon).
- A function for opening files or groups on the sdaemon thread associated with
a Daemon object (Open).
The Open method can only open a file or group that is already open on the
master thread, and it assigns the daemon thread the privileges from the master thread.
- A function to send commands and an optional input object to the to the
sdaemon thread associated with a Daemon object (Run).
The input commands can either be contained in a long string or a stringList.
The Run function returns a stringList containing any terminal output produced
by the input commands.
A SOAP ULI program run on a daemon thread may optionally return an object to the master thread.
The ability to pass objects between the master thread and a daemon thread makes
Daemon objects a much more powerful application tool than the $COMMxx functions.
- A shared method for a daemon thread to retrieve the input object passed from
the master thread (GetInputObject).
This subroutine creates an object instance on the daemon thread that is a
“deep copy” of the input object passed to the Run function that
initiated the program on the daemon thread.
- A shared method for a daemon thread to return an output object to the master
thread (ReturnObject).
This subroutine also uses deep copy to pass an object from the daemon thread
back to the master thread where it is returned into the third parameter of the Run function
that initiated the program on the daemon thread.
Copying objects
Sirius Mods Version 6.7 introduces generic (Object class) methods
for making copies of User Language class objects,
and it also introduces adaptations of those methods
for making copies of several Sirius system class objects.
“Shallow” and “deep” copying methods are available.
The shallow and deep types differ only in how they handle contained objects:
A shallow copy of an object includes a copy of the references to
to its contained objects.
A deep copy includes the references to its contained objects and it
includes a copy of the referenced object itself — and
if a contained object itself contains objects, deep copy copies
those references and objects, and if any of those objects have contained
objects, deep copying continues like this
until the chain of objects contained in contained objects is exhausted.
For example, if
a simple object (%S) contains multiple variable members,
one of which is an object variable(%c, which references an object
that has no contained object variables),
a shallow copy produces a matching object with matching
variable members, including %c.
Remembering that %c is a reference and not the actual object,
the shallow copy of an object that contains an object pointer thus produces
a matching object and object pointer.
A deep copy of %S produces two objects: one object
that matches %S with a pointer to %c, and one object
that is a replica of the actual object that %c references.
For simple objects (objects without contained objects), a shallow copy
is the same as a deep copy.
Shallow copies may be most useful with collections, say
for sorting an ArrayList.
To preserve the original order of a given ArrayList,
you make a shallow copy of the collection
to avoid the expense of making copies of any ArrayList objects,
then you sort the shallow copy on whatever criterion you want.
A shallow copy method may also in turn be used as a building block for
constructing copy methods of arbitrary complexity for hierarchical
object structures.
Deep copies provide
a facility for copying an entire arbitrarily complex object forest,
and they are probably more widely useful than shallow copies.
For example,
deep copying is essential internally in Sirius system methods that
let you pass an object between two threads and
reference the object on both threads.
The Object class copy methods
Two methods are added to the Object class: Copy and DeepCopy.
Both methods are functions without arguments that return a new instance
of the method object to which they are applied.
%cop = %obj:Copy
%dcop = %obj:DeepCopy
Where:
- %cop
- A shallow copy (member variable by member variable assignment) of
method object %obj.
- %dcop
- A deep copy (member by member assignment plus duplication of
any referenced objects) of its method object %obj.
- %obj
- A “copyable” User Language object.
The Public block of such an object's class must include the
Allow Copy, AllowDeepCopy, or both keywords to
make available the Copy, DeepCopy, or both methods.
You specify these keywords as you would a method declaration,
but the method is provided by the system rather
than the class programmer.
Whether an object is copyable is discussed further below.
Usage Notes
- Not all objects may be copied.
For example,
a Sirius Socket object is an example of a class that is not copyable,
because it has a significant
amount of information or state that is not held in the object itself.
And what does it mean to copy a network connection?
- Not all objects that that it is possible to copy should be
allowed to be copied.
As a general rule of thumb, any object that
holds information external to its own public or private variables
is a good candidate for not being allowed to be copyable.
For example, consider a class that is used to manage a record.
Object private variables might
be dependent on the contents of the record, but if you have multiple
instances of the object and the class updates the record, the private
variables in one instance could end up out of synch with the record due to
updates by another source.
- For an object to be copyable, all it's contained objects must
themselves be copyable.
The compiler ensures that if an object's class
contains an object member (or an object member contained in
that object member's “descendant objects,”)
whose class definition does not specify Allow Copy or Allow DeepCopy,
the original object is not copyable or deep-copyable, respectively.
- Allow DeepCopy does not imply Allow Copy.
However, inheritance permits an Allow Copy designated class to have its own
Copy method defined, and it permits an Allow DeepCopy designated class
to have its own DeepCopy method.
- For all Copy and DeepCopy methods (system or generic User Language),
the method object may be null
(internally, it is defined with the AllowNull keyword).
The output of a copy of a null object is a null object.
Copy methods in the Sirius system classes
Not all system classes provided by the Janus SOAP ULI support copy methods.
For example, the following classes do not support copy, typically because of their complexity or
their dependence on information that is not held in the objects themselves:
- Socket
- Daemon
- XmlNodeList
- File classes (Record, RecordSet, SortRecordSet, RecordSetCursor)
- HTTP Helper classes (HTTPRequest, HttpResponse)
- SMTP Helper (Email)
- LDAP objects
As described in the previous section, the presence or absence of
the Copy and DeepCopy methods in the system classes affects
the degree of copyability of any User Language classes that
contain objects of these system classes.
A User Language class that contains a Daemon object, for example, is not copyable.
A User Language class that contains a StringList, though, may be copied or
deep copied, subject to the copyability of the other members of the class.
The deep copyability of the individual Sirius system classes also determines the objects
that are eligible to be used with Sirius system Daemon objects.
Only objects that are deep copyable may be passed to and retrieved from
Daemon objects, which may be called by a User Language program to execute
commands on a separate thread.
DeepDiscard method
Prior to Sirius Mods Version 6.7, the Discard method was available in most
classes to explicitly discard an object variable's underlying object.
However, a Discard method would not necessarily discard all objects
referenced by the object being discarded if those referenced objects
either:
- had other references still around
- had a cycle in them (that is, object A references object B references object A)
To explicitly discard not only an object, but all objects referenced directly
or indirectly by that object, the DeepDiscard method is now available.
%object:DeepDiscard
A DeepDiscard method is not allowed against a class that is
declared with a Disallow Discard clause, or a class
that has direct or indirect references to a Disallow Discard class.
For most system classes, DeepDiscard works identically to Discard.
The exceptions to this are:
- XmlNode objects are allowed to be DeepDiscard'ed but are not allowed to
be Discard'ed.
When an XmlNode is DeepDiscard'ed, the underlying XmlDoc object is
discarded.
- When an XmlNodeList object is DeepDiscard'ed, not only is the XmlNodeList
object discarded, but so is the underlying XmlDoc object.
Booleans Usable in Logical Tests
Boolean enumeration values (True and False) are now usable in contexts
where they would be, well, logical.
For example, they are allowed as the condition in an If statement:
%recset is object recordSet in file sirfiled
...
find records to %recset
rectype = 'FILE'
end find
...
if %recset:isEmpty then
print 'No records found!'
end if
In the above example, the isEmpty method returns a Boolean enumeration value,.
that is, True or False.
Strictly speaking, the If clause expects a numeric zero or non-zero value as
its operand, but in this context Janus SOAP ULI now automatically converts
a True to a 1 and a False to a 0.
Other places where a Boolean value can be used, that is, where it's automatically
converted to the 0 or 1 that User Language expects are:
- As a Repeat statement operand.
- As an operand for a logical operator such as Not, And or Or.
This would usually be in an If or Repeat statement.
System and Subsystem methods for system-wide objects
Sirius Mods Version 6.7 adds methods to the Janus System and Subsystem classes
that make designated objects available to all users in an Online or of a subsystem.
Such objects, referred to as system-wide objects, are made available
via deep copy, so only deep copyable objects are eligible.
An object becomes system-wide if and only if it is saved by the System class
SetObject method or by the Subsystem class SetObject method.
If saved by the System class SetObject method, the “system” in system-wide
refers to all users in the Online; if by the Subsystem SetObject method, all
users in the current or a specified subsystem.
System-wide objects belong to a namespace that is not the same as
that for System and Subsystem longstrings.
That is, both a System longstring and a system-wide object may be called by the
same name at the same time.
The new methods are one System and one Subsystem class
version of each of the following:
- SetObject
- Makes an object available system-wide
with a specified name.
- GetObject
- Retrieves a copy of the specified system-wide object.
- DeleteObject
- Deletes the specified system-wide object.
- ListOfObjects
- Returns a StringList containing information about system-wide objects.
The ability to set and retrieve objects shared between all the users of a subsystem as well as
all users in an online provides a high-performance vehicle for sharing information, eliminating
the need to cordinate access to records in “work” files.
Internal parameter names
The InternalNames statement is now available to map
external parameter names (the names on the method declaration)
to internal ones (those used in the method code).
In the following example, the parameter
names %petrol and %oil are mapped
to internal names %parm.petrol and %parm.oil,
respectively:
subroutine add(%petrol is float nameRequired optional, -
%oil is float nameRequired optional)
internalNames
%parm.petrol is %petrol
%parm.oil is %oil
end internalNames
...
%private.petrol = %private.petrol + %parm.petrol
%private.oil = %private.oil + %parm.oil
The parameters are then used to update some (presumably) private
class variables.
Named parameters
Named parameters are now supported for both system and User Language methods.
For example, the ParseLines method in the StringList class has an
optional named parameter called StripTrailingNull:
%list:ParseLines(%string, stripTrailingNull=false)
Named parameters can be either name allowed (can be accessed by name, but don't have to be)
or name required (must be accessed by name).
For User Language methods, named parameters are indicated by the NameAllowed
and NameRequired keywords in the method declaration:
subroutine display(%customerId is string len 10, -
%startYear is float optional nameAllowed, -
%showFamily is enumeration boolean optional nameRequired, -
%showEmployer is enumeration boolean -
optional nameRequired, -
%showMedical is enumeration boolean -
optional nameRequired)
Such a method might be invoked as follows:
%company:display(%crn, 2002, showMedical=true,
showFamily=true)
or
%company:display(%crn, showMedical=true,
showFamily=true, startyear=2002)
Class statistics
The new OBJSTAT User 0 parameter controls the display of
journal messages that contain user statistics about Janus SOAP ULI object usage per request.
The messages specify server table usage (VTBL and STBL) and object-swapping counts per object
class and summed for all classes.
These messages provide information that allows one to tune the memory management
algorithms used by the Janus SOAP ULI.
You can set OBJSTAT to display object statistics after program compilation,
evaluation, or both.
OBJSTAT is a typical Model 204 bitmask parameter that is also
per-user and resettable.
It contains the following bit options, two or more of which you
can select by specifying the sum of their bit values:
- X'00'
- Display no OBJSTAT statistics; this is the default.
- X'01'
- Display post-compilation object statistics to the journal.
- X'02'
- Display post-evaluation object statistics to the journal.
- X'10'
- Display post-compilation object statistics to both the terminal
and the journal.
- X'20'
- Display post-evaluation object statistics to both the terminal
and the journal.
Note: X'22' is the same as X'20'; X'10' is the same as X'11'; and X'30' is the same as
X'31', X'32', or X'33'.
You can set OBJSTAT in the User 0 stream, and you can reset it
with the RESET command (for example, R OBJSTAT X'33')
or with the $RESETN function (for example, $RESETN('OBJSTAT', $X2D('33'))).
Compiler directives for modifying object server space allocation
Sirius Mods Version 6.7 adds the MaxObjects, MinObjects,
and AddObjects options to the Sirius compiler directive, which
adjust the number of Janus SOAP ULI objects for which VTBL/STBL space is allocated at
request compile time.
By default, that is, with no compiler directives specified, Janus SOAP ULI
scans a request for object references (like, object variable declarations), and
it allocates space for at most three (usually two) objects per class per request.
This ensures that only a small amount of server table space is used for objects,
and no object swapping occurs until more than two or three objects
in a class are instantiated at the same time.
This approach also prevents an exceptional,
object-heavy request from forcing server tables to be huge for all requests.
For an overview of object allocation, including the tools available for monitoring
and tuning, please refer to
Notes for Sirius Mods Version 6.7 or the
Janus SOAP Reference Manual.
New SIRCOMP parameter bits
The X'02' and X'04' bits of the SIRCOMP user parameter now control
what happens at end of procedure during a compilation:
- If the X'02' bit is set, and a compilation that was started inside
a procedure (the Begin statement was in a procedure) is still active
when the last Included procedure is closed (return to command prompt
on an interactive thread), the compilation is terminated with an error.
- If the X'04' bit is set, and a compilation that was started inside
a procedure is still active
when the procedure that contained the Begin is closed, the compilation
is terminated with an error.
Both these settings are intended to minimize the problems or annoyances
associated with a forgotten End statement in a User Language procedure, or, more
commonly, unmatched quotes resulting in an End statement being
“swallowed” as part of a literal (producing the classic
M204.1248: LOOKING FOR CLOSE QUOTE message).
A compilation ended because of the SIRCOMP X'02' or X'04' setting
also automatically closes any unclosed quotes or unclosed comment
blocks.
Janus SOAP Xml Classes
Several enhancements were made to the Janus SOAP Xml* classes (the XML API) in Version 6.7.
Audit and Trace methods
The Trace and Audit methods for XmlDoc and XmlNode objects are just
like the Print method: the result goes to the selected Trace stream
(like the Trace statement), or, as US lines, to the audit trail
(like the Audit statement).
The default indentation width on Print is 3; on Audit and Trace it is 1.
AdjacentText property
Janus SOAP now tolerates the following operations
if the value of the XmlDoc's AdjacentText property
is Combine:
- DeleteSubtree between Text nodes
- AddText applied to an Element whose last child is a Text node
- InsertTextBefore applied to a Text node
- AddSubtree and InsertSubtreeBefore applied to a source subtree that is a Text node
When one of these operations occurs, the values of the Text nodes are combined to form a
new Text node which takes the place of the former Text node(s), which is (are) deleted.
This node deletion, as is typical, also causes any XmlNode or XmlNodelist pointers to the
former Text nodes to be set to Null.
The default value of AdjacentText is Disallow, which continues the same behavior
(request cancellation) that occurs with these cases in version 6.6 of the Sirius Mods.
XmlDecl option on Serial method
The Serial method now allows the string XmlDecl
as one of the options in its second argument.
When this option is present, the serialized XmlDoc will contain the “XML
Declaration” (), if the value of the Version property
is not the null string.
Note that this option may only be specified if the top of the subtree being
serialized is the Root node.
LoadParameterInfo method
This new XmlDoc class method populates an XmlDoc with information about one or more
Model 204 parameters.
Call %doc:LoadParameterInfo([paramOrClass], [classOrParam])
Where:
paramOrClass is either one of the following options,
and classOrParam is the other:
- A pattern used to select matching parameters,
- One or the combination of both of the strings Base and Sirius.
Sirius indicates that information about matching Sirius Mods parameters is obtained.
Base indicates that information about the “base”
(that is, not created by Sirius) Model 204 parameters is obtained.
Both arguments of this method are optional, default to the null string, and
leading and trailing blanks and case are ignored.
Either argument option (parameter pattern
or Base/Sirius string) can be specified first.
For both types of argument, a null string
indicates that all of the respective items are processed.
For the parameter-match pattern, an asterisk
also indicates that all of the respective items are processed.
The information is returned in an XmlDoc, with element and attribute names which, together with
explanations in the Model 204 Command Reference Manual, should be evident.
WspNewline option for deserialization
Whitespace handling has changed in the following, which are the methods
that parse an XML document from its serialized form into the internal
XmlDoc data structure.
Except where noted, these all have an XmlDoc as
the method object:
- LoadFromStringlist
- LoadXml
- ParseXml (in the HttpResponse class)
- WebReceive
The changes are as follows:
- A new algorithm is used for the default handling of whitespace during
deserialization.
This algorithm can also be specified using the WspNewline option.
The purpose of WspNewline is to remove the whitespace that was inserted
to make the structure of an XML document easier (for a person) to read.
The operation of WspNewline is to remove that leading or trailing whitespace
in the value of a Text node, if the sequence contains a carriage return
or linefeed character.
- Stripping of all leading and trailing whitespace, and conversion of
each sequence of whitespace to a single space, is the behavior obtained
with the WspToken option.
This behavior was formerly specified with the WspNorm option;
that option keyword is no longer available.
WspToken was formerly the default for the deserialization methods,
but it no longer is.
The new default is WspNewline.
Character references for serializing whitespace
Serialization of the tab, carriage return, and linefeed characters
has changed (depending on the method and the node type) to use
character references as specified in the XML Canonicalization specification
(http://www.w3.org/TR/xml-c14n).
The EBCDIC and corresponding ASCII encoding of these characters is:
| character name | EBCDIC value | ASCII value |
| tab | X'05" | X'09" |
| carriage return (CR) | X'0D" |
X'0D" |
| linefeed (LF) | X'25" |
X'0A" |
When an Attribute node is serialized, a character reference is used for
all of these characters, as follows:
| character name | character reference |
| tab | 	 |
| carriage return (CR) | 
 |
| linefeed (LF) | 
 |
Also, when a Text node is serialized with the Print method, these same
character references are used for all of these characters.
When a Text node is serialized with the non-debugging serializers,
only CR is serialized (as above) using a character reference.
The non-debugging serializers are:
| method name | class name(s) |
| Serial | XmlDoc and XmlNode |
| WebSend | XmlDoc |
| Xml | XmlDoc |
| AddXml | HttpRequest |
Support for xml:space attribute
The xml:space attribute is now allowed, and the meaning of this attribute
is honored in serialization and deserialization methods.
LoadFromStringlist newlines
The LoadFromStringlist method now inserts a newline character after
each item in the StringList as part of concatenation prior to deserialization.
This newline is usually removed (as leading or trailing whitespace)
by the method's whitespace handling options.
However, if Text node values are split between successive StringList items,
if xml:space="preserve" is in effect, or if WspPreserve is
used to deserialize the Stringlist, the newlines are not removed.
Improved XPath and other performance after some XmlDoc updates
There are some XPath expressions (for example, '//someElement/anotherElement')
and some methods (for example, Difference) whose performance can be affected by the
order in which nodes were added to the XmlDoc.
In some cases, the extra CPU and DKRD consumed for this is necessary for the
Janus SOAP algorithms.
In other cases, the structure of an XmlDoc doesn't actually require extra CPU
and DKRD, but the heuristics used by Janus SOAP are not able to detect this.
In version 6.7, many cases that formerly used extra CPU/DKRD are now
handled more efficiently; that is, these Janus SOAP heuristics have improved.
Janus SOAP StringList Class
The following sections describe changes in the Janus SOAP StringList class
made in Version 6.7.
ParseLines and CreateLines methods
These methods facilitate moving line-end character delimited data
(as typically exists on most non-EBCDIC systems) to StringLists
and vice versa.
Since line-end delimited data typically comes from non-EBCDIC hosts,
these methods are most likely to be used in applications that
communicate with such hosts, such as Janus Web Server and Janus Sockets applications.
The ParseLines method takes as input a longstring and an optional
line delimiter set, and it breaks the longstring up into StringList items,
using the indicated delimiters as the line separators.
For example, the following method loads the names of three popular sandwich
contents onto separate StringList items:
%contents is object stringList
...
%contents:parseLines('Bacon/Lettuce/Tomato', ' /')
The space before the slash character, is the delimiter-set delimiter
character (got that?), that is, the character used to separate multiple
delimiters, should there be more than one.
As this example illustrates, the ParseLines method can be used for
general-purpose parsing, though this was not really its intent, and
it is somewhat limited for this purpose.
The main use of ParseLines is expected to be in parsing text received into a
longstring via $web_input_content, $web_file_content, or
$web_output_content.
As such, the default delimiter set for the ParseLines method is
X'0D', X'25', and X'0D25' (the EBCDIC carriage-return,
line-feed, and carriage-return/line-feed characters).
The CreateLines method is the inverse of ParseLines: it takes the
contents of a StringList and converts it into a line-end character
delimited string.
In the following example, the contents of stringList %sendData are sent over a
Janus Sockets connection (using a Socket object) as line-feed delimited lines:
%sock is object socket
%sendData is object stringList
...
%sock:send( %senddata:createLines($x2c('25')) )
In this example, the delimiter parameter ($x2c('25'))
was really unnecessary because it is the default.
In this example, one would presume that the socket is in CHAR mode,
that is, data is being translated from EBCDIC to ASCII.
Obviously, the CreateLines method does nothing that couldn't
be done quite easily in User Language — it is just a little more convenient
and efficient.
BinaryProcedureEncode and BinaryProcedureDecode methods
These methods facilitate converting data in a longstring into
the format used for storing binary data in procedures by Janus Web Server.
This format is necessary if binary data is to be stored in
Model 204 procedure files, because standard procedure formats are
not amenable to storing binary data.
The BinaryProcedureEncode method takes data from a longstring
and places it on a StringList, from which it could then be
stored in a procedure.
In the following example, a GIF (graphical image) is retrieved
from another web server using a Janus Sockets HTTP Helper request, and
then it is moved onto a StringList with the special binary procedure
encoding:
%req is object httpRequest
%resp is object httpResponse
%gif is longstring
%procData is object stringList
...
%resp = %req:get
%gif = %resp:content(1)
%procData = new
%procData:binaryProcedureEncode(%gif)
The actual saving of the data to a procedure is not shown.
The BinaryProcedureDecode method is the inverse of
BinaryProcedureEncode: it takes the contents of a StringList
in the Janus Web Server binary procedure encoding and converts it to
a longstring.
In the following example, a GIF is sent to another web server
from a Model 204 procedure:
%req is object httpRequest
%resp is object httpResponse
%gif is longstring
%procData is object stringList
%rc is float
...
%rc = $procopn('MONKEY.GIF', 'IMAGES')
%procData = new
%procData:appendOpenProcedure
%gif = %procData:binaryProcedureDecode
%req = new
%req:multiPartFormEncoding = true
%req:addField('IMAGE', %gif)
...
%resp = %req:post
AppendJournalData method
The AppendJournalData method is an object-oriented replacement for $SIRJGET and
is only available to customers licensed for SirScan.
Janus Sockets
Version 6.7 of the Sirius Mods continues the trend of adding high-level
object-oriented APIs for common protocols based upon TCP/IP.
These APIs require that a customer be licensed for both Janus Sockets
and Janus SOAP.
Named parameters on New constructor for Socket object
All but the first parameter (the client port name) for the Socket object New constructor
are now Named parameters (parameters passed by name rather than position).
The following example illustrates the use of named parameters on the New constructor to create
a new socket instance and to connect it to Sirius Software's secure web site:
%socket is object Socket
%socket = new(host='sirius-software.com', port=443, ssl='SSL')
The LDAP Helper
The Lightweight Directory Access Protocol (LDAP) is a a standardized protocol
(based upon Internet RFC 1777) for retrieving information from a directory service.
LDAP clients can be used to validate identity and retrieve personalization
information from a directory service.
Virtually all commercial directory systems, such as Microsoft's Active Directory
or IBM's Security Server support LDAP access.
The LDAP Helper for Janus Sockets is a high-level, object-oriented interface to
client sockets that simplifies writing LDAP clients in User Language.
It requires no understanding of socket level programming or the format of LDAP requests and responses.
The LDAP Helper methods allow a User Language program to act as an LDAP client
to access and retrieve directory information through an LDAP server.
The LDAP server may be running on any platform to which
the LDAP client online can make a TCP/IP connection.
Detailed information on how to use the LDAP Helper may be found in the
Janus Sockets Reference Manual.
Feature summary
The Janus LDAP Helper provides the following capabilities:
- Read access to X.500 and LDAP v2 directory services.
- One-step connection and login to an LDAP server
(with user ID and password passing as well as also anonymous logins).
- Multiple search filters, each in a separate method.
- Text-only retrieval: all returned data is automatically
converted from ASCII to EBCDIC.
- Automatic deserializing of returned data into XML in an XmlDoc object.
- A limit of approximately 1300 bytes to the data sent in or returned from
a single query of the server.
- Optional retrieval of only the directory entry attribute names, that is,
the names without the corresponding attribute values.
- Optional SSL (Secure Sockets Layer) data transmission.
The following LDAP features are not currently supported by Janus LDAP:
- Kerberos user logins.
- Modifying, deleting, or adding directory content.
- Full compliance with LDAP v3 (for example, UTF-8 is not supported).
- Arbitrary, user-constructed search queries
(RFC 1960 syntax featuring boolean operators is not supported).
- Restart of aborted transfers.
- Limiting the quantity of the server data returned or
the number of entries returned.
Using the LDAP Helper
The Helper makes the information in LDAP directories
more easily accessible by removing LDAP protocol concerns from
the programmer.
To retrieve data from an LDAP server, applications must:
- Define a Janus CLSOCK port.
- Use the JANUS DEFINE command to
- Create a TCP/IP port for your Model 204 LDAP client application.
- Indicate the remote LDAP server identifier and port number
(or a pattern that allows the specific server to be specified
by an Ldap class method).
- Set a timeout value for the LDAP connections.
- Use the JANUS NAMESERVER command to let you reference remote hosts by name
rather than IP address.
- Use a JANUS CLSOCK command to specify access rules for your port.
- Use the JANUS START command to start your port.
- Bind a connection and log in to an LDAP server (in your User Language request,
a single Bind method statement performs these actions).
- Send a search query to the LDAP server, using one of the multiple Find methods, which provide
a variety of search filters.
- Optionally, extract particular data from the data returned from the LDAP server,
using the Janus SOAP XML Api.
- End your session when ready, using the Unbind method to log off from the
LDAP server and deactivate the connection.
The SMTP Helper
The Simple Mail Transfer Protocol (SMTP) is a a standardized protocol
(based upon Internet RFC 821) for transfering mail from a client application
to a store and forward mail server.
SMTP standardizes the plumbing between all e-mail services and is one of the
most pervasive protocols of the Internet.
The SMTP Helper for Janus Sockets is a high-level, object-oriented interface to client
sockets that simplifies composing and sending e-mail messages from User Language programs.
It requires no understanding of socket level programming or the format of SMTP requests and responses.
The SMTP Helper methods allow a User Language program to act as an SMTP client
to compose and forward e-mail messages and attachments through an SMTP server.
The SMTP server may be running on any platform to which the SMTP client online can make a
TCP/IP connection.
Detailed information on how to use the SMTP Helper may be found in the
Janus Sockets Reference Manual.
Feature summary
The Janus SMTP Helper provides the following capabilities:
- Creating and sending general purpose e-mail for SMTP.
- Setting e-mail content using longstrings or stringlists.
- Sending MIME content (attachments and alternative content).
- Sending to multiple recipients.
- Access to status (error or confirmation messages).
- Automatic translation between ASCII and EBCDIC character encodings.
Using the SMTP Helper
The SMTP Helper makes it easy to send mail messages by eliminating the
need for programmers to know the communication protocol required to relay
messages to an SMTP server.
To send e-mail to an SMTP server, applications must:
- Define a Janus CLSOCK port.
- Use the JANUS DEFINE command to
- Create a TCP/IP port for your Model 204 SMTP client application.
- Indicate the remote SMTP server identifier and port number (or a pattern that allows
the specific server to be specified by an SMTP class method).
- Set a timeout value for the SMTP connections.
- Use the JANUS NAMESERVER command to let you reference remote hosts by name
rather than IP address.
- Use a JANUS CLSOCK command to specify access rules for your port.
- Use the JANUS START command to start your port.
- Create an e-mail request using the SMTP methods.
In your User Language request, you must instantiate an e-mail object, then add
headers, content, and attachments using the SMTP methods.
- Send the e-mail object to an SMTP server with the mail method.
The mail method connects to the SMTP server, forwards the mail object,
closes the connection, and returns the status. The programmer does
not need to manage the communication connection.
The SMTP methods
- AddBcc subroutine
-
This callable method adds a "blind carbon copy" recipient to an instantiated email object.
- AddCc subroutine
-
This callable method adds a recipient to an instantiated email object.
An email must have at least one recipient before it can be sent with the mail method.
- AddRecipient subroutine
-
This callable method adds a recipient to an instantiated email object.
- AddHeader subroutine
-
This callable method adds a header to the instantiated email object.
No validation is performed on the header name or its value, except that content
headers are not allowed.
"Content-" headers are automatically added whenever either of the SetBody or AddPart methods are invoked.
- Port property
-
This settable property sets or gets the value of the TCP port number
for the e-mail object.
- Host property
-
This property sets or gets the value of the TCP host name for the e-mail object.
- Mail function
-
This function forwards the e-mail content to an SMTP server and
returns a value indicating the status of the operation.
- SetBody subroutine
-
This subroutine sets the content for the main body of the e-mail.
Optional named parameters allow control of the MIME type of
the content and base-64 encoding.
- AddPart subroutine
-
This subroutine adds an attachment to the e-mail object.
Optional named parameters control the MIME type of the content, base-64 encoding,
and a name for the attachment.
- GetReplyCode subroutine
-
This function returns the numeric code of the most recent response from the mail server.
If the mail method has not yet been invoked, the reply code will be zero.
- GetReplyText subroutine
-
This function returns the character string associated with the most recent
response from the mail server.
If the mail method has not yet been invoked, the reply string will be null.
Janus Web Server
$web_put_text and $web_put_bin are longstring capable
$web_put_text and $web_put_bin now accept and correctly process longstring inputs.
This is a sight backward incompatibility with previous versions.
In addition, $web_put_binary has been introduced as a synonym for
$web_put_bin.
New longstring $Web Parameter $functions
Longstring versions of many of the standard $web parameter $functions have been added.
Since these $functions return longstrings, they do not have a starting position
and length parameter — substringing can be accomplished with standard longstring $functions.
The new $functions are:
- $web_parm_lstr
- Corresponds to $web_parm.
- $web_hdr_parm_lstr
- Corresponds to $web_hdr_parm.
- $web_form_parm_lstr
- Corresponds to $web_form_parm.
- $web_isindex_parm_lstr
- Corresponds to $web_isindex_parm.
An error was also found in $web_get_cookie_lstr — it allowed but ignored a third and fourth parameter.
This error was fixed, but it introduced a backward incompatibility.
New URL_parm equivalents of ISINDEX functions
The term “isindex” has largely fallen into disuse, but the
Janus Web Server $functions still use this term.
While there is no “official” term for what are called
Isindex parameters in the Janus Web Server $functions, the most common
term in the industry seems to be “URL parameters.”
For compatibility with more widely used terminology, there are
now URL_parm equivalents of the Isindex functions:
- $web_num_url_parm
- Corresponds to $web_num_isindex.
- $web_url_parm
- Corresponds to $web_isindex_parm.
- $web_url_parm_len
- Corresponds to $web_isindex_parm_len and $web_isindex_len.
- $web_url_parm_line
- Corresponds to $web_isindex_parm_line and $web_isindex_line.
- $web_url_parm_lstr
- Corresponds to $web_isindex_parm_lstr.
- $web_url_parm_name
- Corresponds to $web_isindex_name
- $web_url_parm_num_line
- Corresponds to $web_isindex_parm_num_line and $web_isindex_num_line.
Note that the shortened versions of some of the Isindex $functions (for
example, $web_isindex_len for $web_isindex_parm_len) are not provided
with Url equivalents.
This is because they sounded a bit confusing, since the URL has meaning
independent of the URL parameters.
For example, one might expect $web_url_len to be the length of the
URL, not the length of a URL parameter.
RAWINPUT port definition parameter
A new Janus Web Server port definition parameter, RAWINPUT,
tells Janus Web Server to save the raw input stream for an HTTP Post,
regardless of the mime-type set by the client.
This has two basic advantages:
- The raw input content for an HTTP Post is always available
to Janus Web Server applications (via $web_input_content) regardless of the mime-type.
This could be useful for debugging or perhaps for logging input content.
- Janus Web Server can interact correctly with clients that don't set the mime type,
regardless of what these clients send.
For input with no mime-type set, Janus Web Server assumes that
the content is application/x-www-form-urlencoded (form
Post) encoded.
Prior to RAWINPUT, if Janus Web Server discovered, after reading some of the input
content, that the client sent data in some format other than
application/x-www-form-urlencoded encoding (say,
XML format). it was too late, and the request was
rejected for having an invalid format.
With the RAWINPUT parameter set, Janus Web Server first loads the input content
into CCATEMP, and then, if the mime type is set to
application/x-www-form-urlencoded or not set at all, determines
if it has the application/x-www-form-urlencoded format.
If not, the request is not rejected, and the Janus Web Server application
can still access the data (which is likely to be XML format).
RAWINPUTONLY parameter for JANUS WEB ON rules
A new Janus Web Server ON rule parameter, RAWINPUTONLY, tells Janus Web Server
to save the raw input stream for an HTTP Post, regardless of the Post data content-type
set by the client, and to not parse the input content into form fields, regardless of the
Post data content-type.
This is very similar to the port definition RAWINPUT parameter with the exception that:
- It's an ON rule parameter so can be set for specific URLs.
- The port definition RAWINPUT parameter does not prevent
Janus Web Server from trying to parse the form parameters if the content-type
for the Post was set to application/x-www-form-urlencoded
or multipart/form-data.
RAWINPUTONLY prevents this parsing, so protects Janus Web Server applications
from errors in this parsing. These errors include invalid form data
errors and request buffer full errors.
The RAWINPUTONLY parameter for JANUS WEB ON rules is, perhaps, most useful
for allowing requests with a large number of parameters to be processed
without having to allocate an extremely large request buffer to hold
all the posted parameters.
In fact, if there are enough form parameters, the maximum request
buffer size (65535 bytes) might not be sufficient to hold all the
form data in a post.
In such a case, the RAWINPUTONLY parameter is the only way to
prevent the request from failing with an
MSIR.0353 Insufficient Web request buffer space
If the RAWINPUTONLY parameter is in effect for a URL, the form fields
are no longer available with the $Web_form and $Web_parm functions (that is,
functions that begin with these words) though the $Web_parm, $web_isindex,
and $web_url_parm functions can still be used to access URL parameters.
When using RAWINPUTONLY, the only way to process the form parameters is
by retrieving the form parameters into a longstring using the
$Web_input_content method.
To separate the various parameters, this longstring must then be parsed
and (usually) URL decoded.
If the Post used the default form data encoding of
application/x-www-form-urlencoded then each parameter/value
pair is separated with an ampersand (&).
Processing is considerably more complicated if the encoding is
multipart/form-data.
For Janus SOAP customers, the StringList class ParseLines method provides
a simple, efficient way of parsing a form parameter list with
application/x-www-form-urlencoded encoding:
%formParms is object stringList
...
%formParms = new
%formParms:parseLines($web_input_content('TEXT'), ' &')
This produces a StringList that contains items of the format
fieldname=value.
Assuming that none of the form field names have been URL encoded by
the browser (a reasonable assumption for most latin character field
names), this StringList is in a format that can be easily, though
not prettily, searched.
For example, the following code locate's the field named OrderNumber:
%itemNum = %formParms:locate('Order=', , 1, 6)
There are some things worth noting here:
- The search is case sensitive, though the Locate method does have
a case-insensitive search flag.
Fortunately, almost all browsers return form field names in the case
that was specified in the <input> tags.
Still, the case-insensitive search parameter could be set for Locate if needed.
- The equals sign is specified to prevent accidental matches on other
fields that begin with Order, such as, say, OrderDate.
While it can be left off if the programmer is confident there won't
be such accidental matches, this is not recommended.
- The column range is also specified to prevent accidental matches.
While an equals sign should be URL encoded by the browser, and so an
“Order=” in a value (encoded as “Order%3D”) should
not cause an accidental match, one could still get an accidental match with, say,
“PreviousOrder=”.
Specifying the column range has the side-benefit of making the search more
efficient by limiting it to the start of each StringList item.
For form field names that are used more than once on a form, the values
beyond the first would need to be retrieved by specifying a starting
item number (second) parameter on the Locate method.
Once the desired item number is located, the next step is to retrieve the value.
In the case of a field name with a known length, this can be done easily
with the Item method and the $lstr_substr function:
%itemNum = %formParms:locate('Order=', , 1, 6)
%order = $lstr_substr(%formParms:item(%itemNum), 7)
Unfortunately, the value in %order above will be URL encoded, that
is, spaces will be replaced by pluses and any special characters
(such as ampersands or equals signs) will be encoded with a percent
sign followed by the hexadecimal value of the ASCII code.
For example, the string “90% = 9/10” would be encoded as
“90%25+%3D+9%2F10”.
Even more unfortunately, Janus Web Server does not provide a URL decode
function (there is a $Web_URL_encode to do URL encoding),
so URL decoding must be done in User Language.
Fortunately, such decoding could be easily packaged up in a
method or complex subroutine.
The following illustrates a shared method in a class called URL
that performs this decoding:
class URL
public shared
function decode(%value is longstring) -
is longstring
end public shared
function decode(%value is longstring) -
is longstring
%pos is float
%value = $lstr_translate(%value, ' ', '+')
%pos = 1
repeat forever
%pos = $lstr_index(%value, '%', %pos)
if not %pos then
loop end
end if
%value = $lstr_substr(%value, 1, %pos - 1) with -
$ebcdic($x2c( -
$lstr_substr(%value, %pos + 1, 2) -
)) with -
$lstr_substr(%value, %pos + 3)
%pos = %pos + 1
end repeat
return %value
end function
end class
With this function available, the value in %order in the
previous example can be easily URL decoded:
%itemNum = %formParms:locate('Order=', , 1, 6)
%order = $lstr_substr(%formParms:item(%itemNum), 7)
%order = %(url):decode(%order)
Subsequent releases of the Sirius Mods will provide a native URL decode function,
as well as other $functions or methods to simplify processing form parameters
in an application using RAWINPUTONLY.
$web_input_content and $web_output_content functions
These two new functions make it possible to examine either the input content
sent by the client or the output content currently in the Janus Web Server output
stream.
Both these $functions return content as a longstring, which can
subsequently be parsed and/or logged.
$web_input_content can be used to examine data from the client in the following
situations:
- An HTTP Put.
- An HTTP Post, if the mime-type is set to something other than
application/x-www-form-urlencoded or multipart/form-data.
- Any HTTP Post, if the RAWINPUT parameter is set on the port definition.
$web_output_content can be used to examine the following:
- Data in the Janus Web Server output stream
resulting from Print or Html/Text statements when web capture is on ($web_on).
- Data resulting from $web_proc_send.
$web_output_content cannot examine output data in these cases:
- After a $web_done
- After a $web_proc_send without the MORE parameter
- After a $web_flush
Both $web_input_content and $web_output_content take a single, string, input
parameter, which can be set to Binary or Text to indicate
whether data is to be left untranslated or to be translated from ASCII to EBCDIC
(as text is almost certain to use ASCII encoding).
$web_output_type function
This function makes it possible to determine the current output
mime-type setting set by either JANUS WEB ON rules or by the $web_type function.
It might prove useful for determining the meaning of the contents of
the output stream in code that is shared among many applications, though
of course, it is highly dependent on those applications having already set $web_type.
$web_file_content function
This new function is introduced to make it possible to load the contents
of a file (in a multipart form file upload) to a longstring.
This has several advantages over the existing techniques
($web_proc_receive and $web_list_receive) for loading
multipart form file data:
- It is freed of the line-length issues that were problematic for the old functions.
- It provides the uploaded file in exactly the format in which it is stored
on the client, in a format that is easy to manipulate (string versus the
awkward, binary encoded, procedure format used by the old functions).
This gives a Janus Web Server application complete control over how the
file is manipulated.
- If the uploaded file is XML, it is in a very convenient format
to be passed to the Janus XML API.
- It facilitates the use of the StringList API rather than the
old-fashioned $list API.
$web_file_content can be used to retrieve file content as text (translation
from ASCII to EBCDIC), or binary (no translation).
Binary is the default.
In the following example, the file associated with the form field MYXML
is loaded into a longstring and then loaded into an XmlDoc object:
%xml is longstring
%doc is object xmlDoc
...
%xml = $web_file_content('MYXML')
%doc = new
%doc:loadXml(%xml)
Note: $web_file_content, as well as its close kin $web_input_content and $web_output_content,
are ideal for use with the new StringList methods ParseLines and BinaryProcedureEncode.
SirFact
The following sections present an overview of the changes made to SirFact to support the
new object-oriented facilities provided by the Janus SOAP User Language Interface.
For more detailed information refer to the
SirFact Reference Manual.
Displaying structures and objects in FACT
To the existing support for displaying Janus SOAP XML system class
objects, Version 6.7 adds support for displaying class members from
any system or user-class object.
Note:Some existing FACT syntax is changed by this enhancement.
The format for displaying the contents of a structure variable or of a
Janus SOAP system or user class member (variable or method) is as follows:
D %object:member[(parms)]
This format is very nearly the same as the format used in a User Language program to
access the objects.
Some examples follow:
- D %MG:MILEAGE
- Displays the value of a (user class) public or private variable:
the content of class variable MILEAGE, when %MG is a user class object.
Or, it displays the value of variable MILEAGE in structure %MG.
Note:
If MILEAGE were a shared variable in class CAR, it could also be displayed by the following command:
D %(CAR):MILEAGE
This use of the class name in parentheses instead of an object variable
is valid for system class as well as user class shared variables,
but it is not valid for structure variables.
- D %RS:COUNT
- Displays the value of a system class member: the return from the Count
method, when %RS is a RecordSet object variable, for example.
- D %SL:ITEM(5)
- Displays the value of a system class member: the return from the Item method
applied to the fifth item, when %SL is a StringList object variable,
for example.
- D %NAMES('Bush'):FIRSTNAME
- Displays the value of a (user class) NamedArrayList collection method:
the content of the return from the FIRSTNAME
method, when %NAMES('Bush') is a NamedArrayList collection item.
- D %NAMES('Bush')
- ST:COUNT
- Displays the value of strung-together class
members: the content of the return from the COUNT
method, when %NAMES('Bush') is a NamedArrayList collection item of a user class,
and LIST is a variable that is a StringList object.
- D %DOC
- Displays the value of an object variable: the content of %DOC,
when %DOC is an instance of a system XmlDoc object.
The information displayed always
includes whether or not the %variable is Null.
If the object is not Null,
the output from the Print method applied to
the object is automatically included
(for some classes, such as the StringList class or the XmlDoc class).
For an XmlNodeList object variable, for example, which has no Print method
in its class,
the FACT display simply includes whether or not the variable is Null.
As an example, if %L is a StringList object,
a d %l command might produce:
%L = Not null
%L:PRINT = 'This is a test 1'
= 'This is a test 2'
= 'This is a test 3'
This example also demonstrates that the SirFact display
Note:
Some methods that produce terminal output (such as most Print methods or, for example, the Janus
SOAP XML Serial method) can be invoked explicitly in the DISPLAY command.
For example, if %xmlPier is an XmlDoc object, the following
commands will provide the same information:
D %XMLPIER
D %XMLPIER:PRINT
Advantages of invoking a Print method explicitly include:
Although object contents can be accessed from SirFact very much the
same as they are accessed in User Language, the following restrictions apply:
- The special range, count, and wildcard syntaxes supported for some
other display types are not supported for objects.
For example, to request the display of the first three items in StringList %SL,
you cannot use D %SL(1-3).
You can get the result you want, however, by using StringList Print
method parameters, as in:
D %SL:PRINT(,,1,3)
- Not all system methods may be invoked in a DISPLAY command.
In general, methods that update an object
or that create a new object instance are not allowed.
For example, if %SL is a StringList object, the following is
not allowed:
D %SL:ADD('A new item')
New SirFact $function: $FACT_OPTION
The $FACT_OPTION function is used to set or get the values of options
that affect the retrieval and display of $FACT_DATA output.
$FACT_OPTION accepts two arguments and returns a numeric code or a string.
- The first parameter, which is required, is the name of the option
that is being updated or retrieved.
Current options are:
- CASE
- Controls whether $FACT_DATA internally uppercases
all non-quoted characters in its arguments before processing.
Such auto-uppercasing provides case-insensitivity and mimics the way
mixed-case User Language is supported.
Prior to Sirius Mods Version 6.7, $FACT_DATA respected the case of its arguments; that is,
it performed no automatic uppercasing.
Valid CASE values are LEAVE (do not uppercase) and
TOUPPER; TOUPPER is the default.
LEAVE is useful for accommodating dumps created from code compiled with case-sensitive User Language,
if case-sensitivity is necessary.
Case-sensitive User Language is enabled by starting a User Language program with an all-uppercase
Begin statement or by specifying the Sirius compiler directive Sirius Case Leave.
Note:
Prior to Sirius Mods Version 6.7, the FACT subsystem uppercased all data
passed to $FACT_DATA (which processes FACT system DISPLAY commands).
However, this meant that mixed-case method arguments were also uppercased
before $FACT_DATA processing
(for example, d %myXmlDocrint('/outer/inner')
,
became D %MYXMLDOC:PRINT('/OUTER/INNER')).
In Version 6.7, this FACT subsystem uppercasing is replaced by the
$FACT_DATA uppercasing (which correctly processes the example command as
D %MYXMLDOC:PRINT('/outer/inner')).
The option to change the default case handling is not available to
FACT subsystem users.
- IMPLIM
- Sets the limit for the number of lines that $FACT_DATA
can output for the implied-Print of an object variable's content.
An implied Print is an automatic invocation of the Print method
for the display of the content of an object variable
for those object classes for which such printing is enabled.
Valid IMPLIM values are numbers between 1 and 99999999.
The default is 500.
- The second $FACT_OPTION parameter
is an optional new value for the option you specify as the first argument.
If you specify a value for this parameter that changes the current
setting of the first parameter, the
$FACT_OPTION return depends on whether you are changing CASE or IMPLIM:
- If CASE is changed successfully, the return code is 0.
- If IMPLIM is changed, the return is the previous value of IMPLIM.
Assert Statement Enhancements
The Assert statement has been enhanced in two ways.
- A %variable in the Info clause is now interpreted to
mean the contents of the indicated variable.
Before this release, an unquoted %variable name was interpreted as a
literal, that is something like the following:
assert %x = 22, info %x
would simply display
MSIR.0494: Assert info: %X
Under this release, the Assert info: above would be followed
by the value of %x.
Note:
If %x is not a valid %variable name, the above would
produce a compilation error, so this new feature is a backward incompatibility.
- A Continue keyword on an Assert statement indicates that
an assertion failure should produce a message and possibly, a SirFact dump, but it should
not cause the request to be cancelled.
That is, the request should continue after the Assert statement did whatever it had to do.
The following statement illustrates the use of the Continue keyword:
assert %income gt 10000, continue
Sirius Functions
User buffer functions
Model 204 V6R1.0 introduces support for Large Object data, which can be
passed via the Universal Buffer and/or the MQ/204 Interface.
Sirius Mods 6.7 provides support for Sirius longstring $functions you can use
to work with Large Object (LOB) data.
For Versions of Model 204 prior to 6.1, the new $functions apply only to
the MQ user buffer, and they require the MQ/204 feature.
For Model 204 Version 6.1 and after, the user buffer may also be a
Universal Buffer for LOB data.
The Universal Buffer is a one-per-user, temporary storage area that, like the MQ buffer,
automatically expands to accommodate its data contents.
Unlike prior Versions, the MQ buffer in Model 204 6.1 also becomes a
one-per-user buffer.
The following function returns to a longstring the contents
of the current user buffer (Universal Buffer or MQ/204 user buffer):
%lstr = $lstr_get_userBuffer
Any errors during the transfer of the buffer contents result in request cancellation.
The following function sets the current user buffer to the value of the longstring argument:
%len = $lstr_set_userBuffer(longstring)
%len is the resulting length of the buffer data in bytes, or it
is -1 to indicate an error.
If the buffer has to be expanded to accommodate the longstring,
its length is increased in increments of 4096 bytes (one page).
Any errors during the transfer of the longstring result in request cancellation.
The following function adds the value of its longstring argument to the contents
of the current user buffer.
Data insertions into or deletions from the buffer are not allowed in Model 204 6.1.
%len = $lstr_add_userBuffer(longstring)
The return value, resizing, and error handling are the same as $lstr_get_userBuffer.
$SIRJGET modification
Previously, $SIRJGET retrievals stripped all blanks at the start of an audited line.
They are no longer stripped.
Also, XX lines are combined, so in particular, long user audit entries that had been split
into a US line and one or more XX lines are now displayed just as a US line (with SirScan style
continuations: no timestamp/etc./audit type prefix).
Note:
This change will be reflected in the display of audit trail entries by SirScan.
$GZIP and $GUNZIP functions
The $GZIP and $GUNZIP functions allow compression and decompression of
longstrings:
- $GZIP returns a compressed longstring in the format defined by RFC1952.
- $GUNZIP decompresses a string compressed by $GZIP or any other
RFC1952 compatible compressor.
$GZIP and $GUNZIP can be used with the SMTP helper to attach compressed files to e-mail documents.
SirLib
New $function: $PROC_TOUCH
$PROC_TOUCH lets you change the date/time stamp
of a procedure as well as the account ID of the last updator.
SirMon
A number of statistics were added or modified for Version 6.7.
Most of the new statistics are for monitoring the Large Objects
and Table E added in Model 204 Version 6.1.
The following functions were affected:
- $FISTAT and $FISTATL
- $USSTAT and $USSTATL
- $SYSTAT
SirScan
New StringList class method: AppendJournalData
The StringList class now has an AppendJournalData method, which
is the object-oriented equivalent of $SirJGet.
The AppendJournalData method has four NameAllowed parameters that
exactly correspond to the second through fifth $SirJGet parameters.
Their names, respectively, are StartTime, EndTime,
Threads, and Options.
SirSafe
Changes in Version 6.7 include:
- The information displayed by AUTHCTL VIEW has been enhanced
to better support the monitoring and
management of shared DASD enqueueing within Model 204.
- A system manager may now start and stop any application subsystem without
requiring “subsystem manager” authority for the subsystem.
This enables users to eliminate SCLASSes for many subsystems,
which typically improves performance.
- The SirSafe Reference Manual
has been thoroughly rejuvenated.
Backwards Incompatibilities
In general, backward incompatibility means that an operation which was
previously performed without any indication of error, now operates, given
the same inputs and conditions, in a different manner.
We may not list as backwards incompatibilities those cases in which the
previous behaviour, although not indicating an error, was “clearly and
obviously” incorrect, and which are introduced as normal bug fixes
(whether or not they had been fixed with previous maintenance).
For more information on these backwards incompatibilities, please refer to the
Sirius Mods Release Notes V6.7.
Janus SOAP XML processing
The following backwards compatibility issues have been introduced in the
Janus SOAP Xml* methods.
Prohibit childNumber arg when inserting Text node
In version 6.7 of Janus SOAP, the $Xml_InsText function does not allow a
“child number” argument.
Also, the $Xml_Cop function does not allow a
child number argument other than -1, if the source is a Text node.
Maximum NCName length 100 characters
The maximum length of a prefix or localName of an XML document is now 100 characters.
Previously, it was 650 characters.
WspNewline option for deserialization
In version 6.7 of Janus SOAP, the default option for the deserialization
methods has changed: it is now WspNewline.
Also, the option that strips all leading and trailing whitespace in a Text
node, and which converts every sequence of whitespace in a Text node to
a single space, is now called WspToken.
It formerly was called WspNorm
(which can no longer be specified), and it was the default.
Character references for serializing whitespace
In version 6.7 of Janus SOAP, whitespace serialization has changed.
Formerly, the one-byte value of the whitespace character itself was used
(for example, hexadecimal “0D” was used to serialize a carriage return).
The new whitespace serialization approach is in accordance with the XML standard.
LoadFromStringlist newlines
In version 6.7 of Janus SOAP, a newline character is added after Stringlist
items in the LoadFromStringlist method.
Invalid EBCDIC characters, X'B1' square bracket
In version 6.6 of Janus SOAP, various invalid EBCDIC
characters were accepted in an XML document, either
in the deserialization methods or in the various Add/Insert methods.
These are no longer accepted.
The hexadecimal value of these EBCDIC characters are:
06 08-0A 14-15 1A-1B 20-24 28-2C 30-31 33 36 38-3B 3E
43-49 51-59 62-69 70-78 80
8A 8C-90 9A 9C-A0 AA-AC AE-B0 B2-B9 BC BE-BF
CA-CF DA-DF E1 EA-EF FA-FF
Also, EBCDIC X'B1', one of the representations of square bracket, was
correctly treated as a square bracket (for example, in a CDATA section), but when
translated to ASCII for serialization, it was translated to the ASCII colon (:) character.
X'B1' now translates to the ASCII left square bracket.
Serialized Attribute's extraneous leading blank
In version 6.6 of Janus SOAP, if the result of the Serial method is just
an Attribute node, it started with a blank character.
This bug is fixed in version 6.7, but not by a maintenance zap to version 6.6.
Janus SOAP ULI
Equal sign in method arguments
In version 6.6, an equal sign (=) as the second token in a method invocation would
be treated as a comparison operator, so that the following:
%list is object stringList
...
%list:add('a' = 'b')
would add a “0” to the StringList, since 'a' is not
equal to 'b'.
Under Version 6.7, the argument above would produce a compilation error,
since the Janus SOAP ULI expects a parameter name before the equal sign in
this context.
This would be true whether what precedes the equal sign is a string literal,
a variable name, or a field name.
Should the above construct be used in any method invocations, it can be
corrected by using the character comparison operator (eq)
in place of the symbolic one:
%list is object stringList
...
%list:add('a' eq 'b')
Janus Sockets
HTTP Helper connection errors are non-counting
Prior to this change, the HTTP Helper treated certain run time connection-attempt errors
as non-request-cancelling, Model 204 counting (ER) errors, and it displayed
them on the terminal.
The errors in question were from Get and Post method connection failures
that produced the MSIR.0084, MSIR.0085, and MSIR.0667 messages,
Then, even when the method's no-cancel option was used,
a site's APSY error processing routines might be triggered unnecessarily, and
the Model 204 session error count might become unnecessarily excessive
and cause a user restart.
In Version 6.7, these errors are informational (AD), though they
can still be detected and handled by the application
(by checking for a Null result object, checking $status and $statusd, or both).
This change was also made by maintenance zap to Janus Sockets Version 6.6.
Janus Web Server
$web_get_cookie_lstr
The original implementation of $web_get_cookie_lstr accidentally left
on the third and fourth parameters from $web_get_cookie.
These were offset and length parameters which the longstring
function ignored, and in fact, they were not documented.
However, if they were accidentally entered, they would compile successfully.
Under Version 6.7, specifying a third or fourth parameter on
$web_get_cookie_lstr will produce a compilation error.
$web_put_text and $web_put_bin
$web_put_text and $web_put_bin are now longstring capable:
they accept and send strings longer than 255 bytes.
This is unlikely to be a backward compatibility problem, because
previous attempts to pass a longstring longer than
255 bytes to these functions resulted in request cancellation.
There might be a backward compatibility
issue if a request previously did a $web_put_text or
$web_put_bin of the result of a With operation on
two non-longstring strings.
For example:
%foo is string len 255
%bar is string len 255
...
$web_put_text(%foo with %bar)
Prior to Sirius Mods Version 6.7,
if the result of the expression %foo with %bar was longer
than 255 bytes, the result would be
truncated to 255 bytes before being passed to $web_put_text.
As of Sirius Mods Version 6.7, the result will not be truncated.
SirFact
Displaying XML objects in SirFact
In version 6.7 of Sirius Mods, the FACT syntax for displaying an item in an
XmlNodelist system object has changed.
Formerly, to display the fifth element of a nodelist, for example,
you entered:
D %nl:5
Now you have to enter:
D %nl:item(5)
Similarly, $FACT_DATA calls specifying syntax like %NL:5 no longer work.
$FACT_DATA calls with mixed-case input
Prior to Sirius Mods Version 6.7, $FACT_DATA respected the case of its arguments.
That is, passed the data item %myXmlDocrint
, $FACT_DATA would
search the dump for exactly the mixed-case variable %myXmlDoc.
(To succeed, the dump would have to have been created from code compiled with
case-sensitive User Language.)
In Version 6.7, $FACT_DATA first uppercases the non-quoted data items it is
passed, then does its processing, so it would search the dump for the variable
%MYXMLDOC.
Thus, in general, $FACT_DATA calls with non-quoted, mixed-case values no
longer work &emdash. unless, for an appropriate case-sensitive dump,
you set the CASE option to LEAVE
in the new $FACT_OPTION function.
Assert Info %variable Incompatibility
Before this release, an unquoted %variable name in the Info clause of
the Assert statement was interpreted as a literal, that is, something
like the following:
assert %x = 22, info %x
would simply display
MSIR.0494: Assert info: %X
Under this release the Assert info: would be followed by the
value of %x.
Note that if %x is not a valid %variable name, the above would
produce a compilation error.
Sirius Mods Version 6.6
Version 6.6 of the Sirius Mods was released in August, 2004.
The major enhancements are summarized below.
Please refer to the
Notes for Sirius Mods Version 6.6 for more detailed information.
Janus SOAP
The following sections describe changes to Janus SOAP.
Please refer to the
Janus SOAP Reference Manual for updated documentation.
AddNamespace restrictions somewhat relaxed
The AddNamespace subroutine now adds a namespace declaration to an element
even if the element already contains attributes.
Also, AddNamespace allows the addition of a namespace to an element that has children,
as long as it has no Element children.
The concept of so-called "implicit" declarations, described in the version 6.5 documentation, has been
removed; the documentation has been changed to reflect the operation of AddSubtree (etc.) in version 6.5:
all declarations are copied.
DeleteSubtree allows prefixed nodes
The DeleteSubtree method no longer prevents the deletion of nodes with prefixes
or URIs in the subtree being deleted.
Note that in two cases (only), DeleteSubtree should not be considered
a complete “undo” operation of Add/Insert methods.
The first case is when the URI argument of AddAttribute creates a namespace
declaration: DeleteSubtree of the added attribute node does not delete the declaration.
The second case is when the argument of AddSubtree (or InsertSubtreeBefore) references an attribute node
that has a prefix not in scope at the target of the copy operation:
DeleteSubtree of the added attribute node does not delete the declaration.
Exists
The new method, Exists, returns True if the XPath result is non-empty, and it returns False otherwise.
%bool = nr:Exists(XPath)
For example, the following request:
Begin
%d Object XmlDoc
%d = New
Print 'Root exist?' And %d:Exists('.'):ToString
Print 'Elem of empty doc exist?' And %d:Exists('*'):ToString
End
Prints the following:
Root exist? True
Elem of empty doc exist? False
The Exists method is the most efficient way to check for the existence of one or more nodes in a document.
SelectCount has the relative disadvantage that it may continue to examine
the XmlDoc tree after the first matching node is found.
SelectSingleNode can also force processing of the entire document, since SelectSingleNode guarantees
it will return the first node in XmlDoc order.
LoadFromStringList
The LoadFromStringList method behaves like LoadXML, but it accepts its input from a StringList object:
%pos = doc:LoadFromStringList(strLst, [options])
Where strLst is a StringList object, and options are the same as for LoadXml.
The input consists of the concatenation of the StringList items; that is, there
is no insertion of line end characters at the end of each item.
LoadSystemMethodInfo
The LoadSystemMethodInfo method loads an XmlDoc with information about methods in
classes selected by the “pattern” argument:
Call doc:LoadSystemMethodInfo(pattern)
Where pattern is a string whose case is ignored and which can have any of the following forms:
- methodPattern
- This selects, from any system class, all methods that match the specified pattern.
- classPattern':'methodPattern.
- This selects, from any system class matching “classPattern”,
all methods that match “methodPattern”.
- 'System:'classPattern':'methodPattern.
- This is the same as classPattern':'methodPattern.
Note that the “New” method will only be displayed if either is true:
- The “methodPattern” is the string “New”.
- The “New” method has any arguments.
Print compaction options
The following mutually exclusive Print method options are provided for more compact formats:
- Compact
- An element's entire start tag is printed on a single line, which includes attributes and namespace declarations.
If it has no children or has a single Text child, and does not have attributes nor namespace declarations,
then the Text child is serialized on the same line as the start and end tags.
Compact is the new default for the Print method, which is documented as a compatibility issue.
- Expanded
- A new line is started for each attribute, namespace declaration, and child.
Expanded is the format previously used.
- AttributeCompact
- Attributes and namespace declarations are printed on the same line as the start tag.
- ElementCompact
- An entire element is printed on one line, if it has no attributes nor namespace declarations and has
no children other than possibly a Text child.
- BothCompact
- Combines the effect of AttributeCompact and ElementCompact, producing the most compact formatting.
It displays on one line an element that has no children or that has a single Text child.
Note that these options make the Print method a little more like the format of the non-Print serialization
methods, because the latter do not introduce any line breaks (by default).
The non-Print methods also have options to make them a little more like the Print method
with the BothCompact option (see Serialization (non-Print) newline options).
Serialization (non-Print) newline options
A set of options is available for the following methods (in these classes):
- Serial (XmlDoc and XmlNode)
- Xml (XmlDoc)
- WebSend (XmlDoc)
- AddXml (HttpRequest)
The options are to provide a serialized stream that is easier to read (for example, with WebSend, using a
browser's View/Source to look at XHTML produced with Janus SOAP).
These options will insert a “newline” sequence after serializing the following:
- an element start-tag, if it has any non-text node children
- an empty element tag or element end-tag
- a PI
- a comment
- a text