Sirius Software, Inc.
Contents
 

 

Sirius Home
 
Sirius Product News
Older product releases
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:

  • In some languages, all methods are assumed to be overridable unless some keyword (usually Final) is specified after their declarations.
  • In some languages, a method in an extension class with the same name as an overridable method in a base class is automatically considered to implement the base class method.

    In Janus SOAP ULI, the Implements clause is required in a method declaration for a method to be considered to implement a base class method.

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 nameEBCDIC valueASCII value
tabX'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 namecharacter 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 nameclass name(s)
SerialXmlDoc and XmlNode
WebSendXmlDoc
XmlXmlDoc
AddXmlHttpRequest

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:
  1. 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.
  2. Bind a connection and log in to an LDAP server (in your User Language request, a single Bind method statement performs these actions).
  3. Send a search query to the LDAP server, using one of the multiple Find methods, which provide a variety of search filters.
  4. Optionally, extract particular data from the data returned from the LDAP server, using the Janus SOAP XML Api.
  5. 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:
  1. 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.
  2. 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.
  3. 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:
  1. 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.
  2. 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

    • Uppercases non-quoted command input before processing (this is adjustable if you are using the SirFact$functions to look at dumps).
    • Quotes the output values but not informational or error messages.
    • Uses the “terminal output” form (adding equal signs and quotation marks) for the Print method result and not its normal format.

      This Print output is truncated at 500 lines, a limit that is adjustable if you explicitly specify the Print method or if you are using the SirFact $functions to look at dumps.

    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:

    • You can specify Print method parameters:
      D %XMLPIER:PRINT('/outer/inner')
      
    • The output is not subject to the 500-line (default) limit of an “implied” Print.
  • 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 %myXmlDoc

      rint('/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.

    1. 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.

    2. 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 %myXmlDoc

    rint, $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.

    Return to top of page

    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