Component Interaction Specifications

David Flater, 1998-04-14

Important note -- Not all features are implemented. Please read the limitations section before writing any Component Interaction Specifications.


Introduction

A Component Interaction Specification, or CIS, is a textual specification of an interaction scenario for an entire distributed system. A CIS can be used to generate servers that will execute the scenario that it describes.

An interaction scenario consists of a tree of CORBA requests having specified inputs, outputs, and/or return values. The tree is rooted at the test client that initiates the entire chain of events.

In order to capture the tree structure of the interactions in a flat ASCII script, an outline numbering convention similar to that of UML Collaboration Diagrams is used. To illustrate this:

1 ... first request by testing client on server A ...

2 ... second request by testing client on server A ...

2.1 ... request by server A on server B ...

2.2 ... request by server A on server C ...

3 ... third request by testing client ...

The meaning of the above outline is that the requests on server B and server C are both made by server A before it responds to the second request made by server A. That is, the implementation of the operation requested in the testing client's second request makes requests on servers B and C before it returns a result to the testing client.

History

MCITT's CIS syntax is based on the Object Interaction Diagrams, or OIDs, used by NIST's industrial partners in the Advanced Process Control (APC) Framework Initiative. The format originally used by APC to describe each request is like the following example:

1.3 install_component

Message from System Manager GUI to System Manager server
Format void install_component( SystemManager::ComponentName )

Actual Message:

{
     "DataStore"
}

MCITT's CIS makes the following cosmetic changes to the APC format:

Informal Syntax

A CIS file consists of a sequence of messages having the following form:

1.2  interface::operation
In: { ... argument values ... }
Out: { return value, out values ... }

The specification of the interface can take either of the forms used in ITL, either <interface-name> or <MCITT-identifier> (with the <MCITT-identifier> being declared in the ITL file). Just as in ITL, an <interface-name> generates code that applies to all instances of the class, while an <MCITT-identifier> generates code that only applies to the identified instance.

The In: and Out: lists are both optional. The In: list specifies input values for all parameters whose attribute is in or inout; the Out: list specifies output values for the return and for all parameters whose attribute is out or inout. The return value, if any, is the first item in the Out: list.

The In: list is used to construct the request on the client side, and also to perform assertion checking of the received values on the server side. Similarly, the Out: list is used to construct return values and out-values, and to perform assertion checking of the received values on the client side. (Note: Not everything is implemented; see limitations.)

The syntax of the In: and Out: lists of CIS follows that of the "Actual Message:" and "Actual Return Structure:" lists of APC:

Each "value" is another instance of the above syntax. Sequences, structs, and unions may be nested to construct arbitrarily complex values.

The CIS file may contain comments. Comments are introduced with // exactly as in ITL.

Here is how the previous example from APC would be rewritten in CIS format:

1.3 SystemManager::install_component
In: {"DataStore"}

Usage

The information contained in a CIS file can be used to generate servers that will execute the scenario described by the CIS. This is accomplished by referencing the CIS file with a use command in an ITL file. For example:

declare testservice server "cisdemo.hh" "localhost" "cisdemo"

use "cisdemo.cis"

begin main
  create server 
  serve "cisdemo" 
end main

A server that is generated from a CIS as shown above will return to its initial state after the specified behaviors have been exhausted, so the scenario can be repeated. Of course, if there are any operations specified "manually" in the ITL file, they may not behave in this way.

Precision of Comparisons

ITL assertions support the specification of a precision for approximate numeric comparisons, to tolerate normal roundoff error. Since the CIS syntax does not leave room to specify the precision of approximate numeric comparisons, a constant precision is used. This precision is specified in the mcitt.hh header file and compiled into itlc. The normal value is 1e-5.

Examples

How to construct sequences, structs, and unions

The IDL and CIS shown below are from the demos/cis_regression_test subdirectory of the MCITT distribution.

IDL

// Server for CIS demo with sequences, structs, and unions
// DWF 1998-01-16

module somemodule {
  // "Fixed" struct
  struct Value1 {
    long a;
    short b;
  };
  // "Variable" struct
  struct Value2 {
    string a;
    short b;
  };
  // Nested struct
  struct Value3 {
    Value1 v1;
    Value2 v2;
  };

