Generating standard operations

You may want to use standard operations for a number of purposes, such as copy constructors, serialization, or overriding virtual operations of a base class. IBM® Engineering Systems Design Rhapsody® provides a mechanism for including standard operations in the generated code.

The mechanism for generating standard operations involves:

  • specifying the code for each standard operation in the site.prp file
  • specifying which of the standard operations should be generated for a specific class by listing the operations in the value of the property CG::Class::StandardOperations

Specifying code for standard operations in site.prp file

Declaration and definition properties

In the site.prp file, you must provide a pair of class-level properties for each standard operation. The names must use the following format:

  • CG::Class::op1Declaration
  • CG::Class::op1Definition

The "op1" part of the name is the string that you are going to use in the StandardOperations property to refer to this standard operation.

The content of the Declaration property will be generated in the relevant .h file. The content of the Definition property will be generated in the relevant .c or .cpp file.

Ordinarily you will use one or more Rhapsody keywords in the value of these properties. For example:

Subject CG
	Metaclass Class
		Property op1Declaration MultiLine "void $Name;"
		Property op1Definition MultiLine "void $Name:  $Name() {int x=7;}"
		Property op2Declaration MultiLine "void $Name_serialize;"
		Property op2Definition MultiLine "void $Name:  $Name_serialize{}"
	end
end
Note: The property pairs added to the site.prp file are designed for C and C++. If you are using Java, it is enough to add only the Definition property for the operation (for example, javaOp1Definition) and include all the necessary Java code in the value of that property.

Defining code for class members

Since you are likely to want to include manipulation of class members in the code for the standard operation that you are defining, Rhapsody provides keywords for generating code that will be repeated for each attribute, relation, or operation in the class.

To define code that involves all of the attributes in the class:

  • In the site.prp file, create a property called CG::Attribute::(reference name for standard operation), for example, CG::Attribute::op1. Use this property to specify the code you would like to apply to all the attributes in the class. In the code, you can use standard keywords such as $Name for the name of the attribute.
  • In the value of the Definition property you created for the standard operation, insert the keyword $Attributes where you would like this attribute-related code to be generated.

To define code that involves all of the associations in the class:

  • In the site.prp file, create a property called CG::Relation::(reference name for standard operation), for example, CG::Relation::op1. Use this property to specify the code you would like to apply to all the associations in the class. In the code, you can use standard keywords such as $Name for the name of the association.
  • In the value of the Definition property you created for the standard operation, insert the keyword $Relations where you would like this relation-related code to be generated.

To define code that involves all of the operations in the class:

  • In the site.prp file, create a property called CG::Operation::(reference name for standard operation), for example, CG::Operation::op1. Use this property to specify the code you would like to apply to all the operations in the class. In the code, you can use standard keywords such as $Name for the name of the operation.
  • In the value of the Definition property you created for the standard operation, insert the keyword $Operations where you would like this operation-related code to be generated.

Defining code for arguments

You can also define code that will be repeated for each of the arguments in the class. This includes any event arguments as well as all of the arguments for the operations contained in the class.

To define code that involves all of the arguments:

  • In the site.prp file, create a property called CG::Argument::(reference name for standard operation), for example, CG::Argument::op1. Use this property to specify the code you would like to apply to all the arguments. In the code, you can use standard keywords such as $Name for the name of the argument.
  • In the value of the Definition property you created for the standard operation, insert the keyword $Arguments where you would like this argument-related code to be generated.

Defining code for template classes

When defining standard operations for template classes, you can use the keyword $NameWithTemplateParams. If you have a class named ClassA and it is a template this keyword is replaced with "ClassA<params>". If the class is not a template, the keyword is replaced with "ClassA". The following property definitions demonstrate the use of this keyword when defining a copy constructor.

Subject CG
	Metaclass Class
		Property CopyCtorDeclaration MultiLine "$Name(const $NameWithTemplateParams & x);"
		Property CopyCtorDefinition MultiLine "$NameWithTemplateParams::$Name(const $NameWithTemplateParams & x) { /* some code */ }"
  end

Defining code for base classes

You can also define code that takes information from base classes that a class extends.

To define such code:

  • In the site.prp file, create a property called CG::Class::(reference name for standard operation)Base, for example, op1Base. Use this property to specify the code that should be based on the base class. If you use a keyword like $Attributes in this code, then the code that you specified with the property CG::Attribute::op1 will be generated for each of the attributes in the base class.
  • In the value of the Definition property you created for the standard operation, insert the keyword $Base where you would like this base-class-related code to be generated.

Specifying which standard operations to generate for a class

The property CG::Class::StandardOperations takes a comma-separated list of operation references, based on the property names you included in your site.prp file.

If you added class-level properties named op1Declaration, op1Definition, op2Declaration, and op2Definition, then the two standard operations will be generated for a class if you specify op1, op2 as the value of the property StandardOperations for that class.

Note: The value of the property CG::Class::StandardOperations can also be set at a the level higher than that of individual classes. For example, if you set the property value at the package level, the standard operations will be generated for all of the classes in the package.

Example - using standard operations for serialization

This example shows how you can use the standard operation feature to implement serialization of events. The approach would be similar to implement unserialization.

To have the operation generated for all the events in a given package:

  • Specify serialize as the value of the CG::Event::StandardOperations property at the package level.
  • Define the required code for the serialize operation by adding the following properties to your site.prp file.
    Note: The code assumes that the serialization is done by placing the event argument values inside an strstream.
    • CG::Event::serializeDeclaration

      public: 
         strstream & serializer(strstream & theStrStream) 
         const;
    • CG::Event::serializeDefinition

      strstream & $Name::serialize(strstream & theStrStream) {
         $Base
         $Arguments
         return theStrStream;
      }
    • CG::Argument::serialize

      theStrStream << $Name;
    • CG::Event::serializeBase

      $Name::serialize(theStrStream);

Generated code

If you defined an event named VoiceAlarm with two arguments, severity and priority, and VoiceAlarm inherits from Alarm, then the code generated would be as follows:

strstream & VoiceAlarm::serialize(strstream & theStrStream) {
   Alarm::serialize(theStrStream);
   theStrStream << severity;
   theStrStream << priority;
   return theStrStream;
}