You are on page 1of 442

MSC Software Development Kit 2010

User's Guide
Corporate
MSC.Software Corporation
2 MacArthur Place
Santa Ana, CA 92707 USA
Telephone: (800) 345-2078
Fax: (714) 784-4056

Europe
MSC.Software GmbH
Am Moosfeld 13
81829 Munich, Germany
Telephone: (49) (89) 43 19 87 0
Fax: (49) (89) 43 61 71 6

Asia Pacific
MSC.Software Japan Ltd.
Shinjuku First West 8F
23-7 Nishi Shinjuku
1-Chome, Shinjyku-Ku
Tokyo 160-0023, JAPAN
Telephone: (03)-6911-1200
Fax: (03)-6911-1201

Worldwide Web
www.mscsoftware.com

Disclaimer
MSC.Software Corporation reserves the right to make changes in specifications and other information contained
in this document without prior notice.
The concepts, methods, and examples presented in this text are for illustrative and educational purposes only,
and are not intended to be exhaustive or to apply to any particular engineering problem or design. MSC.Software
Corporation assumes no liability or responsibility to any person or company for direct or indirect damages resulting
from the use of any information contained herein.
User Documentation: Copyright 2010 MSC.Software Corporation. Printed in U.S.A. All Rights Reserved.
This notice shall be marked on any reproduction of this documentation, in whole or in part. Any reproduction or
distribution of this document, in whole or in part, without the prior written consent of MSC.Software Corporation is
prohibited.
This software may contain certain third-party software that is protected by copyright and licensed from
MSC.Software suppliers.
MSC, MD, Dytran, Marc, MSC Nastran, MD Nastran, Patran, MD Patran, the MSC.Software corporate logo, and
Simulating Reality are trademarks or registered trademarks of the MSC.Software Corporation in the United States
and/or other countries.
NASTRAN is a registered trademark of NASA. PAMCRASH is a trademark or registered trademark of ESI Group.
SAMCEF is a trademark or registered trademark of Samtech SA. LS-DYNA is a trademark or registered trademark
of Livermore Software Technology Corporation. All other brand names, product names or trademarks belong to
their respective owners. PCGLSS 6.0, Copyright © 1992-2005, Computational Applications and System
Integration Inc. All rights reserved. PCGLSS 6.0 is licensed from Computational Applications and System
Integration Inc.

Revision 0. May 11, 2010


MDNA:2010:Z:SCA:Z:DC-USR-PDF
Contents
SCA Framework User’s Guide (DEV)

1 Introduction
Introduction 2

Organization of this manual 3

Source Code Examples 4

2 SCA Overview
Introduction 6

Interface Based Programming 7

SCA Interfaces and the IDL language 11

SCA Services 12

SCA Components 13
What is the SCA Kernel 13

The SCA Framework 14

Language support 15

Platform support 16

Summary 17

3 A SCA Hello World Application


Introduction 20

Defining the Interfaces 21


Include guard 21
Include declarations 22
Module declarations 22
Interface declarations 23

Defining the Service 24


2 SCA Framework User’s Guide (DEV)

Include guard 24
Include declarations 24
Module declarations 25
Service declaration 25

Defining the Component 26


Include guard 26
Include declarations 26
Component declaration 27

Generating the Code Skeletons 28


The genskeleton command 28
Adding the required functionality to the skeletons 28
Implementing the service in C++ 29
Implementing the service in java 30
Implementing the service in C# 31
Implementing the service in visual basic 32

Building the Component 34

Creating a Client for the Service 35


Implementing the Application in C++ 35
Implementing the Application in Java 38
Implementing the Application in C# 39
Implementing the Application in Visual Basic 41
Implementing the Application in Python 43

Intra-language Support 45

Summary 46

4 The IDL Language


Introduction 48

Source Files 49
IDL 49
SDL 49
CDL 49

Lexical Rules 51
Comments 51
Identifiers 51
Keywords 51
Escaped identifiers 52
Literals 52
Contents 3

Constant expressions 55

Preprocessing 56

IDL Specification for Interfaces and Types 57


Grammar notation 57
IDL specification 57
Basic IDL Types 58
User-defined Types 62
Template Types 66

Constants 70

Modules, Names and Scoping 74


Name lookup rules 74
Qualified names 75
Scoping rules 76

Interfaces and Operations 78


Interface header 78
Interface inheritance specification 79
Interface body 79
Operation declaration 79
Forward declarations 81
Interface inheritance 82
SCAIService interface 83

Exceptions 85

SDL Specifications 86

CDL Specifications 89
Service Options 92

SCA Component Declaration 94


Component Options 95

Using the SCA-IDL Compiler 96


The IDL compiler command 96
Compiler processing modes 97
Location for compiler generated files 98
The genskeleton command 99

Summary 100
4 SCA Framework User’s Guide (DEV)

5 IDL to C++ Language Mapping


Introduction 102

Mapping for Identifiers 104

Mapping for Modules 105

Mapping for Basic Types 106

Mapping for String Types 107

Mapping for Enumerated Types 108

Mapping for Structures 109

Mapping for Arrays 110


Fixed size arrays 110
Dynamic arrays 111

Mapping for Sequences 116

Mapping for Type Aliases 119

Mapping for SCATypeCode 120

Mapping for SCAAny 121


The SCAAny class definition 121
Creating new SCAAny values 123
Inserting values into exiting SCAAny values 123
Extracting the value contained in a SCAAny 124
Assigning SCAAny values 124
Interrogating the value contained in a SCAAny 125
Miscellaneous SCAAny methods 125
Special SCAAny methods for Dynamic Arrays 126
Limitations in the SCAAny 126

Mapping for SCAResult 127


SCAResult class definition 127
Creating new SCAResult values 128
Resetting the error code in a SCAResult value 128
Adding parameters to a SCAResult value 128
Interrogating the contents of a SCAResult 129
Miscellaneous SCAResult methods 129

Mapping for Constants 130

Mapping for Interfaces 131


Mapping for Interface Smart Pointer Definition 132
Contents 5

Mapping for Interface Abstract Base Class Definition 133


Mapping for Interface Operations 133
Mapping Interface Operation Parameters 134
Using Smart Pointers 135

Mapping for Exceptions 137


SCAException class 137
SCAUserException class 137
SCASystemException class 138
Mapping for IDL defined user exceptions 138
Special Rules for using SCA Exceptions in C++ 139

Mapping for SCA Services 141


The inheritance form of implementation 142
The ServiceAccess interface 145
The delegation form of implementation 147
Singleton Services 148
Aggregation 149

Mapping for SCA Components 150


Embedded Components 150

6 IDL to Java Language Mapping


Introduction 152

Mapping for Identifiers 154

Mapping for Modules 155

Mapping for Basic Types 156

Mapping for Unsigned Data Types 157

Mapping for String Types 158

Mapping for Enumerated Types 159

Mapping for Structures 160

Mapping for Arrays 161


Fixed size arrays 161
Dynamic Arrays 163

Mapping for Sequences 164

Mapping for Type Aliases 166


6 SCA Framework User’s Guide (DEV)

Mapping for SCATypeCode 167

Mapping for SCAAny 168


The SCAAny class definition 168
Creating new SCAAny values 169
Inserting values into exiting SCAAny values 170
Extracting the value contained in a SCAAny 171
Miscellaneous SCAAny methods 172

Mapping for SCAResult 173


SCAResult class definition 173
Creating new SCAResult values 174
Resetting the error code in a SCAResult value 174
Adding parameters to a SCAResult value 175
Interrogating the contents of a SCAResult 175
Miscellaneous SCAResult methods 175

Mapping for Constants 177

Mapping for Interfaces 178


Mapping for Interface Operations 178
Mapping for Interface Parameters 178

Mapping for Exceptions 180


SCAException interface 180
SCAUserException class 180
SCASystemException class 181
Mapping for IDL defined user exceptions 181
The IDL raises clause 182

Mapping for SCA Services 184


The inheritance form of implementation 185
The ServiceAccess interface 188
The delegation form of implementation 188
Singleton Services 188
Aggregation 188

Mapping for SCA Components 189


Embedded Components 189

SCA Framework / JVM Interaction 190


Java Virtual Machine Initialization 190
The IDLTypes.jar archive 190
Contents 7

7 IDL to .Net Languages Mapping


Introduction 192

Mapping for Identifiers 194

Mapping for Modules 195

Mapping for Basic Types 196

Mapping for String Types 198

Mapping for Enumerated Types 199

Mapping for Structures 200

Mapping for Arrays 201


Fixed size arrays 201
Dynamic Arrays 202

Mapping for Sequences 203

Mapping for Type Aliases 204

Mapping for SCATypeCode 205

Mapping for SCAAny 206


The SCAAny class definition 206
Creating new SCAAny values 207
Inserting values into existing SCAAny value 208
Extracting the value contained in a SCAAny 209
Miscellaneous SCAAny methods 210

Mapping for SCAResult 211


SCAResult class definition 211
Creating new SCAResult values 212
Resetting the error code in a SCAResult value 212
Adding parameters to a SCAResult value 213
Interrogating the contents of a SCAResult 213
Miscellaneous SCAResult methods 214

Mapping for Constants 215

Mapping for Interfaces 216


Mapping for Interface Operations 216
Mapping for Interface Parameters 216

Mapping for Exceptions 217


SCAException interface 217
8 SCA Framework User’s Guide (DEV)

SCAUserException class 217


SCASystemException class 217
Mapping for IDL defined user exceptions 218
The IDL raises clause 218

Mapping for SCA Services 220


The inheritance form of implementation 221
Implementation for subservice classes 222
Creating instances of subservice classes 223
The ServiceAccess interface 224
The delegation form of implementation 224
Singleton Services 226
Aggregation 226

Mapping for SCA Components 227


Embedded Components 227

8 IDL to Python Language Mapping


Introduction 230

Mapping for Identifiers 232

Mapping for Modules 233

Mapping for Basic Types 234

Mapping for Enumerated Types 237

Mapping for Structures 238

Mapping for Arrays 240

Mapping for Sequences 241

Mapping for Type Aliases 242

Mapping for TypeCode 243

Mapping for SCAAny 244


The SCAAny class definition 244
Creating new SCAAny values 245
Inserting values into existing SCAAny values 246
Extracting the value contained in a SCAAny 247
Miscellaneous SCAAny methods 247

Mapping for SCAResult 248


SCAResult class definition 248
Contents 9

Creating new SCAResult values 249


Resetting the error code in a SCAResult value 249
Adding parameters to a SCAResult value 250
Interrogating the contents of a SCAResult 250

Mapping for Constants 252

Mapping for Interfaces 253


Mapping for Interface Operations 253
Special Interface Attributes 253
Mapping for Interface Parameters 254
Use of getInterface in Python 255
Implementing SCA Interfaces 256

Mapping for Exceptions 258


SCAException exception 258
Mapping for other exception types 258
The IDL raises clause 260

Mapping for SCA Services 261

Mapping for SCA Components 262

The SCA Module 263

Accessing IDL Type Definitions from Python 264

Running Python Scripts 267


Running Scripts with the ScriptBroker 267
Running Scripts from the command line 267

9 Messages and Internationalization


Introduction 270

Message Files 271


Locale String 271
Message File Naming Convention 271
File Search Order 271
Message File Format 272
Text Formatting 273
Currency Format ($) 273
Date/Time Format (#) 273
All other Formats (%) 274

Text Translation Service 278


10 SCA Framework User’s Guide (DEV)

SCA::Framework::SCAITextTranslationFactory Interface 278


SCA::Framework::SCAITextTranslationSettings Interface 279
SCA::Framework::SCAITextTranslationTable Interface 281

10 Error Processing
Introduction 292

Using SCA Exceptions for Error Handling 294


SCA Exception Hierarchy 295
SCA Framework provided Exceptions 295
Exception API 298
Exception Propagation Rules 298
Recommended usage of SCA Exceptions 300
Complete Exception Error Handling Example for a SCA Service 301

Using SCAResult for Error Handling 305


Introduction 305
The SCAResult data contents 306
Overview of using the SCAResult for Error Handling 307
Registering Message Tables 307
Formatting a SCAResult value 308
Complete SCAResult Error Handling Example for a SCA Service 310
Use of SCAResult values in the client 312

MessageDispatcher Service 316


SCA::Framework::SCAIMsgTableManager Interface 316
SCA::Framework::SCAIMsgListenerManager Interface 318
SCA::Framework::SCAIMessageDispatcher Interface 319
SCA::Framework::SCAIMessageListener Interface 322
Message Listener example using SCAServiceObjectImpl template 324
Message Listener example using a Logger Service Example 325

11 Multi-Threaded Applications
Introduction 332

Thread Safety 333


SCA Framework Synchronization Primitives 333
Kernel Thread Safety Configuration Options 337

Threading Infrastructure 338

Testing Multi-Threaded Services 339


SCA::Framework::SCAIMultiThreadBatchTest Interface Reference 339
Contents 11

Sample Multi-Threaded Application 341

12 Versioning
Introduction 350

Component Metadata 351

13 Configuring and Using the SCA Kernel


Introduction 354

Initializing and Terminating the Kernel 355


SCA Kernel Initialization API 355
SCA Kernel Termination API 355
Examples of Configuring the SCA Kernel 356

Kernel Configuration Variables 359

Kernel Configuration File 361


Default Configuration File Location 363

Runtime Access to Configuration Variables 364

Changing the Prefix for Environement Variable Names 365

Building Applications using the SCA Kernel 366

Running Applications using the SCA Kernel 367

The SCA Services Catalog 370


SCASCons Build options for catalog processing 370
Catalog Configuration Options 370
Service Catalog Precedence Rule for Duplicate Entries 370
Sample Service Catalog File 371

Other Configuration Files 372


IDL Type Definitions Files 372
Message Files 372
Language Support Files 372

Service Manager 373


SCA::Framework::SCAIServiceProvider Interface Reference 373
SCA::Framework::SCAIKernelInfo Interface 374
SCA::Framework::SCAIServiceCatalog Interface 375
12 SCA Framework User’s Guide (DEV)

Shared Library Manager 377


SCA::Framework::SCAISharedLibraryManager Interface Reference 377
Library loading logic 379
Library Release Queue 380
SharedLibraryManager example 381

14 Utility Services
Introduction 384

XML Parser 385

15 SCA Utility Program and Testing Components


Introduction 388

The SCA Utility Program 389


Print the help message 389
Testing Kernel Initialization 390
Running a Batch Test 390
Run a Script 390
Test Loading of a Shared Library 390
Query SCA Kernel Information 391
Query Shared Library Build Information 391

Testing of SCA components 393


SCA::Framework::SCAIBatchTest Interface Reference 393
Running Tests Manual 393
Running Tests with the Build System 394
Setting up Test Aliases 395
Specifying when Tests run by Default 396
Running Test Using a SCA Test Component 396
Testing Using a Program 396
Testing Using Python Script 397
Using a fixup Routine 398
Using the Preprocessor on the Baseline Text 399
Performing Setup and Clean Operations 399
Special Construction Variables used by the TestRun Command 401

16 SCASCons Build System


Introduction 404

Configuring the Build System 405


Contents 13

Construction Variables 405


Directory Trees Processed by the Build System 405
Configuration files 409
Setting up the Build System in a New Source Tree 412
Setting up your Runtime Environment for the Build System 413
The SCons Construction Environment 413
Modifying Construction Variables in the SConscript File 414
Commonly Used Environment Routines 416
Microsoft Visual Studio Projects 417

Running the Build 418


Build Tasks 418
SCons Command 418
Running SCons from a Subdirectory 418
Phases of the Build Process 419
Removing Files Created by the Build 420
SCons Debugging Options 420
Selecting Debug and Optimize builds 420
14 SCA Framework User’s Guide (DEV)
Chapter 1: Introduction
SCA Framework User’s Guide

1 Introduction


Introduction
 Organization of this manual

Source Code Examples
2 SCA Framework User’s Guide
Introduction

Introduction
The Simulation Component Architecture, or SCA, is designed to enable the delivery of MSC’s
simulation technology as reusable software components. With this framework, engineers can develop
integrated high-performance computing (HPC) applications more quickly and efficiently, while also
making the technology more accessible to MSC clients’ applications. It also provides a framework that
allows clients to build extensions or customizations that can easily be plugged into MSC applications or
reuse components that are delivered my MSC.
Chapter 1: Introduction 3
Organization of this manual

Organization of this manual


This manual contains a lot of detailed information on the SCA Framework. Much of it is not required to
get started using SCA. To begin building and using simple SCA components it is recommended that you
review the following chapters first.
• SCA Architecture Overview
• A SCA Hello World Application
• The IDL Language
• The IDL mapping chapter for the language you will be using
• Configuring and Using the SCA Kernel
• The SCASCons Build System

The rest of the chapters in this manual provide details on more specialized topics that can be reviewed
when needed to use the features they cover.
4 SCA Framework User’s Guide
Source Code Examples

Source Code Examples


There are a lot of snippets of example code in the various chapters in this manual. Most of this code is
delivered with the SCA Software Development Kit so you can run and play with them as desired. See the
SCA SDK chapter in the manual for more details.
Chapter 2: SCA Overview
SCA Framework User’s Guide

2 SCA Overview


Introduction
 Interface Based Programming

SCA Interfaces and the IDL language

SCA Services
 SCA Components

The SCA Framework

Language support
 Platform support

Summary
6 SCA Framework User’s Guide
Introduction

Introduction
A central principle of the SCA architecture is the concept of interface-based programming which is
sometimes called component-based programming. Interfaces provide a separation of the API, the clients
see, from their actual implementation. When a developer separates an interface from its implementation,
the client code is developed around an abstraction of the implementation or the interface.
When developing SCA based components, you will be working with three levels of abstractions.
• SCA Interfaces define the API that your clients will be exposed to.
• SCA Services provide the actual implementation of the interfaces.
• SCA Components provide the packages that are used to deliver the services to your clients.
Chapter 2: SCA Overview 7
Interface Based Programming

Interface Based Programming


To better understand interface based programming, consider the following typical C++ class definition.

MyImplementation.h
class MyImplementation
{
public:
void doSomething();
void doSomethingElse();
};

MyImplementation.cpp
void MyImplementation::doSomething()
{ …… }
void MyImplementation::doSomethingElse()
{ …… }
We can then write a client application that uses the simple class.

Client.cpp
#include “MyImplementation.h”
main()
{
MyImplementation* impl;
impl = new MyImplementation();
impl->doSomething();
impl->doSomethingElse();
}
There are a number of disadvantages to this type of implementation and most of these are because the
client code is directly linked to the class implementation. This means that any changes in the internal
implementation of the MyImplementation class will require the client application to be recompiled and
relinked. Some of these changes include the following.
• Size of class
• Method layout of class
• Class inheritance structure

This type of inter dependency is unacceptable in a large software development environment. In such
environments it is desired to hide internal changes to the private portion of a class from the users of the
class. For example, why should the client have to be recompiled because the implementation adds a new
private data member or method? Only changes to public methods should have an effect on them.
What we really need is a way of separating the API that the client uses from the code that actually
implements it. To do this we introduce the concept of an interface. The following is a definition of an
interface class, MyInterface, for our sample class.
8 SCA Framework User’s Guide
Interface Based Programming

MyInterface.h
class MyInterface
{
public:
virtual void doSomething() = 0;
virtual void doSomethingElse() = 0;
};
The interface definition is a normal C++ class where every method is a pure virtual method. In C++, a
pure virtual function declaration provides only the prototype of the method and no implementation. The
actual implementation for the methods remains in the same C++ class, MyImplementation, we had
before. The only difference is now our implementation class must inherit from the interface class.

MyImplementation.h
class MyImplementation : public MyInterface
{
public:
void doSomething();
void doSomethingElse();
};

MyImplementation.cpp
void MyImplementation::doSomething()
{ …… };
void MyImplementation::doSomethingElse()
{ …… };
When using interfaces, there is one other issue that needs to be resolved. The desire is for the client to
only reference the interface class and have no knowledge of the actual implementation. But, how does
the client get an instance of the class. They cannot do a C++ new operation on the interface class because
it is abstract meaning it does not contain all of the implementation for the methods it contains. C++ does
not allow you to instantiate an abstract class. To fix this problem we introduce the concept of a factory.
Each class that implements an interface that you want to expose to your clients must provide a factory
function. The factory function is responsible for getting new instances of the class. Since the factory
function is part of the class's implementation, it has access to the header files for the implementation
which are required for the C++ new operation. The following is the definition of the factory for our
example class.

MyFactory.h
MyInterface* MyFactory();

MyFactory.cpp
MyInterface* MyFactory()
{
return new MyImplementation();
};
Chapter 2: SCA Overview 9
Interface Based Programming

Notice that this function returns a pointer to the interface class, MyInterface, and not the implementation
class. We now have all of the pieces to recode our client application to use the interface version of our
example class.

Client.cpp
#include “MyInterface.h”
#include “MyFactory.h”
main()
{
MyInterface* inf;
inf = MyFactory();
inf->doSomething();
inf->doSomethingElse();
}
The client gets an instance of the MyImplementation class using its factory function, MyFactory. But it
knows nothing about the implementation class because it is returned a pointer to the interface class. Once
the interface pointer is obtained, any of the methods it contains may be called.
When you package this class for delivery to your clients, you would only need to deliver the header file
for the interface class and the object for the implementation class and its factory. There is no need to
delivery any of the header or implementation files from the MyImplementation class. Because of this, the
client has no knowledge of the implementation other then the API exposed to them through its interface.
Another advantage of interface-based programming is that one version of the implementation can replace
a different version without requiring the client code to change. This new implementation could correct
errors in the previous version or it could provide different internal algorithms. In the example, you could
write a different implementation class called MyImplementation2, and as long as it inherits from the same
MyInterface interface class and implements all of the methods, it can be used interchangeably with the
first version. The client’s code would be able to use this updated code without any changes except to link
with the object file for MyImplementation2.
It is also possible to deliver the implementation in a shared library instead of an object library. By using
this method, the client’s code would not have to be modified in any way, including linking, to use the new
implementation.
This illustrates another important feature of an interface: once an interface is delivered to a client, it
should not change. This insures that the client code will continue to function correctly even if the
underlying implementation is changed. If the new implementation needs to change the interface, then it
should provide a different interface for the new functionality and continue to support the old interface, if
possible. The client code can then determine at run time if the implementation they are using provides
the new or old interface and follow the appropriate procedure. This allows old clients to work with new
implementations and new clients to work with old implementations.
In summary, the use of interfaces provides the following advantages.
• Client code is separated from class implementation code.
• As long as the interface does not change, then class implementation changes do not affect the
client.
10 SCA Framework User’s Guide
Interface Based Programming

• One version of implementation can be replaced with another without requiring the client to be
recompiled but it may have to be relinked.
• If implementation is in a shared library then even the relink is not required.
• The implementation of the class can be shared by more than one client.
• Applications can be built on a component-by-component basis.
Chapter 2: SCA Overview 11
SCA Interfaces and the IDL language

SCA Interfaces and the IDL language


The SCA Framework uses interface-based programming as a fundamental design premise. Access to all
exposed functionality is indirectly through interfaces. In SCA, all interface definitions are defined in the
interface definition language (IDL). These definitions completely define the interface. This includes its
methods, each of their parameters and any user constructed data types required. The IDL definitions of
the interfaces provide the information needed to develop clients that use the interface’s operations.
The IDL language is a purely descriptive language. This means that the implementation of the interfaces
are not written in IDL, but in normal programming languages for which mappings from the IDL concepts
have been defined. The SCA IDL compiler will process the IDL language and generate the required
source files needed to access the functionality of the interfaces in the requested language. Currently the
SCA Framework supports mappings for the C++, Java, C#, Visual Basic and Python languages.
In addition to the benefits of using interfaces, the use of IDL offers a number of additional benefits.
• The success of any large scale system may be strongly influenced by the design of its interfaces.
The use of an IDL promotes good software engineering practice by reinforcing the idea of good
interface design by forcing the developer to consider the interfaces to the system before the
implementation details are coded.
• Because the IDL language is different from the various implementation languages, it enables
cross language applications development. You can use any of the supported implementation
languages to implement the API defined in an interface.
• The use of an IDL compiler can greatly enhance productivity by automating the generation of
much of the code required to implement the many low-level details. This frees the developer
from performing these mundane tasks.
• Similar to multi-language support, the use of IDL also allows for the transparent access between
SCA services and clients running on different computers.
12 SCA Framework User’s Guide
SCA Services

SCA Services
SCA services provide the implementation for the interfaces. One or more classes may be used to
implement each service. These classes inherit from one or more interface classes and provide the
implementation for their methods. The service is the level of functionality that a client requests. They do
not request an interface because several different implementations for the same interface may reside in
difference services. By requesting the service, the client can easily select from the available
implementations that they require.
Instances of the classes that make up a SCA service are called SCA service objects. The lifecycle of SCA
service objects is automatically handled by the SCA Kernel. The technique used to manage the lifecycle
depends on the language being used.
• In C++, smart pointers are used to automate the destruction of service objects when all
references to them have been removed.
• In Java, .NET and Python the normal garbage collection facilities in the languages are used.
Chapter 2: SCA Overview 13
SCA Components

SCA Components
A SCA component is the container that is used to deliver one or more services. Depending on the
language, physically it may be a dynamically linked shared library or a Java JAR file.
Client code is not aware of components. When a client requests an instance of a SCA service, the SCA
Kernel will look in the SCA Service Catalog to determine which component contains the requested
service. It will then load the appropriate shared library or JAR file and request an instance of the service
from its factory. The lifecycle of components is also automatically handled. When all instances of
services in a component are released, the shared library will be unloaded.

What is the SCA Kernel


The SCA Kernel is a collection of common services that reside in the SCAKernel and SCAKernelUtil
shared libraries.
One of the main functions the kernel provides is the lifecycle management of services. The process of
getting instances of service objects, tracking their use and deleting them when they are no longer required
is referred to as the lifecycle management. The SCA Kernel performs the following function to help
control lifecycle.
• Maintains a catalog of services and the shared libraries that contain them.
• Loads the required shared libraries for services when they are requested.
• Initializes the shared libraries which makes available to the application all of the services they
contain.
• Gets instances of the class for a service by calling its factory method.
• Unloads the shared library when it is no longer required.

The SCA Kernel is composed of the following services.


• ServiceManager which is responsible for the lifecycle management of services.
• SharedLibraryManager which is responsible for loading and unloading of shared libraries.
• TextTranslation which provides the core message processing functions.
• EventManager which provides facilities for event processing.
14 SCA Framework User’s Guide
The SCA Framework

The SCA Framework


The SCA Framework is composed of the SCA Kernel, utility services, and supporting infrastructure. It
is delivered as a collection of shared libraries, Python files, Java files, XML files, and other configuration
files. The framework facilitates the designing, coding, and building of applications through several
facilities. These facilities are accessed though a set of common services using interfaces provided by the
SCA Framework. They currently include the following:
• Loading and lifecycle management of services
• Error and exception management
• Event support
• Implementation reuse support
• Memory management
• Messaging support
• Scripting support
• Multithreading support
• Regular expression searching
• Remoting support
• I/O
• System Utilities
• XML parsing

Some of the infrastructure related utilities provided by the SCA Framework include the following:
• Build system based on the SCons software
• IDL compiler
Chapter 2: SCA Overview 15
Language support

Language support
The SCA Framework language support differs from language to language. The level of support for a
given language can be described by the following capabilities.
• Can you call SCA interfaces implemented in the same language or in other languages?
• Can you implement a SCA interface in the language?
• Can you implement a SCA service in the language?

The following is the supports matrix for the languages currently supported.

Language Call Interface Implement Interfaces Implement Services


C++ Yes Yes Yes
Java Yes Yes Yes
C# Yes Yes Yes
Visual Basic Yes Yes Yes
Other .NET Languages Yes No No
Python Yes Yes No
16 SCA Framework User’s Guide
Platform support

Platform support
The SCA Framework is currently support on the following Windows, Linux and UNIX platforms.

Identifier Description
aix IBM RS/6000 AIX, 64 bit
aixi8 IBM RS/6000 AIX, ILP64 bit
aix32 IBM RS/6000 AIX, 32 bit
hpux Hewlett-Packard HP-UX PA-RISC, 64 bit
hpuxi8 Hewlett-Packard HP-UX PA-RISC, ILP64 bit
hpux32 Hewlett-Packard HP-UX PA-RISC, 32 bit
hpuxipf Hewlett-Packard HP-UX IPF (IA-64)
hpuxipfi8 Hewlett-Packard HP-UX IPF (IA- 64) (ILP64)
irix SGI Irix, 64-bit
linux64 Linux on Intel x86_64 or AMD Opteron hardware, 64 bit
linux64i8 Linux on Intel x86_64 or AMD Opteron hardware, ILP64
bit
linux32 Linux on Intel x86 or similar AMD hardware, 32 bit
linuxipf Linux on Intel IPF (IA-64) hardware
linuxipfi8 Linux on Intel IPF (IA- 64) hardware (ILP64)
solaris Solaris on Sparc hardware, 64 bit
solarisi8 Solaris on Sparc hardware, ILP64 bit
solaris32 Solaris on Sparc hardware, 32 bit
win64 Windows on Intel x86_64 or AMD Opteron hardware, 64
bit
win64i8 Windows on Intel x86_64 or AMD Opteron
hardware,ILP64 bit
win32 Windows on x86 or similar AMD hardware, 32 bit

Note that not all of the advanced features of the platform are supported on all platforms.
Chapter 2: SCA Overview 17
Summary

Summary
An important thing to remember about the SCA Architecture is that it is not anything entirely new or
radical.
• SCA interfaces are just C++ pure virtual classes or Java or .NET interface classes
• Services are made up of one or more normal language classes.
• Components are just shared libraries or JAR files

The development of SCA component is not that different from the development of a normal C++
application.
What SCA provides is a formalization of the processes that govern normal object based programming
practices. In addition to this, the SCA Framework provides a set of tools that automates much of the
mundane aspects of building and deploying SCA components. These include benefits at both build time
and run time. For example the build time benefits include the automatic generation of much of the
infrastructural code required by SCA service like the service factories. At runtime the SCA Kernel
provides the automatic lifecycle management of SCA components.
The benefits provided by SCA do not come completely free. In order to provide them it is necessary to
impose some restrictions on what you are allowed to do. An example of this is the restriction on the type
of interface arguments and return values that are allowed. Because of the requirement that the API
defined by the IDL language must be implemented in a number of different languages and you must be
able to marshal the data from one language to the other at run time, you are only allowed to use types that
are fully defined. This means that indescript types like pointers are not allowed. Full details on all of these
restrictions are presented in the appropriate chapters of this manual.
In summary, the use of interface-based programming and the SCA Framework provide a number of
benefits to the developers:
• The success of any large scale system may be strongly influenced by the design of its interfaces.
The use of an IDL promotes good software engineering practice by reinforcing the idea of good
interface design by forcing the developer to consider the interfaces to the system before the
implementation details are coded.
• Because the IDL language is different from the various implementation languages, it enables
cross language applications development. You can use any of the supported implementation
languages to implement the API defined in an interface.
• The use of an IDL compiler can greatly enhance productivity by automating the generation of
much of the code required to implement the many low-level details. This frees the developer
from performing these mundane tasks.
• Similar to multi-language support, the use of IDL also allows for the transparent access between
SCA services and clients running on different computers.
• Clients and services can be implemented in any of the supported programming languages and do
not have to be implemented in the same language.
• Inter-process communication is automatically provided by the Framework.
18 SCA Framework User’s Guide
Summary

• A service’s implementation can change without affecting the client, as long as the interface does
not change. Developers can replace an existing version of a service with a new version without
requiring any changes to the client.
• Applications can be built on a component-by-component basis.

A service can be used by all applications that use the SCA Framework.
Chapter 3: A SCA Hello World Application
SCA Framework User’s Guide

3 A SCA Hello World Application

 Introduction 20
 Defining the Interfaces 21

Defining the Service 24
 Defining the Component 26
 Generating the Code Skeletons 28
 Building the Component 34
 Creating a Client for the Service 35

Intra-language Support 45

Summary 46
20 SCA Framework User’s Guide
Introduction

Introduction
The Simulation Component Architecture (SCA) Framework is designed to enable the development of
reusable software components quickly and efficiently. In this chapter we will show the actual steps
involved in implementing a SCA component by creating a simple component that contains one service
named HelloWorld. This service will implement the SCAIHello interface. We will then show an example
client application that uses this service. Each of these examples will be done in the following languages
which are currently supported by the SCA Framework.
• C++
• C#
• Java
• Visual Basic
• Python

Currently you cannot implement SCA components in Python so for this language we will only show a
sample client application.
The following are the basic steps that you must follow to create a SCA component. The steps are the same
regardless of which implementation language you choose.
1. Define the interfaces
2. Define the services
3. Define the component
4. Generating code stubs for the language of your choice
5. Add the required functionality to the generated stubs
All of the code for the examples created in this chapter is delivered with the SCA Software Development
Kit. The actual building of the components and client applications will not be discussed in this chapter.
If you wish to actual build and run the samples please consult the instructions delivered with the
examples.
Chapter 3: A SCA Hello World Application 21
Defining the Interfaces

Defining the Interfaces


The first step in creating a service is to define the interfaces that the service will support. These interfaces
form the API that the service's clients will use, and they should not change once they are delivered to the
client. Because of this, it is important that the appropriate thought is given to develop consistent and
well-designed interfaces.
Interfaces are defined by using the SCA interface definition language (IDL). The SCA IDL compiler
processes the IDL and generates the required source files needed to access the functionality defined by
the interfaces in each of the supported languages. The SCA IDL is based on the OMG IDL and is
described in detail in the IDL Language chapter of this manual
IDL files have the extension .idl and may contain as many interface and type definitions as you need.
Our HelloWorld service will implement one interface which is called SCAIHello. This interface has one
method named printHello which requires a single string argument which is the implementation language
of the client calling the service. The printHello method for our simple service will just print the language
that it was called from and the language that it is implemented in.

The following is the IDL definition for the SCAIHello interface.

#ifndef SCA_HELLOWORLD_EXAMPLE_HELLOWORLD_IDL_INCLUDED
#define SCA_HELLOWORLD_EXAMPLE_HELLOWORLD_IDL_INCLUDED

#include "SCA/Service.idl"

module SCA { module HelloWorld { module Example {

interface SCAIHello : SCAIService


{
SCAResult printHello (in SCAString sName );
};

}; }; };

#endif

The IDL definition contains the following sections.

Include guard
The first two lines of the IDL definition contain the standard include guard definitions that keep the file
from being expanded more than once during each compilation. This may happen if the IDL file is
included by more than one file that is part of the current compilation. To make sure the guard name is
unique, the convention is use the full relative path to the file being guarded followed by _INCLUDED.
In this case we have used SCA_HELLOWORLD_EXAMPLE_HELLOWORLD_IDL_INCLUDED for
the guard name.
22 SCA Framework User’s Guide
Defining the Interfaces

Include declarations
The next section of the IDL file is for the include statements for any other IDL files that are required by
the interface definitions. If the SCA Framework or some other service has previously defined an
interface that is being implemented, the IDL file where it is defined should be included, instead of
redefining the interface in your file.
It is important to remember that the file names used in these include statements must include the correct
relative directory location in the delivery tree for the IDL files. You should not use the directory names
in the source tree. This is because the IDL you create must be delivered to the users of your service. When
they use the IDL files, they will be using them from the delivery tree. They should have no knowledge
of the structure of your source tree. To enforce this, The IDL compiler will not look in the source tree for
the files that are included.
The build system will automatically copy the IDL files from the source tree into the correct location in
your delivery tree before it runs the IDL compiler. However, if the IDL compiler is manually run, you
may need to copy the files and add appropriate include paths on the command.
In our IDL file we have included the IDL file SCA/Service.idl because the SCAIHello interface inherits
from the SCAIService interface which is defined in this file.

Module declarations
The IDL file's module statements are used to define the namespace and the locations in the delivery tree
where the IDL and header files are stored.
A namespace should always be used for interface definitions to minimize naming collisions with other
definitions. The fully qualified name of an interface is determined by combining the module names and
the interface name. The fully qualified interface name in this example is
SCA.HelloWorld.Example.SCAIHello.
The implementation language's namespace for the interface is also taken directly from the module
statements as well. For example in C++ the namespace in this example would be
SCA::HelloWorld::Example and in Python it would be SCA.HelloWorld.Example.
The installation subdirectories for the IDL in the delivery tree are also taken from the module statements.
In this example, the IDL files will be stored in the idl/SCA/HelloWorld/Example directory in the delivery
tree. This is the relative location that should be used by all users of the SCAIHello interface.
In a similar manner, any language specific support files that are generated by the IDL compiler and are
required for the clients to use your interface will also be stored in the delivery tree. The installation
subdirectories for these files are also taken from the module statements. In this example, the C++ include
file for this interface will be stored in the include/SCA/HelloWorld/Example directory in the delivery
tree.
Chapter 3: A SCA Hello World Application 23
Defining the Interfaces

Interface declarations
Each interface is declared with an interface statement that contains the definitions of the methods it
implements. The syntax for interface definition is similar to C++ class declarations. The main difference
is that each parameter in the method definitions must contain a direction parameter. This parameter can
be in, out, or inout and is used to define whether the parameter is input only, output only, or both input
and output. It is used to determine how the parameters are declared and passed. It also determines the
data transfer direction for marshalling the parameters between different languages or different address
spaces.
A SCA Framework requires that each interface inherits from the SCAIService interface. This inheritance
may be direct, as in this example, or indirectly through another interface from which it inherits. The
SCAIService interface defines the methods used to support interface navigation, reference counting, and
runtime introspection. You need to include the file that defines this interface, SCA/Service.idl, in the IDL
file unless it is already included in another file that you have included. Since every interface must inherit
from the SCAIService interface, the IDL compiler will generate all the code that is required to implement
the methods it contains.
24 SCA Framework User’s Guide
Defining the Service

Defining the Service


After defining the interfaces in the IDL file, you must define the service itself. A service definition
language (SDL) file is used to define which interfaces a service supports. It also defines the structure of
the classes that will implement the interfaces. The IDL compiler uses this information to generate a set
of skeleton implementation classes to which the developer adds the required functionality. When the
build system compiles your service, it will also run the IDL compiler to generate the implementation for
the required base classes.
SDL files have the extension .sdl and only one service definition is allowed in each SDL file.
We have defined the HelloWorld service which implements the SCAIHello interface with the SDL file
HelloWorld.sdl, which is listed below.

#ifndef HELLOWORLDCPP_HELLOWORLD_SDL_INCLUDED
#define HELLOWORLDCPP_HELLOWORLD_SDL_INCLUDED

#include "SCA/HelloWorld/Example/HelloWorld.idl"

module Samples { module HelloWorld { module Example {

service SCA.Example.CPP.HelloWorld {
interface SCA::HelloWorld::Example::SCAIHello;
};

}; }; };

#endif

Note that this is the SDL file for the C++ implementation of the HelloWorld service. The only difference
for the implementation in the other languages is the include guard and the actual name of the service.
Most of the SDL file is similar to the IDL file. It contains the include guard, include statements, module
statements and service statements.

Include guard
The first two lines of the SDL definition contain the standard include guard that keep the file from being
expanded more than once during each compilation. To make sure the guard name is unique, the
convention is use the full relative path to the file being guarded followed by _INCLUDED. In this case
we have used HELLOWORLDCPP_HELLOWORLD_SDL_INCLUDED for the guard name.

Include declarations
The next section of the SDL file is for the include statements. You should include all the IDL files that
define the interfaces implemented by the service. Once again remember that when including IDL files
you need to use the correct relative directory location in the deliver tree and not the directory names from
the source tree.
Chapter 3: A SCA Hello World Application 25
Defining the Service

Module declarations
The SDL file's module statements are used to define the implementation code's namespace. For example,
in C++, the namespace for the service's implementation class would be Samples::HelloWorld::Example.
The general policy for SDL files is that each service is put in its own separate implementation code
namespace to minimize the change of symbol collisions.
The SDL namespace is not related to the IDL namespace and will normally be different. Remember that
the interface namespace is exposed to clients and has different requirements than the implementation
code's namespace. The IDL namespace needs to coexist with all of the other interfaces defined by all of
the components in your application. It therefore should follow some application determined convention.
The SDL namespace is unique to your implementation and you can choose any appropriate value you
like. One common convention is to use the directory structure of the source tree for you namespace.
There is no installation information needed for services because they are delivered in components and
not installed by themselves. As a result, the SDL namespace has no affect on any installation decisions.

Service declaration
The definition of the service starts with the service statement in the SDL file. The fully qualified service
name is the name clients will use to request instances of this service and is defined by the name following
the service statement. It must be a fully qualified name to make sure the service name is unique from all
other service names in the system. The service name in the example is SCA.Example.CPP.HelloWorld.
The fully qualified service name is not based on the namespace defined by the SDL file's module
statements. The service name is also not related to the IDL namespace, even though it may be similar to
it. The last part of the service name, HelloWorld, is used as the name of the top level class that will be
generated to implement the service.
26 SCA Framework User’s Guide
Defining the Component

Defining the Component


Once the service has been defined, a component must be defined to contain it. The exact format of the
component generated by the build system depends on the language it is implemented in. If you are using
C++, C# or Visual Basic, the component is a dynamically linked shared library and for Java it will be a
jar file.
CDL files have the extension .cdl and only one component definition is allowed in each CDL file.
In our example, the CPPGreeting component contains one service, HelloWorld. The following is the
CDL file for the component.

#ifndef HELLOWORLDCPP_HELLOWORLD_CDL_INCLUDED
#define HELLOWORLDCPP_HELLOWORLD_CDL_INCLUDED

#include "HelloWorld.sdl"

component SCA.HelloWorld.CPPGreeting
{
service HelloWorld;
};

#endif

Once again, note that this is the CDL file for the C++ implementation of the HelloWorld service. The
only difference for the implementation in the other languages is the include guard and the actual name of
the component.
The component definition does not require a namespace or module declarations. If you include one it will
have no affect on the build.

Include guard
The first two lines of the CDL definition contain the standard include guard that keep the file from being
expanded more than once during each compilation. To make sure the guard name is unique, the
convention is use the full relative path to the file being guarded followed by _INCLUDED. In this case
we have used HELLOWORLDCPP_HELLOWORLD_CDL_INCLUDED for the guard name.

Include declarations
The next section of the CDL file is for the include statements. You should include all the SDL files that
define the services that the component will contain. Because the SDL files are never delivered to the
clients of your services, they are never installed in the delivery tree. As a result, the directory structure
for including SDL files should be relative to the source tree and not the delivery tree.
Chapter 3: A SCA Hello World Application 27
Defining the Component

Component declaration
The fully qualified component name is determined directly from the name following the component
statement, which is SCA.HelloWorld.CPPGreeting in the example. It is not related to the IDL
namespace, SDL namespace, or service name, though it may look similar to any of them. The short name
is CPPGreeting, and it is used for the name of the generated library file.
The fully qualified component defines the relative path where the build system stores the shared library.
The delivery locations for the example components in each of the supported languages are show below.

Language Platform File


C++ Windows WINNT/bin/SCA/HelloWorld/CPPGreeting.dll
Linux LX86/lib/SCA /HelloWorld/libGreeting.so
Java All lib/java/SCA/HelloWorld/JavaGreeting.jar
C# Windows WINNT/bin/SCA/HelloWorld/CSGreeting.dll
Visual Basic Windows WINNT/bin/SCA/HelloWorld/VBGreeting.dll
28 SCA Framework User’s Guide
Generating the Code Skeletons

Generating the Code Skeletons


Once the IDL and SDL files have been created, the IDL compiler can be used to generate the skeleton
code for the implementation of the service. This code will only include the methods that are defined in
the interfaces that the service will implement. The exception is the SCAIService interface; its methods
are implemented in a base class that the HelloWorld service implementation needs to inherit from. The
code for the base class will be generated as part of the build process.

The genskeleton command


A special command called genskeleton is provided with the SDK. It is used to run the IDL compiler and
create these code file skeletons. The genskeleton command takes an option to indicate which language
the services will be implemented in. The default is to generate the implementation in C++. The
genskeleton command is located in the SCA tools directory.
Using the definitions in the SDL files, the IDL compiler will generate a number of language specific
skeleton code files in the current directory. For example, when running the genskeleton command for
C++, it will create a .h header and a .cpp implementation file.
If there are existing versions of any of the files to be generated, then all of the new files will be generated
with the additional extension of .new. If you add the -r option to the genskeleton command, then the
existing files will be renamed by adding an extension of .old and the newly generated files will not nave
the .new extension.
These files can now be used as a base to implement the service.
The genskeleton command will only work correctly if you are running from a directory inside of a
properly formatted SCA source tree. This means the directory needs to contain a SConscript file and the
source tree must contain a SConstruct in its root directory. These are required because a short build step,
which uses them, is initially run to install any IDL files from the current directory in the source tree into
the delivery tree so the IDL compiler can access them.
The IDL compiler does not need to be manually run on the IDL or CDL files. That will be done as part
of the normal build process when required.

Adding the required functionality to the skeletons


Once you have generated the skeleton files, you can modify them to add whatever details are required to
implement the desired functionality. You are free to add any new methods or data that you require. There
are a couple of things that you cannot change.
• The implementation class must inherit from the IDL generated base class. You may add to the
inheritance structure but you may not remove the generated one.
• You cannot change the signature of the constructor for the implementation class. The IDL
compiler will also generate factory code that is used to instantiate instances of the service and it
requires the signature of the constructor as generated.
Chapter 3: A SCA Hello World Application 29
Generating the Code Skeletons

In the HelloWorld example, the only implementation that is required is a simple write statement in the
printHello method.
In the following sections we show the formats for the generated skeleton file for the implementation in
each of the supported languages. In the example code, the light gray background shows the code
generated by the genskeleton command. The lines of code that have the darker gray background represent
the lines of code that were changed to add the required functionality to the generated skeletons.

Implementing the service in C++


The following genskeleton command will generate the implementation stubs in C++.
/Tools/genskeleton HelloWorld.sdl
Or
/Tools/genskeleton -cxx HelloWorld.sdl
From the SDL, the compiler will generate the following C++ skeleton code files in the current directory.

HelloWorld.h C++ header file for the top level service class
HelloWorld.cpp C++ implementation file for the top level service class

The following is the content of the C++ header file HelloWorld.h that is generated.

#ifndef SAMPLES_HELLOWORLD_EXAMPLE_HELLOWORLD_H_INCLUDED
#define SAMPLES_HELLOWORLD_EXAMPLE_HELLOWORLD_H_INCLUDED

#include "HelloWorldBase.h"

namespace Samples { namespace HelloWorld { namespace Example {

class HelloWorld : public HelloWorldBase


{
public:
// Constructor and Destructor
HelloWorld(SCAIHelloWorldFactoryAccess* factoryAccess);
virtual ~HelloWorld();

// Methods for interface SCA.HelloWorld.Example.SCAIHello


virtual SCA::SCAResult printHello(const SCA::SCAString sName);
};

} } }

#endif

The following is the content of the C++ implementation file HelloWorld.cpp that is generated.
30 SCA Framework User’s Guide
Generating the Code Skeletons

#include "HelloWorld.h"
#include <iostream>

namespace Samples { namespace HelloWorld { namespace Example {

// Constructor
HelloWorld::HelloWorld(SCAIHelloWorldFactoryAccess* factoryAccess)
: HelloWorldBase(factoryAccess)
{
}

// Destructor
HelloWorld::~HelloWorld()
{
}

SCA::SCAResult HelloWorld::printHello(const SCA::SCAString sName)


{
std::cout << sName << " client calling HelloWorld "
<< "implemented in C++" << std::endl;
return SCA::SCASuccess;
}

} } }

Next we just need to add the actual functionality to the stubs. In our simple case, there were no changes
required to the header file. The only change required to the implementation file was to add an include
statement and an output statement in the printHello method.
We now have a complete SCA service implemented in C++ that is ready to be built.

Implementing the service in java


The following genskeleton command will generate the implementation stubs in Java.
/Tools/genskeleton -java HelloWorld.sdl
From the SDL, the compiler will generate the following Java skeleton code file.

HelloWorld.java Java implementation file for the top level service class

For Java, the generated implementation files will not be in the current directory. This is because the Java
compiler uses the relative directory structure to determine the name of the Java package that is created.
The SDL namespace is used to determine this package name. In our example, the generated Java
implementation files will actually be in the directory Samples/HelloWorld/Example relative to the
current directory.
The following is the content of the Java implementation file
Samples/HelloWorld/Example/HelloWorld.java that is generated.
Chapter 3: A SCA Hello World Application 31
Generating the Code Skeletons

package Samples.HelloWorld.Example;

public class HelloWorld extends HelloWorld_base


{
// Constructor
public HelloWorld (SCA.Framework.SCAIServiceProvider provider)
{
super();
setServiceProvider(provider);
}

// Methods for interface SCA.HelloWorld.Example.SCAIHello


public final SCA.SCAResult printHello (String sName)
{
System.out.println(sName+" client calling HelloWorld "+
"implemented in Java");
return SCA.SCAResult.SCASuccess;
}
}

Next we just need to add the actual functionality to the stubs. In our simple case, the only changed
required to the implementation file was to add a print statement in the printHello method and to return
the appropriate value.
We now have a complete SCA service implemented in Java that is ready to be built.

Implementing the service in C#


The following genskeleton command will generate the implementation stubs in C#.

/Tools/genskeleton -csharp HelloWorld.sdl

From the SDL, the compiler will generate the following C# skeleton code file in the current directory.

HelloWorld.cs C# implementation file for the top level service class

The following is the content of the C# implementation file HelloWorld.cs that is generated.
32 SCA Framework User’s Guide
Generating the Code Skeletons

using System.Collections.Generic;
using SCA;

namespace Samples { namespace HelloWorld { namespace Example {

public class HelloWorld: HelloWorld_base ,


SCA.HelloWorld.Example.SCAIHello
{
// Constructor
public HelloWorld (SCA.Framework.SCAIServiceProvider provider)
{
setServiceProvider(provider);
}

// Methods for interface SCA.HelloWorld.Example.SCAIHello


SCA.SCAResult SCA.HelloWorld.Example.SCAIHello.printHello (string
sName)
{
System.Console.WriteLine(sName+" client calling HelloWorld "+
"implemented in C#");
return SCA.SCAResult.SCASuccess;
}

} } }

Next we just need to add the actual functionality to the stubs. In our simple case, the only changed
required to the implementation file was to add a write statement in the printHello method and to return
the appropriate value.
We now have a complete SCA service implemented in C# that is ready to be built.

Implementing the service in visual basic


The following genskeleton command will generate the implementation stubs in Visual Basic.
/Tools/genskeleton -vb HelloWorld.sdl
From the SDL, the compiler will generate the following Visual Basic skeleton code file in the current
directory.

HelloWorld.vb VB implementation file for the top level service class

The following is the content of the Visual Basic implementation file HelloWorld.vb that is generated.
Chapter 3: A SCA Hello World Application 33
Generating the Code Skeletons

Imports System.Collections.Generic

Namespace Samples
Namespace HelloWorld
Namespace Example

Public Class HelloWorld


Inherits HelloWorld_base
Implements SCA.HelloWorld.Example.SCAIHello

' Constructor
Public Sub New(ByVal provider As SCA.Framework.SCAIServiceProvider)
setServiceProvider(provider)
End Sub

' Methods for interface SCA.HelloWorld.Example.SCAIHello


Public Function printHello (ByVal sName As String) As SCA.SCAResult
_
Implements SCA.HelloWorld.Example.SCAIHello.printHello
System.Console.WriteLine(sName & " client calling HelloWorld " &
_
"implemented in VB")
Return SCA.SCAResult.SCASuccess
End Function

End Class

End Namespace
End Namespace
End Namespace

Next we just need to add the actual functionality to the stubs. In our simple case, the only change required
to the implementation file was to add a write statement in the printHello method and to return the
appropriate value.
We now have a complete SCA service implemented in Visual Basic that is ready to be built.
34 SCA Framework User’s Guide
Building the Component

Building the Component


Once we have created the implementation files for our service, we can now build the component. We will
not go into details on how this is done in this chapter because it will be discussed in detail latter in the
manual.
All of the code for the examples created in this chapter is delivered with the SCA Software Development
Kit. If you wish to actually build and run the samples please consult the instructions delivered with the
examples.
In this section what we will discuss is some of the processing that the build system will take care of to
build a SCA component. All of these steps are automatic and require no actions by the developer.
As part of building a SCA component, the SCA build system will perform the following general steps.
The exact details of these and what each generates is a function of the implementation language being
used and the platform you are building on.
• Run the IDL compiler on the IDL file to generate the appropriate language support files. For
C++ these include header files that are stored in the delivery tree. For the other language they
include implementation files that will be stored in the object directory which will be compiled
and linked as required by the language.
• Run the IDL compiler on the SDL file to generate the required base class implementation files
for the service. These will be stored in the object directory and be compiled and linked in with
your component.
• Run the IDL compiler on the CDL file to generate the required initialization function for the
component. These will be stored in the object directory and be compiled and linked in with your
component. Not all languages require this step.
• Compile and link your code for the implementation of the service.
Chapter 3: A SCA Hello World Application 35
Creating a Client for the Service

Creating a Client for the Service


Now that we have a working SCA component, the next sections will show how we can create a simple
client application that will use our component in each of the supported languages.
The basic steps for the client application are as follows.
1. Initialize the SCA Kernel
2. Get an instance of the HelloWorld service which returns a SCAIService interface on it.
3. Obtain a SCAIHello interface on the service instance. This usually involves calling the
getInterface method in the SCAIService interface.
4. Call the printHello method in the interface
5. Terminate the SCA Kernel
The client applications that we will create in these sections are all stand-alone programs. It is also
possible to use SCA services from code that that is part of the implementation of another SCA service.
When doing this, it is not necessary to initialize or terminate the SCA Kernel because it will already be
active. Also, the process of getting an instance of a SCA service is usually different when you are inside
the implementation of another SCA service. Consult the language mapping chapter for your
implementation language for the complete details.

Implementing the Application in C++


The following is a sample C++ application that will exercise our HelloWorld service.
36 SCA Framework User’s Guide
Creating a Client for the Service

#include <iostream>
#include <SCA/HelloWorld/Example/SCAIHello.h>
#include <SCA/SCAKernel.h>

using namespace std;


using namespace SCA;
using namespace SCA::HelloWorld::Example;

int main()
{
try {
initializeSCAKernel(1);
} catch (SCAException& e) {
cout << "Initialization of SCAKernel failed" << endl << e.what()
<< endl;
return 0;
}

SCAIService spService;
SCAIHello hwInf;

try {
spService = getSCAService("SCA.Example.CPP.HelloWorld");
hwInf = static_cast<SCAIHello>(spService);
spService = NULLSP;
hwInf->printHello("C++");
hwInf = NULLSP;
} catch (SCAException& e) {
cout << "Load of HelloWorld service failed" << endl << e.what()
<< endl;
}

try {
terminateSCAKernel();
} catch (SCAException& e) {
cout << "Termination of the SCAKernel failed" << endl
<< e.what() << endl;
}
return 0;
}

The basic SCA Kernel operations are provided in the SCA/SCAKernel.h header file. These include the
following functions that are used in this example.
Chapter 3: A SCA Hello World Application 37
Creating a Client for the Service

void initializeSCAKernel( SCA::SCAInt32 verbose=0,


const SCA::SCAString& configPath="" );

SCA::SCAIService getSCAService( const SCA::SCAString name );

SCA::SCAInt32 terminateSCAKernel();

All of these will throw an exception if they encounter an error so they have been included in try/catch
blocks in the sample application.
The first thing our application must do is initialize the SCA kernel.

initializeSCAKernel(1);

Since this call may throw an exception, in the actual application we have enclosed it in a try/catch block.
This is the case for all of the functions defined in the SCA/SCAKernel.h header file that we will be using.
Once we have initialized the SCA Kernel, we need to get an instance of the HelloWorld service. In this
example we are getting an instance of the version of the service that is implemented in C++ but it could
have been one of the versions implemented in any of the other languages by just changing the service
name. To do this we use the following lines of code.

SCAIService spService;
spService = getSCAService("SCA.Example.CPP.HelloWorld");

The getSCAService function will always return a SCAIService interface pointer on the service. This is
possible because every SCA interface must inherit from the SCAIService interface. But what we really
want is a SCAIHello interface pointer. In the C++ language mapping, SCA interface pointers are special
C++ classes know as smart pointers. These smart pointers can automate many of the details of using the
interfaces. This includes the automatic handling of reference counting and providing a simplified method
of interface navigation using normal C++ casting syntax. The following lines of code will get a
SCAIHello interface pointer from the SCAIService pointer that was returned when we got an instance of
the service.

SCAIHello hwInf;
hwInf = static_cast<SCAIHello>(spService);

Once we have the SCAIHello interface pointer we can then call the printHello method that it contains.

hwInf->printHello("C++");

The final thing our application should do is terminate the SCA kernel.
38 SCA Framework User’s Guide
Creating a Client for the Service

terminateSCAKernel();

Implementing the Application in Java


The following is a sample Java application that will exercise our HelloWorld service.

import SCA.*;
import SCA.HelloWorld.Example.*;
import SCA.SystemProvider.*;

public class Driver{


public static void main (String args[]) {

try{
SCA.SystemProvider.loadSCA();
} catch (SCASystemException e) {
System.out.println("Initialization of SCAKernel failed\n" +
e.what());
}

SCAIService spService;
SCAIHello hwInf;

try{
spService = SCA.SystemProvider.getService(
"SCA.Example.Java.HelloWorld");
hwInf = (SCAIHello)spService.getInterface(
"SCA.HelloWorld.Example.SCAIHello");
hwInf.printHello("Java");
} catch (SCASystemException e) {
System.out.println("Failed to get HelloWorld\n" + e.what());
}

try{
SCA.SystemProvider.unloadSCA();
} catch (SCASystemException e) {
System.out.println("Termination of the SCAKernel failed\n" +
e.what());
}

}
}

In Java, the SCA.SystemProvider interface provided by the SCA Kernel is used to access the basic SCA
Kernel operations. All of the method of this interface will throw exceptions if they encounter errors, so
be sure to enclose these calls in a try/catch block.
The first thing our application must do is initialize the SCA kernel utilizing this interface.
Chapter 3: A SCA Hello World Application 39
Creating a Client for the Service

import SCA.SystemProvider.*;
SCA.SystemProvider.loadSCA();

Once we have initialized the SCA Kernel, we need to get an instance of the HelloWorld service. In this
example we are getting an instance of the version of the service that is implemented in Java but it could
have been one of the versions implemented in any of the other languages by just changing the service
name. To do this we use the following lines of code.

SCAIService spService;
spService = SCA.SystemProvider.getService(
"SCA.Example.Java.HelloWorld");

The getService function will always return a SCAIService interface pointer on the service. This is
possible because every SCA interface must inherit from the SCAIService interface. But what we really
want is a SCAIHello interface pointer. In the Java language mapping it is only possible to navigate from
one interface to anther using the normal JAVA casting syntax if the interface is pointing to a service
implemented in Java. If the service is implemented in any other language you must make an explicit
getInterface call to do the navigation. Since you never know for sure what language the service you are
using is written in, it is a good practice to always use this syntax. The following lines of code will get a
SCAIHello interface pointer from the SCAIService pointer that was returned when we got an instance of
the service.

SCAIHello hwInf;
hwInf = (SCAIHello)spService.getInterface(
"SCA.HelloWorld.Example.SCAIHello");

Once we have the SCAIHello interface pointer we can then call the printHello method that it contains.
.

hwInf.printHello("Java");

The final thing our application should do is terminate the SCA kernel.

SCA.SystemProvider.unloadSCA();

Implementing the Application in C#


The following is a sample C# application that will exercise our HelloWorld service..
40 SCA Framework User’s Guide
Creating a Client for the Service

using System;
using SCA;
using SCA.HelloWorld.Example;

class CSDriver
{
static void Main(string[] args)
{
try {
SCA.SystemProvider.loadSCA();
} catch (SCAException e) {
Console.WriteLine("Initialization of SCAKernel failed\n" +
e.what());
}

SCAIService spService;
SCAIHello hwInf;

try {
spService = SCA.SystemProvider.getService(
"SCA.Example.CS.HelloWorld");
hwInf = (SCAIHello)spService.getInterface(
"SCA.HelloWorld.Example.SCAIHello");
spService = null;
hwInf.printHello("C#");
} catch (SCAException e) {
Console.WriteLine("Load of HelloWorld service failed\n" +
e.what());
} finally {
hwInf = null;
}

try {
SCA.SystemProvider.unloadSCA();
} catch (SCAException e) {
Console.WriteLine("Termination of the kernel failed\n" +
e.what());
}

}
}

In C#, the SCA.SystemProvider interface provided by the SCA Kernel is used to access the basic SCA
Kernel operations. All of the method of this interface will throw exceptions if they encounter errors, so
be sure to enclose these calls in a try/catch block.
The first thing our application must do is initialize the SCA kernel utilizing this interface.
Chapter 3: A SCA Hello World Application 41
Creating a Client for the Service

using SCA;
SCA.SystemProvider.loadSCA();

Once we have initialized the SCA Kernel, we need to get an instance of the HelloWorld service. In this
example we are getting an instance of the version of the service that is implemented in C# but it could
have been one of the versions implemented in any of the other languages by just changing the service
name. To do this we use the following lines of code.

SCAIService spService;
spService = SCA.SystemProvider.getService(
"SCA.Example.CS.HelloWorld");

The getService function will always return a SCAIService interface pointer on the service. This is
possible because every SCA interface must inherit from the SCAIService interface. But what we really
want is a SCAIHello interface pointer. In the C# language mapping it is only possible to navigate from
one interface to anther using the normal C# casting syntax if the interface is pointing to a service
implemented in one of the .Net languages which include C# and VB. If the service is implemented in any
other language you must make an explicit getInterface call to do the navigation. Since you never know
for sure what language the service you are using is written in, it is a good practice to always use this
syntax. The following lines of code will get a SCAIHello interface pointer from the SCAIService pointer
that was returned when we got an instance of the service.

SCAIHello hwInf;
hwInf = (SCAIHello)spService.getInterface(
"SCA.HelloWorld.Example.SCAIHello");

Once we have the SCAIHello interface pointer we can then call the printHello method that it contains.
.

hwInf.printHello("C#");

The final thing our application should do is terminate the SCA kernel.

SCA.SystemProvider.unloadSCA();

Implementing the Application in Visual Basic


The following is a sample Visual Basic application that will exercise our HelloWorld service.
42 SCA Framework User’s Guide
Creating a Client for the Service

Imports SCA
Imports System
Imports SCA.HelloWorld.Example

Module ModuleMain

Sub Main(ByVal args As String())

Try
SystemProvider.loadSCA()
Catch e As SCASystemException
System.Console.WriteLine("Initialization of SCAKernel failed\n" +
_
e.ToString())
End Try

Try
Dim spService As SCA.SCAIService = SystemProvider.getService( _
"SCA.Example.VB.HelloWorld")
Dim hwInf As SCAIHello = CType(spService.getInterface( _
"SCA.HelloWorld.Example.SCAIHello"), SCAIHello)
hwInf.printHello("Visual Basic")
Catch e As SCASystemException
System.Console.WriteLine("Load of HelloWorld service failed\n" +
_
e.ToString())
End Try

Try
SystemProvider.unloadSCA()
Catch e As SCASystemException
System.Console.WriteLine("Termination of SCAKernel failed\n" + _
e.ToString())
End Try

End Sub

End Module

In Visual Basic, the SCA.SystemProvider interface provided by the SCA Kernel is used to access the
basic SCA Kernel operations. All of the method of this interface will throw exceptions if they encounter
errors, so be sure to enclose these calls in a try/catch block.
The first thing our application must do is initialize the SCA kernel utilizing this interface.

Imports SCA
SystemProvider.loadSCA()

Once we have initialized the SCA Kernel, we need to get an instance of the HelloWorld service. In this
example we are getting an instance of the version of the service that is implemented in Visual Basic but
Chapter 3: A SCA Hello World Application 43
Creating a Client for the Service

it could have been one of the versions implemented in any of the other languages by just changing the
service name. To do this we use the following line of code.

Dim spService As SCA.SCAIService = SystemProvider.getService( _


"SCA.Example.VB.HelloWorld")

The getService function will always return a SCAIService interface pointer on the service. This is
possible because every SCA interface must inherit from the SCAIService interface. But what we really
want is a SCAIHello interface pointer. In the Visual Basic language mapping it is only possible to
navigate from one interface to anther using the Visual Basic DirectCast keyword if the interface is
pointing to a service implemented in one of the .Net languages which include C# and VB. If the service
is implemented in any other language you must make an explicit getInterface call to do the navigation.
Since you never know for sure what language the service you are using is written in, it is a good practice
to always use this syntax. The following lines of code will get a SCAIHello interface pointer from the
SCAIService pointer that was returned when we got an instance of the service.

Dim hwInf As SCAIHello = CType(spService.getInterface( _


"SCA.HelloWorld.Example.SCAIHello"), SCAIHello)

Once we have the SCAIHello interface pointer we can then call the printHello method that it contains.

hwInf.printHello("Visual Basic")

The final thing our application should do is terminate the SCA kernel.

SystemProvider.unloadSCA()

Implementing the Application in Python


We have not discussed using Python yet because currently you cannot implement a SCA component in
Python. But you can easily use SCA services written in any of the other support languages from Python.
The following is a sample Python application or script that will exercise our HelloWorld service.
44 SCA Framework User’s Guide
Creating a Client for the Service

try:
import SCA

svc = SCA.getService("SCA.Example.CPP.HelloWorld")

(ret,hwinf) = svc.getInterface("SCA.HelloWorld.Example.SCAIHello")

hwinf.printHello("Python")

except SCA.SCAException, exc:


print "SCAException:",exc.what()

In Python, the SCA module provided by the SCA Kernel is used to access the basic SCA Kernel
operations. All of the method of this interface will throw exceptions if they encounter errors, so be sure
to enclose these calls in a try/except block.
The first thing our application must do is initialize the SCA kernel utilizing this interface. This is done
by importing the SCA module. In Python there is no explicit call required to initialize the SCA Kernel.
It is done automatically when it is required.

import SCA

Once we have initialized the SCA Kernel, we need to get an instance of the HelloWorld service. In this
example we are getting an instance of the version of the service that is implemented in C++ but it could
have been one of the versions implemented in any of the other languages by just changing the service
name. To do this we use the following line of code.

svc = SCA.getService("SCA.Example.CPP.HelloWorld")

The getService function will always return a SCAIService interface pointer on the service. This is
possible because every SCA interface must inherit from the SCAIService interface. But what we really
want is a SCAIHello interface pointer. Since Python is a type less language, it is only possible to navigate
from one interface to anther using an explicit getInterface call to do the navigation. The following line of
code will get a SCAIHello interface pointer from the SCAIService pointer that was returned when we got
an instance of the service.

(ret,hwinf) = svc.getInterface("SCA.HelloWorld.Example.SCAIHello")

Once we have the SCAIHello interface pointer we can then call the printHello method that it contains.

hwinf.printHello("Python")

In Python there is no requirement to terminate the SCA kernel.


Chapter 3: A SCA Hello World Application 45
Intra-language Support

Intra-language Support
46 SCA Framework User’s Guide
Summary

Summary
In this chapter we have shown how to develop a simple SCA HelloWorld service in each of the supported
languages. Let's review the basic steps that are required.
• Design the interfaces the service will support and code them in IDL
• Create the SDL file for the service.
• Create the CDL file for the component.
• Run the IDL compiler to generated skeleton implementation code for the service.
• Add code to skeletons to implement the desired behavior for each interface method.
• Build the component using the SCA build system.

We then showed how to implement a simple client application in each of the supported languages that
exercised our HelloWorld service.
Chapter 4: The IDL Language
SCA Framework User’s Guide

4 The IDL Language

 Introduction 48
 Source Files 49

Lexical Rules 51
 Preprocessing 56
 IDL Specification for Interfaces and Types 57
 Constants 70
 Modules, Names and Scoping 74

Interfaces and Operations 78

Exceptions 85
 SDL Specifications 86
 CDL Specifications 89

SCA Component Declaration 94

Using the SCA-IDL Compiler 96

Summary 100
48 SCA Framework User’s Guide
Introduction

Introduction
The Object Management Group (OMG) Interface Definition Language, or IDL, is the language used to
describe SCA interfaces. The OMG is an open membership, not-for-profit consortium that produces and
maintains computer industry specifications for interoperable enterprise applications. Some of these
specifications include the Unified Modeling Language, or UML and the CORBA middleware platform.
An interface definition written in the IDL language completely defines the interface. This includes its
methods, each of their parameters and any user constructed data types required. The IDL definitions of
the interfaces provide the information needed to develop clients that use the interface's operations.
Extensions to the OMG IDL language have been added to allow for the description of SCA services and
components.
The IDL language is a purely descriptive language. This means that services are not written in IDL, but
in languages for which mappings from the IDL concepts have been defined. Currently the SCA
Framework supports mapping for the C++, Java, C#, Visual Basic and Python languages.
Chapter 4: The IDL Language 49
Source Files

Source Files
The SCA IDL compiler processes three types of source files. All of these files use the same IDL language
but each is restricted to different types of definitions.

IDL
These source files contain definitions of interfaces and user constructed data types. These files must have
an extension of ".idl". These definitions declare the exposed API for a service that is available to its users.
No implementation details are contained in the IDL files.

SDL
These source files contain service definitions and must have an extension of ".sdl". Service definitions
specify the implementation details that the IDL compiler needs to generate the appropriate code to link
a service to the SCA Framework. This information includes which interfaces the service will implement
and how these interfaces are mapped to language specific class definitions which will be used in the
implementation.

CDL
These source files contain component definitions and must have an extension of ".cdl". Component
definitions specify which services a component will contain.
The separation of the different types of definitions into different files has been done for several reasons.
• Because IDL files contain the definitions of the published interfaces and their supporting types,
these are generally delivered with their components. Since service and component definitions
contain implementation specific information you do not want to deliver these. By separating
these definitions from the interface and type definitions, they do not need to be delivered.
• Separating the definitions into separate files allow them to be placed in the appropriate locations
in the source tree. For example a component may include several services and each is
implemented in a different directory in the source tree. This way the SDL files can be places with
their service definition and the CDL file place where the component is built.
• The separate files allow developers and the SCA Build system to easily determine the types of
objects that are being built in the various source tree directories without having to examine the
contents of the files. For example, if a directory contains a CDL file, then it is immediately
known that an appropriate package file must for a SCA component needs be built in that
directory.
The SCA IDL compiler processes the IDL definitions and generates the appropriate code in the chosen
implementation language. In general, the following types of source code are generated.
50 SCA Framework User’s Guide
Source Files

• Interface definitions: For each interface, appropriate source files are generated that defines the
interface and the operations it contains. Additional files may also be generated for any user
constructed IDL types defined.
• Service definitions: Two types of code are generated for SCA service definitions. During the
build process, various source files are generated which are used to link the developer's
implementation code to the SCA Framework. This is done to reduce as much as possible the
amount of code that must be written by the developer. This support code also provides a level of
isolation between the service's implementation code and the SCA Framework. This allows
framework changes to be made with less impact on the existing service implementation code.
The developer can also run the IDL compiler to generate skeleton implementation code for their
service. This is usually done once at the beginning of the development cycle. The generated
skeletons can then be expanded with the code to implement the desired behavior for each
interface method. You can also run the IDL compiler at a later time if any interface changes are
made and you want to see how these affect the skeletons.
• Component definitions: During the build process, the IDL compiler may be run to generate
support code used to initialize the services it implements. This is not required for all support
languages. The developer never required to generate any code for the implementation of a SCA
component.
See the sections on the IDL mappings for the language you will be using for additional information on
the generated code.
Chapter 4: The IDL Language 51
Lexical Rules

Lexical Rules
The IDL language obeys the same lexical rules as C++ with a few exceptions.

Comments
Both C and C++ style comments are supported. C style comments start with the characters "/*" and
terminate with the characters "*/". These comments do not nest. C++ style comments start with the
characters "//" and terminate at the end of the line on which they occur. The comment characters "//", "/*",
and "*/" have no special meaning within a C++ style comment and are treated just like other characters.
Similarly, the comment characters "//" and "/*" have no special meaning within a C style comment.
Comments may contain alphabetic, digit, graphic, space, horizontal tab, vertical tab, form feed, and new
line characters.

Identifiers
An identifier is an arbitrarily long sequence of ASCII alphabetic, digits, and underscores characters. The
first character of an identifier must be an ASCII alphabetic character. All characters in the sequence are
significant.
When comparing two identifiers, upper and lower case letters are treated as the same letter. Identifiers
that differ only in case of the letters are treated as the same identifier and can cause compilation errors if
used improperly. This rule is used to allow mapping to implementation languages that are not case
sensitive.

Keywords
The identifiers listed in the following table are reserved by the OMG IDL specification for use as
keywords and may not be used otherwise unless they are properly escaped. Keywords must be written
exactly as shown in the table. Identifier names that collide with keywords are illegal. For example, since
boolean is a valid keyword, Boolean and BOOLEAN would be illegal identifiers.
52 SCA Framework User’s Guide
Lexical Rules

any double interface readonly unsigned


attribute enum long sequence union
boolean exception module short void
case FALSE object string wchar
char fixed octet struct wstring
const float oneway switch
context in out TRUE
default inout raises typedef

The SCA Framework does not support all of the capabilities of the OMG IDL language, but since it uses
a modified OMG IDL compiler, all of the OMG keywords are still restricted.

Escaped identifiers
As described in the previous section, the IDL language contains a set of reserved keywords that may not
be used as identifiers. As the language evolves, new keywords that are added may inadvertently collide
with identifiers used in existing IDL definitions and implementation code. Fixing these collisions could
require not only the modification to the IDL definitions, but also to the implementation coded that uses
them. To minimize this effect, the language allows you to lexically escape identifiers by prefixing an
underscore "_" to an identifier. This is purely a lexical convention that turns off keyword checking. The
resulting identifier follows all of the other rules for identifier processing except the underscore is not
considered part of its name. For example, the identifier _attribute is treated the same as if it were attribute
but it will not clash with the IDL reserved attribute keyword. The implementation code should still use
the identifier name without the prefix. This way only the IDL definitions and not the implementation
code need to be changed to fix any conflicts.

Literals
The IDL language supports the same literals as C++.

Integer literals
An integer literal consists of an optional "+" or "-" sign character followed by a sequence of digits that is
treated as a decimal (base ten) value. If the sequence of digits starts with the digit zero, then they are
treated as an octal (base eight) value. If the characters "0x" or "0X" precedes the sequence of digits, then
they are treated as a hexadecimal (base sixteen) value. The hexadecimal digits also include the letters "A"
through "F" which represent the decimal values of ten through fifteen, respectively. Hexadecimal digits
can be either upper or lower case. Here are some examples for integer literals.
Chapter 4: The IDL Language 53
Lexical Rules

const SCAInt32 i1 = -123; // decimal value -123


const SCAInt32 i2 = 0123; // octal value 123
const SCAInt32 i3 = 0X1A2B3C; // hexidimal value 1A2B3C

Floating-point Literals
A floating-point literal consists of an optional sign character, an integer part, a decimal point, a fraction
part, and optionally a signed integer exponent proceeded by the character "e" or "E". The integer and
fraction parts both consist of a sequence of decimal (base ten) digits. Either the integer part or the fraction
part, but not both, may be missing; either the decimal point or the exponent part, but not both, may be
missing. The following are some examples for floating point literals.

const SCAReal64 D1 = 1.23e-10; // integer, fraction and exponent


const SCAReal64 D2 = -1.23; // integer and fraction
const SCAReal64 D3 = .23; // fraction only
const SCAReal64 D4 = 1.; // integer only
const SCAReal64 D5 = 1e10; // integer and exponent
const SCAReal64 D6 = .23e-1 // fraction and exponent

Character literals
A character literal is one or more character enclosed in single quotes. A character is an 8-bit quantity
defined by the ISO Latin-1 character set which supports a superset of the ASCII character set. The
following escape sequences are supported.

Newline \n
Horizontal tab \t
Vertical tab \v
Backspace \b
Carriage return \r
Form feed \f
Alert \a
Backslash \\
Question mark \?
Single quote \’
Double quote \”
Octal byte value \ooo
Hexadecimal byte value \xhh

Each escape sequence specifies a single character. The escape "\ooo" consists of the backslash followed
by one, two, or three octal digits that are taken to specify the value of the desired character. The escape
"\xhh" consists of the backslash followed by the character "x" followed by one or two hexadecimal digits
54 SCA Framework User’s Guide
Lexical Rules

that are taken to specify the value of the desired character. A sequence of octal or hexadecimal digits is
terminated by the first character that is not an octal or a hexadecimal digit, respectively. The following
are some examples for character literals.

const SCAChar C1 = 'c'; // character c


const SCAChar C2 = '\123'; // character with value of octal 123
const SCAChar C3 = '\t'; // horizontal tab character
const SCAChar C4 = '\XAB'; // character with a value of hex AB

Wide character literals have an L prefix, for example.

const SCAWChar WC1 = L'c' // wide character c

Attempts to assign a wide character literal to a non-wide character constant or to assign a non-wide
character literal to a wide character constant will result in a compile time diagnostic.

String literals
A string literal is a sequence of characters surrounded by double quotes. Adjacent string literals are
concatenated. Characters in concatenated strings are kept distinct. For example, the following string
contains the two characters "\xA" and "B" after concatenation and not the single hexadecimal character
"xAB"
“\xA” “B”
The size of a string literal is the number of character literals enclosed by the quotes after concatenation.
Within a string, the double quote character " must be preceded (escaped) by a "\". A string literal may not
contain the null character "\0". The following are some examples of string literals.

const SCAString S1 = "this is a string"; // simple string


const SCAString S2 = "\"quoation\""; // embeded double quotes
const SCAString S3 = "one" "string"; // concatenated string
// = "onestring"
const SCAString S4 = "this is a " "string"; // concatenated string
// = "this is a string"
const SCAString S3 = "ap" "pear"; // concatenated string
// = "appear"

Wide string literals have an L prefix, for example:

const SCAWString WS1 = L"this is a string"; // simple wide string

A wide string literal may not contain a wide character with a value of zero.
Attempts to assign a wide string literal to a non-wide string constant or to assign a non-wide string literal
to a wide string constant will result in a compile time diagnostic.
Chapter 4: The IDL Language 55
Lexical Rules

Constant expressions
The IDL language offers the arithmetic and bitwise binary operators shown in the following table.

Operator Meaning
+ Arithmetic addition
- Arithmatic subtraction
* Arithmatic multiplication
/ Arithmatic division
% Arithmatic modulo
| Bitwise OR
& Bitwise AND
^ Bitwise exclusive OR
<< Bitwise left shift
>> Bitwise right shift
~ Bitwise complement

The arithmetic operators apply to both floating-point and integer expressions with the exception of "%"
which must have integer operands. Bitwise operators only apply to integer expressions. The semantics of
these operators are the same as their C++ counterparts with the following exceptions.
• The arithmetic operators do not support mixed-mode expressions. You may not mix integer and
floating-point constants in the same expression. There is no automatic promotion.
• The bitwise shifting operators always perform logical shifts.

See section Constant Declaration the detailed syntax and semantics of constant expressions.
56 SCA Framework User’s Guide
Preprocessing

Preprocessing
IDL source files are preprocessed to perform file inclusion and macro substitution before being compiled.
Preprocessing is controlled by directives introduced by lines having "#" as the first non white space
character. The preprocessing rules for IDL are the same as defined for the C and C++ languages.
When coding IDL files, make sure you include the appropriate preprocessor guard definitions just as you
would in a C or C++ header file. These are required to make sure the file will not get expanded more than
once in the same compilation, which can cause compilation errors due to duplicate definitions of the
symbols.

#ifndef TEST_KERNEL_BASEIMPL_IDL_INCLUDED
#define TEST_KERNEL_BASEIMPL_IDL_INCLUDED

#include "SCA/Service.idl"

module Test { module Kernel {

interface SCAIBaseImpl : SCAIService


{

};

}; };

#endif

The preprocessor used by the IDL compiler also supports the normal conditional compilation directives.
But you are strongly discouraged from using them because they may cause some confusion to the build
system.
Chapter 4: The IDL Language 57
IDL Specification for Interfaces and Types

IDL Specification for Interfaces and Types

Grammar notation
The description of OMG IDL grammar in this document uses a syntax notation that is similar to Extended
Backus-Naur Format (EBNF). The following table lists the symbols used in this format and their
meaning..

Symbol Meaning
::= Is defined to be
| Alternatively
<text> Non-terminal
“text” Literal
* The preceding syntactic unit can be repeated zero or more times
+ The preceding syntactic unit can be repeated one or more times
{} The enclosed syntactic units are grouped as a single syntactic unit
[] The enclosed syntactic unit is optional--may occur zero or one time

IDL specification
An OMG IDL specification consists of one or more type, constant, exception, interface, module, service
and component definitions. The grammar is:
<specification> ::= <definition>+
<definition> ::= <type_dcl> ";"
| <const_dcl> ";"
| <except_dcl> ";"
| <interface> ";"
| <module> ";"
| <service> ";"
| <component> ";"
See section Type Declaration for the specification of <type_dcl>.
See section Constant Declaration for the specification of <const_dcl>.
See section SCA Exception Declaration the specification of <except_decl>.
See section SCA Interface Declaration for the specification of <interface>.
See section Module Declaration for the specification of <module>.
See section SCA Services Declaration for the specification of <service>.
See section SCA Component Declaration for the specification of <component>.
58 SCA Framework User’s Guide
IDL Specification for Interfaces and Types

Basic IDL Types


The IDL language provides constructs for naming data types; that is, it provides C language like
declarations that associate an identifier with a type. IDL supports both basic and user constructed types.
The complete grammar for type declarations is:
<type_dcl> ::= "typedef" <type_declarator>
| <struct_type>
| <enum_type>
<type_declarator> ::= <type_spec> <declarators>
<type_spec> ::= <simple_type_spec>
| <constr_type_spec>
<simple_type_spec> ::= <base_type_spec>
| <template_type_spec>
| <scoped_name>
<base_type_spec> ::= <floating_pt_type>
| <integer_type>
| <char_type>
| <wide_char_type>
| <boolean_type>
| <any_type>
<template_type_spec> ::= <sequence_type>
| <string_type>
| <wide_string_type>
<constr_type_spec> ::= <struct_type>
| <enum_type>
<declarators> ::= <declarator> { "," <declarator> }?
<declarator> ::= <simple_declarator>
| <complex_declarator>
<simple_declarator> ::= <identifier>
<complex_declarator> ::= <array_declarator>
| <dynarray_declarator>
<floating_pt_type> ::= "SCAReal32"
| "SCAReal64"
<integer_type> ::= <signed_int>
| <unsigned_int>
<signed_int> ::= <signed_byte_int>
| <signed_short_int>
| <signed_long_int>
| <signed_llong_int>
<signed_byte_int> ::= "SCAInt8"
<signed_short_int> ::= "SCAInt16"
<signed_long_int> ::= "SCAInt32"
<signed_llong_int> ::= "SCAInt64"
<unsigned_int> ::= <unsigned_byte_int>
| <unsigned_short_int>
| <unsigned_long_int>
| <unsigned_llong_int>
<unsigned_byte_int> ::= "SCAUInt8"
<unsigned_short_int> ::= "SCAUInt16"
<unsigned_long_int> ::= "SCAUInt32"
<unsigned_llong_int> ::= "SCAUInt64"
<char_type> ::= "SCAChar"
<wide_char_type> ::= "SCAWChar"
Chapter 4: The IDL Language 59
IDL Specification for Interfaces and Types

<boolean_type> ::= "SCABool"


<any_type> ::= "SCAAny"
<struct_type> ::= "struct" <identifier> "{"
<member_list> "}"
<member_list> ::= <member>+
<member> ::= <type_spec> <declarators> ";"
<enum_type> ::= "enum" <identifier> "{"
<enumerator> { "," <enumerator> }??"}"
<enumerator> ::= <identifier>
<sequence_type> ::= "SCASequence"
"<" <simple_type_spec> ">"
<string_type> ::= "SCAString"
<wide_string_type> ::= "SCAWString"
<array_declarator> ::= <identifier> <array_size>
| <identifier> <array_size> <array_size>
<array_size> ::= "[" <positive_int_const> "]"
<dynarray_declarator> ::= <identifier> "[" "]"
| <identifier> "[" "]" "[" "]"
<scoped_name> ::= <identifier>
| "::" <identifier>
| <scoped_name> "::" <identifier>
<positive_int_const> ::= <const_exp>
The <scoped_name> in <simple_type_spec> must be a previously defined type introduced by an
interface declaration <interface_dcl>, see section SCA Interface Declaration, or a type declaration
<type_dcl>, see section Type Declaration.
An IDL <type_spec>, which can consist of a basic or constructed type, can be used in operation
declarations to assign data types to parameters and in the construction of user defined data types. The
next sections describe the basic and constructed types.

Basic types
The IDL language supports a number of different basic data types. When specifying the size of the basic
data types, the OMG IDL requirements only specify a lower bound. Since not all CPU architectures or
languages provide the ability to implement exact size definitions, the range requirements for the IDL
types have been left loose. When passing IDL data types between machines or languages, you are only
guaranteed of maintaining the documented data ranges. For example, you may have code running on a
CPU architecture or language that allows values larger than 16 bits in a SCAInt16 value, but when the
data is marshaled to another CPU type or a different language, which restricts the size to 16 bits, then the
data will be truncated.
All basic data types are subject to changes in representation if they are transmitted between different CPU
architectures. For example, a SCAInt32 value undergoes byte swapping when sent from a big-endian to
a little-endian machine.
The grammar for the basic type declarations is as follows:
<base_type_spec> ::= <floating_pt_type>
| <integer_type>
| <char_type>
| <wide_char_type>
60 SCA Framework User’s Guide
IDL Specification for Interfaces and Types

| <boolean_type>
| <any_type>
<floating_pt_type> ::= "SCAReal32"
| "SCAReal64"
<integer_type> ::= <signed_int>
| <unsigned_int>
<signed_int> ::= <signed_byte_int>
| <signed_short_int>
| <signed_long_int>
| <signed_llong_int>
<signed_byte_int> ::= "SCAInt8"
<signed_short_int> ::= "SCAInt16"
<signed_long_int> ::= "SCAInt32"
<signed_llong_int> ::= "SCAInt64"
<unsigned_int> ::= <unsigned_byte_int>
| <unsigned_short_int>
| <unsigned_long_int>
| <unsigned_llong_int>
<unsigned_byte_int> ::= "SCAUInt8"
<unsigned_short_int> ::= "SCAUInt16"
<unsigned_long_int> ::= "SCAUInt32"
<unsigned_llong_int> ::= "SCAUInt64"
<char_type> ::= "SCAChar"
<wide_char_type> ::= "SCAWChar"
<boolean_type> ::= "SCABool"
<any_type> ::= "SCAAny"

Integer
The following basic types represent integer values in the ranges indicated.

SCAInt8
SCAInt16
SCAInt32
SCAInt64
SCAUInt8
SCAUInt16
SCAUInt32
SCAUInt64

Floating-point
A number of different floating-point types are supported. See the IEEE Standard for Binary Floating-
Point Arithmetic, ANSI/IEEE Standard 754-1985, for complete details.
Chapter 4: The IDL Language 61
IDL Specification for Interfaces and Types

SCAReal32 IEEE single


SCAReal64 IEEE double

Note: The number of bits includes the sign, the mantissa and the exponent. The actual number of
bits in each field is defined in the IEEE standard.

Character
The SCAChar data type is defined as an 8-bit quantity. The ISO Latin-1 character set, which supports a
superset of the ASCII character set, is used. The bottom 128-character positions are identical to ASCII.
The upper 128 character positions are extensions to ASCII that allow most European languages to be
used with an 8-bit character set.

SCAChar

Wide character
The SCAWChar data type that encodes wide characters from any character set. As with character data,
an implementation is free to use any code set internally for encoding wide characters. The size of a
SCAWChar is implementation dependent.

SCAWChar

Booleans
The SCABool data type is used to denote a data item that can only take a value of TRUE or FALSE. The
IDL specification has no requirements on how these values are represented or about their size.

SCABool TRUE or FALSE

SCAAny
The SCAAny data type is a universal container type that can hold a value of any arbitrary IDL type with
the exception of an exception type. This includes all basic types, user constructed types and interface
types. This allows for interface operations to pass a value when the actual type is not known before run
time. A SCAAny contains a pair of values that includes a type code value, which describes what type of
data is contained, and the actual value of the data. The language mappings for each IDL data type provide
operations that allow you to insert and extract the type code and data value from a SCAAny.

SCAAny Any IDL type

The SCAAny type can be compared to a void* in C. Like a pointer to a void, a SCAAny value can denote
a value of any type. However, there is an important difference. The void* denotes a completely type less
value that can be interpreted only with advance knowledge of its contents. In contrast, values of type
62 SCA Framework User’s Guide
IDL Specification for Interfaces and Types

SCAAny maintain type safety. For example, if the caller places a string value in a SCAAny, the receiver
cannot extract the string as a value of the wrong type. Attempts to treat the contents of the SCAAny as
the wrong type will cause a run-time error. This is possible because the SCAAny contains a type code
value, defining the type of data stored, which can be used by the language mappings to enforce type
safety.
Type codes not only serve to enforce type safety but also provide an introspection capability. The receiver
of the SCAAny value can access the type code to find out what type of value it contains. This capability
is useful because it makes SCAAny values stand-alone data items. The receiver of the SCAAny can
always interpret the value inside it without requiring additional contextual information.

User-defined Types
In addition to the basic data types, The IDL language allows you to construct more complex types like
enumerations, structures and arrays.

Enumeration
Enumerated types consist of ordered lists of identifiers. The grammar for an enum is:
<enum_type> ::= "enum" <identifier> "{"
<enumerator> { "," <enumerator> }* "}"
<enumerator> ::= <identifier>
The <identifier> in the <enum_type> specification introduces the name of the new legal data type.
The IDL enumeration is similar to the C++ version except IDL does not allow you to control the ordinal
values of the enumerator values.

enum Grade {A, B, C, D, F,};

A maximum of 232 identifiers may be specified in an enumeration. Therefore, the enumerated names are
mapped to a data type capable of representing a 32-bit value.
Enum definitions do not introduce a new namespace. Enumeration value names are introduced into the
enclosing scope and then are treated like any other declaration in that scope. See section on Scoping
Rules for further details.
Enumerated types may also be defined using a typedef declaration, which will introduce an additional
alias for the type.

typedef enum Grade {A, B, C, D, F,} MyGrade;

In this example, Grade and MyGrade are now valid IDL type names that can be used to reference the
newly defined enum.
Chapter 4: The IDL Language 63
IDL Specification for Interfaces and Types

Structure
The IDL language supports structures containing one or more named members of arbitrary type,
including user constructed complex types. The grammar for the struct type is
<struct_type> ::= "struct" <identifier> "{"
<member_list> "}"
<member_list> ::= <member>+
<member> ::= <type_spec> <declarators> ";"
<declarators> ::= <declarator> { "," <declarator> }?
<declarator> ::= <simple_declarator>
| <complex_declarator>
<simple_declarator> ::= <identifier>
<complex_declarator> ::= <array_declarator>
| <dynarray_declarator>
The <identifier> in the <struct_type> specification introduces the name of the new legal data type.

The following is an example of a simple structure definition..

struct TimeOfDay
{
SCAInt8 hour;
SCAInt8 minute;
SCAInt8 second;
};

These definitions can be more complicated by using other constructed types as members..

typedef SCAInt16 MeetingDate[3];


struct MeetingTime
{
SCAInt8 Hour,Minute;
MeetingDate Date;
};
enum MeetingType { REQUIRED, OPTIONAL };
typedef SCASequence<SCAString> MeetingComments;
struct Meeting
{
SCAString Subject;
MeetingTime StartTime,EndTime;
MeetingType Type;
MeetingComments Comments;
};

Structure definitions form a new namespace, so the names of the structure members need to be unique
only within their enclosing structure. The following demonstrates this..

struct FirstStructure { SCAInt32 first; SCAInt32 second; };


struct SecondStructure { SCAInt32 first; SCAInt32 second; };
64 SCA Framework User’s Guide
IDL Specification for Interfaces and Types

While this type of definition is legal, it should be considered a bad practice to reuse the same identifiers
for two different purposes.
Structure types may also be defined using a typedef declaration, which will introduce an additional alias
for the type..

Typedef struct TimeOfDay


{
SCAInt8 hour;
SCAInt8 minute;
SCAInt8 second;
} CurrentTime;

In this example, TimeOfDay and CurrentTime are now valid IDL type names that can be used to
reference the newly defined struct.
The IDL grammar allows for the generation of recursive structures for members that have a sequence
type. For example, the following is a valid IDL definition:.

struct Node
{
SCAInt32 value;
sequence<Node> children;
};

This example defines a structure for a Node, which contains a SCAInt32 value and list of children Nodes.

Fixed-size array
The IDL language supports multidimensional arrays with fixed-sized dimensions. A fixed-size array
definition must include explicit sizes for each dimension. Only arrays of rank 1 or 2 are allowed. Arrays
of arbitrary element types are supported in IDL.
The grammar for arrays is:
<array_declarator> ::= <identifier> <array_size>
| <identifier> <array_size> <array_size>
<array_size> ::= "[" <positive_int_const> "]"
<positive_int_const> ::= <const_exp>
The array size, <const_exp>, for each dimension is fixed at compile time and must be a positive constant
integer expression.
When an array is passed as a parameter in an operation invocation, all elements of the array are
transmitted. The implementation of array indices is language mapping specific. Some language
mappings may define the first element in the array as having an index value of zero and others may use
Chapter 4: The IDL Language 65
IDL Specification for Interfaces and Types

a value of one. As a result, passing of array indices as parameters may yield incorrect results unless they
are correctly handled..

typedef SCAInt32 ArrayOfLongs[100];


typedef TimeOfDay ArrayOfTimes[100];
typedef SCAInt32 MultiDimensionalArray[10][100];

The use a typedef construct to declare an array is required. The following array definition is invalid..

SCAInt32 ArrayOfLongs[100]; // Error: typedef missing

All array dimensions must be specified in the IDL. Open-ended arrays are not supported because IDL
does not support pointers. The complete size for each data type must be known at compilation time.
Because of this rule, the following definition is invalid..

typedef SCAString StringTable[][10]; // Error: missing dimension

Dynamic array
The IDL language also supports multidimensional arrays with dynamic dimensions which are not set
until run time. Only arrays of rank 1 or 2 are allowed. Dynamic arrays differ from fixed-size arrays in
that the actual array dimensions are not determined until run time. Arrays of arbitrary element types are
supported in IDL.
The grammar for arrays is:
<dynarray_declarator> ::= <identifier> "[" "]"
| <identifier> "[" "]" "[" "]"
The array size for each dimension must be left blank and is specified when the array is allocated at run
time.
When a dynamic array is passed as a parameter in an operation invocation, all elements of the array are
transmitted. The implementation of dynamic array indices is language mapping specific. Some language
mappings may define the first element in the array as having an index value of zero and others may use
a value of one. As a result, passing of array indices as parameters may yield incorrect results unless they
are correctly handled.

typedef SCAInt32 ArrayOfLongs[];


typedef TimeOfDay ArrayOfTimes[];
typedef SCAInt32 MultiDimensionalArray[][];

The use a typedef construct to declare an array as is required. The following array definition is invalid.
66 SCA Framework User’s Guide
IDL Specification for Interfaces and Types

SCAInt32 ArrayOfLongs[]; // Error: typedef missing

For convenience, the SCA Framework provides predefined dynamic arrays types for each basic SCA
type. These are described in the section Special SCA Framework Provided Types.

Template Types
SCASequence
The IDL language provides the sequence type that is a one-dimensional array with a length that is
determined at run time.
The grammar for a sequence is:
<sequence_type> ::= "SCASequence"
"<" <simple_type_spec> ">"
<simple_type_spec> ::= <base_type_spec>
| <template_type_spec>
| <scoped_name>
Variable length arrays of arbitrary element types are supported in IDL with the sequences type. You must
use a typedef construct to declare a sequence.

typedef SCASequence<SCAInt32> SCAInt32Sequence;


typedef SCASequence<Grade> Grades;
typedef SCASequence<TimeOfDay> Times;

The SCASequence only supports one-dimensional arrays, but defining a sequence of sequences can
approximate a multi-dimensional array.

typedef SCASequence<SCAInt32> SCAInt32Sequence;


typedef SCASequence<SCAInt32Sequence> SequenceOfSequence;

typedef SCASequence< SCASequence<SCAInt32> > SequenceOfSequence;

Notice that in the nested sequence declaration a white space must be used to separate the two tokens of
">" at the end of the declaration. This is required to keep the two characters from being parsed as a single
token of ">>".
The SCA Framework does not support bounded sequences as defined by the OMG IDL specification.
For convenience, the SCA Framework provides predefined sequence types for each basic SCA type.
These are described in the section Special SCA Framework Provided Types.

SCAString
The IDL language provides a string type of SCAString that is a sequence of character values. ASCII null
values of '\0' are not allowed inside IDL strings. Strings are singled out as a separate data type because
Chapter 4: The IDL Language 67
IDL Specification for Interfaces and Types

many languages have special built-in or standard library functions for string manipulation. A separate
string type may permit substantial optimization in the handling of strings compared to what can be done
with sequences of characters.
The grammar for a string declaration is:
<string_type> ::= "SCAString"
The SCA Framework does not support bounded string types as defined by the OMG IDL specification.

SCAWString
The IDL language provides a wide string type of SCAWString that is a sequence of wide character values.
Wide character null values of L'\0' are not allowed inside IDL wide strings. Wide strings are singled out
as a separate data type because many languages have special built-in or standard library functions for
wide string manipulation. A wide separate string type may permit substantial optimization in the
handling of strings compared to what can be done with sequences of characters.
The grammar for a string declaration is:
<wide_string_type> ::= "SCAWString"
The SCA Framework does not support bounded string types as defined by the OMG IDL specification.

Aliases to other types


The typedef construct can be used to create a new type name or alias for any other valid IDL type. The
grammar for a typedef declaration is as follows:
<type_dcl>::= "typedef" <type_declarator>
<type_declarator>::= <type_spec> <declarators>
<declarators>::= <declarator> { "," <declarator> }?
<declarator>::= <simple_declarator>
| <complex_declarator>
<simple_declarator> ::= <identifier>
<complex_declarator> ::= <array_declarator>
Some simple examples of typedef declarations follow:

typedef SCAInt16 YearType;


typedef SCAInt16 MonthType;

These types of specifications can make the IDL file more readable and self-documenting. This example
would indicate to the reader that the values represent a year or month, rather than the more generic
SCAInt16 type.
For more complex data types, the typedef construct can be used to define the data type and create an alias
for it in the same statement.:
68 SCA Framework User’s Guide
IDL Specification for Interfaces and Types

typedef sequence <SCAInt32> SCAInt32Sequence;

typedef struct Time


{
SCAInt8 hour;
SCAInt8 minute;
SCAInt8 second;
} CurrentType;

typedef enum Color { RED, BLUE, GREEN } CurrentColor;

typedef SCAInt32 ArrayOfLongs[100];

Sequences versus arrays


Sequences and the two arrays types are similar because they all provide a vector of elements of the same
type. The three types of vectors are provided to allow more efficient mappings in the various languages.
In some languages, the mappings for some of the vector types may be the same and in others they may
all be different. The language dependent mappings have been chosen to optimize performance and to
provide various memory management models where appropriate. You should consult the IDL mapping
section for your language for complete details.
Here are some general guidelines to help you decide whether a sequence or an array is the more
appropriate type.
• If the length of the list is not known at compilation time, either a dynamic array or a sequence
must be used.
• If you have a fixed length list and all of the elements exist all of the time, use either the fixed-
size array or the dynamic array.
• If you have a variable length list, even if the upper bound on the size is known at compile time, it
may be more efficient to use a sequence rather than an array.

Consider the following IDL example for the definition of a matrix.:

typedef SCAReal32 Matrix[100][100];

This definition defines a square matrix of dimension 100. It also will cause the allocation of 10,000
storage locations, which could be very inefficient if the matrix is sparse. If this matrix is passed out-of-
proc, it is even more inefficient because all 10,000 values will be transmitted, even if only a few are used.
In contrast, consider the following IDL definition which could be used to define a sparse matrix storage
scheme.:
Chapter 4: The IDL Language 69
IDL Specification for Interfaces and Types

struct MatrixElement
{
SCAUInt32 row;
SCAUInt32 col;
SCAReal32 value;
};
typedef sequence<MatrixElement> Matrix;

This definition is more efficient in both storage and transmission time because only the meaningful
matrix elements will be stored and processed.
70 SCA Framework User’s Guide
Constants

Constants
The grammar for a constant declaration in the IDL language is:

<const_dcl> ::= "const" <const_type>


<identifier> "=" <const_exp>
<const_type> ::= <integer_type>
| <char_type>
| <wide_char_type>
| <boolean_type>
| <floating_pt_type>
| <string_type>
| <wide_string_type>
| <scoped_name>
<const_exp> ::= <or_expr>
<or_expr> ::= <xor_expr>
| <or_expr> "|" <xor_expr>
<xor_expr> ::= <and_expr>
| <xor_expr> "^" <and_expr>
<and_expr> ::= <shift_expr>
| <and_expr> "&" <shift_expr>
<shift_expr> ::= <add_expr>
| <shift_expr> ">>" <add_expr>
| <shift_expr> "<<" <add_expr>
<add_expr> ::= <mult_expr>
| <add_expr> "+" <mult_expr>
| <add_expr> "-" <mult_expr>
<mult_expr> ::= <unary_expr>
| <mult_expr> "*" <unary_expr>
| <mult_expr> "/" <unary_expr>
| <mult_expr> "%" <unary_expr>
<unary_expr> ::= <unary_operator> <primary_expr>
| <primary_expr>
<unary_operator> ::= "-"
| "+"
| "~"
<primary_expr> ::= <scoped_name>
| <literal>
| "(" <const_exp> ")"
<literal> ::= <integer_literal>
| <string_literal>
| <character_literal>
| <floating_pt_literal>
| <boolean_literal>
<boolean_literal> ::= "TRUE"
| "FALSE"
<positive_int_const> ::= <const_exp>
<scoped_name> ::= <identifier>
| "::" <identifier>
| <scoped_name> "::" <identifier>
Chapter 4: The IDL Language 71
Constants

The <scoped_name> in the <const_type> definition must be a previously defined name of an


<integer_type>, <char_type>, <wide_char_type>, <string_type>, <wide_string_type>, <enum_type>
<boolean_type> or <floating_pt_type> constant. The value of a <positive_int_const> expression must
evaluate to a positive integer constant.
One side effect of a constant type definition is the <identifier> in the <const_dcl> specification
introduces the name of the new legal data type with the same type as <const_type>. This can be confusing
if you use this type for any other purposes in the IDL definitions. Consider the following example.:

const SCAInt32 ConstType = 123;

interface Inf
{
SCAVoid meth1 ( in ConstType inval );
SCAVoid meth2 ( in SCAInt32 inval );
};

In this example the signature for both methods in the interface definition will be identical. This is because
the first method is just defining a parameter of type ConstType which is the same as SCAInt32. It is not
defining parameter with a value of "123". To avoid this confusion you should not use the type names
introduced by constant definitions in any other places in the IDL. They should only used by the
implementation code where normal constant can appear. For example it is perfectly fine to use the
constant value as a parameter value in a call to an interface method, but it is not appropriate to use in the
declaration of a method.
Only integer values can be assigned to integer (SCAInt8, SCAInt16, SCAInt32 and SCAInt64) constants.
Only positive integer values can be assigned to unsigned integer (SCAUInt8, SCAUInt16, SCAUInt32
and SCAUInt64) constants. If the value of the right hand side of an integer constant declaration is too
large to fit in the actual type of the constant, or the value is inappropriate for the actual type of the left
hand side, it is flagged as a compile time error.
72 SCA Framework User’s Guide
Constants

const SCAInt16 s = 655592; // Error: value to large


const SCAUInt16 o = -54; // Error: negative value in unsigned type

Only floating-point values can be assigned to floating point (SCAReal32 and SCAReal64) constants. If
the value of the right hand side is too large to fit in the actual type of the constant to which it is being
assigned it is flagged as a compile time error.
A binary operator can combine two integers or two floats, but not mixtures of these. Binary operators are
applicable only to integer and float-point types.
If the type of an integer constant is a SCAInt8, SCAUInt8, SCAInt16, SCAUInt16, SCAInt32 or
SCAUInt32, then each sub expression of the associated constant expression is treated as a signed
SCAInt32 or unsigned SCAUInt32 value accordingly. It is an error if any sub expression values exceed
the precision of the SCAInt32 or SCAUInt32 type, or if a final expression value exceeds the precision of
the target type. A similar rule applies to SCAInt64 and SCAUInt64 constants.
If the type of a floating-point constant is SCAReal64, then each sub expression of the associated constant
expression is treated as a SCAReal64. It is an error if any sub expression value exceeds the precision of
SCAReal64.
Unary (+ -) and binary (* / + -) operators are applicable in floating-point expressions. Unary (+ - ~) and
binary (* / % + - << >> & | ^) operators are only applicable in integer expressions.
The "~" unary operator indicates that the bit-complement of the expression to which it is applied should
be generated. For the purposes of such expressions, the values are 2's complement numbers. As such, the
complement can be generated as follows:

Integer Expression Type Generated 2’s Complement Numbers


SCAInt32 SCAInt32 -(value+1)
SCAUInt32 SCAUInt32 (2**32-1) - value
SCAInt64 SCAInt64 -(value+1)
SCAUInt64 SCAUInt64 (2**64-1) - value

The "%" binary operator yields the remainder from the division of the first expression by the second. If
the second operand is zero, the result is undefined. If both operands are nonnegative, then the remainder
is nonnegative; if not, the sign of the remainder is implementation dependent.
The "<<" binary operator indicates that the value of the left operand should be shifted left the number of
bits specified by the right operand with zero fill for the vacated bits. The right operand must be in the
range 0 <= right operand < 64.
The ">>" binary operator indicates that the value of the left operand should be shifted right the number
of bits specified by the right operand with zero fill for the vacated bits. The right operand must be in the
range 0 <= right operand < 64.
Chapter 4: The IDL Language 73
Constants

The "&" binary operator indicates that the logical, bitwise AND of the left and right operands should be
generated.
The "|" binary operator indicates that the logical, bitwise OR of the left and right operands should be
generated.
The "^" binary operator indicates that the logical, bitwise EXCLUSIVE-OR of the left and right operands
should be generated.
An enum constant can only be defined using a correctly scoped name for the enumerator. The scoped
name is resolved using the normal scope resolution rules described in section Scoping Rules. For
example:

enum Color { red, green, blue };


const Color FAVORITE_COLOR = red;

module M {
enum Size { small, medium, large };
};
const M::Size MYSIZE = M::medium;

The constant name for the right hand size of an enumerated constant definition must denote one of the
enumerators defined for the enumerated type of the constant. For example::

const Color col = red; // OK


const Color another = M::medium; // Error: medium is not a Color

Constant definitions in IDL are not permitted for user constructed complex types of structures or arrays.
The following are some examples of constant definitions.:

const SCAString Version = "Version 10.3";


const SCAWString wstr = L"Test wide string";
const SCAReal32 Pi = 3.14159;
const SCAChar Null = '\0';
const SCAWChar wchr = 'A';
const SCABool myTrue = TRUE;
enum Color { RED, GREEN, BLUE };
const Color Favorite_Color = RED;
const SCAReal32 Test1 = (1.0+4.0-2.0)*20.0/2.0;
const SCAInt32 Test2 = (1+4-2)*20/2;
const SCAUInt32 Test3 = ~2;
const SCAInt32 Test4 = 100 % 12;
const SCAInt32 Test5 = 2 << 4;
const SCAInt32 Test6 = 32 >> 4;
const SCAInt32 Test7 = 1 | (1<<4) | (1<<8);
const SCAInt32 Test8 = 0x1234 & 0xF;
const SCAInt32 Test9 = 0xF ^ 0x5;
74 SCA Framework User’s Guide
Modules, Names and Scoping

Modules, Names and Scoping


The IDL language uses the module construct to create a namespace. Namespaces combine related
definitions into a logical group and prevent the pollution of the global namespace. A module definition
satisfies the following grammar:
<module> ::= "module" <identifier> "{"
<definition>+ "}"
A <definition> is any valid IDL specification as shown in section SCA IDL Specification. Nested
module definitions are supported as the following example illustrates.

module SCA
{
module FileReader
{
// Some definitions here
};
};

Modules are similar to C++ namespaces in that they can be reopened to add additional definitions.

module A
{
// Some definitions here
};

module B
{
// Some definitions here
};

module A
{
// Reopen module A and add some definitions to it
};

Name lookup rules


IDL identifiers are case insensitive; that is, two identifiers that differ only in the case of their characters
are considered redefinitions of one another. However, all references to a definition must use the same case
as the defining occurrence. This allows natural mappings to case-sensitive languages. For example:.
Chapter 4: The IDL Language 75
Modules, Names and Scoping

module M
{
typedef SCAInt32 Long; // Error: Long clashes
with keyword long
typedef SCABool MyBool;
interface I {
typedef SCAInt32 MyLong;
SCAResult meth1(
in myLong val; // Error: inconsistent
capitalization
in MyBool mybool; // Error: MyBool
clashes with mybool
);
};
};

Qualified names
A qualified name, of the form scope::identifier, is resolved by first resolving the qualifier scope in scope
S, where S is the current scope, and then locating the definition of identifier within S::scope. If the
qualified name is not found in S, then each of S's enclosing scopes will be checked. The identifier must
exist in the namespace scope; it is not searched for directly in the enclosing scopes of S. Consider the
following example.

module A { module B {
typedef C::X mytype;
}; };

The following fully qualified names will be tried to find X


::A::B::C::X
::A::C::X
::C::X

The following fully qualified names will NOT be tried to find X


::A::B::X
::A::X
::X

When a qualified name begins with "::", the resolution process will only look in the file or global scope
and not look in any intermediate enclosing scopes. For example:
76 SCA Framework User’s Guide
Modules, Names and Scoping

module A { module B {
typedef ::C::X mytype;
}; };

The only fully qualified name that will be tried to find X


::C::X

Inheritance causes all of the identifiers defined in the base interfaces, both direct and indirect, to be
visible in the derived interfaces. Such identifiers are considered to be semantically the same as the
original definitions.

interface CBase
{
typedef long X;
};
interface C : CBase
}
};

Either of the following references are identical


typedef CBase::X mytype1;
typedef C::X mytype2;

Scoping rules
The scoping rules used in IDL are the same as in C++. The IDL compiler searches for the definition of
an identifier from the innermost scope outward toward the outermost scope.
The entire contents of an IDL file, together with the contents of any files referenced by #include
statements, forms a naming scope. Definitions that do not appear inside a scope are part of the global
scope. There is only a single global scope, irrespective of the number of source files that form a
specification. The following IDL definitions form new naming scopes:
• module
• struct
• interface
• interface operation

The appearance of a declaration for any of these in any scope opens a nested scope associated with that
declaration. An identifier can only be defined once in a scope. However, identifiers can be redefined in
nested scopes. An identifier declaring a module is defined by its first occurrence in a scope. Subsequent
occurrences of a module declaration with the same identifier within the same scope reopens the module
and hence its scope, allowing additional definitions to be added to it.
Chapter 4: The IDL Language 77
Modules, Names and Scoping

The name of an interface, struct, or a module may not be redefined within the immediate scope of the
interface, struct, or the module. For example:

module Test
{
typedef SCAInt16 Test; // Error: Test is the name of the module
interface Inf
{
SCAResult inf ( ); // Error: inf clashes with interface Inf
};
};

Enum definitions do not introduce a new scope. Enumeration value names are introduced into the
enclosing scope and then are treated like any other declaration in that scope. For example:

module Test
{
enum VAL { E1, E2, E3 };
enum BAD { E3, E4, E5 }; // Error: Test::E3 is already defined
};
78 SCA Framework User’s Guide
Interfaces and Operations

Interfaces and Operations


An interface definition satisfies the following grammar:
<interface> ::= <interface_dcl>
| <forward_dcl>
<interface_dcl> ::= <interface_hdr> "{"
<interface_body> "}"
<forward_dcl> ::= "interface" <identifier>
<interface_hdr> ::= "interface" <identifier>
[ <inheritance_spec> ]
<interface_body> ::= <export>*
<export> ::= <type_dcl> ";"
| <const_dcl> ";"
| <op_dcl> ";"
<inheritance_spec> ::= ":" <inferface_name> { ","
<interface_name> }*
<interface_name> ::= <scoped_name>
<scoped_name> ::= <identifier>
| "::" <identifier>
| <scoped_name> "::" <identifier>
<op_dcl> ::= <op_type_spec> <identifier>
<parameter_dcls> [ <raises_expr> ]
<op_type_spec> ::= "SCAResult"
<parameter_dcls> ::= "(" <param_dcl>
{ "," <param_dcl> }* ")"
| "(" ")"
<param_dcl> ::= <param_attribute> <param_type_spec>
<simple_declarator>
<param_attribute> ::= "in"
| "out"
| "inout"
<raises_expr> ::= "raises" "(" <scoped_name>
{"," <scoped_name> }* ")"
<param_type_spec> ::= <base_type_spec>
| <string_type>
| <wide_string_type>
| <scoped_name>

Interface header
The interface header consists of these elements:
• The keyword interface.
• The interface name consists of an <identifier> that names the interface. The SCA Framework
uses the convention that all interface names should begin with the prefix SCAI but this is not
enforced by the IDL compiler.
• An optional inheritance specification, which consists of, a colon followed by a comma-separated
list of interfaces that are inherited from.
Chapter 4: The IDL Language 79
Interfaces and Operations

• Definition of the interface body enclosed by the characters "{" and "}".

interface A {};
interface B : A {};
interface C : A, B {};

The <identifier> that names an interface introduces a new legal type name. Such a type name may be
used anywhere an <identifier> is legal in the grammar.

Interface inheritance specification


The grammar for interface inheritance is as follows:
<inheritance_spec> ::= ":" <inferface_name> { ","
<interface_name> }*
<interface_name> ::= <scoped_name>
Each <scoped_name> in an <inheritance_spec> must denote a previously defined interface. See section
Interface Inheritance for the description of how interface inheritance is use in the SCA Framework.

Interface body
The interface body can contain the following kinds of declarations:
• Type declarations, which specify the type definitions that the interface exports as described in
section Type Declaration.
• Constant declarations, which specify the constants that the interface exports as described in
section Constant Declaration.
• Operation declarations, which specify the operations that the interface exports and the format of
each, including operation name, the type of data returned and the types of all parameters for the
operation. Operation declarations are described in section Operation Declaration.
Although it is legal to include type and constant definitions inside an interface body, it is a discouraged
practice. This is because the required language mapping for these types is not always obvious and can
lead to undesirable implementation code.
Empty interfaces, that contain no declarations, are permitted.

Operation declaration
Operation declarations in the IDL language are similar to C++ method declarations. The grammar is:
<op_dcl> ::= <op_type_spec> <identifier>
<parameter_dcls> [ <raises_expr> ]
<op_type_spec> ::= "SCAResult"
<parameter_dcls> ::= "(" <param_dcl>
{ "," <param_dcl> }* ")"
80 SCA Framework User’s Guide
Interfaces and Operations

| "(" ")"
<param_dcl> ::= <param_attribute> <param_type_spec>
<simple_declarator>
<param_attribute> ::= "in"
| "out"
| "inout"
<raises_expr> ::= "raises" "(" <scoped_name>
{"," <scoped_name> }* ")"
<param_type_spec> ::= <base_type_spec>
| <string_type>
| <wide_string_type>
| <scoped_name>
An operation declaration consists of:
• The type of the operation's return result.
• An identifier that names the operation in the scope of the interface in which it is defined.
• A parenthesized, comma separated parameter list that specifies zero or more parameter
declarations for the operation.
• An optional raises clause that identifies which exceptions the operation may throw.

Each parameter declaration consists of three parts.


• A directional attribute for the parameter.
• The type of the parameter that may be any type that is defined in IDL.
• An identifier that names the parameter. Since the parameter list for each operation opens a new
naming scope, the names only need to be unique in the same list.
Each parameter declaration must have a directional attribute that informs the framework the direction in
which the parameter is to be passed. This is different than a parameter definition in a C++ method. The
directional attributes are as follows:.

in The parameter is passed from caller to callee


out The parameter is passed from callee to caller
inout The parameter is passed in both directions

It is expected that an implementation will not attempt to modify an in parameter. The ability to even
attempt to do so is language-mapping specific. The effect of such an action is undefined.
The following are valid operation definitions.
Chapter 4: The IDL Language 81
Interfaces and Operations

interface A
{
SCAResult meth1 ( );
SCAResult meth2 ( out SCAInt32 val );
SCAResult meth3 ( in SCABool ival, out SCAInt32 oval,
inout SCAString ioval );
};

An IDL operation may have an optional raises clause. The raises clause defines what type of exceptions
the method may throw. The syntax is defined as follows:
<raises_expr> ::= "raises" "(" <scoped_name>
{"," <scoped_name> }* ")"
Where <scoped_name> is any valid IDL exception specification as show in section SCA Exception
Declaration.
You may also specify one of the built-in exceptions, SCASystemException, SCAUserException or
SCAException, in the raises clause. The following shows an example of the raises clause.

interface A
{
SCAResult meth1 ( )raises (Exception1, Exception2);
SCAResult meth2 ( )raises (SCAException);
};

Forward declarations
It is valid for interface-defined types to be passed as parameters to operations. Occasionally, interfaces
are mutually dependent to each other; each one is expecting a parameter of the other's type. This can
present a problem because the IDL compiler is a one-pass compiler and all types must be defined before
being used. In this case a forward declaration can be used to resolve the problem.
A forward declaration declares the name of an interface without defining it. This interface can then be
used as a parameter in another interface definition. Multiple forward declarations of the same interface
name are legal. It is illegal to inherit from a forward-declared interface that has not yet been defined.
82 SCA Framework User’s Guide
Interfaces and Operations

module Example
{
interface A; // Forward declaration of A
interface B // Full declaration of B
{
SCAResult meth ( in A inf ); // Use forward declared A
};
interface A // Full declaration of A
{
SCAResult meth ( in B inf ); // Use fully declared B
};
};

Interface inheritance
An interface can be derived from another interface, which is then called a base interface of the derived
interface. A derived interface, like all interfaces, may declare new constants, types, and operations. In
addition, unless redefined in the derived interface, the elements of a base interface can be referred to as
if they were elements of the derived interface. The name resolution operator "::" may be used to refer to
a base element explicitly. This permits reference to a name that has been redefined in the derived
interface. A derived interface may redefine any of the types or constants that have been inherited. A
derived interface may not redefine operations that have been inherited.
An interface is called a direct base if it is mentioned on the interface definition and an indirect base if it
is not a direct base but is a base interface of one of the interfaces that is inherited from. An interface may
be derived from any number of base interfaces, which is often referred to as multiple inheritance. The
order of derivation is not significant except that is should never be changed once it has been set. An
interface may not be specified as a direct base interface of a derived interface more than once, but it may
be an indirect base interface more than once. Consider the following valid examples:.

interface A { ... };
interface B: A { ... }; // Direct base of A
interface C: A { ... }; // Direct base of A
interface D: B, C { ... }; // Multiple indirect bases of A
interface E: A, B { ... }; // A is both a direct and indirect base

References to base interface elements must be unambiguous. A reference to a base interface element is
ambiguous if the name is declared as a constant or type in more than one base interface. Ambiguities can
be resolved by qualifying a name with its interface name. Consider the following examples:
Chapter 4: The IDL Language 83
Interfaces and Operations

interface A
{
typedef SCAInt32 L1;
SCAResult meth1(in L1 l_1);
};
interface B
{
typedef SCAInt16 L1;
SCAResult meth2(in SCAInt32 l);
};
interface C: B, A
{
typedef L1 L2; // Error: L1 ambiguous
typedef A::L1 L3; // OK: A::L1 is not ambiguous
SCAResult meth1
(
in L3 val1, // OK: L3 is not ambiguous
in B::L1 val2 // OK: B::L1 is not ambiguous
);
};

Overloading of operation definitions is not allowed. This means it is illegal to inherit from two interfaces
containing the same operation name, or to redefine an operation in the derived interface. This is required
because operation names are used at run-time with dynamic interfaces and in scripting and must be
unique. Also, not all implementation languages support operation overloading.

interface A
{
SCAResult meth1();
};
interface B: A
{
SCAResult meth1(in long times); // Error: redefinition of meth1
};

SCAIService interface
The SCA Framework requires that all interfaces inherit, either directly or indirectly form the
SCAIService interface. The SCAIService interface defines the methods used to support interface
navigation, reference counting and runtime introspection. You need to include the file that defines this
interface, "SCA/Service.idl", in your IDL file unless it is already included in another include file that you
are using. The following is the definition of the SCAIService interface.
84 SCA Framework User’s Guide
Interfaces and Operations

Module SCA {
interface SCAIService
{
SCAVoid addReference();
SCAVoid releaseReference( out SCAVoidPtr pPublisher );
SCAResult getInterface( in SCAString sName,
out SCAVoidPtr pIface );
SCAString getImplName();
SCAInt32 getInstanceID();
};
};

The following example shows two valid SCA interface definitions. The first interface directly inherits
from the SCAIService interface and the second one indirectly inherits from it.

#include "SCA/Service.idl"

module Test {

interface SCAITest1 : SCA::SCAIService


{
SCAResult meth1();
};

interface SCAITest2: SCAITest1


{
SCAResult meth2();

};

Since every interface must inherit from the SCAIService interface, the IDL compiler will generate all the
code that is normally required to implement its methods.
Chapter 4: The IDL Language 85
Exceptions

Exceptions
The IDL language supports exception declarations containing zero or more named members of arbitrary
type, including user constructed complex types. The grammar for the exception is similar to the struct
type with several differences. Exceptions are allowed to inherit from other exceptions but inheritance is
not supported on structures. Also it is possible to define an exception type with zero members. The
following is the grammar for the exception type.
<except_dcl> ::= "exception" <identifier>
[ <except_inherit> ] "{" <member>* "}"
<except_inherit> ::= ":" <scoped_name>
<member> ::= <type_spec> <declarators> ";"
<declarators> ::= <declarator> { "," <declarator> }?
<declarator> ::= <simple_declarator>
| <complex_declarator>
<simple_declarator> ::= <identifier>
<complex_declarator> ::= <array_declarator>
| <dynarray_declarator>
[ <except_inherit> ] "{" <member>* "}"
The <identifier> in the <except_dcl> specification introduces the name of the new legal data type. These
identifiers may appear only in an exception inheritance <except_inherit> clause or a raises clause in an
interface operation definition described in section Operation Declaration. Exception identifiers are not
allowed to be used for any other purpose.

The following is an example of SCA IDL exception definition..

exception MyException : SCAUserException {


SCAInt32 id;
SCAString value;
};

exception MyException2 : MyException {


SCAString extradata;
};
86 SCA Framework User’s Guide
SDL Specifications

SDL Specifications
The SCA Framework SDK delivery includes many IDL files which define types supported by the
framework. But, most of these types are no different than the types you define in the components you
deliver. There are a few exceptions to this. The framework also provides a number of special types,
described in this section, that are treated differently for the following reasons.
• Some types are provided for convenience because they tend to be useful to all developers. In this
case it is better to use the framework provided types rather than defining your own for the
purpose of consistency.
• Some of these types are provided because they utilize special language specific mappings to
provide the required functionality. In many of these cases the framework provided special
implementation classes for these types in each supported language.
The following special types can be thought of as new basic types provided by the SCA Framework. The
IDL compiler treats them the same as any other IDL provided type but they are so fundamental to the
workings of the framework that it provides special implementations for each.

module SCA {

// Type for holding return values and error messages


struct SCAResult
{
SCAInt32 errorCode;
SCAInt32 messageTable;
SCAInt32 messageID;
SCAAnySequence params;
};

// UUID definition for SCA Types


struct SCAUUID {
SCA::SCAUInt64 part1;
SCA::SCAUInt64 part2;
};

};

The following exception types are predefined by the SCA framework. .


Chapter 4: The IDL Language 87
SDL Specifications

module SCA {

// Base for all SCA exceptions


exception SCAException{};

// Base for all User defined exceptions


exception SCAUserException: SCAException{};

// Base for all System defined exception


exception SCASystemException: SCAException {
SCAInt32 id;
};

};

The following sequence and dynamic array types are provided by the framework. These are provided for
convenience and to since many components required similar definitions it is more consistent if everyone
uses the same ones.
88 SCA Framework User’s Guide
SDL Specifications

module SCA {

// Standard sequence types


typedef sequence<SCAInt8> SCAInt8Sequence;
typedef sequence<SCAUInt8> SCAUInt8Sequence;
typedef sequence<SCAInt16> SCAInt16Sequence;
typedef sequence<SCAUInt16> SCAUInt16Sequence;
typedef sequence<SCAInt32> SCAInt32Sequence;
typedef sequence<SCAUInt32> SCAUInt32Sequence;
typedef sequence<SCAInt64> SCAInt64Sequence;
typedef sequence<SCAUInt64> SCAUInt64Sequence;
typedef sequence<SCAReal32> SCAReal32Sequence;
typedef sequence<SCAReal64> SCAReal64Sequence;
typedef sequence<SCAChar> SCACharSequence;
typedef sequence<SCAWChar> SCAWCharSequence;
typedef sequence<SCAString> SCAStringSequence;
typedef sequence<SCAWString> SCAWStringSequence;
typedef sequence<SCABool> SCABoolSequence;
typedef sequence<SCAAny> SCAAnySequence;
typedef sequence<SCATypeCode> SCATypeCodeSequence;

// Define some standard dynamic array types


typedef SCAInt8 SCAInt8DynamicArray[];
typedef SCAUInt8 SCAUInt8DynamicArray[];
typedef SCAInt16 SCAInt16DynamicArray[];
typedef SCAUInt16 SCAUInt16DynamicArray[];
typedef SCAInt32 SCAInt32DynamicArray[];
typedef SCAUInt32 SCAUInt32DynamicArray[];
typedef SCAInt64 SCAInt64DynamicArray[];
typedef SCAUInt64 SCAUInt64DynamicArray[];
typedef SCAReal32 SCAReal32DynamicArray[];
typedef SCAReal64 SCAReal64DynamicArray[];
typedef SCAChar SCACharDynamicArray[];
typedef SCAWChar SCAWCharDynamicArray[];
typedef SCAString SCAStringDynamicArray[];
typedef SCAWString SCAWStringDynamicArray[];
typedef SCABool SCABoolDynamicArray[];
typedef SCAAny SCAAnyDynamicArray[];
typedef SCATypeCode SCATypeCodeDynamicArray[];

};
Chapter 4: The IDL Language 89
CDL Specifications

CDL Specifications
The SCA IDL language allows for the definition of SCA services. The definition of services should
always be placed in source files with the extension of ".sdl" and these SDL files should only contain
service definitions. Only one service definition is allowed in each SDL file.
The IDL compiler uses the service definitions in SDL files to generate sample implementation code
skeletons for a service in one of the supported languages. See the IDL mapping section for your language
for the complete details.
The IDL compiler also uses the service definitions to generate support code that links the developer's
implementation code to the SCA Framework. This code is automatically generated, compiled and linked
with the SCA services you build.
When designing the implementation for a SCA service, the developer is free to structure the code any
way they wish. Usually the implementation of a service will be split among several different classes. In
some cases the IDL compiler needs to understand this structure. In general, the following types of classes
might be used.
• The Top-Level class that is instantiated when an instance of the service is requested. This class
must implement at least one SCA interface. This class is referred to as the Top-Level service
class.
• Additional classes may be instantiated that also implement SCA interfaces. Pointers to instances
of these classes, in the form of interface references, may then be passed outside of the service to
other SCA services. These classes are referred to as Sub-Service classes.
• Additional classes may be instantiated that do not implement SCA interfaces. Because these
classes do not implement any SCA interfaces, pointers to them cannot be passed outside of the
service. They can only be used internally as part of the implementation of the service.
Of these three types of classes, the IDL compiler only needs to be aware of the first two because they
each implement SCA interfaces. Since interface references to any instance of these classes may be passed
outside of the service, appropriate support code is generated to control the life cycle of these instances to
insure that they will be deleted when no longer referenced.
When coding SDL definitions, the general rule is that any class in the implementation of a service that
implements a SCA interface must be declared in the SDL file. The declaration must also include, either
directly or indirectly, all of interfaces that each class implements. Because interfaces can inherit from
other interfaces, if the SDL specifies that a class implements a specific interface, then the class must also
implement all interfaces that it is derived from. Because of this it is not required that you specify every
base interface in your SDL definitions. It is only required that you include the most derived interfaces.
The structure of the Top-Level service class and Sub-Service classes is very similar but do differ because
of the way instances of them are created. An instance of the Top-Level class is only triggered when a
SCA Framework request is made for a new instance of the service. There is no provision for this type of
request to include any parameters that can be passed to the service instance when it is constructed. Sub-
Service classes, however, can only be instantiated from within the implementation code of a service. It
is reasonable to assume that there will be a need to initialize these classes so this information can also be
provided in the definition of Sub-Service classes.
90 SCA Framework User’s Guide
CDL Specifications

The grammar of a SCA service definition is as follows:


<service> ::= <service_dcl> "{" <service_body> "}"
<service_dcl> ::= "service" <service_name>
< service_name > ::= <identifier>
| < service_name > "." <identifier>
<service_body> ::= <service_entry>+
<service_entry> ::= <option_dcl> ";"
| <interface_ref> ";"
| <sub_service> ";"
<option_dcl> ::= <option>+
<option> ::= "singleton"
| "delegate"
| "inherit"
| "aggregates"
| "aggregated"
<interface_ref> ::= "interface" <scoped_name>
<scoped_name> ::= <identifier>
| "::" <identifier>
| <scoped_name> "::" <identifier>
<sub_service> ::= <subservice_dcl>
"{" <sub_service_body> "}"
<sub_service_dcl> ::= "subservice" <identifier>
[ <parameter_dcls> ]
<parameter_dcls> ::= "(" <param_dcl>
{ "," <param_dcl> }* ")"
| "(" ")"
<sub_service_body> ::= <sub_service_entry>+
<sub_service_entry> ::= <interface_ref> ";"
A service definition consists of these elements:
• The keyword service
• The fully qualified dotted service name
• Definition of the service body enclosed by the characters "{" and "}".

service A.B.C.MyService {};

The fully qualified dotted service name serves several purposes. For complete details on these see section
IDL/SDL/CDL Names, Namespaces and Directories.
The body of a service definition consists of the following elements in any order.
• Zero or more service option specifications.
• One or more interface references for the interfaces that the Top-Level service class will
implement. The interface names must be normally scoped names that resolve to previously
defined interfaces.
• Zero or more Sub-Service definitions.

The following example shows a service that implements one interface.


Chapter 4: The IDL Language 91
CDL Specifications

service A.B.C.MyService1
{
interface Inf1;
};

Since the service class must also implement all base classes of the specified interface, in reality this
service class will implement a minimum of two interfaces. The second interface is SCA::SCAIService
which is the common base class for all SCA interfaces. It may also implement additional interfaces
depending on the actual definition of the Inf1.
You may also specify more the one interface for the service class.

service A.B.C.MyService2
{
interface Inf1;
interface Inf2;
};

You may need to also specify some options for the service.

service A.B.C.MyService3
{
singleton;
delegate;
interface Inf1;
};

A Sub-Service definition consists of these elements.


• The keyword subservice.
• An optional parenthesized initialization parameter list for the Sub-Service class that is passed to
the class when it is instantiated.
• Definition of the Sub-Service body enclosed by the characters "{" and "}"

The grammar for the optional parameter list for a Sub-Service is the same as for an interface operation
and is described in section Operation Declaration. Generally, the only parameter types that are allowed
in the parameter list are those that can be defined in the IDL. But, in some languages it is possible to pass
non-IDL pointer types using the special SCAVoidPtr type.
The Sub-Service body contains one or more interface references for the interfaces this Sub-Service class
will implement. The interface names must be normally scoped names that resolve to previously defined
interfaces.
92 SCA Framework User’s Guide
CDL Specifications

service A.B.C.MyService1
{
interface Inf1;
subservice MySub1
{
interface Inf2;
};
};

The following example shows a second subservice class which includes optional parameters.

service A.B.C.MyService2
{
interface Inf1;
subservice MySub1
{
interface Inf2;
};
subservice MySub2( in SCAInt32 value, in
SCAVoidPtr ptr )
{
interface Inf3;
interface Inf4;
};
};

Service Options
In the definition of a SCA service there are several options that can be specified which will affect the type
of code generated by the IDL compiler.
• singleton: Only one instance of a singleton service may exist at any given time. Once an instance
of the service has been created, additional calls to get a copy of the service will return the same
instance. For normal non-singleton services, each call to get a copy of the service will return a
new instance of the service.
• delegate or inherit: The default code generated for a SCA service will use an implementation that
inherits from a base class generated by the IDL compiler. This base class will then inherit from
the interface class and also provide all the necessary links to the SCA Framework. There may be
situations where this form of implementation is inconvenient because of other requirements in
your classes. To resolve this, the delegation form of implementation can be used. With
delegation, the skeleton classes generated by the IDL compiler do not inherit from a base or
interface classes. Instead the base class is replaced with a separate or tie class which inherits
from the interface class and provides all the necessary links to the SCA Framework. When a new
instance of the service is requested, an instance of the tie class is constructed and returned. The
tie class will internally construct a separate instance of your implementation class when it is
initialized. Interface calls to the methods in the tie class are then delegated to the methods in the
implementation class.
Chapter 4: The IDL Language 93
CDL Specifications

• aggregates: Interface aggregation is one method in interface based programming to extend a


service by reusing implementation from another service. The aggregates option specifies that
this service class will use aggregation. The services that implement the interfaces that will be
aggregated must be defined with the aggregated option. For complete details on aggregation see
the section on implementation reuse.
• aggregated: This option specifies that the interfaces implemented by this service class may be
aggregated by another service which is defined with the aggregates option.
Not all languages support all of these options. See the sections on the IDL mappings for the language you
will be using for the complete details on which options are supported.
94 SCA Framework User’s Guide
SCA Component Declaration

SCA Component Declaration


The SCA IDL language allows for the definition of SCA components. A SCA component is the container
that is used to deliver one or more services. The definition of components should always be placed in
files with the extension of ".cdl" and these CDL files should only contain component definitions. Only
one component definition is allowed in each CDL file.
The IDL compiler uses the component definitions to generate support code that makes the services in the
component available to the SCA Framework. This code is automatically generated, compiled and linked
with the SCA component you build.
Since SCA components are nothing more than a container for one or more SCA services, their definitions
consists of a list of these services.
The grammar of a SCA component definition is as follows:
<component> ::= <component_dcl>
"{" <component_body> "}"
<component_dcl> ::= "component" <component_name>
< component_name > ::= <identifier>
| < component_name > "." <identifier>
<component_body> ::= <component_entry>+
<component_entry> ::= <option_dcl> ";"
| <service_ref> ";"
<option_dcl> ::= <option>+
<option> ::= "embedded"
<service_ref> ::= "service" <service_name>
< service_name > ::= <identifier>
| < service_name > "." <identifier>
A component definition consists of these elements:
• The keyword component
• The fully qualified dotted component name
• Definition of the component body enclosed by the characters "{" and "}"

The body of a component definition consists of the following elements in any order.
• Zero or more component option specifications.
• One or more service references for the services that the component will contain.

component A.B.C.MyComponent1
{
service Service1;
service SCA.Util.Service2;
};

You may need to also specify some options for a component.


Chapter 4: The IDL Language 95
SCA Component Declaration

component A.B.C.MyComponent1
{
service Service1;
service SCA.Util.Service2;
};

The fully qualified dotted component name serves several purposes. For complete details on these see
section IDL/SDL/CDL Names, Namespaces and Directories.
The service names used may be either a short name or the fully qualified dotted name. If a short name is
used there must be no ambiguities when resolving it to a service definition based on the following rules.
• If there is only one service in the entire source tree with the same short name, that that service
definition is used.
• If there is more than one service in the entire source tree with the same short name, there must be
only one in the sub-tree of the source tree that is rooted in the directory that contains the CDL
file for the component.

Component Options
In the definition of a SCA component there are several options that can be specified which will affect the
type of code generated by the IDL compiler.
• embedded: Normally, each SCA component will be packaged by the build system into a separate
package that is appropriate for the language it is implemented in. For example a component
implemented in C++ is linked into a shared library and a Java component is packaged in a jar
file. Under some conditions it may be desirable to not do this packaging. This allows you to
manually package the files with other parts of your program as required. See the section on
Embedded Components for examples of when this may be useful.
Not all languages support all of these options. See the sections on the IDL mappings for the language you
will be using for the complete details on which options it supports.
96 SCA Framework User’s Guide
Using the SCA-IDL Compiler

Using the SCA-IDL Compiler


The SCA Framework provides an IDL compiler that is used to process the ".idl", ".sdl" and ".cdl" files.
Using the definitions in these files, the compiler generates a set of source files that are appropriate for the
implementation language being used.

The IDL compiler command


The following is the syntax for the command to run the SCA IDL compiler command..
Chapter 4: The IDL Language 97
Using the SCA-IDL Compiler

Run the SCA/IDL compiler.

Usage: idl [options] file, [file, file, ...]

One of the following options must be given:

-w : Generates glue part of interfaces, services and components


-s : Generates skeleton for user's part of a service
-h : Print this message

Additional Options:

-b backend : Name of back-end module to run


-c : Keep comments from IDL files in interface headers
-e : An error is generated if any of the files already exist
-f : List the files that will be generated, do not generate them
-Dxxx : Add pre-preprocessor define
-i path : Add path to the list of search directories for includes
-nf : Do not warn about unresolved forward declarations
-o path : Base directory where output files are written
Default is the current working directory
-xmlo path : Base directory where XML output files are written
Default is the same as specified with the "-O" parameter
-nrd : Do not put interface header files in relative sub-directories
specified by IDL module statements. Instead they will be put
directly in the current working directory or the directory
specified with the "-o" option.
-q : Do not print the IDL compiler version number on stdout
-t : Generate tie or delegated service implementation
-wbxxx : Pass option "xxx" directly to the back-end module
-tc : Generate TypeCode information for IDL defined types
-ntc : Do not generate TypeCode information for IDL defined types
-xmltc : If "-tc" set, generate XML TypeCode information
-nxmltc : If "-tc" set, generate embedded TypeCode information

Debug options:

-dump : Dump the parsed IDL then exit, without running back-end
-p : Only run the pre-processor, sending its output to stdout
-v : Verbose output to trace compilation stages

The extension of the input file is used to determine the type of files that
will be generated:

.cdl -> Generate component implementation (-w)


.sdl -> Generate service implementation (-w) or skeletons (-s)
.idl -> Generate interface headers (-w)

Compiler processing modes


When running the IDL compiler, one of the two following modes must be selected.
98 SCA Framework User’s Guide
Using the SCA-IDL Compiler

• The "-s" option is used when you want the IDL compiler to generate skeleton code for the
implementation of a SCA service. This option only has affect when processing SDL files. The
files generated will always have an extension of ".new" appended to their name so they will not
accidentally overwrite any existing implementation files. This option is normally used when you
are first starting to develop a SCA service. You first write the IDL and SDL definitions for the
service and then use the IDL compiler to generate the skeleton code. You may also want to rerun
the compiler at a latter time if you make significant changes to your IDL and/or SDL files and
need to update your existing implementation. Normally you do not directly run the IDL compiler
with this option. Instead you will use the genskeleton command which provides additional
features for generate your skeletons.
• The "-w" option is used when you want the IDL compiler to generate the code that is required to
link the developer's implementation code to the SCA Framework. This option is normally only
used by the SCA Build System and applies to all three IDL file types.

Location for compiler generated files


The files generated by the IDL compiler will be stored in several different locations depending on the
compiler options provided and the type of files being generated.
The default location for files generated from SDL and CDL inputs, regardless of whether the "-s" or "-
w" mode is selected, is always the current directory where the command was run from. The "-o" compiler
option can be used to change this location.
For IDL files, which are only processed when the "-w" mode is selected, the generated files are normally
stored in a relative sub-directory that is determined from the module commands in the IDL file. Consider
the following example IDL file.

module SCA { module FileReaders { module Nastran {

interface SCAIReader : SCAIService


{
SCAResult importBDF( in SCAString sFileName );
};

}; }; };

In this example, the file generated for the "SCAIReader" interface would be stored in the relative sub-
directory "SCA/FileReaders/Nastran". The base for the relative sub-directory will be the current
directory where the command was run from. The "-o" compiler option can be used to change this base
location. If the "-nrd" compiler option is specified, then the files will not be stored in a relative sub-
directory. Instead they will be stored directly in the current directory or in the directory specified with the
"-o" option.
Chapter 4: The IDL Language 99
Using the SCA-IDL Compiler

The genskeleton command


The genskeleton command is used to generate skeletons for the implementation code, in the language of
your choice, for the service definitions provide in ".sdl" files.
The following is the syntax for the command to run the SCA genskeleton command.

Generate skeleton code for a service implementation from the definitions in a


SDL file.

Usage: genskeleton [options] file [files, file, ...]

The following options are available:

-h : Print usage information


-cxx : For C++ implmentation (default)
-java : For Java implmentation
-csharp : For C# implmentation
-vb : For Visual Basic .NET implmentation
-r : If versions of the output files already exist, they will be
renamed by appending an extension of ".old". The new files
will then have their ".new" extension removed.
-v : Show the actual commands as they are executed.

The generation of skeleton files is a two step process.


• The SCons build system is run to install any IDL files in the current directory into your
APPS_LOCAL directory. This is required because the IDL compiler cannot use the IDL files
located in your source directory. This is because the relative paths for the IDL files that must be
included must use the directory structure in the APPS_LOCAL tree and not the directory
structure used in the source tree.
• The IDL compiler is run to build the skeletons from the SDL file.

Since the build system must be run first, this script will only work if you are located in a properly
configured source tree. This means there must be a SConscript file in the current directory and there must
be a SConstruct file in either the the current directory or one of its parents.
The skeleton files generated by the IDL compiler normally have an extension of ".new" appended to the
files names so they will not overwrite any existing versions. If none of the files currently exist, then the
new versions will have the ".new" extension removed. If any of the files do exist, the newly generated
files will keep their ".new" extension unless "-r" option is provided. In this case, the existing versions of
the files will be saved by adding an extension of ".old", and the new versions will then replace them.
100 SCA Framework User’s Guide
Summary

Summary
Chapter 5: IDL to C++ Language Mapping
SCA Framework User’s Guide

5 IDL to C++ Language Mapping


Introduction 102

Mapping for Identifiers 104
 Mapping for Modules 105

Mapping for Basic Types 106

Mapping for String Types 107
 Mapping for Enumerated Types 108

Mapping for Structures 109

Mapping for Arrays 110
 Mapping for Sequences 116

Mapping for Type Aliases 119

Mapping for SCATypeCode 120
 Mapping for SCAAny 121
 Mapping for SCAResult 127

Mapping for Constants 130
 Mapping for Interfaces 131
 Mapping for Exceptions 137

Mapping for SCA Services 141

Mapping for SCA Components 150
102 SCA Framework User’s Guide
Introduction

Introduction
The IDL language provides a language independent definition of SCA interfaces and data types. In order
to actually use these definitions, there must be a set of rules, commonly known as a mapping; that
describes how these types are represented in a particular language. This chapter explains the mapping
that SCA uses for the C++ language.
For every type defined in IDL, the IDL compiler will generate the code required to expose the proper
C++ definition of the type. In addition to the actual C++ definition of the type, there is also some support
code generated which is used by the SCA Framework to manage instances of each type. An example of
this is the bridging of instances of the type between C++ and the other languages supported by the SCA
Framework.
• The SCA C++ mapping uses a set of overloaded bi-directional marshalling operators to
manipulate data in instances of the SCAAny type and for some bridging operations. For each
user defined type the IDL compiler will generate these required operator definitions. The format
for these is different for each different type and will be shown in the various mapping sections
below. For the basic and predefined types that are delivered with the SCA Framework, these
operators are predefined in the delivered header files.
• For each type the IDL compiler will generate some support code for accessing the
SCATypeCode created at runtime by the SCA Framework. This code will be described in the
SCATypeCode mapping section latter in this chapter.
The code that is generated by the IDL compiler is stored in one of several files depending on whether it
is an interface or a user defined type definition.
• All of the user defined types, defined outside of interfaces, in the same .idl file will be store in a
single header file. The name of the file will be xxxTypes.h for the IDL file named xxx.idl. The
relative directory under the include directory in the delivery tree where the generated file is
stored is taken from the namespace of the first type defined in the file.
• For each interface defined in the IDL file, two header files will be generated, one for the smart
pointer definition and one for the full definition of the abstract interface class. The relative
directory under the include directory in the delivery tree where the generated files are stored is
taken from the namespace that the interface is defined in.
Consider the following simple IDL file to demonstrate these rules.

IDL file “mytest.idl”


module SCA { module Test {

enum MyENUM { VALUE1, VALUE2 };

Module Test2 {

Struct MyStruct { SCAInt32 data; } ;

Interface SCAITest1 : SCAIService { };


Chapter 5: IDL to C++ Language Mapping 103
Introduction

};

Interface SCAITest2 : SCAIService { };

}; };

The IDL compiler will generate the following type file for this definition.

SCA/Test/mytestTypes.h - contains MyEnum and MyStruct


SCA/Test/Test2/SCAITest1SPtr.h - contains smart pointer for SCAITest1
SCA/Test/Test2/SCAITest1.h - contains interface for SCAITest1
SCA/Test/SCAITest2SPtr.h - contains smart pointer for SCAITest2
SCA/Test/SCAITest2.h - contains interface for SCAITest2

Although it is legal to include type and constant definitions inside an interface body, it is a discouraged
practice. As a result the affect on the mappings described in this section will not be discussed.
104 SCA Framework User’s Guide
Mapping for Identifiers

Mapping for Identifiers


IDL identifiers are mapped to C++ with no change. For example:

IDL
enum Color { RED, GREEN, BLUE };

C++
enum Color { RED, GREEN, BLUE };
There is one potential problem to be aware of. If the IDL contains an identifier that is also a C++ reserved
keyword, then the resulting C++ code will not compile. The OMG IDL specification dictates that in this
case the identifier should be automatically prefixed with the string “_cxx_”. Since this leads to ugly and
non-intuitive code, the SCA IDL compiler does not implement this feature. Therefore, the use of C++
reserved words for identifiers is not allowed.
Chapter 5: IDL to C++ Language Mapping 105
Mapping for Modules

Mapping for Modules


The IDL module construct is mapped directly to a C++ namespace with the same name.

IDL
module SCA { module Test {
// definitions
}; };

C++
namespace SCA { namespace Test {
// definitions
} }
The IDL module constructs also affect other aspects of the SCA mapping. See the IDL Compiler chapter
for detailed information on how the IDL module statements are used.
106 SCA Framework User’s Guide
Mapping for Basic Types

Mapping for Basic Types


Each basic IDL data type is mapped to a C++ typedef in the SCA namespace with the same name. This
is done because some types, like SCAInt16 and SCAInt32, may have different representations on
different platforms, and the SCA definitions will reflect the appropriate representation for that platform.
It is therefore important to use the appropriate SCA types and not the native C++ types when dealing with
interface parameters and results to insure compatibility across platforms.

SCA IDL Type C++ Type


SCA::SCAInt8 SCA::SCAInt8
SCA::SCAInt16 SCA::SCAInt16
SCA::SCAInt32 SCA::SCAInt32
SCA::SCAInt64 SCA::SCAInt64
SCA::SCAUInt8 SCA::SCAUInt8
SCA::SCAUInt16 SCA::SCAUInt16
SCA::SCAUInt32 SCA::SCAUInt32
SCA::SCAUInt64 SCA::SCAUInt64
SCA::SCAReal32 SCA::SCAReal32
SCA::SCAReal64 SCA::SCAReal64
SCA::SCAChar SCA::SCAChar
SCA::SCAWChar SCA::SCAWChar
SCA::SCABool SCA::SCABool

All of the mappings for the basic types are distinguishable and unique with respect to overloading. That
is, one can safely write overloaded C++ functions for SCAInt8, SCAUInt8, SCAInt16, SCAUInt16,
SCAInt32, SCAUInt32, SCAInt64, SCAUInt64, SCAReal32, SCAReal64, SCAChar, SCAWChar
and SCABool types and each of these will be unique. Remember that overloading is not permitted in
interface operations in IDL but it can be used in service implementation code. This is also a requirement
to allow type-safe processing of data in a SCAAny type.
Chapter 5: IDL to C++ Language Mapping 107
Mapping for String Types

Mapping for String Types


The IDL SCAString type is directly mapped to the C++ STL string class and the SCAWString type is
directly mapped to the C++ STL wstring class.
namespace SCA {
typedef std::string SCAString;
typedef std::wstring SCAWString;
}
108 SCA Framework User’s Guide
Mapping for Enumerated Types

Mapping for Enumerated Types


An IDL enum maps directly to the corresponding C++ enum type definition.

IDL
enum Color { RED, GREEN, BLUE };

C++
enum Color { RED, GREEN, BLUE };

inline SCAMarshaller& operator >>= (const Color& val,


SCAMarshaller& stream){
SCAInt32 ival = static_cast< SCAInt32 >(val);
ival >>= stream;
return stream;
}

inline SCAMarshaller& operator <<= (Color& val,


SCAMarshaller& stream){
SCAInt32 ival;
ival <<= stream;
val = static_cast< Color >(ival);
return stream;
}
Chapter 5: IDL to C++ Language Mapping 109
Mapping for Structures

Mapping for Structures


An IDL structure maps to a C++ struct, with each IDL structure member mapped to a corresponding
member of the C++ structure. The C++ structure members appear in the same order as the corresponding
IDL structure members. For example:

IDL
struct Node
{
SCAInt32 id;
SCAReal32 x;
SCAReal32 y;
SCAReal32 z;
};

C++
struct Node
{
SCAInt32 id;
SCAReal32 x;
SCAReal32 y;
SCAReal32 z;
};

inline SCAMarshaller& operator >>= (const Node& val


SCAMarshaller& stream){
stream.setSize(TypeCodeForType< Node >::get());
val.id >>= stream;
val.x >>= stream;
val.y >>= stream;
val.z >>= stream;
return stream;
}

inline SCAMarshaller& operator <<= (Node& val,


SCAMarshaller& stream){
val.id <<= stream;
val.x <<= stream;
val.y <<= stream;
val.z <<= stream;
return stream;
}
110 SCA Framework User’s Guide
Mapping for Arrays

Mapping for Arrays


Two types of array definitions are supported in IDL. Fixed size arrays must have their size defined in the
IDL and can never change. Dynamic arrays allow you to delay the specification of the array size until it
is actually allocated. Only arrays of rank 1 or 2 are supported.

Fixed size arrays


The C++ compiler represents a standard array reference as a simple pointer to values of their data type.
As a result, two different IDL defined arrays which contain data of the same type will be treated as the
same type when distinguishing operator overloads. This would make it difficult to support the insertion
of these arrays into a SCAAny value in a type-safe manner. To allow for the type-safe handling of arrays,
each IDL defined array is mapped to a light weight C++ class which acts like a normal C++ array.

IDL
typedef SCAInt32 Date[3];

C++
class Date
{
public:
typedef SCAInt32 value_type;
typedef size_t size_type;
Date() { }
size_type size() const { return 3; }
value_type& operator[](size_type idx) { return data[idx]; }
const value_type& operator[](size_type idx)const {
return data[idx];
}
private:
value_type data[3];
};

inline SCAMarshaller& operator >>= (const Date& val,


SCAMarshaller& stream){
stream.setSize(TypeCodeForType< Date >::get());
for(Date::size_type i=0; i<3; i++) val[i] >>= stream;
return stream;
}

inline SCAMarshaller& operator <<= (Date& val,


SCAMarshaller& stream){
for(Date::size_type i=0; i<3; i++) val[i] <<= stream;
return stream;
}

Two dimensional arrays are handled in a similar manner.


Chapter 5: IDL to C++ Language Mapping 111
Mapping for Arrays

IDL
typedef SCAInt32 Matrix[5][5];

C++
class Matrix
{
public:
typedef SCAInt32 value_type;
typedef size_t size_type;
Matrix() {}
size_type size1() const { return 5; }
size_type size2() const { return 5; }
value_type* operator[](size_type idx) { return data[idx]; }
const value_type* operator[](size_type idx) const {
return data[idx];
}
private:
value_type data[5][5];
};

inline SCAMarshaller& operator >>= (const Matrix& val,


SCAMarshaller& stream){
stream.setSize(SCA::TypeCodeForType< Matrix >::get());
for(Matrix::size_type i=0; i<5; i++)
for(Matrix::size_type j=0; j<5; j++)
val[i][j] >>= stream;
return stream;
}

inline SCAMarshaller& operator <<= (Matrix& val,


SCAMarshaller& stream){
for(Matrix::size_type i=0; i<5; i++)
for(Matrix::size_type j=0; j<5; j++)
val[i][j] <<= stream;
return stream;
}
Only one and two dimensional arrays are support by the C++ mapping.

Dynamic arrays
Dynamic arrays are implemented in C++ with several template class types. The following is the
definitions for the one and two dimensional dynamic array.
The ArrayData class is the actual object that stores the data for an instance of either a one or two
dimensional dynamic array. It adds reference counting to the data to allow more efficient handling of it.
template <typename T>
class ArrayData
{
public:
typedef T value_type;
112 SCA Framework User’s Guide
Mapping for Arrays

typedef size_t size_type;


typedef value_type& reference;
typedef const value_type& const_reference;
typedef value_type* pointer;
typedef const value_type* const_pointer;
friend class ArrayPtr1<value_type>;
friend class ArrayPtr2<value_type>;
friend class SCAMemoryMarshaller;

ArrayData(pointer data, size_type size1, size_type size2,


DestroyFunc destroyFunc, SCATypeCode contTC);
~ArrayData();
SCAVoid addReference();
SCAVoid releaseReference();

private:
value_type* m_data;
unsigned long m_refcnt;
size_type m_size1;
size_type m_size2;
DestroyFunc m_destroyFunc;
SCATypeCode m_contTC;
};
ArrayPtr1 is the template class for a one dimensional dynamic array. The actual instance of a dynamic
array objects are an instance of this class. It contains an instance of the ArrayData class and manages
the reference count on it. The ArrayPtr1 class provides the appropriate operator overloads to act like a
normal C++ array. It also provides a number of additional methods for managing the ArrayData data it
points to.

template<typename T>
class ArrayPtr1
{
public:
typedef T value_type;
typedef ArrayData<value_type> arraydata;
typedef typename arraydata::size_type size_type;
typedef typename arraydata::reference reference;
typedef typename arraydata::const_reference const_reference;
typedef typename arraydata::pointer pointer;
typedef typename arraydata::const_pointer const_pointer;
friend class SCAMemoryMarshaller;

ArrayPtr1();
ArrayPtr1(value_type* data, size_type size,
DestroyFunc destroyFunc=NULL,
SCATypeCode contTC=SCATypeCode());
ArrayPtr1(const ArrayPtr1& val)
~ArrayPtr1();
void set(pointer data, size_type size,
DestroyFunc destroyFunc=NULL,
SCATypeCode contTC=SCATypeCode());
Chapter 5: IDL to C++ Language Mapping 113
Mapping for Arrays

void setTypeCode(SCATypeCode contTC);


void clear();
size_t size() const;
bool empty() const;
bool shared() const;
pointer data() const;
ArrayPtr1<value_type>& operator=(const ArrayPtr1& val);
const_reference operator[](size_type index) const;
reference operator[](size_type index);

private:
arraydata* m_arraydata;
};
ArrayPtr2 is the template class for a two dimensional dynamic array. The actual instance of a dynamic
array objects are an instance of this class. It contains an instance of the ArrayData class and manages
the reference count on it.
template<typename T>
class ArrayPtr2
{
public:
typedef T value_type;
typedef ArrayData<value_type> arraydata;
typedef typename arraydata::size_type size_type;
typedef typename arraydata::reference reference;
typedef typename arraydata::const_reference const_reference;
typedef typename arraydata::pointer pointer;
typedef typename arraydata::const_pointer const_pointer;

ArrayPtr2();
ArrayPtr2(value_type* data, size_type size1, size_type size2,
DestroyFunc destroyFunc=NULL,
SCATypeCode contTC=SCATypeCode());
ArrayPtr2(const ArrayPtr2& val);
~ArrayPtr2();
void set(pointer data, size_type size1, size_type size2,
DestroyFunc destroyFunc=NULL,
SCATypeCode contTC=SCATypeCode());
void setTypeCode(SCATypeCode contTC);
void clear();
size_t size1() const;
size_t size2() const;
bool empty() const;
bool shared() const;
pointer data() const;
ArrayPtr2<value_type>& operator=(const ArrayPtr2& val);
const_pointer operator[](size_type index) const;
pointer operator[](size_type index);

private:
arraydata* m_arraydata;
};
114 SCA Framework User’s Guide
Mapping for Arrays

The generated code for dynamic array types must also be handled differently because the C++ compiler
treats two different instantiation of a template with the same parameter type the same when distinguishing
operator overloads. This would make it difficult to support the insertion of the dynamic arrays into a
SCAAny value in a type-safe manner. To allow for the type-safe handling of dynamic arrays, each IDL
defined sequence is mapped to a light weight C++ class that inherits from the template class.
The following shows an example of the generated code for a one dimensional dynamic array type.

IDL
typedef SCAInt32 DynDate[];

C++
class DynDate : public DynamicArray::ArrayPtr1< SCAInt32 >
{
public:
typedef SCAInt32 value_type;
typedef DynamicArray::ArrayPtr1<value_type> base;
typedef base::size_type size_type;
DynDate() : base() {}
DynDate(value_type* data, size_type size,
DynamicArray::DestroyFunc desfunc=0) :
base(data,size,desfunc) {};
};

inline SCAMarshaller& operator >>= (const DynDate& val,


SCAMarshaller& stream)
{
stream.packDynamicArray(&val);
return stream;
}

inline SCAMarshaller& operator <<= (DynDate& val,


SCAMarshaller& stream)
{
stream.unpackDynamicArray(&val);
return stream;
}
The following shows an example of the generated code for a two dimensional dynamic array type.

IDL
typedef SCAInt32 DynMatrix[][];

C++
class DynMatrix : public DynamicArray::ArrayPtr2< SCAInt32 >
{
public:
typedef SCAInt32 value_type;
typedef DynamicArray::ArrayPtr2<value_type> base;
typedef base::size_type size_type;
DynMatrix() : base() {}
Chapter 5: IDL to C++ Language Mapping 115
Mapping for Arrays

DynMatrix(value_type* data, size_type size1, size_type size2,


DynamicArray::DestroyFunc desfunc=0) :
base(data,size1,size2,desfunc) {};
};

inline SCAMarshaller& operator >>= (const DynMatrix& val,


SCAMarshaller& stream)
{
stream.packDynamicArray(&val);
return stream;
}

inline SCAMarshaller& operator <<= (DynMatrix& val,


SCAMarshaller& stream)
{
stream.unpackDynamicArray(&val);
return stream;
}
The details of using dynamic arrays are an advanced topic and are discussed in detail in the Dynamic
SCA chapter of the Advanced SDK manual.
116 SCA Framework User’s Guide
Mapping for Sequences

Mapping for Sequences


The IDL SCASequence type is implemented in C++ as a template class type that inherits from the
standard C++ STL vector class. The SCASequence template class adds the following new behavior to
the standard STL vector class.
• The actual sequence data is reference counted to reduce to a minimum the times when the actual
data will be copied.
• The SCASequence implements the copy on write idiom so multiple readers can share the same
copy of the data and only when one copy is changed is a copy of the actual data made
The following example uses the framework provided SCAInt32Sequence to show how this works. First
the code declares an instance of the sequence, values1, and fills it with data.
SCAInt32Sequence values1;
for ( int i=0; i<1000; i++ )
values1.push_back(i);
Then a new instance of the sequence, values2, is allocated and set equal to the first instance. This
operation will not cause a new copy of the data in the sequence to be made. Instead both instances,
values1 and values2, will be referencing the same data.
vector<int> values2 = values1;
for ( int i=0; i<1000; i++ )
cout << values2.r_at(i) << endl;
Then an entry in the sequence is changed using the values2 instance. At this time a copy of the data will
be made and only the value in the second copy will be changed. Now when the sequence instance values1
is printed it will contain the original values but the values2 instance will contain the modified data.
values2[5] = 10;
for ( int i=0; i<1000; i++ )
cout << values1.r_at(i) << endl;
for ( int i=0; i<1000; i++ )
cout << values2.r_at(i) << endl;
In order for the copy on write behavior to work correctly, the various methods in the SCASequence class
must know when the data in the sequence is being read or when it is being written. The standard C++
vector class does not provide this ability because certain methods can be used for both purposes as shows
by the following example.
vector<int> values(10);
values.at(5) = 10;
int ival = values.at(5);
To solve this problem, the SCASequence provides two different versions of these methods, one for
reading and one for writing. The version for reading uses the standard std::vector name with an r_ prefix
and the writing version uses a w_ prefix.
SCAInt32Sequence values(10);
values.w_at(5) = 10;
int ival = values.r_at(5);
Chapter 5: IDL to C++ Language Mapping 117
Mapping for Sequences

The following table shows the standard methods in the STL vector class and their corresponding methods
in the SCASequence class which are different. All of the other methods are the same.

std::vector SCASequence – read SCASequence - write


begin r_begin w_begin
end r_end w_end
rbegin r_rbegin w_rbegin
rend r_rend w_rend
address r_address w_address
at r_at w_at
front r_front w_front
back r_back w_back

The mapping for sequences types must be handled differently because the C++ compiler treats two
different instantiation of a template with the same parameter type the same when distinguishing operator
overloads. This would make it difficult to support the insertion of these sequences into a SCAAny value
in a type-safe manner. To allow for the type-safe handling of sequences, each IDL defined sequence is
mapped to a light weight C++ class that inherits from the template class.

IDL
typedef SCASequence<Node> NodeSequence;

C++
class NodeSequence : public SCA::SCASequence< Node >
{
public:
NodeSequence(size_type n, const Node& value = Node())
: SCA::SCASequence< Node >(n,value) { }
NodeSequence()
: SCA::SCASequence< Node >() { }
template <class InputIterator>
NodeSequence(InputIterator first, InputIterator last)
: SCA::SCASequence< Node >(first,last) { }
};
inline void swap(NodeSequence& x, NodeSequence& y)
{
x.swap(y);
}

inline SCAMarshaller& operator >>= (const NodeSequence& val,


SCAMarshaller& stream){
SCAUInt32 len = static_cast< SCAUInt32 >(val.size());
len >>= stream;
for(SCAUInt32 i=0; i<len; i++) val.r_at(i) >>= stream;
return stream;
118 SCA Framework User’s Guide
Mapping for Sequences

inline SCAMarshaller& operator <<= (NodeSequence& val,


SCAMarshaller& stream){
SCAUInt32 len;
len <<= stream;
val.resize(len);
for(SCAUInt32 i=0; i<len; i++) val.w_at(i) <<= stream;
return stream;
}
Chapter 5: IDL to C++ Language Mapping 119
Mapping for Type Aliases

Mapping for Type Aliases


An IDL typedef creates an alias for a type and is mapped to the corresponding C++ typedef. The examples
below illustrate this mapping.

IDL
typedef SCAInt32 Hour;
typedef SCAInt32 Minute;
typedef SCAInt32 Second;

C++
typedef SCAInt32 Hour;
typedef SCAInt32 Minute;
typedef SCAInt32 Second;
120 SCA Framework User’s Guide
Mapping for SCATypeCode

Mapping for SCATypeCode


The SCATypeCode type is a special type used by the SCA Framework to describe the details about each
IDL defined type. The SCA Framework creates instances of the SCATypeCode using XML data
generated by the IDL compiler. Each instance of the SCATypeCode contains the complete description
of one IDL defined type. For example, the description of a structure would include the name and type for
each of its members.
The SCATypeCode type is treated in IDL as a basic type and it can appear anywhere in the IDL where
a basic type can appear. For example it could be the member of a structure or one of the arguments in an
interface method.
In C++ a type code is represented by an instance of the SCA::SCATypeCode class. The definition of a
SCATypeCode contains a pair of values. These include a SCATypeCodeID value that indicates the type
of data and a description of the type. The contents of the description depend on the value of the
SCATypeCodeID. The SCATypeCode class is fairly complex and will not be discussed in detail here.
The data contained in this class is mostly used internally within the SCA Framework. If you need to
access these detailed type definitions you are encouraged to use the SCA.Framework.Reflection service
that is describe in detail in the Dynamic SCA chapter of the Advanced SDK manual.
Besides generating the XML type definition for every type defined, the IDL compiler also generates a
small bit of code for every IDL defined type which is used to obtain the SCATypeCode instance for a
given type. The following is the format of this code which is the same for all IDL types.
static SCATypeCode TC_SCA_Test_Color;
template<> struct TypeCodeForType< Color >
{
static const SCATypeCode get() {
if ( !TC_SCA_Test_Color.m_ptc )
getCachedTypeCodeInit("SCA.Test.Color",TC_SCA_Test_Color);
return TC_SCA_Test_Color;
}
};
The usage of these template specializations as well as other methods for accessing SCATypeCode values
is also described in the Dynamic SCA chapter of the Advanced SDK manual
Chapter 5: IDL to C++ Language Mapping 121
Mapping for SCAAny

Mapping for SCAAny


The SCAAny is a container data type which can hold a single value of any other arbitrary IDL data type.
Only values for types that are defined in IDL can be stored in a SCAAny. This is because the SCAAny
design requires a SCATypeCode value to describe the data it holds and marshalling operators to insert
and extract the actual value. Both of these are generated by the IDL compiler and will not exist for types
that are not defined in IDL.
The C++ mapping for the IDL type SCAAny fulfills two important requirements:
• It must handle the C++ types in a type-safe manner.
• It must handle values for complex types that are not known at compile time.

The first requirement covers the typical usage of the SCAAny type, the insertion of typed values into the
SCAAny and the type-safe extraction of the values. The second requirement covers situations like a
requirement to process a SCAAny value that holds data of a type that is unknown when the service was
built. In this case the receiver must be able to determine information about what type of data the SCAAny
contains so it can be processed correctly.
To achieve these requirements, the definition of a SCAAny contains a pair of values that includes a
SCATypeCode value, which describes what type of data is contained, and the actual value of the data.
Using the type code value, the C++ mapping of the SCAAny can enforce type safety and also allow for
the handling of types not known at compile time.
If the value stored in a SCAAny instance is a type that is referenced counted, like an interface pointer or
a SCASequence, the reference count will be correctly incremented when the value is inserted into the
instance and decremented when the SCAAny instance is destroyed or overwritten. It is therefore safe for
the SCAAny to hold only a reference to value and not a copy of it.
To decrease the chances of creating a SCAAny with a mismatched SCATypeCode and value, the C++
operator overloading facility is utilized. Specifically, for each distinct type in an IDL specification,
overloaded operators to insert and extract values of that type are used. Overloaded operators are used
instead of functions definitions to avoid namespace pollution. The usage of these insertion and extraction
operators is described below.

The SCAAny class definition


In C++ the SCAAny type is implemented by the SCA::SCAAny class. The public methods for the class
are shown below.

namespace SCA {
class SCAAny
{
public:

// Default constructor
SCAAny();
122 SCA Framework User’s Guide
Mapping for SCAAny

// Templated constructor to intialize SCAAny with a value


template<typename t_type>
explicit SCAAny(const t_type& val);

// Destructor
~SCAAny();

// Copy constructor
SCAAny(const SCAAny& val);

// Assignment operator
SCAAny& operator = (const SCAAny& val);

// Special insertion operator for a SCAAny iself


SCAVoid operator <<= (const SCAAny& val);

// Templated insertion operator for all other values.


template<typename t_type>
SCAAny& operator <<= (const t_type& val);

// Special extraction operator for a SCAAny iself. True is


// returned if and only if the extraction is successful
SCABool operator >>= (SCAAny& val) const;

// Templated extraction operator for all other values. True is


// returned if and only if the extraction is successful
template<typename t_type>
SCABool operator >>= (t_type& val) const;

// Routines to directly process dynamic arrays in a Any


SCAAny& insertArray(const SCATypeCode tcval,
SCAVoid* values,
SCAUInt32 numEnt1,
SCAUInt32 numEnt2,
const SCATypeCode tcArray=SCATypeCode(),
const DynamicArray::DestroyFunc destroyFunc=NULL);
SCABool extractArray(SCATypeCode& tcval,
SCAVoid** values,
SCAUInt32& numEnt1,
SCAUInt32& numEnt2) const;

// Data extraction and testing


SCAVoid dump() const;
SCATypeCode getType() const;
SCATypeCodeID getTypeID() const;
SCAString getTypeDesc() const;
SCAUInt32 getLength() const;
SCABool sameTypeCode(const SCATypeCode& tcval) const;
SCABool empty() const;
SCAVoid flush();
};
}
Chapter 5: IDL to C++ Language Mapping 123
Mapping for SCAAny

The class provides the following capabilities:


• Default constructor to create an empty SCAAny instance
• Copy constructor
• Destructor to release all resource held by the SCAAny instance
• Assignment operator
• Templated constructors to create a SCAAny instance from the given value
• Utility members for accessing and testing type of data stored in the SCAAny
• Templated insertion operator <<= for inserting a value into SCAAny
• Templated extraction operator >>= for extracting the contents of a SCAAny

Examples of the usages of these are show in the following sections.

Creating new SCAAny values


The following example creates an empty SCAAny value.
// Create an empty SCAAny instance
SCAAny anyval;
To create a new SCAAny value that contains a value you can use the templated constructor. Note that if
the value is a constant that could be converted to any one of several SCA types, you will have to explicitly
tell the compiler which one you wish to use.
// Create a SCAAny instance which contains a SCAInt32 value
SCAAny anyval(SCAInt32(100));

Inserting values into exiting SCAAny values


The insertion operator is used to insert a value into an existing SCAAny instance. If the SCAAny already
holds a value it will be replaced with the existing value and any resources used by the old value will be
released. Remember that the SCAAny can only hold a single instance at a time.
// Insert an SCAInt32 value to SCAAny instance
SCAInt32 int32val = 100;
anyval <<= int32val;
Or for a simpler version of the same operation you could use the following.
// Insert an SCAInt32 value to SCAAny instance
anyval <<= SCAInt32(100);
Remember that a SCAAny can hold any IDL defined type, not just the basic types used in the previous
example. Here is an example of inserting a sequence into a SCAAny.
// Insert an SCAReal32Sequence value to SCAAny instance
SCAReal32Sequence seqval;
seqval.push_back(1.2);
124 SCA Framework User’s Guide
Mapping for SCAAny

seqval.push_back(2.3);
anyval <<= seqval;
A SCAAny can even hold another SCAAny instance.
// Insert an SCAAny value to SCAAny instance
SCAAny anyval1(SCAInt32(100));
anyval <<= anyval1;

Extracting the value contained in a SCAAny


The extraction operator is used to extract the value from a SCAAny instance. The SCAAny remains
unchanged after the extraction.
// Extract the value from a SCAAny instance
SCAInt32 int32val
anyval >>= int32val;
The C++ implementation of the SCAAny is type safe. This means you can only extract the value from
the SCAAny if the type of the value it contains is the same as the type of the value you are trying to
extract it into. Since the compiler has no way of knowing what type of value it may contain, this decision
must be made at runtime. To handle this, the extraction operator returns a logical flag indicating if the
extraction was successful or if it failed. If the extraction was successful, the operation returns true,
otherwise it returns false. The following example shows how several extractions can be used to handle
different possible types of values that may be in the SCAAny instance.
// Extract the value from the SCAAny instance
SCAInt32 int32val;
SCAReal32 real32val;
if ( anyval >>= int32val ){
// Value in SCAAny was a SCAInt32 value and stored in “int32val”
} else if( anyval >>= real32val ){
// Value in SCAAny was a SCAReal32 value and stored in “real32val”
} else {
// Unsupported type
}

Assigning SCAAny values


The SCAAny provides an assignment operator and copy constructor that allows you to copy the value of
one SCAAny value into another. The actual data stored in the SCAAny is referenced counted so this
operation does not result in the coping of any actual data. It only needs to copy the pointer to the data and
increase its reference count.
// Assign a SCAAny value to another SCAAny instance
SCAAny anyval2;
anyval2 = anyval;
Chapter 5: IDL to C++ Language Mapping 125
Mapping for SCAAny

Interrogating the value contained in a SCAAny


In addition to using the return value from the extraction operator, you can also directly interrogate the
SCAAny value to see what type of data it contains. This is done by using the information in the
SCATypeCode value contained in the SCAAny instance. The following shows an example of using this
information to determine what type of value should be extracted instead of using the return value from
the extraction operator.
// Extract the value from the SCAAny instance
SCAInt32 int32val;
SCAReal32 real32val;
if ( anyval.getTypeID() == TCID_Int32 ){
anyval >>= int32val
} else if(anyval.getTypeID() == TCID_Real32 ){
anyval >>= real32val
} else {
// Unsupported type
}
Other methods are also available for accessing the type information.
// Get the SCATypeCode for the value in the SCAAny
SCATypeCode tcval = anyval.getType();

// Get the ID from the SCATypeCode for the value in the SCAAny
SCATypeCodeID tcid = anyval.getTypeID();

// Get the type description from the SCATypeCode for the value
SCAString tcdesc = anyval.getTypeDesc();

// Check if value of the type in the SCAAny is the same as


// the given SCATypeCode value
If ( anyval.sameTypeCode(tcval) ) {
// Value in SCAAny is the same as SCATypeCode tcval
}

Miscellaneous SCAAny methods


The SCAAny provides several miscellaneous methods that can be used to check if the SCAAny contains
any data or to flush its contents.
// Check if SCAAny is empty
If ( anyval.empty() ){
// SCAAny value is empty
}
// Flush the contents of the SCAAny which will now be empty
any.flush();
126 SCA Framework User’s Guide
Mapping for SCAAny

Special SCAAny methods for Dynamic Arrays


Two special methods, insertArray and extractArray, are also provided by the SCAAny. These are used
for the processing of dynamic arrays and are discussed in detail in the Dynamic SCA chapter of the
Advanced SDK manual.

Limitations in the SCAAny


The current mapping for SCAAny does not allow you to control the precise type code if an IDL typedef
definition is used. Consider the following IDL.

IDL
typedef SCAInt16 YearType;
typedef SCAInt16 MonthType;
The problem is that any of the types SCAInt16, YearType or MonthType can be used for insertion and
extraction into the same SCAAny. This is because C++ does not permit overloading on types that are
aliased to the same underlying type.
Chapter 5: IDL to C++ Language Mapping 127
Mapping for SCAResult

Mapping for SCAResult


The SCAResult type is used to return error information from calls to interface methods. It contains the
following information.
• Error code
• Message table ID
• Message number
• Message parameters

The values in a SCAResult instance can be used by the SCA Framework to format and dispatch
messages in the language appropriate for the current user. For more information on using SCAResult for
error processing see the Error Handling chapter of this manual.

SCAResult class definition


The SCAResult type is directly mapped to the C++ SCA::SCAResult class. It provides methods to
construct instances of the class, add parameters and interrogate it contents.
namespace SCA {
class SCA_EXPORT SCAResult
{
public:

// Constructors
SCAResult( SCAInt32 eid=0)
SCAResult( SCAInt32 eid, SCAInt32 msgTableId, SCAInt32 mid);
SCAResult( const SCAResult &sr )
~SCAResult();

// Add an error parameter to SCAResult


void addParam( SCAInt8 );
void addParam( SCAUInt8 );
void addParam( SCAInt16 );
void addParam( SCAUInt16 );
void addParam( SCAInt32 );
void addParam( SCAUInt32 );
void addParam( SCAInt64 );
void addParam( SCAUInt64 );
void addParam( SCAReal32 );
void addParam( SCAReal64 );
void addParam( SCAChar );
void addParam( SCAString );
void addParam( SCAWString );
void addParam( SCABool );

// Conversion operator which returns error code value


operator SCAInt32() const;

// Comparison operator
128 SCA Framework User’s Guide
Mapping for SCAResult

bool equals(const SCAResult& );

// Assignment operators
SCAResult & operator=( const SCAResult& );
SCAResult & operator=( const SCAInt32 eid );

// Return the information of error


SCAInt32 getTableID() const;
SCAInt32 getMessageID() const;
SCAInt32 getErrorCode() const;
SCAAnySequence getParams() const;
SCABool hasParams() const;
SCABool isOk() const;
SCABool isSystemError() const;

// Marshalling insertion and extraction operators


SCAMarshaller& operator >>= (SCAMarshaller& stream) const;
SCAMarshaller& operator <<= (SCAMarshaller& stream);
};
}
Two predefined SCAResult values are provided when you do not need to return more detailed
information to the caller.
namespace SCA {
const SCAResult SCASuccess(0);
const SCAResult SCAError(0XFFFFFFFF);
}
Examples of the usages of these are shown in the following sections.

Creating new SCAResult values


The following example creates SCAResult values with different levels of initialization.
// Create SCAResult with all zero values
SCA.SCAResult rstat = new SCA.SCAResult();
// Create SCAResult with only an error value
SCA.SCAResult rstat = new SCA.SCAResult(1);
// Create SCAResult with error, tableID and messageID
SCA.SCAResult rstat = new SCA.SCAResult(1,4,301);}

Resetting the error code in a SCAResult value


The error code in an existing SCAResult value can be reset using the normal assignment operator.
// Reset error code in SCAResult
rstat = 201;

Adding parameters to a SCAResult value


You use one of the overloaded addParam methods to add a parameter to a SCAResult value.
Chapter 5: IDL to C++ Language Mapping 129
Mapping for SCAResult

// Add parameters to SCAResult value


rstat.addParam(SCAInt8(1));
rstat.addParam(SCAInt16(12));
rstat.addParam(SCAInt32(123));
rstat.addParam(SCAInt64(1234));
rstat.addParam(SCAUInt8(2));
rstat.addParam(SCAUInt16(23));
rstat.addParam(SCAUInt32(234));
rstat.addParam(SCAUInt64(2345));
rstat.addParam(SCAReal32(12.34));
rstat.addParam(SCAReal64(123.456));
rstat.addParam('A');
rstat.addParam("TestString");
rstat.addParam(L"TestWideString");
rstat.addParam(true);

Interrogating the contents of a SCAResult


The is Ok method provides a simple way to test if the SCAResult value has an error.
// Test if SCAResult has a non-zero error
if ( !rstat.isOk() )
// Process error
The get methods can be used to extract the error, table and message values.
// Extract the error, tableID and messageID values
int error = rstat.getErrorCode();
int tableid = rstat.getTableID();
int messageid = rstat.getMessageID();
The hasParams and getParams methods can be used to determine if the SCAResult has parameters and
to process them. The parameter values are returned in a SCAAnySequence.
// If the SCAResult has parameters, print them
if ( rstat.hasParams() ) {
SCAAnySequence params = rstat.getParams();
for ( int i=0; i<params.size(); i++ ) {
SCA.SCAAny param = params.elementAt(i);
System.out.println("Param " + i + " = " + param.toString());
}
}

Miscellaneous SCAResult methods


The SCAResult also implements a dump method which allows you to print the raw contents.
// Print contents using the dump method
anyval.dump();
130 SCA Framework User’s Guide
Mapping for Constants

Mapping for Constants


IDL constants are mapped directly to C++ constant definitions.

IDL
const SCAString name1 = "testing1";
const SCAWString name1 = L"testing2";

C++
const SCA::SCAString name1 = "testing1";
const SCA::SCAWString name1 = L"testing2";
In certain situations, use of a constant in IDL might generate the constant’s value instead of the constant’s
name. This is shown in the following array definition which uses a constant definition for its size.

IDL
const SCAInt32 n = 10;
typedef SCAInt32 Vec[n];

C++
const SCAInt32 n = 10;
class Vec
{
public:
typedef SCAInt32 value_type;
typedef size_t size_type;
Vec() { }
size_type size() const { return 10; }
value_type& operator[](size_type idx) { return data[idx]; }
const value_type& operator[](size_type idx)const
{ return data[idx]; }
private:
value_type data[10];
};
Chapter 5: IDL to C++ Language Mapping 131
Mapping for Interfaces

Mapping for Interfaces


SCA interfaces are mapped to abstract C++ base classes that contain only pure virtual functions with no
implementation. The mapping for each interface will also contain a smart pointer definition that is used
by the client code to access the interface.
The following is a simple interface definition. This example is missing the definitions of all the required
types but they have no affect on actual interface mapping so they have been left out to simplify the
example.

IDL
#include "SCA/Service.idl"

module SCA { module Test {

interface SCAIReader : SCA::SCAIService


{
SCAVoid readModel( in SCAString name ) raises(ReaderException);
SCAINode getNode( in SCAInt32 id ) raises(ReaderException);
};

}; };
Each IDL defined interface will generate two different C++ definitions. Each of these definitions will be
put in a separate header file
• A smart pointer definition for the interface with the same name as the interface. In this example
the smart pointer name will be SCAIReader and it will be stored in a header file with the name
SCAIReaderSPtr.h.
• An abstract class with the name composed of the interface name followed by the string
Interface. In this example the name of the C++ class will be SCAIReaderInterface and it will
be stored in a header file with the name SCAIReader.h. This file will always include the file
containing the smart pointer definition so you do not need to explicitly include both.
Each of the generated header files is completely defined. This means they will include any required
header files to allow a successful compile whenever it is used.
The definitions are split between different header files because the smart pointer definition can act very
similar to the forward definition of a C++ class. When you do not need the detailed information about
the methods in an interface you can include the header file for the smart pointer, SCAIReaderSPtr.h,
instead of the header file with the full interface class definition, SCAIReader.h. This can result in a
substantial reduction in the size of the expanded source files because they do not need to include the
definitions of all the types that are used as parameters in the interface methods. The IDL compiler makes
extensive use of the behavior to keep down the size of the expanded skeleton files it generates. This
means that the generated header files for the full interface definition will only include the smart pointer
definitions for any other interfaces that appear only as parameter values.
There is a side effect when only including the smart pointer definition that needs to be understood. The
stub files for your implementation class will compile correctly as generated by the IDL compiler. But, as
132 SCA Framework User’s Guide
Mapping for Interfaces

soon as you add a call to a method on an interface that is passed in as a parameter, you may get a compiler
error. Unfortunately these errors tend to be very cryptic and difficult to understand because they are
related to template expansions. If you get one of these cryptic errors, just include the header file with the
full definition of the interface appearing in the error and it will usually fix the problem.
To illustrate this problem consider the following portion of a simple interface definition.
interface SCAITest1 : SCA::SCAIService
{
SCAVoid test1( in SCAITest2 inf );
};
The code for the test1 method in the generated implementation stub would look something like this. This
code will compile as generated with no errors.
SCA::SCAVoid TestService::test1(const SCAITest2 inf)
{
}
But if you then add a call to a method in the SCAITest2 interface a compilation error may occur.
SCA::SCAVoid TestService::test1(const SCAITest2 inf)
{
inf->test2();
}
To fix the error, just add an include statement for the SCAITest2.h header file.

Mapping for Interface Smart Pointer Definition


The generated code for the header file containing the definition of the smart pointer for the SCAIReader
interface is shown below.
// Definition of SmartPointer for SCAIReader

#ifndef SCA_TEST_SCAIREADERSPTR_H_INCLUDED
#define SCA_TEST_SCAIREADERSPTR_H_INCLUDED

namespace SCA { namespace Test {


struct SCAIReaderInterface;
typedef SCASmartPointer< SCAIReaderInterface > SCAIReader;
} }

namespace SCA {

template <>
const SCAString SCASmartPointer< SCAIReaderInterface >::getInfName()
{
static SCAString infName = "SCA.Test.SCAIReader";
return infName;
}

template <>
Chapter 5: IDL to C++ Language Mapping 133
Mapping for Interfaces

const SCAUUID& SCASmartPointer< SCAIReaderInterface >::getUUID(){


static SCAUUID uuid = {0x0d291f4bfd5331e3,0xa1fcefd01e371d1f};
return uuid;
}

#endif
The smart pointer definition contains the following pieces of information.
• The expansion of the SCASmartPointer template for the SCAIReaderInterface abstract class
which has the name SCAIReader. The smart pointer is used by the client to access the methods
in the interface.
• A template specialization of the getInfName method of the SCASmartPointer class which
contains the name of the interface.
• A template specialization of the getUUID method of the SCASmartPointer class which
contains the UUID value for the interface.

Mapping for Interface Abstract Base Class Definition


The generated code for the header file containing the full definition of the SCAIReaderInterface
abstract base class is shown below.
#ifndef SCA_TEST_SCAIREADER_H_INCLUDED
#define SCA_TEST_SCAIREADER_H_INCLUDED

#include "SCAIReaderSPtr.h"
#include "FileReaderTypes.h"
#include "SCAINodeSPtr.h"

// Definition of Interface SCAIReader

namespace SCA { namespace Test {

struct SCAIReaderInterface : public SCAIServiceInterface


{
virtual SCAVoid readModel(const SCAString name) = 0;
virtual SCAINode getNode(const SCAInt32 id) = 0;
};

} }

#endif

Mapping for Interface Operations


Each interface operation maps to a C++ member function with the same name as the operation.
134 SCA Framework User’s Guide
Mapping for Interfaces

Mapping Interface Operation Parameters


The following table shows details on how each IDL type is passed when it is use as an in, out or inout
parameter in an interface method or as a return value from a method.

Type in inout out return


SCAInt8 const SCAInt8 SCAInt8& SCAInt8& SCAInt8
SCAInt16 const SCAInt16 SCAInt16& SCAInt16& SCAInt16
SCAInt32 const SCAInt32 SCAInt32& SCAInt32& SCAInt32
SCAInt64 const SCAInt64 SCAInt64& SCAInt64& SCAInt64
SCAUInt8 const SCAUInt8 SCAUInt8& SCAUInt8& SCAUInt8
SCAUInt16 const SCAUInt16 SCAUInt16& SCAUInt16& SCAUInt16
SCAUInt32 const SCAUInt32 SCAUInt32& SCAUInt32& SCAUInt32
SCAUInt64 const SCAUInt64 SCAUInt64& SCAUInt64& SCAUInt64
SCAReal32 const SCAReal32 SCAReal32& SCAReal32& SCAReal32
SCAReal64 const SCAReal64 SCAReal64& SCAReal64& SCAReal64
SCAChar const SCAChar SCAChar& SCAChar& SCAChar
SCAWChar const SCAWChar SCAWChar& SCAWChar& SCAWChar
SCABool const SCABool SCABool& SCABool& SCABool
SCAResult const SCAResult& SCAResult& SCAResult& SCAResult
enum const enum enum& eum& eum
interface interface& interface& interface& interface
struct const struct& struct& struct& struct
SCAString const SCAString SCAString& SCAString& SCAString
SCAWString const SCAWString SCAWString& SCAWString& SCAWString
SCASequence const sequence& sequence& sequence& sequence
array const array& array& array& array
SCAAny const SCAAny& SCAAny& SCAAny& SCAAny
SCATypeCode const SCATypeCode& SCATypeCode& SCATypeCode& SCATypeCode
Chapter 5: IDL to C++ Language Mapping 135
Mapping for Interfaces

Using Smart Pointers


In the SCA Framework, all access to interfaces is through smart pointers generated by the SCA IDL
compiler. The smart pointers are used to automatically manage the lifecycle control of the objects that
implement the interfaces.
A smart pointer is a C++ class that implements all the required methods and operator overloads to allow
it to behave like a normal C pointer. Since the smart pointer is really a class object, it can act as an
intelligent pointer to objects and hide the complications of dealing with the objects they point to. Some
of the functionality that the SCA smart pointers provide is as follows.
• Every time a smart pointer is created, destroyed, copied or assigned to another smart point, the
appropriate reference counting calls are made to automatically manage the lifecycle of the
objects pointed to.
• Navigating or switching between interfaces implemented by the same service object can be
made using standard C++ assignment or casting operators instead of requiring special
framework calls.
• Allows you to determine if two different interface references point to the same underlying
implementation object using standard C++ comparison tests.
The following shows some examples of how using smart pointers simplify the handling of interfaces.
Declarations of smart pointer instances are the same as instances of any C++ class. Note that no * is used
as would be the case with a normal C pointer.
SCAITest1 spTest1;
SCAITest2 spTest2;
The conversion of one smart pointer type to another smart point type is also referred to as interface
navigation. With smart pointers, the syntax for interface navigation is the same as normal C++ casts or
conversions.
try {
spTest2 = static_cast<SCAITest2>(spTest1);
spTest2 = (SCAITest2)spTest1;
spTest2 = spTest1;
} catch(SCAIException ex) {
cout << “Interface cast failed = “ << e.what() << endl;
}
It is important to remember that you can only navigate from one interface to another interface if the
underlying implementation object supports both interfaces. If the underlying object does not implement
the interface that you wish to navigate to, a SCAException will be thrown. As a result you should always
include interface casts in a try/catch block to catch any errors.
The smart pointer implementation provides a number of different operator overloads that can be used.
Two smart pointers are defined to be equal if they point to the same underlying implementation object.
The normal C++ equality operators can be used for this test. Less then and greater then operators have
no meaning and are not defined.
if ( spTest1 == spTest2 ) ...;
136 SCA Framework User’s Guide
Mapping for Interfaces

if ( spTest1 != spTest2 ) ...;


The C++ pointer-to-member operator is used to make a call to a method in the interface.
spTest1->doSomething();
A special value, SCA::NULLSP, is provided which is a used to represent a null interface pointer. The
use of the normal C++ NULL value or a 0 value will not work and will generate a compilation error. The
following shows how a smart pointer instance can be reset. If the instance currently contains a pointer to
an implementation object, then the reference count on that object will be decremented before the pointer
is set to null.
spTest1 = NULLSP;
The NULLSP value can also be used to test for an unassigned smart pointer or you can just test its value.
if ( spTest1 == NULLSP ) ...;
if ( spTest1 != NULLSP ) ...;
if ( !spTest1 ) ...;
if ( spTest1 ) ...;
Several methods are provided which allow you to interrogate information about the contents of the smart
pointer.
// Get the name of the interface the smart pointer is for
cout << “Interface name is “ << spTest1.getInfName() << endl;

// Get the UUID for the interface the smart pointer is for
SCAUUID uuid = spTest1.getUUID();

// Get the raw pointer that is held by the smart pointer


void* ptr = spTest1.getInfPtr();
Chapter 5: IDL to C++ Language Mapping 137
Mapping for Exceptions

Mapping for Exceptions


The SCA Framework predefines three exception types, SCA::SCAException,
SCA::SCAUserException and SCA::SCASystemException. All user defined exceptions in IDL must
inherit either SCA::SCAUserException or another user-defined exception. Only single inheritance is
allowed.

SCAException class
The base for all IDL defined exceptions is SCA::SCAException. It is mapped to the following C++
class. Only those methods intended for external use have been shown here. Other methods required by
the framework to manage exceptions and marshal them between different languages have not been
shown.
namespace SCA {
struct SCA_EXPORT SCAException
{
//Constructors and destructors
SCAException(SCABool deleteOnThrow=false);
SCAException(const SCAException &copy);
virtual ~SCAException() throw();

//Method to print out description of exception


SCAString what() const throw();

//Method to get SCATypeCode for this exception


virtual SCATypeCode getTypeCode() const throw();

//Method to get raw text string for this exception


SCAString getText() const throw();

//Method to set raw text string for this exception


SCAVoid setText(const SCAString text) throw();

//Creates an SCAException object


static SCAException* create();

//Throws this exception


virtual void throwit();

//Optional exception description


SCAString m_text;
};
}

SCAUserException class
The SCA::SCAUserException class adds no new data or method. It is provided as a base for all user
defined exceptions.
138 SCA Framework User’s Guide
Mapping for Exceptions

namespace SCA {
struct SCA_EXPORT SCAUserException: public SCAException
{
//Constructors and destructors
SCAUserException(SCABool deleteOnThrow=false);
SCAUserException(SCAString text, SCABool deleteOnThrow=false);
virtual ~SCAUserException() throw();

//Method to get SCATypeCode for this exception


virtual SCATypeCode getTypeCode() const throw();

//Creates an SCAUserException object


static SCAException* create();

//Throws this exception


virtual void throwit();
};
}

SCASystemException class
The SCA::SCASystemException class should only be used internally by the SCA Framework. It adds
an error ID to the base SCAException.
namespace SCA {
struct SCA_EXPORT SCASystemException: public SCAException
{
//Constructors and destructors
SCASystemException(SCABool deleteOnThrow=false);
SCASystemException(SCAInt32 id, SCAString text,
SCABool deleteOnThrow=false);
virtual ~SCASystemException() throw();

//Method to get SCATypeCode for this exception


virtual SCATypeCode getTypeCode() const throw();

//Creates an SCASystemException object


static SCAException* create();

//Throws this exception


virtual void throwit();

//System exception ID
SCAInt32 id;
};
}

Mapping for IDL defined user exceptions


All exceptions defined in IDL should inherit either directly or indirectly from the SCAUserException
type.
Chapter 5: IDL to C++ Language Mapping 139
Mapping for Exceptions

IDL
exception ReaderException : SCAUserException
{
SCAString name;
SCAString error;
};

C++

struct ReaderException : public SCAUserException


{
ReaderException(SCABool deleteOnThrow=false) :
SCAUserException(deleteOnThrow) {}
virtual ~ReaderException() throw() {}
static SCAException* create() {
return new ReaderException(true);
}
virtual void throwit() {
if ( m_deleteOnThrow ) {
ReaderException exc = *this;
delete this;
exc.setThrow();
throw exc;
} else {
this->setThrow();
throw *this;
}
}
virtual SCATypeCode getTypeCode() const throw() {
return getCachedTypeCode("SCA.FileReader.ReaderException");
}
SCAString name;
SCAString error;
};

Special Rules for using SCA Exceptions in C++


The using of SCA exceptions in the C++ language is the same as normal C++ exception usage with one
exception. You should not use the normal C++ throw statement to throw SCA exceptions. Instead you
should use the throwit method provided in the base SCAException class. The following code shows how
this should be done.
ReaderException ex;
ex.name = “TestInput.dat”;
ex.error = “The file does not exist”;
ex.throwit();
To understand why this is important, consider the following simple example which loads a service and
calls a method which throws an exception.
try {
SCAIReader spReader = getSCAService("SCA.Test.FileReader");
140 SCA Framework User’s Guide
Mapping for Exceptions

SCAINode spNode = spReader->getNode(123);


} catch (SCAException& e) {
cout << "Exception: " << e.what() << endl;
}
In this example, if the getNode method throws an exception there is a potential problem. Notice that the
getSCAService call to load the service and the only references to it, spReader and spNode, are all inside
the try block. This means that when the method throws an exception, and the execution flow leaves the
try block to enter the catch block, the destructors for the smart pointers spReader and spNode will be
called. Since these are the only references to the service, the shared library for the service may be
unloaded by the SCA Kernel at this point. This is a problem because the code in the catch block requires
access to the implementation of the exception object which would be no longer available. This can trigger
a crash in the catch block. To keep this from happening you should always throw the exception using the
throwit method. This will trigger some additional logic in the SCA Kernel that will insure that no shared
libraries are unloaded until all of the SCA exception objects that have been thrown have been deleted.
For a complete discussion of how exceptions are used in the SCA Framework see the Error Processing
chapter of this manual.
Chapter 5: IDL to C++ Language Mapping 141
Mapping for SCA Services

Mapping for SCA Services


Two types of code are generated for SCA service definitions.
1. The genskeleton command is used to generate the initial implementation skeletons for a service.
The generated skeletons can then be expanded with the code required to implement the desired
behavior for the various interface operations.
2. During the build process, various C++ base, tie and factory classes are generated by the IDL
compiler. This code is used to link the developer generated implementation code to the SCA
Framework. This is done to reduce as much as possible the amount of code that must be written
by the developer to implement a service. This support code also provides a level of isolation
between the service’s implementation code and the SCA Framework. This allows for future
changes to be made in the interaction between the base or tie classes and the SCA Framework
without affecting the developer’s implementation code. The low level details of this support code
will not be discussed in this section. The only things about the support code that will be shown
are the methods that it exposes for use by the component developer.
The following is the IDL for an example interface definition that will be used in this section.

#ifndef SCA_FILEREADER_FILEREADER_IDL_INCLUDED
#define SCA_FILEREADER_FILEREADER_IDL_INCLUDED

#include "SCA/Service.idl"

module SCA { module FileReader {

struct Node
{
SCAInt32 id;
SCAReal32 x;
SCAReal32 y;
SCAReal32 z;
};

exception ReaderException : SCAUserException


{
SCAString name;
SCAString error;
};

interface SCAINode;

interface SCAIReader : SCA::SCAIService


{
SCAVoid readModel( in SCAString name ) raises(ReaderException);
SCAINode getNode( in SCAInt32 id ) raises(ReaderException);
};

interface SCAINode : SCA::SCAIService


{
142 SCA Framework User’s Guide
Mapping for SCA Services

SCAInt32 getID();
SCAReal32 getX();
SCAReal32 getY();
SCAReal32 getZ();
};

}; };

#endif
The following is the SDL for an example service that will implement these interfaces.

#ifndef FILEREADER_SDL_INCLUDED
#define FILEREADER_SDL_INCLUDED

#include "SCA/FileReader/FileReader.idl"

module SCA { module FileReader { module Impl {

service SCA.Test.FileReader {
interface SCA::SCAIReader;
subservice NodeImpl ( in SCA::Node node ) {
interface SCA::SCAINode;
};
};

}; }; };

#endif

The inheritance form of implementation


The C++ mapping for SCA services supports two styles of implementation. The default code generated
will use an implementation form where the implementation classes generated by genskeleton will inherit
from base classes that the IDL compiler will generate at build time. These base classes then inherit from
the interface classes and also provide all the necessary links to the SCA Framework.
When the genskeleton command is run on the above SDL file to generate the skeleton code for the
service, it will generate two C++ classes, FileReader which implements the SCAIReader interface and
NodeImpl which implements the SCAINode interface. The FileReader class is referred to as the top-
level class for the service because it has the same name as the service. A service implemented in C++
will always have a top-level class. The NodeImpl class is referred to as a subservice class because it is
defined using the subservice construct in the SDL definition for the service. Subservice classes are
optional and will only be generated if requested in the SDL.

Implementation for top-level class


The following is the header file FileReader.h that is generated for the top-level service class.
Chapter 5: IDL to C++ Language Mapping 143
Mapping for SCA Services

#ifndef SCA_FILEREADER_IMPL_FILEREADER_H_INCLUDED
#define SCA_FILEREADER_IMPL_FILEREADER_H_INCLUDED

#include "FileReaderBase.h"

namespace SCA { namespace FileReader { namespace Impl {

class FileReader : public FileReaderBase


{
public:

// Constructor and Destructor


FileReader(SCAIFileReaderFactoryAccess* factoryAccess);
virtual ~FileReader();

// Methods for interface SCA.FileReader.SCAIReader


virtual SCAVoid readModel(const SCAString name);
virtual SCAINode getNode(const SCAInt32 id);
};

} } }

#endif
The following is the implementation file FileReader.cpp that is generated.
#include "FileReader.h"

namespace SCA { namespace FileReader { namespace Impl {

// Constructor
FileReader::FileReader(SCAIFileReaderFactoryAccess* factoryAccess)
: FileReaderBase(factoryAccess)
{
}

// Destructor
FileReader::~FileReader()
{
}

SCAVoid FileReader::readModel(const SCAString name)


{
}

SCAINode FileReader::getNode(const SCAInt32 id)


{
}

} } }
The C++ implementation will be put in a namespace that is defined by the SDL module statements. In
this example it will be SCA::FileReader::Impl.
144 SCA Framework User’s Guide
Mapping for SCA Services

The implementation classes generated are fairly simple, but there are a couple of requirements for these
that are imposed by the SCA Framework. These are the requirements when using the default or
inheritance form of implementation.
• The class must inherit from the base class generated by the IDL compiler. The name of the base
class will be xxxBase where xxx is the name of the service class.
• The class can have only one constructor and it must have a single argument of
SCAIxxxFactoryAccess* where xxx is the name of the top-level service class. This pointer is
used by the base class to access the SCA Framework.
• The base class constructor must be explicitly called from the class constructor.
• The class must implement each of the operations defined in the interfaces it supports and any
interfaces that inherit from them. The exception to this rule is the methods in the SCAIService
interface do not need to be implemented.
As long as these requirements are followed, the developer is free to make any desired modifications to
these implementation classes.
The base class, FileReaderBase, generated by the IDL compiler during the build process, does the
following.
• Inherits from the abstract base class for each interface implemented by the service object. In this
example it will be the SCAIReaderInterface class.
• Provides the implementation for all of the required reference counting, interface navigation and
introspection methods in the SCAIService interface that every SCA service must implement.
• Provides complete access to the SCA Framework facilities through the service access interface.
• Provides helper functions for creating new instances of subservice objects using any
initialization parameters defined in the SDL through the service access interface.
If the FileReader service used in this example implemented additional interfaces, the only changes to
the generated code would be the addition of the method definitions for the operations in the new
interfaces.
Implementation for subservice class
The SDL for the FileReader service also includes the definition of a subservice NodeImpl which takes
a Node constructor argument. A separate C++ class, NodeImpl, will be generated for the subservice
class. The format of this class is identical to the FileReader class except for the addition of an extra
argument on the class constructor and the interface methods it implements. The following is the header
file generated for this class.
#ifndef SCA_FILEREADER_IMPL_NODEIMPL_H_INCLUDED
#define SCA_FILEREADER_IMPL_NODEIMPL_H_INCLUDED

#include "NodeImplBase.h"

namespace SCA { namespace FileReader { namespace Impl {

class NodeImpl : public NodeImplBase


Chapter 5: IDL to C++ Language Mapping 145
Mapping for SCA Services

{
public:

// Constructor and Destructor


NodeImpl(SCAIFileReaderFactoryAccess* factoryAccess,
const Node& node);
virtual ~NodeImpl();

// Methods for interface SCA.FileReader.SCAINode


virtual SCAInt32 getID();
virtual SCAReal32 getX();
virtual SCAReal32 getY();
virtual SCAReal32 getZ();
};

} } }

#endif
Subservice classes have the same requirements imposed by the SCA Framework as top-level classes
except the restrictions on its constructor are relaxed. Subservice classes may still only have one
constructor defined but it is possible for it to have additional user defined arguments.
Only subservice classes can have user defined constructor arguments. This is because instances of the
top-level FileReader class are instantiated by the IDL generated factory class in response to getService
calls made by the clients of the service. There is currently no way for clients to passes constructor
arguments through the getService call. On the other hand, instances of subservice objects can only be
generated by the implementation code in the service. In this case the implementation is free to pass any
desired arguments to the constructors. It is even possible to pass argument types that are not supported in
IDL by using the SCAVoidPtr IDL type in the SDL definition.

The ServiceAccess interface


In addition to the supporting base classes, the IDL compiler will always generate a unique ServiceAccess
interface for each service. This interface is the link between the implementation of the service and the
SCA Framework. The name of this interface will always be SCAIxxxServiceAccess where xxx is the
name of the top-level service class. The following is the generated interface for the FileReader service.
#ifndef SCA_FILEREADER_IMPL_SCAIFILEREADERSERVICEACCESS_H_INCLUDED
#define SCA_FILEREADER_IMPL_SCAIFILEREADERSERVICEACCESS_H_INCLUDED

#include "SCA/SCAIServiceAccess.h"
#include "FileReaderTypes.h"

namespace SCA { namespace FileReader { namespace Impl {

SCAINTERFACE SCAIFileReaderServiceAccess : public SCAIServiceAccess


{
// Ask the Service Manager for a service instance
virtual SCAIService getService(const SCAString name,
const SCAString attributes="");
146 SCA Framework User’s Guide
Mapping for SCA Services

virtual SCAIService getService(const SCAString name,


const SCAString attributes,
SCAResult& rstatus);
virtual SCAIService getService(const SCAString name,
SCAResult& rstatus);

// Get system interfaces


virtual SCAIServiceProvider getSCAIServiceProvider();
virtual SCAIServicePublisher getSCAIServicePublisher();
virtual SCAIServiceFactory getSCAIServiceFactory();

// Get a subservice object


virtual SCAIService getNodeImpl(const Node& node);
};

} } }

#endif
The ServiceAccess interface is made available to the implementation classes using the m_serviceAccess
variable defined in the base class.
The ServiceAccess interface provides three overloaded getService methods that should be used by the
implementation code if it needs to load other SCA services. Here is an example of using these.
SCAIService spSvc;
SCAResult rStat;

spSvc = m_serviceAccess->getService(“Test.Service.Name”);

spSvc = m_serviceAccess->getService(“Test.Service.Name”,rStat)
if ( rStat ) return rStat;
For each subservice class defined in the SDL, the ServiceAccess interface will also include a helper
method that can be used to create instances of it. The arguments to the method will match the constructor
arguments specified in the SDL for the class. These simplify the task of creating subservice object
instances because the implementation code does not need to worry about the Factory Access interface
that is always required as a constructor argument. The name of each helper method will be getXxx where
Xxx is the name of the subservice class. The following shows how we can use this helper method in a
sample implementation of the getNode method in the SCAIReader interface. This interface is
implemented by the FileReader class.
SCAINode FileReader::getNode(const SCAInt32 id)
{
// Find and initialize the node with the requested ID
Node node = …

// Return a new subservice object for this node


SCAINode spNode = m_serviceAccess->getNodeImpl(node);
return spNode;
}
Chapter 5: IDL to C++ Language Mapping 147
Mapping for SCA Services

The delegation form of implementation


There may be situations where the inheritance form of implementation is inconvenient because of other
requirements in your classes. An example of this is if you wish to use a base class to provide the
implementation for some of the interface methods. The C++ compiler will not allow the implementation
of method in one branch of the inheritance tree to satisfy a pure virtual method in another branch of the
inheritance tree. To resolve this, the delegation form of implementation can be used. With delegation, the
skeleton classes generated by the IDL compiler do not inherit from a base or interface classes. Instead
the base class is replaced with a separate tie class which inherits from the interface class and provides all
the necessary links to the SCA Framework. When a new instance of the service is requested, an instance
of the tie class is constructed and returned. The tie class will internally construct a separate instance of
your implementation class when it is initialized. Interface calls to the methods in the tie class are then
delegated to the methods in the implementation class that it wraps.
You use the delegate keyword in the SDL file to select the delegation form of implementation. The
following is the header file FileReader.h that is generated for the top-level service class when delegation
is used. The lines in a darker shade of gray are the lines that are different from the format of this header
when the inheritance form of implementation is used.
#ifndef SCA_FILEREADER_IMPL_FILEREADER_H_INCLUDED
#define SCA_FILEREADER_IMPL_FILEREADER_H_INCLUDED

#include "SCA/Framework/Scripting/SCAITypeProvider.h"
#include "SCA/FileReader/SCAIReader.h"
#include "SCAIFileReaderServiceAccess.h"

namespace SCA { namespace FileReader { namespace Impl {

class FileReader
{
public:

// Constructor and Destructor


FileReader(SCAIFileReaderServiceAccess* serviceAccess);
virtual ~FileReader();

// Methods for interface SCA.FileReader.SCAIReader


SCAVoid readModel(const SCAString name);
SCAINode getNode(const SCAInt32 id);

private:
SCAIFileReaderServiceAccess* m_serviceAccess;
};

} } }

#endif
148 SCA Framework User’s Guide
Mapping for SCA Services

Notice that class no longer inherits from a base class and as a result the interface methods are no longer
declared virtual. Because there is no requirement that the implementation inherit from an IDL generated
base class, you are free to use any inheritance structure you require. Also note that the m_serviceAccess
variable must now be a member of the implementation class because there is no longer a base class for it
to reside in.
The following is the implementation file FileReader.cpp that is generated for the delegation form of
implementation.

#include "FileReader.h"

namespace SCA { namespace FileReader { namespace Impl {

// Constructor
FileReader::FileReader(SCAIFileReaderServiceAccess* serviceAccess)
{
m_serviceAccess = serviceAccess;
}

// Destructor
FileReader::~FileReader()
{
}

SCAVoid FileReader::readModel(const SCAString name)


{
}

SCAINode FileReader::getNode(const SCAInt32 id)


{
}

} } }

Singleton Services
It is also possible to indicate that the service is a singleton in the SDL. The use of this keyword has no
affect on any of the C++ implementation skeletons generated for a service. The processing of singleton
services is handled entirely in the factory support code that is generated when the service is built. It is
important to remember that even so the generated skeletons are the same; the implementation code for a
singleton service may need to be different. Because multiple clients may be sharing the same instance of
the service, the code needs to make sure this is done in a safe manner.
Chapter 5: IDL to C++ Language Mapping 149
Mapping for SCA Services

Aggregation
The C++ mapping also supports the aggregates and aggregated keywords in the SDL. The affect of these
on the mapping for service objects is an advanced topic that is covered later in this manual.
150 SCA Framework User’s Guide
Mapping for SCA Components

Mapping for SCA Components


The C++ mapping uses a normal shared library for SCA components. The only code required for SCA
components is support code generated by the IDL compiler during the build process. This code is used
by the SCA Framework to initialize the component and expose the services it provides when the
component is loaded at runtime. There is no code that the developer needs to create for a component.

Embedded Components
The C++ mapping supports the embedded option in the CDL. When this option is specified, the build
system compiles the source for the component in normal fashion but it will not link the object files into
a separate shared library. Instead you are allowed to include the generated object files where ever you
would like in the application. Also since the SCA framework will no longer be loading the share library,
a different initialization scheme is required. See section on embedded components in the Advanced SDK
manual for complete details.
Chapter 6: IDL to Java Language Mapping
SCA Framework User’s Guide

6 IDL to Java Language Mapping



Introduction 152
 Mapping for Identifiers 154

Mapping for Modules 155

Mapping for Basic Types 156
 Mapping for Unsigned Data Types 157

Mapping for String Types 158

Mapping for Enumerated Types 159
 Mapping for Structures 160

Mapping for Arrays 161

Mapping for Sequences 164
 Mapping for Type Aliases 166

Mapping for SCATypeCode 167

Mapping for SCAAny 168
 Mapping for SCAResult 173
 Mapping for Constants 177

Mapping for Interfaces 178
 Mapping for Exceptions 180
 Mapping for SCA Services 184

Mapping for SCA Components 189
 SCA Framework / JVM Interaction 190
152 SCA Framework User’s Guide
Introduction

Introduction
The IDL language provides a language independent definition of SCA interfaces and data types. In order
to actually use these definitions, there must be a set of rules, commonly known as a mapping that
describes how these types are represented in a particular language. This chapter explains the mapping
that SCA uses for the Java language.
The following table summarizes the data type mapping between IDL and Java types. The following
sections of this chapter will provided the details on each mapping.

IDL Type Java Type


SCA::SCAInt8 byte
SCA::SCAUInt8 short
SCA::SCAInt16 short
SCA::SCAUInt16 int
SCA::SCAInt32 int
SCA::SCAUInt32 long
SCA::SCAInt64 long
SCA::SCAUInt64 long
SCA::SCAReal32 float
SCA::SCAReal64 double
SCA::SCAChar char
SCA::SCAWChar char
SCA::SCAString java.lang.String
SCA::SCAWString java.lang.String
SCA::SCABool boolean
SCA::SCAAny SCA.SCAAny
SCA::SCATypeCode SCA.SCATypeCode
SCA::SCAVoid void
SCA::SCAResult SCA.SCAResult
sequence class (extends java.util.Vector)
enum enum
struct class
array [] or class (that wraps [])
const interface.value
Chapter 6: IDL to Java Language Mapping 153
Introduction

IDL Type Java Type


interface interface
exception class (extends SCA.SCAException)

For every type defined in IDL, the IDL compiler will generate the code required to expose the proper
Java definition of the type. In addition to the actual Java definition of the type, there is also some support
code generated for each interface which is used by SCA Framework to make interface calls from Java to
services implemented in the other supported languages.
When building a Java application or component, the SCA SCons build system will compile the Java
definitions for all of the known IDL types and store them in a single jar file APPS/lib/java/IDLTypes.jar.
See the section on the SCA Kernel interactions with the JVM later in this chapter for more details on this.
154 SCA Framework User’s Guide
Mapping for Identifiers

Mapping for Identifiers


IDL identifiers are mapped to Java with no change. For example:

IDL
enum Color { RED, GREEN, BLUE };

Java
public enum Color { RED, GREEN, BLUE }
There is one potential problem to be aware of. If the IDL file contains an identifier that is also a Java
reserved keyword, then the resulting Java code will not compile. Therefore, the use of Java reserved
words for identifiers is not allowed.
Chapter 6: IDL to Java Language Mapping 155
Mapping for Modules

Mapping for Modules


IDL defined types are created in Java packages with the same name as the fully qualified IDL name
scope.

IDL
module SCA {
module FileReader {
// definitions
};
};

Java
package SCA.FileReader;
// definitions
The IDL module constructs also affect other aspects of the SCA mapping. See the IDL Compiler chapter
for detailed information on how the IDL module statements are used.
156 SCA Framework User’s Guide
Mapping for Basic Types

Mapping for Basic Types


Basic data types, SCAInt8, SCAInt16, SCAInt32, SCAInt64, SCAReal32, SCAReal64 and SCABool
are directly mapped to Java primitives with no potential for data loss. The SCAChar is mapped to the
Java char. This can cause issues because the Java char contains multi-byte Unicode characters while the
IDL definition of a SCAChar only accommodates the single-byte ISO Latin-1 character set. When
passing SCAChar data from Java to a different language, the high byte will be discarded.
The following table shows the Java mapping for the basis SCA types.

SCA IDL Type Java Type


SCAInt8 byte
SCAInt16 short
SCAInt32 int
SCAInt64 long
SCAReal32 float
SCAReal64 double
SCAChar char
SCAWChar char
SCABool boolean

The following structure definition illustrates this mapping.

IDL:
struct Node
{
SCAInt32 id;
SCAReal32 x;
SCAReal32 y;
SCAReal32 z;
};

Java:
public class Node
{
public int id;
public float x;
public float y;
public float z;
}
Chapter 6: IDL to Java Language Mapping 157
Mapping for Unsigned Data Types

Mapping for Unsigned Data Types


Since Java does not provide unsigned data types, the IDL unsigned integers are mapped to larger Java
integers to preserve their values. For example, SCAUInt8 is mapped to Java short (16-bit). The
exception is that SCAUInt64 is also mapped to long (64-bit).

SCA IDL Type Java Type


SCAUInt8 short
SCAUInt16 int
SCAUInt32 long
SCAUInt64 long

The following example illustrates this mapping.

IDL
struct Time
{
SCAUInt8 hour;
SCAUInt8 minute;
SCAUInt8 second;
};

Java
public class Time
{
public short hour;
public short minute;
public short second;
}
Because of the mapping of IDL unsigned data to Java signed data, care must be taken when dealing with
the unsigned SCA data types in the Java code.
• When calling an interface method implemented in a non-Java service, the Java number may be
truncated if its value is out of the supported range for the IDL type.
• When calling an interface method implemented in a non-Java service and the Java value is
negative, the converted IDL unsigned value will be a large positive value.
• If a non-Java client passes a large SCAUint64 value to an interface implemented in Java and its
value does not fit in a Java long, then the convert Java value will be a very large negative value.
158 SCA Framework User’s Guide
Mapping for String Types

Mapping for String Types


Both SCAString and SCAWString are mapped to java.lang.String. Converting from a SCAString or
SCAWString to a Java value will not lose any information. When converting from a Java value to a
SCAString, the Java value is first converted to Unicode UTF8 value which is then stored in the
SCAString.

IDL:
struct address
{
SCAString street;
SCAString city;
SCAInt32 zipcode;
};

Java:
public class address
{
public String street;
public String city;
public int zipcode;
}
Chapter 6: IDL to Java Language Mapping 159
Mapping for Enumerated Types

Mapping for Enumerated Types


An IDL enum is directly mapped to Java enum.

IDL
enum Colors{
RED, GREEN, BLUE
};

Java
public enum Colors
{
RED, GREEN, BLUE
}
160 SCA Framework User’s Guide
Mapping for Structures

Mapping for Structures


An IDL structure maps to a Java class with all public fields. Each IDL structure member is mapped to a
corresponding member of the Java structure. The Java structure members appear in the same order as the
corresponding IDL structure members. For example:

IDL
struct Node
{
SCAInt32 id;
SCAReal32 x;
SCAReal32 y;
SCAReal32 z;
};

Java
public class Node
{
public int id;
public float x;
public float y;
public float z;
}
Chapter 6: IDL to Java Language Mapping 161
Mapping for Arrays

Mapping for Arrays


Two types of array definitions are supported in IDL. Fixed size arrays must have their size defined in the
IDL and can never change. Dynamic arrays allow you to delay the specification of the array size until it
is actually allocated. Only arrays of rank 1 or 2 are supported.

Fixed size arrays


In Java, arrays are mapped to a Java class of the same name which wraps a Java array. The class provides
a setElementAt and elementAt method, like Java’s java.util.Vector, for setting and accessing the members
of the array. The following is an example of a one dimensional array.

IDL
typedef SCAInt32 Date[3];

Java
public class Date
{
public Date(){
data=new int[size];
}
public void setElementAt(int e, int index){
data[index]=e;
}
public int elementAt(int index){
return data[index];
}
public int[] getArray(){
return data;
}
public static final int size=3;
private int[] data;
}
The following example shows how the array can be used.
// Set the values of the array
Date dateVal = new Date();
dateVal.setElementAt(8,0);
dateVal.setElementAt(10,1);
dateVal.setElementAt(2009,2);
System.out.println("Data is " + dateVal.elementAt(0) + "/" +
dateVal.elementAt(1) + "/" + dateVal.elementAt(2));
The class also provided a getArray method that allows you to extract a reference to the wrapped Java
array which can then be used to
// Access wrapped Java array directly
int[] dateArray = dateVal.getArray();
System.out.println("Data is " + dateArray[0] + "/" +
dateArray[1] + "/" + dateArray[2]);
162 SCA Framework User’s Guide
Mapping for Arrays

dateArray[0] = 12;
System.out.println("Modified data is " + dateArray[0] + "/" +
dateArray[1] + "/" + dateArray[2]);
Two dimensional IDL arrays are handled in a similar manner.

IDL
typedef SCA::SCAInt64 Matrix[5][5];

Java
public class Matrix
{
public Matrix(){
data=new long[size1][size2];
}
public void setElementAt(long e, int index1, int index2){
data[index1][index2]=e;
}
public long elementAt(int index1, int index2){
return data[index1][index2];
}
public long[][] getArray(){
return data;
}
public long[] getRow(int index1){
return data[index1];
}
private long[][] data;
public static final int size1=5;
public static final int size2=5;
}
If an IDL array appears as a member of a structure, it is mapped directly to the member of the Java defined
structure.

IDL
struct Node2
{
SCAInt32 id;
SCAReal32 location[3];
};

Java
public class Node2
{
public int id;
public final float[] location= new float[3];
}
Chapter 6: IDL to Java Language Mapping 163
Mapping for Arrays

Dynamic Arrays
Dynamic Arrays are mapped to Java classes which are very similar to fixed size arrays except they take
in the size of the array as an argument of the constructor. Dynamic Arrays cannot be declared inside
structures and they are not a substitute for a java.util.Vector since they do not allow resizing of the array
at runtime. Dynamic arrays exist primarily to provide more optimized code in other languages supported
by the SCA framework.

IDL
typedef Node NodeArray[];

Java
public class NodeArray
{
public NodeArray(int s1){
size=s1;
data=new Node[size];
}
public void setElementAt(Node e, int index){
data[index]=e;
}
public Node elementAt(int index){
return data[index];
}
public Node[] getArray(){
return data;
}
public final int size;
private final Node[] data;
}
Two dimensional dynamic arrays are handled in a similar manner.
164 SCA Framework User’s Guide
Mapping for Sequences

Mapping for Sequences


An IDL sequence is mapped to a Java class that inherits from java.util.Vector.

IDL
typedef SCASequence<Node> NodeSequence;

Java
public class NodeSequence extends java.util.Vector<Node>
{
public NodeSequence(){
super();
}
public NodeSequence(int initialCapacity){
super(initialCapacity);
}
public NodeSequence(int initialCapacity, int capacityIncrement){
super(initialCapacity, capacityIncrement);
}
}
When an IDL sequence appears as a member of a structure, a Java class for the sequence is defined inside
the Java class for the structure and it is used for the structure member.

IDL
struct Node3
{
SCAInt32 id;
SCASequence<SCAReal32> location;
};

Java
public class Node3
{
public static class Internal_location_1 extends
java.util.Vector<Float>
{
public Internal_location_1(){
super();
}
public Internal_location_1(int initialCapacity){
super(initialCapacity);
}
public Internal_location_1(int initialCapacity,
int capacityIncrement){
super(initialCapacity, capacityIncrement);
}
}
public int id;
public Node3.Internal_location_1 location;
}
Chapter 6: IDL to Java Language Mapping 165
Mapping for Sequences

Since generated sequence classes inherit from java.util.Vector, they are used the same way as any Java
Vector object.
// Initialize contents of the sequence
SCAReal64Sequence seq = new SCAReal64Sequence();
seq.add(1.0);
seq.add(2.0);
seq.add(3.0);

// Print contents of the sequence


for ( int i=0; i<seq.size(); i++ )
System.out.println("seq[" + i + "] = " + seq.get(i));
166 SCA Framework User’s Guide
Mapping for Type Aliases

Mapping for Type Aliases


A typedef is used in SCA IDL to define a sequence, an array or an alias for an existing type. The Java
mapping for sequences and arrays has already been discussed in the previous sections.
The use of the IDL typedef to create a new name for an existing type must be handled differently in Java
because the language does not support this concept. Therefore, IDL typedef definitions are first unwound
to either the SCA basic type or the user defined IDL type that it refers to and then the unwound type is
used as the Java type. As a result, the name of the IDL typedef type will never appear in the generated
Java code.
The following examples show how IDL typedef definitions that refer to both SCA basic types and other
IDL defined types are unwound.

IDL
typedef SCAInt32 HourValue;
typedef SCAInt32 MinuteValue;
typedef SCAInt32 SecondValue;

struct TimeDef
{
HourValue hour;
MinuteValue minute;
SecondValue second;
};

typedef TimeDef LocalTime;


typedef TimeDef GMTTime;

interface SCAITimeConvert
{
LocalTime convert(in GMTTime time);
};

Java
public class TimeDef
{
public int hour;
public int minute;
public int second;
}

public interface SCAITimeConvert extends SCA.SCAIService


{
TimeDef convert(TimeDef time);
}
Notice how the HourValue, MinuteValue, SecondValue, LocalTime and GMTTime alias types have
been unwound and the SCA basic types or IDL defined types have been used instead.
Chapter 6: IDL to Java Language Mapping 167
Mapping for SCATypeCode

Mapping for SCATypeCode


The SCATypeCode type is a special type used by the SCA Framework to describe the details about each
IDL defined type. The SCA Framework creates instances of the SCATypeCode using XML data
generated by the IDL compiler. Each instance of the SCATypeCode contains the complete description
of one IDL defined type. For example, the description of a structure would include the name and type for
each of its members.
The SCATypeCode type is treated in IDL as a basic type and it can appear anywhere in the IDL where
a basic type can appear. For example it could be the member of a structure or one of the arguments in an
interface method.
In Java a type code value is represented by the SCATypeCode class. The definition of a SCATypeCode
contains a pair of values. These include a SCATypeCodeID value that indicates the type of data and a
description of the type. The contents of the description depend on the value of the SCATypeCodeID.
The SCATypeCode class is fairly complex and will not be discussed in detail here. The data contained
in this class is mostly used internally within the SCA Framework. If you need to access these detailed
type definitions you are encouraged to use the SCA.Framework.Reflection service that is describe in
detail in the Dynamic SCA chapter of this manual.
168 SCA Framework User’s Guide
Mapping for SCAAny

Mapping for SCAAny


The SCAAny is a container data type which can hold a single value of any other arbitrary IDL data type.
Only values for types that are defined in IDL can be stored in a SCAAny. This is because the SCAAny
design requires a SCATypeCode value to describe the data it holds and these are only generated by the
IDL compiler and will not exist for types that are not defined in IDL.
The Java mapping for the IDL type SCAAny fulfills two important requirements:
• It must handle the Java types in a type-safe manner.
• It must handle values for complex types that are not known at compile time.

The first requirement covers the typical usage of the SCAAny type, the insertion of typed values into the
SCAAny and the type-safe extraction of the values. In Java the type-safety is ensured by the SCAAny
class and the Java JVM. When you try to insert a value into a SCAAny, the class will make sure that the
data being inserted is an IDL defined type and consistent with the SCA type description. If it is not, then
a SCASystemException will be thrown. When you try to extract a value from the SCAAny, the JVM
will attempt to cast it to the type you requested. If the value can be converted then the extraction will
succeed. If it cannot be converted then a Java RuntimeException exception will be thrown.
The second requirement covers situations like the need to extract data from the SCAAny when you do
not know the type of data it contains. In this case the receiver must be able to determine information about
what type of data the SCAAny contains. To achieve this, SCAAny contains a pair of values that includes
the actual value of the data and a description of its type. The type information can then be inspected to
determine the details on the value stored in the SCAAny instance.

The SCAAny class definition


In Java the SCAAny type is implemented by the SCA.SCAAny class. The public methods for the class
are shown below.
package SCA;
public class SCAAny
{
// Constructors
public SCAAny()
public SCAAny(Object data);
public SCAAny(Object data, String typeString);

// Methods for inserting and extracting values


public void setSCAInt8(byte data);
public byte getSCAInt8();
public void setSCAUInt8(short data);
public short getSCAUInt8();
public void setSCAInt16(short data);
public short getSCAInt16();
public void setSCAUInt16(int data);
public int getSCAUInt16();
public void setSCAInt32(int data);
public int getSCAInt32();
Chapter 6: IDL to Java Language Mapping 169
Mapping for SCAAny

public void setSCAUInt32(long data);


public long getSCAUInt32();
public void setSCAInt64(long data);
public long getSCAInt64();
public void setSCAUInt64(long data);
public long getSCAUInt64();
public void setSCAReal32(float data);
public float getSCAReal32();
public void setSCAReal64(double data);
public double getSCAReal64();
public void setSCAChar(char data);
public char getSCAChar();
public void setSCAString(String data);
public String getSCAString();
public void setSCAWChar(char data);
public char getSCAWChar();
public void setSCAWString(String data);
public String getSCAWString();
public void setSCABool(boolean data);
public boolean getSCABool();
public void setSCAAny(SCAAny data);
public SCAAny getSCAAny();
public void setSCATypeCode(SCATypeCode data);
public SCATypeCode getSCATypeCode();
public void setSCAResult(SCAResult data);
public SCAResult getSCAResult();
public void setSCAObject(Object data);
public void setSCAObject(Object data, String typeString);
public Object getSCAObject();

// Flush the contents


public void flush();

// Methods for getting information about the contents


public String type();
public boolean empty();
public String toString();

// SCAAny data
private Object m_data;
private String m_type;

}
Examples of using the SCAAny are show in the following sections.

Creating new SCAAny values


The following example creates an empty SCAAny value.
// Create an empty SCAAny instance
SCA.SCAAny any = new SCA.SCAAny();
170 SCA Framework User’s Guide
Mapping for SCAAny

To create a new SCAAny value that contains a value you can use the constructor which takes a Java
Object and an optional string description of the type. Which form you use depends on the way the SCA
type is mapped in Java. If the SCA type maps to a Java class that is generated by the IDL compiler, then
you only need to provide the instance in the constructor. This includes types like sequences, structures,
enumerations, array and interfaces. The following shows an example of this.
// Create a SCAAny instance which contains a structure value
Node node = new Node();
node.id = 123;
node.x = 1.0;
node.y = 2.0;
node.z = 3.0;
SCA.SCAAny any = new SCA.SCAAny(node);
But, if the SCA type maps to a native Java type that cannot be uniquely mapped to a SCA type then you
will need to add the type description to explicitly specify the type. An example of this is a Java String
value which can be mapped to either a SCAString or a SCAWString value.
// Create a SCAAny instance which contains a SCAString value
SCA.SCAAny any = new SCA.SCAAny(new String(“test”),”SCA.SCAString”);
Because the SCAAny will only hold an object that inherits from the Java Object type, you cannot create
a new SCAAny with a primitive type directly. Instead you must use its corresponding wrapper classes as
shown in this example. Since the wrapper classes do have unique SCA mappings, you must also include
the type description in this case.
// Create a SCAAny instance which contains a SCAInt32 value
SCA.SCAAny any = new SCA.SCAAny(new Integer(123),”SCA.SCAInt32”);

Inserting values into exiting SCAAny values


You also insert a value into an existing SCAAny instance. If the instance already holds a value it will be
replaced with the new value. Remember that the SCAAny can only hold a single value at a time.
Inserting values into an existing SCAAny instance follows a similar pattern that was described
previously for constructing new SCAAny values with one exception. Since the insertion of basic types
into a SCAAny is so common, a special group of set methods is provided. There is a separate set method
defined for each basic SCA type. These methods allow you to insert primitive values directly into the
SCAAny without having to use the wrapper classes.
// Insert a SCAInt32 value into a SCAAny instance
anyval.setSCAInt32(12);

// Insert a SCAString value into a SCAAny instance


Anyval.setSCAString(“value”);
Non-basic types are inserted using the setSCAObject method. Here is an example of inserting a sequence
into a SCAAny.
// Insert a SCAReal64Sequence value into a SCAAny instance
SCAReal64Sequence seq = new SCAReal64Sequence();
seq.add(1.0);
Chapter 6: IDL to Java Language Mapping 171
Mapping for SCAAny

seq.add(2.0);
anyval.setSCAObject(seq);
As before, since a SCA sequence has a unique mapping to a Java class, you do not need to add the type
description. But if the mapping is not unique you will need to.
// Insert a SCAString value into a SCAAny instance
anyval.setSCAObject(new String(“value”),”SCA.SCAString”);

// Insert a SCAInt32 value into a SCAAny instance


anyval.setSCAObject(new Integer(123),”SCA.SCAInt32”);
A SCAAny can even hold another SCAAny instance.
// Insert an SCAAny value to SCAAny instance
SCA.SCAAny anyval2 = new SCA.SCAAny(new Long(123),”SCA.SCAInt64”);
anyval.setSCAAny(anyval2);

Extracting the value contained in a SCAAny


To extract a value from the SCAAny, you use the get method that corresponds to the data contained in
it. When extracting values, it is important that you pick the correct method otherwise Java will throw a
RuntimeException exception.

// Extract a SCAInt32 from a SCAAny instance


try {
int int32val = anyval.getSCAInt32();
} catch (RuntimeException ex) {
System.out.println("RuntimeException:" + ex.toString());
}
For non-basic types, you will need to use the getSCAObject method to extract the value. This value must
be cast to the desired Java type as shown in this example.

// Extract a Node structure value from a SCAAny instance


try {
Node node = (Node)anyval.getSCAObject();
System.out.println("Extracted value: id=" + node2.id +
" x=" + node.x +
" y=" + node.y +
" z=" + node.z);
} catch (RuntimeException ex) {
System.out.println("RuntimeException:" + ex.toString());
}
There may be cases where the SCAAny value may hold one of a number of different types and you do
not know at compilation time which one it is. In this case you can use the type method to determine what
type it contains so you can choose the correct get method. The following example shows how several
extractions can be used to handle different possible types of values that may be in the SCAAny instance.
172 SCA Framework User’s Guide
Mapping for SCAAny

// Extract an unknown type from a SCAAny instance


int int32val;
float real32val;
if ( anyval.type() == "SCA.SCAInt32" ) {
int32val = anyval.getSCAInt32();
System.out.println("int32val = " + int32val);
} else if ( anyval.type() == "SCA.SCAReal32" ) {
real32val = anyval.getSCAReal32();
System.out.println("real32val = " + real32val);
} else {
System.out.println("Unsupported type " + anyval.type());
}

Miscellaneous SCAAny methods


The SCAAny provides several miscellaneous methods that can be used to check if the SCAAny contains
any data or to flush its contents.
// Check if SCAAny is empty
If ( anyval.empty() ){
// SCAAny value is empty
}
// Flush the contents of the SCAAny which will now be empty
any.flush();
The SCAAny also implements the toString method which allows you to get a string representation of its
contents.
// Print the information about the contents of the SCAAny
System.out.println("SCAAny value is " + anyval.toString());
Chapter 6: IDL to Java Language Mapping 173
Mapping for SCAResult

Mapping for SCAResult


The SCAResult type is used to return error information from calls to interface methods. It contains the
following information
• Error code
• Message table ID
• Message number
• Message parameters

The values in a SCAResult instance can be used by the SCA Framework to format and dispatch
messages in the language appropriate for the current user. For more information on using SCAResult
for error processing see the Error Handling chapter of this manual.

SCAResult class definition


The SCAResult type is mapped to the following Java class
package SCA;
public class SCAResult
{
// Constructors
public SCAResult();
public SCAResult(int errorCode);
public SCAResult( int errorCode, int msgTableId, int messageID);

// Setting values
public void setErrorCode( int errorCode );

// Return values
public int getErrorCode();
public int getTableID();
public int getMessageID();

// Add a new parameter


public void addSCAInt8(byte t );
public void addSCAUInt8(short t );
public void addSCAInt16(short t );
public void addSCAUInt16(int t );
public void addSCAInt32(int t );
public void addSCAUInt32(long t );
public void addSCAInt64(long t );
public void addSCAUInt64(long t );
public void addSCAReal32(float t );
public void addSCAReal64(double t );
public void addSCAChar(char t );
public void addSCAString(String t );
public void addSCAWString(String t );
public void addSCABool(boolean t );

// Compare all fields of SCAResult data, excluding parameters


174 SCA Framework User’s Guide
Mapping for SCAResult

public boolean equals(SCAResult sr );

// Return the parameters


public SCAAnySequence getParams();

// Return true if has parameters, return false otherwise.


public boolean hasParams();

// Return true if the error code == 0


public boolean isOk();

// Return true if it is a system error


public boolean isSystemError();

// Print raw contents of SCAResult


public void dump();

// Return a formatted message


public String toString();

// Predefined SCAResult values


public final static SCAResult SCASuccess = new SCAResult(0);
public final static SCAResult SCAError = new SCAResult(0X7FFFFFFF);
}
Two predefined SCAResult values are provided when you do not need to include more detailed
information to the callers.
// Return error
return SCA.SCAResult.SCAError;
// Return success
return SCA.SCAResult.SCASuccess;
Examples of the usages of these are shown in the following sections.

Creating new SCAResult values


The following example creates SCAResult values with different levels of initialization.
// Create SCAResult with all zero values
SCA.SCAResult rstat = new SCA.SCAResult();
// Create SCAResult with only an error value
SCA.SCAResult rstat = new SCA.SCAResult(1);
// Create SCAResult with error, tableID and messageID
SCA.SCAResult rstat = new SCA.SCAResult(1,4,301);}

Resetting the error code in a SCAResult value


The error code in an existing SCAResult value can be reset as follows.
// Reset error code in SCAResult
rstat.setErrorCode(201);
Chapter 6: IDL to Java Language Mapping 175
Mapping for SCAResult

Adding parameters to a SCAResult value


You use one of the add methods to add a parameter to a SCAResult value.
// Add parameters to SCAResult value
rstat.addSCAInt8((byte)1);
rstat.addSCAInt16((short)12);
rstat.addSCAInt32((int)123);
rstat.addSCAInt64((long)1234);
rstat.addSCAUInt8((byte)2);
rstat.addSCAUInt16((short)23);
rstat.addSCAUInt32((int)234);
rstat.addSCAUInt64((long)2345);
rstat.addSCAReal32(12.34F);
rstat.addSCAReal64(123.456);
rstat.addSCAChar('A');
rstat.addSCAString("TestString");
rstat.addSCAWString("TestWideString");
rstat.addSCABool(true);

Interrogating the contents of a SCAResult


The is Ok method provides a simple way to test if the SCAResult value has an error.
// Test if SCAResult has a non-zero error
if ( !rstat.isOk() )
// Process error
The get methods can be used to extract the error, table and message values.
// Extract the error, tableID and messageID values
int error = rstat.getErrorCode();
int tableid = rstat.getTableID();
int messageid = rstat.getMessageID();
The hasParams and getParams methods can be used to determine if the SCAResult has parameters and
to process them. The parameter values are returned in a SCAAnySequence.
// If the SCAResult has parameters, print them
if ( rstat.hasParams() ) {
for ( int i=0; i<params.size(); i++ ) {
SCA.SCAAny param = params.elementAt(i);
System.out.println("Param " + i + " = " + param.toString());
}
}

Miscellaneous SCAResult methods


The SCAResult also implements the toString and dump method which allows you to get or print the
contents. The toString method will attempt to format a message for the SCAResult value while the dump
method just prints the raw data.
// Print a string representation of the SCAAny
176 SCA Framework User’s Guide
Mapping for SCAResult

System.out.println("SCAResult value is " + anyval.toString());

// Print contents using the dump method


anyval.dump();
Chapter 6: IDL to Java Language Mapping 177
Mapping for Constants

Mapping for Constants


An IDL defined constants are mapped to an interface of the same name as the constant which contains a
single fixed data value with the name value which has the value of the IDL constant.

IDL
const SCA::SCAInt32 NUM_OF_STATES = 50;

Java
public interface NUM_OF_STATES
{
final int value = 50;
}

The value of the constant can be referenced using the value field.
// Print value of constant defined in IDL
System.out.println("constant value = " + NUM_OF_STATES.value);
178 SCA Framework User’s Guide
Mapping for Interfaces

Mapping for Interfaces


SCA interfaces are mapped directly to Java interfaces.
The following is a simple interface definition. This example is missing the definitions of all the required
types but they have no affect on actual interface mapping so they have been left out to simplify the
example.

IDL
interface SCAIReader : SCA::SCAIService
{
SCAVoid readModel( in SCAString name ) raises(ReaderException);
SCAINode getNode( in SCAInt32 id ) raises(ReaderException);
SCAVoid getNodeCoordinates( in SCAInt32 id,
out SCAReal32 x,
out SCAReal32 y,
out SCAReal32 z )
raises(ReaderException);
};

Java
public interface SCAIReader extends SCA.SCAIService
{
void readModel(String name) throws ReaderException;
SCAINode getNode(int id) throws ReaderException;
void getNodeCoordinates(int id,
SCA.Holder<Float> x,
SCA.Holder<Float> y,
SCA.Holder<Float> z) throws ReaderException;
}

Mapping for Interface Operations


Each interface operation (or method) is mapped to a method in the Java interface with the same name.

Mapping for Interface Parameters


Each parameter in an IDL operation must have direction of in, out or inout. Input parameters are mapped
directly to their corresponding Java parameters. But, since Java does not support output type parameters,
they must be handled specially. The mapping for out or inout parameters in Java uses a predefined generic
class, SCA.Holder, that holds an instance of the parameter.
package SCA;
public class Holder<T>{
public Holder(){
value=null;
}
public Holder(T obj){
value=obj;
Chapter 6: IDL to Java Language Mapping 179
Mapping for Interfaces

}
public T value;
}
If the IDL parameter is one of the SCA basic types then the SCA.Holder class must hold its
corresponding Java box type and not the primitive type. The following table shows the corresponding
box type for each SCA IDL type.

IDL Type Java primitive type Java box type


SCA::SCAInt8 byte java.lang.Byte
SCA::SCAUInt8 short java.lang.Short
SCA::SCAInt16 short java.lang.Short
SCA::SCAUInt16 int java.lang.Short
SCA::SCAInt32 int java.lang.Integer
SCA::SCAUInt32 long java.lang.Integer
SCA::SCAInt64 long java.lang.Long
SCA::SCAUInt64 long java.lang.Long
SCA::SCAReal32 float java.lang.Float
SCA::SCAReal64 double java.lang.Double
SCA::SCAChar char java.lang.Character
SCA::SCAWChar char java.lang.Character
SCA::SCABool boolean java.lang.Boolean

When calling a method with output parameters, you must first create instances of the SCA.Holder class
and pass them as the parameter as shown in this example.

SCA.Holder<Float> x = new SCA.Holder<Float>();


SCA.Holder<Float> y = new SCA.Holder<Float>();;
SCA.Holder<Float> z = new SCA.Holder<Float>();;
inf.getNodeCoordinates(id,x,y,z);
System.out.println(“X=” + x.value());
System.out.println(“Y=” + y.value());
System.out.println(“Y=” + z.value());
If any of these parameters was specified with the inout direction, the value in the holder class should be
set before the interface method is called.
180 SCA Framework User’s Guide
Mapping for Exceptions

Mapping for Exceptions


The SCA Framework predefines three exception types, SCA.SCAException, SCA.SCAUserException
and SCA.SCASystemException. All user defined exceptions in IDL must inherit either
SCA::SCAUserException or another user-defined exception. Only single inheritance is allowed.

SCAException interface
The base for all IDL defined exceptions is SCAException which is mapped to the java interface
SCA.SCAException.

package SCA;
public interface SCAException
{
// Method to return description of the exception
String what();
// Method to get SCATypeCode for this exception
SCATypeCode getTypeCode();
// Method to get raw text string for this exception
String getText();
// Method to set raw text string for this exception
void setText(String text);
}

SCAUserException class
The SCAUserException exception adds no new data to SCAException and should be used as the base
for all user defined exceptions. It is mapped to the predefined Java class SCA.SCAUserException which
implements the SCA.SCAException interface.

package SCA;
public class SCAUserException extends Exception
implements SCAException
{
// Constructor
public SCAUserException();
// Methods to return description of exception
public final String what();
public final String toString();
// Method to get SCATypeCode for this exception
public final SCATypeCode getTypeCode();
// Method to get raw text string for this exception
public final String getText();
// Method to set raw text string for this exception
public final void setText(String text);
// Method to set exception type
protected final void setType(String type);
Chapter 6: IDL to Java Language Mapping 181
Mapping for Exceptions

// Exception data
private String m_type;
protected String m_text;
}

SCASystemException class
The SCASystemException exception should only be used internally by the SCA Framework and adds
an error ID member to SCAException. It is mapped to the predefined Java class
SCA.SCASystemException which implements the SCA.SCAException interface. Note that
SCA.SCASystemException inherits from Java’s RuntimeException exception, so it is treated as an
unchecked exception by the java runtime.
package SCA;
public class SCASystemException extends RuntimeException
implements SCAException
{
// Constructors
public SCASystemException();
public SCASystemException(int iid);
public SCASystemException(int iid, String text);
// Methods to return description of the exception
public final String what();
public final String toString();
// Method to get SCATypeCode for this exception
public final SCATypeCode getTypeCode();
// Method to get raw text string for this exception
public final String getText();
// Method to set raw text string for this exception
public final void setText(String text);
// Method to set exception type
protected final void setType(String type);
// Method to return exception traceback
public static String getTrace(Throwable e);
// Exception data
private String m_type;
protected String m_text;
public int id;
}

Mapping for IDL defined user exceptions


User-defined exceptions are mapped to respective Java classes. All the user defined members in an
exception are mapped as public fields in the exception class.

IDL
exception ReaderException : SCAUserException
{
SCAString name;
182 SCA Framework User’s Guide
Mapping for Exceptions

SCAString error;
};

Java
public class ReaderException extends SCA.SCAUserException
{
public ReaderException();
public String name;
public String error;
};
The following code shows an example of how you throw a SCA exception in Java.
ReaderException ex = new ReaderException();
ex.name = “TestInput.dat”;
ex.error = “The file does not exist”;
throw ex;

And the exception can be caught as follows.

try
{
// Code that triggers an exception
}
catch (ReaderException ex)
{
System.out.println("ReaderException caught for");
System.out.println(“File: “ + ex.name);
System.out.println(“Error: “ + ex.error);
}

The IDL raises clause


An IDL interface operation may contain a raises clause to indicate what kind of exceptions the operation
may throw.

IDL
interface SCAIReader : SCA::SCAIService
{
SCAVoid readModel( in SCAString name ) raises(ReaderException);
};

Java
public interface SCAIReader extends SCA.SCAIService
{
void readModel(String name) throws ReaderException;
}
Chapter 6: IDL to Java Language Mapping 183
Mapping for Exceptions

Use of the raises clause is especially important in Java, since a method that throws an exception should
specify it in a throws clause. The SCASystemException exception is an unchecked Java exception so
it can always be thrown and users do not need to include it in the raises clause. Other exceptions that may
be thrown must be one of the exceptions in the raises clause to inherit from one of them.
184 SCA Framework User’s Guide
Mapping for SCA Services

Mapping for SCA Services


Two types of code are generated for SCA service definitions.
1. The genskeleton command is used to generate the initial implementation skeletons for a service.
The generated skeletons can then be expanded with the code required to implement the desired
behavior for the various interface operations.
2. During the build process, various Java base classes are generated which are used to link the
developer generated implementation code to the SCA Framework. This is done to reduce as much
as possible the amount of code that must be written by the developer to implement a service.
These classes also provide a level of isolation between the service’s implementation code and the
SCA Framework. This allows for future changes to be made in the interaction between the base
classes and the SCA Framework without affecting the developer’s implementation code.
The following is the IDL file for an example interface definition that will be used in this section.

#ifndef SCA_FILEREADER_FILEREADER_IDL_INCLUDED
#define SCA_FILEREADER_FILEREADER_IDL_INCLUDED

#include "SCA/Service.idl"

module SCA { module FileReader {

struct Node
{
SCAInt32 id;
SCAReal32 x;
SCAReal32 y;
SCAReal32 z;
};

exception ReaderException : SCAUserException


{
SCAString name;
SCAString error;
};

interface SCAINode;

interface SCAIReader : SCA::SCAIService


{
SCAVoid readModel( in SCAString name ) raises(ReaderException);
SCAINode getNode( in SCAInt32 id ) raises(ReaderException);
};

interface SCAINode : SCA::SCAIService


{
SCAInt32 getID();
SCAReal32 getX();
SCAReal32 getY();
SCAReal32 getZ();
Chapter 6: IDL to Java Language Mapping 185
Mapping for SCA Services

};

}; };

#endif
The following is the SDL for an example service that will implement these interfaces.
#ifndef FILEREADER_SDL_INCLUDED
#define FILEREADER_SDL_INCLUDED

#include "SCA/FileReader/FileReader.idl"

module SCA { module FileReader { module Impl {

service SCA.Test.FileReader {
interface SCA::FileReader::SCAIReader;
subservice NodeImpl ( in SCA::FileReader::Node node ) {
interface SCA::FileReader::SCAINode;
};
};

}; }; };

#endif

The inheritance form of implementation


In the inheritance form of implementation, the implementation classes generated by genskeleton will
inherit from base classes generated by the IDL compiler at build time. These base classes will then inherit
from the interface classes and also provide all the necessary links to the SCA Framework.
When the genskeleton command is run for the above SDL file to generate the skeleton code for the
service, it will generate two Java classes, FileReader which implements the SCAIReader interface and
NodeImpl which implements the SCAINode interface.
The Java implementation will be put in a package that is defined by the SDL module statements. In this
example it is SCA.FileReader.Impl. This will also define the subdirectory where the implementation
files will be written. In this example the actual file created for the FileReader class will be
SCA/FileReader/Impl/FileReader.java.
The following is the file FileReader.java that is generated for the top-level service class.
package SCA.FileReader.Impl;

public class FileReader extends FileReader_base


{
// Constructor
public FileReader (SCA.Framework.SCAIServiceProvider provider)
{
super();
186 SCA Framework User’s Guide
Mapping for SCA Services

setServiceProvider(provider);
}

// Methods for interface SCA.FileReader.SCAIReader


public final void readModel (String name)
throws SCA.FileReader.ReaderException
{
//implementation goes here
}
public final SCA.FileReader.SCAINode getNode (int id)
throws SCA.FileReader.ReaderException
{
//implementation goes here
}
}
The implementation classes generated are fairly simple, but there are a couple of requirements for these
imposed by the SCA Framework. These are the requirements when using the default or inheritance form
of implementation.
The class must inherit from the base class generated by the IDL compiler.
• The class can have only one constructor and it must have a single argument of
SCAIServiceProvider type. This argument is used by the base class to access the SCA
Framework.
• The base class constructor must be explicitly called from the class constructor.
• The class must implement each of the operations defined in the interfaces it supports except for
SCAIService.
As long as these requirements are met, the developer is free to make any desired modifications to these
implementation classes.
The base class FileReader_base, which will be generated by the IDL compiler when it is run during the
build process, provides the following.
• Inherits from the respective interface for each interface implemented by the service class. In this
example it will be the SCAIReader interface.
• Provides the implementation for all of the required reference counting, interface navigation and
introspection methods in the SCAIService interface that every SCA service class must
implement.
• Provides access to the SCA Framework facilities.

If the FileReader service used in this example implemented additional interfaces, the only changes to
the generated code would be the addition of the method definitions for the operations in the new
interfaces.
The SDL for the FileReader service also includes the definition of a subservice NodeImpl which takes
a Node constructor argument. A separate Java class, NodeImpl, will be generated for the subservice
class. The format of this class is identical to the FileReader class except for the addition of an extra
argument defined in the SDL file on the class constructor and the interface methods it implements.
Chapter 6: IDL to Java Language Mapping 187
Mapping for SCA Services

Following is the NodeImpl.java class generated by the genskeleton command


package SCA.FileReader.Impl;

public class NodeImpl extends NodeImpl_base


{
// Constructor
public NodeImpl (SCA.Framework.SCAIServiceProvider provider,
SCA.FileReader.Node node)
{
super();
setServiceProvider(provider);
}

// Methods for interface SCA.FileReader.SCAINode


public final int getID ()
{
//implementation goes here
}
public final float getX ()
{
//implementation goes here
}
public final float getY ()
{
//implementation goes here
}
public final float getZ ()
{
//implementation goes here
}
}
Only subservice classes can have user specified constructor arguments. This is because instances of the
top-level FileReader class are instantiated by the IDL generated factory class in response to getService
calls made by the clients of the service. There is currently no way for clients to passes constructor
arguments through the getService call. On the other hand, instances of subservice classes can only be
generated by the implementation code in the service. In this case the implementation is free to pass any
desired arguments to the constructors.
The following is an example implementation for the getNode method which returns an instance of the
SCAINode interface. The SDL definition for this service specifies that the SCAINode interface is
implemented by the NodeImpl subservice class. That means that the getNode method needs to allocate
an instance of the NodeImpl class and return the SCAINode interface on it. The constructor for the
NodeImpl class, generated by the genskeleton utility, requires two parameters. The first parameter is the
SCAIServiceProvider interface which is available in the m_provider variable in the base class. The
second argument is an instance of the Node structure that was specified as a constructor argument in the
SDL.
SCAINode FileReader::getNode(const SCAInt32 id)
{
// Find and initialize the node which cooresponds to ID
Node node = …
188 SCA Framework User’s Guide
Mapping for SCA Services

// Return a new subservice class instance for this node


NodeImpl spNode = new NodeImpl(m_provider,node);
return (SCAINode)spNode;
}

The ServiceAccess interface


The base classes generated by the IDL compiler will always implement the SCA.ServiceAccess
interface. This interface is the link between the implementation of the service and the SCA Framework.
The following is the definition of the ServiceAccess interface:
package SCA;
public interface ServiceAccess
{
// Load a SCA service
SCAIService getService(String name, String attr);

// Set the SCAIServiceProvider interface


void setServiceProvider(SCA.Framework.SCAIServiceProvider
provider);
}
If the implementation of the service needs to load another SCA service, then the getService method in
the ServiceAccess class is used.
SCAIService spSvc;
spSvc = getService(“Test.Service.Name”, “”)

The delegation form of implementation


You use the delegate keyword in the SDL file to select the delegation form of implementation. Currently
the delegation form of implementation is not supported in Java.

Singleton Services
It is also possible to indicate that the service is a singleton in the SDL. The use of this keyword has no
affect on any of the Java implementation skeletons generated for a service. The processing of singleton
services is handled entirely in the factory support code that is generated when the service is built. It is
important to remember that even so the generated skeletons are the same; the implementation code for a
singleton service may need to be different. Because multiple clients may be sharing the same instance of
the service, the code needs to make sure this is done in a safe manner.

Aggregation
The support for aggregation is requested with the aggregates and aggregated keywords in the SDL.
Currently aggregation is not supported in Java.
Chapter 6: IDL to Java Language Mapping 189
Mapping for SCA Components

Mapping for SCA Components


The Java mapping uses a normal jar files for SCA components. The only code required for a SCA
component is support code generated by the IDL compiler during the build process. This code is used by
the SCA Framework to initialize the component and expose the services it provides when the component
is loaded at runtime. There is no code that the developer needs to create for a component.

Embedded Components
Support for embedded components is requested with the embedded option in the CDL. Currently
embedded components are not supported in Java.
190 SCA Framework User’s Guide
SCA Framework / JVM Interaction

SCA Framework / JVM Interaction

Java Virtual Machine Initialization


The initialization of the Java virtual machine can be triggered in two different ways when running SCA
applications that use components written in Java.
• If the SCA application is written in Java, then the application will normally be started using the
Java application launcher utility. In this case the application launcher is responsible for
initializing the JVM and the normal command line parameters and environment variables it
supports are used to provide any user defined options for the JVM.
• If the SCA application is written in a language other than Java, then the JVM will be initialized
by the SCA Kernel when the first Java service is loaded. In this case, the SCA Kernel
JVMConfig configuration parameter is used to provide any user defined options for the JVM.

The IDLTypes.jar archive


When the scons build command is run to build the Java service, the IDL compiler will be run on all the
known IDL files to generate the required Java mappings. This includes all of the IDL files in the
APPS_SYSTEM and the APPS_LOCAL directories. The generated Java files will be compiled and
archived in a single jar archive, APPS_LOCAL/lib/java/ IDLTypes.jar. This jar archive must be included
in the class path for the JVM.
• If the SCA application is written in Java, then the IDLTypes.jar archive must be manually added
to the Java class path using either CLASSPATH environment variable or the classpath or cp
command line parameter for the Java application launcher utility.
• If the SCA application is written in a language other than Java, then the SCA kernel will
initialize the JVM using the JVMConfig configuration variable. If no JVMConfig variable is
provided, then it will automatically provide one that includes an IDLTypes.jar archive which is
located relative to the SCA resource directory which is specified with the Resource
configuration value.
JVMConfig=”-Djava.class.path=Resource/../lib/java/IDLTypes.jar”
• If the SCA application is written in a language other than Java and the JVMConfig
configuration variable is provided, then the location of the IDLTypes.jar archive must be
manually included in it.
For further details on setting the JVMConfig and other SCA configuration parameters please refer to the
SCA Kernel documentation.
Chapter 7: IDL to .Net Languages Mapping
SCA Framework User’s Guide

7 IDL to .Net Languages Mapping


Introduction 192
 Mapping for Identifiers 194

Mapping for Modules 195

Mapping for Basic Types 196
 Mapping for String Types 198

Mapping for Enumerated Types 199

Mapping for Structures 200
 Mapping for Arrays 201

Mapping for Sequences 203

Mapping for Type Aliases 204
 Mapping for SCATypeCode 205

Mapping for SCAAny 206

Mapping for SCAResult 211
 Mapping for Constants 215
 Mapping for Interfaces 216

Mapping for Exceptions 217

Mapping for SCA Services 220
 Mapping for SCA Components 227
192 SCA Framework User’s Guide
Introduction

Introduction
The IDL language provides a language independent definition of SCA interfaces and data types. In order
to actually use these definitions, there must be a set of rules, commonly known as a mapping that
describes how these types are represented in a particular language. This chapter explains the mapping
that SCA uses for the .NET languages.
Since .NET has a unified type system, the SCA types can be used in any .NET language. The following
table summarizes the data type mapping between IDL, CLR, C# and Visual Basic types. The following
sections of this chapter will provide the details on each mapping.

IDL Type CLR Type C# Type VB Type


SCA::SCAInt8 SByte sbyte SByte
SCA::SCAUInt8 Byte byte Byte
SCA::SCAInt16 Int16 short Short
SCA::SCAUInt16 UInt16 ushort UShort
SCA::SCAInt32 Int32 int Integer
SCA::SCAUInt32 UInt32 uint UInteger
SCA::SCAInt64 Int64 long Long
SCA::SCAUInt64 UInt64 ulong ULong
SCA::SCAReal32 Single float Single
SCA::SCAReal64 Double double Double
SCA::SCAChar Char char Char
SCA::SCAWChar Char char Char
SCA::SCAString String string String
SCA::SCAWString String string String
SCA::SCABool Boolean bool Boolean
SCA::SCAAny SCA.SCAAny
SCA::SCATypeCode SCA.SCATypeCode
SCA::SCAResult SCA.SCAResult
sequence class that inherits from List
enum enum
struct struct
array [] or[][]
interface interface
exception class that inherits from System.Exception
Chapter 7: IDL to .Net Languages Mapping 193
Introduction

See the HelloWorld Application chapter of this manual for examples on how SCA applications can be
written in different .NET languages. In that chapter both a C# and Visual Basic version of the application
is shown.
To reduce the amount of sample code, this chapter will only show examples in the C# language.
For every type defined in IDL, the IDL compiler will generate the code required to expose the proper
CLR definition of the type. In addition to the actual CLR definition of the type, there is also some support
code generated for each interface which is used by SCA Framework to make interface calls from .NET
to services implemented in the other supported languages.
When building a .NET application or component, the SCA SCons build system will compile the CLR
definitions for all of the known IDL types and store them in a single assembly
APPS/WINNT/bin/IDLTypes.dll.
194 SCA Framework User’s Guide
Mapping for Identifiers

Mapping for Identifiers


IDL identifiers are mapped to CLR identifiers with no change. For example:

IDL
enum Color { RED, GREEN, BLUE };

C#
public enum Color { RED, GREEN, BLUE }
There is one potential problem to be aware of. If the IDL file contains an identifier that is also a reserved
keyword in the language you are using, then the code will not compile. Therefore, the use of any of these
reserved words for IDL identifiers is not allowed.
Chapter 7: IDL to .Net Languages Mapping 195
Mapping for Modules

Mapping for Modules


SCA IDL namespaces are defined with the module keyword. These namespaces are mapped directly to
CLR namespaces.

IDL
module Test{

};

C#
namespace Test{

}
The IDL module constructs also affect other aspects of the SCA mapping. See the IDL Compiler chapter
for detailed information on how the IDL module statements are used.
196 SCA Framework User’s Guide
Mapping for Basic Types

Mapping for Basic Types


Basic data types, SCAInt8, SCAUInt8, SCAInt16, SCAUInt16, SCAInt32, SCAUInt32, SCAInt64,
SCAUInt64, SCAReal32, SCAReal64, SCAChar, SCAWChar and SCABool are mapped to the
corresponding Common Language Runtime (CLR) types. The SCAChar is mapped to the CLR Char.
This can cause issues because the CLR Char contains multi-byte Unicode characters while the IDL
definition of a SCAChar only accommodates the single-byte ISO Latin-1 character set. When passing
SCAChar data from .NET to a different language, the high byte will be discarded.
The following table shows the CLR, C# and Visual Basic mappings for the basic SCA types.

IDL Type CLR Type C# Type VB Type


SCA::SCAInt8 SByte sbyte SByte
SCA::SCAUInt8 Byte byte Byte
SCA::SCAInt16 Int16 short Short
SCA::SCAUInt16 UInt16 ushort UShort
SCA::SCAInt32 Int32 int Integer
SCA::SCAUInt32 UInt32 uint UInteger
SCA::SCAInt64 Int64 long Long
SCA::SCAUInt64 UInt64 ulong ULong
SCA::SCAReal32 Single float Single
SCA::SCAReal64 Double double Double
SCA::SCAChar Char char Char
SCA::SCAWChar Char char Char
SCA::SCABool Boolean bool Boolean

The following structure definition illustrates this mapping.

IDL:
struct Node
{
SCAInt32 id;
SCAReal32 x;
SCAReal32 y;
SCAReal32 z;
};

C#:
public struct Node
{
public int id;
public float x;
Chapter 7: IDL to .Net Languages Mapping 197
Mapping for Basic Types

public float y;
public float z;
}
198 SCA Framework User’s Guide
Mapping for String Types

Mapping for String Types


Both SCAString and SCAWString are mapped to System.String. Converting from a SCAString or
SCAWString to a CLR value will not lose any information. When converting from a CLR value to a
SCAString, the CLR value is first converted to an ANSI value which is then stored in the SCAString.

IDL:
struct address
{
SCAString street;
SCAString city;
SCAInt32 zipcode;
};

C#:
public class address
{
public String street;
public String city;
public int zipcode;
}
Chapter 7: IDL to .Net Languages Mapping 199
Mapping for Enumerated Types

Mapping for Enumerated Types


An IDL enum is mapped directly to a CLR enum.

IDL
enum Colors {
RED, GREEN, BLUE
};

C#
public enum Colors
{
RED, GREEN, BLUE
}
200 SCA Framework User’s Guide
Mapping for Structures

Mapping for Structures


An IDL structure maps to a CLR struct with all public fields. Each IDL structure member is mapped to
a corresponding member of the CLR structure. The CLR structure members appear in the same order as
the corresponding IDL structure members. For example:

IDL
struct Node
{
SCAInt32 id;
SCAReal32 x;
SCAReal32 y;
SCAReal32 z;
};

C#
public struct Node
{
public int id;
public float x;
public float y;
public float z;
}
Chapter 7: IDL to .Net Languages Mapping 201
Mapping for Arrays

Mapping for Arrays


Two types of array definitions are supported in IDL. Fixed size arrays must have their size defined in the
IDL and can never change. Dynamic arrays allow you to delay the specification of the array size until it
is actually allocated. Only arrays of rank 1 or 2 are supported.

Fixed size arrays


There is no special code generated for the mapping of IDL defined arrays. Normal CLR arrays should be
used for these types. When arrays are allocated you need to make sure that the correct length is specified.
The array sizes are not checked when making interface calls between .NET languages, but if making a
call to another language through a SCA bridge the sizes are checked and a SCASystemException will
be thrown if incorrect.

IDL
typedef SCAInt32 Date[3];

C#
int[] date = new int[3];
Two dimension arrays use the CLR jagged array format.

IDL
typedef SCAInt32 Matrix[3][3];

C#
int[][] matrix = {
new int[] {1,3,5},
new int[] {0,2,4},
new int[] {11,22,22}
};
If an IDL array is defined in a structure, it is also mapped directly to a CLR array.

IDL
struct Node2
{
SCAInt32 id;
SCAReal32 location[3];
};

C#
public struct Node2
{
public int id;
public float[] location
}
202 SCA Framework User’s Guide
Mapping for Arrays

Dynamic Arrays
Dynamic Arrays also use normal CLR arrays types. Since the size of a dynamic array is not fixed in the
IDL, you can use any appropriate size when you allocate the CLR array type. Dynamic arrays exist
primarily to provide more optimized code in other languages supported by the SCA framework.
Chapter 7: IDL to .Net Languages Mapping 203
Mapping for Sequences

Mapping for Sequences


An IDL sequence is mapped to a class that inherits from System.Collections.Generic.List.

IDL
typedef SCASequence<SCA::SCAInt32> NodeSequence;

C#
public class NodeSequence : List<SCA.FileReader.Node>{
public NodeSequence() { }
public NodeSequence(int initialCapacity): base(initialCapacity) {
}
public override string ToString() {
string s="[";
foreach(SCA.FileReader.Node i in this){
s+=i.ToString()+" ";
}
s+="]";
return s;
}
}
When an IDL sequence appears as a member of a structure, it is mapped directly to a
System.Collections.Generic.List type as the member of the structure.

IDL
struct Node3{
SCAInt32 id;
SCASequence<SCAReal32> location;
};

C#
public struct Node3{
int id;
public List<float> location;
}
Since generated sequence classes inherit from List they are used the same way as any List object.
// Initialize contents of the sequence
SCAReal64Sequence seq = new SCAReal64Sequence();
seq.Add(1.0);
seq.Add(2.0);
seq.Add(3.0);

//Print contents of the sequence


foreach (double val in seq)
Console.WriteLine(val);
204 SCA Framework User’s Guide
Mapping for Type Aliases

Mapping for Type Aliases


A typedef is used in SCA IDL to define a sequence, an array or an alias for an existing type. The CLR
mapping for sequences and arrays has already been discussed in the previous sections.
The use of the IDL typedef to create a new name for an existing type must be handled differently in .NET
because not all of the different languages provide a similar capability. Therefore, IDL typedef definitions
are first unwound to either the SCA basic type or the user defined IDL type that it refers to and then the
unwound type is used as the CLR type. As a result, the name of the IDL typedef type will never appear
in the generated code.
The following examples show how IDL typedef definitions that refer to both SCA basic types and other
IDL defined types are unwound.

IDL
typedef SCAInt32 HourValue;
typedef SCAInt32 MinuteValue;
typedef SCAInt32 SecondValue;

struct TimeDef
{
HourValue hour;
MinuteValue minute;
SecondValue second;
};

typedef TimeDef LocalTime;


typedef TimeDef GMTTime;

interface SCAITimeConvert
{
LocalTime convert(in GMTTime time);
};

C#
public struct TimeDef
{
public int hour;
public int minute;
public int second;
}

public interface SCAITimeConvert : SCA.SCAIService


{
TimeDef convert(TimeDef time);
}
Notice how the HourValue, MinuteValue, SecondValue, LocalTime and GMTTime alias types have
been unwound and the SCA basic types or IDL defined types have been used instead.
Chapter 7: IDL to .Net Languages Mapping 205
Mapping for SCATypeCode

Mapping for SCATypeCode


The SCATypeCode type is a special type used by the SCA Framework to describe the details about each
IDL defined type. The SCA Framework creates instances of the SCATypeCode using XML data
generated by the IDL compiler. Each instance of the SCATypeCode contains the complete description
of one IDL defined type. For example, the description of a structure would include the name and type for
each of its members.
The SCATypeCode type is treated in IDL as a basic type and it can appear anywhere in the IDL where
a basic type can appear. For example it could be the member of a structure or one of the arguments in an
interface method.
In .NET a type code value is represented by the SCATypeCode class. The definition of a SCATypeCode
contains a pair of values. These include a SCATypeCodeID value that indicates the type of data and a
description of the type. The contents of the description depend on the value of the SCATypeCodeID.
The SCATypeCode class is fairly complex and will not be discussed in detail here. The data contained
in this class is mostly used internally within the SCA Framework. If you need to access these detailed
type definitions you are encouraged to use the SCA.Framework.Reflection service that is describe in
detail in the Dynamic SCA chapter of this manual.
206 SCA Framework User’s Guide
Mapping for SCAAny

Mapping for SCAAny


The SCAAny is a container data type which can hold a single value of any other arbitrary IDL data type.
Only values for types that are defined in IDL can be stored in a SCAAny. This is because the SCAAny
design requires a SCATypeCode value to describe the data it holds and these are only generated by the
IDL compiler and will not exist for types that are not defined in IDL.
The .NET mapping for the IDL type SCAAny fulfills two important requirements:
1. It must handle the CLR types in a type-safe manner.
2. It must handle values for complex types that are not known at compile time.
The first requirement covers the typical usage of the SCAAny type, the insertion of typed values into the
SCAAny and the type-safe extraction of the values. In .NET the type-safety is ensured by the SCAAny
class and the CLR. When you try to insert a value into a SCAAny, the class will make sure that the data
being inserted is an IDL defined type and consistent with the SCA type description. If it is not, then a
SCASystemException will be thrown. When you try to extract a value from the SCAAny, the CLR will
attempt to cast it to the type you requested. If the value can be converted then the extraction will succeed.
If it cannot be converted then a CLR Exception will be thrown.
The second requirement covers situations like the need to extract data from the SCAAny when you do
not know the type of data it contains. In this case the receiver must be able to determine information about
what type of data the SCAAny contains. To achieve this, SCAAny contains a pair of values that includes
the actual value of the data and a description of its type. The type information can then be inspected to
determine the details on the value stored in the SCAAny instance.

The SCAAny class definition


In .NET the SCAAny type is implemented by the SCA.SCAAny class. The public methods for the class
are shown below.
namespace SCA {
public class SCAAny
{
// Constructors
public SCAAny();
public SCAAny(Object data);
public SCAAny(Object data, String typeName);

// Methods for inserting and extracting values


public void setSCAInt8(sbyte data);
public sbyte getSCAInt8();
public void setSCAUInt8(byte data);
public byte getSCAUInt8();
public void setSCAInt16(short data);
public short getSCAInt16();
public void setSCAUInt16(ushort data);
public ushort getSCAUInt16();
public void setSCAInt32(int data);
public int getSCAInt32();
Chapter 7: IDL to .Net Languages Mapping 207
Mapping for SCAAny

public void setSCAUInt32(uint data);


public uint getSCAUInt32();
public void setSCAInt64(long data);
public long getSCAInt64();
public void setSCAUInt64(ulong data);
public ulong getSCAUInt64();
public void setSCAReal32(float data);
public float getSCAReal32();
public void setSCAReal64(double data);
public double getSCAReal64();
public void setSCAChar(char data);
public char getSCAChar();
public void setSCAString(String data);
public String getSCAString();
public void setSCAWChar(char data);
public char getSCAWChar();
public void setSCAWString(String data);
public String getSCAWString();
public void setSCABool(bool data);
public bool getSCABool();
public void setSCAAny(SCAAny data);
public SCAAny getSCAAny();
public void setSCATypeCode(SCATypeCode data);
public SCATypeCode getSCATypeCode();
public void setSCAResult(SCAResult data);
public SCAResult getSCAResult();
public void setSCAObject(Object data);
public void setSCAObject(Object data, String typeName);
public Object getSCAObject();

// Flush the contents


public void flush();

// Methods for getting information about the contents


public String type();
public bool empty();
public override String ToString();

// Data
private Object m_data;
private String m_type;

}
}
Examples of using the SCAAny are show in the following sections.

Creating new SCAAny values


The following example creates an empty SCAAny value.
// Create an empty SCAAny instance
SCA.SCAAny any = new SCA.SCAAny();
208 SCA Framework User’s Guide
Mapping for SCAAny

To create a new SCAAny value that contains a value you can use the constructor which takes a CLR
Object and an optional string description of the type. Which form you use depends on the way the SCA
type is mapped in .NET. If the SCA type uniquely maps to a CLR type, then you only need to provide
the object in the constructor. Types like sequences, structures, enumerations, interfaces and all basic types
except characters and strings fall into this category. The following shows several examples of this.
// Create a SCAAny instance which contains a structure value
Node node = new Node();
node.id = 123;
node.x = 1.0;
node.y = 2.0;
node.z = 3.0;
SCA.SCAAny any = new SCA.SCAAny(node);

// Create a SCAAny instance which contains a SCAInt64 value


SCA.SCAAny any2 = new SCA.SCAAny((long)123);
But, if the SCA type maps to a native CLR type that cannot be uniquely associated to a SCA type then
you will need to add the type description to explicitly specify the type. An example of this is a CLR String
value which can be mapped to either a SCAString or a SCAWString value. If the type description is not
specified when required a SCASystemException will be thrown.
// Create a SCAAny instance which contains a SCAString value
SCA.SCAAny any = new SCA.SCAAny(new String(“test”),”SCA.SCAString”);

Inserting values into existing SCAAny value


You can also insert a value into an existing SCAAny instance. If the instance already holds a value it will
be replaced with the new value. Remember that the SCAAny can only hold a single value at a time.

Inserting values into an existing SCAAny instance follows a similar pattern that was described
previously for constructing new SCAAny values with one exception. Since the insertion of basic types
into a SCAAny is so common, a special group of set methods is provided. There is a separate set method
defined for each basic SCA type. These methods allow you to easily insert primitive values directly into
the SCAAny without having to specify the SCA type names or do any casts to remove ambiguities.
// Insert an SCAInt32 value to SCAAny instance
anyval.setSCAInt32(12);

// Insert a SCAString value into a SCAAny instance


Anyval.setSCAString(“value”);
Non-basic types are inserted using the setSCAObject method. Here is an example of inserting a sequence
into a SCAAny.
// Insert an SCAReal64Sequence value to SCAAny instance
SCAReal64Sequence seq = new SCAReal64Sequence ();
seq.Add(1.0);
seq.Add(2.0);
anyval.setSCAObject(seq);
Chapter 7: IDL to .Net Languages Mapping 209
Mapping for SCAAny

As before, since a SCA sequence has a unique mapping to a CLR class, you do not need to add the type
description. But if the mapping is not unique you will need to.
// Insert a SCAString value into a SCAAny instance
anyval.setSCAObject(new String(“value”),”SCA.SCAString”);
A SCAAny can even hold another SCAAny instance.
// Insert an SCAAny value to SCAAny instance
SCAAny anyval2 = new SCAAny((long)123,"SCA.SCAInt64");
anyval.setSCAAny(anyval2);

Extracting the value contained in a SCAAny


To extract a value from the SCAAny, you use the get method that corresponds to the data contained in
it. When extracting values, it is important that you pick the correct method otherwise the CLR will throw
a SystemException exception.
// Extract the value from an the SCAAny instance
try {
int int32val = anyval.getSCAInt32();
} catch (Exception ex) {
Console.WriteLine("Exception:" + ex);
}
For non-basic types, you will need to use the getSCAObject method to extract the value. This value must
be cast to the desired CLR type as shown in this example.
// Extract a Node structure value from a SCAAny instance
try {
Node node = (Node)anyval.getSCAObject();
Console.WriteLine("Extracted value: id=" + node2.id +
" x=" + node.x +
" y=" + node.y +
" z=" + node.z);
} catch (Exception ex) {
Console.WriteLine("Exception:" + ex);
}
There may be cases where the SCAAny value may hold a number of different types and you do not know
at compilation time which one it is. In this case you can use the type method to determine what type it
contains so you can choose the correct get method. The following example shows how several extractions
can be used to handle different possible types of values that may be in the SCAAny instance.
// Extract an unknown type from a SCAAny instance
int int32val;
float real32val;
if ( anyval.type() == "SCA.SCAInt32" ) {
int32val = anyval.getSCAInt32();
Console.WriteLine("int32val = " + int32val);
} else if ( anyval.type() == "SCA.SCAReal32" ) {
real32val = anyval.getSCAReal32();
Console.WriteLine("real32val = " + real32val);
210 SCA Framework User’s Guide
Mapping for SCAAny

} else {
Console.WriteLine("Unsupported type " + anyval.type());
}

Miscellaneous SCAAny methods


The SCAAny provides several miscellaneous methods that can be used to check if the SCAAny contains
any data or to flush its contents.
// Check if SCAAny is empty
If ( anyval.empty() ){
// SCAAny value is empty
}
// Flush the contents of the SCAAny which will now be empty
any.flush();
The SCAAny also implements the ToString method which allows you to get a string representation of its
contents.
// Print the information about the contents of the SCAAny
Console.WriteLine("SCAAny value is " + anyval.ToString());
Chapter 7: IDL to .Net Languages Mapping 211
Mapping for SCAResult

Mapping for SCAResult


The SCAResult type is used to return error information from calls to interface methods. It contains the
following information.
• Error code
• Message table ID
• Message number
• Message parameters

The values in a SCAResult instance can be used by the SCA Framework to format and dispatch
messages in the language appropriate for the current user. For more information on using SCAResult
for error processing see the Error Handling chapter of this manual.

SCAResult class definition


The SCAResult type is mapped to the following class:
namespace SCA {
public class SCAResult
{
// Constructors
public SCAResult();
public SCAResult(int errorCode);
public SCAResult( int errorCode, int msgTableId, int messageID;

// Setting values
public void setErrorCode( int errorCode );

// Return values
public int getErrorCode();
public int getTableID();
public int getMessageID();

// Add a parameter
public void addSCAInt8(sbyte t);
public void addSCAUInt8(byte t);
public void addSCAInt16(short t);
public void addSCAUInt16(ushort t);
public void addSCAInt32(int t);
public void addSCAUInt32(uint t);
public void addSCAInt64(long t);
public void addSCAUInt64(ulong t);
public void addSCAReal32(float t);
public void addSCAReal64(double t);
public void addSCAChar(char t);
public void addSCAString(string t);
public void addSCAWString(string t);
public void addSCABool(bool t);

// Compare all fields of SCAResult data, excluding parameters


212 SCA Framework User’s Guide
Mapping for SCAResult

public bool equals (SCAResult sr);

// Return the parameters


public SCAAnySequence getParams();

// Return true if has parameters, return false otherwise


public bool hasParams();

// Return true if the error code ==0


public bool isOk();

// Returns true if it is a system error


public bool isSystemError();

// Print raw contents of SCAResult


public void dump();

// Returns a formatted message


public override string ToString();

// Predefined SCAResult values


public static SCAResult SCASuccess = new SCAResult(0);
public static SCAResult SCAError = new SCAResult(0X7FFFFFFF);
}
}
Two predefined SCAResult values are provided when you do not need to include more detailed
information to the callers.
// Return error
return SCA.SCAResult.SCAError;
// Return success
return SCA.SCAResult.SCASuccess;
Examples of the usages of these are shown in the following sections.

Creating new SCAResult values


The following example creates SCAResult values with different levels of initialization.
// Create SCAResult with all zero values
SCA.SCAResult rstat = new SCA.SCAResult();

// Create SCAResult with only an error value


SCA.SCAResult rstat = new SCA.SCAResult(1);

// Create SCAResult with error, tableID and messageID


SCA.SCAResult rstat = new SCA.SCAResult(1,4,301);}

Resetting the error code in a SCAResult value


The error code in an existing SCAResult value can be reset as follows.
Chapter 7: IDL to .Net Languages Mapping 213
Mapping for SCAResult

// Reset error code in SCAResult


rstat.setErrorCode(201);

Adding parameters to a SCAResult value


You use one of the add methods to add a parameter to a SCAResult value.
// Add parameters to SCAResult value
rstat.addSCAInt8((sbyte)1);
rstat.addSCAInt16((short)12);
rstat.addSCAInt32((int)123);
rstat.addSCAInt64((long)1234);
rstat.addSCAUInt8((byte)2);
rstat.addSCAUInt16((ushort)23);
rstat.addSCAUInt32((uint)234);
rstat.addSCAUInt64((ulong)2345);
rstat.addSCAReal32(12.34F);
rstat.addSCAReal64(123.456);
rstat.addSCAChar('A');
rstat.addSCAString("TestString");
rstat.addSCAWString("TestWideString");
rstat.addSCABool(true);

Interrogating the contents of a SCAResult


The is Ok method provides a simple way to test if the SCAResult value has an error.

// Test if SCAResult has a non-zero error


if ( !rstat.isOk() )
// Process error
The get methods can be used to extract the error, table and message values.
// Extract the error, tableID and messageID values
int error = rstat.getErrorCode();
int tableid = rstat.getTableID();
int messageid = rstat.getMessageID();
The hasParams and getParams methods can be used to determine if the SCAResult has parameters and
to process them. The parameter values are returned in a SCAAnySequence.
// If the SCAResult has parameters, print them
if ( rstat.hasParams() ) {
for ( int i=0; i<params.size(); i++ ) {
SCA.SCAAny param = params.elementAt(i);
Console.WriteLine("Param " + i + " = " + param.ToString());
}
}
214 SCA Framework User’s Guide
Mapping for SCAResult

Miscellaneous SCAResult methods


The SCAResult also implements the ToString and dump method which allows you to get or print the
contents. The ToString method will attempt to format a message for the SCAResult value while the dump
method just prints the raw data.
// Print a string representation of the SCAAny
Console.WriteLine("SCAResult value is " + anyval.ToString());

// Print contents using the dump method


anyval.dump();
Chapter 7: IDL to .Net Languages Mapping 215
Mapping for Constants

Mapping for Constants


IDL defined constants are mapped to a struct of the same name as the constant which contains a single
fixed data value with the name value which has the value of the IDL constant.

IDL
const SCAInt32 NUM_OF_STATES = 50;

C#
public struct NUM_OF_STATES {
public const int value = (int)50;
}
The value of the constant can be referenced using the value field.
// Print value of constant defined in IDL
Consol.WriteLine("constant value = " + NUM_OF_STATES.value);
216 SCA Framework User’s Guide
Mapping for Interfaces

Mapping for Interfaces


SCA interfaces are mapped directly to CLR interfaces.
The following is a simple interface definition. This example is missing the definitions of all the required
types but they have no affect on actual interface mapping so they have been left out to simplify the
example.

IDL
interface SCAIReader : SCA::SCAIService
{
SCAVoid readModel( in SCAString name ) raises(ReaderException);
SCAINode getNode( in SCAInt32 id ) raises(ReaderException);
SCAVoid getNodeCoordinates( in SCAInt32 id,
out SCAReal32 x,
out SCAReal32 y,
out SCAReal32 z )
raises(ReaderException);
};

C#
public interface SCAIReader : SCA.SCAIService
{
void readModel(string name);
SCAINode getNode(int id);
void getNodeCoordinates(int id,
out float x,
out float y,
out float z);
}

Mapping for Interface Operations


Each interface operation (or method) is mapped to a method in the CLR interface with the same name.

Mapping for Interface Parameters


Each parameter in an IDL operation must have a direction of in, out or inout. They are mapped to C#
and Visual Basic according to the following table.

IDL direction CLR attribute C# keyword VB keyword


in In ByVal
out Out out ByRef
inout In+Out ref ByRef
Chapter 7: IDL to .Net Languages Mapping 217
Mapping for Exceptions

Mapping for Exceptions


The SCA Framework predefines three exception types, SCA.SCAException, SCA.SCAUserException
and SCA.SCASystemException. All user defined exceptions in IDL must inherit either
SCA::SCAUserException or another user-defined exception. Only single inheritance is allowed

SCAException interface
The base for all IDL defined exceptions is SCAException which is mapped to the SCA.SCAException
class.
namespace SCA{
public class SCAException: System.Exception {
// return a string to explain what message the exception carries
public string what(){…}

//Method to get SCATypeCode for this exception


public SCATypeCode getTypeCode(){…}

//Method to get raw text string for this exception


public string getText(){…}

//Method to set raw text string for this exception


public void setText(string text){…}
}
}

SCAUserException class
The SCAUserException exception adds no new data to SCAException and should be used as the base
for all user defined exceptions. It is mapped to the SCA.SCAUserException class which inherits from
the SCA.SCAException class.
namespace SCA {
public class SCAUserException: SCAException
{
public SCAUserException(){…}
}
}

SCASystemException class
The SCASystemException exception should only be used internally by the SCA Framework and adds
an error ID member to SCAException. It is mapped to the SCA.SCASystemException class which
inherits from the SCA.SCAException class.
namespace SCA {
public class SCASystemException: SCAException{
218 SCA Framework User’s Guide
Mapping for Exceptions

//Constructors
public SCASystemException() {…}
public SCASystemException(int iid) {…}
public SCASystemException(int iid, string text) {…}
public int id;
}
}

Mapping for IDL defined user exceptions


User-defined exceptions are mapped to respective classes. All the user defined members in an exception
are mapped as public fields in the exception class.

IDL
exception ReaderException : SCAUserException
{
SCAString name;
SCAString error;
};

C#
public class MyException : SCA.SCAUserException{
public MyException();
public string name;
public string error;
}
The following code shows an example of how you throw a SCA exception in C#.
ReaderException ex = new ReaderException();
ex.name = “TestInput.dat”;
ex.error = “The file does not exist”;
throw ex;
And the exception can be caught as follows.
try
{
// Code that triggers an exception
}
catch (ReaderException ex)
{
Console.WriteLine("ReaderException Caught for”);
Console.WriteLine(“File: “ + ex.name);
Console.WriteLine(“Error: “ + ex.error);
}

The IDL raises clause


An IDL interface operation may contain a raises clause to indicate what kind of exceptions the operation
may throw.
Chapter 7: IDL to .Net Languages Mapping 219
Mapping for Exceptions

IDL
interface SCAIReader : SCAIService
{
SCAVoid readModel( in SCAString name ) raises (ReaderException);
};

C#
interface TestInterface{
public void testEx();
}
Since the CLR does not support checked exceptions, the presence of a raises clause in the IDL has no
affect on any of the generated code. But, when implementing components in .NET it is still important
that the IDL definition of the interfaces that they implement contain the appropriate raises clauses. This
is because the various SCA language bridges do check the exceptions thrown and will only pass those
that have been specified. If an exception is thrown that is not specified in the raises clause, it will be
converted to a SCASystemException.
The SCASystemException exception is an unchecked exception that can always be thrown. Users do
not need to include SCASystemException or SCAException in the raises clause.
220 SCA Framework User’s Guide
Mapping for SCA Services

Mapping for SCA Services


Two types of code are generated for SCA service definitions.
• The genskeleton command is used to generate the initial implementation skeleton for a service.
The generated skeleton can then be expanded with the code required to implement the desired
behavior for the various interface operations.
• During the build process, various base or tie classes are generated which are used to link the
developer generated implementation code to the SCA Framework. This is done to reduce as
much as possible the amount of code that must be written by the developer to implement a
service. These classes also provide a level of isolation between the service’s implementation
code and the SCA Framework. This allows for future changes to be made in the interaction
between the base or tie classes and the SCA Framework without affecting the developer’s
implementation code.
The following is the IDL file for an example interface definition that will be used in this section.
#ifndef SCA_FILEREADER_FILEREADER_IDL_INCLUDED
#define SCA_FILEREADER_FILEREADER_IDL_INCLUDED

#include "SCA/Service.idl"

module SCA { module FileReader {

struct Node
{
SCAInt32 id;
SCAReal32 x;
SCAReal32 y;
SCAReal32 z;
};

exception ReaderException : SCAUserException


{
SCAString name;
SCAString error;
};

interface SCAINode;

interface SCAIReader : SCA::SCAIService


{
SCAVoid readModel( in SCAString name ) raises(ReaderException);
SCAINode getNode( in SCAInt32 id ) raises(ReaderException);
};

interface SCAINode : SCA::SCAIService


{
SCAInt32 getID();
SCAReal32 getX();
SCAReal32 getY();
SCAReal32 getZ();
Chapter 7: IDL to .Net Languages Mapping 221
Mapping for SCA Services

};

}; };
#endif
The following is the SDL for an example service that will implement these interfaces.
#ifndef FILEREADER_SDL_INCLUDED
#define FILEREADER_SDL_INCLUDED

#include "SCA/FileReader/FileReader.idl"

module SCA { module FileReader { module Impl {

service SCA.Test.FileReader {
interface SCA::FileReader::SCAIReader;
subservice NodeImpl ( in SCA::FileReader::Node node ) {
interface SCA::FileReader::SCAINode;
};
};

}; }; };
#endif

The inheritance form of implementation


In the inheritance form of implementation, the implementation classes generated by genskeleton will
inherit from base classes generated by the IDL compiler at build time. These base classes will then inherit
from the interface classes and also provide all the necessary links to the SCA Framework.
When the genskeleton command is run for the above SDL file to generate the skeleton code for the
service, it will generate two classes, FileReader which inherits from the SCAIReader interface and
FileReader_base and NodeImpl which inherits from the SCAINode interface and NodeImpl_base.
The implementation will be put in a namespace that is defined by the SDL module statements. In this
example its namespace is SCA.FileReader.Impl.
The following is the file FileReader.cs that is generated for the top-level service class.
using System.Collections.Generic;

namespace SCA { namespace FileReader { namespace Impl {

public class FileReader: FileReader_base , SCA.FileReader.SCAIReader


{
// Constructor
public FileReader (SCA.Framework.SCAIServiceProvider provider)
{
setServiceProvider(provider);
}

// Methods for interface SCA.FileReader.SCAIReader


void SCA.FileReader.SCAIReader.readModel (string name)
222 SCA Framework User’s Guide
Mapping for SCA Services

{
//implementation goes here
}

SCA.FileReader.SCAINode SCA.FileReader.SCAIReader.getNode (int id)


{
//implementation goes here
}
}

} } }
The implementation classes generated are fairly simple, but there are a couple of requirements for these
imposed by the SCA Framework. These are the requirements when using the default or inheritance form
of implementation.
• The class must inherit from the base class generated by the IDL compiler.
• The class can have only one constructor and it must have a single argument of
SCAIServiceProvider type. This argument is used by the base class to access the SCA
Framework.
• The class must implement each of the operations defined in the interfaces it supports except for
SCAIService.
As long as these requirements are met, the developer is free to make any desired modifications to these
implementation classes.
The base class FileReader_base, which will be generated by the IDL compiler when it is run during the
build process, provides the following.
• Inherits from the respective interface for each interface implemented by the service class. In this
example it will be the SCAIReader interface.
• Provides the implementation for all of the required reference counting, interface navigation and
introspection methods in the SCAIService interface that every SCA service class must
implement.
• Provides access to the SCA Framework facilities.

If the FileReader service used in this example implemented additional interfaces, the only changes to
the generated code would be the addition of the method definitions for the operations in the new
interfaces.

Implementation for subservice classes


The SDL for the FileReader service also includes the definition of a subservice NodeImpl which takes
a Node constructor argument. A separate class, NodeImpl, will be generated for the subservice class.
The format of this class is identical to the FileReader class except for the addition of an extra argument
on the class constructor and the interface methods it implements.
Following is the NodeImpl.cs class generated by the genskeleton command
Chapter 7: IDL to .Net Languages Mapping 223
Mapping for SCA Services

using System.Collections.Generic;

namespace SCA { namespace FileReader { namespace Impl {

public class NodeImpl: NodeImpl_base , SCA.FileReader.SCAINode


{
// Constructor
public NodeImpl (SCA.Framework.SCAIServiceProvider provider,
SCA.FileReader.Node node)
{
setServiceProvider(provider);
}

// Methods for interface SCA.FileReader.SCAINode


public int SCA.FileReader.SCAINode.getID ()
{
//implementation goes here
}
public float SCA.FileReader.SCAINode.getX ()
{
//implementation goes here
}
public float SCA.FileReader.SCAINode.getY ()
{
//implementation goes here
}
public float SCA.FileReader.SCAINode.getZ ()
{
//implementation goes here
}
}
} } }
Only subservice classes can have user specified constructor arguments. This is because instances of the
top-level FileReader class are instantiated by the IDL generated factory class in response to getService
calls made by the clients of the service. There is currently no way for clients to pass constructor
arguments through the getService call. On the other hand, instances of subservice classes can only be
created by the implementation code in the service. In this case the implementation is free to pass any
desired arguments to the constructors.

Creating instances of subservice classes


Instances of subservice classes can only be created by the implementation code in the service. The
following is an example implementation for the getNode method of the SCAIReader interface which
returns an instance of the SCAINode interface. The SDL definition for this service specifies that the
SCAINode interface is implemented by the NodeImpl subservice class. That means that the getNode
method needs to allocate an instance of the NodeImpl class and return the SCAINode interface on it.
The constructor for the NodeImpl class, generated by the genskeleton utility, requires two parameters.
The first parameter is the SCAIServiceProvider interface which is available in the m_provider variable
in the base class. The second argument is an instance of the Node structure that was specified as a
constructor argument in the SDL.
224 SCA Framework User’s Guide
Mapping for SCA Services

SCAINode FileReader::getNode(const SCAInt32 id)


{
// Find and initialize the node which cooresponds to ID
Node node = …

// Return a new subservice class instance for this node


NodeImpl spNode = new NodeImpl(m_provider,node);
return (SCAINode)spNode;
}

The ServiceAccess interface


The base classes generated by the IDL compiler will always implement the SCA.ServiceAccess
interface. This interface is the link between the implementation of the service and the SCA Framework.
The following is the definition of the ServiceAccess interface:
namespace SCA{
public interface ServiceAccess {
SCAIService getService(string name, string attr) ;
void setServiceProvider(SCAIServiceProvider provider);
SCA.Framework.SCAIServiceProvider getServiceProvider();
}
}
If the implementation of the service needs to load another SCA service, then the getService method in
the ServiceAccess class is used.
SCAIService spSvc;
spSvc = getService(“Test.Service.Name”, “”)

The delegation form of implementation


There may be situations where the inheritance form of implementation is inconvenient because of other
requirements in your classes. An example is if you want to inherit the implementation class from your
own base class. This is not possible with the inheritance form of implementation because the CLR does
not allow multiple inheritance and the implementation class must inherit from the base class generated
by the IDL compiler. To resolve this, the delegation form of implementation can be used. With
delegation, the skeleton classes generated by the IDL compiler do not inherit from a base or interface
classes. Instead the base class is replaced with a separate tie class which inherits from the interface class
and provides all the necessary links to the SCA Framework. When a new instance of the service is
requested, an instance of the tie class is constructed and returned. The tie class will internally construct
a separate instance of the implementation class when it is initialized. Interface calls to the methods in the
tie class are then delegated to the methods in the implementation class that it wraps.
You use the delegate keyword in the SDL file to select the delegation form of implementation. The
following is the FileReader.cs class that is generated for the top-level service class when delegation is
used. The lines in a darker shade of gray are the lines that are different from the format of this file when
the inheritance form of implementation is used.
Chapter 7: IDL to .Net Languages Mapping 225
Mapping for SCA Services

using SCA.FileReader;

namespace SCA { namespace FileReader { namespace Impl {

public class FileReader


{
// Constructor
public FileReader (FileReader_tie tie)
{
m_tie = tie;
}

// Methods for interface SCA.FileReader.SCAIReader


public void readModel (string name)
{
//implementation goes here
}

public SCA.FileReader.SCAINode getNode (int id)


{
//implementation goes here
}

protected FileReader_tie m_tie;


}
} } }
Notice that class no longer inherits from a base class and as a result the interface methods names are not
longer in the scope of the interface. Because there is no requirement that the implementation inherit from
an IDL generated base class, you are fee to use any inheritance structure you required. The class also
saves a reference to the tie class which is required to access the ServiceAccess interface that it
implements.
Since a subservice was also defined in the SDL file, NodeImpl is also created as a delegated subservice.
A separate tie class named NodeImp_tie is created for the subservice which creates an instance of the
NodeImpl generated by the genskeleton command. Therefore, when creating an instance of the
subservice, the user will have to create an instance of the tie class. The following illustrates how the
getNode method would be implemented when delegation is used.
public SCA.FileReader.SCAINode getNode (int id)
{
// Find and initialize the node which cooresponds to ID
Node node = …

// Return a new subservice class instance for this node


NodeImpl_tie spNode = new NodeImpl_tie(m_tie.getServiceProvider(),
node)
return (SCAINode)spNode;
}
226 SCA Framework User’s Guide
Mapping for SCA Services

Singleton Services
It is also possible to indicate that the service is a singleton in the SDL. The use of this keyword has no
affect on any of the implementation skeletons generated for a service. The processing of singleton
services is handled entirely in the factory support code that is generated when the service is built. It is
important to remember that even so the generated skeletons are the same; the implementation code for a
singleton service may need to be different. Because multiple clients may be sharing the same instance of
the service, the code needs to make sure this is done in a safe manner.

Aggregation
The .NET mapping also supports the aggregates and aggregated keywords in the SDL. The affect of
these on the mapping for service objects is an advanced topic that is covered in a separate manual.
Chapter 7: IDL to .Net Languages Mapping 227
Mapping for SCA Components

Mapping for SCA Components


The .NET mapping uses normal assemblies for SCA components. The only code required for a SCA
component is support code generated by the IDL compiler during the build process. This code is used by
the SCA Framework to initialize the component and expose the services it provides when the component
is loaded at runtime. There is no code that the developer needs to create for a component.

Embedded Components
Support for embedded components is requested with the embedded option in the CDL. Currently
embedded components are not supported in .NET.
228 SCA Framework User’s Guide
Mapping for SCA Components
Chapter 8: IDL to Python Language Mapping
SCA Framework User’s Guide

8 IDL to Python Language Mapping



Introduction 230

Mapping for Identifiers 232
 Mapping for Modules 233

Mapping for Basic Types 234

Mapping for Enumerated Types 237
 Mapping for Structures 238

Mapping for Arrays 240

Mapping for Sequences 241
 Mapping for Type Aliases 242

Mapping for TypeCode 243

Mapping for SCAAny 244
 Mapping for SCAResult 248

Mapping for Constants 252

Mapping for Interfaces 253
 Mapping for Exceptions 258
 Mapping for SCA Services 261

Mapping for SCA Components 262

The SCA Module 263
 Accessing IDL Type Definitions from Python 264

Running Python Scripts 267
230 SCA Framework User’s Guide
Introduction

Introduction
Python scripting in the SCA Framework allows a SCA enabled application to execute one or more
Python scripts at runtime. Users can also access SCA services from the Python command line. In both
cases, the Python scripts can load SCA services and invoke their methods. SCA interfaces can also be
implemented in Python scripts.
Python is a type-less language which means that you do not declare variables to be of a specific type.
Instead, any Python variable can assume any type at runtime. In addition to this, the SCA mappings of
types in many cases directly use native Python types. As a result many of the type names defined in IDL
never appear in Python. Instead you just use the native Python types as appropriate. But because Python
does no type checking, you have to be careful when calling a SCA interface to make sure the arguments
are Python objects of the correct type. If you try to pass a Python object to a SCA interface that cannot
be converted to the required SCA type, then the SCA language bridge will throw a
SCASystemException exception.
The following table summarizes the data type mappings between IDL and Python types. The following
sections of this chapter will provided the details on each mapping.

IDL Type Python Type


SCA::SCAInt8 plain integer
SCA::SCAUInt8 plain integer
SCA::SCAInt16 plain integer
SCA::SCAUInt16 plain integer
SCA::SCAInt32 plain integer
SCA::SCAUInt32 long integer
SCA::SCAInt64 long integer
SCA::SCAUInt64 long integer
SCA::SCAReal32 float
SCA::SCAReal64 float
SCA::SCAChar string of length 1
SCA::SCAString string
SCA::SCAWChar Unicode string of length 1
SCA::SCAWString Unicode string
SCA::SCABool plain integer
SCA::SCAAny SCA.SCAAny class
SCA::SCATypeCode SCA.SCATypeCode class
SCA::SCAVoid None
SCA::SCAResult SCA.SCAResult class
Chapter 8: IDL to Python Language Mapping 231
Introduction

IDL Type Python Type


sequence list
array list of the array size (1D array)

list of lists of array size (2D array)


enum plain integer
struct SCA defined structure type
interface SCA defined interface type or Python class inheriting from SCAIServiceBase
exception SCA.SCAException class or SCA defined exception type
232 SCA Framework User’s Guide
Mapping for Identifiers

Mapping for Identifiers


IDL identifiers are mapped to Python with no change. For example:

IDL
struct Node
{
SCAInt32 id;
SCAReal32 x;
SCAReal32 y;
SCAReal32 z;
};

Python
node = Node()
node.id = 123
node.x = 2.345
node.y = 3.456
node.z = 4.567
Remember that most IDL defined identifies will never appear in the Python mappings. The only IDL
defined types whose identifiers will appear are enumerators, structures, exceptions and constants. This
will be described in more detail in the following sections.
Chapter 8: IDL to Python Language Mapping 233
Mapping for Modules

Mapping for Modules


IDL defined types are created in Python modules with the same name as the fully qualified IDL name
scope. When referencing an interface or an IDL defined type, the fully qualified name should be used.

IDL
module SCA { module Test {
struct Node
{
SCAInt32 id;
SCAReal32 x;
SCAReal32 y;
SCAReal32 z;
};
}; };

Python
node = SCA.Test.Node()
234 SCA Framework User’s Guide
Mapping for Basic Types

Mapping for Basic Types


SCA basic types are mapped directly to native Python types. Also since Python is a type-less language,
the SCA basic type names have no purpose in Python and are not exposed.
The mapping between SCA basic types and Python type happens in two directions. If the Python script
is calling an interface method written in a different language, the SCA language bridge maps any input
type in a two step process.
• The Python value is converted to a C value
• The range of the C value is checked to be consistent with the SCA type

These conversions use the functions provided by the Python interpreter and are quite liberal. For example
you they will convert a Python plain integer, long integer, floating point or even a string value to a C long
value as long as the conversion makes sense. The following examples show some valid types of
conversions that would be acceptable when making a call to an interface method that has an input
SCAInt32 value.
inf.method(123)
inf.method(long(123))
inf.method (123.0)
inf.method ('123')
But the following calls would throw a SCASystemException exception because they do not represent a
valid integer value.
inf.method (123.45)
inf.method ('123.45')
The following table shows the Python types and value ranges that can be converted to each SCA basic
type.

IDL Type Python Types Legal Range


IDL Type Python Types Legal Range
SCA::SCAInt8 integer, long, float, string -128,127
SCA::SCAUInt8 integer, long, float, string 0,255
SCA::SCAInt16 integer, long, float, string -32768,32767
SCA::SCAUInt16 integer, long, float, string 0,65535
SCA::SCAInt32 integer, long, float, string -2147483648,2147483647
SCA::SCAUInt32 integer, long, float, string 0,4294967295
SCA::SCAInt64 integer, long, float, string -9223372036854775808,

9223372036854775807
SCA::SCAUInt64 integer, long, float, string 0,18446744073709551615
Chapter 8: IDL to Python Language Mapping 235
Mapping for Basic Types

IDL Type Python Types Legal Range


SCA::SCAReal32 integer, long, float, string -3.4028235×1038,

3.4028235×1038
SCA::SCAReal64 integer, long, float, string -1.7976931348623157×10308,

1.7976931348623157×10308
SCA::SCAChar string string length 1
SCA::SCAString string
SCA::SCAWChar string, string length 1

Unicode string
SCA::SCAWString string,

Unicode string
SCA::SCABool integer, long, float, string, True, False True = 0

False != 0

After making the actual call to the interface method, any output values must then be converted back to a
Python value. This conversion is much simpler because the SCA types are already strongly typed and no
value checking is required. The following table shows the Python type that will be created for each value
type.

IDL Type Python Type


SCA::SCAInt8 plain integer
SCA::SCAUInt8 plain integer
SCA::SCAInt16 plain integer
SCA::SCAUInt16 plain integer
SCA::SCAInt32 plain integer
SCA::SCAUInt32 long integer
SCA::SCAInt64 long integer
SCA::SCAUInt64 long integer
SCA::SCAReal32 floating point
SCA::SCAReal64 floating point
SCA::SCAChar string
SCA::SCAString string
SCA::SCAWChar Unicode string
236 SCA Framework User’s Guide
Mapping for Basic Types

IDL Type Python Type


SCA::SCAWString Unicode string
SCA::SCABool integer 0 or 1
Chapter 8: IDL to Python Language Mapping 237
Mapping for Enumerated Types

Mapping for Enumerated Types


Each enumerator of an enumerated type is mapped to a Python integer with the appropriate value as show
in this example.

IDL
module SCA { module Test {
enum Color {
RED,
GREEN,
BLUE
};
}; };

Python
print 'Enumerator Color.RED =',SCA.Test.RED
print 'Enumerator Color.GREEN =',SCA.Test.GREEN
print 'Enumerator Color.BLUE =',SCA.Test.BLUE
The following output would be generated by this code
Enumerator Color.RED = 0
Enumerator Color.GREEN = 1
Enumerator Color.BLUE = 2
Since the mapping for enumerators is to plain Python integers which are not write protected, care should
be taken to not accidentally change their values.
The actual enumeration type, Color in this example, is not required in Python and not exposed in the
mapping.
238 SCA Framework User’s Guide
Mapping for Structures

Mapping for Structures


Each IDL defined structure is mapped to a Python class which contains a data value for each member.

IDL
module SCA { module Test {
struct Node
{
SCAInt32 id;
SCAReal32 x;
SCAReal32 y;
SCAReal32 z;
};
}; };

Python
node = SCA.Test.Node()
node.id = 123
node.x = 2.345
node.y = 3.456
node.z = 4.567
print 'node =',node.id,node.x,node.y,node.z
The structure objects also have a couple of special attributes that can be used to reflect on their definition.

Attribute Value
__doc__ String representation of definition
__name__ Name of structure
__members__ Python list with data member names

The following example shows how these attributes can be used.

Python
print '\nStructure name is',node.__name__
print '\n',node.__doc__
print '\nStructure members are',node.__members__
Would produce the following output:
Structure name is SCA.Test.Node

Structure SCA.Test.Node {
SCA.SCAInt32 id
SCA.SCAReal32 x
SCA.SCAReal32 y
SCA.SCAReal32 z
}
Chapter 8: IDL to Python Language Mapping 239
Mapping for Structures

Structure members are ['id', 'x', 'y', 'z']


Because Python is type-less, each member in the structure is defined as a generic Python object. When
initializing the structure, you need to be careful that it can be converted to the required SCA type when
the structure passes through a SCA language bridge. If it cannot, then a SCASystemException exception
will be thrown at that time. The following IDL contains a structure with an array member to demonstrate
this.

IDL
module SCA { module Test {
struct Node2
{
SCAInt32 id;
SCAReal32 loc[3];
};
}; };

Python
node = SCA.Test.Node2()
node.id = 123
node.loc = [2.345,3.456,4.567]
When using structures, you should remember that Python assignment statements only generate a new
reference to the data. As a result, the change to the node2.id value in the following example will also
cause the value of the node1 reference to change.
node1 = SCA.Test.Node()
node1.id = 1
node2.id = node1
node2.id = 999
To make the node2 value a separate copy of the data so any changes to it will not affect the node1 value,
you can use the following code.
node1 = SCA.Test.Node()
node1.id = 1
node2.id = SCA.Test.Node(node1)
node2.id = 999
240 SCA Framework User’s Guide
Mapping for Arrays

Mapping for Arrays


Two types of array definitions are supported in IDL. Fixed size arrays must have their size defined in the
IDL and can never change. Dynamic arrays allow you to delay the specification of the array size until it
is actually allocated. Only arrays of rank 1 or 2 are supported.
Both types of arrays are mapped directly to native Python lists. As a result, the IDL defined type name
will not appear in the Python mapping.

Fixed size arrays


In Python, arrays are represented by normal Python lists. When arrays are created you need to make sure
that their length is correct and that each entry of the list can be converted to the required SCA type. The
array sizes and types are not checked when making calls within Python but if making a call to an interface
implemented in another language through a SCA language bridge, a SCASystemException will be
thrown if the length is incorrect or any of the entries cannot be converted.

IDL
typedef SCAInt32 Date[3];

Python
date = [9,1,2009]
Two dimensional IDL arrays are represented as a list of lists.

IDL
typedef SCAInt64 Matrix[5][5];

Python
matrix = []
for i in range(5):
column = []
for j in range(5):
column.append((i+1)*10 + (j+1))
matrix.append(column)

Dynamic Arrays
Dynamic Arrays are handled the same way as fixed size arrays except they may have any desired size.
Dynamic arrays exist primarily to provide more optimized code in other languages supported by the SCA
framework.
Chapter 8: IDL to Python Language Mapping 241
Mapping for Sequences

Mapping for Sequences


In Python, sequences are represented by normal Python lists. When sequences are created you need to
make sure that each entry of the list can be converted to the required SCA type. The entry types are not
checked when making interface calls within Python but if making a call to another language through a
SCA language bridge a SCASystemException will be thrown if any of the entries cannot be converted.

IDL
typedef sequence<SCAReal64> SCAReal64Sequence;

Python
# Initialize contents of the sequence
seq = []
for i in range(100):
seq.append(i+1+.2)

# Print contents of the sequence


print seq
Since sequences are mapped directly to native Python lists, the IDL defined type name will not appear in
the Python mapping.
242 SCA Framework User’s Guide
Mapping for Type Aliases

Mapping for Type Aliases


A typedef is used in SCA IDL to define a sequence, an array or an alias for an existing type. The Python
mapping for sequences and arrays has already been discussed in the previous sections.
The use of the IDL typedef to create a new name for an existing type normally does not have a meaning
in Python because it is a type-less language. As a result most of the IDL defined type names never appear
in Python. The one exception to this is for structures where actual Python classes are created to represent
the IDL type. In this case, any aliases defined for these types in IDL will also be available in Python as
shown in the following examples.

IDL
module SCA { module Test {
struct TimeDef
{
SCAInt32 hour;
SCAInt32 minute;
SCAInt32 second;
};
typedef TimeDef LocalTime;
typedef TimeDef GMTTime;
}; };

Python
time = SCA.Test.TimeDef()
localtime = SCA.Test.LocalTime()
gmttime = SCA.Test.GMTTime()
Chapter 8: IDL to Python Language Mapping 243
Mapping for TypeCode

Mapping for TypeCode


The SCATypeCode type is a special type used by the SCA Framework to describe the details about each
IDL defined type. The SCA Framework creates instances of the SCATypeCode using XML data
generated by the IDL compiler. Each instance of the SCATypeCode contains the complete description
of one IDL defined type. For example, the description of a structure would include the name and type for
each of its members.
The SCATypeCode type is treated in IDL as a basic type and it can appear anywhere in the IDL where
a basic type can appear. For example it could be the member of a structure or one of the arguments in an
interface method.
In Python a type code value is represented by the SCATypeCode class. The definition of a
SCATypeCode contains a pair of values. These include a SCATypeCodeID value that indicates the type
of data and a description of the type. The contents of the description depend on the value of the
SCATypeCodeID. The SCATypeCode class is fairly complex and will not be discussed in detail here.
The data contained in this class is mostly used internally within the SCA Framework.
If you need to access these detailed type definitions you are encouraged to use the
SCA.Framework.Reflection service that is describe in detail in the SCA SDK Advanced Features
manual.
244 SCA Framework User’s Guide
Mapping for SCAAny

Mapping for SCAAny


The SCAAny is a container data type which can hold a single value of any other arbitrary IDL data type.
Only values for types that are defined in IDL can be stored in a SCAAny. This is because the SCAAny
design requires a SCATypeCode value to describe the data it holds and these are only generated by the
IDL compiler and will not exist for types that are not defined in IDL.
The normal mapping for the SCAAny type in the languages supported by SCA fulfills two important
requirements:
• It must handle types in a type-safe manner.
• It must handle values for complex types that are not known at compile time.

The first requirement covers the typical usage of the SCAAny type, the insertion of typed values into the
SCAAny and the type-safe extraction of the values. Because of the type-less nature of Python, many of
the type-safe features of the SCAAny provided in other languages are not supported in Python. More
details on what type-safe features are supported are discussed later in this section.
The second requirement covers situations like the need to extract data from the SCAAny when you do
not know the type of data it contains. In this case the receiver must be able to determine information about
what type of data the SCAAny contains. To achieve this, SCAAny contains a pair of values that includes
the actual value of the data and a description of its type. The type information, contained in a
SCATypeCode value, can then be inspected to determine the details on the value stored in the SCAAny
instance.

The SCAAny class definition


The Python mapping for the IDL type SCAAny is pretty simple and is implemented by the
SCA.SCAAny class. The methods for the class are shown below.
class SCAAny:

# Attributes
m_type = None
m_data = None

# Initialize the SCAAny


def __init__(self, data=None, tc=None):

# Reset the value in the SCAAny


def setValue(self, data=None, tc=None):

# Return the type of data in the SCAAny


def getType(self):

# Return the data in the SCAAny


def getData(self):

# Determine if the SCAAny has data


def empty(self):
Chapter 8: IDL to Python Language Mapping 245
Mapping for SCAAny

# Flush the SCAAny


def flush(self):

# Methods to format contents


def dump(self):
def __str__(self):
Examples of using the SCAAny are show in the following sections.

Creating new SCAAny values


The following example creates an empty SCAAny value.
# Create an empty SCAAny instance
any = SCA.SCAAny()
To create a new SCAAny value that contains a value you can use the constructor which takes a Python
value and an optional string description of the type. The form you choose depends on the type of the
Python value you provide. The following table shows the Python types which support an automatic
mapping to a SCA type. For these types you only need to provide the Python object when creating a
SCAAny instance.

Python type SCA Type used


Plain Integer SCA.SCAInt32
Long integer SCA.SCAInt64
Boolean SCA.SCABool
Floating SCA.SCAReal64
String SCA.SCAString
Unicode SCA.SCAWString
SCA.SCATypeCode SCA.SCATypeCode
SCA.SCAAny SCA.SCAAny
SCA.SCAResult SCA.SCAResult
SCA Structure Appropriate structure type
SCA Interface Appropriate interface type

The following shows some examples of this.


# Create a SCAAny instance which contains a SCAInt32 value
any = SCA.SCAAny(123)

# Create a SCAAny instance which contains a SCABool value


any = SCA.SCAAny(True)
246 SCA Framework User’s Guide
Mapping for SCAAny

# Create a SCAAny instance which contains a structure value


node = SCA.Test.Node()
node.id = 123
node.x = 1.0
node.y = 2.0
node.z = 3.0
any = SCA.SCAAny(node)
If the Python value is not one of the types that supports an automatic mapping or if you want a different
mapping then you will need to add the type description to explicitly specify the type. An example of this
is a Python plain integer value which will normally map to a SCAInt32 value but you wish to make it a
SCAInt64 value instead.
# Create a SCAAny instance which contains a SCAInt64 value
any = SCA.SCAAny(123,'SCA.SCAInt64')
Another example of this would be inserting a Python list that has no automatic mapping defined.
# Create a SCAAny instance which contains a SCA.Test.Date value
date = [9,1,2009]
any = SCA.SCAAny(date,'SCA.Test.Date')
When both a Python object and the type description are given, some limited checking will be done to
ensure that the two are consistent. For example for an array a check is made to be sure the Python object
is a list and that its length is correct but the individual entries in the list will not be checked. The complete
checking will be performed when the data is actually used when making an interface method call through
a SCA language bridge.

Inserting values into existing SCAAny values


You can also insert a value into an existing SCAAny instance. If the instance already holds a value it will
be replaced with the new value. Remember that the SCAAny can only hold a single value at a time.
Inserting values into an existing SCAAny instance follows the same pattern that was described
previously for constructing new SCAAny values and used the setValue method.
# Insert a SCAInt32 value into a SCAAny instance
Any.setValue(123)

# Insert a SCA.Test.Node value into a SCAAny instance


node = SCA.Test.Node()
node.id = 123
node.x = 1.0
node.y = 2.0
node.z = 3.0
any.setValue(node)

# Insert a SCA.Test.Date value into a SCAAny instance


date = [9,1,2009]
any.setValue(date,'SCA.Test.Date')
A SCAAny can even hold another SCAAny instance.
Chapter 8: IDL to Python Language Mapping 247
Mapping for SCAAny

# Insert an SCAAny value to SCAAny instance


any2 = SCA.SCAAny(123)
any.setValue(any2)

Extracting the value contained in a SCAAny


To extract a value from the SCAAny, you use the getData method.
# Extract a SCAInt32 from a SCAAny instance
val = any.getData()
print 'Extracted value is',val
There may be cases where the SCAAny value may hold one of a number of different types and you do
not know beforehand which one it contains. In this case you can use the getType method to determine the
type so you can process the data correctly. The getType method returns a SCA.SCATypeCode value
which describes the type. The following example shows how the type of the value can be tested at runtime
to handle different possibilities.
# Extract an unknown type from a SCAAny instance
typeid = any.getType().getTypeID()
if typeid == SCA.TCID_Int32:
print 'SCAInt32 value is',any.getData()
elif typeid == SCA.TCID_Real64:
print 'SCAReal64 value is',any.getData()
elif typeid == SCA.TCID_String:
print 'SCAString value is',any.getData()
else:
print 'Unsupported type',any.getType().getTypeDesc()

Miscellaneous SCAAny methods


The SCAAny provides several miscellaneous methods that can be used to check if the SCAAny contains
any data or to flush its contents.
# Check if SCAAny is empty
if any.empty():
print 'The SCAAny is empty'

# Flush the contents of the SCAAny which will now be empty


any.flush()
The SCAAny also implements the dump method which allows you print its contents and the __str__
method which allows you to convert its value to a string.
# Print the information about the contents of the SCAAny
any.dump()
print str(any)
248 SCA Framework User’s Guide
Mapping for SCAResult

Mapping for SCAResult


The SCAResult type is used to return error information from calls to interface methods. It contains the
following information
• Error code
• Message table ID
• Message number
• Message parameters

The values in a SCAResult instance can be used by the SCA Framework to format and dispatch
messages in the language appropriate for the current user. For more information on using SCAResult
for error processing see the Error Handling chapter of this manual.

SCAResult class definition


The Python mapping for the IDL type SCAResult is implemented by the SCA.SCAResult class. The
methods for the class are shown below.
class SCAResult:

# Supported attributes
m_errorCode=0
m_msgTable=0
m_messageID=0
m_params=None

# Initialization
def __init__(self, eid=0, tid=0, mid=0, params=None):

# Setting values
def setErrorCode(self,errorCode):

# Return values
def getErrorCode(self):
def getTableID(self):
def getMessageID(self):

# Add a new parameter


def addSCAInt8(self,value):
def addSCAUInt8(self,value):
def addSCAInt16(self,value):
def addSCAUInt16(self,value):
def addSCAInt32(self,value):
def addSCAUInt32(self,value):
def addSCAInt64(self,value):
def addSCAUInt64(self,value):
def addSCAReal32(self,value):
def addSCAReal64(self,value):
def addSCAChar(self,value):
Chapter 8: IDL to Python Language Mapping 249
Mapping for SCAResult

def addSCAString(self,value):
def addSCAWString(self,value):
def addSCABool(self,value):
def addParam(self, anyvalue):

# Compare all fields of SCAResult data, excluding parameters


def equals(self, obj):

# Return the parameters


def getParams(self):

# Return true if has parameters, return fals otherwise


def hasParams(self):

# Return true if the error code == 0


def isOK(self):

def SCABool(self):

# Return true if it is a system error


def isSystemError(self):

# Print the raw contents of the SCAResult


def dump(self):

# Return a formatted message


def __str__(self):
Two predefined SCAResult values are provided to indicate a simple success or error when you do not
need to include more detailed information to the callers.
// Return error
return SCA.SCAError
// Return success
return SCA.SCASuccess
Examples of the usages of these are shown in the following sections.

Creating new SCAResult values


The following example creates SCAResult values with different levels of initialization.
# Create SCAResult with all zero values
rstat = SCA.SCAResult()
# Create SCAResult with only an error value
rstat = SCA.SCAResult(1)
# Create SCAResult with error, tableID and messageID
rstat = SCA.SCAResult(1,4,301)

Resetting the error code in a SCAResult value


The error code in an existing SCAResult value can be reset as follows.
250 SCA Framework User’s Guide
Mapping for SCAResult

# Reset error code in SCAResult


rstat.setErrorCode(201)

Adding parameters to a SCAResult value


You use one of the add methods to add a parameter to a SCAResult value. There is a separate method
for each basic type that is supported as a parameter value.
# Add parameters to SCAResult value
rstat.addSCAInt8(1)
rstat.addSCAInt16(12)
rstat.addSCAInt32(123)
rstat.addSCAInt64(1234)
rstat.addSCAUInt8(2)
rstat.addSCAUInt16(23)
rstat.addSCAUInt32(234)
rstat.addSCAUInt64(2345)
rstat.addSCAReal32(12.34)
rstat.addSCAReal64(123.456)
rstat.addSCAChar('A')
rstat.addSCAString('TestString')
rstat.addSCAWString('TestWideString')
rstat.addSCABool(True)
You can also use the addParam method to add a parameter which takes a SCAAny value.
rstat.addParam(SCA.SCAAny('TestString'))
You can even create a SCAResult value and add parameters in one operation. But in this case you can
only user parameter values that have already been inserted into SCAAny instances.
params = []
params.append(SCA.SCAAny("TestString"))
params.append(SCA.SCAAny(123))
rstat = SCA.SCAResult(1,4,301,params)

Interrogating the contents of a SCAResult


The is Ok method provides a simple way to test if the SCAResult value has an error.
# Test if SCAResult has a non-zero error
if not rstat.isOk():
print 'The SCAResult contains an error'
The get methods can be used to extract the error, table and message values.
# Extract the error, tableID and messageID values
error = rstat.getErrorCode()
tableid = rstat.getTableID()
messageid = rstat.getMessageID()
The hasParams and getParams methods can be used to determine if the SCAResult has parameters and
to process them. The parameter values are returned in a SCAAnySequence.
Chapter 8: IDL to Python Language Mapping 251
Mapping for SCAResult

# If the SCAResult has parameters, print them


if rstat.hasParams():
params = rstat.getParams()
for (i,param) in zip(range(len(params)),params):
print 'Param',i,'=',str(param)

Miscellaneous SCAResult methods


The SCAResult also implements the __str__ and dump methods which allow you to get or print the
contents. The __str__ method will attempt to format a message for the SCAResult value using the
MessageDispatcher service which is described in the Error Handling chapter of this manual. The dump
method will just print the raw data contained in the SCAResult value.
# Print a string representation of the SCAAny
print 'SCAResult value is ' + str(rstat)

# Print contents using the dump method


rstat.dump()
252 SCA Framework User’s Guide
Mapping for Constants

Mapping for Constants


IDL defined constants are mapped directly to appropriate Python values in the module they are defined
in. Since the mapping for constants is to plain Python values which are not write protected, care should
be taken to not accidentally change their values.

IDL
module SCA { module Test {
const SCA::SCAInt32 NUM_OF_STATES = 50;
}; };

Python
# Print value of constant defined in IDL
print 'Constant value = ',SCA.Test.NUM_OF_STATES
Chapter 8: IDL to Python Language Mapping 253
Mapping for Interfaces

Mapping for Interfaces


There are two different Python mappings for SCA interfaces depending on what language they are
implemented in.
• SCA interfaces implemented in a language other than Python are mapped to a special SCA
proxy class.
• Interfaces implemented in Python are mapped to a normal Python class that inherits from the
SCA.SCAIServiceBase class.
Since interfaces are either mapped to an instance of a generic proxy class or to a user provided Python
class, the IDL interface names are not used in Python and are not exposed. The only required references
to interface names are using string types which contain their name.
The following is a simple interface definition that will be used in this section to demonstrate the use of
SCA interfaces in Python.
IDL
module SCA { module Test {
typedef SCAInt32 Date[3];
interface SCAITestInterface : SCA::SCAIService
{
SCAInt32 testInt32(in SCAInt32 inval,
out SCAInt32 outval,
inout SCAInt32 inoutval);
Date testDate(in Date inval,
out Date outval,
inout Date inoutval);
SCAInt32 testNoArg();
};
}; };

Mapping for Interface Operations


Each interface operation (or method) is mapped to a method in the Python class with the same name.
There is one exception to this rule. Since Python does not allow a class attribute with the name print, if
the IDL method name is print, it will be mapped to _print in Python.

Special Interface Attributes


The interface mappings also provide a couple of special attributes that can be used to reflect their
definition.

Attribute Value
__doc__ Information about interface object
__methods__ Python list with names of methods
254 SCA Framework User’s Guide
Mapping for Interfaces

The following example shows how these attributes can be used assuming you have an instance of a
Python mapping to the SCA.Test.SCAITestInterface interface.

Python
# Variable sp points to a SCAITestInterface interface
print sp.__doc__
for meth in sp.__methods__:
print 'method ',meth
Would produce the following output:
SCAPyInterface object for interface SCA.Test.SCAITestInterface
method addReference
method releaseReference
method getInterface
method getImplName
method getInstanceID
method testInt32
method testDate
method testNoArg

Mapping for Interface Parameters


The Python language does not support the concept of output arguments so the handling of arguments in
calls to interface methods must be a bit different. Only arguments with an IDL defined direction of in or
inout should appear in the argument list. This is because these are the only type of arguments that have
an input value. The arguments should maintain the same relative order as specified in the IDL. Each
interface call will normally return a tuple of values. The first member of the tuple is always the return
value of the method unless it is a SCAVoid. The remaining values in the tuple are any arguments with
an IDL defined direction of inout or out. Once again these will maintain the same relative order as
specified in the IDL. Note that arguments with a direction of inout appear in both the argument list and
the return tuple.
The following example calls the testInt32 method of the SCAITestInterface interface. This method has
an argument of each of the supported directions plus a return value to show how they are handled in
Python.
inval = 1
inoutval = 3
(retval,outval,inoutval) = splist.testInt32(inval,inoutval)
print 'Call results: inval=%d outval=%d inoutval=%d retval=%d' %
(inval,outval,inoutval,retval)
Notice the actual call only passes the arguments with a direction of in and inout which are the ones with
input values. The argument with the out direction is not passed as an argument in the call. The return
value from the call is a tuple which contains the return value and the arguments with a directions of out
or inout.
While Python does not support the concept of output arguments it does support mutable arguments which
act like arguments with a inout direction. An example of this is an argument which is a Python list type.
Chapter 8: IDL to Python Language Mapping 255
Mapping for Interfaces

Some SCA types map to mutable Python types. Examples of these are arrays and sequences which map
to Python lists. Even so these types of arguments could be mapped to take advantage of the fact that they
are mutable, this is not done. If this was done then a different set of mapping rules would be used for
different parameter types and this would be confusing. As a result, even for SCA types which map to
mutable Python types, a parameter with a inout direction should still appear in both the argument list and
the return tuple. This is shown with the following example.
# Test with mutable arguments
indate = [11,12,13]
inoutdate = [31,32,33]
(retdate,outdate,inoutdate) = splist.testDate(indate,inoutdate)
print 'Call results: inval=%s outval=%s inoutval=%s retval=%s' %
(indate,outdate,inoutdate,retdate)
If the total number of return values and arguments with a direction of out or inout is only one, then the
single value will be returned directly instead of in a tuple of length one. This is demonstrated in the
following example.
# Test with single value return
retval = splist.testNoArg()
print 'Call results: retval=%d' % retval
You can also use keyword arguments when calling interface methods. In this case the order of the
arguments is not important, but you need to make sure that a value for each required argument is supplied.
# Test with keyword arguments
ival = 1
ioval = 3
(rval,oval,ioval) = splist.testInt32(inoutval=ioval,inval=ival)
print 'Call results: inval=%d outval=%d inoutval=%d retval=%d' %
(ival,oval,ioval,rval)

Use of getInterface in Python


Since Python is a type-less language, the use of casting for interface navigation which is supported by
other language is not available in Python. Instead you must always make explicit getInterface calls to
obtain the desired interface pointer. Every SCA interface mapping provides a getInterface method. This
is true if the interface object is represented by a SCA proxy object or a user provided Python class that
inherits from the SCA.SCAIServiceBase class. The following example shows how this is done.
import SCA
svc = SCA.getService('ServiceName')
(ret,sp) = svc.getInterface('SCA.Test.SCAITestProcessor')
The important thing to remember here is that the getService routine returns a SCA.SCAIService
interface. You must then make a getInterface call on this object to obtain the interface that you really
need.
256 SCA Framework User’s Guide
Mapping for Interfaces

Implementing SCA Interfaces


Currently you cannot implement a normal SCA service in Python. But it is still possible to implement a
SCA interface in Python. A common pattern where this is needed is the listener pattern. Consider the
following IDL.
IDL
module SCA { module Test {
interface SCAITestListener : SCA::SCAIService
{
void notify(in SCA::SCAString msg);
};
interface SCAITestProcessor : SCA::SCAIService
{
void registerListener(in SCAITestListener spListener);
SCA::SCAResult process();
};
}; };
The service that implements the SCAITestProcessor interface is using a listener interface. Any client of
this service is required to implement the SCAITestListener interface and register it with the service. The
service can then use this interface to make calls back into the client as required. This means that if the
client using this service is written in Python, then it must be able to implement the listener interface.
A SCA interface can be implemented with a normal Python class. The class must follow the following
rules.
• The class must inherit from the SCA.SCAIServiceBase class provided with the SCA
framework.
• The initialization routine in the implementation class must explicitly call the initialization
routine of the SCA.SCAIServiceBase class. The arguments for this call must be a list with the
names of interfaces that the class will implement.
• The class must implement each method in each of the interfaces that are implemented. This also
includes methods in any interfaces that they inherit from. You do not need to implement the
methods in SCA.SCAIService because these are implemented in SCA.SCAIServiceBase class.
The following example shows a simple Python class that will implement the listener interface.
class MyPyImpl(SCA.SCAIServiceBase):

def __init__(self):
interfaces = ['SCA.Test.SCAITestListener']
SCA.SCAIServiceBase.__init__(self,interfaces)

def notify(self,msg):
print 'MyPyImpl::notify -',msg
The __init__ routine in SCA.SCAIServiceBase checks to make sure that the Python class implements
each of the required interface methods. If any of the methods are missing it will throw an exception.
Chapter 8: IDL to Python Language Mapping 257
Mapping for Interfaces

When implementing interface methods, you need to use the same rules for handling arguments that was
described above. Only arguments with directions of in and inout should appear as parameters to the
method and the method should return a tuple which contains the return value and any arguments with
directions of out or inout. You also need to make sure that the values in the return tuple can be converted
to the required SCA types.
The following example shows how an instance of this interface can be created and passed to the test
service.
sp = SCA.getService('ServiceName','SCA.Test.SCAITestProcessor')
myinf = MyPyImpl()
sp.registerListener(myinf)
sp.process()
258 SCA Framework User’s Guide
Mapping for Exceptions

Mapping for Exceptions


The SCA Framework provides three predefined exception types, SCA.SCAException,
SCA.SCAUserException and SCA.SCASystemException. All user defined exceptions in IDL must
inherit from either SCA::SCAUserException or another user-defined exception. Only single inheritance
is allowed.

SCAException exception
The base for all IDL defined exceptions is SCAException which is mapped to the Python class
SCA.SCAException.
class SCAException:

# Supported attributes
text = None
typecode = None

def __init__(self):

def what(self):

def getTypeCode(self):

def getText(self):

def setText(self,text):

def __str__(self):

Mapping for other exception types


The predefined exceptions SCA.SCAUserException and SCA.SCASystemException and all user
exceptions defined in IDL are mapped to internally generated Python classes. All the user defined
members in an exception are mapped to attributes in these exception classes.
Consider the listener example used in the previous section. Let’s modify the example so the process
method can now throw an exception by adding a raises clause to its IDL definition. This exception will
be thrown if the process method is called but a listener interface was not registered.

IDL
module SCA { module Test {
exception NoListenerException : SCAUserException
{
SCAInt32 id;
};
interface SCAITestProcessor : SCA::SCAIService
{
void registerListener(in SCAITestListener spListener);
Chapter 8: IDL to Python Language Mapping 259
Mapping for Exceptions

SCA::SCAResult process() raises(NoListenerException);


};
}; };
When calling the process method in Python, we can now catch the exception as follows.
try:
sp.process()
except SCA.Test.NoListenerException, exc:
print 'NoListenerException:',exc.what()
print 'id =',exc.id
Because we caught the actual SCA.Test.NoListenerException exception we have full access to the data
members defined in it. In this case this is the id data member.
It is also possible to catch the SCA.SCAException type which is the base SCA exception. But in this
case we would not have access to any data members defined in the actual exception.
try:
sp.process()
except SCA.SCAException, exc:
print 'SCAException:',exc
SCA exceptions do not inherit from Python's Exception type so you cannot catch them with an except
clause using it.
There may also be situations where you need to throw a SCA exception from a Python script. This is
unusual and normally will only occur if you are implementing an interface in Python. The following
Python code will implement the SCAITestProcessor interface that was described before. In the
implementation of the process method, an exception will be thrown if the listener interface was never
registered.
class MyPyImpl(SCA.SCAIServiceBase):

def __init__(self):
interfaces = []
interfaces.append('SCA.Test.SCAITestProcessor')
SCA.SCAIServiceBase.__init__(self,interfaces)

m_spListener = None

def registerListener(self,spListener):
self.m_spListener = spListener

def process(self):
if not self.m_spListener:
exc = SCA.Test.NoListenerException()
exc.setText('Listener interface was never registered')
exc.id = 123
raise exc
self.m_spListener.notify('This is test notification from Python')
260 SCA Framework User’s Guide
Mapping for Exceptions

The IDL raises clause


An IDL interface operation may contain a raises clause to indicate what kind of exceptions the operation
may throw. An example of this was shown previously. The presence of a raises clause in the IDL has no
affect on any of the actual Python code required to call or implement the SCA interfaces. But, when
implementing interfaces in Python it is still important that the IDL definition of the interfaces contain the
appropriate raises clauses. This is because the various SCA language bridges will check the exceptions
thrown and will only pass those that have been specified. If an exception is thrown that is not specified
in the raises clause, it will be converted to a SCASystemException and much of the information it
contains may be lost.
Chapter 8: IDL to Python Language Mapping 261
Mapping for SCA Services

Mapping for SCA Services


Currently, the implementation of SCA services in Python is not supported.
262 SCA Framework User’s Guide
Mapping for SCA Components

Mapping for SCA Components


Currently, the implementation of SCA components in Python is not supported.
Chapter 8: IDL to Python Language Mapping 263
The SCA Module

The SCA Module


The Python mapping provides an SCA module which is used to access the SCA Framework services
from the Python script. The importing of the SCA module also insures that the SCA Framework is
successfully initialized so SCA services and predefined types can be accessed.
The following functions are available in this module.

Method Purpose
getService Load a SCA service
loadTypes Make IDL defined type available

The getService function is used to load SCA services. The following is an example of how it is used.
import SCA
svc = SCA.getService('ServiceName')
(ret,sp) = svc.getInterface('SCA.Test.SCAITestProcessor')
It is also possible to combine the two calls into one as shown below.
import SCA
sp = SCA.getService('ServiceName','SCA.Test.SCAITestProcessor')
The loadTypes function will be described in the next section.
264 SCA Framework User’s Guide
Accessing IDL Type Definitions from Python

Accessing IDL Type Definitions from Python


The various mappings defined for SCA types in this chapter fall into four different categories.
• Some types are provided by the SCA Python Bridge. These types are immediately available
when the SCA module is imported. Examples of these types include SCAAny, SCAResult and
SCAException.
• Some types are mapped to normal Python types. These include basic types, arrays and
sequences.
• Some types required special Python classes to be created to represent the SCA type in Python.
These types include structures and exceptions.
• Some types required instances of normal Python variables be created with the value defined by
an IDL definitions. Examples of these include enumerations and IDL defined constants.
The last two categories are important because they both required the SCA Python Bridge to create Python
objects at runtime which represent the IDL defined type. When using these types, it is important to
understand what actually triggers the creation of these Python objects.
The SCA Python Bridge will normally process these definitions when a proxy object is created for a SCA
interface and only the types referenced in that interface will be created.
The following IDL definitions will be used to demonstrate this. Two interfaces are defined and each one
references a separate structure definition. There is also a constant definition included.

IDL
module SCA { module Test {
const SCAInt32 ERROR_1 = 1;
struct Struct1
{
SCAInt32 val;
};
interface SCAITestInterface1 : SCA::SCAIService
{
void method1(in Struct1 sval1);
};
struct Struct2
{
SCAInt32 val;
};
interface SCAITestInterface2 : SCA::SCAIService
{
void method2(in Struct2 sval2);
};
}; };
The following Python code illustrates when the various types will become available in the Python script.
def TestVariables():
vars = []
vars.append('SCA.Test.Struct1')
Chapter 8: IDL to Python Language Mapping 265
Accessing IDL Type Definitions from Python

vars.append('SCA.Test.Struct2')
vars.append('SCA.Test.ERROR_1')
for var in vars:
try:
exec 'val = %s' % var
print '%s defined' % var
except:
print '%s not defined' % var

import SCA
print '\nStart of test'
TestVariables()

print '\nLoad service'


svc = SCA.getService('ServiceName')
TestVariables()

print '\nCall to getInterface for SCA.Test.SCAITestInterface1'


(ret,sp) = svc.getInterface('SCA.Test.SCAITestInterface1')
TestVariables()

print '\nCall to getInterface for SCA.Test.SCAITestInterface2'


(ret,sp) = svc.getInterface('SCA.Test.SCAITestInterface2')
TestVariables()

print '\nCall to SCA.loadTypes for SCA.Test'


SCA.loadTypes('SCA.Test',True)
TestVariables()
Running this script generates the following output
Start of test
SCA.Test.Struct1 not defined
SCA.Test.Struct2 not defined
SCA.Test.ERROR_1 not defined

Load service
SCA.Test.Struct1 not defined
SCA.Test.Struct2 not defined
SCA.Test.ERROR_1 not defined

Call to getInterface for SCA.Test.SCAITestInterface1


SCA.Test.Struct1 defined
SCA.Test.Struct2 not defined
SCA.Test.ERROR_1 not defined

Call to getInterface for SCA.Test.SCAITestInterface2


SCA.Test.Struct1 defined
SCA.Test.Struct2 defined
SCA.Test.ERROR_1 not defined

Call to SCA.loadTypes for SCA.Test


SCA.Test.Struct1 defined
266 SCA Framework User’s Guide
Accessing IDL Type Definitions from Python

SCA.Test.Struct2 defined
SCA.Test.ERROR_1 defined
Notice that at the start of the test none of the types defined in the IDL are available. This is even true after
the getService call. This is because the getService call returns a SCA.SCAIService interface and none of
the desired types are references by it. Only after the getInterface call for SCA.Test.SCAITestInterface1
do we get some types defined. In this case only the structure SCA.Test.Struct1 is defined because it is
the only type referenced by this interface. The second structure, SCA.Test.Struct2, is not defined until
the second getInterface call for SCA.Test.SCAITestInterface2 is made.
Notice that even after all of the getInterface calls, the constant value SCA.Test.ERROR_1 is still not
defined. This is the normal case for constants because they are usually not directly referenced by any of
the methods in an interface so the SCA Python Bridge will never define them.
To resolve these issues, you must explicitly trigger the loading of these SCA type definitions using the
loadTypes function in the SCA module.
SCA.loadTypes('SCA.Test',True)
The first argument to the loadTypes call is the IDL namespace for the types you want defined. The second
argument is a boolean value. If it is true then all the type in the specified namespace and recursively all
of the namespaces it contains will be defined. If false then only the types in the specified namespace will
be defined.
It is also possible to use the loadTypes call to force the definition of types before they would normally be
available. For example in the above example, if the loadTypes call is done immediately after the SCA
module is imported then all of the types will be defined and available immediately.

Python
import SCA
print '\nImmediate call to SCA.loadTypes for SCA.Test'
SCA.loadTypes("SCA.FileReader",True)
TestVariables()
Will generate this output
Immediate call to SCA.loadTypes for SCA.Test
SCA.FileReader.Struct1 defined
SCA.FileReader.Struct2 defined
SCA.FileReader.ERROR_1 defined
Chapter 8: IDL to Python Language Mapping 267
Running Python Scripts

Running Python Scripts


There are two different ways to run Python scripts in the SCA Framework
• Scripts can be run from inside an application using the ScriptBroker service
• Scripts can be run using the command line Python command

This section will briefly describe both of these methods. For complete details you should consult the
Scripting chapter in the SCA SDK Advanced Features manual.

Running Scripts with the ScriptBroker


The ScriptBroker is a service that is provided with the SCA Framework which can be used to run Python
scripts from inside an application. The following is a simple example of a C++ routine that will use the
ScriptBroker to run a script.
#include <SCA/Framework/Scripting/SCAIScriptBroker.h>

void runScript(SCA::SCAString scriptName)


{
SCA::Framework::Scripting::SCAIScriptBroker spBroker;
spBroker = getSCAService("SCA.Framework.Scripting.ScriptBroker");
spBroker->runScript(scriptName);
}
Complete details on using the ScriptBroker service are available in the Scripting chapter in the SCA
SDK Advanced Features manual.

Running Scripts from the command line


To run a Python script which used the SCA Framework from the command line, you need to make sure
the environment has been setup appropriately for the SCA Kernel. The following is a simple CShell
script that shows an example of this on the Windows platform.
#!/bin/csh
set ISYSTEM = D:/sCAKernel-V4-007
set path = ( $ISYSTEM/WINNT/bin $ISYSTEM/WINNT/lib $path )
setenv SCA_SERVICE_CATALOG "$ISYSTEM/res/SCAServiceCatalog.xml"
setenv SCA_RESOURCE_DIR "$ISYSTEM/res"
setenv PYTHONPATH "$ISYSTEM/lib/python;$ISYSTEM/WINNT/bin"
/Tools-V5-004/python $*
This script is using the Python installation that is provided in the SCA Tools directory. This is a good
practice because you can be sure that it is the same version that the SCA Kernel was built with. If you
use the Python installation on your machine there could be problems if the versions are not compatible.
For complete details on the initialization of the SCA Kernel, see the SCA Kernel chapter of this manual.
268 SCA Framework User’s Guide
Running Python Scripts
Chapter 9: Messages and Internationalization
SCA Framework User’s Guide

9 Messages and
Internationalization


Introduction 270

Message Files 271

Text Translation Service 278
270 SCA Framework User’s Guide
Introduction

Introduction
Internationalization is the process of adding capabilities in the software applications so that they can be
adapted to various locales (languages and regions) without re-building them.
Localization is the actual process of translating and formatting the text and other GUI components.
The SCA Framework provides the following localization capabilities.
• XML Message Tables
• The text from messages, dialog boxes and widgets is stored in XML message files.
• Parameter Substitution
• Support for number, date, time and currency formats.
• Language Customization
• The substitution parameters are indexed, so the order could be different in different
languages. This is necessary to support different writing directions, grammar and
composition.
• Text Translation Service
• Provides the interfaces to load the contents of the XML message files and format messages.
Chapter 9: Messages and Internationalization 271
Message Files

Message Files
The message files supported by the SCA framework are UTF-8 encoded XML files that allows a simple
one-to-one mapping from a text ID to the respective message text. The text includes place holders to
allow parameter substitution and formatting of number, date, time and currency values.

Locale String
<localeLanguageCode>_<localeCountryCode>
The locale string contains the locale value, which is a 2-character language code (as defined by ISO 639-
1), optionally followed by an underscore and a 2-character country identifier (as defined by ISO 3166).
For example "en" for English, "en_GB" for British, "fr" for French, "fr_CA" for Canadian French etc.
This format is also used in XML documents as a value for the xml:lang attribute (as described in
http://www.faqs.org/rfcs/rfc3066.html )

Message File Naming Convention


The message file name has the following format:
<baseName>_<localeLanguageCode>_<localeCountryCode>.xml

Examples:
TextTranslation_fr.xml
TextTranslation_en_GB.xml

File Search Order


The message file is expected to reside in the component's resource directory. For more information on
setting the resource directory see the Kernel Configuration Variables seciton of SCA Kernel chapter in
this manual.
The SCA Kernel will first look in one of several subdirectories of the resouce directory, RESDIR, for the
message file. These are as follows.
Locale_<localeLanguageCode>_<localCountryCode>
Locale_<localeLangueCode>
If the messge file is not found in one of the subdirectores then it will search directly in the resource
diretory.
If a message file in the desired language can not be found, a final try will be made to load the English
version of the table using the same search order as shown above.
The complete order of search is as follows.
RESDIR/Locale_<language>_<country>/<baseName>_<language>_<country>.xml
RESDIR/Locale_<language>/<baseName>_<language>.xml
272 SCA Framework User’s Guide
Message Files

RESDIR/<baseName>_<language>_<country>.xml
RESDIR/<baseName>_<language>.xml
RESDIR/Locale_en/<baseName>_en.xml
RESDIR/<baseName>_en.xml
Only the first file found using the above order is loaded.

Example:
baseName= "TextTranslation",
localeLanguageCode = "fr"
localeCountryCode= "CA"
Search order:
RESDIR/Locale_fr_CA/TextTranslation_fr_CA.xml
RESDIR/Locale_fr/TextTranslation_fr.xml
RESDIR/TextTranslation_fr_CA.xml
RESDIR/TextTranslation_fr.xml
RESDIR/Locale_en/TextTranslation_en.xml
RESDIR/TextTranslation_en.xml

Message File Format


The supported tags and their attributes are described below:
<sim_office_resource>: Wraps all nodes of the translation table entries. It can have the following
attributes:
• version: <major-number>.<minor-number> (e.g. "1.0") [mandatory]
• comment: explains the context of the text in this file [optional]
• author: In the English ("en") version of the file, the email address of the original
author/programmer who created it, otherwise the translator. [optional]
• xml:lang: The language provided in this file. The language is also mangled into the file name,
but specifying it in the file again allows for easier conversion to other formats. [optional]
<text>: A translation unit. It contains the text node in the translated language. It has the following
attributes:
• id: Specifies the string id that is used to retrieve the message [mandatory]
• comment: Can be used to explain the context of the text [optional]
• author: If the text was not written by the author specified in the <sim_office_resource > author
attribute [optional]
<module>: A dialog box. It has one attribute:
• id: Specifies the string id that is used in getModuleText etc. [mandatory]

The following enclosed tags describe the text in the module:


Chapter 9: Messages and Internationalization 273
Message Files

• <text>: This node describes the dialog's caption; it has the same attributes as the <text> tag
described above. The id attribute is optional here! If provided, it is used to identify the context.
• <help>: A help text for the dialog.

Text Formatting
The formatting place holders are embedded in the text. Since the argument order can change in different
languages, each argument is prefixed by the index of its entry in the argument sequence that is passed to
the getFormattedText method. The index is 1-based. The format of this prefix is %<index>:, so the first
argument would be %1:, the second %2: and so on.
This index reference is followed by the data formatting information. Currently, there are three different
formatting styles, which are distinguished by the first character:

Currency Format ($)


The provided argument should be an integer or a floating point number . If a floating point number is
used the fractional part is ignored. The units used for the currency argument depend on the current locale
setting. For example, in English they are cents.

Example:
Text: "The price is %1:$"
Arg1= 1999
Formatted Text: "The price is $19.99"

Date/Time Format (#)


The provided argument should be an integer that stores the number of seconds since 01/01/70 (UTC).
This number will be converted to the timezone that is set for the computer's system clock. It is possible
to define a different timezone by changing the environment variable TZ. Caveat: changing this variable
puts the whole process in a different timezone, which could have unwanted effects in a multi-threaded
environment (unless secured by mutex sections). Accepted values for TZ should be found in system's
documentation.
How that date is displayed depends on the character that follows the # character. The available options
are identical to the formats accepted by the standard C language function strftime (except that strftime
uses % as prefix)
274 SCA Framework User’s Guide
Message Files

code Meaning
a abbreviated weekday name (e.g. Fri)
A full weekday name (e.g. Friday)
b abbreviated month name (e.g. Oct)
B full month name (e.g. October)
c the standard date and time string
d day of the month, as a number (1-31)
h hour, 24 hour format (0-23)
I hour, 12 hour format (1-12)
j day of the year, as a number (1-366)
m month as a number (1-12). Note: some versions of Microsoft Visual C++
may use values that range from 0-11.
M minute as a number (0-59)
p locale's equivalent of AM or PM
s second as a number (0-59)
u week of the year, (0-53), where week 1 has the first Sunday
w weekday as a decimal (0-6), where Sunday is 0
W week of the year, (0-53), where week 1 has the first Monday
x standard date string
X standard time string
y year in decimal, without the century (0-99)
Y year in decimal, with the century
Z time zone name

Example:
Text: "Today is a %1:#A in %1:#B, the time is %1:#X",
Arg1 = 1130514894
Formatted Text: "Today is a Friday in October, the time is 5:54:54 PM".

All other Formats (%)


This formatting is modeled after printf in the programming language C:
%[flags][width][.precision][modifier]conversion
Chapter 9: Messages and Internationalization 275
Message Files

conversion Output Example


c Character a
d or i Signed decimal integer 392
e Scientific notation (mantise/exponent) using e character 3.9265e+2
E Scientific notation (mantise/exponent) using E character 3.9265E+2
f Decimal floating point 392.65
g Use the shorter of %e or %f 392.65
G Use the shorter of %E or %f 392.65
o Signed octal 610
s String of characters sample
u Unsigned decimal integer 7235
x Unsigned hexadecimal integer 7fa
X Unsigned hexadecimal integer (capital letters) 7FA
p Pointer address B800:0000
n Nothing printed. The argument must be a pointer to a signed int,
where the number of characters written so far is stored.
% A % followed by another % character will write % to stdout.

flags Description
- Left-justify within the given field width; Right justification is the default (see width sub-
specifier).
+ Forces to precede the result with a plus or minus sign (+ or -) even for positive numbers. By
default, only negative numbers are preceded with a - sign.
(space) If no sign is going to be written, a blank space is inserted before the value.
# Used with o, x or X specifiers the value is preceded with 0, 0x or 0X respectively for values
different than zero.

Used with e, E and f, it forces the written output to contain a decimal point even if no digits
would follow. By default, if no digits follow, no decimal point is written.

Used with g or G the result is the same as with e or E but trailing zeros are not removed.
0 Left-pads the number with zeroes (0) instead of spaces, where padding is specified (see
width sub-specifier).
276 SCA Framework User’s Guide
Message Files

width Description
# Minimum number of characters to be printed. If the value to be printed is shorter than this
number, the result is padded with blank spaces. The value is not truncated even if the result
is larger.
* The width is not specified in the format string, but as an additional integer value argument
preceding the argument that has to be formatted.

.precision Description
.number For integer specifiers (d, i, o, u, x, X): precision specifies the minimum number of digits
to be written. If the value to be written is shorter than this number, the result is padded
with leading zeros. The value is not truncated even if the result is longer. A precision of
0 means that no character is written for the value 0.

For e, E and f specifiers: this is the number of digits to be printed after the decimal point.

For g and G specifiers: This is the maximum number of significant digits to be printed.

For s: this is the maximum number of characters to be printed. By default all characters
are printed until the ending null character is encountered.

For c type: it has no effect.

When no precision is specified, the default is 1. If the period is specified without an


explicit value for precision, 0 is assumed.
.* The precision is not specified in the format string, but as an additional integer value
argument preceding the argument that has to be formatted.

modifier description
h The argument is interpreted as a short int or unsigned short int (only applies to integer
specifiers: i, d, o, u, x and X).
l The argument is interpreted as a long int or unsigned long int for integer specifiers (i, d,
o, u, x and X), and as a wide character or wide character string for specifiers c and s.
L The argument is interpreted as a long double (only applies to floating point specifiers: e,
E, f, g and G).

Example:
Text: "%1:%d + %2:%g %3:%s"
Arg1 = 1, Arg2 = 2.5, Arg3 = "is equal to..."
Formatted Text: "1 + 2.5 is equal to...".
Sample1: English Message File.
Chapter 9: Messages and Internationalization 277
Message Files

<?xml version='1.0' encoding='UTF-8' ?>


<!DOCTYPE SIMOFFICERES>
<!--
Copyright (c) 2005, MSC.Software Corporation. All Rights Reserved.
MSC PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
-->
<sim_office_resources version="1.0" xml:lang="en"
comment="Translation Test"
author="soeren.fietzke@mscsoftware.com">
<text id="color" comment="material"
author="soeren.fietzke@mscsoftware.com">Color</text>
<text id="help">Help</text>
<text id="formatTest">
This is a formatting test: string '%1:%ls', long: %2:%d, double:
%3:%1.3g
</text>
<text id="currencyTest">The price is %1:$</text>
<text id="dateTimeTest">Today is %1:#A %1:#B - %1:#x %1:#X</text>
<module id="mod_test">
<text id="m1">Text in mod_test::m1.</text>
<text id="m2">Text in mod_test::m2.</text>
</module>
</sim_office_resources>

Sample2: German Message File.

<?xml version='1.0' encoding='UTF-8' ?>


<!DOCTYPE SIMOFFICERES>
<!--
Copyright (c) 2005, MSC.Software Corporation. All Rights Reserved.
MSC PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
-->
<sim_office_resources version="1.0" xml:lang="de"
comment="Translation Test"
author="soeren.fietzke@mscsoftware.com">
<text id="color" comment="material"
author="fred@acme_translation.com">Farbe</text>
<text id="help">Hilfe</text>
<text id="formatTest">
Dies ist ein Formatierungs-Test: Zeichenkette '%1:%ls', long:
%2:%d, double: %3:%1.3g
</text>
<text id="currencyTest">Der Preis beträgt %1:$</text>
<text id="dateTimeTest">Heute ist %1:#A %1:#B - %1:#x %1:#X</text>
<module id="mod_test">
<text id="m1">Der Text von mod_test::m1.</text>
<text id="m2">Der Text von mod_test::m2.</text>
</module>
</sim_office_resources>
278 SCA Framework User’s Guide
Text Translation Service

Text Translation Service


Text Translation service provides the interfaces to load the contents of the XML message files and format
messages. These interfaces are described in detail in the following sections.

SCA::Framework::SCAITextTranslationFactory Interface
The SCAITextTranslationFactory is used to create new translation tables and provides access to the
common settings object.

Member Functions
SCAResult getTextTranslationSettings (out SCAITextTranslationSettings settings)
SCAResult createTextTranslationTable (in SCAWString fileBaseName, out
SCAITextTranslationTable newTable)
SCAResult setDefaultFallbackTranslationTable (in SCAITextTranslationTable
defaultTable)

Member Function Documentation


SCAResult getTextTranslationSettings (out SCAITextTranslationSettings settings )
Returns the singleton instance of SCAITextTranslationSettings (which is created by the framework on
startup).

Parameters:
settings SCAITextTranslationSettings object

Returns:
Returns SCASuccess on success, else returns an error.
SCAResult createTextTranslationTable ( in SCAWString fileBaseName,
out SCAITextTranslationTable newTable )
Creates a new translation table instance.

Parameters:
fileBaseName Base-name of the message file, which is expected to reside inside the components
resource directory.
newTable Newly created text translation table.

SCAResult setDefaultFallbackTranslationTable ( in SCAITextTranslationTable defaultTable )


Chapter 9: Messages and Internationalization 279
Text Translation Service

Sets the default Translation Table. All translation tables created after the default table has been set will
have their fallback set to the default table. Existing tables are not affected.

Parameters:
defaultTable Default text translation table.

Returns:
Returns SCASuccess on success, else returns an error.

SCA::Framework::SCAITextTranslationSettings Interface
The SCAITextTranslationSettings has methods to set and get the current locale.
Member Functions
SCAResult getLocale (in LocaleCategory category, out SCAString locale)
SCAResult getNativeLocale (in LocaleCategory category, out SCAString
nativeLocaleName)
SCAResult setLocale (in LocaleCategory category, in SCAString locale)

Member Function Documentation


SCAResult getLocale (in LocaleCategory category, out SCAString locale )
Inquires the currently used locale string.

Parameters:
category The category whose locale is requested.

locale Locale string

Returns:
Returns SCASuccess on success, else returns an error.
SCAResult getNativeLocale (in LocaleCategory category, out SCAString nativeLocaleName )
This method is used to inquire the locale name in a format that can be used with native locale functions
like setlocale or std::locale. For example the locale names are different on Windows and UNIX.
280 SCA Framework User’s Guide
Text Translation Service

Parameters:
category The category whose locale is requested.
nativeLocaleName Native locale string

Returns:
Returns SCASuccess on success, else returns an error.
SCAResult setLocale (in LocaleCategory category, in SCAString locale )
Sets the locale string for the given category.

Parameters:
category Locale category
locale Locale string

Returns:
Returns SCASuccess on success, else returns an error.

LocaleCategory
The LocaleCategory is an enum defined below.

enum LocaleCategory
{
LC_All, // All categories. When inquiring, it returns the
locale last
// used to set LC_All.
LC_Messages,// Text translation. Determines the message file to
load.
LC_Collate, // String handling.
LC_CharType,// Character handling.
LC_Numeric, // Formatting of numbers.
LC_Monetary,// Formatting of monetary values.
LC_Time // Formatting of time and date.
};

Locale String
The locale string contains the locale value, which is a 2-character language code (as defined by ISO 639-
1), optionally followed by an underscore and a 2-character country identifier (as defined by ISO 3166).
For example "en" for English, "en_GB" for British, "fr" for French, "fr_CA" for Canadian French etc.
This format is also used in XML documents as a value for the xml:lang attribute (as described in
http://www.faqs.org/rfcs/rfc3066.html )
Chapter 9: Messages and Internationalization 281
Text Translation Service

Mixed Locales
The text translation service supports mixed locales by allowing the assignment of different locales to
different categories. The mixed locales can be set either by making multiple calls to the 'setLocale'
method or by making a single call using LC_ALL category and a mixed locale strring. The mixed locale
string has the following format:
"CATEGORY1=locale1; CATEGORY2=locale2; locale3;locale4..."
The optional category is in uppercase and the separation character is semicolon ";"
For example the following call to setLocale will select German messages with US-English numeric
format and Japanese for all other categories,

SCAITextTranslationSettings spSettings;
spFactory->getTextTranslationSettings( spSettings );
spSettings->setLocale(LC_All,
"LC_MESSAGES=de;LC_NUMERIC=en_US;ja");

SCA::Framework::SCAITextTranslationTable Interface
The SCAITextTranslationTable makes the contents of a Message File available to the client applications.
The text translation table allows a simple one-to-one mapping from a text ID to the respective text. There
is separate message file for each locale. Changing the locale requires re-loading of the message file.
When an exact match is not possible, (i.e. locale is set to "fr-CA", but translations exist only for the "fr"
locale), then only the first two characters (which always indicate the language) are compared. If even then
no match can be found, the default will be English ("en").
282 SCA Framework User’s Guide
Text Translation Service

Member Functions
SCAResult getText (in SCAString textID, out SCA::SCAWString text)
SCAResult getTextByIntId (in SCAInt32 textID, out SCA::SCAWString text)
SCAResult getModuleText (in SCAString moduleName, in SCAString itemName, in
GuiMessageKind kind, out SCA::SCAWString text)
SCAResult getFormattedText (in SCAString textID, in SCAAnySequence args, out
SCAWString text)
SCAResult getFormattedTextByIntId (in SCAInt32 textID, in SCAAnySequence args,
out SCAWString text)
SCAResult getFormattedModuleText (in SCAString moduleName, in SCAString
itemName, in GuiMessageKind kind, in SCAAnySequence args, out
SCAWString text)
SCAResult getModuleTextByComment (in SCAString moduleName, in SCAString
commentName, in SCAString itemName, in GuiMessageKind kind, out
SCA::SCAWString text)
SCAResult getFormattedModuleTextByComment (in SCAString moduleName, in
SCAString commentName, in SCAString itemName, in GuiMessageKind
kind, in SCAAnySequence args, out SCAWString text)
SCAResult setFallbackTable (in SCAITextTranslationTable table)
SCAResult setFixedLocale (in SCAString locale)

Member Function Documentation


SCAResult getText (in SCAString textID, out SCA::SCAWString text )
Gets the simple unformatted text, which does not require any arguments.

Parameters:
textID String that identifies the message.
text Contains the simple text on return.

Returns:
Returns SCASuccess on success, else returns an error.
SCAResult getTextByIntId (in SCAInt32 textID, out SCA::SCAWString text )
Same as getText(), but instead of string the input is an integer textID.
Chapter 9: Messages and Internationalization 283
Text Translation Service

Parameters:
textID Integer value that identifies which message should be looked up.
text Contains the simple text on return.

Returns:
Returns SCASuccess on success, else returns an error.
SCAResult getModuleText ( in SCAString moduleName,
in SCAString itemName,
in GuiMessageKind kind,
out SCA::SCAWString text )
Gets simple GUI text from <dialog> or <module> sections of the message file.

Parameters:
moduleName Module name ( dialog name).
itemName Item name (widget name).
kind Sub-item type (GMK_Text, GMK_Help).
text Contains the simple text on return.

Returns:
Returns SCASuccess on success, else returns an error.
SCAResult getFormattedText (in SCAString textID,
in SCAAnySequence args,
out SCAWString text )
Gets the formatted text. The section "Text Formatting" discusses the formatting in detail.

Parameters:
textID String that identifies the message.
args List of message arguments used for formatting. Could be NULLSP if no arguments
are provided.
text Contains the translated and formatted text on return.

Returns:
Returns SCASuccess on success, else returns an error.
SCAResult getFormattedTextByIntId (in SCAInt32 textID,
284 SCA Framework User’s Guide
Text Translation Service

in SCAAnySequence args,
out SCAWString text )
Same as getFormattedText(), but instead of string the input is an integer textID.
See also:
getFormattedText

Parameters:
textID Integer value that identifies which message should be looked up.
args List of message arguments used for formatting. Could be NULLSP if no arguments
are provided.
text Contains the translated and formatted text on return.

Returns:
Returns SCASuccess on success, else returns an error.
SCAResult getFormattedModuleText (in SCAString moduleName,
in SCAString itemName,
in GuiMessageKind kind,
in SCAAnySequence args,
out SCAWString text )
Gets the formatted GUI text from <dialog> or <module> sections of the message file. The section "Text
Formatting" discusses the formatting in detail.

Parameters
moduleName Module name ( dialog name).
itemName Item name (widget name).
kind Sub-item type (GMK_Text, GMK_Help).
args List of message arguments used for formatting. Could be NULLSP if no
arguments are provided.
text Contains the translated and formatted text on return.

Returns:
Returns SCASuccess on success, else returns an error.
SCAResult getModuleTextByComment (in SCAString moduleName,
in SCAString commentName,
Chapter 9: Messages and Internationalization 285
Text Translation Service

in SCAString itemName,
in GuiMessageKind kind,
out SCA::SCAWString text )
Gets simple GUI text from <dialog> or <module> sections of the message file. Uses the combination of
comment and id as the key. The key is of the format (comment_id)

Parameters:
moduleName Module name ( dialog name).
commentName String that identifies the widget.
itemName Item name (widget name).
kind Sub-item type (GMK_Text, GMK_Help).
text Contains the translated and formatted text on return.

Returns:
Returns SCASuccess on success, else returns an error.
SCAResult getFormattedModuleTextByComment (in SCAString moduleName,
in SCAString commentName,
in SCAString itemName,
in GuiMessageKind kind,
in SCAAnySequence args,
out SCAWString text )
Gets formatted GUI text from <dialog> or <module> sections of the message file. Uses the combination
of comment and id as the key. The key is of the format (comment_id). The section "Text Formatting"
discusses the formatting in detail.

Parameters:

moduleName Module name ( dialog name).


commentName String that identifies the widget.
itemName Name of the widget for which contains the text that is searched.
kind Sub-item type (GMK_Text, GMK_Help).
args List of message arguments used for formatting. Could be NULLSP if no
arguments are provided.
text Contains the translated and formatted text on return.
286 SCA Framework User’s Guide
Text Translation Service

Returns:
Returns SCASuccess on success, else returns an error.
SCAResult setFallbackTable ( in SCAITextTranslationTable table )
This method sets the fallback translation table. The fallback table is searched if a text ID is not found in
this table. When the table is created by the SCAITextTranslationFactory, the fall back table is set to the
default translation table.

Parameters:
table Fallback table.

Returns:
Returns SCASuccess on success, else returns an error.
SCAResult setFixedLocale (in SCAString locale )
Sets a fixed locale for the translation table which overrides the locale set in the
SCAITextTranslationSettings instance. Passing an empty string resets the override and re-attaches the
locale to the global SCAITextTranslationSettings instance.

Parameters:
locale Locale string.

Returns:
Returns SCASuccess on success, else returns an error.

Using the service


The following C++ code snippets demonstrate how the text translation service should be used. The
intention is to demonstrate the usage of methods. It uses the sample translation tables presented earlier in
this chapter. The real code should contain proper exception and SCAResult handling.
Chapter 9: Messages and Internationalization 287
Text Translation Service

SCA::SCAResult result;

// Get an instance of the SCAITextTranslationFactory


SCA::Framework::SCAITextTranslationFactory spFactory;
spFactory = getService("SCA.Framework.TextTranslation","");
if (spFactory == SCA::NULLSP){
std::cerr << "ERROR:Unable to load the TextTranslation service" <<
std::endl;
return SCA::SCAError;
}

// Set the Locale to German "de"


SCA::Framework::SCAITextTranslationSettings spSettings;
result = spFactory->getTextTranslationSettings(spSettings);
if (!result.isOk()){
std::cout << "Could not get SCAITextTranslationSettings" <<
std::endl;
return SCA::SCAError;
}
result = spSettings->setLocale(SCA::Framework::LC_All,"de");

// Create a text translation table by loading the messages from the


file
// $SCA_RESOURCE_DIR/TranslationSample_de.xml
SCA::Framework::SCAITextTranslationTable spTable;
result = spFactory-
>createTextTranslationTable(L"TranslationSample",spTable);

// Get the simple text without any place holders


SCA::SCAWString text;
result = spTable->getText("help",text);
std::printf("%ls\n",text.c_str());

// Get the text formatted using the supplied arguments for the place
holders
SCAAnySequence args;
args.push_back(SCA::SCAAny(SCA::SCAString("TestString")));
args.push_back(SCA::SCAAny(SCA::SCAInt32(1234)));
args.push_back(SCA::SCAAny(SCA::SCAReal32(123.456)));
result = spTable->getFormattedText("formatTest",args,text);
std::printf("%ls\n",text.c_str());

// Get Module text


result = spTable->getModuleText("mod_test","m1",
SCA::Framework::GMK_Text,text);
std::printf("%ls\n",text.c_str());
result = spTable->getModuleText("DeformPlotMetaDataFrame",
"Qt Linguist context",
SCA::Framework::GMK_Text,text);
std::printf("%ls\n",text.c_str());
288 SCA Framework User’s Guide
Text Translation Service

Language Support Files


The text translation service uses several xml files to store language and country settings. These files must
be located in the applications resource directory. At startup LocaleLanguagesMap.xml and
LocaleCountriesMap.xml files are parsed to load the settings. Since these settings are global they are read
only once and are available to all instances of the TextTranslationSettings object. The country map is only
required for Windows.
LocaleLanguagesMap.xml.

<?xml version="1.0" encoding="utf-8"?>


<!-- for list of language/country strings, see
http://msdn2.microsoft.com/en- us/library/cdax410z(VS.71).aspx -->
<LanguagesMap version="1.0">
<language code="zh" defaultCountry="cn">chinese;chinese-
simplified;chs;chinese-traditional;cht</language>
<language code="cs" defaultCountry="cz">csy;czech</language>
<language code="da" defaultCountry="dk">dan;danish</language>
<language code="nl" defaultCountry="nl">dutch;nld;belgian;dutch-
belgian;nlb</language>
<language code="en"
defaultCountry="us">english;australian;ena;english-
aus;canadian;enc;english-can;english-nz;enz;eng;english-
uk;uk;american;american english;american-english;english-
american;english-us;english-usa;enu;us;usa</language>
<language code="fi" defaultCountry="fi">fin;finnish</language>
<language code="fr" defaultCountry="fr">fra;french;frb;french-
belgian;frc;french-canadian;french-swiss;frs</language>
<language code="de" defaultCountry="de">deu;german;dea;german-
austrian;des;german-swiss;swiss</language>
<language code="el" defaultCountry="gr">ell;greek</language>
<language code="hu" defaultCountry="hu">hun;hungarian</language>
<language code="is" defaultCountry="is">icelandic;isl</language>
<language code="it" defaultCountry="it">ita;italian;italian-
swiss;its</language>
<language code="ja" defaultCountry="jp">japanese;jpn</language>
<language code="ko" defaultCountry="kr">kor;korean</language>
<language code="no" defaultCountry="no">norwegian</language>
<language code="nb" defaultCountry="no">nor;norwegian-
bokmal</language>
<language code="nn" defaultCountry="no">non;norwegian-
nynorsk</language>
<language code="pl" defaultCountry="pl">plk;polish</language>
<language code="pt"
defaultCountry="pt">portuguese;ptg;portuguese-brazil;ptb</language>
<language code="ru" defaultCountry="ru">rus;russian</language>
<language code="sk" defaultCountry="sk">sky;slovak</language>
<language code="es" defaultCountry="es">esp;spanish;esm;spanish-
mexican;esn;spanish-modern</language>
<language code="sv" defaultCountry="se">sve;swedish</language>
<language code="tr" defaultCountry="tr">trk;turkish</language>
</LanguagesMap>
Chapter 9: Messages and Internationalization 289
Text Translation Service

LocaleCountriesMap.xml.

<?xml version="1.0" encoding="utf-8"?>


<!-- for list of language/country strings, see
http://msdn2.microsoft.com/en-us/library/cdax410z(VS.71).aspx -->
<CountriesMap version="1.0">
<country code="au">aus;australia</country>
<country code="at">aut;austria</country>
<country code="be">bel;belgium</country>
<country code="br">bra;brazil</country>
<country code="ca">can;canada</country>
<country code="cn">china;chn;pr china;pr-china</country>
<country code="cz">cze;czech</country>
<country code="dk">dnk;denmark</country>
<country code="fi">fin;finland</country>
<country code="fr">fra;france</country>
<country code="de">deu;germany</country>
<country code="gr">grc;greece</country>
<country code="hk">hkg;hong kong;hong-kong</country>
<country code="hu">hun;hungary</country>
<country code="is">iceland;isl</country>
<country code="ie">irl;ireland</country>
<country code="it">ita;italy</country>
<country code="jp">jpn;japan</country>
<country code="kr">kor;korea</country>
<country code="mx">mex;mexico</country>
<country code="nl">nld;holland;netherlands</country>
<country code="nz">nzl;new zealand;new-zealand;nz</country>
<country code="no">nor;norway</country>
<country code="pl">pol;poland</country>
<country code="pt">prt;portugal</country>
<country code="ru">rus;russia</country>
<country code="sg">sgp;singapore</country>
<country code="sk">svk;slovak</country>
<country code="es">esp;spain</country>
<country code="se">swe;sweden</country>
<country code="ch">che;switzerland</country>
<country code="tw">twn;taiwan</country>
<country code="tr">Turkey tur;turkey</country>
<country code="gb">gbr;britain;england;great britain;uk;united
kingdom;united-kingdom</country>
<country code="us">usa;america;united states;united-
states;us</country>
</CountriesMap>
290 SCA Framework User’s Guide
Text Translation Service
Chapter 10: Error Processing
SCA Framework User’s Guide

10 Error Processing


Introduction 292
 Using SCA Exceptions for Error Handling 294

Using SCAResult for Error Handling 305

MessageDispatcher Service 316
292 SCA Framework User’s Guide
Introduction

Introduction
Error handling is a crucial part of any programming project. SCA supports the two most common forms
for handling errors.
• The interface methods throw exceptions.
• The interface methods return error codes.

Both methods have their own advantages over the other and users should choose the one that is most
appropriate to their application.
Exceptions tend to be easier to implement than error codes. Consider the example where routine A calls
B, B calls C and C calls D and then D produces an error code. In this case C has to check the code, return
its own code, which would be checked by B which would return its own code which would finally be
checked by A. Whereas with exceptions, if D throws the exception, then a simple try/catch block in A
can catch it and no special code is required in any of the intermediate routines in the call stack.
Furthermore, many programmers get lazy and do not always do the appropriate checking of error codes.
With error codes this can be disastrous because the error is lost and the caller will continue as if nothing
happened. But with exceptions, the errors will always be triggered. If the programmer does not include
the appropriate try/catch block for the exception, it will still be propagated up to the next routine in the
call stack until someone eventually catches it.
On the other hand, error codes tend to be more efficient then exceptions. To properly handle exceptions,
the compilers need to generate special support code in every routine to correctly process them. This tends
to make the generated code larger and adds overhead. Also, error codes provide for more sophisticated
processing of messages. This includes more flexible formatting of error messages including parameter
substitution and the ability to internationalize the messages to any language supported by the application.
Exceptions and error codes are two different general error handling approach. The mixing of the two can
lead to confusion and should be avoided. The following conventions are recommended for best practice.
• If an interface method defines a raises clause for any explicit exceptions, then the method should
not use a SCAResult or any other value as an error indication.
• If an interface method returns a SCAResult or any other value as an error indication, it should
not have a raises clause and it should not throw any exceptions.
• Throwing user-defined exceptions is preferred over the throwing of any of the SCA provided
base exceptions.
• Normally the same error handling method should be chosen for all interfaces implemented by a
given service.
Even if the SCAResult form of error handling is chosen, it is important to realize that calls to SCA
interface methods may still throw SCASystemException exceptions. This may occur if the call crosses
languages boundaries or accesses remote components. In this case the SCA language bridges may need
to report an error when trying to marshal the call. This is generally not a problem because these types of
errors are usually catastrophic in nature and there is no recovery logic available. As a result the individual
routines do not need to catch these SCASystemException exceptions. Instead they can be caught in a
global try/catch block at the top of the applications call stack so the application can terminate cleanly.
Chapter 10: Error Processing 293
Introduction

Both SCA exceptions and the SCAResult forms of error handling described in this chapter are available
in all of the languages supported by the SCA framework. The exact syntax of using them vary from
language to language but their general functionality is similar. As a result this chapter will only show
examples using the C++ language. You should consult the IDL Mapping chapters of this manual for the
complete details of using these features in each of the supported languages.
294 SCA Framework User’s Guide
Using SCA Exceptions for Error Handling

Using SCA Exceptions for Error Handling


The SCA exception processing is available in each of the languages supported by the SCA framework
including the Python scripting language. Exceptions can be thrown in one language and caught in any of
the other supported languages. The SCA language bridges will catch the exception in the language it is
thrown in, convert all of the data contained in it and then rethrow the exception in the language of the
caller. This entire process is transparent to either the caller or the routine where the exception was thrown.
SCA exceptions are types that are defined by the user through the SCA IDL language. See the IDL
Language chapter of this manual for the complete details on how they are defined.
Three exceptions types, SCA::SCAException, SCA::SCASystemException, and
SCA::SCAUserException, are predefined in the SCA Framework. All user defined exceptions must
inherit SCA::SCAUserException or another user-defined exception. Only single inheritance is allowed.
In addition to the definition of the exceptions, the IDL definition of interface methods may have an
optional raises clause. The raises clause defines what type of exceptions the method may throw. The use
of the raises clause in the IDL interface definitions is important. While the raises information is not used
by all languages when making intra language calls it is required by some. For example C++ does not use
the information but Java requires it. Also when calls to SCA interface methods cross language
boundaries, the various SCA language bridges are responsible for marshalling the data. These bridges
will not allow exceptions to pass unless they have been specified in IDL. If a method throws an exception
that is not specified in the IDL definition, it will be converted to a SCASystemException exception and
some valuable information it contains may be lost. The section on exception propagation rules later in
this section discusses in detail the rules used by the language bridges to propagate exceptions. Since the
IDL definitions are language neutral and you never know which language they be implemented in you
should always include the raises information. Also you can never be sure when a call to the interface may
have to cross language boundaries.
An important thing to notice about SCA exceptions is they only contain data. The IDL definition does
not provide for any implementation to be included as part of the definition. The main reason for this is
that exceptions may need to be marshaled between different languages and it is extremely difficult to
marshal implementation. If you wish to attach implementation to a SCA exception there are several ways
this can be done. The easiest way is to create your own custom class that inherits from the IDL defined
SCA exception class. The disadvantage of this approach is the implementation in your custom class and
any data it contains will be lost if the exception has to be marshaled to a different language. The second
approach is to include a SCA interface member in the definition of the exception which contains the
implementation you wish to associate with the exception. This interface will be correctly marshaled
between different language types. The disadvantage of this approach is that each call to this interface will
itself need to be marshaled back to the language that it was originally implemented in. If the number of
calls is small this is not a problem, but there can be performance penalties if a large number of calls are
made.
The following example IDL shows the definition of a user exception, ReaderException, and an interface
method, readModel, which can throw it. These definitions will be used for the examples in rest of this
section.
Chapter 10: Error Processing 295
Using SCA Exceptions for Error Handling

IDL
#ifndef SDK_ERRORHANDLING_EXCEPTIONS_FILEREADER_IDL_INCLUDED
#define SDK_ERRORHANDLING_EXCEPTIONS_FILEREADER_IDL_INCLUDED

#include "SCA/Service.idl"

module SDK { module ErrorHandling { module Exceptions {

exception ReaderException : SCA::SCAUserException


{
SCA::SCAString modelName;
};

interface SCAIReader : SCA::SCAIService


{
void readModel( in SCA::SCAString name ) raises(ReaderException);
};

}; }; };

#endif

SCA Exception Hierarchy


The SCA exception hierarchy is shown below. The ultimate base of all SCA exceptions is
SCAException. The SCASystemException is a special exception that is mainly used by the SCA
framework to handle internal errors. The SCAUserException inherits SCAException and it is the base
for all user defined exceptions, directly or indirectly.

SCA Framework provided Exceptions


Three exceptions types, SCA::SCAException, SCA::SCASystemException, and
SCA::SCAUserException, are predefined in the SCA Framework.

The SCAException Exception


The SCAException is the base for all exceptions. It has the following IDL definitions.

IDL
module SCA {
exception SCAException
{
SCAString text;
};
};
This exception contains a SCAString value that the user can set to describe the nature of the exception.
Each language mapping for the SCAException provides a way to set and fetch the value of this string.
Since SCAException is the base class for all SCA exceptions, many of the methods it contains are
available to all SCA exceptions. The individual language mapping for the SCAException may also
296 SCA Framework User’s Guide
Using SCA Exceptions for Error Handling

contain other information required by the SCA Framework but these should generally not be used for
other purposes.

The SCASystemException Exception


SCASystemException is used to handle internal SCA framework errors that cannot be conveniently
reported in any other manner. Even if a method does not have a raises clause in its definition, the
SCASystemException may always be thrown. The IDL definition of the SCASystemException is as
follows.

IDL
module SCA {
exception SCASystemException : SCAException {
SCAInt32 id;
};
};
This exception contains an integer error value that is used to contain one of the following SCA system
errors.

SCA System Error ID SCA System Error Description


2000000010 Unknown error
2000000020 Invalid interface
2000000030 Invalid method
2000000040 Invalid Parameter(s)
2000000050 Undefined type code
2000000060 Communication failure
2000000070 Data conversion error
2000000080 Memory error
2000000090 Implementation not available
2000000100 Invalid exception thrown
2000000110 Error reading type codes
2000000120 Error in CORBA Rpc bridge
2000000130 Error in C++ bridge
2000000140 C++ interface cast failed
2000000150 XML TypeCode processing error
2000000160 Error in python bridge
2000000170 Marshalling error
2000000180 SCABinary processing error
Chapter 10: Error Processing 297
Using SCA Exceptions for Error Handling

SCA System Error ID SCA System Error Description


2000000190 Internal Error
2000000200 Error in Java bridge
2000000210 SCAAny marshalling error
2000000220 SCA Kernel initialization error
2000000230 Invalid global service provider
2000000240 SCA Framework configuration error
2000000250 Error in .NET bridge
2000000260 SCADynAny error
2000000270 Corruption in SCASequence memory
2000000280 getSCAService error
2000000290 Error terminating the SCA Kernel
2000000300 Error initializing embedded component
2000000310 Error terminating embedded component

Most of these errors are generated during the marshalling of data through SCA language bridges. Many
are unexpected problems which should never occur but there are others that can easily occur because of
the nature of some of the SCA language mappings. For example the Python language only supports 32
and 64 bit integers. As a result types like the SCAInt16 are mapped to a 32 bit integer. When an interface
method is called that has a SCAInt16 argument, the value in the 32 bit Python integer is checked to make
sure it will fit in the required SCA type. If it is too large then a SCASystemException will be generated
with one of the above codes. It is the responsibility of the Python code to make sure that this condition
never happens.
For the complete definitions of these errors see the SCA/SystemError.h header file delivered with the
SCA Framework.

The SCAUserException Exception


The SCAUserException is the (direct or indirect) base for all user defined exceptions. It has the
following IDL definition.

IDL
module SCA {
exception SCAUserException: SCAException
{
};
};
This exception does not contain any data member. Its purpose is to only define the base class for user
defined exceptions.
298 SCA Framework User’s Guide
Using SCA Exceptions for Error Handling

Exception API
The syntax for using SCA exceptions and the API they provide is different for each supported language.
The following example code shows how an instance of the ReaderException can be created and thrown
in C++.

C++
ReaderException except;
except.modelName = name;
except.setText("The requested model \""+name+
"\" could not be located.");
except.throwit();
Notice that the actual exception is thrown using the throwit method it provides and not using the normal
C++ throw statement. This is an important rule which is discussed in detail in the IDL to C++ Mapping
chapter of this manual.
The exception can be caught and processed like this.
try {
spReader->readModel("Test.Model");
} catch (SCAException& e) {
cout << e.what() << endl;
}
For language specific exception APIs, please refer to the respective Language Mapping chapters of this
manual.

Exception Propagation Rules


The exact rules covering the throwing and catching of exception vary depending on whether the thrower
and the catcher are coded in the same language or in different languages.

Inter Language Propagation Rules


An IDL exception thrown from a callee can be caught by the caller even when the callee and the caller
are coded in different languages. In the case of inter language calls, the exceptions must be marshaled
through a SCA language bridge. The following rules apply in this case.
• Exception types that are defined in the raises clause always pass through the language bridges.
• Exception that inherits (directly or indirectly) from an exception in the raises clause always
passes through the language bridges.
• Users may define their own non SCA exception classes that inherit from the SCA exception
classes. In this case the SCA exception that is inherited from is the one that determines if it will
pass through the language bridges. When these exceptions are thrown, only the data defined in
SCA exception definitions will be passed. Any data in the non SCA exception class will be lost.
• The SCASystemException always pass through the language bridges.
Chapter 10: Error Processing 299
Using SCA Exceptions for Error Handling

• All other exceptions are blocked by the language bridge and a SCASystemException is thrown
instead. In this case any data contained in the original exception will be lost.
For an example of these rules, consider the following exception hierarchy.
IDL
exception SCAException { };
exception SCAUserException : SCAException { };
exception TestExcept1 : SCAUserException { };
exception TestExcept2 : TestExcept1 { };
exception TestExceptX: SCAUserException { };
The following table shows which combination of exceptions specified on the raises clause in the IDL and
the actual exception thrown are allowed to pass through the SCA language bridges. The exceptions that
are not allowed to pass will be converted to a SCASystemException.

Raises clause Thrown Does bridge pass


SCAUserException TestException1 Yes
SCAUserException TestException2 Yes
SCAUserException TextExceptionX Yes
SCAUserException None SCA Exception No
TestException1 TestException1 Yes
TestException1 TestException2 Yes
TestException1 TextExceptionX No
TestException1 None SCA Exception No
TestException2 TestException1 No
TestException2 TestException2 Yes
TestException2 TextExceptionX No
TestException2 None SCA Exception No

Intra Language Propogation Rules


Normally when making interface calls between a caller and callee written in the same language, the SCA
framework is not involved. As a result the rules for using exceptions in this case are the normal rules that
apply to the language being used.

Exception Catching Rules


The rules covering which exceptions will be caught by which catch statement is completely a function of
the language you are catching the exception in. It does not matter which language the exception was
thrown in. This is because when an exception is marshaled through a SCA language bridge it will be
rethrown by the bridge in the language of the caller. The exception that is rethrown is either the original
exception thrown if it passes the propagation rules discussed above or else a SCASystemException. In
300 SCA Framework User’s Guide
Using SCA Exceptions for Error Handling

either case it is now a native exception in the language of the caller and the rules for this language are
used.
Most languages have a similar set of rules governing which exceptions will be caught by which catch
statement. Normally, a catch statement, or whatever the equivalent statement is in the language you are
using, will catch an exception that is the same as the one thrown or if it is a base class of the one thrown.
Using the same exception hierarchy that was used above the following table shows how these rules
typically work.

Catch Statement Exception Thrown Will it be Caught


SCAUserException TestException1 Yes
SCAUserException TestException2 Yes
SCAUserException TextExceptionX Yes
TestException1 TestException1 Yes
TestException1 TestException2 Yes
TestException1 TextExceptionX No
TestException2 TestException1 No
TestException2 TestException2 Yes
TestException2 TextExceptionX No
TestExceptionX TestException1 No
TestExceptionX TestException2 No
TestExceptionX TextExceptionX Yes

Recommended usage of SCA Exceptions


There is nothing special about SCA exceptions and the best practice usage of them is the same as using
normal exception processing. But there are a few rules that should be followed to better utilize the
infrastructure provided by the SCA framework.
• Always throw user-defined exceptions. You should never directly throw a SCAException or
SCASystemException.
• When you throw an SCA user-defined exception, always define the basic text field that is
provided by the SCAException. This way there will be some information about the exception
regardless of the exception class that is actually caught.
• In your code, only add catch statements for exceptions that you expect to catch and have some
special processing for.
• Always have a catch block for the SCAException class somewhere in the calling tree. Since all
SCA exceptions inherit from this one, this catch block will catch any SCA exception that was
not explicitly caught by any other catch block. The text field of this exception can then be used to
provide some useful information.
Chapter 10: Error Processing 301
Using SCA Exceptions for Error Handling

Complete Exception Error Handling Example for a SCA


Service
The following is the complete implementation of an example FileReader service that shows the use of
SCA exceptions for error handling. This service implements the SCAIReader interface.
The IDL for this example was defined earlier in this chapter. The SDL and CDL files for this example
are as follows.

SDL
#ifndef FILEREADER_SDL_INCLUDED
#define FILEREADER_SDL_INCLUDED

#include "SDK/ErrorHandling/Exceptions/FileReader.idl"

module SDK { module ErrorHandling { module Exceptions {

service SDK.ErrorHandling.Exceptions.FileReader
{
interface SCAIReader;
};

}; }; };

#endif

CDL
#ifndef FILEREADER_CDL_INCLUDED
#define FILEREADER_CDL_INCLUDED

#include "FileReader.sdl"

component SDK.ErrorHandling.FileReaderExceptions
{
service FileReader;
};

#endif
The SCAIReader interface contains a single method, readModel that must be implemented. Only the
portion of the implementation that shows the error handling functionality is shown in this example. The
rest of the code is omitted to keep the code sample small. The implementation files for the FileReader
service follow.

FileReader.h
#ifndef SDK_ERRORHANDLING_EXCEPTIONS_FILEREADER_H_INCLUDED
#define SDK_ERRORHANDLING_EXCEPTIONS_FILEREADER_H_INCLUDED

#include "FileReaderBase.h"
302 SCA Framework User’s Guide
Using SCA Exceptions for Error Handling

namespace SDK { namespace ErrorHandling { namespace Exceptions {

class FileReader : public FileReaderBase


{
public:

// Constructor and Destructor


FileReader(SCAIFileReaderFactoryAccess* factoryAccess);
virtual ~FileReader();

// Methods for interface SDK.ErrorHandling.Exceptions.SCAIReader


virtual SCA::SCAVoid readModel(const SCA::SCAString name);
};

} } }

#endif

FileReader.cpp
#include "FileReader.h"

namespace SDK { namespace ErrorHandling { namespace Exceptions {

// Constructor
FileReader::FileReader(SCAIFileReaderFactoryAccess* factoryAccess)
: FileReaderBase(factoryAccess)
{
}

// Destructor
FileReader::~FileReader()
{
}

SCA::SCAVoid FileReader::readModel(const SCA::SCAString name)


{
bool error;

// Locate the model


. . . .

// Return error if model could not be located


if ( error ) {
ReaderException except;
except.modelName = name;
except.setText("The requested model \""+name+
"\" could not be located.");
except.throwit();
}

// Process the model


. . . .
Chapter 10: Error Processing 303
Using SCA Exceptions for Error Handling

// Return error processing the model


if ( error ) {
ReaderException except;
except.modelName = name;
except.setText("An error was encountered reading model \""+
name+"\".");
except.throwit();
}

// Return
return;
}

} } }

The example client application that uses this version of the FileReader service is shown next.

Client.cpp
#include <iostream>
using namespace std;
#include <SCA/SCAKernel.h>
#include "SCA/Framework/SCAIMessageDispatcher.h"
#include <SDK/ErrorHandling/Exceptions/SCAIReader.h>

using namespace SCA;


using namespace SDK::ErrorHandling::Exceptions;

int main()
{
try {
cout << "Test using exceptions for error processing" << endl;

// Initialize the SCA Kernel


initializeSCAKernel(1);

// Load the FileReader service


SCAString svcName = "SDK.ErrorHandling.SCAResult.FileReader";
SCAIReader spReader = getSCAService(svcName);

// Read the model


try {
spReader->readModel("Test.Model");
} catch (SCAException& e) {
cout << e.what() << endl;
}

// Clean up
spReader = NULLSP;
304 SCA Framework User’s Guide
Using SCA Exceptions for Error Handling

// Terminate the SCA Kernel


terminateSCAKernel();

} catch (SCAException& e) {
cout << e.what() << endl;
}
return 0;
}
Chapter 10: Error Processing 305
Using SCAResult for Error Handling

Using SCAResult for Error Handling

Introduction
If you choose to use the error handling method where interface methods return error codes, the SCA
framework provides the SCAResult type. A SCAResult instance provides information about what
happened within the interface method. This includes whether the method was successful or failed and
optional information that is used to generate an appropriate error message. The SCAResult data type is
used in conjunction with the MessageDispatcher service to format the messages in the desired language
and optionally to dispatch them. In this section, examples will show how the SCAResult data type and
the MessageDispatcher service can be used to process errors.
For this discussion we will use the same FileReader service that was previously used to demonstrate the
use of SCA exceptions for error handling. Only in this case we will modify the IDL so the readModel
method now returns a SCAResult value instead of throwing an exception.

IDL
#ifndef SDK_ERRORHANDLING_SCARESULT_FILEREADER_IDL_INCLUDED
#define SDK_ERRORHANDLING_SCARESULT_FILEREADER_IDL_INCLUDED

#include "SCA/Service.idl"

module SDK { module ErrorHandling { module SCAResult {

// Error codes
const SCA::SCAInt32 MODEL_LOCATE_ERR = 1;
const SCA::SCAInt32 MODEL_READ_ERR = 2;

// Message ids
const SCA::SCAInt32 MODEL_LOCATE_MSG = 101;
const SCA::SCAInt32 MODEL_READ_MSG = 102;

// Message severity values


enum MSG_SeverityType {
SDK_INFORMATION,
SDK_WARNING,
SDK_ERROR
};

interface SCAIReader : SCA::SCAIService


{
SCA::SCAResult readModel( in SCA::SCAString name );
};

}; }; };

#endif
306 SCA Framework User’s Guide
Using SCAResult for Error Handling

The SCAResult data contents


The SCAResult type is used to return error information from calls to interface methods. It contains the
following information.
• Error code – The meaning of the error code values are defined by the service you are using.
There may be a unique set of error codes for each method or a single set for the entire service or
component. You should consult the documentation of the service you are using for definitions of
the error codes that it may return.
• Message table ID – The message table ID is a unique value that is assigned by the
MessageDispatcher service when a message table is registered. In order to use a message in a
message table, the message table must be first registered with the MessageDispatcher service.
This registration is the responsibility of the service that will be returning SCAResult values that
reference the message table.
• Message number – Message number in the message table referenced by the message table ID.
• Message parameters – Optional values for parameters that will be used to format the requested
messages.
The use of the message information in the SCAResult is optional. When used, the messages in
SCAResult values may also include parameter values that will be substituted during the formatting of
the message. The following types of parameters are supported in a SCAResult.

SCA Type
SCAInt8
SCAUInt8
SCAInt16
SCAUInt16
SCAInt32
SCAUInt32
SCAInt64
SCAUInt64
SCAReal32
SCAReal64
SCAChar
SCAWChar
SCAString
SCAWString
SCABool
Chapter 10: Error Processing 307
Using SCAResult for Error Handling

You should consult the appropriate IDL mapping chapter for the language you are using for the exact
syntax for adding parameter values to a SCAResult instance.

Overview of using the SCAResult for Error Handling


The general error processing steps for using the SCAResult are as follows.
• The client application loads the SCA FileReader service.
• The constructor for the service instance uses the MessageDispatch to register its message table
with the framework and saves the message table ID that is returned.
• The client calls the readModel interface method.
• The readModel method tries to read the model but encounters an error. It formats a SCAResult
value and returns it to the caller. The SCAResult value includes an error code value, the message
table ID, the message number and any optional parameter values.
• The client checks the error code in the SCAResult value to determine if there is an error.
• The client uses the MessageDispatcher to format the message contained in the SCAResult
value. The formatted message is either dispatched to any registered message listeners or returned
to the client.

Registering Message Tables


The definition of messages that are reference by the SCAResult values must be defined in a SCA XML
message table. For a complete description of the format of these message tables see the Messages and
Internationalization chapter of this manual. For our test service we have defined a simple message table
with several messages. The following is the English version of the message table.

FileReaderMsgTable_en.xml
<?xml version='1.0' encoding='UTF-8' ?>
<!--
Copyright (c) 2009, MSC.Software Corporation. All Rights Reserved.
MSC PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
-->
<sim_office_resources version="1.0" xml:lang="en"
comment="Message Table for FileReader Service">
<text id="101" comment="MODEL_LOCATE_MSG" >
The requested model "%1:%s" could not be located.
</text>
<text id="102" comment="MODEL_READ_MSG" >
An error was encountered reading model "%1:%s:".
</text>
</sim_office_resources>
We also provide a German version of the messages.

FileReaderMsgTable_de.xml
<?xml version='1.0' encoding='UTF-8' ?>
308 SCA Framework User’s Guide
Using SCAResult for Error Handling

<!--
Copyright (c) 2009, MSC.Software Corporation. All Rights Reserved.
MSC PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
-->
<sim_office_resources version="1.0" xml:lang="en"
comment="Message Table for FileReader Service">
<text id="101" comment="MODEL_LOCATE_MSG" >
Das angeforderte Modell "%1:%s" konnte nicht gefunden werden.
</text>
<text id="102" comment="MODEL_READ_MSG" >
Beim Einlesen des Modells "%1:%s:" trat ein Fehler auf.
</text>
</sim_office_resources>

If you look at the IDL for FileReader example earlier in this chapter, you will see a set of IDL constants
were also defined for each message. These can be used when creating SCAResult values instead of using
hardcoded values. The use of these constants is a recommended practice because it provides a consistent
location to document the messages and makes maintenance easier.

IDL
// Message ids
const SCAInt32 MODEL_LOCATE_MSG = 101;
const SCAInt32 MODEL_READ_MSG = 102;
In order to use a message table, the table must be first registered with the MessageDispatcher service.
Normally a service will do this registration in its constructor and save the message table IDL for later use.
When registering the message table you used the portion of the filename for the table which does not
include the language information. For our example, the name used for the registration would be
FileReaderMsgTable.
The following code shows how the the message table is registered.

C++
#include "SCA/Framework/SCAIMsgTableManager.h"

// Register our message table


SCA::Framework::SCAIMsgTableManager spManager;
spManager = getService("SCA.Framework.MessageDispatcher");
spManager->addTable(L"FileReaderMsgTable",m_msgTableID);
In this example code the message table ID returned is m_msgTableID which should be saved for later use
when it is necessary to format a SCAResult value.

Formatting a SCAResult value


There are a number of different ways that the SCAResult can be used to return error information.
• The SCAResult may only contain a success or failure indications
• The SCAResult may only contain an error code value
Chapter 10: Error Processing 309
Using SCAResult for Error Handling

• The SCAResult may contain both an error code value and the information to format a message.

There may be times when specific error code values are not required. Instead it is only necessary to
indicate if the method call succeeded or failed. In this case you can use one of the two predefined
SCAResult values provided by the SCA framework.

SCA::SCASuccess Error code = 0


SCA::SCAError Error Code = 0X7FFFFFFF

If the readModel method in our example only needed to return a generic error indication it could use the
predefined SCAError value as follows.

C++
return SCAError;
Normally, this is not the ideal solution because it does not provide any details to the caller about what the
error actual was. As a result it is usually a better solution if you at least return an error code value that
represents the error that occurred.
If you look at the example IDL again, you will notice that a set of constant values were also defined for
the error codes that can be returned. Depending on how you have set up your error code values and
message IDs, you may choose to use a single set of constant values for both.
// Error codes
const SCAInt32 MODEL_LOCATE_ERR = 1;
const SCAInt32 MODEL_READ_ERR = 2;
The use of these constants is a recommended practice because it provides a consistent place where the
possible error code values can be documented for the users of the service. Additionally, the use of IDL
defined constants reduces maintenance of the code. If you need to change error values they only need to
be changed in the IDL file and not in every implementation and client file that uses them.
The readModel interface routine could now create a SCAResult instance containing only an error code
if that was appropriate. In this example we are using the IDL defined constants to indicate the error code
value.

C++
SCAResult rstat = SCAResult(MODEL_READ_ERR);
return rstat;
Normally, it is more desirable to also include message information that your callers can use to format and
display a message which described the details of the error. The following code adds a message to the
SCAResult value. The message requires one parameter which is the name of the model that cannot be
read.

C++
SCAResult rstat;
310 SCA Framework User’s Guide
Using SCAResult for Error Handling

rstat = SCAResult(MODEL_READ_ERR,m_msgTableID,MODEL_READ_MSG);
rstat.addParam(name);
return rstat;
If the readModel method did not encounter any errors, then it should return the predefined SCASuccess
value to indicate that the operation was successful.

C++
return SCASuccess;
The exact syntax for using the SCAResult data type is a function of the language you are using. Although
the basic concepts are the same in all of the languages the exact syntaxes are a bit different. For complete
details you should consult the IDL mapping chapter in this manual for your language.

Complete SCAResult Error Handling Example for a SCA


Service
The following is the complete implementation of the example FileReader service which now uses
SCAResult values for error handling.
The IDL for this example was defined earlier in this chapter. The SDL and CDL files for this example
follow.

SDL
#ifndef FILEREADER_SDL_INCLUDED
#define FILEREADER_SDL_INCLUDED

#include "SDK/ErrorHandling/SCAResult/FileReader.idl"

module SDK { module ErrorHandling { module SCAResult {

service SDK.ErrorHandling.SCAResult.FileReader
{
interface SCAIReader;
};

}; }; };

#endif

CDL
#ifndef FILEREADER_CDL_INCLUDED
#define FILEREADER_CDL_INCLUDED

#include "FileReader.sdl"

component SDK.ErrorHandling.FileReaderSCAResult
{
service FileReader;
};
Chapter 10: Error Processing 311
Using SCAResult for Error Handling

#endif
The new versions of the implementation files for the service are as follows. Once again only the error
processing logic of the readModel method has been included.

FileReader.h
#ifndef SDK_ERRORHANDLING_SCARESULT_FILEREADER_H_INCLUDED
#define SDK_ERRORHANDLING_SCARESULT_FILEREADER_H_INCLUDED

#include "FileReaderBase.h"

namespace SDK { namespace ErrorHandling { namespace SCAResult {

class FileReader : public FileReaderBase


{
public:

// Constructor and Destructor


FileReader(SCAIFileReaderFactoryAccess* factoryAccess);
virtual ~FileReader();

// Methods for interface SDK.ErrorHandling.SCAResult.SCAIReader


virtual SCA::SCAResult readModel(const SCA::SCAString name);

private:
// Message table ID assigned by the MessageDispatcher
SCA::SCAInt32 m_msgTableID;
};

} } }

#endif

FileReader.cpp
#include "FileReader.h"
#include "SCA/Framework/SCAIMsgTableManager.h"
#include "SDK/ErrorHandling/SCAResult/FileReaderTypes.h"

namespace SDK { namespace ErrorHandling { namespace SCAResult {

// Constructor
FileReader::FileReader(SCAIFileReaderFactoryAccess* factoryAccess)
: FileReaderBase(factoryAccess)
{
// Register our message table
SCA::Framework::SCAIMsgTableManager spManager;
spManager = getService("SCA.Framework.MessageDispatcher");
spManager->addTable(L"FileReaderMsgTable",m_msgTableID);
}

// Destructor
FileReader::~FileReader()
312 SCA Framework User’s Guide
Using SCAResult for Error Handling

{
}

SCA::SCAResult FileReader::readModel(const SCA::SCAString name)


{
SCA::SCAResult rstat;
bool error;

// Locate the model


. . . .

// Return error if model could not be located


if ( error ) {
rstat = SCA::SCAResult(MODEL_LOCATE_ERR,
m_msgTableID,
MODEL_LOCATE_MSG);
rstat.addParam(name);
return rstat;
}

// Process the model


. . . .

// Return error processing the model


if ( error ) {
rstat = SCA::SCAResult(MODEL_READ_ERR,
m_msgTableID,
MODEL_READ_MSG);
rstat.addParam(name);
return rstat;
}

// Successful return
return SCA::SCASuccess;
}

} } }

Use of SCAResult values in the client


Up until this point, we have discussed how the SCAResult values are created and returned from a SCA
service. Now we will discuss how the values are used by the clients of the service.
The procedure for using the SCAResult value depends on the type of error and message values it
contains. For example if a simple SCASuccess or SCAError value is returned all that is required is to
check the error code as follows.

C++
if ( rstat ) {
cout << "Error encountered" << endl;
return 1;
}
Chapter 10: Error Processing 313
Using SCAResult for Error Handling

if ( !rstat.isOk() ) {
cout << "Error encountered" << endl;
return 1;
}
But the disadvantage of this approach is there is no indication of what the error may have been. To add
some additional information, the interface method may return different error code values which may be
checked.

C++
if ( rstat == MODEL_LOCATE_ERR ) {
cout << "Error encountered locating the model" << endl;
return 1;
} else if ( rstat == MODEL_READ_ERR ) {
cout << "Error encountered reading the model" << endl;
return 1;
}
But ideally the service will also include message information in the SCAResult value that can be used
to format a message. In this example we use the MessageDispatcher to format the message and print it.
The second blank argument to the getMessage call is the language the message should be formatted in.
In this case the blank value means the current default language setting.

C++
if ( rstat ) {
SCA::Framework::SCAIMessageDispatcher spDispatcher;
spDispatcher = getSCAService("SCA.Framework.MessageDispatcher");
SCAWString wstr;
spDispatcher->getMessage(rstat,"",wstr);
wcout << wstr << endl;
return 1;
}
It is also possible to dispatch the message to any registered message listeners. See the section on the
MessageDispatcher later in this chapter for more details on message listeners. In this example the
dispatchMessage method is used to dispatch the message. The second argument of zero in the call is
severity level you can set. This value is passed to the message listeners and they can use it as required.

C++
if ( rstat ) {
SCA::Framework::SCAIMessageDispatcher spDispatcher;
spDispatcher = getSCAService("SCA.Framework.MessageDispatcher");
spDispatcher->dispatchMessage(rstat,0);
return 1;
}
The following is simple C++ client application that uses the FileReader service and does the appropriate
handling of any errors. In this example we are using the getMessage method to format the error message
and printing it out.
314 SCA Framework User’s Guide
Using SCAResult for Error Handling

Client.cpp
#include <iostream>
using namespace std;
#include <SCA/SCAKernel.h>
#include "SCA/Framework/SCAIMessageDispatcher.h"
#include <SDK/ErrorHandling/SCAResult/SCAIReader.h>
#include <SDK/ErrorHandling/SCAResult/FileReaderTypes.h>

using namespace SCA;


using namespace SDK::ErrorHandling::SCAResult;

int main()
{
try {
cout << "Test using MessageDispatcher to format errors" << endl;

// Initialize the SCA Kernel


initializeSCAKernel(1);

// Load the FileReader service


SCAString svcName = "SDK.ErrorHandling.SCAResult.FileReader");
SCAIReader spReader = getSCAService(svcName);

// Read the model


SCAResult rstat = spReader->readModel("Test.Model");
if ( rstat ) {
SCA::Framework::SCAIMessageDispatcher spDispatcher;
spDispatcher =
getSCAService("SCA.Framework.MessageDispatcher");
SCAWString wstr;
spDispatcher->getMessage(rstat,"",wstr);
wcout << wstr << endl;
}

// Clean up
spReader = NULLSP;

// Terminate the SCA Kernel


terminateSCAKernel();

} catch (SCAException& e) {
cout << e.what() << endl;
}
return 0;
}
If this application was run, and the readModel method returned an error indicating it could not locate the
model, the following is what the output of the formatted message would look like if the default language
was English.
The requested model "Test.Model" could not be located.
If the default language was German, we would get the following.
Das angeforderte Modell "Test.Model" konnte nicht gefunden werden.
Chapter 10: Error Processing 315
Using SCAResult for Error Handling

It is also possible to use a message listener and then used the dispatchMessage method to dispatch the
error. This technique will be shown in the next section.
316 SCA Framework User’s Guide
MessageDispatcher Service

MessageDispatcher Service
The MessageDispatcher is a messaging service that formats the message information stored in
SCAResult values and optionally dispatches them. The MessageDispatcher service provides three
functions each of which is handled by a different interface.
• SCAIMsgTableManager - Acts as a front-end to the TextTranslation service discussed in the
Messages and Internationalization chapter of this manual and manages instances of client
registered message tables and their locales
• SCAIMsgListenerManager - Manages instances of client registered message listeners
• SCAIMessageDispatcher - Formats and optionally dispatches messages

The MessageDispatcher service uses message listeners to process the dispatched messages. The main
reason for message listeners is to allow an application to compartmentalize the handling of messages into
a single piece of code instead of spreading it around the application. A message listener is a SCA object
which implements the SCAIMessageListener interface. This code must be provided by the clients of the
MessageDispatcher and instances of the SCAIMessageListener interface must be registered by the
client if the dispatching of messages is used. Each message listener can specify its own locale that it wants
any message formatted in or it may choose to use the current system default locale. An application may
utilize as many message listeners as it needs. Normally a different listener would be used for each
different type of processing that is required for dispatched messages. For example there may be one
listener that handles the logging of messages to a log file and a different listener that informs the user of
the errors by displaying them in a message box.
The MessageDispatcher is tightly coupled with the SCAResult data type. The SCAResult type
provides the data structure where the information required for formatting the message is stored. This
include the message number, message table ID and any optional message parameters. The
MessageDispatcher service ignores the error code data value in the SCAResult instant.
It is also possible to use the MessageDispatcher service to format general messages and not just error
messages. To do this you just create a SCAResult value with the appropriate message information. In
this case the error ID information has no meaning. The same interface methods in the
SCAIMessageDispatcher interface are then use to format and optionally dispatch the message.
The following sections describe each of the three interfaces and shows examples of how they are used.

SCA::Framework::SCAIMsgTableManager Interface
The SCAIMsgTableManager interface allows a client service to register message tables with the
MessageDispatcher.
Chapter 10: Error Processing 317
MessageDispatcher Service

Inherits SCA::SCAIService.

Member Functions
SCAResult addTable (in SCAWString fileBaseName, out SCAInt32 tableId)

Member Function Documentation

SCAResult addTable ( in SCAWString fileBaseName,


out SCAInt32 tableId
)

Method to add a message table to the Messaging service so it can be used in a SCAResult value. If the
table has already been added, then the table ID that was previously assigned for it will be returned.
Parameters:

[in] fileBaseName Message table root name which does not include locale information.
[out] tableId Table ID that can be used to create a SCAResult value.

Returns:
SCAResult Status of request which should always be a SCASuccess
In order to use a message table, the table must be first registered with the MessageDispatcher service.
Normally, a service will do this registration in its constructor and save the message table ID for later use.
To register the message table you use the portion of the filename for the table which does not include the
language information. In our example the complete name of the message table names were
FileReaderMsgTable_en.xml and FileReaderMsgTable_de.xml so the name for addTable call would be
FileReaderMsgTable.
The following code shows how the message table is registered using this interface.

C++
#include "SCA/Framework/SCAIMsgTableManager.h"

// Register our message table


SCA::Framework::SCAIMsgTableManager spManager;
spManager = getService("SCA.Framework.MessageDispatcher");
spManager->addTable(L"FileReaderMsgTable",m_msgTableID);
The addTable method returns an integer message table ID, m_msgTableID in this example, which should
be saved. It is required when creating SCAResult instances which reference messages defined in this
table. Once a table has been registered the table ID will be valid for the duration of the current execution.
318 SCA Framework User’s Guide
MessageDispatcher Service

It is also important to understand that the addTable method will always return a SCASuccess value. This
is true even if there are no message tables available that match the name provided. This is because the
registering of a table does not trigger the processing of the actual XML file for the message table. At the
time of registration it is not known what language will actually be used to format any of its messages and
there may be multiple message tables available. The actual language is not determined until a message is
formatted so the processing of the XML file must be delayed until that time. If the message table cannot
be found or there are errors reading it at this time, the formatting operation will instead return a message
indicating why the desired message could not be formatted. It will also include the message number and
table name so you can still determine what the original error was. The following is an example of what
one of these messages would look like.
Error formatting message 101 in table FileReaderMsgTable
XML file for message table FileReaderMsgTable for locale "en_US.1252"
or "en" does not exist.

SCA::Framework::SCAIMsgListenerManager Interface
The SCAIMsgListenerManager interface allows a client service to add and remove message listeners.
Inherits SCA::SCAIService.

Member Functions
SCAResult addListener (in SCAIMessageListener msgListener, in
SCAString locale)
SCAResult removeListener (in SCAIMessageListener msgListener)

Member Function Documentation

SCAResult addListener ( in SCAIMessageListener msgListener,


in SCAString locale
)

Method to add a message listener to the Messaging service.


Parameters:

[in] msgListener Interface to the listener that is to be added.


[in] locale Locale string for this message listener. All messages dispatched to this listener
will be formatted in this locale. The value can be an empty string which means
the listener uses the current default locale.

Returns:
Chapter 10: Error Processing 319
MessageDispatcher Service

SCAResult Status of request which should always be SCASuccess

SCAResult removeListener ( in SCAIMessageListener msgListener )

Method to remove a message listener from the Messaging service.


Parameters:

[in] msgListener Interface to the listener that is to be removed.

Returns:
SCAResult Status of request which should always be SCASuccess
The SCAIMsgListenerManager allows clients to add and remove message listeners. Each message
listener can specify the language that it wants the messages formatted in. It is not required for all
registered listeners to use the same locale. The following example shows how message listeners can be
added and removed. In this case we will request that the messages received by the listener be formatted
in German.

C++
// Get instance of message listener
SCAIMessageListener spListener = . . .;

// Register our message listener using the German locale


SCA::Framework::SCAIMsgListenerManager spManager;
spManager = getSCAService("SCA.Framework.MessageDispatcher");
spManager->addListener(spListener,"de");

// Application does its thing

// Remove our message listener


spManager->removeListener(spListener);
This example does not show how the message listener was actually implemented. Later in this section a
number of examples of this will be provided.

SCA::Framework::SCAIMessageDispatcher Interface
The SCAIMessageDispatcher interface is used to format messages. The formatted messages can either
be dispatched to the registered message listeners or returned to the caller.
320 SCA Framework User’s Guide
MessageDispatcher Service

Inherits SCA::SCAIService.

Member Functions
SCAResult setDefaultLocale (in SCAString locale)
SCAResult dispatchMessage (in SCAResult rStat, in SCAInt32 severity)
SCAResult getMessage (in SCAResult rStat, in SCAString locale, out SCAWString
outString)

Member Function Documentation

SCAResult dispatchMessage ( in SCAResult rStat,


in SCAInt32 severity
)

Method to format a message described by a SCAResult value and dispatch it to all registered listeners.
The message may need to be formatted several times if multiple message listeners have been added which
requested different locales.

Parameters:

[in] rStat The SCAResult value to format


[in] severity The severity code for the message. This value is passed directly to the message
listeners.

Returns:
SCAResult Status of request

SCAResult getMessage ( in SCAResult rStat,


in SCAString locale,
out SCAWString outString
)

Method to format a message described by a SCAResult value and return it to the caller.
Chapter 10: Error Processing 321
MessageDispatcher Service

Parameters:

[in] rStat The SCAResult value to format


[in] locale The locale string that the message will be formatted in. The value can be an
empty string which means the current default locale is used.
[out] outString Formatted message value

Returns:
SCAResult Status of request

SCAResult setDefaultLocale ( in SCAString locale )

Method to set the default locale for all message listeners that are added with a blank locale specified.
Calls to this routine will affect message listeners that were previously added as well as those that are
added in the future.

Parameters:

[in] locale Locale string

Returns:
SCAResult Status of request
The SCAIMessageDispatcher interface is used by the client to request the formatting of a message. The
message can be either returned directly to the caller or can be dispatched to all registered message
listeners. The first example shows how the message can be formatted and returned to the caller. In this
example the current default locale is used for the message translation.

C++
SCAResult rstat = sp->someMethod()
if ( rstat ) {
SCA::Framework::SCAIMessageDispatcher spDispatcher;
spDispatcher = getSCAService("SCA.Framework.MessageDispatcher");
SCAWString wstr;
spDispatcher->getMessage(rstat,"",wstr);
wcout << wstr << endl;
return 1;
}
It is also possible to dispatch the message to all register message listeners using the dispatchMessage
method. The second parameter in this call is the message severity. The severity value is passed directly
to the message listeners and not used by the MessageDispatcher itself. Each application can define its
own mechanism of interpreting the severity code or it can choose to ignore it altogether. One common
322 SCA Framework User’s Guide
MessageDispatcher Service

way of handling the severity value is to use an IDL enum definition to contain the valid values. In the
FileReader example we have used the following values for the severity of a message.

IDL
enum SeverityType
{
SDK_INFORMATION,
SDK_WARNING,
SDK_ERROR
}
These values can be used in the call to the dispatchMessage method.

C++
SCAResult rstat = sp->someMethod()
if ( rstat ) {
SCA::Framework::SCAIMessageDispatcher spDispatcher;
spDispatcher = getSCAService("SCA.Framework.MessageDispatcher");
spDispatcher->dispatchMessage(rstat,SDK_ERROR);
return 1;
}
The dispatchMessage call may result in the requested message being formatted more than once. This
could happen if multiple message listeners are registered and they require different languages.
The SCAIMessageDispatcher interface can also be used to change the default locale setting.

C++
SCA::Framework::SCAIMessageDispatcher spDispatcher;
spDispatcher = getSCAService("SCA.Framework.MessageDispatcher");
spDispatcher->setDefaultLocale("de");
It is important to remember that this default setting will affect all message listeners that are currently
registered which requested the default locale as well as any added in the future. Message listeners
currently registered that requested a specific locale are not affected.

SCA::Framework::SCAIMessageListener Interface
The SCAIMessageListener interface is used to implement message listeners that can be used with the
MessageDispatcher service.
Inherits SCA::SCAIService.

Member Functions
SCAResult doPublishMessage (in SCAWString str, in SCAInt32 severity)
Chapter 10: Error Processing 323
MessageDispatcher Service

Member Function Documentation

SCAResult doPublishMessage ( in SCAWString str,


in SCAInt32 severity
)

Method used by the MessageDispatcher to dispatch messages to the listeners that have been registered
with it.

Parameters:

[in] str Message to be dispatched.


[in] severity The severity level that was provided by the code that requested the message to be
dispatched.

Returns:
SCAResult Status of request
The SCAIMessageListener interface is used in the implementation of the message listeners that the
MessageDispatcher uses to dispatch messages. It must be implemented by the client application that is
using the MessageDispatcher service. Once an application has obtained an instance of the SCA object
that implements this interface, it must then register it with the MessageDispatcher service. Once a
message listener has been added then all messages dispatched through the MessageDispatcher will be
sent to the message listener until it is removed.
There are a number of different techniques that can be used to implement the SCAIMessageListener
interface.
• The interface can be implemented in a normal SCA service.
• The interface can be implemented in a SCA service contained in an embedded component.
• The interface can be implemented using techniques provided by the individual language
mappings. For example in C++ the SCAServiceObjectImpl templates could be used and in
Python the SCAIServiceBase class could be used.
Examples of the first and last of these methods are provided later in this section. For more details on using
embedded components and the SCAServiceObjectImpl templates see the SCA SDK Advanced Features
manual. The SCAIServiceBase class is described in the Python Mapping chapter of this manual.
The SCAIMessageListener interface has a single method.
doPublishMessage ( in SCAWString str, in SCAInt32 severity );
When implementing the SCAIMessageListener interface, the doPublishMessage method must be
implemented. This method will be called by the MessageDispatcher when there is a message to process.
The first argument is the formatted text string for the message in the language specified when the listener
324 SCA Framework User’s Guide
MessageDispatcher Service

was registered. The second input is the severity code that is provided by the call that originally dispatched
the message. Each application can define its own mechanism of interpreting the severity code or it can
choose to ignore it altogether.

Message Listener example using SCAServiceObjectImpl


template
The first example of using a message listener will implement it directly in the client application program.
This implementation will use one of the SCAServiceObjectImpl templates provided by the SCA
Framework to create a class which implements the SCAIMessageListener interface. For complete
details on using these templates see the SCA SDK Advanced Features manual.

Client.cpp
#include <iostream>
using namespace std;
#include <SCA/SCAKernel.h>
#include <SCA/Framework/ServiceObjectImpl.h>
#include "SCA/Framework/SCAIMessageDispatcher.h"
#include "SCA/Framework/SCAIMsgListenerManager.h"
#include "SCA/Framework/SCAIMessageListener.h"
#include <SDK/ErrorHandling/SCAResult/SCAIReader.h>
#include <SDK/ErrorHandling/SCAResult/FileReaderTypes.h>

using namespace SCA;


using namespace SCA::Framework;
using namespace SDK::ErrorHandling::SCAResult;

//
// Implementation of SCAIMessageListener interface
//
char ImplName[] = "ExampleListener";
class Listener : SCAServiceObjectImpl1
<SCAIMessageListener,ImplName>
{
public:
// Constructors and Destructor
Listener() { }
~Listener() { }

// Methods for interface SCA.Framework.SCAIMessageListener


SCAResult doPublishMessage(const SCAWString str,
const SCAInt32 severity) {
cout << "Error published with severity of "
<< severity << endl;
wcout << str << endl;
return SCASuccess;
}
};

int main()
{
Chapter 10: Error Processing 325
MessageDispatcher Service

try {
cout << "Test using local listener to format messages" << endl;

// Initialize the SCA Kernel


initializeSCAKernel(1);

// Get instance of message listener


Listener* pListener = new Listener();
SCAIMessageListener spListener = (SCAIMessageListener)pListener;

// Register our message listener


SCAIMsgListenerManager spManager;
spManager = getSCAService("SCA.Framework.MessageDispatcher");
spManager->addListener(spListener,"");

// Load the FileReader service


SCAString svcName = "SDK.ErrorHandling.SCAResult.FileReader";
SCAIReader spReader = getSCAService(svcName);

// Read the model


SCAResult rstat = spReader->readModel("Test.Model");
if ( rstat ) {
SCAIMessageDispatcher spDispatcher = spManager;
spDispatcher->dispatchMessage(rstat,SDK_ERROR);
}

// Clean up
spReader = NULLSP;
spManager = NULLSP;

// Terminate the SCA Kernel


terminateSCAKernel();

} catch (SCAException& e) {
cout << e.what() << endl;
}
return 0;
}

Message Listener example using a Logger Service Example


The next example of implementing a message listener will use a separate SCA service that provides basic
logging functionality. The logging service implements the SCAILogger interface which provides
methods to open and close the log file. It also implements the SCAIMessageListener interface so it can
function as a message listener and log any messages it receives. The following is the complete definition
of the logging service.

Logger.idl
#ifndef SDK_ERRORHANDLING_LOGGER_IDL_INCLUDED
#define SDK_ERRORHANDLING_LOGGER_IDL_INCLUDED

#include "SCA/Service.idl"
326 SCA Framework User’s Guide
MessageDispatcher Service

module SDK { module ErrorHandling {

interface SCAILogger : SCA::SCAIService


{
SCA::SCAResult openLog( in SCA::SCAString fileName,
in SCA::SCABool append );
SCA::SCAResult writeLog( in SCA::SCAString msg );
SCA::SCAResult closeLog( );
};

}; };

#endif

Logger.sdl
#ifndef LOGGER_SDL_INCLUDED
#define LOGGER_SDL_INCLUDED

#include "SDK/ErrorHandling/Logger.idl"
#include "SCA/Framework/MessageListener.idl"

module SDK { module ErrorHandling {

service SDK.ErrorHandling.Logger {
interface SCA::Framework::SCAIMessageListener;
interface SCAILogger;
};

}; };

#endif

Logger.cdl
#ifndef LOGGER_CDL_INCLUDED
#define LOGGER_CDL_INCLUDED

#include "Logger.sdl"

component SDK.ErrorHandling.Logger
{
service Logger;
};

#endif

The implementation for the logging service is as follows. To make the example code smaller and easier
to understand, the detailed error checking that would normally be part of the implementation has been
omitted.
Chapter 10: Error Processing 327
MessageDispatcher Service

Logger.h
#ifndef SDK_ERRORHANDLING_LOGGER_H_INCLUDED
#define SDK_ERRORHANDLING_LOGGER_H_INCLUDED

#include "LoggerBase.h"
#include <iostream>
#include <fstream>

namespace SDK { namespace ErrorHandling {

class Logger : public LoggerBase


{
public:

// Constructor and Destructor


Logger(SCAILoggerFactoryAccess* factoryAccess);
virtual ~Logger();

// Methods for interface SCA.Framework.SCAIMessageListener


SCA::SCAResult doPublishMessage(const SCA::SCAWString str,
const SCA::SCAInt32 severity);

// Methods for interface SDK.ErrorHandling.SCAILogger


SCA::SCAResult openLog(const SCA::SCAString fileName,
const SCA::SCABool append);
SCA::SCAResult writeLog(const SCA::SCAString msg);
virtal SCA::SCAResult closeLog();

private:
std::ofstream m_file;
};

} }

#endif

Logger.cpp
#include "Logger.h"
#include <SCA/StringUtility.h>
#include <time.h>
using namespace std;
using namespace SCA;

namespace SDK { namespace ErrorHandling {

// Constructor
Logger::Logger(SCAILoggerFactoryAccess* factoryAccess)
: LoggerBase(factoryAccess)
{
}

// Destructor
Logger::~Logger()
{
328 SCA Framework User’s Guide
MessageDispatcher Service

SCA::SCAResult Logger::doPublishMessage(const SCA::SCAWString str,


const SCA::SCAInt32 severity)
{
SCAString msg = StringUtility::stringFromWString(str);
m_file << "Error dispatched with severity of "
<< severity << endl;
m_file << msg << endl;
return SCASuccess;
}

SCA::SCAResult Logger::openLog(const SCA::SCAString fileName,


const SCA::SCABool append)
{
// Open the log file
if ( fileName.empty() ) {
return SCAError;
} else {
if ( append== true ) {
m_file.open(fileName.c_str(),
ios_base::out| ios_base::app);
} else {
m_file.open(fileName.c_str(),
ios_base::out| ios_base::trunc );
}
}

// Add the current date and time


time_t rawtime;
struct tm * timeinfo;
time ( &rawtime );
timeinfo = localtime ( &rawtime );
m_file << "Log file opened on " << asctime(timeinfo);

return SCASuccess;
}

SCA::SCAResult Logger::writeLog(const SCA::SCAString msg)


{
m_file << msg << endl;
return SCASuccess;
}

SCA::SCAResult Logger::closeLog()
{
m_file.close();
return SCASuccess;
}

} }
The following is a sample client that uses the logging service to save all error messages in a log file. It is
similar to our previous example except it loads and initializes an instance of the logging service and uses
Chapter 10: Error Processing 329
MessageDispatcher Service

it for the message listener instead of providing its own implementation. The client will also use the
logging feature to save messages indicating the flow of the program.

Client.cpp
#include <iostream>
#include <SCA/SCAKernel.h>
#include <SCA/Framework/ServiceObjectImpl.h>
#include "SCA/Framework/SCAIMessageDispatcher.h"
#include "SCA/Framework/SCAIMsgListenerManager.h"
#include "SCA/Framework/SCAIMessageListener.h"
#include <SDK/ErrorHandling/SCAResult/SCAIReader.h>
#include <SDK/ErrorHandling/SCAResult/FileReaderTypes.h>
#include <SDK/ErrorHandling/SCAILogger.h>

using namespace SCA;


using namespace SCA::Framework;
using namespace SDK::ErrorHandling;
using namespace SDK::ErrorHandling::SCAResult;

int main()
{
try {
cout << "Test using Logger service to process errors" << endl;

// Initialize the SCA Kernel


initializeSCAKernel(1);

// Get instance of error logger service and open a log file


SCAILogger spLogger;
spLogger = getSCAService("SDK.ErrorHandling.Logger");
spLogger->openLog("Test.log",false);

// Register our message listener


SCA::Framework::SCAIMsgListenerManager spManager;
spManager = getSCAService("SCA.Framework.MessageDispatcher");
SCAIMessageListener spListener = spLogger;
spManager->addListener(spListener,"");

// Get SCAIMessageDispatcher interface for future error


processing
// Load the FileReader service
SCAString svcName = "SDK.ErrorHandling.SCAResult.FileReader";
spLogger->writeLog("Getting "+svcName+" service");
SCAIReader spReader = getSCAService(svcName);

// Read the model


SCAString modelName = "Test.Model";
spLogger->writeLog("Reading model "+modelName);
SCAResult rstat = spReader->readModel(modelName);
if ( rstat ) {
SCAIMessageDispatcher spDispatcher = spManager;
spDispatcher->dispatchMessage(rstat,SDK_ERROR);
}
330 SCA Framework User’s Guide
MessageDispatcher Service

// Clean up
spReader = NULLSP;
spManager->removeListener(spListener);
spManager = NULLSP;
spLogger->closeLog();
spLogger = NULLSP;

// Terminate the SCA Kernel


terminateSCAKernel();

} catch (SCAException& e) {
cout << e.what() << endl;
}
return 0;
}
Chapter 11: Multi-Threaded Applications
SCA Framework User’s Guide

11 Multi-Threaded Applications


Introduction 332
 Thread Safety 333

Threading Infrastructure 338

Testing Multi-Threaded Services 339
 Sample Multi-Threaded Application 341
332 SCA Framework User’s Guide
Introduction

Introduction
Multithreading is a widespread programming and execution model that allows multiple threads to exist
within a single process. These threads share the process resources but are able to execute independently.
The threaded programming model provides developers with a useful abstraction of this concurrent
execution. The advantage of a multithreaded program is it allows it to operate faster on computer systems
that have multiple CPUs because the threads can execute concurrently.
When building multi-threaded applications, there are several different aspects of the problem that need
to be addressed.
• The various components of the application that are going to be run concurrently in different
threads must be thread-safe. This means that internal data structures in the components must be
protected in such a way that they cannot be corrupted when several different threads are
accessing them concurrently. This is usually done by protecting the data with various
synchronization primitives such as mutexes to lock data structures against concurrent access and
atomic operations.
• The application must be able to create and manage multiple threads. Typically you also want a
way of creating and managing data that is unique for each thread and is not shared.
The SCA Framework handles each of these aspects differently which is described in the following
sections.
Chapter 11: Multi-Threaded Applications 333
Thread Safety

Thread Safety
The following portions of the SCA Framework are thread-safe.
• Core services like ServiceManager, SharedLibraryManager and TextTranslation
• IDL generated support code like the base and factory classes created for services implemented in
C++
• Implementation for framework defined types like SCAAny, SCAResult and SCATypeCode

Utility services like the XML reader and regular expression processor are not thread safe. These services
are not singletons and each user typically gets their own instance.

SCA Framework Synchronization Primitives


The SCA Framework provides a set of synchronization primitives that can be used by services
implemented in C++. For languages other than C++, you should use the threading primitives provided
by those languages. Both Java and the .NET languages have these built into the language. The SCA
provided primitives are implemented on top of the Intel Threading Building Blocks, or TBB, package. It
is not required that these primitives be used in all SCA applications. Typically the use of threading
synchronization primitives from different threading packages in the same application is not a problem.
The following is the header file which defines the threading primitives provide by the SCA Framework.
It provides the following synchronization primitives.
• Spin lock and mutex
• Recursive lock and mutex
• Atomic increment and decrement operations
• Atomic counter template
• Atomic pointer template

SCA/Threading/Threads.h
//
// Threading support used in SCA Kernel
//

#ifndef SCA_FRAMEWORK_SCATHREADS_H_INCLUDED
#define SCA_FRAMEWORK_SCATHREADS_H_INCLUDED

namespace SCA { namespace Threading {

//
// Single access spin mutex/lock
//
class SpinLock;
class SpinMutex
{
friend class SpinLock;
334 SCA Framework User’s Guide
Thread Safety

public:
SpinMutex();
~SpinMutex();
};
class SpinLock
{
public:
SpinLock();
SpinLock(SpinMutex&);
~SpinLock();
void acquire(SpinMutex&);
void release();
private:
SpinLock(const SpinLock&);
SpinLock& operator=(const SpinLock&);
};

//
// Single access recursive mutex/lock
//
class RecursiveLock;
class RecursiveMutex
{
friend class RecursiveLock;
public:
RecursiveMutex();
~RecursiveMutex();
};
class RecursiveLock
{
public:
RecursiveLock();
RecursiveLock(RecursiveMutex&);
~RecursiveLock();
void acquire(RecursiveMutex&);
void release();
private:
RecursiveLock(const RecursiveLock&);
RecursiveLock& operator=(const RecursiveLock&);
};

//
// Thread safe atomic increment and decrement operation
//

inline long
AtomicAdd(volatile long& value, long addend);
inline long
AtomicIncrement(volatile long& value);
inline long
AtomicDecrement(volatile long& value);
inline long
AtomicCompareExchange(volatile long& value,
long exchange,
long compare);
template <typename T>
inline T AtomicLoadAcquire(const volatile T& value);
template <typename T, typename V>
Chapter 11: Multi-Threaded Applications 335
Thread Safety

inline void AtomicStoreRelease(volatile T& value, const V rhs);

//
// Thread safe Atomic counter class
//

class AtomicCounter
{
public:
typedef long value_type;
// Default constructor
inline AtomicCounter() : value(0);
// Conversion operator
inline operator value_type() const;
// Assignment operator
inline value_type operator=(value_type rhs);
// Assignment operator
inline AtomicCounter& operator=(const AtomicCounter& rhs);
// Addition operator
inline value_type operator+=(value_type rhs);
// Subtraction operator
inline value_type operator-=(value_type rhs);
// Prefix increment operator
inline value_type operator++();
// Prefix decrement operator
inline value_type operator--();
// Postfix increment operator
inline value_type operator++(int);
// Postfix decrement operator
inline value_type operator--(int);
// Counter value
value_type value;
private:
// No copy constructor defined
inline AtomicCounter(const AtomicCounter&);
};

//
// Thread safe Atomic pointer class
//

template <typename T>


class AtomicPointer
{
public:
typedef T* value_type;
// Default constructor
inline AtomicPointer() : pointer(0);
// Conversion operator
inline operator value_type() const;
// Assignment operator
inline value_type operator=(value_type rhs);
// Indirect access member operator
inline value_type operator->() const;
336 SCA Framework User’s Guide
Thread Safety

// Pointer value
value_type pointer;
private:
// No copy constructor defined
inline AtomicPointer(const AtomicPointer&);
};

} }

#endif

The following example shows a simple class that uses a recursive lock and mutex to only allow one
thread at a time access to some shared data.

#include <map>
#inclued <SCA/SCA.h>
class SafeMap
{
public:
// Method to set value in shared data
void setMap(string key,int value) {
SCA::Threading::RecursiveLock lock(m_mutex);
m_mapData[key] = value;
}
// Method to get data from shared data
int getMap(string key) {
SCA::Threading::RecursiveLock lock(m_mutex);
return m_mapData[key];
}
private:
// Map data that must be protected
std::map<string,int> m_mapData;
// Mutex for protecting map data
SCA::Threading::RecursiveMutex m_mutex;
};

The following example shows the use of an atomic counter to implement reference counting in a class.

class TestClass
{
public:
. . .
void addReference() {
m_refCount++;
}
void releaseReference() {
if(--m_refCount == 0) delete this;
Chapter 11: Multi-Threaded Applications 337
Thread Safety

}
private:
SCA::Threading::AtomicCounter m_refCount;
};

Kernel Thread Safety Configuration Options


There is a certain level of overhead associated with insuring that various pieces of the SCA Framework
are thread-safe. If you are running in a single threaded environment you may wish to disable this feature.
The SCA Kernel initialization processing provides the Locking configuration variable that allows you to
turn off the thread safety logic. For details on setting SCA configuration variables see the SCA Kernel
chapter of this manual.
338 SCA Framework User’s Guide
Threading Infrastructure

Threading Infrastructure
The SCA Framework leaves the issues relating to the starting and management of individual threads to
the application. The reason for this is that only the application itself has the knowledge required to decide
how threads should be used and the framework does not want to impose any restrictions relative to this.
As a result the SCA Kernel does not provide any infrastructure to create and manage threads. Also
internally the SCA Kernel does not use or have any expectation about the availability of multiple threads.
Another reason the SCA Framework has chosen not to provide any thread management infrastructure is
you typically do not want to use more than one threading management package in a single application.
The use of more than one can cause over subscription of threads because the different packages do not
know about each other which could cause performance issues. Since many of the applications that may
want to use the features of the SCA Framework may already have their own threading support, it could
cause problems if the framework used a different package.
Chapter 11: Multi-Threaded Applications 339
Testing Multi-Threaded Services

Testing Multi-Threaded Services


The SCA Framework provides the scautil utility program which provides a number of useful options.
These are described in detail in the SCA Utility Program chapter of this manual. One of the options
discussed in that chapter is the –test option which allows you to test SCA components. The –mtest option
is a variant of this which allows you to test the thread safety of services in a multi-threaded environment.
The use of the -mtest option is similar to the normal -test option except the service driving the test must
implement the SCAIMultiThreadBatchTest interface instead of the SCAIBatchTest interface. The
difference in this interface is that the output from the test should be returned as a string argument instead
of being directly written to stdout. This way the results of each call can be checked without concern about
the output from the various threads being interspersed.
To run the test, the scautil application gets a single instance of the test service. A call is then made to the
runMultiThreadBatchTest method in the test driver to get a baseline output in a single-threaded
environment. It then creates and starts 25 threads. Each thread makes a single call to the
runMultiThreadBatchTest method. The result of this is 25 different threads will be exercising the test
simultaneously. After all of the threads have finished, the output of each is compared with the baseline
output.
The following is an example of using the –mtest argument.
scautil –mtest SCA.ThreadSafety.TheadTester

SCA::Framework::SCAIMultiThreadBatchTest Interface
Reference
SCAIMultiThreadBatchTest is the interface used by the scautil program to run batch tests on any
service that implements it. In contrast to SCAIBatchTest, these tests are executed concurrently by
multiple threads. To support the running of tests in a multi-threaded environment, all the output from the
test service should be returned in the output arguments instead of being directly sending it to stdout. This
way the results of the test can be easily tested without concern about the output from the various threads
being interspersed with each other.
Inherits SCA::SCAIService.

Member Functions
SCAResult runMultiThreadBatchTest (in SCAStringSequence args, out SCAString
output)

Member Function Documentation

SCAResult runMultiThreadBatchTest ( in SCAStringSequence args,


out SCAString output
)
340 SCA Framework User’s Guide
Testing Multi-Threaded Services

Runs a test on a service.

Parameters:

args SCASequence of command line arguments


output The test must not write to stdout, instead all output should be appended to a string variable
and returned through this parameter.
Chapter 11: Multi-Threaded Applications 341
Sample Multi-Threaded Application

Sample Multi-Threaded Application


In this section a small application is shown that demonstrates how you can use SCA services in a multi-
threaded environment. This application is actually a stripped down version the actual scautil code and
does the same process as the –mtest option discussed in the previous section.
This is the execution flow for the application.
• Loads a single instance of the service that drives the test.
• Casts to the SCAIMultiThreadBatchTest interface.
• Calls the runMultiThreadBatchTest method in a single threaded mode to establish a baseline set
of output.
• Creates and starts 20 threads with each calling the runMultiThreadBatchTest method.
• The output from the test that is run in each thread is compared against the baseline output.

For the threading infrastructure, this sample application uses the Intel TBB library to start and manage
threads. For the details on using the library the Intel TBB documentation should be consulted.

Client.cpp
#include <iostream>
using namespace std;

#include <SCA/SCAKernel.h>
#include "SCA/Framework/SCAIMultiThreadBatchTest.h"
#include <SCA/SCAKernel.h>
#include <SCA/StringUtility.h>
using namespace SCA;
using namespace SCA::Framework;

#include <tbb/task.h>
#include "tbb/task_scheduler_init.h"

//
// Global variable for counting complete thread tasks
//
SCA::Threading::AtomicCounter tasksDone;

//
// Task for driving a thread instance
//
class TestThread : public tbb::task
{
public:
TestThread(SCAIMultiThreadBatchTest spTest,
SCAStringSequence args,
SCAString& result)
: m_spTest(spTest), m_args(args), m_result(result)
{
};
~TestThread()
342 SCA Framework User’s Guide
Sample Multi-Threaded Application

{
};
tbb::task* execute()
{
m_spTest->runMultiThreadBatchTest(m_args,m_result);
++tasksDone;
return NULL;
}
private:
SCAIMultiThreadBatchTest m_spTest;
SCAStringSequence m_args;
SCAString& m_result;
};

int main()
{
try {

cout << "Initializing the SCA Kernel" << endl;


initializeSCAKernel(1);

// Load test service


SCAIMultiThreadBatchTest spTest;
spTest = getSCAService("SDK.ThreadSafety.ThreadTester");

// Get baseline results


SCAString baseline;
SCAStringSequence sqTestArgs;
sqTestArgs.push_back("0");
spTest->runMultiThreadBatchTest(sqTestArgs,baseline);
cout << "*** Baseline results" << endl << baseline << endl;

// Initialize the TBB library


const int numThreads = 20;
tbb::task_scheduler_init init(numThreads);

// Create a list of tasks


tbb::task_list tasks;
SCAString results[numThreads];
for ( SCAInt32 i=0; i<numThreads; i++ ) {
cout << "Allocating task for thread " << i+1 << endl;
sqTestArgs[0] = StringUtility::stringFromInt32(i+1);
TestThread& test = *new(tbb::task::allocate_root())
TestThread(spTest,sqTestArgs,results[i]);
tasks.push_back(test);
}

// Start all the tasks and wait for them to finish


cout << "Starting all threads" << endl << flush;
tbb::task::spawn_root_and_wait(tasks);
cout << flush;

// Make sure all threads finished


if ( tasksDone != numThreads )
Chapter 11: Multi-Threaded Applications 343
Sample Multi-Threaded Application

cout << "***Error: Only " << tasksDone << " of "
<< numThreads << " threads finished" << endl;

// Check each thread result


for ( SCAInt32 i=0; i<numThreads; i++ ) {
if ( results[i] != baseline ) {
cout << "*** Thread " << i+1 << " results are incorrect"
<< endl;
cout << results[i] << endl;
} else {
cout << "*** Thread " << i << " results are correct" << endl;
}
}

// Clean up
spTest = NULLSP;

// Terminate kernel
terminateSCAKernel();

} catch( const SCAException& exc ) {


cout << "Caught SCAException: " << exc.what() << endl;
}

return 0;
}
We also need to implement a thread-safe SCA service to be tested. In this example it is a simple service
that implements the SCAIMultiThreadBatchTest interface. To demonstrate a use of synchronization
primitives, the test service will keep a std::map data structure. A single instance of this map will be
shared by each thread. The runMultiThreadBatchTest method makes a series of modifications and
queries on this data. Since the std::map data structure is not thread safe itself, a locking primitive is used
to gain exclusive use of the structure every time it is accessed.
The following SDL and CDL files are used to define the service. We do not need to create an IDL file
because the only interface the service is implementing is defined in an IDL file that is delivered with the
SCA Framework.

ThreadTester.sdl
#ifndef THREADTESTER_SDL_INCLUDED
#define THREADTESTER_SDL_INCLUDED

#include "SCA/Framework/BatchTest.idl"

module SDK { module ThreadSafety {

service SDK.ThreadSafety.ThreadTester
{
interface SCA::Framework::SCAIMultiThreadBatchTest;
};

}; };
344 SCA Framework User’s Guide
Sample Multi-Threaded Application

#endif

ThreadTester.cdl
#ifndef THREADTESTER_CDL_INCLUDED
#define THREADTESTER_CDL_INCLUDED

#include "ThreadTester.sdl"

component SDK.ThreadSafety.ThreadTester
{
service SDK.ThreadSafety.ThreadTester;
};

#endif

The following is the implementation for the service.

ThreadTester.h
#ifndef SDK_THREADSAFETY_THREADTESTER_H_INCLUDED
#define SDK_THREADSAFETY_THREADTESTER_H_INCLUDED

#include "ThreadTesterBase.h"
#include "SCA/Threading/Threads.h"
using namespace SCA;
using namespace SCA::Threading;
#include <map>
using namespace std;

namespace SDK { namespace ThreadSafety {

class ThreadTester : public ThreadTesterBase


{
public:

// Constructor and Destructor


ThreadTester(SCAIThreadTesterFactoryAccess* factoryAccess);
virtual ~ThreadTester();

// Methods for interface SCA.Framework.SCAIMultiThreadBatchTest


SCAResult runMultiThreadBatchTest(const SCAStringSequence& args,
SCAString& output);

private:

// Private methods for manipulating map data


void setMap(string,int);
int getMap(string);
Chapter 11: Multi-Threaded Applications 345
Sample Multi-Threaded Application

// Map data that must be protected


map<string,int> m_mapData;

// Mutex for protecting map data


RecursiveMutex m_mutex;
};

} }

#endif

ThreadTester.cpp
#include "ThreadTester.h"
#include "SCA/StringUtility.h"

namespace SDK { namespace ThreadSafety {

// Constructor
ThreadTester::ThreadTester(SCAIThreadTesterFactoryAccess*
factoryAccess)
: ThreadTesterBase(factoryAccess)
{
}

// Destructor
ThreadTester::~ThreadTester()
{
}

// Method to test multi-threaded access to shared map data


SCAResult ThreadTester::runMultiThreadBatchTest(
const SCAStringSequence& args,
SCAString& output)
{
int count = 0;
for ( int j=0; j<50; j++ ) {
for ( int i=0; i<20; i++ ) {
string key = "Key" + args[0] + "_" +
StringUtility::stringFromInt32(i+1);
setMap(key,(100*j+i+1));
}
for ( int i=0; i<20; i++ ) {
string key = "Key" + args[0] + "_" +
StringUtility::stringFromInt32(i+1);
count += getMap(key);
}
}
output = StringUtility::stringFromInt32(count);
return SCASuccess;
}

// Method to set value in map


346 SCA Framework User’s Guide
Sample Multi-Threaded Application

void ThreadTester::setMap(string key,int value)


{
RecursiveLock lock(m_mutex);
m_mapData[key] = value;
}

// Method to get value from map


int ThreadTester::getMap(string key)
{
RecursiveLock lock(m_mutex);
return m_mapData[key];
}

} }
The following is the output from the test. For this test 20 threads were used. The results of the test show
that each of the tests generates the same result as the single threaded baseline call. This demonstrates that
shared data structures are being correctly synchronized. As a simple test of this you can comment the
locking calls in the setMap and getMap methods of the ThreadTester class and rerun the tests. You will
probably get incorrect results or even a crash because of corruption in the data structures being modified.
Initializing the SCA Kernel
SCA Kernel 4.8.0 successfully initialized
*** Baseline results
353000
Allocating task for thread 1
Allocating task for thread 2
Allocating task for thread 3
Allocating task for thread 4
Allocating task for thread 5
Allocating task for thread 6
Allocating task for thread 7
Allocating task for thread 8
Allocating task for thread 9
Allocating task for thread 10
Allocating task for thread 11
Allocating task for thread 12
Allocating task for thread 13
Allocating task for thread 14
Allocating task for thread 15
Allocating task for thread 16
Allocating task for thread 17
Allocating task for thread 18
Allocating task for thread 19
Allocating task for thread 20
Starting all threads
*** Thread 0 results are correct
*** Thread 1 results are correct
*** Thread 2 results are correct
*** Thread 3 results are correct
*** Thread 4 results are correct
*** Thread 5 results are correct
*** Thread 6 results are correct
*** Thread 7 results are correct
Chapter 11: Multi-Threaded Applications 347
Sample Multi-Threaded Application

*** Thread 8 results are correct


*** Thread 9 results are correct
*** Thread 10 results are correct
*** Thread 11 results are correct
*** Thread 12 results are correct
*** Thread 13 results are correct
*** Thread 14 results are correct
*** Thread 15 results are correct
*** Thread 16 results are correct
*** Thread 17 results are correct
*** Thread 18 results are correct
*** Thread 19 results are correct
It is important to remember that because of the nondeterministic nature of multi-threaded programs, a
single test like this does not guarantee the correctness of the code. A more reliable testing procedure is
to use a tool that is specifically designed to analyze the execution flow of a multi-threaded application
and detect potential race conditions. This tool can be used in conjunction with the SCA provided test
driver to better determine the correctness of the code.
348 SCA Framework User’s Guide
Sample Multi-Threaded Application
Chapter 12: Versioning
SCA Framework User’s Guide

12 Versioning


Introduction 350
 Component Metadata 351
350 SCA Framework User’s Guide
Introduction

Introduction
The SCA Framework does not currently support a formal versioning policy. Work is currently in progress
to do this which will be available in a future release of the framework.
The SCASCons build system does currently provide a facility that allows you to attach metadata to SCA
components and offers several ways to access this data. This feature can be used to provide version
information that users can use to implement their own versioning scheme if desired. Currently the
component metadata is only supported in components written in C++.
Chapter 12: Versioning 351
Component Metadata

Component Metadata
Each time a C++ SCA component is built; the SCASCons Build System will automatically add build
date and build time information to it. This data can be extracted programmatically from inside the
component’s code or externally directly from the shared library object. You can also add your own
customized metadata to the component. This is done by defining a set of construction variables with
special names of BUILDINFO_xxx. These variables can then be set to your desired value like any other
construction variable. See the SCASCons Build System chapter of this manual for details on how
construction variables are defined and set.
The following shows an example of how build metadata can be added to a source tree. First we must
update the SConstruct file in the root of the source code to define a new construction variable that will
hold each piece of customized metadata. In this example we have defined four pieces of data.

SConstruct
#
# Component metadata
#
Norm('BUILDINFO_MajorVersion','Major version number',None)
Norm('BUILDINFO_MinorVersion','Minor version number',None)
Norm('BUILDINFO_BuildVersion','Build version number',None)
Norm('BUILDINFO_ComponentName','Component name',None)
The values of the construction variables are normally set in the SConopts file in the root of the source
tree. It is also possible to set these variables on the scons command line or in the SConscript files in the
various directories in the tree.

SConopts
#
# Set component metadata
#
BUILDINFO_MajorVersion = 4
BUILDINFO_MinorVersion = 8
BUILDINFO_BuildVersion = 0
BUILDINFO_ComponentName = "MessageDispatcher"
Each time a component is built the build date, build time and the current values of any user defined
metadata construction variables will be stored in its shared library.
The easiest way to extract this metadata is with the scautil utility that is provided with the SCA
Framework. Using the –buildinfo option and the name of the shared library for the component, it will
print the value of each piece of metadata.

Command: cd /Kernel-V4-008/WINNT/bin
Command: scautil -buildinfo SCA/Framework/MessageDispatcher.dll

Build Information for SCA/Framework/MessageDispatcher.dll


Build Date = Sep 3 2009
Build Time = 12:31:14
352 SCA Framework User’s Guide
Component Metadata

MinorVersion = 8
MajorVersion = 4
BuildVersion = 0
ComponentName = MessageDispatcher
You can also access the metadata programmatically from code inside the component. Note that this will
only work from code inside the component because the symbols used are not exported from the
components shared library. The following sample code shows how this can be done for a sample
component.
#include "MessageDispatcherBuildInfo.h"
using namespace SCA::BuildInfo;

SCAString date = SCA_Framework_MessageDispatcher_BuildDate();


SCAString time = SCA_Framework_MessageDispatcher_BuildTime();
SCAString minor = SCA_Framework_MessageDispatcher_MinorVersion();
SCAString major = SCA_Framework_MessageDispatcher_MajorVersion();
SCAString bver = SCA_Framework_MessageDispatcher_BuildVersion();
SCAString name = SCA_Framework_MessageDispatcher_ComponentName();

cout << "MessageDispatcher component build metadata" << endl;


cout << " Build Date " << date << endl;
cout << " Build Time " << time << endl;
cout << " Major version " << major << endl;
cout << " Minor version " << minor << endl;
cout << " Build version " << bver << endl;
cout << " Component Name " << name << endl;
One routine is generated for each piece of build information. These routines are always in the
SCA::BuildInfo namespace and their names are of the form xxx_getyyy where xxx is the fully qualified
component name with the periods replaced with underscore characters and yyy is the name of the
BuildInfo variable. In this example, one of the generated routine names is
SCA_Framework_MessageDispatcher_getComponentName. This is generated from the fully qualified
component name, SCA.Framework.MessageDispatcher, and the BuildInfo variable name,
ComponentName. A header file, MessageDispatcherBuildInfo.h, is also generated which declares these
routines and should to be included in any routine that is using them.
Note that the BuildDate and BuildTime data is always provided by default and does not need to be added
by the user.
If you want to expose this data to users of the component, you can define and implement an interface with
appropriate methods to retrieve it.
Currently all BuildInfo construction definitions are global to the source tree they are defined in. This
means that every component built in the same source tree will have the same build metadata variables.
But, it is possible to define different values to the variables for each component in the SConscript file in
the directory where the component is built. Also, the build metadata is currently managed at a component
level and not a service level.
Chapter 13: Configuring and Using the SCA Kernel
SCA Framework User’s Guide

13 Configuring and Using the SCA


Kernel

 Introduction 354

Initializing and Terminating the Kernel 355

Kernel Configuration Variables 359
 Kernel Configuration File 361

Runtime Access to Configuration Variables 364

Changing the Prefix for Environement Variable Names 365
 Building Applications using the SCA Kernel 366

Running Applications using the SCA Kernel 367

The SCA Services Catalog 370
 Other Configuration Files 372

Service Manager 373

Shared Library Manager 377
354 SCA Framework User’s Guide
Introduction

Introduction
The SCA Framework provides an infrastructure to facilitate the design, coding and building of
applications. All access to these facilities is through a set of common services and interfaces provided by
the framework. The SCA Kernel portion of the framework provides the runtime core functionality
required by the framework. This includes the loading, unloading and lifecycle management of services
and shared libraries and the processing of messages and events.
The SCA Kernel is composed of the following services.
• ServiceManager which is responsible for loading and unloading of services.
• SharedLibraryManager which is responsible for loading and unloading of shared libraries.
• TextTranslation which provides the core message processing functions.
• EventManager which provides facilities for event processing.

The TextTranslation service is described in the Messaging and Internationalization chapter in this manual
and the EventManager is described in the SCA SDK Advanced Features manual.
The rest of these services are discussed in this chapter.
The SCA Kernel is delivered in the SCAKernel shared library. There is also a SCAKernelUtil shared
library that is part of the kernel. The utility library is statically linked against the SCAKernel shared
library and all SCA components.
Chapter 13: Configuring and Using the SCA Kernel 355
Initializing and Terminating the Kernel

Initializing and Terminating the Kernel


The SCA Kernel must be initialized by the application before any services may be loaded. When the
kernel is initialized, a set of configuration data is required. This data can come from environment
variables or from a XML configuration file. Using configuration file is recommended because there is
less chance of conflicting environments between two different applications using the SCA Kernel.
This section shows the API that is used for the initialization and termination of the SCA Kernel in all
supported languages. Code examples in each language are provided later in this chapter.

SCA Kernel Initialization API


The following API is provided to initialize the SCA Kernel

C++
void initializeSCAKernel( SCA::SCAInt32 verbose=0,
const SCA::SCAString& configPath="")

Java
void SCA.SystemProvider.loadSCA()
void SCA.SystemProvider.loadSCA(String configPath)

C#
void SCA.SystemProvider.loadSCA()
void SCA.SystemProvider.loadSCA(string configPath)

Visual Basic
Sub SCA.SystemProvider.loadSCA()
Sub SCA.SystemProvider.loadSCA(String configPath)

Python
import SCA
Each of these calls will throw a SCASystemException exception if errors occur trying to initialize the
kernel.
The configPath argument in each of these calls is the name of the XML configuration file. If it is an empty
string, the SCA Kernel is configured with environment variables. For Python the name of the
configuration file must be provided on the Python command line which is discussed later in this chapter.
The verbose argument controls the amount of the output generated by the initialization routines. If
nonzero, the version of the SCA Kernel that is loaded will be printed.

SCA Kernel Termination API


The following API is provided to terminate the SCA Kernel
356 SCA Framework User’s Guide
Initializing and Terminating the Kernel

C++
SCA::SCAInt32 terminateSCAKernel()
SCA::SCAInt32 terminateSCAKernel(SCAStringSequence& orphans)

Java
void SCA.SystemProvider.unloadSCA()

C#
void SCA.SystemProvider.unloadSCA ()

Visual Basic
Sub SCA.SystemProvider.unloadSCA()

Python
None available
Each of these calls will throw a SCASystemException exception if errors occur trying to terminate the
kernel.
It is not required to explicitly terminate the SCA Kernel in your application. The required termination
processing will automatically occur when the application terminates. You can explicitly terminate the
kernel at an earlier point if you want to release any resources it is using.
It is important to understand that the call to terminate of the SCA Kernel does not force the deleting of
any SCA service objects instances that may still exist. The fact the instances still exist means that there
are active references to them from somewhere else in the application. If the instances were forcibly
deleted with active reference to them this could cause the application to crash at a later time. Instead these
instances are left alone but they are disconnected from the SCA ServiceManager. This way the
ServiceManager and other services in the kernel can still release their resources and terminate. When the
active references to the left over service objects are finally remove, then they will automatically delete
themselves. This process is called orphaning. Some of languages provide a termination call that will
optionally provide a list of any orphaned services.

Examples of Configuring the SCA Kernel


The following simple examples show the use of the API to initialize and terminate the SCA Kernel in
each of the supported languages. The examples do no useful work but are just provided to show the use
of this API.

C++
#include <iostream>
#include <SCA/SCAKernel.h>
using namespace std;
using namespace SCA;

int main()
{
try {
Chapter 13: Configuring and Using the SCA Kernel 357
Initializing and Terminating the Kernel

cout << "Initializing the SCA Kernel" << endl;


initializeSCAKernel(1);
. . .
cout << "Terminating the SCA Kernel" << endl;
terminateSCAKernel();
} catch(SCAException& e) {
cout << "Error: " << e.what() << endl;
}
return 0;
}

Java
import SCA.*;
import SCA.SystemProvider.*;

public class Client{


public static void main (String args[]) {
try{
System.out.println("Intitialize the SCA Kernel");
SCA.SystemProvider.loadSCA();
. . .
System.out.println("Terminate the SCA Kernel");
SCA.SystemProvider.unloadSCA();
} catch (SCASystemException e) {
System.out.println("Error: " + e.what());
}
}
}

C#
using System;
using SCA;

class ClientCS
{
static void Main(string[] args)
{
try {
Console.WriteLine("Initialization the SCA");
SCA.SystemProvider.loadSCA();
. . .
Console.WriteLine("Terminate the SCA");
SCA.SystemProvider.unloadSCA();
} catch (SCAException e) {
Console.WriteLine("Error: " + e.what());
}
}
}
358 SCA Framework User’s Guide
Initializing and Terminating the Kernel

Visual Basic
Imports SCA
Imports System

Module ModuleMain
Sub Main(ByVal args As String())
Try
System.Console.WriteLine("Initialize the SCA Kernel")
SystemProvider.loadSCA()
. . .
System.Console.WriteLine("Termination the SCA Kernel")
SystemProvider.unloadSCA()
Catch e As SCAException
System.Console.WriteLine("Error: " + e.what())
End Try
End Sub
End Module

Python
try:
print "Initializing the SCA Kernel"
import SCA
except SCA.SCAException, e:
print "Error:",e.what()
. . .
Chapter 13: Configuring and Using the SCA Kernel 359
Kernel Configuration Variables

Kernel Configuration Variables


The SCA Kernel uses a set of configuration variables to help it locate required resources, libraries and to
define other options. The configuration variables can be set using environment variables or from a XML
configuration file, but not both. If a configuration file is used, the environment variables have no effect
on that kernel.
The following configuration variables are currently supported. For each configuration variable the
environment variable associated with it is given.

Variable Name Environment Variable Value Type


KernelLibPath N/A path
Resource SCA_RESOURCE_DIR List of paths
Catalog SCA_SERVICE_CATALOG List of paths
XMLParser SCA_XML_PARSER_DIR List of paths
JavaPath SCA_JAVA_COMP_PATH List of paths
JVMConfig SCA_JVM_CONFIG List of options
LibraryPath SCA_LD_LIBRARY_PATH List of paths
Debug SCA_KERNEL_DEBUG List of options
Locking SCA_KERNEL_LOCKING on or off

The SCA_ prefix of each environment variable in the above table can be changed by the application. The
API for this is discussed in a later section of this chapter.
The following table provides the description and default value for each configuration variable.

Variable Name Description and Default Value


KernelLibPath Defines the path where the SCA Kernel shared library was loaded from. This
value is determined internally by the kernel and cannot be set by the
application.
Resource Defines a set of paths for the location of the SCA resource directories. The
default uses the KernelLibPath configuration value and is directory
KernelLibPath/../../res.
Catalog Defines a set of paths for the files or directories where the SCA service catalog
information is obtained. The default value is the file SCAServiceCatalog.xml in
each of the directories specified in the Resource configuration value. At least
one of these must exist.
360 SCA Framework User’s Guide
Kernel Configuration Variables

Variable Name Description and Default Value


XMLParser Defines a set of paths for the directories the XML parser service will search for
XML files. The search order used by the XML parser is to first look in the
directories defined by this value and then to look in the directories defined by
the Resource configuration value. If the requested XML file is not in any of
these directories it looks in the current directory.
JavaPath Defines a set of paths for the root locations for loading Java components. The
default value is the directory RESOURCE/../lib/java where RESOURCE is each
of the directories specified in the Resource configuration value.
JVMConfig Defines a set of configuration options for the Java virtual machine. Multiple
options are separated by commas. See the Java Mapping chapter of this manual
for a discussion of when this value is used and what its default is.
LibraryPath Defines a set of paths for the root locations of C++ and .NET components. The
default value is taken from the appropriate system environment library variable
on the current platform (for example, PATH on WINDOWS and
LD_LIBRARY_PATH on Linux).
Debug Defines a set of debug output options. Multiple options are separated by
commas. The default is to generate no debug output.
Locking Specifies if thread safety is required for SCA Kernel. The default value is on.
Chapter 13: Configuring and Using the SCA Kernel 361
Kernel Configuration File

Kernel Configuration File


An example XML configuration file is shown below.

SCAConfig.xml
<?xml version="1.0"?>
<SCA>
<session os="win32">
<tmp name="%APPSYS%" value="%SCAKERNEL_LIBPATH%/../.."/>
<env name="%APPLOC%” value="MY_APPS_LOCAL"/>
<var name="Resource" value="%APPLOC%/res;%APPSYS%/res"/>
<tmp name="%TYPEJAR%" value="%APPLOC%/lib/java/IDLTypes.jar"/>
<var name="JVMConfig" value="-Djava.class.path=%TYPEJAR%"/>
<var name="Locking" value="off"/>
</session>
<session os="linux32">
<tmp name="%APPSYS%" value="%SCAKERNEL_LIBPATH%/../.."/>
<env name="%APPLOC%” value="MY_APPS_LOCAL"/>
<var name="Resource" value="%APPLOC%/res:%APPSYS%/res"/>
<tmp name="%TYPEJAR%" value="%APPLOC%/lib/java/IDLTypes.jar"/>
<var name="JVMConfig" value="-Djava.class.path=%TYPEJAR%"/>
<var name="Locking" value="off"/>
</session>
</SCA>
The configuration files following the following rules.
• The root tag must be <SCA>
• The options for each platform should be grouped inside a <session> tag. A session must exist
for the platform you are running on.
• If the value type is a list of paths, the paths must be separated by either a colon or semicolon
depending on the current platform.
• If the value type is list of options, the options are separated by commas.
• The syntax <var name=”X” value=”Y”> sets the configuration variable X = Y
• The syntax <tmp name=”T” value=”S”> specifies a temporary variable T = S
• The syntax <env name=”E” value=”N”> specifies a temporary variable whose value is set to
the value of the specified environment variable. E = NVAL where NVAL is the value of
environment variable N. A configuration error will occur if the specified environment variable is
not set.
• While not required, the convention is for all temporary variable names to be enclosed in percent
signs such as %T% so they are easily distinguished from real configuration values. The value of
these variables will be substituted verbatim for all occurrences of the name in the remaining
entries in the current session.
• The temporary variable %SCAKERNEL_LIBPATH% is a reserved name that stands for the
directory where the shared library for the SCA Kernel was loaded from. It is determined by the
SCA Kernel at runtime.
362 SCA Framework User’s Guide
Kernel Configuration File

The following are the supported platform names.

win32
win64
aix
alpha
hpux
irix
hpuxipf
solaris
linux64
linux32
linuxipf

The following is an example of a simple setting of a configuration variable. This example sets the value
of the Locking variable to off.
<var name="Locking" value="off"/>
The configuration process supports the concept of temporary variables. Temporary variables can be used
to create a value that can subsequently be used in the setting of several configuration values. This way
the logic does not need to be repeated in more than one configuration entry. Temporary variables may
also be used to include the settings for system environment variables in the configuration settings. The
convention for temporary variable names is to enclose them in percent signs like %APPLOC%. While
this is not a requirement, it is a good practice because it reduces the chance that the name of the temporary
variable will appear elsewhere in a configuration value which could cause undesired substitutions. Every
occurrence of the temporary variable name in all of the entries in the current session will be substituted
with its value. Note that this substitution occurs in every entry, even those that appear before the
definition of the temporary variable in the configuration file.
To include the setting of a system environment variable in the configuration you must first set a
temporary variable with its value. Only temporary variable names can be set to the value of an
environment variable. You cannot directly set an actual configuration variable. The following is a sample
configuration file entry that sets the temporary variable %APPLOC% to the current value of the
environment variable MY_APPS_LOCAL.
<env name=”%APPLOC%” value="MY_APPS_LOCAL” >
Temporary variable names can also be set in the configuration file. In this example the %TYPEJAR%
temporary variable is set to a string value. In this case the string value used contains an instance of
another temporary variable and its value will be substituted during the process.
<tmp name="%TYPEJAR%" value="%APPLOC%/lib/java/IDLTypes.jar"/>
Chapter 13: Configuring and Using the SCA Kernel 363
Kernel Configuration File

The special reserved temporary variable of %SCAKERNEL_LIBPATH% is set by the SCA Kernel to
the directory where the actual SCA Kernel shared library was loaded from. This value can then be used
to set other values in the configuration file.
<tmp name="%APPSYS%" value="%SCAKERNEL_LIBPATH%/../.."/>

Default Configuration File Location


The SCA Kernel provides a set of default locations for the XML configuration file. If a special string,
auto, is specified as the configuration path, the SCA Kernel will look for the following files and use the
first one it finds. All of these locations are relative to the value of the KernelLibPath configuration value.
KernelLibPath/SCAConfig.xml
KernelLibPath/../bin/SCAConfig.xml
KernelLibPath/../../res/SCAConfig.xml
The following is an example of using this feature.

C++
initializeSCAKernel(1,"auto");
364 SCA Framework User’s Guide
Runtime Access to Configuration Variables

Runtime Access to Configuration Variables


The following API is provided to access the configuration variables at runtime. These functions are
currently only available in C++.
SCAStringSequence SCA::getSCAEnv( const SCAString variable )
SCAString SCA::getSCAEnvValue( const SCAString variable )
The definition of these symbols is in the SCA/KernelConfiguration.h include file delivered with the SCA
Framework.
The first routine returns a sequence of strings containing paths or options that were set for the requested
variable.
The second routine returns a single string value of the configuration variable. The function should only
be used for single value options, such as Locking. For multi-value options it will only return the first
value.
Chapter 13: Configuring and Using the SCA Kernel 365
Changing the Prefix for Environement Variable Names

Changing the Prefix for Environement Variable Names


When using environment variables to configure the SCA Kernel, the default name of each environment
variable starts with SCA_. There may be cases where this may cause conflicts with other requirements
of your application. The following API is provided which allows you to change this prefix.
SCA_EXPORT SCAVoid setSCAEnvPrefix( const SCAString prefix );
SCA_EXPORT SCAString getSCAEnvPrefix( );
The following example call will change the configuration process so each of the configuration values will
use an environment variable with a name like MYAPP_RESOURCE_DIR instead of
SCA_RESOURCE_DIR.
setSCAEnvPrefix("MYAPP");
Current these functions are only available in C+.
366 SCA Framework User’s Guide
Building Applications using the SCA Kernel

Building Applications using the SCA Kernel


The only special requirement when building an application using the SCA Framework is the executable
or shared library that does the actual initialization of the SCA Kernel needs to be linked with the
SCAKernel and SCAKernelUtil shared libraries. These libraries are provided with the SCA Framework.
The following SCASCons SConscript file can be used to build the executable for a simple application
that uses the SCA Framework.
Import("env_base")
env = env_base.Copy()

#============== Perform local customization here =================

env.Append(LIBS=["SCAKernel","SCAKernelUtil"])
env.BuildProgram("Client")

#==================================================================

retval = env.ProcessDir(env_base)
Return('retval')
For more information on the use of the SConscript files, see the SCASCons Build System chapter in this
manual.
Chapter 13: Configuring and Using the SCA Kernel 367
Running Applications using the SCA Kernel

Running Applications using the SCA Kernel


The following example CSH scripts show what is required to run an application using the SCA
Framework written in each of the supported languages. In this case a very simple configuration is used
and the required values are set using environment variables. The Resource configuration value is the only
value that is set.

C++
#! /bin/csh
#
set ILOCAL = D:/Builds/Initialization/Apps
set DLOCAL = $ILOCAL/WINNT
#
set ISYSTEM = D:/Kernel-WINNT/Apps-Opt
set DSYSTEM = $ISYSTEM/WINNT
#
set path = ( $DLOCAL/bin $DLOCAL/lib $DSYSTEM/bin $DSYSTEM/lib $path
)
#
setenv SCA_RESOURCE_DIR "$ISYSTEM/res"
#
$DLOCAL/bin/ClientCPP.exe

Java
#! /bin/csh
#
set ILOCAL = D:/Builds/Initialization/Apps
set DLOCAL = $ILOCAL/WINNT
#
set ISYSTEM = D:/Kernel-WINNT/Apps-Opt
set DSYSTEM = $ISYSTEM/WINNT
#
set path = ( $DLOCAL/bin $DLOCAL/lib $DSYSTEM/bin $DSYSTEM/lib $path
)
#
setenv JRE /ThirdParty/jdk/1.6.0/WINNT
set JAVALIB = $ILOCAL/lib/java
set path = ( $path $JRE/jre/bin/client )
#
setenv SCA_RESOURCE_DIR "$ISYSTEM/res"
#
$JRE/bin/java -Xms256m -Xmx512m –cp \
"$JAVALIB;$JAVALIB\IDLTypes.jar;$JAVALIB\ClientJava.jar" Client

C# or Visual Basic
#! /bin/csh
#
set ILOCAL = D:/Builds/Initialization/Apps
set DLOCAL = $ILOCAL/WINNT
#
set ISYSTEM = D:/Kernel-WINNT/Apps-Opt
368 SCA Framework User’s Guide
Running Applications using the SCA Kernel

set DSYSTEM = $ISYSTEM/WINNT


#
set path = ( $DLOCAL/bin $DLOCAL/lib $DSYSTEM/bin $DSYSTEM/lib $path
)
#
setenv SCA_RESOURCE_DIR "$ISYSTEM/res"
#
$DLOCAL/bin/ClientCS.exe

Python
#! /bin/csh
#
set ILOCAL = D:/Builds/Initialization/Apps
set DLOCAL = $ILOCAL/WINNT
#
set ISYSTEM = D:/Kernel-WINNT/Apps-Opt
set DSYSTEM = $ISYSTEM/WINNT
#
setenv PYTHONPATH "$ISYSTEM/lib/python;$DSYSTEM/bin"
setenv PYTHONHOME /ThirdParty/Python/2.5.0-1/WINNT
#
set path = ( $DLOCAL/bin $DLOCAL/lib $DSYSTEM/bin $DSYSTEM/lib $path
)
set path = ( $PYTHONHOME/libs $path )
#
setenv SCA_RESOURCE_DIR "$ISYSTEM/res"
#
$PYTHONHOME/python ClientPy/Client.py
With the exception of Python, the only change to these scripts to use a XML configuration files would
be to remove the setting of the SCA_RESOURCE_DIR environment variable. The initialization for the
SCA Kernel in the source code for the application would also have to be changed to include the name of
the XML configuration file. For this simple example, the following XML configuration file is equivalent
to the previous environment variable examples.

SCAConfig.xml
<?xml version="1.0"?>
<SCA>
<session os="win32">
<var name="Resource" value="%SCAKERNEL_LIBPATH%/../../res"/>
</session>
<session os="win64">
<var name="Resource" value="%SCAKERNEL_LIBPATH%/../../res"/>
</session>
<session os="linux32">
<var name="Resource" value="%SCAKERNEL_LIBPATH%/../../res"/>
</session>
<session os="linux64">
<var name="Resource" value="%SCAKERNEL_LIBPATH%/../../res"/>
</session>
</SCA>
An example of a modified initialization call follows.
Chapter 13: Configuring and Using the SCA Kernel 369
Running Applications using the SCA Kernel

initializeSCAKernel(1,"SCAConfig.xml");
The API to initialize the SCA Kernel in Python does not provide the ability to specify the name of a XML
configuration file. In Python, you must include this information on the command line that runs the Python
interpreter. In the above sample script for Python we would use the following line to accomplish this.
$PYTHONHOME /python ClientPy/Client.py -SCAConfig="SCAConfig.xml"
370 SCA Framework User’s Guide
The SCA Services Catalog

The SCA Services Catalog


The SCA service catalogs are XML files used by the SCA Kernel to determine which services are
available and in which component they are contained. These catalog files are created by the SCASCons
build system when you build your components and normally they should not be manually changed.

SCASCons Build options for catalog processing


The SCASCons build system can create either a single XML service catalog with entries for all the
components it builds in the current source tree or it can create a separate XML file for each component.
The use of separate XML files can make the delivery of SCA components to other users easier if more
than one component is built in the same source tree. With this option it is easier to package up and install
the files for a component because all of its information is in files unique to the component. If the single
XML file option is used, then the installation procedure has to update an existing catalog file or create a
new one for each component installed which complicates the process. If you are not delivering the
components separately you may wish to use a single XML catalog file because it is slightly more
efficient.
The following examples shows how the construction variables for the SCASCons build system are used
to control these options.

Single Catalog File:


SCACATALOGDIR = ‘$APPS_LOCAL/res’
SCACATALOG = ‘SCAServiceCatalog.xml’

Separate catalog file for each SCA component:


SCACATALOGDIR = ‘$APPS_LOCAL/res/catalog’
SCACATALOG = ‘split_by_component’
For more information on the setting of build system construction variables, see the SCASCons Build
System chapter in this manual.

Catalog Configuration Options


The Catalog configuration variable is used to specify the locations of the SCA service catalogs. It
contains a list of path entries where each one can point to either a single catalog file or to a directory. If
the entry is a directory then every XML file in that directory will be read and each one must be a valid
catalog file.
If the Catalog configuration value is not defined the kernel will look for the file SCAServiceCatalog.xml
in each directory included in the Resource configuration value.

Service Catalog Precedence Rule for Duplicate Entries


If the same service is defined in more than one catalog file, the first one found will be used. Any
subsequent entries will be ignored.
Chapter 13: Configuring and Using the SCA Kernel 371
The SCA Services Catalog

Sample Service Catalog File


The following is a sample SCA service catalog file.

<?xml version="1.0" ?>


<SCA>
<component language="C++" library="SCAKernel" name="SCAKernel">
<service name="SCA.Framework.EventManager" />
<service name="SCA.Framework.ServiceManager" />
<service name="SCA.Framework.SharedLibraryManager" />
<service name="SCA.Framework.ResourceManager" />
<service name="SCA.Framework.TextTranslation" />
</component>
<component language="C++"
library="SCA/Framework/MessageDispatcher"
name="SCA.Framework.MessageDispatcher">
<service name="SCA.Framework.MessageDispatcher" />
</component>
</SCA>
372 SCA Framework User’s Guide
Other Configuration Files

Other Configuration Files


The SCA Kernel also requires several other types of configuration files.

IDL Type Definitions Files


To support the various dynamic features of the SCA Framework like scripting and the SCAAny data
type, the SCA Kernel needs to know information about the various interfaces and types that are defined
in IDL files. For details on these features see the IDL Language chapter in this manual and SCA SDK
Advanced Features manual. The SCA Kernel gets this type information from a set of XML files
generated by the IDL compiler. These files are stored in the directory RESOURCE/types where
RESOURCE is each of the directories specified in the Resource configuration value.

Message Files
Application defined messages are stored in XML files that are installed as part of the build process. These
XML files are stored in the directories specified by the Resource configuration value or in a subdirectory
of them. See the Messages and Internationalization chapter of this manual for complete details on these
XML files and how they are located.

Language Support Files


The SCA Kernel requires several XML configuration files which define the supported languages and
country codes available to internationalize messages. These files must be stored in one of the directories
specified by the Resource configuration value.
1. LocaleLanguagesMap.xml
2. LocaleCountriesMap.xml
The language support files are discussed in detail in the Messages and Internationalization chapter of this
manual.
Chapter 13: Configuring and Using the SCA Kernel 373
Service Manager

Service Manager
The ServiceManager service provides important interfaces for managing the available services. These
interfaces expose methods to load services and to query kernel information and available services. This
section describes these interfaces and provides examples to illustrate their usage.

SCA::Framework::SCAIServiceProvider Interface Reference


Interface used to load SCA services.

Inherits SCA::SCAIService.

Member Functions
SCAResult getService (in SCAString sName, in SCAString sAttr, out
SCAIService spService)

Member Function Documentation

SCAResult getService ( in SCAString sName,


in SCAString sAttr,
out SCAIService spService
)

Loads a SCA service.

Parameters:

[in] sName Fully qualified name of the service to load


[in] sAttr Additional keyword=value attributes to specify additional information about
the service to be loaded
[out] spService SCAIService interface to the loaded service

Return values:

SCAResult Status of the request

The SCAIServiceProvider interface implemented in the ServiceManager is the only way to load a SCA
service. The various language bridges and mappings provide different APIs to load services. For example
the C++ language mappings provides the routine m_serviceAccess.getService()for loading services when
374 SCA Framework User’s Guide
Service Manager

inside other SCA services or the routine getSCAService when external to a SCA service. But all of these
APIs eventual use the SCAIServiceProvider interface to do the actual loading of the service.

SCA::Framework::SCAIKernelInfo Interface
SCAIKernelInfo is used to query the Kernel version and other information

Member Functions
SCAResult getMajorVersion (out SCAString sMajorVersion)
SCAResult getMinorVersion (out SCAString sMinorVersion)
SCAResult getBuildVersion (out SCAString sBuildVersion)

Member Function Documentation


SCAResult getBuildVersion ( out SCAString sBuildVersion )
Returns the build version.

Parameters:

sBuildVersion Build version

Returns:
Returns SCASuccess on success, else returns an error.

SCAResult getMajorVersion ( out SCAString sMajorVersion )


Returns the major version .

Parameters:

sMajorVersion Major version

Returns:
Returns SCASuccess on success, else returns an error.

SCAResult getMinorVersion ( out SCAString sMinorVersion )


Returns the minor version.

Parameters:

sMinorVersion Minor version


Chapter 13: Configuring and Using the SCA Kernel 375
Service Manager

Returns:
Returns SCASuccess on success, else returns an error.

The following example demonstrates how to get the Kernel version and build date using the
SCAIKernelInfo interface.

#include <SCA/Framework/SCAIKernelInfo.h>
#include <SCA/StringUtility.h>

namespace std;
using namespace SCA;
using namespace SCA::Framework;

// Get Kernel Version and build date


SCAIKernelInfo spInfo;
spInfo = getSCAService("SCA.Framework.ServiceManager");
SCAString sMajor,sMinor,sBuild;
spInfo->getMajorVersion(sMajor);
spInfo->getMinorVersion(sMinor);
spInfo->getBuildVersion(sBuild);
cout << "SCA Kernel version is " << sMajor << "."
<< sMinor << "." << sBuild << endl;
SCAString sDate,sTime;
spInfo->getBuildDate(sDate);
spInfo->getBuildTime(sTime);
cout << "SCA Kernel was built on " << sDate << " at "
<< sTime << endl;
spInfo = NULLSP;

SCA::Framework::SCAIServiceCatalog Interface
SCAIServiceCatalog is used to manage the service catalog

Member Functions
SCAResult getAvailableServices (out SCAStringSequence sqServices)
SCAResult getServiceInfo (in SCAString sName, out ServiceInfo info)

Member Function Documentation


SCAResult getAvailableServices ( out SCAStringSequence sqServices )
Gets the list of available services.

Parameters:

sqServices Available services


376 SCA Framework User’s Guide
Service Manager

Returns:
Returns SCASuccess on success, else returns an error.

SCAResult getServiceInfo ( in SCAString sName, out ServiceInfo info )

Gets the service information.

Parameters:

sName Service name


info Service information

Returns:

Returns SCASuccess on success, else returns an error.

This example demonstrates how to get the list of services and query information on them using the
SCAIServiceCatalog interface.
#include <iostream>
#include <SCA/Framework/SCAIKernelInfo.h>
#include <SCA/Framework/SCAIServiceCatalog.h>
#include <SCA/StringUtility.h>

using namespace std;


using namespace SCA;
using namespace SCA::Framework;

// Query the available services and get service information


SCAIServiceCatalog spCatalog;
spCatalog = getSCAService("SCA.Framework.ServiceManager");
SCAStringSequence services;
spCatalog->getAvailableServices(services);
for ( size_t i=0; i<services.size(); i++ ) {
SCAString name = services.r_at(i);
ServiceInfo info;
SCAResult rstat = spCatalog->getServiceInfo(name,info);
SCAStringSequence parts;
parts = StringUtility::split(info.genericName,"/");
cout << setiosflags(ios::left)
<< setw(50) << name
<< setw(25) << parts.r_at(parts.size()-1)
<< setw(8) << info.language
<< setw(5) << info.loadCount
<< endl;
};
spCatalog = NULLSP;
Chapter 13: Configuring and Using the SCA Kernel 377
Shared Library Manager

Shared Library Manager


The SharedLibraryManager service provides an interface for the loading and unloading of shared
libraries.

SCA::Framework::SCAISharedLibraryManager Interface
Reference
The SCAISharedLibraryManager interface provides the methods for processing shared libraries.

Inherits SCA::SCAIService.

Member Functions
SCAResult loadLibrary (in SCAString sName, out SCAInt32 iHandle)
SCAResult releaseLibrary (in SCAInt32 iHandle)
SCAResult findFunction (in SCAInt32 iHandle, in SCAString sFuncName, out
SCAVoidPtr pSym)
SCAResult getLibraryInfo (in SCAInt32 iHandle, out SCAString
sGenericName, out SCAString sRealName)
SCAVoid setReleaseQueueSize (in SCA::SCAUInt32 size)

Member Function Documentation

SCAResult findFunction ( in SCAInt32 iHandle,


in SCAString sFuncName,
out SCAVoidPtr pSym
)

findFunction returns the pointer to a requested function if it exists.


Parameters:

iHandle handle to the library (obtained via loadLibrary)


sName name of the function whose pointer is requested
pSym pointer to symbol

Returns:
378 SCA Framework User’s Guide
Shared Library Manager

status of request 0 if the symbol was found

SCAResult getLibraryInfo ( in SCAInt32 iHandle,


out SCAString sGenericName,
out SCAString sRealName
)

getLibraryInfo returns the generic library name and the real shared library object name
Parameters:

iHandle handle to the library (obtained via loadLibrary)


sGenericName generic library name
sRealName real shared object name

Returns:
status of request 0 if the name was returned

SCAResult loadLibrary ( in SCAString sName,


out SCAInt32 iHandle
)

loadLibrary opens the shared library


Parameters:

sName name of the library


SCAIHandle handle to the opened library

Returns:

status of request 0 if the library was loaded correctly

SCAResult releaseLibrary ( in SCAInt32 iHandle )


Chapter 13: Configuring and Using the SCA Kernel 379
Shared Library Manager

releaseLibrary decrements the reference count on the shared library. The library may be unloaded if there
are no other references to it
Parameters:

iHandle handle to the library (obtained via load)

Returns:

status of request

SCAVoid setReleaseQueueSize ( in SCA::SCAUInt32 size )

setReleaseQueueSize change the release buffer size to the given size


Parameters:

size real shared object name

Library loading logic


The procedure the SharedLibraryManager uses to locate the shared library to load depends on whether
the name passed to the loadLibrary method is an absolute or relative name.
If the input name is an absolute path of the form of /.../libname or C:/.../libname then the library is loaded
directly from the path given. The libname portion of the name is also modified to include the appropriate
prefix and suffix required for shared libraries on the current platform. This is the only attempt made for
an absolute path.
If the input name is a relative name meaning it contains an embedded path separator character but not a
leading one, like dir/libname, or if only the library name is supplied, like libname, then the following
logic is used. The libname portion of the name is first modified to include the appropriate prefix and
suffix required for shared libraries on the current platform. The LibraryPath configuration variable is
380 SCA Framework User’s Guide
Shared Library Manager

then used to find the list of paths to search for the library. If LibraryPath is not set then the following
platform specific environment variables are used.

Platform Environment Variable


Windows LIB

AIX LIBPATH

IRIX LD_LIBRARY64_PATH

LD_LIBRARY_PATH
Other Linux/Unix LD_LIBRARY_PATH

The relative or library only name is then appended to each search path. If the search path entry is a relative
directory name, it is made absolute by adding the current working directory to the name.
Internally the SharedLibraryManager always uses absolute paths when loading libraries. This is done for
several reasons.
• This keeps the number of directories that must be tried to load the shared library to a minimum.
Since most shared libraries for SCA components are in subdirectories and not the root directory,
you would have to include each subdirectory in the system search path list. But since the
SharedLibraryManager assembles the absolute directories itself, you can give it a name relative
to the root directory and it will only need to try to load from the single subdirectory required.
• The operating system rules for how the system search path for loading shared libraries is used is
different on the various platforms supported by SCA. By bypassing the Operating System's
processing of the system search path it is possible to provide a consistent loading behavior across
all platforms.

Library Release Queue


The life cycle control logic provided by the ServiceManager will unload the shared libraries for SCA
components when all references to the services in the component have been released. To avoid
unnecessary load and unload requests should one of the services in the component be immediately loaded
again, the SharedLibraryManager does not immediately unload shared libraries when requested. Instead
it keeps a queue of unload requests and will only unload the actual library when the queue is full. At this
point the shared library for the oldest queue entry is unloaded. The default size of the queue is 10 entries
but this can be changed with the setReleaseQueueSize interface member. Setting the size of the release
queue to zero will disable this feature.
Chapter 13: Configuring and Using the SCA Kernel 381
Shared Library Manager

SharedLibraryManager example
The following example shows using the SharedLibraryManager to load and call a function in a shared
library. In this example we will be calling the SCA_CompInfo entry in the SCA Kernel shared library to
extract all the build information that is stored in the library.

#include <iostream>
#include <SCA/SCAKernel.h>
#include <SCA/KernelConfiguration.h>
#include <SCA/Framework/SCAISharedLibraryManager.h>
#include <SCA/StringUtility.h>

using namespace std;


using namespace SCA;
using namespace SCA::Framework;

// Load the SharedLibraryManager Service


SCAISharedLibraryManager spLib;
spLib = getSCAService("SCA.Framework.SharedLibraryManager");

// Load the SCA Kernel shared library


SCAString kernelLibPath = getSCAEnvValue("KernelLibPath");
SCAString kernelLib = kernelLibPath + "/SCAKernel";
SCAInt32 iHandle;
SCAResult rStatus = spLib->loadLibrary(kernelLib,iHandle);
if( rStatus ) {
cout << "Error: Could not load library " << kernelLib << endl;
return 1;
}

// Get the address of the "SCA_CompInfo" symbol


SCAVoid* pSym;
rStatus = spLib->findFunction(iHandle,"SCA_Comp_Info",&pSym);
if( !rStatus ) {
SCAString sValue;
SCAString (*pfunc)(SCAString) = (SCAString(*)(SCAString))pSym;
cout << "Build Information for " << kernelLib << endl << endl;
// Get the build date
sValue = pfunc("BuildDate");
if ( sValue.length() > 0 )
cout << " Build Date = " << sValue << endl;
// Get the build time
sValue = pfunc("BuildTime");
if ( sValue.length() > 0 )
cout << " Build Time = " << sValue << endl;
// Get the other build information entries
sValue = pfunc("?");
SCAStringSequence varNames = StringUtility::split(sValue,",");
for ( size_t iLoc=0; iLoc<varNames.size(); iLoc++ ) {
sValue = pfunc(varNames[iLoc]);
if ( sValue.length() > 0 )
cout << " " << left << setw(17)
382 SCA Framework User’s Guide
Shared Library Manager

<< varNames.r_at(iLoc) << " = "


<< sValue << endl;
}
} else {
cout << "No build information was available library"
<< kernelLib << endl;
}
spLib->releaseLibrary(iHandle);
spLib = NULLSP;
Chapter 14: Utility Services
SCA Framework User’s Guide

14 Utility Services


Introduction 384
 XML Parser 385
384 SCA Framework User’s Guide
Introduction

Introduction
This chapter discusses the following utility services that are provided as part of the SCA Framework.
• XML Parser
• Regular Expression Facility
• System Utilities
• Stream I/O Utilities
Chapter 14: Utility Services 385
XML Parser

XML Parser
The XML Parser is an efficient and high performance SCA compliant XML reader/writer utility
component. It is provides a set of services and interfaces to facilitate the parsing, generating,
manipulating, and validating of XML documents. It consolidates various features of different XML
Parsers by using a standard set of interfaces in a uniform manner across different products within the
Simulation enterprise umbrella.
XML Parser is implemented as a wrapper around libxml2, which is a third party XML library.
The XML Parser supports the following parsing mechanisms.
1. Tree based parsing - Document Object Model (DOM)
This mechanism provides access to the information stored in the XML document as ahierarchical object
model. The DOM parser creates a tree of nodes based on the structure and information in the XML
document. Once the document is loaded, the user can manipulate the data by traversing the tree.
2. Event driven parsing - Simple API for XML (SAX)
This mechanism provides access to the information stored in the XML document through a set of
predefined events. The parser fires a sequence of these events depending on the tags encountered while
reading an XML document. The user needs to provide event handlers to intercept and process the events.
3. XSLT style sheet processor
XSLT is a declarative XML language that allows you to translate XML files into arbitrary text output
using a style sheet. The XSLT processor provides the functions to perform the required transformation.
The XML parser is composed of the following services.
• SCA.MXP.MXPDOMParser –The DOM parser
• SCA.MXP.MXPSAXParser –The SAX parser
• SCA.MXP.MXPXSLT – The XSLT style sheet processor
In the following sections we will discuss the interfaces supported by the XML Parser and provide some
usage examples.

DOM Parser Interfaces


386 SCA Framework User’s Guide
XML Parser
Chapter 15: SCA Utility Program and Testing Components
SCA Framework User’s Guide

15 SCA Utility Program and Testing


Components

 Introduction 388

The SCA Utility Program 389

Testing of SCA components 393
388 SCA Framework User’s Guide
Introduction

Introduction
This chapter describes the functionality available in the SCA Framework for testing of services and
components. In particular it discusses the SCA utility program scautil and the TestRun environment
routine of the SCA SCons build system. The combination of these two can be used to test loading of
components, query information and run tests. The tests could be run either manually or as part of the build
process.
Chapter 15: SCA Utility Program and Testing Components 389
The SCA Utility Program

The SCA Utility Program


The SCA utility program scautil is used to perform the following tasks.
• Test Kernel initialization
• Run a test service
• Run a script
• Test loading of a shared library
• Query the Kernel information
• Query the shared library build information

There is no script provided with the SCA Framework to run the scautil program because it would be
difficult to provide one that was general enough to be helpful. But, the scautil is just a normal SCA
application and it requires the same configuration as any SCA application. The details of this are
discussed in SCA Kernel chapter of this manual. As an example, the following simple C shell script could
be used to run the delivered version of the Framework.
#! /bin/csh
#
set ISYSTEM = D:/SCAKernel-V4-007
set DSYSTEM = $ISYSTEM/WINNT
#
set path = ( $DSYSTEM/lib $DSYSTEM/bin $path )
#
setenv SCA_SERVICE_CATALOG "$ISYSTEM/res/SCAServiceCatalog.xml"
#
setenv SCA_RESOURCE_DIR "$ISYSTEM/res"
#
$DSYSTEM/bin/scautil.exe $*
Typically, you would need to modify this to also point to the APPS directory for the components you have
built.
The syntax for running scautil is a follows.

Syntax:
scautil [arg1] [arg2] [arg3] . . .
The rest of this section describes the usage of the scautil program.

Print the help message


The –h argument can be used to generate a listing of all the available options that the scautil program
supports.
scautil -h
390 SCA Framework User’s Guide
The SCA Utility Program

Testing Kernel Initialization


If no arguments are provided to the command, the program initializes the SCA Kernel and then exits.
This can be used to test for the proper configuration of the Kernel.

Usage:
scautil

Output:
SCA Kernel 4.7.0 successfully initialized
SCAUtil: No arguments were specified
SCAUtil: Kernel loaded successfully and is now cleaning up

Running a Batch Test


One of the most commonly used options of the scautil utility is to use it to run component tests. To do
this you must code a test service which implements the SCAIBatchTest interface. The requested service
is loaded and the runBatchTest method is called. Any additionally arguments supplied on the command
line are passed to the service in a sequence of strings.

Usage:
scautil -test servicename [optional arguments...]

Examples:
scautil -test Test.Kernel.Test BaseImpl SmartPointer
The complete details of this feature are described later in this chapter.

Run a Script
The –script option can be used to run a script using the runScript method of the ScriptBroker service.

Usage:
scautil -script file

Example:
scautil -script test.py

Test Loading of a Shared Library


The –testload option can be used to test if the specified library exists and can be loaded correctly. If the
loading of the library fails, a detailed error message is provided which can be helpful to determine why
the load failed.
Chapter 15: SCA Utility Program and Testing Components 391
The SCA Utility Program

Usage:
scautil -testload [-noinfo] library_name
This option also checks if any of the known symbols that a SCA component might export from a library
exist and outputs this information.
If the optional argument –noinfo is specified as the second argument, the library is loaded but no
information will printed except for the appropriate errors if the load is unsuccessful.

Example:
scautil -testload SCAKernel.dll

Output:
SCA Kernel 4.7.0 successfully initialized

Symbol SCA_Comp_Info was found at address 008869D0

Library generic name is SCAKernel


Library full name is /SCA/SCAKernel-V4-007/WINNT/bin/SCAKernel.dll

Query SCA Kernel Information


The –kernelinfo command can be used to show the information about the SCA Kernel that is being used.

Usage:
scautil -kernelinfo

Output:
SCA Kernel 4.7.0 successfully initialized

Kernel Build Information

Build Date = Jul 28 2009


Build Time = 18:16:09
Major Version = 4
Minor Version = 7
Source Label = V4-007

Query Shared Library Build Information


To print the build and product information for the specified SCA component, you can use the -buildinfo
option.

Usage:
scautil -buildinfo library_name
392 SCA Framework User’s Guide
The SCA Utility Program

Example:
scautil -buildinfo C:/SCAKernel-V4-007/WINNT/bin/SCAKernel.dll

Output:
Build Information for SCAKernel.dll

Build Date = Jul 28 2009


Build Time = 18:16:09
MajorVersion = 4
MinorVersion = 7
BuildVersion = 0
BuildLabel = V4-007
ProductName = SCA Kernel
ProductLabel = SCA
Every SCA component will have information with the date and time of the build. See the SCA Build
System Guide for the details on how you can add other build information to a component.
Chapter 15: SCA Utility Program and Testing Components 393
Testing of SCA components

Testing of SCA components


The scautil command provides the –test option which can be used for testing components. To use this
option, you normally write a separate service that is used to drive the test. This test service must
implement the SCAIBatchTest interface.

SCA::Framework::SCAIBatchTest Interface Reference


SCAIBatchTest is interface used by the scautil program to run batch tests on any service that
implements it.
Inherits SCA::SCAIService.

Member Functions
SCAResult runBatchTest (in SCAStringSequence args)

Member Function Documentation

SCAResult runBatchTest ( in SCAStringSequence args )


Runs test on a service.

Parameters:

args SCASequence of command line arguments

Running Tests Manual


Tests can be run manually using the scautil program.
scautil -test servicename [optional arguments...]
For example the following command will test the base class implementation and smart pointers.
scautil -test Test.Kernel.Test BaseImpl SmartPointer
When manually running tests, the output you get is what is directly produced by the service you use to
run the test. In order to check if the test was successful, you either have to have self checking built into
the testing service or you need to compare the output against a baseline that you know is correct. Because
of this, the preferable way is to run the tests using the SCA build system and the TestRun environment
command which provides much more flexibility and power.
394 SCA Framework User’s Guide
Testing of SCA components

Running Tests with the Build System


The TestRun environment command is used to run tests as part of the build process. This feature is
primarily designed for cases where the tests can be run in a batch mode and is generally not appropriate
for testing interactive applications.
The basic idea is to run the test whenever the test component is built. The output from the run can then
be compared to the baseline data contained in a text file to find any regressions.

Syntax:
Def TestRun ( program=None,
component=None,
baseline=None,
command=None,
args=None,
aliases=None,
fixup=None,
nocatalog=None,
loadpaths=None,
setup=None,
cleanup=None,
title=None,
dependfiles=None,
dependaliases=None,
preprocess=None,
addtodefaults=None)
The following are the arguments that are available for the TestRun routine.

Argument Description
program Programs(s) that this test is dependent on. They must be built in the current build
run.
component Components(s) that this test is dependent on. They must be built in the current
build run. Non C++ components can be specified by prefacing them with the
language and a virtical slash. (java|X.Y.Z)
baseline The baseline results file for the test. If this argument is omitted, then no check is
performed on the test output.
command The actual command that will run the test. If this argument is omitted, then the
first entry in the program argument is used. This argument may be a python
function or an executable program in the Apps Local or Apps System bin
directory.
args Any additional arguments to be passed to the command running the tests.
aliases Aliases that can be used as targets on the scons command to request the running
of this test.
Chapter 15: SCA Utility Program and Testing Components 395
Testing of SCA components

Argument Description
fixup Python script that is used to modify each line of output from the test run before
it is compared to the baseline output.
nocatalog Normally the test is also made dependent on the Service catalog to make sure
any catalog updates are done before the test is run. If this argument is set true,
then this dependency is not established.
loadpaths Any extra paths for loading libraries to be used when running the test. These
paths may be absolute or relative to the bin or lib subdirectory, depending on the
current platform, in the APPS_LOCAL_MACH and
APPS_SYSTEM_MACH directories.
setup Python script that will be run before the actual test is run. It can be used to do
any special setup processing that the run requires.
cleanup Python script that will be run after the actual test is run. It can be used to do any
required clean up processing after the test.
title Title which is printed out for test
dependfiles File or list of files that the test is dependent on
dependaliases Alias or list of aliases that the test is dependent on
preprocess The baseline file is run through a macro preprocessor before it is used. The value
of this option is a Python dictionary that contains the variables and their values
which are referenced in the preprocessor commands. For example:
env = {}
env['VAR1'] = True
env['VAR2'] = False
env.TestRun(...,preprocess=env)
addtodefaults If true, the targets of the test are added to the list of default targets. This way the
test will run if no command line targets are provided. The normal behavior is the
test will only run if it is requested by a target on the command line.

Setting up Test Aliases


Normally the env.TestRun command in your SConscript file should define an alias for the test. This
makes it much easier to request which test you want to run on the scons command. The following shows
an example of how this is done.
env.TestRun(program="KernelUse",
baseline="KernelUse.txt",
aliases="KernelUseTest")

env.TestRun(program="MemManager",
baseline="MemManager.txt",
396 SCA Framework User’s Guide
Testing of SCA components

aliases="MemManagerTest")
To select the test you want to run, you use the alias name on the build command.
scons KernelUseTest
scons KernelUseTest MemManagerTest

Specifying when Tests run by Default


By default, the targets from the TestRun command are not added to the list of targets that SCons will
build if you do not request any on the command line. This means if you use a build command similar to
the following, the test will not be run.
scons
You can change this behavior by adding the addtodefaults argument on the TestRun command. Now the
tests will be run when no targets are given on the command line.
env.TestRun(program="MemManager",
baseline="MemManager.txt",
aliases="MemManagerTest"
addtodefaults=True)

Running Test Using a SCA Test Component


A typical test scenario is to have a separate SCA component that is used to test your production
components. Normally the component to do the testing is built in the same directory where the TestRun
routine is issued. The following is an example of how this type of test is run.
env.TestRun(component="Test.CatalogTest",
command="scautil",
args="-test Test.CatalogTest.Test",
baseline="CatalogTest.txt",
aliases="CatalogTest")
In this case, the test component, Test.CatalogTest, is built in the current directory. The scautil command
with the -test option is used to load and run the test service it contains. The output from the run is
compared to the baseline data contained in the file CatalogTest.txt which is also in the current directory.
This test will be run when the CatalogTest alias is specified on the scons command as follows.
scons CatalogTest

Testing Using a Program


A similar test could have been done using a program instead of a SCA component as the test driver. This
is shown in the following example.
# Build a main program that depends on a shared library
env.ProgDependsOnAlias("UtilTest","Utilities")
env.BuildProgram("UtilTest")
Chapter 15: SCA Utility Program and Testing Components 397
Testing of SCA components

# Run the test and check the results


env.TestRun(program="UtilTest",
baseline="UtilitiesTest.txt",
loadpaths="File/Utilities",
alias=”UtilitiesTest”)
In this example we are using a program, UtilTest, built in the current directory to run the tests on a non-
SCA shared library, Utilities. The shared library is built in a different directory so we set up a dependency
between the program and the shared library to make sure it will be built when needed. The TestRun
routine specifies that we are using a program to run our tests. In this case, it is not necessary to specify
the command to run since it is the same as was specified in the program argument. We have also used the
loadpaths argument so the loader can find the shared library. This is required since the File/Utilities
directory, where the shared library is built, is not in the default load path.

Testing Using Python Script


You can also use a Python script as the driver for the test. The following is an example of how this can
be done.
# Set Python's path to the current directory and import the script
import sys
sys.path.insert(0,env.AbsDirPathInSou("."))
import TestScript

# Run the test


env.TestRun( command=TestScript.test,
baseline=”TestRun.txt”,
aliases="TestRunTest")
In this example, the TestRun routine executes the test function in the TestScript.py Python script. If you
want to use the feature to compare the test results to a baseline, then the script should return a Python list
containing the lines of output to be compared. The following is an example of what the Python script
could look like.
# Python script to drive test
import SCA
def test(env,args):
output = []
spService = SCA.getService(‘Test.CatalogTest.Test’)
if not spService:
output.append(‘Error loading service’)
return output
(ret,inf) = spService.getInterface(‘SCA.Catalog.SCAICatalog’)
if ret:
output.append(str(ret))
return output
entry = inf.getCatalogEntry(‘TestEntry’)
output.append(‘Catalog entry = ’ + entry)
return output
398 SCA Framework User’s Guide
Testing of SCA components

Using a fixup Routine


Sometimes it is difficult to use the baseline compare feature because some lines of output change from
run to run and these will always trigger an error. A simple example of this could be if the output contained
the date of the run. To handle these situations, you can provide a Python script to the TestRun routine
that is used to process each line of output before it is compared to the baseline. The following is an
example of doing this.
# Set Python's path to the current directory and import fixup script
import sys
sys.path.insert(0,env.AbsDirPathInSou("."))
import CatalogTestFixUp

# Run the test


env.TestRun(component="Test.CatalogTest",
command="scautil",
args="-test Test.CatalogTest.Test",
baseline="CatalogTest.txt",
fixup=CatalogTestFixUp.fixup,
aliases="CatalogTest")
In this example the fixup routine in the Python script CatalogTestFixUp.py is used to process each line
of output. It looks for any occurrences of a date with the form dd/mm/yyyy and replaces it with a generic
xx/xx/xxxx so the compare can be successful.
import re
def fixup(env,line):
line = re.sub(" [0-9]{2}/[0-9]{2}/[0-9]{4} "," xx/xx/xxxx ",line)
return line
The fixup routine is called with two arguments. The first argument is the current SCons environment that
the test is running in and the second argument is the line of output to be processed.
The fixup routine can also specify that the output line should completely be deleted from the comparison
as follows.
def fixup(env,line):
if line.find(“Sting to trigger line deletion”) > 0:
return []
return line
Or it can replace one line with several lines.
def fixup(env,line):
if line.find(“Line to be replace with several lines”) > 0:
line = []
line.append(“new line 1”)
line.append(“new line 2”)
return line
return line
In general, the return value from the fixup routine should be one of the following.
• The original string value of the line
Chapter 15: SCA Utility Program and Testing Components 399
Testing of SCA components

• A new string value for the line


• A list of string values to replace the original one. This list may be empty.

Using the Preprocessor on the Baseline Text


The fixup routine provides a convenient way to handle simple changes in the output which only affect a
single line. If the changes that need to be made involve processing a block of lines as a unit then it can
be difficult to do with the fixup feature. To handle these cases, the TestRun command provides a simple
preprocessor that can be used to customize the baseline text before it is used to test the result. To use this
feature you add a preprocessor argument to the TestRun command. The value of the argument is a
Python dictionary which contains the preprocessor variable names and their values. The following
example shows the use of this feature for the case where a particular test is only run the Windows
platform.
# Setup the preprocessor arguments
vars = {}
if env[‘MACHINE’] == “WINNT”:
vars[‘WINNT’] = True
else
vars[‘WINNT’] = False

# Run the test


env.TestRun(component="Test.CatalogTest",
command="scautil",
args="-test Test.CatalogTest.Test",
baseline="CatalogTest.txt",
preprocess=vars,
aliases="CatalogTest")
The baseline text file, CatalogTest.txt, would then include the appropriate preprocessor command to
skip the relative lines if the test is not being run on Windows.
Line for all machine
#if WINNT
Line for Windows only
#endif
Line for all machines

Performing Setup and Clean Operations


There may be cases when you need to do some special setup processing before the test is run and related
clean up processing after the test. An example of this may be the creation of special input files and the
deleting of temporary files created during the test. It is important to remember that these types of
operations should not be performed directly in the SConscript file for a number of reasons.
• Any setup type operations executed directly in the SConscript file will be performed every time
the build is run, even so the actual test may not be executed during the current build.
400 SCA Framework User’s Guide
Testing of SCA components

• The SConscript file is always completely executed before any targets are built which means in
this case before any tests are run. As a result there is no way to perform any cleanup operations
in SConscript file.
The proper way to perform these types of operations is to use the setup and cleanup arguments in the
TestRun command. Each of these should point to a Python routine which takes a single argument which
is the SCons environment for the test. The setup routine, if provided, will be run immediately before the
test is run and the cleanup routine will be run immediately after the test is run. The following shows an
example of how these can be used.
import os

# Setup routine
SetupFunc(env):
# Create a test input file
try:
file = open(‘Test.data’, 'w')
for i in range(1024):
file.write(" ")
file.close()
except:
pass

# Cleanup routine
CleanupFunc(env):
try:
os.remove(‘Test.data’)
except:
pass

# Run the test


env.TestRun(component="Test.CatalogTest",
command="scautil",
args="-test Test.CatalogTest.Test",
baseline="CatalogTest.txt",
setup=SetupFunc,
cleanup=CleanupFunc,
aliases="CatalogTest")
Chapter 15: SCA Utility Program and Testing Components 401
Testing of SCA components

Special Construction Variables used by the TestRun


Command
The TestRun command also looks for several special construction variables in the build environment to
provide additional control on the test. These are shown in the following table.

Variable Meaning
TESTRUN_DEBUG SCA Kernel debug parameters which are normally set with the system
environment variable SCA_KERNEL_DEBUG.
TESTRUN_ENV Python dictionary with values to be added to the operating system
environment for the test.
TESTRUN_LOADPATH Replacements to the default Apps Local and Apps System locations that
are added for the test command. These are in addition to any paths that
are specified using the loadpaths argument to the TestRun command.

The following example shows how these can be used.


# Setup special environment for the test
env['TESTRUN_DEBUG'] = "ShrLibLoad=all"
pylib = os.path.join(env['APPS_LOCAL'],"lib","python")
scripts = os.path.join(env['APPS_LOCAL'],"res","scripts")
env['TESTRUN_ENV'] = { "PYTHONHOME":env['PYTHON_SYSTEM'],
"PYTHONPATH":pylib+os.pathsep+scripts }

# Run the test


env.TestRun(component="Test.PythonTest",
command="scautil",
args="-test Test.PythonTest.Test",
baseline="PythonTest.txt",
aliases="PythonTest")
402 SCA Framework User’s Guide
Testing of SCA components
Chapter 16: SCASCons Build System
SCA Framework User’s Guide

16 SCASCons Build System

 Introduction 404
 Configuring the Build System 405

Running the Build 418
404 SCA Framework User’s Guide
Introduction

Introduction
The SCA Build System is used to build SCA Framework components. Together, the build system and
the SCA IDL compiler make the development of SCA components easier for the programmer by
automating many of the required steps in the coding and build process.
The SCA build system utilizes the SCons utility to do the builds. SCons is an open source software build
tool that is an improved cross-platform replacement for the classic Make utility. SCons is implemented
as a Python script and set of modules. Because SCons configuration files are actually executed as Python
scripts, build customization can be done using the Python language.
The SCons system has been customized for the SCA environment and provides the following
functionality.
• Automatic traversal of the source tree processing all directories containing a SConscript file
• Setting up appropriate processing for every file in a directory with a supported file type
• Automating the building and management of SCA components

This section provides a basic overview of the SCA build system and describes the steps for building a
SCA service. For a complete description of the build system, see the document SCA Build System
Guide.
Chapter 16: SCASCons Build System 405
Configuring the Build System

Configuring the Build System


The build system has to be configured before it can run successfully. The main parts of configuring the
build are as follows:
1. Create the source tree, which contains all the code files to build.
2. Create the configuration files in the source tree with proper construction variables.
3. Install the SCA Build System (if it is not already installed).
4. Install any required third party software.
5. Set the system environment variables.

Construction Variables
The SCA build system uses construction variables containing string values that are substituted into
command lines or used by the builder functions. The construction variables may contain paths, compiler
flags and other build options.
The following places can be used to specify the construction variables.
1. The SConscript files in each directory
2. Using command line arguments
3. The SConopts.user option file in the users home directory
4. The SConopts option file in the root directory of the source tree

Examples:
APPS_DIR = "MyComponent-015"
SCA_OBJECT = “C:/Builds/HelloWorld”
APPS_SYSTEM = “C:/SCA/SCAKernel-V4-007”
APPS_LOCAL = “C:/Builds/HelloWorld/Apps”
Note that these examples show the setting of configuration variables on the command line and the
SConopts files. The syntax for setting configuration variables in the SConscript file is discussed later.

Directory Trees Processed by the Build System


The SCA build systems processes several different directory trees including the source tree, the object
tree, and two delivery trees. Depending on the options the user has set, these directory trees may overlay
each other or be completely separate.

Source
The source tree contains the source code for the SCA components you are developing. The source tree
is normally stored in source control so any changes can be controlled and tracked. As far as the build
system is concerned, it is a directory tree containing the source and has no dependency on any source
control software.
406 SCA Framework User’s Guide
Configuring the Build System

The source tree is also where you must run the build command. The root of the source tree is determined
by the presence of a file named SConstruct. If you start the build in a subdirectory within the source
tree with the –D option, the build system will traverse up the directory tree until it finds a SConstruct
file to determine where the root of the source tree is located.

Object
The object directory contains transitory files created during the build that can be deleted afterwards if
desired. Each build run will only rebuild files that are out of date in the object directory. The location
for the object directory is defined by the SCA_OBJECT construction variable, and it has the same
directory structure as the source tree.

Apps System
The Apps System directory contains all of the components that make up the release of the product on
which your component is based. This is where the SCA Framework is located as well as any other
components that your component uses. It does not contain your component.
The tree is organized in a structure optimized for running the application.
The types of files listed below are stored in both the Apps System and Apps Local directory trees.
• IDL files
• C++ header files generated from the IDL files
• Dynamically linked shared library for the component
• Resource files that are required by the component

The location of the Apps System directory is defined by the APPS_SYSTEM (absolute path)
construction variable or the APPS_DIR (relative path) construction variable.

Apps Local
The Apps Local tree has the same structure as the Apps System and only contains the components that
you have built. This is where you will find the build results for your component. Some of the files in
this directory are copied from the source tree, some from the object tree and some are generated directly
in the tree.
The location of the Apps Local directory is defined by the APPS_LOCAL (absolute path) construction
variable. If APPS_LOCAL variable is not defined, then the default location is used which is under the
object directory.

Third Party tree


The build system provides facilities for including support for third party packages. Third party packages
are non-SCA components that are required to build and run an application. Support for Mozilla, Qt, and
Python packages is supplied by default. Support for additional libraries can be added. This support
requires that the third party package be installed in a directory structure that is understood by the build
system.
Chapter 16: SCASCons Build System 407
Configuring the Build System

The basic directory hierarchy for the third party tree is:
ThirdParty/Package/Version/Platform

This structure allows support for multiple versions of each package on each platform type. The version
identifiers in the above tree are just directory names and can be numeric, alphabetic or any combination
of both. Multiple packages can be installed under the same third party tree or they may be installed in
different trees. Depending on how the version of the package is located at run time, the ThirdParty,
PackageX or VersionX directory levels many not be required in the directory tree.

Tools Directory
The Tools tree contains the SCA Build System and the other tools required for building SCA
Components. These are some of the utilities included.
• genskeleton - Generate skeletons for service implementations
• idl - SCA IDL Compiler
• scons - SCA Build system

This location could be added to the operating system’s path environment variable to make it easy to run
the tools.

Rules for locating Apps System and Third Party Trees


There is a common set of rules that are used to locate the Apps System and third party directory trees.
These rules allow you to specify the full path to the directory or only the directory name and the build
408 SCA Framework User’s Guide
Configuring the Build System

system will determine its full path. The table below shows what construction variables can be used. The
X field in the variable names can be APPS or a third party package name.

Variable Description
X_SYSTEM Full path to the location of the X directory tree.
X_DIR Directory name of the X tree.
X_BASE Name of the base directory for locating the X_DIR directory for
package X.
SCA_THIRDPARTY_BASE Name of the base directory for locating X_DIR directories for third
party packages only.
SCA_BASE Name of the base directory for locating X_DIR directories for the
APPS and third party packages.

To locate APPS_SYSTEM, either the APPS_SYSTEM or the APPS_DIR variable must be specified.
If the APPS_SYSTEM variable is used, it already contains the full path to the desired directory and the
search is done. However, if the APPS_DIR variable is used, the following locations are searched to
determine the full path.
• If APPS_BASE is defined: APPS_BASE/APPS_DIR.
• If SCA_BASE is defined: SCA_BASE/APPS_DIR.
• ../APPS_DIR relative to the location of the SCons script running.

Locating third party directories follows the same general rule except the third party directory tree
structure is used. For the third party package X, either the X_SYSTEM or the X_DIR variable must be
specified. If the X_SYSTEM variable is used, it already contains the full path to the desired directory
and the search is done. In this case it should point to the specific platform specific directory for the
desired version of the package. For example, the Qt package on Windows could be located using the
following value.
QT_SYSTEM = “C:/SCA/ThirdParty/Qt/3.3.2/WINNT”
If the X_DIR variable is used, the following locations are searched to determine the full path. The
MACH value in these rules is substituted with the appropriate value for the platform you are building for.
• If X_BASE is defined: X_BASE/X_DIR/MACH.
• If SCA_THIRDPARTY_BASE is defined: SCA_THIRDPARTY_BASE/X/X_DIR/MACH.
• If SCA_BASE is defined: SCA_BASE/ThirdParty/X/X_DIR/MACH.
• ../ThirdParty/X/X_DIR/MACH relative to the location of the scons script running.

Rules for locating Apps Local and object trees


The location of the Apps Local and Object directory trees is controlled by the construction variables
SCA_OBJECT and APPS_LOCAL.
Chapter 16: SCASCons Build System 409
Configuring the Build System

The following table shows the possible combinations for SCA_OBJECT and APPS_LOCAL and how
they affect the location of these trees.

Location of Apps
SCA_OBJECT APPS_LOCAL Local Tree Location of Object Tree
Not set Not set Source/Apps Source/ObjectSubTree

e.g.
/source/WINNT_SRC_DEBUG
Set Not set SCA_OBJECT/Apps SCA_OBJECT/ObjectSubTree
Not set Set APPS_LOCAL Source/ObjectSubTree
Set Set APPS_LOCAL SCA_OBJECT/ObjectSubTree

The ObjectSubTree could be MACH_SOURCE_DEBUG or MACH_SOURCE_OPT depending on


debug or optimized build. For example on Windows if the Source directory is TestComp, then
ObjectSubTree could be WINNT_TESTCOMP_DEBUG or WINNT_TESTCOMP_OPT.
The APPS_LOCAL construction variable is not normally set in the users SConopts.user options file.
Normally its location is set using the SCA_OBJECT construction variable.

Configuration files
There are four main types of configuration files that control the configuration of the build which are
described below. The build system uses a directory hierarchy model so the appropriate configuration
files must be present at the appropriate places in the source tree for the whole directory structure to be
processed.
An important point to remember is that the build system uses these files to create the build environment.
The build system only propagates the HOME environment variable into the build environment from the
list of environment variables defined for the user. None of the other environment variables set by the user
are propagated. The reason for this is to maintain a standard build environment independent of the user
settings. There are also some operating system environment variables that individual system commands
required that are also automatically propagated into the build environment. An example of this is the
TMP variable that is required by the Windows linker.

SConstruct
This is the master configuration file and must exist in the root of the source tree. It is used to initiate build
processing by identifying the root of the source tree and specifying any special build system
configuration options for it.
The SConstruct file provides customizations and extensions to the build system itself. Examples of
these types of customizations might be adding user specific construction variables, environment routines
and third party packages. Because the SConstruct file is run at an early stage of the build process, the
rules for coding this file are different than the two options files. Setting values for construction variables
410 SCA Framework User’s Guide
Configuring the Build System

should not be done in this file. Only new construction variable names and their default values can be
declared. Customized values for these variables should be set in the normal manner in the SConopts or
SConopts.user files or on the command line.
After the initial setup, this file only needs to be updated when new build configuration options are
needed, such as adding a third party software dependency. An example SConstruct file with one third
party software configuration is provided below.

# Main SCons configuration file for the SCA build system.


from SCASCons.Configure import *

#================== Perform local customization here


==================

#
# Set up for LibXML processing
#
def IncludeLibXML2(env, compile=True,extraincs=[],
link=True,extralibs=[]):
# Set compilation related values
if compile:
libXMLInc = os.path.join("$LIBXML_SYSTEM", "include")
env.Append( CPPPATH = libXMLInc )
for inc in env.Split(extraincs):
env.Append( CPPPath = os.path.join( libXMLInc, inc ))
# Set link related values
if link:
if env["MACHINE"] == "LX8664":
env.Append( LINKFLAGS=os.path.join("$LIBXML_SYSTEM", "lib",
"libxml2.so.2") )
else:
env.Append(LIBPATH=os.path.join("$LIBXML_SYSTEM", "lib"))
env.Append(LIBS="libxml2")
for lib in env.Split(extralibs):
env.Append(LIBS=lib)

# Initialize the package


ThirdPartyPackage('libxml', 'libxml2 support', IncludeLibXML2)

#====================================================================
==

import SCASCons.Setup
SCASCons.Setup.Setup()
There is a sample SConstruct file, in the Runtime/lib/python/SCASCons subdirectory of the Tools tree,
with a list of all the available commands.
Chapter 16: SCASCons Build System 411
Configuring the Build System

SConopts
This file is in the root of the source tree and contains build options, i.e. construction variable settings,
unique to this source tree. The file should only set options that are specific to the source tree as they will
be treated as default values for every user working in the tree. Examples of this type of information might
be SCA Framework version, build information, and third party versions.
After the initial setup, this file only needs to be updated when new build configuration options are
needed, such as using different version of the SCA Framework. The SConopts.user file, which is
described next, contains options that are unique to users but not to the source tree. The same types of
items can go into either of the files, but they are separated for the reasons described.
An example of the SConopts file is provided below.
# Source tree specific build options file
import SCASCons

# Apps System directory location relative to APPS_BASE.


APPS_DIR = "SCAKernel-V4-007"

# Third party option for LibXML.


if SCASCons.MACHINE == 'WINNT':
LIBXML_DIR = "2-2.6.27-2"
else:
LIBXML_DIR = "2-2.6.27"

SConscript
One of these configuration files must exist in each directory that is to be processed. If a directory does
not have a SConscript file, then processing will stop at that point and the directory and all of its
subdirectories will be skipped. This small file can also contain special build instructions for the files in
its directory. If there are no special requirements, as in this example, then the default version of this file
still needs to be present.
Import("env_base")
env = env_base.Copy()

#================= Perform local customization here


=================

#====================================================================

retval = env.ProcessDir(env_base)
Return('retval')

SConopts.user
This optional file exists in the user’s home directory and contains user-specific build options used for any
builds that they perform. Options in this file have precedence over options in the SConopts file, and
unlike the SConopts file, this file may change often depending on the user’s environment.
412 SCA Framework User’s Guide
Configuring the Build System

User specific options should be put in each user’s SConopts.user file. Examples of this information
might be temporary object locations and output requests. You can also override any of the settings in the
SConopts file. You may wish to do this if you want to build against a different version of a third party
package for example. Be careful about the settings you put in this file because they will affect every build
you as a specific user run no matter which source tree you are processing.
Before using the SCA build system, you need to make sure your personal build options file is setup
correctly. The file is a Python script that is run at the start of the build process.
An example of the SConopts.user file is provided below.
import sys
import os

# Set location for object tree


root = os.path.basename(os.getcwd())
if sys.platform == “win32”:
SCA_OBJECT = “C:/Builds/” + root
else:
SCA_OBJECT = “/tmp/rich/Builds/” + root

# Set reduced command output


COMMANDPRINT = ‘short’
Normally you should only define the locations of the SCA_OBJECT and optionally the APPS_LOCAL
directory trees in your SConopts.user file. The APPS_SYSTEM directory is defined in the SConopts
file, which resides in the root of the source tree. If APPS_LOCAL directory is not defined, then the
default location is used and is under the object directory.

Setting up the Build System in a New Source Tree


Setting up the SCA Build System in a new source tree is a relatively simple task. In the root of source
tree, you need to copy the following configuration files.
• Copy SConstruct.example to SConstruct
• Copy SConscript.example to SConscript
• Copy SConopts.example to SConopts

The example configuration files can be found in the SCASCons directory which is located in the
Runtime/lib/python/SCASCons subdirectory of the Tools tree. These configuration files should be
modified as required for the source tree. In particular, the SConopts file should be modified to specify
the correct version of the SCA Framework that will be used.
Next, you need to create a SConscript file in each directory in the source tree that needs to be processed.
If required you may modify these files to do special processing in their directory.
For details on the available customization options for these files, see the document SCA Build System
Guide.
Chapter 16: SCASCons Build System 413
Configuring the Build System

Setting up your Runtime Environment for the Build System


There are a couple of settings in your runtime environment that you will usually want to set up when
using the SCA build system
1. Add the Tools System directory to the user’s path environment variable. This is not required, but
if it isn’t in the path, the scons command will require a fully qualified path name each time it is
executed. The path used in the example configuration files is C:\SCA\Tools-V5-003.
2. Your home directory must be defined with the HOME environment variable. This is standard for
Linux and UNIX, but Windows users may have to add it manually if they want to use the
SConopts.user file.
3. Create the TMP environment variable on Windows to define a directory for temporary files if it
has not already been defined. This is required by the Windows Linker for temporary storage.

The SCons Construction Environment


The construction environment is a special Python object which is usually referenced with the Python
variable named env. This object is used by SCons to store the current values for each construction
variable. It also contains the API that is used in the SConscript files to manipulate it. The construction
environment and its construction variables contain all of the knowledge required to create the actual
commands that will be run during the build.
When SCons starts up, the first thing it does is initialize the base construction environment. For example,
on Linux it initializes the processing for C and C++ files. The builder defines a construction variable,
CCCOM, which contains the actual command used to compile the files.
CCCOM = $CC $CCFLAGS $CPPFLAGS $CPPDEFFLAGS $CPPINCFLAGS
-c -o $TARGET $SOURCES
Notice that the compilation command definition is mostly composed of other construction variables. By
modifying any of the variables, or the CCCOM variable itself, you have complete control over the actual
commands used by the build system to build the various types of targets.
After SCons creates the base construction environment, the SConopts and SConopts.user option files
are executed. They can modify any construction variables as required for this build. The complete order
of precedence, starting with the highest, for setting construction variables is as follows.

SConscript Options in this directory only


Command line Options for this run only
SConopts.user Options for this user only
SConopts Options for the source tree only
Defaults Default options provided by SCons

As the SCA Build System processes the source tree, the SConscript file in each directory is executed.
The first two lines of each SConscript file should be the following.
414 SCA Framework User’s Guide
Configuring the Build System

Import("env_base")
env = env_base.Copy()
These two lines make a copy of the base construction environment that will be used in this directory. A
copy of the construction environment is made in each directory so any changes made to it in the current
directory will not affect processing in any other directory. You should not make any changes to the base
construction variable, env_base, directly. If you wish to have change you make in the current directory
be propagated down to all of its subdirectories you should use the env.Propagate command.

Modifying Construction Variables in the SConscript File


The SConscript configuration files are run as part of the actual build operations, so they must follow
some rules that are different from the options files discussed previously. Instead of setting construction
variables using normal Python global variables, they must be accessed in the actual SCons construction
environment.
if env[‘MACHINE’] == ‘LX86’:
env.Append(CCFLAGS=["-wd810"])
When the actual build commands are run, the current working directory is in the root of the source tree.
This means that when build options include paths arguments, they should normally be coded as absolute
paths or paths relative to the root of the source tree and not paths relative to the directory containing the
SConscript file.
env.Append(CCFLAGS=["-IFramework/include"])
There is a common exception to the rule. Construction variable names, which end with PATH, are
treated differently. The path names in these variables are relative to the directory that contains the
SConscript file. If you want these values to be relative to the root of the source tree, you can use the
special syntax of #/… to indicate this. You can also code these as absolute paths if you wish but this is
not normally a good practice because it makes relocating the source tree more difficult. In the following
examples, all of the paths are equivalent assuming the SConscript file is in directory
/scasystem/Framework/Kernel.
env.Append(CPPPATH="#/Framework/KernelUtil")
env.Append(CPPPATH="/scasystem/Framework/KernelUtil")
env.Append(CPPPATH="../KernelUtil")
If you have platform specific construction variables in the SConscript files, you should use the
construction variable MACHINE to test for the current platform.
if env["MACHINE"] == "LX86":
. . .
elif env["MACHINE"] == "WINNT":
. . .

Special processing for CPPPATH construction variable


The CPPPATH construction variable has two functions.
Chapter 16: SCASCons Build System 415
Configuring the Build System

• Adds directories to the list of include paths searched by the C preprocessor just like -I arguments
in the CCFLAGS variable.
• Triggers dependency processing between all of these header files located in these directories.

If the directory contains header files in which you want to include all dependency scanning and testing
then they should be added with the CPPATH construction variable. Notice how the -I preprocessor
argument is not used in this case. It will be added automatically when the values are added to the
CCFLAGS variable by SCons.
env.Append(CPPPATH=["$QT_SYSTEM/include"])
If the directory contains packages that change very seldom and you do not wish to do any dependency
scanning or testing then they should be added directly to the CCFLAGS construction variable. In this
case, the -I flag is now required because these arguments are sent directly to the compiler.
env.Append(CCFLAGS=["-I$QT_SYSTEM/include"])

Available construction variables


The following are some of the commonly used construction variables that you might set in the
SConscript files.

CCFLAGS C and C++ compiler options

CPPDEFINES C preprocessor defines

CPPFLAGS C preprocessor options

CPPPATH C preprocessor include paths

CXXFLAGS C++ compiler options

FORTRANFLAGS FORTRAN compiler options

LIBPATH Link library paths

LIBS Link libraries

LINKFLAGS Link program options

BUILDTYPE Optimized or debug build selection

COMMANDPRINT Level of build output desired

For a complete list of the available construction variables you can run the following command from
inside any SCons source tree.
scons –h
416 SCA Framework User’s Guide
Configuring the Build System

Commonly Used Environment Routines


The following are some common environment routines that are used in the SConscript files. For details
on all of the available routines, see the document SCA Build System Guide.

Modifying construction variables


To replace the value of a variable with a new value you can use either of the following commands.
env.Replace(VARIABLE=value)
env[“VARIABLE”] = value
For example, the following command specifies the additional libraries to link.
env.Replace(LIBS=["comdlg32",”wsock32",”advapi32.lib"])
To append a new value to an existing variable you use the following command.
env.Append(VARIABLE=[value])
To prepend a new value to an existing variable you use the following command.
env.Prepend(VARIABLE=[value])

Building programs and libraries


When the SCA Build system finds a SDL or a CDL file in a directory, it will automatically trigger the
building of a static object library or a dynamically linked shared library. The building of a program or a
non-SCA shared object or shared library must be explicitly requested in the SConscript file. The object
files used to build each of these will include all of the objects files generated in the current directory and
the any objects files from its subdirectories that were not previously used in the building of a different
library or program.
The following routines are available in the SConscript file to trigger the build.
# Build a main program in the current directory
env.BuildProgram(progname,aliases=None)

# Build a shared library in the current directory


env.BuildSharedLibrary(shlibname,aliases=None)

# Build an object library in the current directory


env.BuildObjectLibrary(objlibname,aliases=None)

Adding libraries and objects to a link


Sometime you may need to add extra shared libraries or object files to a link. The following routines
allow you to do this.
env.AddLinkSharedLibrary(names,appendend=None)
env.AddLinkSource(names)
Chapter 16: SCASCons Build System 417
Configuring the Build System

Installing files
The SCons will automatically install certain file types into the APPS_LOCAL directory when they are
found in the source tree. Examples of these include IDL files and any XML files. The following routine
can be used to explicitly install other files that are not supported.
env.InstallFile(files,installdir,aliases=None,newname=None)

Propagating commands to subdirectories


As discussed before, changes made to the values of construction variables are local to the directory they
are made in. Sometimes you may wish for these changes to apply for the current directory and all of it
subdirectories. The env.Propagate routine allows you to do this.
env.Propagate(routine,*args,**keywords)
The arguments to this routine are the name of any other environment routine and its arguments. For
example, the following will change the C compiler flags in the current directory and all subdirectories.
# Change only in current directory
env.Append(CCFLAGS=["-wd810"])

# Change in current directory and all subdirectores


env.Propagate(env.Append,CCFLAGS=["-wd810"])

Skipping files and directories


A number of routines are provided which allow you to skip files or directories that the build system would
normally process.
env.SkipFiles(names)
env.SkipSubDirs(dirs)
env.SkipThisDir()

Microsoft Visual Studio Projects


SCons automatically builds Visual Studio project files using its complete knowledge of the build tree.
There is one project file generated for each SCA component, main program, static object library and
shared library. There is also a global solution file that is generated in the root of the source tree that can
be used to reference all of the project files contained in the source tree.
When you do a build from within Visual Studio, the project files will invoke SCons to do the actual build.
This causes the same build procedure to be used whether you are running from the command line for from
within the Visual Studio IDE and you will get the same build behavior and results.
The Visual Studio project files can also be generated by executing the following command from the root
directory of the source tree.
scons msvs
For more details on Visual Studio projects, see the document SCA Build System Guide.
418 SCA Framework User’s Guide
Running the Build

Running the Build

Build Tasks
When building SCA components, the build system will take care of most of required tasks. This
processing is triggered by the presence of the appropriate files in the directory being processed. The
following are some of the tasks that are automatically performed.
1. The IDL compiler processes the IDL file, generates header files for each interface, and stores
them in the APPS_LOCAL tree.
2. The IDL compiler processes the SDL file and generates the required base class files for the service
and each sub-service defined. These will be stored in the object directory.
3. The IDL compiler processes the CDL file and generates the required initialization function for the
component. This file will also be stored in object directory.
4. The build system compiles and links all of the code created in the previous steps as well as the
source in the source directory; it then stores the object files in the object directory. The
component’s dynamically linked shared library and any other files that come out of the linking
procedure will be copied into the APPS_LOCAL directory for future use.
5. The build system adds an entry to the Service catalog for each service that is contained in the
component. The service catalog’s path is APPS_LOCAL/res/SCAServiceCatalog.xml in the
Apps Local directory.

SCons Command
The simplest way to run SCons is from the root of the source tree. The following command will cause
the entire tree to be built.
scons
Or to build only selected components you simply add the name of the component.
scons HelloWorldCPP

Running SCons from a Subdirectory


By default, SCons requires a SConstruct file to be in the current directory when you run the command.
If you are working in a subdirectory of the source tree, you must use one of the following options to cause
SCons to search up the directory tree to find the SConstruct file, which defines the root of the entire
source tree.
Search up directory tree for SConstruct and build all default targets.
scons –D
Chapter 16: SCASCons Build System 419
Running the Build

You can also use other targets on this command. A common example would be if you are working in the
source directory for a component, for example HelloWorldCPP, and you wanted to rebuild the
HelloWorldCPP shared library. You can use the following command to accomplish this.
scons –D HelloWorldCPP

Phases of the Build Process


The build is performed in three phases: configuration file processing, dependency processing, and
executing build commands. These phases are described below.

Configuration file processing


The first phase of the build process is to process all of the configuration files. The system traverses the
source tree and performs the steps below in each directory.
• The build executes the SConscript file. The build skips the directory if it does not contain a
SConscript file.
• The build processes each file in the directory and creates build actions for it if the file type is
supported. The file is ignored if the type is not supported. As the build actions are created, they
are linked together into a global dependency tree containing all of the relationships of the files in
the source tree and the targets that they generate.
As each directory is processed, a list of object files created is maintained. If the build system determines
that an object library, shared library or main program is to be built, this list of object files is used. If none
of these is built in the directory, then the list of object files is passed back to the parent directory to be
added to its list of object files. This way, whenever an object library, shared library or main program is
built, it will contain all of the object files from the current directory and any unused objects from its
subdirectories.

Dependency processing
SCons automatically scans the source files for any implicit dependencies they have and adds them to the
global dependency tree. Examples of these are the include files a C++ source file references.

Executing build commands


After all of the dependencies have been determined, SCons checks if any of the dependencies are out of
date. By default, MD5 checksums are used to determine when a dependency has changed instead of file
timestamps. This is so clock differences between file servers do not affect the build process and allow
SCons to rebuild only the minimal files required.
It is important to note that no targets are built during configuration file and dependency processing
phases. The build commands such as env.BuildProgram and env.BuildSharedLibrary found in
SConscript files are only used to create entries in the global dependency tree. The actual targets are not
built until the final phase of the build, using the information in the dependency tree. This is important
because any Python code you add to SConscript file will be executed before any actual targets are built.
420 SCA Framework User’s Guide
Running the Build

There is no way to control the exact order in which these targets are built. The only thing that can be
assured is that all dependencies for a target will be built before the target.

Removing Files Created by the Build


SCons has a clean option that allows you to remove all the targets it has built. This is requested with the
-c argument. If you include a target on the command then only that target and all of the targets required
to build it will be removed.
scons -c
scons -c HelloWorldCPP
scons -D -c HelloWorldCPP
You should take care using the clean command without any targets because it may delete things you don’t
expect. If you want to do a clean build, the easiest and fastest thing to do is to just delete the entire object
tree.

SCons Debugging Options


There are several SCons command line options available to help debug any build problems.

debugprint=x Prints debugging information for level “x”. For a list of the available levels use
debugprint=’?’
--debug=tree Print tree of dependencies generated by SCons. This option can generate a
large amount of output for big source trees.
--debug=explain Give an explanation why each target is being built.

It is also sometimes desirable to see the actual values of various construction variables that will be used
for the build. This can be done by using the name of the construction variable as the target on the SCons
command line.

scons CPPATH
This command will not perform a build, but will instead traverse the source tree and show the default
value for the CPPATH construction variable and any directory that has a different value. The printing
of construction variables values is only triggered when all of the targets on the command line are upper
case. If any of them contain lower case characters then they are assumed normal build targets and a
normal build is performed.

Selecting Debug and Optimize builds


The SCA Build System supports both debug and optimized builds. The appropriate compiler options are
provided for each of these. These are controlled with the BUILDTYPE variable, which accepts a value
Chapter 16: SCASCons Build System 421
Running the Build

of debug or opt. This variable can be specified on the command line but is normally only used in the
SConopts or SConopts.user options file.
BUILDTYPE=debug
BUILDTYPE=opt
For convenience, special command line only options are supported to control the type of build.
scons debug=yes
scons debug=no
scons opt=yes
scons opt=no
There is no difference between specifying debug=yes or opt=no, on the command line. They will both
generate a debug compile. Similarly, debug=no and opt=yes will both generate an optimized compile.
It should also be noted that the debug and optimize compile options only change the compiler options
that are used. No special preprocessor defines are generated to indicate which is being used. If these are
desired, you need to add them yourself. This was done because large amounts of undesired debug output
can be generated if all programmers are triggering off the same preprocessor values
422 SCA Framework User’s Guide
Running the Build
MSC.Fatigue Quick Start Guide

Index
SCA Framework User’s Guide (DEV)

A I
Aliases to other types, 67 IDL, 49
IDL compiler command, 96
B IDL Langauage, 11
IN
Basic IDL types, 58 IDL specification, 57
DE IDL to .Net
Build tasks, 418
X mapping for arrays, 201
Building component, 34
Index mapping for basic types, 196
mapping for constants, 215
C mapping for enumerated types, 199
CDL, 49 mapping for exceptions, 217
CDL Specifications, 89 mapping for Identifiers, 194
Code skeletons, 28 mapping for interfaces, 216
Component metadata, 351 mapping for modules, 195
Configuration files, 409 mapping for SCA Components, 227
Constant expressions, 55 mapping for SCAAny, 206
Constants, 70 mapping for SCAResult, 211
Creating client, 35 mapping for SCATypeCode, 205
mapping for sequences, 203
D mapping for string types, 198
Define, interface, 21 mapping for structures, 200
Defining component, 26 mapping for type aliases, 204
Directory trees, 405
Dynamic arrays, 111

E
Embedded components, 150
Environment routines, 416
Exceptions, 85

F
Fixed size array, 110
Forward declarations, 81

G
Genskeleton command, 28
424 SCA Framework User’s Guide (DEV)

IDL to C++ IDL to Python


mapping for arrays, 110 mapping for arrays, 240
mapping for basic types, 106 mapping for basic types, 234
mapping for constants, 130 mapping for constants, 252
mapping for enumerated types, 108 mapping for enumerated types, 237
mapping for exceptions, 137 mapping for exceptions, 258
mapping for identifiers, 104 mapping for identifiers, 232
mapping for interfaces, 131 mapping for interfaces, 253
mapping for modules, 105 mapping for modules, 233
mapping for SCA components, 150 mapping for SCA components, 262
mapping for SCA services, 141 mapping for SCA services, 261
mapping for SCAAny, 121 mapping for SCAAny, 244
mapping for SCAResult, 127 mapping for SCAResult, 248
mapping for SCATypeCode, 120 mapping for sequences, 241
mapping for sequences, 116 mapping for structures, 238
mapping for string types, 107 mapping for type aliases, 242
mapping for structures, 109 mapping for TypeCode, 243
mapping for type aliases, 119 SCA module, 263
IDL to Java IDL type definitions from Python, 264
mapping for arrays, 161 IDLTypes.jar, 190
mapping for Basic Types, 156 Interface body, 79
mapping for constants, 177 Interface header, 78
mapping for enumerated types, 159 Interface inheritance, 79
mapping for exceptions, 180 Interface, programming, 7
mapping for identifiers, 154 Interfaces and operations, 78
mapping for interfaces, 178 Interfaces, define, 21
mapping for modules, 155
mapping for SCA components, 189 J
mapping for SCA services, 184 Java virtual machine, 190
mapping for SCAAny, 168
mapping for SCAResult, 173
mapping for SCATypeCode, 167 K
mapping for sequences, 164 Kernal
mapping for string types, 158 initialization, 355
mapping for structures, 160 terminating, 355
mapping for type aliases, 166 Kernel configuration variables, 359
mapping for unsigned data types, 157
L
Language support, 15
Lexical rules, 51
Library manager, 377
Literals, 52

M
Mapping for identifiers, 104
Mapping for SCA services, 220
INDEX 425

Message files, 271 SCA-IDL compiler, 96


MessageDispatcher, 316 SCAIService interface, 83
Metadata, 351 SCAResult for error handling, 305
Multi-Threaded application, 341 SCASequence, 66
Multi-Threaded services, 339 SCAString, 66
SCAWString, 67
N SCons, 418
Name lookup rules, 74 SConscript, 414
Scoping rules, 76
ScriptBroker, 267
O SDL, 24, 49
Operation declaration, 79 SDL Specifications, 86
Sequences versus arrays, 68
P Service manager, 373
Platform support, 16 Service options, 92
Prefix changing, 365 Source files, 49
Preprocessing, 56
Programming, 7 T
Python scripts, 267 Template types, 66
Testing SCA components, 393
Q Text translation service, 278
Qualified names, 75 Thread safety, 333
Threading infrastructure, 338
R Types, 158
Running SCA kernel, 367 IDL, 58
Running the build, 418
U
S User defined types, 62
SCA component, 13 Using SCA kernel, 366
SCA component declaration, 94
SCA exceptions for error handling, 294 X
SCA framework, 14 XML parser, 385
language support, 15
platform support, 16
SCA framework / JVM interaction, 190
SCA interfaces, IDL language, 11
SCA kernal, 366
SCA kernal using, 366
SCA kernel, 13
SCA overview, 5
SCA services, 12
SCA services catalog, 370
SCA utility program, 389
SCAAny class, 121
426 SCA Framework User’s Guide (DEV)

You might also like