  enum Loc {Saskatoon, Tuktoyuktuk, ChejuDo};

  union Value4 switch (Loc) {
    case Saskatoon:  short v1;
    case Tuktoyuktuk:  float v2;
    default:  string v3;
  };

  typedef sequence<long> longSeq;
  typedef sequence<Value4> value4Seq;
  typedef sequence<char> charSeq;
  typedef sequence<octet> octetSeq;
};

interface testservice {
  somemodule::Value1 foo (in long a);
  somemodule::Value2 bar (in short b);
  somemodule::Value3 baz (in string c);
  somemodule::Value4 frob (in somemodule::Value4 d);

  somemodule::longSeq borf (in somemodule::longSeq d,
    out somemodule::longSeq e, inout somemodule::longSeq f);
  somemodule::value4Seq zab ();
  somemodule::charSeq rab ();
  somemodule::octetSeq oof ();
  boolean toggle ();

  void i1 (in somemodule::Value1 a, out somemodule::Value1 b,
           inout short c);
  void i2 (in somemodule::Value2 a, out somemodule::Value2 b,
           inout somemodule::Value2 c);
  attribute somemodule::Value3 i3;
};

CIS

1 server::foo
In: {2}
Out: {{9,10}}

2 server::bar
In: {4}
Out: {{"Feldspar",9}}

3 server::baz
In: {"ink"}
Out: {{{21,22},{"Granite",100}}}

4 server::frob
In: {[Saskatoon, 42]}
Out: {[ChejuDo, "Albatross"]}

5 server::borf
In: {#(100, 200, 300), #()}
Out: {#(10000, 20000, 30000, 40000), #(4, 5), #(10)}

6 server::zab
Out: {#([Saskatoon, 256],
        [Tuktoyuktuk, 3.1416],
        [ChejuDo, "Aardvark"])}

7 server::rab
Out: {#('s','t','a','p','l','e')}

8 server::oof
Out: {#(0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99,
        0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF)}

9 server::toggle
Out: {true}

10 server::toggle
Out: {false}

11 server::i1
In: {{42000, 42}, 67}
Out: {{62000, 62}, 2}

12 server::i2
In: {{"toner", 53}, {"ink", 35}}
Out: {{"argon", 271}, {"lead", 394}}

13 server::i3
In: {{{21,22},{"Granite",100}}}

14 server::i3
Out: {{{21,22},{"Granite",100}}}

How to return usable object references

The CIS shown below is from the demos/machine_cis subdirectory of the MCITT distribution. It generates a server to execute a scenario in which Parameter and LimitedParameter object references are returned to and used by the client program.

IDL

// IDL for the Machine Demo.

// Machines have operating parameters.

interface Parameter {

  // It may be impossible to apply requested adjustments for some reason.
  exception ParmNotAdjusted {
    string reason;
  };

  readonly attribute string name;
  readonly attribute float val;
  readonly attribute string units;

  // Adjust value by d (positive or negative).
  void adjust (in float d) raises (ParmNotAdjusted);
};

// Some parameters have known limits.

interface LimitedParameter: Parameter {
  readonly attribute float limit;
};

// Generic machine controller manages varying sets of parameters.

interface Machine {

  // The controller may refuse to create a new parameter for some reason.
  exception ParmNotCreated {
    string reason;
  };

  Parameter newParameter (in string name, in float initval, in string units)
    raises (ParmNotCreated);
  LimitedParameter newLimitedParameter (in string name, in float initval,
    in string units, in float limit) raises (ParmNotCreated);
  void removeParameter (in Parameter p);
};

CIS

// -*-fundamental-*-
// CIS for Machine server.
// DWF 1998-03-10

1	ChipShooter::newParameter
In: {"rate", 240.0, "placements per minute"}
Out: {Parameter}

2	ChipShooter::newParameter
In: {"part mass", 1.0, "grams"}
Out: {Parameter}

// Larger components have to go slower.

3	Parameter::adjust
In: {-40.0}

4	Parameter::adjust
In:	{+0.5}

5	Parameter::val
Out: {200.0}

6	Parameter::val
Out:	{1.5}

7	WaveSolder::newParameter
In: {"temperature", 190.0, "degrees C"}
Out: {Parameter}

8	Parameter::adjust
In:	{-2.0}

9	Parameter::val
Out:	{188.0}

10	Testbed::newParameter
In: {"voltage", 12.0, "volts DC"}
Out: {Parameter}

11	Parameter::adjust
In:	{-3.0}

12	Parameter::val
Out:	{9.0}

// There's no way to throw an exception yet.
// 13	Testbed::newParameter
// In: {"voltage", 115.0, "volts AC"}

14	Testbed::newLimitedParameter
In: {"temperature", 75.0, "degrees F", 110.0}
Out: {LimitedParameter}

15	Parameter::adjust
In:	{+25.0}

16	Parameter::val
Out:	{100.0}

17	Testbed::newLimitedParameter
In: {"sampling rate", 66.0, "MHz", 100.0}
Out: {LimitedParameter}

// Currently, instances can't be distinguished in the superclass
// (see doc/limitations) so Parameter:: must be used instead of
// LimitedParameter::.

18	Parameter::adjust
In:	{+33.0}

19	Parameter::val
Out:	{99.0}

20	LimitedParameter::limit
Out:	{100.00}

// There's no way to throw an exception yet.
// 21	Parameter::adjust
// In: {+33.0}

22	Testbed::removeParameter
In: {Parameter}

Current Limitations (MCITT 1.0)

Generating requests from CIS is not supported. Only assertion-checking and response generation is done.

The assertion checking in generated servers will not always detect deviations from the CIS which consist of the correct messages happening in the wrong order. (Note that fixing this "bug" would also break the "feature" of being able to mix ITL and CIS constructs freely as demonstrated in the PDM_cis example.)

In assertions for complex types (sequences, structs, unions), the actual value is not printed, but the assertion is checked and the verdict is shown correctly.

Unions must be discriminated by enums.

Enum symbols cannot be used except for discriminating unions.

There is no way to throw an exception.

In general, CIS behaviors can't be specified for anything but the first repetition of any given overloaded function. However, get and set attributes will be resolved correctly if you provide appropriate In: or Out: specifications.

Appendix A -- Semi-Formal Syntax

(Note that this grammar does not distinguish 'Any' types.)

<cis_file> ::= <cis_message>
             | <cis_file> <cis_message>

<cis_message> ::= <message_number> <message>
                | <message_number> <message> <cis_in> <value>
                | <message_number> <message> <cis_out> <value>
                | <message_number> <message> <cis_in> <value> <cis_out> <value>

<value> ::= <leaf>
          | <cis_sequence>
          | <cis_struct>
          | <cis_union>

<leaf> ::= <cis_string>
         | <cis_float>
         | <cis_int>
         | <cis_char>
         | <cis_boolean>
         | <cis_octet>
         | <repository_ID>

<valuelist> ::= <value>
              | <valuelist> ',' <value>

<cis_sequence> ::= <start_sequence> <valuelist> <end_sequence>
                 | <start_sequence> <end_sequence>

<cis_struct> ::= <start_struct> <valuelist> <end_struct>

<cis_union> ::= <start_union> <discriminator> ',' <value> <end_union>

<start_sequence> ::= "#("

<end_sequence> ::= ')'

<start_struct> ::= '{'

<end_struct> ::= '}'

<start_union> ::= '['

<end_union> ::= ']'

<cis_in> ::= "In:"

<cis_out> ::= "Out:"

!! The following are loosely defined -- follow examples

<message_number> ::= <leaf>

<message> ::= <leaf>

<discriminator> ::= <leaf>

!! The following contain regular expressions

<comment> ::= "//"[^\n]*

<cis_string> ::= \"[^"\n]*\"

<cis_char> ::= '.'

<cis_float> ::= -?([0-9]*\.[0-9]+)

<cis_int> ::= -?([0-9]+)

<cis_boolean> ::= "true" | "false"

<cis_octet> ::= "0x"[0-9a-fA-F][0-9a-fA-F]

<repository_ID> ::= [a-zA-Z:_][a-zA-Z0-9:_]*