You are on page 1of 68

MD Nastran R3

SCA Service Guide

Main Index
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 © 2008 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. April 25, 2008


jak^WoPWwWp`^WwWa`JrpoJmac

Main Index
Contents
MD Nastran R3 SCA Service Guide

1 Introduction
Introduction 2
SCA Framework 2
Interfaces 3
Services 4
Components 4
Smart Pointers 5

2 Creating Services
Create a Service 8
Define the Interfaces 8
Define the Service 13
Define the Component 17
Generate the Code Files 18
Implement the Interfaces 19
Summary 24

3 Building Components
Build a Component 26
Configure the Build 26
Run the Build 32
Build Delivery 33

4 Using Services
Use a Service 36
Using a SCA Service from another SCA Service 36
Using a SCA Service from an Application 44
Using a SCA Service from a Python Script 45
Summary 46

Main Index
iv MD Nastran R3 SCA Service Guide
==

5 Supported Data Types


Supported Types 48
Basic Types 48
Constant Types 49
User Defined Types 49
SCA Result Type 58
SCA Exception Types 59

Main Index
Ch. 1: Introduction SCA Service Guide

1 Introduction


Introduction

Main Index
2 SCA Service Guide
Introduction

Introduction
The Simulation Component Architecture (SCA) Framework is designed to enable the delivery of MSC’s
simulation technology as reusable software components. The framework allows client applications to
access and extend the simulation components.
Previous experience of interface-based programming is not necessary to use the SCA Framework;
however, an understanding of the basic concepts is important to successfully develop services.
The central principle of interface-based programming, sometimes called component-based
programming, is the separation of the interface from the implementation. When a developer separates an
interface from its implementation, client code is developed around an abstraction of the implementation.
This abstraction is the interface and not a particular implementation, which is the actual object.
Interface-based programming and the SCA Framework provide several benefits to developers:
• 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.
• 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.

There are several points throughout the guide where there will be small variances on syntax based on the
programming language used. This guide uses C++ for the default examples and syntax.

SCA Framework
The SCA Framework is composed of the SCA Kernel, utility services, and supporting infrastructure and
is delivered as a collection of dynamically linked 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
• Implementation reuse support
• I/O
• Memory management
• Messaging support
• Scripting support
• Regular expression searching

Main Index
CHAPTER 1 3
Introduction

• Remoting support
• System Utilities
• GUI Widget
• 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

Interfaces
An interface is the API presented by a SCA service. An interface contains one or more methods that are
related in some manner. All interfaces are defined using an interface definition language or IDL. The
SCA IDL compiler that is provided will process the IDL language and generate the required source files
needed to access the functionality of the interfaces.
To help illustrate the use of interfaces, consider the C++ code below for an interface class, an
implementation class, a factory method, and a client program.
class myInterface
{
public:
virtual void doSomething() = 0;
};

class myImplementation : public myInterface


{
public:
void doSomething() { cout << "doing something" << endl; }
};

myInterface* instanceFactory()
{
return new myImplementation();
};
int main()
{
myInterface* inf = instanceFactory();
inf->doSomething();
}
The client gets an instance of the implementation class using the provided factory method. The return
type of the factory method is the interface class and not the implementation class because the interface
class defines the API that the client can use and only contains pure virtual methods, which means the
interface has no implementation. To deliver the implementation in the example to a client, you only need
to deliver the header file for the interface class and the library for the implementation class and its

Main Index
4 SCA Service Guide
Introduction

factory. Because of this, the client has no knowledge of any aspects of the implementation other then the
API exposed through the 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
myInterface 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
dynamically linked 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.

Services
Services contain the implementation for interfaces and are the level of functionality that a client requests.
Each service is usually implemented by one or more classes in a supported implementation language,
usually C++ or Java. These classes must implement one or more interfaces, which provide the only way
for clients to access a service's functionality. Different implementations for the same interface may reside
in difference services. The client can easily select the desired implementation by requesting an instance
of the appropriate service, which is called a service object.
The lifecycle of a service object is automatically handled, and a service object will delete itself when all
references to it are released. This is true for clients implemented in C++ as well, because they use smart
pointers to access a service's interfaces.

Components
Services are delivered in SCA components, which are dynamically linked shared libraries when using
C++ and jar files when using Java. Client code is not aware of components. When a client requests an
instance of a 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 dynamically linked shared library and
request an instance of the service. The lifecycle of components is automatically handled. When all
instances to the services in a component are released, the shared library will be unloaded.

Main Index
CHAPTER 1 5
Introduction

Smart Pointers
For clients implemented in C++, 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 service
objects that implement the interfaces. The supported client languages that have automatic garbage
collection, such as Java, do not use smart pointers; they use the standard object references provided by
the language. The content of this topic only refers to C++ clients.
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 a 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 detailed below.
• Every time a smart pointer is created, destroyed, copied or assigned to another smart pointer, 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.
• Allow you to determine if two different interface references point to the same underlying
implementation object using standard C++ comparison tests.
Examples of using the C++ smart pointers are provided below.
// Define smart pointers like normal C++ classes.
// Note that no “*” is used as with normal C pointers.
SCAIMyInterface ptr1;
SCAIMyOtherInterface ptr2;

// Different forms of navigating or switching between interfaces.


// If the underlying object does not support the new interface, a
// C++ exception is thrown.
try {
ptr2 = static_cast<SCAIMyOtherInterface>(ptr1);
ptr2 = ptr1;
}
catch(...) {
}

// Tests for a unassigned smart pointer.


if ( ptr1 == NULLSP ) ...;
if ( ptr1 != NULLSP ) ...;
if ( !ptr1 ) ...;
if ( ptr1 ) ...;

// Test if two interfaces point to the same object.


if ( ptr1 == prt2 ) ...;
if ( ptr1 != prt2 ) ...;

// Call a method on the interface.


ptr1->doSomething();

// Releasing the pointer.


ptr1 = NULLSP;

Main Index
6 SCA Service Guide
Introduction

Main Index
Ch. 2: Creating Services MD Nastran R3 SCA Service Guide

2 Creating Services


Create a Service

Main Index
8 SCA Service Guide
Create a Service

Create a Service

Define 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. The SCA IDL is based on the OMG IDL and is defined in the SCA IDL Language and
Compiler Guide.
IDL files have the extension .idl and can contain the sections listed below.

IDL File Sections


IFDEF Definition Recommended
Include Declarations Required
Module Declarations Required
Constant Declarations Optional
Type Declarations Optional
Interface Declarations Required

Example
We will show how to take some existing C++ code and convert it into a SCA service and create a SCA
component to deliver it. We will use a simple Nastran BDF reader as the example. The service that will
be implemented is not a fully functional reader but is intended to just illustrate how a service is created.
We have designed the four interfaces described below for this service.
• SCAIReader: Used to read a data deck.
• SCAISummary: Used to obtain summary information about the deck.
• SCAIExtract: Used to extract grid information.
• SCAIGrid: Used to get information about a single grid.

The example IDL defining these interfaces is listed below. Note that constant declarations are not present
in the example.
#ifndef SCA_FILEREADERS_NASTRAN_NASTBDF_IDL_INCLUDED
#define SCA_FILEREADERS_NASTRAN_NASTBDF_IDL_INCLUDED

#include "SCA/Service.idl"

Main Index
CHAPTER 2 9
Creating Services

module SCA { module FileReaders { module Nastran {

interface SCAIReader : SCAIService


{
SCAResult importBDF( in SCAString sFileName );
};
interface SCAISummary : SCAIService
{
SCAResult getNumGrid( out SCAInt32 iNumGrid );
SCAResult getNumElem( out SCAInt32 iNumElem );
};
interface SCAIGrid;
interface SCAIExtract : SCAIService
{
SCAResult resetGrid();
SCAResult getNextGrid( out SCAIGrid spGrid );
};

struct GridEntry
{
SCAInt32 ID;
SCAReal32 X;
SCAReal32 Y;
SCAReal32 Z;
};

interface SCAIGrid : SCAIService


{
SCAResult getCord( out GridEntry sGrid );
};

}; }; };
#endif

IFDEF Definition
#ifndef SCA_FILEREADERS_NASTRAN_NASTBDF_IDL_INCLUDED
#define SCA_FILEREADERS_NASTRAN_NASTBDF_IDL_INCLUDED
The first two lines of the IDL definition contain the definitions that keep the file from being expanded
more then once during each IDL compilation.

Include Declarations
#include "SCA/Service.idl"
The IFDEF definitions are followed by 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.

Main Index
10 SCA Service Guide
Create a Service

It is important to remember that the file names used in these include statements must include the correct
relative folder location in the delivery structure for the IDL files.
DO NOT use the folder structure in the source tree because the IDL compiler will not look there for the
files. This example uses the path SCA/Service.idl in the delivery tree instead of the location in the source
tree, which is Framework/Kernel/ServiceManager/Service.idl.
The build system will automatically copy the IDL files from the source tree into the local 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.

Module Declarations
module SCA { module FileReaders { module Nastran {

};};};
The IDL file’s module statements are used to define the IDL namespace, which is a scoping construct
used to organize collections of IDL definitions and their visibility in IDL files. It is also used to define
locations in the delivery tree where the IDL and header files are stored. It is not related to the other
namespaces described in this document, including the implementation namespace. It is not required that
all of the interfaces in a service be in the same namespace. The IDL namespace is exposed to clients so
this should be taken into consideration when creating one.
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 with the language specific scope operator. The fully qualified interface name for the
SCAIReader interface in this example is SCA::FileReaders::Nastran::SCAIReader, which
is shown with the IDL and C++ scope operator (::). The scoping is required when using an interface from
a different namespace in an interface definition.
The IDL compiler generates a header file for each interface in the IDL file, and the files are named after
the interface that they contain. The location of these files in the delivery tree is determined by the
namespace, which is SCA.FileReaders.Nastran (shown with the dot notation for description
purposes) in this example. The client code to include these headers is shown below.
#include "SCA/FileReaders/Nastran/SCAIReader.h"
#include "SCA/FileReaders/Nastran/SCAISummary.h"
#include "SCA/FileReaders/Nastran/SCAIExtract.h"
#include "SCA/FileReaders/Nastran/SCAIGrid.h"
The IDL compiler also generates a header file for the types defined in the IDL file. The name of this
header file is the word “Types” appended to the name of the IDL file. The location of this file in the
delivery tree is determined by the namespace as well. The client code to include the type header file
generated from the BDFReader.idl file is shown below.
#include "SCA/FileReaders/Nastran/BDFReaderTypes.h"
As mentioned above, the installation subfolder for the IDL and the generated header files in the delivery
tree are taken directly from the module statements. In this example, the IDL file will be stored in the
idl/SCA/FileReaders/Nastran folder and the generated include files will be stored in the

Main Index
CHAPTER 2 11
Creating Services

include/SCA/FileReaders/Nastran folder in the delivery tree. These are the relative locations that should
be used by all clients of these interfaces.

Constant Declarations
A constant can be defined using a basic or previously defined name of an integer, char, string, enum,
Boolean or floating point type. More details are provided in the Supported Types section. The BDF
reader example does not contain constant declarations.

Type Declarations
struct GridEntry
{
SCAInt32 ID;
SCAReal32 X;
SCAReal32 Y;
SCAReal32 Z;
};
The IDL supports basic (built-in) data types, which are similar to the C++ basic data types; it also
supports more complex types such as enumerations, structures, and arrays. The data types are described
in the Supported Types section. The example defines a GridEntry structure which contains the data for
a single grid point.

Interface Declarations
interface SCAIReader : SCAIService
{
SCAResult importBDF( in SCAString sFileName );
};

interface SCAISummary : SCAIService


{
SCAResult getNumGrid( out SCAInt32 iNumGrid );
SCAResult getNumElem( out SCAInt32 iNumElem );
};

interface SCAIGrid;
interface SCAIExtract : SCAIService
{
SCAResult resetGrid();
SCAResult getNextGrid( out SCAIGrid spGrid );
};

interface SCAIGrid : SCAIService


{
SCAResult getCord( out GridEntry sGrid );
};

Main Index
12 SCA Service Guide
Create a Service

Each interface is declared with an interface statement that contains the definitions of the methods it
implements. The syntax 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 C++ parameters are declared and passed. It also determines the data transfer
direction on an out-of-process call.
A SCA Framework requirement is that each interface inherits from the SCA::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.
When one interface inherits from another interface, it is called interface inheritance. Interface inheritance
only inherits the signatures of the methods in the interface. No implementation is inherited. This means
the implementation class for the service will need to provide all of the implementation for these methods.
Since every interface must inherit from the SCAIService interface, the IDL compiler will generate all
the code that is required for it.
When referencing an interface from a method definition and it is not in the same IDL namespace defined
by the module statements, the external interface must be properly scoped with the scoping operator (::).
The scope syntax and operation is similar to C++. The fully scoped syntax for the SCAIReader
interface is SCA::FileReaders::Nastran::SCAIReader.
As with the scoping rules, forward declarations follow the C++ standard in the IDL file. If there are two
interfaces in the IDL file that reference each other, then a forward declaration must be made for one of
them.
Exceptions can be defined in IDL and added to interface methods to define the expected exceptions the
method will throw. Details are provided in the Supported Types section.

Important Considerations
There are several important points to consider when creating interface definitions.
• The module statement defines an IDL namespace and the locations in the delivery tree where
IDL files and generated header files are stored. It is independent of the other namespaces
described in this document.
• The IDL namespace is visible to clients.
• Include statements for IDL files must always reference the delivery tree folder structure and not
the source tree folder structure.
• Interfaces must always inherit from the SCAIService interface either directly or indirectly.
• Scoping is required when using interfaces from different namespaces.
• Interface names should be prefixed with an identifier, such as SCAI or simply I, for easy and
consistent identification.

Main Index
CHAPTER 2 13
Creating Services

• The methods defined in interfaces should return a SCAResult type or explicitly define
exceptions so it is clear to clients what form errors will take.

Define 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.
SDL files have the extension .sdl and contain the sections listed below. Only one service definition is
allowed in each SDL file. Most of the SDL file is similar to the IDL file. It contains the IFDEF
definition, include statements, module statements, and service statements.

SDL File Sections


IFDEF Definition Recommended
Include Declarations Required
Module Declarations Required
Service Declaration Required
Subservice Declaration Optional

SDL files can contain several keywords for additional configuration that are not shown in the SDL
example below. These keywords include defining the implementation language and if the service will be
a singleton.

Example
In the SDL below, we have defined the NastBDF service that implements the SCAIReader,
SCAISummary, SCAIExtract, and SCAIGrid interfaces.
#ifndef SCA_FILEREADERS_NASTBDF_SDL_INCLUDED
#define SCA_FILEREADERS_NASTBDF_SDL_INCLUDED

#include "SCA/FileReaders/Nastran/NastBDF.idl"

module SCA { module Modules { module FileReaders { module Nastran {


service SCA.FileReaders.Nastran.NastBDF {
interface SCA::FileReaders::Nastran::SCAIReader;
interface SCA::FileReaders::Nastran::SCAISummary;
interface SCA::FileReaders::Nastran::SCAIExtract;
subservice Grid(in SCAInt32 grid, in SCAReal32 x, in SCAReal32 y,
in SCAReal32 z)
{
interface SCA::FileReaders::Nastran::SCAIGrid;
};

Main Index
14 SCA Service Guide
Create a Service

};

}; }; }; };
#endif

IFDEF Definition
#ifndef SCA_FILEREADERS_NASTBDF_SDL_INCLUDED
#define SCA_FILEREADERS_NASTBDF_SDL_INCLUDED
The first two lines of the SDL definition contain the definitions that keep the file from being expanded
more then once during each SDL compilation.

Include Declarations
#include "SCA/FileReaders/Nastran/NastBDF.idl"
Those definitions are followed by the include declarations. These list all the IDL files that define the
interfaces implemented by the service.

Module Declarations
module SCA { module Modules { module FileReaders { module Nastran {

};};};};
The SDL file’s module statements are used to define the implementation code’s namespace, which is a
scoping construct used to organize collections of objects and their visibility in implementation files. The
namespace for the service’s implementation class in this example is
SCA::Modules::FileReaders::Nastran in C++. The general policy for SDL files is that each
service is put in its own separate implementation namespace.
The implementation namespace is not related to other namespaces described in this document, including
the IDL namespace. It will normally be different because the IDL namespace is exposed to clients and
has different requirements than the implementation namespace. The implementation namespace is more
likely to reflect the folder structure in the source tree. There is also no installation information needed for
services because they are delivered in components and not installed by themselves.

Service Declaration
service SCA.FileReaders.Nastran.NastBDF {

};
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 using the dot notation to make sure the service
name is unique from all other service names in the system. The service name in the example is
SCA.FileReaders.Nastran.NastBDF.
The fully qualified service name is not related to the implementation namespace defined by the SDL file’s
module statements. The service name is also not related to the IDL namespace either, even though it may

Main Index
CHAPTER 2 15
Creating Services

be similar to it because they are both visible to clients. The last part of the service name, NastBDF, is
used as the name of the top level class that implements the service.
All classes that implement an interface must be defined as either a service or a subservice in the SDL
file. This is necessary so the IDL compiler can generate the required code to make sure that these objects
follow the rules required by the SCA Framework. These include interface navigation and reference
counting, which is used to automatically delete the objects and unload the components when they are no
longer needed.
The IDL compiler creates the entry class from the service definition. This class is the entry point to the
service so it is mandatory and there is only one per service. An instance of the entry class represents the
service to clients and exists for the entire lifecycle of the service. The getService call returns the
SCAIService interface on an instance of the entry class. All interfaces in the entry class can be directly
accessed by casting from the SCAIService interface.
In the example, the NastBDF service will implement four interfaces that were previously defined in the
IDL file. Three of these interfaces, SCAIReader, SCAISummary, and SCAIExtract are
implemented in the entry class, NastBDF.

Service Summary
• The IDL compiler creates an implementation class for the service definition in the SDL file.
This class is the entry point to the service and is often called the entry class. There is only one
entry class for each service.
• The entry class exists for the entire lifecycle of the service.
• The client can directly access a service by calling the getService method, which returns the
SCAIService interface on an instance of the service’s entry class.
• An entry class cannot take parameters in its constructor.

Subservice Declaration
subservice Grid(in SCAInt32 grid, in SCAReal32 x, in SCAReal32 y,
in SCAReal32 z)

};
The subservice keyword can be optionally added in the SDL file inside the service definition and is used
to define extra implementation classes that have interfaces. The IDL compiler creates extra
implementation classes from the subservice definitions in the SDL file. The interfaces in a subservice
cannot be directly accessed by the client, which is a significant difference between a subservice and a
service. The service must instantiate a subservice and return an interface on the subservice before the
client can access the subservice. There are a variety of situations where one would want to break up the
service’s implementation and interfaces across several classes; some of these situations are described
later in this section.
The methods in the service’s interfaces often take the form of factories for subservices. Because the
service creates subservices as desired, subservices do not necessarily exist for the service’s lifecycle.

Main Index
16 SCA Service Guide
Create a Service

They are created on demand by the service and are destroyed when no more references to them exist. The
service may continue to exist when a subservice is destroyed.
Subservices are useful in several situations. The first situation is when you have multiple interfaces in
your service that the client should not be allowed to cast between because they are not related. Putting
these interfaces into separate subservices prevents the user from casting between them. The client can
only cast between interfaces in a single implementation class, which can be either the entry class or a
subservice class. An example is a Shape factory service that has Circle and Square interfaces, which are
implemented as subservices.
Another situation where subservices are useful is when a service’s interfaces can be broken up into sets
that have distinctive functionality. Putting these interfaces into subservices reduces overhead because the
client only has a reference to a specific subservice instance, which has a smaller memory footprint and
only contains relevant data. It also is cleaned up when the client is finished with it.
In the example, the SCAIGrid interface, which is used to return the data for a single grid, is a subservice
and will be implemented in a separate C++ class, Grid. SCAIGrid instances are returned to the caller with
the getNextGrid factory method in the SCAIExtract interface. We have also defined some extra
parameters that will be passed when each of these Grid instances is constructed. We will see later how
these parameters are used.

Subservice Summary
• The IDL compiler creates an implementation class for each subservice definition in the SDL file.
• Subservices are created on demand by the service and are destroyed when no more references to
them exist.
• A client can only access a subservice through a factory method in the service.
• Subservices can take parameters in their constructors.
• Subservices can be used to encapsulate distinctive functionality in a service.
• Subservices can be used to control a service’s memory overhead.
• Subservices can be used to control the client’s ability to cast between interfaces in a service.

Important Considerations
• The module statement defines an implementation namespace and is not related to the IDL
namespace or the service name.
• The service name uniquely identifies the service and is independent of the IDL namespace and
the implementation namespace, which is defined by the module statements.
• Service objects are retrieved by getService calls while subservices are not.
• Subservices are extra implementation classes with interfaces that can be provided to a client by
methods in a service.

Main Index
CHAPTER 2 17
Creating Services

Define the Component


Once the service has been defined, a component must be defined to contain it. The component is the
language-specific service container generated by the build system. It is a dynamically linked shared
library in C++.
CDL files have the extension .cdl and contain the sections listed below. Only one component definition
is allowed in each CDL file. The component definition does not require module declarations because the
only code generated from the CDL file is the component initialization function, which exists in the global
namespace.

CDL File Sections


IFDEF Definition Recommended
Include Declarations Required
Component Declaration Required

Example
In our example, the BDFReader component contains one service, NastBDF. We have defined the
component with the CDL in the BDFReader.cdl file, which is listed below.
#ifndef MODULES_FILEREADERS_NASTRAN_BDFREADER_CDL_INCLUDED
#define MODULES_FILEREADERS_NASTRAN_BDFREADER_CDL_INCLUDED

#include "NastBDF.sdl"

component SCA.FileReaders.Nastran.BDFReader {
service NastBDF;
};

#endif

IFDEF Definition
#ifndef MODULES_FILEREADERS_NASTRAN_BDFREADER_CDL_INCLUDED
#define MODULES_FILEREADERS_NASTRAN_BDFREADER_CDL_INCLUDED
The first two lines of the CDL definition contain the definitions that keep the file from being expanded
more then once during each CDL compilation.

Include Declarations
#include "NastBDF.sdl"
The include declarations list all the SDL files that define the services contained in the component.

Component Declaration
component SCA.FileReaders.Nastran.BDFReader {

};

Main Index
18 SCA Service Guide
Create a Service

The fully qualified component name is determined directly from the name following the component
statement, which is SCA.FileReaders.Nastran.BDFReader in the example. It is not related to
the IDL namespace, the implementation namespace, or the service name, though it may look similar to
any of them. The short name is BDFReader, and it is used for the name of the generated shared library.
The fully qualified component defines the relative path where the build creates the shared library. The
delivery location and names for the example component are listed below.
Windows
SCA/FileReaders/Nastran/BDFReader.dll

Linux
SCA/FileReaders/Nastran/libBDFReader.so

Generate the Code Files


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 BDFReader service implementation needs to inherit from. The
code for the base class will be generated as part of the build process.
A special command called genskeleton is provided for running the IDL compiler to create these code
file skeletons. The files for executing the genskeleton command are located in the bin folder in the
SCA tools folder. An example command is provided below.
genskeleton NastBDF.sdl
The build system must be setup for the genskeleton command to execute. The compiler will generate
the skeleton code files listed below from the SDL. These files will be created in the current folder.
• NastBDF.h: Header file for the entry class.
• NastBDF.cpp: Implementation file for the entry class.
• Grid.h Header file for the subservice class.
• Grid.cpp Implementation file for the subservice class.
If there are existing versions of these files, they will be generated with the additional extension of “.new”.
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 folder inside of a
properly formatted SCA source tree. This means the folder needs to contain a SConscript file. It does not
have to contain SConopts or SConstruct files if they exist higher in the path hierarchy.
These files are required because a short build step, which uses them, is initially run to install any IDL
files from the current folder in the source tree into the delivery tree so the IDL compiler can access them.
The IDL compiler does not need to be run on the IDL or CDL files. That will be done as part of the normal
build process.

Main Index
CHAPTER 2 19
Creating Services

Implement the Interfaces


The last step of creating a service is to actually implement the interfaces in the code files you have
created. You can add any additional includes, namespaces, or private class members to the header file.
We are going to use an existing BDF reader class, NastReader, and the service will just wrap calls to it.
Calls to the SCA service will be delegated to the NastReader class for processing.

Update the Header Files

NastBDF.h
The first set of changes is to the header file NastBDF.h. The existing NastReader class header file and a
few private data members were included. The using namespace SCA::FileReaders::Nastran
statement was added to simplify the coding. If this were not done, then each interface reference used in
the code would need to include a full scope like SCA::FileReaders::Nastran::SCAIGrid
instead of just using SCAIGrid.
#ifndef SCA_MODULES_FILEREADERS_NASTRAN_NASTBDF_H_INCLUDED
#define SCA_MODULES_FILEREADERS_NASTRAN_NASTBDF_H_INCLUDED

#include "NastBDFBase.h"
#include "bdfread/NastReader.h"
using namespace SCA::FileReaders::Nastran;
namespace SCA { namespace Modules {
namespace FileReaders { namespace Nastran {

class NastBDF : public NastBDFBase


{
public:

// Constructor and Destructor


NastBDF( SCAINastBDFFactoryAccess* factoryAccess );
virtual ~NastBDF();

// Interface methods
SCAResult importBDF ( const SCAString sFileName );
SCAResult getNumGrid ( SCAInt32& iNumGrid );
SCAResult getNumElem ( SCAInt32& iNumElem );
SCAResult resetGrid ();
SCAResult getNextGrid ( SCAIGrid& spGrid );
private:
bool m_bGotReader;
NastReader* m_pReader;
EdbNodePtr m_pNode;
};
}; }; }; };
#endif

Main Index
20 SCA Service Guide
Create a Service

Grid.h
We also need to make a few changes to the header file Grid.h. The Grid class will represent the data for
a single grid point. Therefore, the only required changes are to add a few private variables to hold this
data.
#ifndef SCA_MODULES_FILEREADERS_NASTRAN_GRID_H_INCLUDED
#define SCA_MODULES_FILEREADERS_NASTRAN_GRID_H_INCLUDED
#include "GridBase.h"

using namespace SCA::FileReaders::Nastran;

namespace SCA { namespace Modules {


namespace FileReaders { namespace Nastran {

class Grid : public GridBase


{
public:
// Constructor and Destructor
Grid( SCAINastBDFFactoryAccess* factoryAccess,
const SCAInt32 grid, const SCAReal32 x,
const SCAReal32 y, const SCAReal32 z );
virtual ~Grid();
// Interface methods
SCAResult getCord( GridEntry& sGrid );
private:
SCAInt32 m_iGrid;
SCAReal32 m_fX;
SCAReal32 m_fY;
SCAReal32 m_fZ;
};
}; }; }; };
#endif

Update the Implementation Files

NastBDF.cpp
We can now make changes to the NastBDF.cpp file that will contain the actual implementation of the
service. The first set of changes is to the constructor and the destructor. The constructor needs to initialize
the private data and the destructor needs to delete the instance of the BDF reader to which we are
delegating the calls.
#include "NastBDF.h"
namespace SCA { namespace Modules {
namespace FileReaders { namespace Nastran {

// Constructor

Main Index
CHAPTER 2 21
Creating Services

NastBDF::NastBDF( SCAINastBDFFactoryAccess *factoryAccess)


: NastBDFBase (factoryAccess)
{
// Initialize data
m_bGotReader = false;
}

// Destructor
NastBDF::~NastBDF ()
{
// Delete any allocated reader
if ( m_bGotReader ) delete m_pReader;
}
The SCAIReader interface that we are implementing has one method, importBDF. This method will first
delete any existing instance of the NastReader class. It then instantiates a new copy of the class and uses
its readDeck method to process the desired BDF file.
SCAResult NastBDF::importBDF ( const SCAString sFileName )
{
// Delete any previous reader
if ( m_bGotReader ) delete m_pReader;

// Allocate a reader
m_pReader = new NastReader();
m_bGotReader = true;

// Read the deck


SCABool bStat = m_pReader->readDeck(sFileName.c_str());
if ( !bStat ) return SCAError;

return SCASuccess;
}
The getNumGrid and getNumElem methods in the SCAISummary interface make simple calls to the
NastReader object and return the results.
SCAResult NastBDF::getNumGrid ( SCAInt32& iNumGrid )
{
// Return number of grids
iNumGrid = m_pReader->getNumberNodes();
return SCASuccess;
}
SCAResult NastBDF::getNumElem ( SCAInt32& iNumElem )
{
// Return number of elements
iNumElem = m_pReader->getNumberElements();
return SCASuccess;
}
The implementations of the methods in the SCAIExtract interface are a bit more interesting. The
resetGrid method results in a simple call to the NastReader object. The getNextGrid is a bit more
complex because it needs to loop through the grids in the BDF file using the iterator provided in the

Main Index
22 SCA Service Guide
Create a Service

NastReader class. On each call it needs to create a new instance of the Grid subservice class, initialize it
with the data defining a grid and return a SCAIGrid interface on it to the caller.
This is done using the getGrid method of the ServiceAccess interface. The ServiceAccess interface is
generated by the IDL compiler for each service and is accessed via the m_serviceAccess pointer. It is
described in more detail in the next section. One of these get methods is generated for each subservice
and its parameters are the same as those defined in its definition in the SDL file. These methods return a
SCAIService interface on the newly created subservice, and the compiler automatically casts it to the
SCAIGrid interface that is returned to the caller. The subservices created by these get methods will be
reference counted in the same manner as the NastBDF service and will delete themselves automatically
when all references to them are released.
SCAResult NastBDF::resetGrid ()
{
// Reset the grid pointer to the beginning
m_pNode.resetPtr(m_pReader);
return SCASuccess;
}

SCAResult NastBDF::getNextGrid ( SCAIGrid& spGrid )


{
// Return the next grid
SCAInt32 iID;
SCAReal32 fX;
SCAReal32 fY;
SCAReal32 fZ;
if (!m_pNode)
{
iID = m_pNode->getId();
fX = m_pNode->getX();
fY = m_pNode->getY();
fZ = m_pNode->getZ();
spGrid = m_serviceAccess->getGrid(iID,fX,fY,fZ);
++m_pNode;
return SCASuccess;
}
return SCAError;
}
}; }; }; };

Grid.cpp
The final set of changes is to the Grid object's implementation. Remember that in the SDL file for this
service, we provided a set of arguments in the Grid subservice definition. These arguments show up in
the constructor for the object. All we need to do is save this data.
#include "Grid.h"

namespace SCA { namespace Modules {


namespace FileReaders { namespace Nastran {

// Constructor

Main Index
CHAPTER 2 23
Creating Services

Grid::Grid ( SCAINastBDFFactoryAccess *factoryAccess,


const SCAInt32 grid, const SCAReal32 x,
const SCAReal32 y, const SCAReal32 z )
: GridBase (factoryAccess)
{
m_iGrid = grid;
m_fX = x;
m_fY = y;
m_fZ = z;
}

// Destructor
Grid::~Grid ()
{
}
The Grid object implements one interface, SCAIGrid that has one method, getCord. The
implementation for this routine simply returns the grid’s information in the GridEntry structure
provided in the calling sequence.
SCAResult Grid::getCord( GridEntry& sGrid )
{
sGrid.ID = m_iGrid;
sGrid.X = m_fX;
sGrid.Y = m_fY;
sGrid.Z = m_fZ;
return SCASuccess;
}
}; }; }; };

ServiceAccess Interface
A service can internally create instances of subservices through its ServiceAccess interface. This is done
with the service’s m_serviceAccess pointer and getX methods, where X is the name of a subservice, as
demonstrated in the examples. These are generated by the IDL compiler and return the subservice’s
SCAIService interface. Example code in a service that creates a subservice named MySubService is
shown below.
SCAISomeInterface spMySubService;
spMySubService = m_serviceAccess->getMySubService();
A service’s ServiceAccess interface can also be used by the service to access any required SCA
Framework services. It provides several methods including the get subservice method described above.
The methods include getSCAIService, which gets a SCAIService interface on the current object,
and getService, which gets a new instance of another service.
The ServiceAccess interfaces are internal interfaces since they are only used in the implementation
of the service and are never passed outside of it. Because of this, normal C++ pointers are used to
reference them instead of the smart pointers that normal SCA interfaces use. Another difference is that
internal interfaces do not need to inherit from the SCAIService interface like SCA interfaces do.

Main Index
24 SCA Service Guide
Create a Service

Summary
As a quick review here is the list of files required to create our basic service.
• IDL file with the interface definitions (NastBDF.idl).
• SDL file with the service definition (NastBDF.sdl).
• CDL file with the component definition (BDFReader.cdl).
• Header file for service class (NastBDF.h).
• Implementation file for the service class (NastBDF.cpp).
• Header file for the subservice class (Grid.h).
• Implementation file for the subservice class (Grid.cpp).

Remember that all of the header and implementation files were originally generated by the IDL compiler,
and we only needed to fill in the code for the methods declared in the interfaces. Additional files are
generated by the build system during the build; these will be discussed in the build section.
That is all that is required to create a basic SCA service. In this example, we created the NastBDF service
with the SCAIReader, SCAISummary, SCAIExtract, and SCAIGrid interfaces. The service is
contained in the BDFReader component or shared library.

Steps to Create a Service


The steps for designing and implementing a SCA service are summarized below.
• Design the interfaces the service will support.
• Create the IDL file for the interfaces.
• 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.

Main Index
Ch. 3: Building Components MD Nastran R3 SCA Service Guide

3 Building Components


Build a Component

Main Index
26 SCA Service Guide
Build a Component

Build a Component
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 with Python scripts.
This section provides a basic overview of the SCA build system and describes the steps for building a
SCA service

Configure the Build


The build system has to be configured before it can run successfully. The main parts of configuring the
build are as follows:
• Create the source tree, which contains all the code files to build.
• Create the configuration files in the source tree with proper construction variables.
• Install Python (if it is not already installed).
• Install the SCA Build System (if it is not already installed).
• Install any required third party software.
• Set the system environment variables.

Build Folder Trees


The SCA build systems processes several different folder trees including the source tree, the object tree,
and two delivery trees. Depending on the options the user has set, these folder 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 folder tree containing the source and has no dependency on any source control
software.
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 subfolder within the source tree
with the –u option, the build system will traverse up the folder tree until it finds a SConstruct file to
determine where the root of the source tree is located.

Main Index
CHAPTER 3 27
Building Components

Object
The object folder 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 folder. The location for
the object folder is defined by the SCA_OBJECT construction variable, and it has the same folder
structure as the source tree.

Apps System
The Apps System folder 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 folder 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 folder 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
folder 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 folder 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 folder.

Tools System
The Tools System 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
• xrefcomponent - Component cross reference utility
• xrefinterface - Interface cross reference utility

Main Index
28 SCA Service Guide
Build a Component

This location should be added to the operating system’s path environment variable so the tools can run
correctly.

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 folder structure that is understood by the build
system.

Rules for Finding Common Folders


There is a common set of rules that are used to locate the Apps System, Tools System, and third party
folder trees. These rules allow you to specify the full path to the folder or only the folder name and the
build 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, TOOLS, or a third party package name.

Variable Description
X_SYSTEM Full path to the location of the X folder tree.
X_DIR Folder name of the X tree.
X_BASE Name of the base folder for locating the X_DIR folder
for package X.
SCA_THIRDPARTY_BASE Name of the base folder for locating X_DIR folders
for third party packages only.
SCA_BASE Name of the base folder for locating X_DIR folders
for the APPS, TOOLS, and third party packages.

The following locations can be used to specify any of these construction variable names in order of their
priority.
• Using command line arguments
• The system environment variables
• The SConopts.user option file in the users home folder
• The SConopts option file in the root folder of the source tree

Either the X_SYSTEM or X_DIR variable must be specified. If the X_SYSTEM variable is used, it
already contains the full path to the desired folder and the search is done. However, if the X_DIR variable
is used, the following locations are searched to determine the full path.
• If X_BASE is defined: X_BASE/X_DIR.
• If SCA_BASE is defined: SCA_BASE/X_DIR.
• ../X_DIR relative to the location of the SCons script running.

Main Index
CHAPTER 3 29
Building Components

Locating third party folders follows the same general rules as above, except the ThirdParty folder tree
structure is used. The basic folder hierarchy for the ThirdParty tree is
ThirdParty/Package/Version/OperatingSystem. If the X_SYSTEM folder is specified, it should point to
the specific operating system folder for the desired version of the package. For example, the Qt packaged
on Windows could be located using the following value.
QT_SYSTEM = “C:/Build/ThirdParty/Qt/3.3.2/winnt”
If the X_DIR variable is used, the following locations are searched to determine the full path. The OS
value in these rules is substituted with the appropriate value for the operating system you are running on.
In addition, the SCA_THIRDPARTY_BASE variable is checked before the SCA_BASE variable for
third party packages only.
• If X_BASE is defined: X_BASE/X_DIR/OS.
• If SCA_THIRDPARTY_BASE is defined:
SCA_THIRDPARTY_BASE/ThirdParty/X/X_DIR/OS .
• If SCA_BASE is defined: SCA_BASE/ThirdParty/X/X_DIR/OS.
• ../ThirdParty/X/X_DIR/OS relative to the location of the SCons script running.

Configuration files
There are four main types of configuration files that control the configuration of the build and are
described below. The build system uses a folder hierarchy model so the appropriate configuration files
must be present at the appropriate places in the source tree for the whole folder 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 from the list of the user’s
environment variables. The reason the build system does not propagate the user’s environment settings
is to maintain a standard build environment independent of user settings. There are some operating
system environment variables that are required for the build system to run correctly, but they are not used
within the build itself.

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 and environment routines.
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 should not be done in this
file. Only new construction variable names can be declared. Values for these variables should be set in
the normal manner in the SConopts or SConopts.user files or on the command line.

Main Index
30 SCA Service Guide
Build a Component

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 up compiler includes. Use CCFLAGS instead of CPPPATH for
# Boost.threads include folders because we don't want SCons to
# scan these for dependencies
#
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 ))
#
# Third party configuration for LibXML. Sets libs for linking.
#
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)
ThirdPartyPackage('libxml', 'libxml2 support', IncludeLibXML2)

#======================================================================

import SCASCons.Setup
SCASCons.Setup.Setup()

SConopts
This file is in the root of the source tree and contains build options 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 system folder versions,
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 versions of the SCA Framework or tools. 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 sys
import SCASCons

Main Index
CHAPTER 3 31
Building Components

# Apps System folder location relative to APPS_BASE.


APPS_DIR = "MyComponent-015"
# Third party option for LibXML.
if SCASCons.MACHINE == 'WINNT':
LIBXML_DIR = "2-2.6.27-2"
else:
LIBXML_DIR = "2-2.6.27"
The APPS_DIR must be defined because it is appended to the APPS_BASE variable to determine the
location of the APPS_SYSTEM folder. If the SConopts.user file does not exist, the SCA_OBJECT
variable needs to be defined in this file as it is required by the build system.

SConscript
One of these configuration files must exist in each folder that is to be processed. If a folder does not have
a SConscript file, then processing will stop at that point in the folder tree and all subfolders will be
ignored as well. This small file can also contain special build instructions for the files in its folder. 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 folder 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.
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
packager 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.

Main Index
32 SCA Service Guide
Build a Component

import sys

if sys.platform == “win32”:
# Object folder
SCA_OBJECT = “C:/builds/nastran”
# Apps Local folder (optional)
APPS_LOCAL = “C:/builds/Apps”
else:
# Object folder
SCA_OBJECT = “/builds/nastran”
# Apps Local folder (optional)
APPS_LOCAL = “/builds/Apps”
Normally you should only define the locations of the SCA_OBJECT and optionally the APPS_LOCAL
folder trees in your SConopts.user file. The APPS_SYSTEM folder is defined in the SConopts file, which
resides in the root of the source tree. If APPS_LOCAL folder is not defined, then the default location is
used and is under the object folder.

Setting up the Build System

Environment Variables
Add the Tools System folder 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:\builds\Tools-V3COMP-004.
Your home folder 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.
Create the TMP environment variable on Windows to define a folder for temporary files if it has not
already been defined. This is required by the Windows Linker for temporary storage.

Windows Systems
The SCA IDL compiler invokes a Microsoft CMD.EXE shell internally. This invocation will fail if the
current working folder is a UNC style path name due to a restriction in the command shell. Map the
source folder to a drive letter or follow the instructions in Microsoft Knowledge Base article 156272 to
resolve the issue.

Run the Build


Once the build system has been setup, you are ready to build your component. The first thing to do is
open a command window and change folders to the root folder of the source tree or in the folder where
the component is defined. If you are in the root folder of the source tree and want to build everything you
can run the command below with no arguments.
scons
The example source code is in the Modules/FileReaders/Nastran folder. The command below is then used
to build the BDFReader component from a subfolder in the source tree.

Main Index
CHAPTER 3 33
Building Components

scons -u BDFReader
The BDFReader argument is the name of the component that we want to build. If the component name,
or target, is provided, only this component will be built. If no target is provided, then all of the
components in the source tree will be built.
The –u argument is required if you are not in the root folder of the source tree. It tells SCons to travel
up the folder tree to locate the folder where the SConstruct file is located to determine the root of the
source tree.

Build Tasks
The build system will perform the steps below to build the BDF reader component. The build is run on
Windows for this example.
• The IDL compiler processes the IDL file, generates header files for each interface, and stores
them in the APPS_LOCAL tree.
Header files location: C:/build/Apps/include/SCA/FileReaders/Nastran
IDL file location: C:/build/Apps/idl/SCA/FileReaders/Nastran
• 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 folder. Object files
location: C:/build/WINNT_SCAVERT1_DEBUG/Modules/FileReaders/Nastran
• The IDL compiler processes the CDL file and generates the required initialization function for
the component. This file will also be stored in object folder.
• The build system compiles and links all of the code created in the previous steps as well as the
source in the source folder; it then stores the object files in the object folder. 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 folder for future use: C:/build
/Apps/Win32/bin/SCA/FileReaders/Nastran
• The build system adds an entry to the Service catalog for each service that is built.
The service catalog’s path is \res\SCAServiceCatalog.xml in the Apps Local folder. Service
catalog path: C:/build/Apps/res/SCAServiceCatalog.xml

Build Delivery
As described above, the build system puts the completed component and output files in subfolders
located in the Apps Local folder. In general, the subfolders have a folder hierarchy determined by the
IDL and CDL namespaces, which are defined by the module statements in the IDL and CDL files. The
folders of interest contained in the Apps Local folder are described in the following sections.
The IDL namespace for the BDF reader is SCA::FileReaders::Nastran and the path for the
Apps Local folder is C:\build\Apps.

Main Index
34 SCA Service Guide
Build a Component

IDL
The IDL files for all the built components are contained in a subfolder located in the idl folder. The
subfolder’s path is determined by appending the IDL namespace to the APPS_LOCAL\idl folder, which
is listed below for the example.
C:\build\Apps\idl\SCA\FileReaders\Nastran

Include
The header files for all the built components are contained in a subfolder located in the include folder.
The subfolder’s path is determined by appending the IDL namespace to the APPS_LOCAL\include
folder, which is listed below for the example.
C:\build\Apps\include\SCA\FileReaders\Nastran

<Operating System>
The dynamically linked libraries are contained in a subfolder located in folders denoted by operating
system. For example, the .dll built for 32-bit Windows is located in a subfolder named win32. The
subfolder’s path is determined by appending the CDL namespace to the APPS_LOCAL\<operating
system>\bin folder, which is listed below for the example.
C:\build\Apps\Win32\bin\SCA\FileReaders\Nastran

Main Index
Ch. 4: Using Services MD Nastran R3 SCA Service Guide

4 Using Services


Use a Service

Main Index
36 SCA Service Guide
Use a Service

Use a Service
The basic procedure for using a service is to get an instance of a service and then use the correct interface
to access the desired functionality. The steps vary slightly depending if it is a SCA service or an
application (code not in a service) that is using the service.
The items listed below are required when using a SCA service.
• SCA Framework
• Dynamic linked shared library for the component containing the service
• IDL files which describe the interfaces supported by the services in the component
• Language-specific definition files needed by client code to access the interfaces (header files in
C++).
• SCAServiceCatalog entries for the services in the component
• Any resource files required by the services in the component

Using a SCA Service from another SCA Service


Basic Procedure
• Retrieve a service using the m_serviceAccess member.
• Use the interface that was returned to access methods in that interface.
• Cast to new interface as necessary and repeat step 2.

Detailed Description
The only way to load a SCA service from your SCA service is using the SCAIServiceProvider
interface. This interface provides a getService method that is used to load services.
Each SCA service is provided a set of helper methods that it can use to access this interface. These
methods are accessed through the service’s m_serviceAccess pointer and include several
overloaded getService methods that can be called. All of these methods use the copy of the
SCAIServiceProvider interface that was provided to the service to do the actual loading of the
requested services. These methods are listed below.
SCAIService getService( const SCAString name, const SCAString
attributes );

SCAIService getService( const SCAString name, const SCAString


attributes, SCAResult& rstatus );

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


If you need to write code that is shared by several services then it needs to use the appropriate
SCAIServiceProvider interface directly. This is easily done because each m_serviceAccess
implementation also provides a method to access this interface, which is listed below. Each service can

Main Index
CHAPTER 4 37
Using Services

use this method to get access to the SCAIServiceProvider interface and make it available to the
shared code that needs to load the services.
SCAIServiceProvider getSCAIServiceProvider();
It is important to understand that the correct copy of the SCAIService interface used to load services
depends on whether the code is part of an application or part of a SCA service. Code that is part of a SCA
service should always use the SCAIServiceProvider interface that was provided to the service and
accessed through the methods in m_serviceAccess. It should never use any global copy that an
application may have saved.

Examples

Basic
The C++ example shown below is code in a service that loads and uses another service. The basic steps
are similar when using a service from a non-SCA application; however, make sure that you use the
proper procedure based on the location of the calling code.
// Include the header file defining the interface.
#include "SCA/Example/Service/SCAIExample.h"

// Provide namespace scoping.


using namespace SCA::Example::Service;

// Get an instance of a service to use.


SCAIService spService;
spService = m_serviceAccess
->getService("SCA.Example.Service.MyService");

// Cast to the desired interface and call interface methods.


SCAIExample spExample;
spExample = static_cast<SCAIExample>(spService);
SCAResult rStatus = spExample->doSomething();
In C++, you can optimize the code to automatically cast the interface returned from getService to
SCAIExample as shown below.
// Set the type of the l-value to the desired interface.
SCAIExample spExample;
spExample = m_serviceAccess
->getService("SCA.Example.Service.MyService");

BDF Reader
To demonstrate how SCA services can be used, we will build another service named NastBDFTest that
uses the BDF Reader service we just completed. We will also use one of the facilities provided by the
SCA Framework to help with the testing of SCA services, which is the SCAIBatchTest interface. To
use this facility, we need to perform the following steps.
• Build a SCA service that implements the SCAIBatchTest interface.

Main Index
38 SCA Service Guide
Use a Service

• Run the test with the scautil utility.

SCAIBatchTest Interface
The SCAIBatchTest interface is provided with the SCA Framework to facilitate a simple method to
test SCA services. The interface contains one method called runBatchTest, which is called with a
sequence of arguments for the test. We are going to use the arguments in this example to pass the name
of the BDF file that we wish to read. Note that the SCAIBatchTest interface is defined in the
SCA::Framework namespace; we will need this information when creating the SDL file for this
service. The IDL for the SCAIBatchTest is shown below:
#ifndef BATCHTEST_IDL
#define BATCHTEST_IDL
#include "SCA/Service.idl"

module SCA { module Framework {

interface SCAIBatchTest : SCAIService


{
SCAResult runBatchTest( in SCAStringSequence args );
};
}; };
#endif

Defining the NastBDFTest Service


Once again, the first step in defining a SCA service is to create the IDL, SDL and CDL files for the
service.
In this case, we do not need to create an IDL file since the SCA Framework already provides the IDL file
for the only interface this service will implement.
The SDL file, NastBDFTest.sdl, is pretty simple since we will not need any subservices. Note that we
still need to include the IDL file for the SCAIBatchTest interface from the appropriate location provided
by the SCA Framework since we are implementing this interface.
#ifndef SCA_FILEREADERS_NASTRAN_BDFTEST_SDL_INCLUDED
#define SCA_FILEREADERS_NASTRAN_BDFTEST_SDL_INCLUDED

#include "SCA/Framework/BatchTest.idl"

module SCA { module Modules { module FileReaders { module Nastran {

service SCA.FileReaders.Nastran.NastBDFTest
{
interface SCA::Framework::SCAIBatchTest;
};
}; }; }; };
#endif
When designing the NastBDFTest service, we have two choices for the CDL file. If we choose to put the
service in a separate shared library we would need to create a new CDL file for the component. In this

Main Index
CHAPTER 4 39
Using Services

case, we would also need to put the code for the service in a separate folder from the NastBDF service
because two different components cannot be in the same folder. Instead, we are going to just add the new
NastBDFTest service to the existing BDFReader component. This way we can have all of the required
code for both services and the component in the same directory. We need to modify the CDL file
BDFReader.cdl that we created earlier to add the new service to the existing component.
#ifndef MODULES_FILEREADERS_NASTRAN_BDFREADER_CDL_INCLUDED
#define MODULES_FILEREADERS_NASTRAN_BDFREADER_CDL_INCLUDED

#include "NastBDF.sdl"
#include "NastBDFTest.sdl"
component SCA.FileReaders.Nastran.BDFReader
{
service NastBDF;
service NastBDFTest;
};
#endif

Implementing the NastBDFTest Service


The implementation for the NastBDFTest service is straightforward. After we have coded the SDL and
CDL files, we once again use the genskeleton command to create the skeleton implementation code
for the service.
genskeleton NastBDFTest.sdl
We are then ready to start coding. The header file, NastBDFTest.h, generated by the IDL compiler
contains all that is required and no additional modifications are necessary. The header file is shown
below.
#ifndef SCA_MODULES_FILEREADERS_NASTRAN_NASTBDFTEST_H_INCLUDED
#define SCA_MODULES_FILEREADERS_NASTRAN_NASTBDFTEST_H_INCLUDED

#include "NastBDFTestBase.h"

namespace SCA { namespace Modules {


namespace FileReaders { namespace Nastran {

class NastBDFTest : public NastBDFTestBase


{
public:
// Constructor and Destructor
NastBDFTest( SCAINastBDFTestFactoryAccess* factoryAccess );
virtual ~NastBDFTest();

// Interface methods
SCAResult runBatchTest(const SCAStringSequence& args);
};
}; }; }; };
#endif

Main Index
40 SCA Service Guide
Use a Service

We need to update the implementation file, NastBDFTest.cpp, which will be using the BDF Reader
service. First we need to add some includes and definitions, which are shown highlighted in the example
provided below. Notice that we must include the interface definition header files which define the
interfaces from the BDF Reader service that we are using. Remember that the correct relative path in the
delivery tree must be used for each interface header file and not its location in the source tree. We have
also included a using namespace SCA::FileReaders::Nastran statement to simplify the coding.
If this were not done, then each interface reference used would need to be fully scoped like
SCA::FileReaders::Nastran::SCAIReader instead of just SCAIReader.
#include "NastBDFTest.h"
#include "SCA/FileReaders/Nastran/SCAIGrid.h"
#include "SCA/FileReaders/Nastran/SCAIReader.h"
#include "SCA/FileReaders/Nastran/SCAIExtract.h"
#include "SCA/FileReaders/Nastran/SCAISummary.h"

using namespace SCA::FileReaders::Nastran;


using namespace std;

namespace SCA { namespace Modules {


namespace FileReaders { namespace Nastran {

// Constructor
NastBDFTest::NastBDFTest(SCAINastBDFTestFactoryAccess *factoryAccess)
: NastBDFTestBase (factoryAccess)
{
}

// Destructor
NastBDFTest::~NastBDFTest ()
{
}
Next we define several interface smart pointers that will be needed later.
// Smart pointers for the required interfaces
SCAIService spService;
SCAIReader spReader;
SCAISummary spSummary;
SCAIExtract spExtract;
SCAIGrid spGrid;
The next step is to get an instance of the service using the getService method provided in the
ServiceAccess interface. This interface is referenced through the m_serviceAccess pointer
provided in the base classes generated by the IDL compiler. The method will instantiate a new instance
of the NastBDF class and return a SCAIService interface on the instance to the caller.
// Get an instance of the NastBDF service
spService = m_serviceAccess->getService(
"SCA.FileReaders.Nastran.NastBDF" );

if( !spService ) return SCAResult( errorCode );

Main Index
CHAPTER 4 41
Using Services

We can now cast from the SCAIService interface returned from the getService call to any of the
interfaces supported by the service. The example below shows how this is done for the SCAIReader
interface. Notice how the casting operation has been enclosed in a C++ try/catch block. This is because
the cast can fail if the underlying implementation class does not implement the requested interface,
which causes a C++ exception to be thrown. It is always a good practice to catch these exceptions and
do the appropriate thing. In this case, we are just going to re-throw another exception with an appropriate
message.
The importBDF method in the SCAIReader interface is then used to process the BDF file. We just
use an argument passed to us as the input for this method.
// Cast to the SCAIReader interface and read the deck
try
{
spReader = static_cast<SCAIReader>(spService);
}
catch(...)
{
throw SCAString("Cast to SCAIReader failed");
}
SCAResult rStatus = spReader->importBDF(args[0]);
if ( rStatus ) return SCAError;
We can now cast to the SCAISummary interface and obtain a summary of the file just processed. Notice
that the cast to the new interface is from the SCAIReader interface smart pointer. It could just as easily
have used the SCAIService smart pointer. It is valid to cast from any interface to any other interface
as long as the two interfaces are implemented in the same implementation class.
// Cast to the SCAISummary interface and get a summary of the deck.
try
{
spSummary = static_cast<SCAISummary>(spReader);
}
catch(...)
{
throw SCAString("Cast to SCAISummary failed");
}
SCAInt32 iNumGrid;
spSummary->getNumGrid(iNumGrid);
cout << "Number of grids in deck is " << iNumGrid << endl;

SCAInt32 iNumElem;
spSummary->getNumElem(iNumElem);
cout << "Number of elements in deck is " << iNumElem << endl;
The SCAIExtract interface is then used to extract the actual data about every grid point.
// Cast to the SCAIExtract interface and get each grid
try
{
spExtract = static_cast<SCAIExtract>(spSummary);
}
catch(...)

Main Index
42 SCA Service Guide
Use a Service

{
throw SCAString("Cast to SCAIExtract failed");
}
spExtract->resetGrid();
while ( spExtract->getNextGrid(spGrid) == SCASuccess )
{
GridEntry sGrid;
spGrid->getCord(sGrid);
cout << "Grid " << setw(5) << sGrid.ID << ":"
<< " X=" << setw(6) << sGrid.X
<< " Y=" << setw(6) << sGrid.Y
<< " Z=" << setw(6) << sGrid.Z << endl;
spGrid = NULLSP;
}
The getNextGrid call in the example above shows how a method can return an interface, SCAIGrid,
in an argument of the call. If you remember from the implementation of the BDF Reader service, the
SCAIGrid interface is actually implemented by a different class from the other interfaces in the service
because it was defined as a subservice and a separate instance is created for each grid. This
implementation detail is transparent to the client. All the client knows is that it receives a valid
SCAIGrid interface, so the actual class that implements it is irrelevant. We don’t need to worry about
deleting these subservices because they are reference counted and will be deleted automatically when no
longer needed.
In the example above, we have assigned the NULLSP to the smart pointer when we were done using it
on each pass through the loop. You must use NULLSP in this assignment, a value of NULL or 0 will not
compile. This assignment will trigger a call to reduce the reference count on the instance of the class
implementing the interface, which will then automatically delete itself when the count reaches zero. It
can also trigger an unloading of the service's shared library when it is no longer required, but that will
not happen in this case because the other interface smart pointers still reference objects in the same
library. It is not required that you do this assignment explicitly because the smart pointers will handle this
automatically when they are reassigned at the top of the loop, or when the variable goes out of scope. It
is still a good practice to explicitly do the release as soon as possible to free up any resources that are no
longer need.
After we have looped through the grids, we can then release the existing smart pointers and return.
// Clean up to trigger unload of component
spService = NULLSP;
spReader = NULLSP;
spSummary = NULLSP;
spExtract = NULLSP;
return SCASuccess;

Building the NastBDFTest Service


We can now use the same build command as before to build the new code.
scons -u BDFReader
This will compile any new or changed routines and create a new copy of the BDFReader component
shared library.

Main Index
CHAPTER 4 43
Using Services

Testing the Service


To run a test on the new service, we use the scautil command provided with the SCA Framework.
scautil -test SCA.FileReaders.Nastran.NastBDFTest tiny.dat
This test will do the following:
• Initialize the SCA Framework
• Get an instance of the SCA.FileReaders.Nastran.NastBDFTest service
• Cast to the SCAIBatchTest interface.
• Call the runBatchTest method on this interface passing it the argument “tiny.dat”.

It is also possible in the SConscript file to have this test run as part of the build process and to then
compare the output to an archived version. This allows you to do regression tests as part of the normal
builds.

Summary
This completes the example using the BDF Reader and BDF Reader Test services. In this example, we
built two services, NastBDF and NastBDFTest, which were contained in a single SCA component or
shared library. The NastBDFTest service used the testing interface provided by the SCA Framework to
test the NastBDF service.
The following source files were used in the example:
• Bdfread Subfolder with existing NastReader class files
• NastBDF.idl IDL for the NastBDF interface definitions
• NastBDF.sdl SDL for the NastBDF service definition
• NastBDF.h Header for NastBDF entry class
• NastBDF.cpp Implementation for NastBDF entry class
• Grid.h Header for Grid subservice class
• Grid.cpp Implementation for Grid subservice class
• NastBDFTest.sdl SDL file with the NastBDFTest service definition
• NastBDFTest.h Header for NastBDFTest entry class
• NastBDFTest.cpp Implementation for NastBDFTest entry class
• SConscript SCA build system control
• tiny.dat Sample Nastran BDF file
• BDFReader.cdl CDL for the BDFReader component definition

Main Index
44 SCA Service Guide
Use a Service

Using a SCA Service from an Application


Basic Procedure
• Initialize the SCA kernel.
• Retrieve the service using the global getSCAService function defined in SCAKernel.h.
• Use the interface that was returned to access methods in that interface.
• Cast to new interface as necessary and repeat step 3.

Detailed Description
Non-SCA applications use the SCAIServiceProvider interface to load SCA services just as SCA
services do. The difference is that the application must initialize the SCA kernel and use the interface
provided by the global getSCAService function, which is defined in SCAKernel.h.
The SCA Framework provides a set of utility functions that an application can use to make these actions
easier. These functions are accessed using the SCAKernel.h include file mentioned above, and a partial
listing of the functions is provided below. For complete details on these methods consult the actual header
file.
SCA::SCAInt32 initializeSCAKernel( SCA::SCAString& errmsg,
SCA::SCAInt32 verbose);

SCA::SCAInt32 getSCAService( const SCA::SCAString name,


SCA::SCAIService& spService, SCA::SCAString& errmsg );

SCA::SCAInt32 terminateSCAKernel( );
In addition to including the SCAKernel.h header file in the application’s source code, the application must
be statically linked with the SCAKernel and SCAKernelUtil shared libraries. This enables the application
to use the SCA Framework and components. The libraries for specific components do not need to be
linked as they are accessed through the SCA Framework.
The initializeSCAKernel function calls the internal initialization method and saves the provided
SCAIServiceProvider interface in a global variable. The getSCAService function then uses
this saved copy of the interface to load the requested services.
For the application to use SCA services, the loader path must be set to the location of the SCAKernel
library, and the SCA_SERVICE_CATALOG environment variable must be defined with the service
catalog’s path, which is \res\SCAServiceCatalog.xml in the Apps Local folder. This is
C:/build/Apps/res/SCAServiceCatalog.xml in the example.

Examples
An example program that demonstrates how to initialize the kernel and call a service is shown below.
Note that the program must be linked against the SCAKernel and SCAKernelUtil shared libraries.
#include <iostream>
using namespace std;

Main Index
CHAPTER 4 45
Using Services

#include "SCA/SCAKernel.h"
#include "SCA/Framework/SCAIKernelInfo.h"
using namespace SCA;
using namespace SCA::Framework;

int main(int argc, char** argv)


{
SCAInt32 ierr;
SCAString errmsg;
SCAIService spService;

//Initialize the kernel


ierr = initializeSCAKernel(errmsg,1);
if ( ierr ) {
cout << "-> Initialization of the kernel failed"
<< endl << errmsg << endl;
return 1;
}

//Load a service
ierr =
getSCAService("SCA.Example.Service.MyService",spService,errmsg);
if ( ierr ) {
cout << "-> Load failed" << endl << errmsg << endl;
return 1;
}

// Cast to the desired interface and call interface methods.


SCAIExample spExample;
spExample = m_serviceAccess
->getService("SCA.Example.Service.MyService");
SCAResult rStatus = spExample->doSomething();
return 0;
}

Using a SCA Service from a Python Script


The Python script procedure is similar to the procedure for calling a service from another service. The
only difference is that the getService call is provided by the SCA module, which must be imported
in the script. Note that Python support is only available on Windows and Linux platforms.

Examples
The Python example below shows how to use a service from a Python script.
# Import the SCA module which provides the service functionality.
import SCA
# Get an instance of a service to use.
spService = SCA.getService ("SCA.Example.Service.MyService")

Main Index
46 SCA Service Guide
Use a Service

# Get the desired interface and call interface methods.


(ret, spExample) =
spService.getInterface("SCA.Example.Service.SCAIExample")
err = spExample.doSomething()
Because Python is a type-less language, you must specifically make the getInterface call normally.
However, you can specify the interface you want in the getService call so you don’t have to call
getInterface; this is useful when you only want to use one of the service’s interfaces. If you want
to use multiple interfaces on a service, you must get the SCAIService interface to call
getInterface.
# Specify the interface in the getService call.
spExample = SCA.getService(“SCA.Example.Service.MyService”,
“SCA.Example.Service.SCAIExample”)

Summary
A SCA service can be used by applications, scripts, and other SCA services as we have seen. A service
is accessed with a simple procedure that varies slightly depending on the location of the client code. The
client code must be in a language that is supported by the SCA Framework.
Several things to remember when using SCA services are listed below.
• An application has several requirements when using the SCA Framework that scripts and other
services do not have.
• The application must include the language-specific file defining the framework’s utility
functions (SCAKernel.h for C++).
• The application must be statically linked with the SCAKernel and SCAKernelUtil shared
libraries.
• The SCA_SERVICE_CATALOG environment variable must be defined with the service
catalog’s path, which is \res\SCAServiceCatalog.xml in the Apps Local folder.
• The SCAKernel library’s path must be included in the library loader path or the global path
environment variable.
• The application must explicitly initialize the SCA Framework before calling services.
• The client code in SCA services and applications must include language-specific interface
definition files (header files in C++) for the interfaces it uses. Scripts only need to import the
SCA module.
• When retrieving a service, the client code must use the appropriate getService method
depending if it is in an application or a service.

Main Index
Ch. 5: Supported Data Types MD Nastran R3 SCA Service Guide

5 Supported Data Types


Supported Types

Main Index
48 SCA Service Guide
Supported Types

Supported Types
This section defines the data types that are available for use when designing SCA interfaces. Only data
types that are fully described in the IDL definitions are allowed. This rule is required because the data
must be able to be passed to a remote machine and may require data conversion to be used. This means
pointers are not allowed because the memory location they point to is only valid within the same process;
it cannot be marshaled because the length and content of the data are not defined. Also C++ class
references are not allowed because the contents of these classes cannot be defined in the IDL definitions.
It is important to understand that the limitation of using these data types is only enforced at the interface
level. Only the data types supported in the IDL can be passed across an interface. However, the developer
can use any types in the internal implementation of an interface. These include pointers, C++ classes, and
STL containers. If any of this data needs to be passed out of the service in an interface, it must be
convertible to one of the IDL supported data types.

Basic Types
The basic data types below can be passed directly in an interface method or be used to construct more
complex data types. The numeric types are always the size indicated; it does not matter if they are
compiled and run on a 32-bit system or a 64-bit system.

Name Type
SCAInt8 8-bit signed integer
SCAUInt8 8-bit unsigned integer
SCAInt16 16-bit signed integer
SCAUInt16 16-bit unsigned integer
SCAInt32 32-bit signed integer
SCAUInt32 32-bit unsigned integer
SCAInt64 64-bit signed integer
SCAUInt64 64-bit unsigned integer
SCAReal32 32-bit float
SCAReal64 64-bit float
SCABool Boolean
SCAChar Character
SCAWChar Wide character
SCAString String
SCAWString Wide string
SCAAny Variant
SCAResult Error code structure

Main Index
CHAPTER 5 49
Supported Data Types

The SCAAny is a special type that can be used to hold a single value of any type that can be defined in
IDL. This is useful when required to pass data where the type is not known until runtime.
In C++, the SCAString and SCAChar types do not use a defined encoding. This means that no
assumptions can be made as to how characters outside the ASCII range 0 – 127 are stored. This may
become a problem when exchanging strings with 3rd-party or operating system libraries. To store texts
that may contain European or Asian characters, such as filenames, dialog messages, and user text input,
it is recommended to use SCAWString and SCAWChar. Their encoding is not explicitly defined either,
but it can be assumed that text can be safely exchanged with 3rd-party and OS libraries.

Constant Types
Constant values can also be defined in IDL using the const keyword. Constant values can only be
defined for the basic types and enumerated types. Constant values for more complex types like arrays,
sequences and structures are not supported. Examples are shown below.
const SCAInt32 longConstant = 100;
const SCAChar charConstant = 'A';
const SCAWChar wcharConstant = L'A';
const SCAString stringConstant = ”string value”;
const SCAWString wstringConstant = L”string value”;
const myEnum enumConstant = ENUMVALUE2;

User Defined Types


Service developers can construct more complex data types from the basic IDL types or from other
constructed types. The different user defined types are arrays, sequences, enumerations, and structures.

Typedef
Some of the user defined types must use the IDL typedef keyword in their definition. The typedef
keyword can be used to create a new name for a type as shown below. It is similar to the C++ typedef
keyword.
typedef SCAInt32 YearType;

Enumeration
The enumeration type is similar to the C++ enum and can be defined in the IDL as shown below.
enum myEnum
{
EnumValue1,
EnumValue2,
EnumValue3
};

Main Index
50 SCA Service Guide
Supported Types

Fixed-Length Array

Fixed-Length Array Characteristics


Memory Management Automatically by Compiler
Type Definition Compile-time (IDL)
Length Definition Compile-time (IDL)
Length Change No
When to Use Using fixed-length collection of small amount of
data

Fixed-length arrays of data can be used in interfaces as long as the length of the data is a constant and
defined in the IDL. These arrays must be defined with a typedef statement and the new type,
myArray in this example, can then be used anywhere else in the IDL.
typedef SCAInt32 myArray[10];
Normally fixed-length arrays are used to store small amounts of data. Fixed-length arrays may be defined
in the IDL as members in a structure definition. Arrays of rank 1 or rank 2 are supported.
// Define fixed-length array types
typedef SCA::SCAInt32 Array1[2];
typedef SCA::SCAInt32 Array2[2][2];

// Define structure that contains fixed-length arrays


struct MyStruct {
SCA::SCAInt32 data1[2];
Array1 data2;
SCA::SCAInt32 data3[2][2];
Array2 data4;
};
Fixed-length arrays are used in C++ the same way C arrays are used.
// Using rank 1 array
Array1 val1;
val1[0] = 1;

// Using rank 2 array


Array2 val2;
val2[0][0] = 1;

// Using array in structure


MyStruct struct;
struct.data1[0] = 1;
struct.data2[0] = 1;
struct.data3[0][0] = 1;
struct.data4[0][0] = 1;

Main Index
CHAPTER 5 51
Supported Data Types

Size
In addition to the standard C array operations, fixed-length arrays also have a size method which
allows you to determine the size of the array. The definition for this is generated by the IDL compiler.
// Using size member for rank 1 array
for(int i=0,i<val1.size();i++)
val1[i] = i;
// Using size members for rank 2 array
for(int i=0,i<val2.size1();i++)
for(int j=0,j<val2.size2();j++)
val2[i][j] = i;

Dynamic Array

Dynamic Array Characteristics


Memory Management Manually by User
Type Definition Compile-time or Run-time
Length Definition Run-time
Length Change No
When to Use Passing fixed-length collection of large amount of
data through interfaces

Dynamic arrays are similar to fixed-length arrays except the user is responsible for managing the
memory they use instead of the compiler. Because dynamic arrays perform no internal memory
management, operations that would result in an expansion or contraction are not supported. Only simple
operations like those available with fixed-length arrays are available. Like other types of arrays
supported in the SCA Framework, dynamic arrays may hold any type of data that can be defined in IDL.
Dynamic arrays are defined in IDL in a similar manner to fixed-length arrays except the actual array sizes
are left blank. Dynamic arrays may be defined in the IDL as separate data types or as members in a
structure definition. Arrays of rank 1 or rank 2 are supported.
// Define dynamic array types
typedef SCA::SCAInt32 Array1[];
typedef SCA::SCAInt32 Array2[][];

// Define structure that contains dynamic arrays


struct MyStruct {
SCA::SCAInt32 data1[];
Array1 data2;
SCA::SCAInt32 data3[][];
Array2 data4;
};
Dynamic arrays are used in C++ the same way C arrays are used, except the programmer must provide
and manage the memory used by the array when it is allocated. Because the programmer is providing the

Main Index
52 SCA Service Guide
Supported Types

memory, it is possible to initialize a dynamic array on top of existing initialized data. The dynamic array
can be used as a wrapper on existing data, allowing it to be passed across interface boundaries without
making any copies of the data. This could be very important if large amounts of data need to be passed.
If either fixed-length arrays or sequences are used for this purpose, at least one copy of the data must be
made.
// Using rank 1 array
SCAInt32* mem1 = new SCAInt32[10];
Array1 val1(mem1,10);
val1[0] = 1;

// Using rank 2 array


SCAInt32* mem2 = new SCAInt32[10];
Array2 val2(mem2,2,5);
val2[0][0] = 1;

Size
Dynamic arrays provide size methods similar to fixed-length arrays.
// Using rank 1 array
SCAInt32* mem1 = new SCAInt32[10];
Array1 val1(mem1,10);
for(int i=0,i<val1.size();i++)
val1[i] = i;

// Using rank 2 array


SCAInt32* mem2 = new SCAInt32[10];
Array2 val2(mem2,2,5);
for(int i=0,i<val2.size1();i++)
for(int j=0,j<val2.size2();j++)
val2[i][j] = i;

Set
It is also possible to instantiate a dynamic array without any data. In this case the set method must be
used to initialize the array before it can be used. The empty method is provided to determine if an
instance of an array has been initialized.
// Using rank 1 array
Array1 val1;
cout << "Empty=" << val1.empty() << endl; (Array is empty so value
is "true")
SCAInt32* mem1 = new SCAInt32[10];
val1.set(mem1,10);
cout << "Empty=" << val1.empty() << endl; (Array is initialized so
value is "false")
// Using rank 2 array
Array2 val2;
cout << "Empty=" << val2.empty() << endl; (Array is empty so value
is "true")
SCAInt32* mem2 = new SCAInt32[10];

Main Index
CHAPTER 5 53
Supported Data Types

val2.set(mem2,2,5);
cout << "Empty=" << val2.empty() << endl; (Array is initialized so
value is "false")
Initializing a dynamic array at a later time is very useful if the array is a member of a structure. This is
because it is difficult to provide initial values in a structure for complex member types.
// Using dynamic array in structure
MyStruct struct;
SCAInt32* mems1 = new SCAInt32[10];
struct.data1.set(mems1,10);
struct.data1[0] = 1;
SCAInt32* mems2 = new SCAInt32[10];
struct.data2.set(mems2,10);
struct.data2[0] = 1;
SCAInt32* mems3 = new SCAInt32[10];
struct.data3.set(mems3,10);
struct.data3[0][0] = 1;
SCAInt32* mems4 = new SCAInt32[10];
struct.data4.set(mems4,10);
struct.data4[0][0] = 1;
If you use the set method on a dynamic array that already contains data, its reference to the old data is
removed and the new data is added. Since the dynamic array does no memory management, the old data
is not deleted. It is the responsibility of the programmer to make sure the data gets deleted.
Dynamic arrays are also referenced counted. The reference counting is done to allow the program to
determine if the actual data in the array is being shared by more then one instance of the dynamic array.
Since dynamic arrays do not do any memory management, the reference count is not used to actually
delete the data. A shared method is available to determine if the data in a dynamic array is being
shared.

Clear
The dynamic array also provides a clear method to un-initialize it which will release it reference on
the contained data.
// Allocate a dynamic array
SCAInt32* mem1 = new SCAInt32[10];
Array1 val1(mem1,10);
for(int i=0,i<val1.size();i++) val1[i] = i;
cout << "Shared=" << val1.shared() << endl; (Array is not shared so
value is "false")
// Assign a second dynamic array using the same data – this does not
make a copy of the data
Array1 val2 = val1;
cout << "Shared=" << val1.shared() << endl; (Array is shared so
value is "true")
val2.clear();
cout << "Shared=" << val1.shared() << endl; (Array is not shared so
value is "false")

Main Index
54 SCA Service Guide
Supported Types

// Allocate a second dynamic array using the copy constructor – This


does not make a copy
Array1 val2(val1);
cout << "Shared=" << val1.shared() << endl; (Array is shared so
value is "true")
val2.clear();
cout << "Shared=" << val1.shared() << endl; (Array is not shared so
value is "false")
When using dynamic arrays, you should always check to see if the data is being shared before you delete
it.
// Allocate a dynamic array
SCAInt32* mem1 = new SCAInt32[10];
Array1 val1(mem1,10);
for(int i=0,i<val1.size();i++) val1[i] = i;

// Pass the dynamic array in an interface method


sp->someMethod(val1);

// Delete the data if it is not shared


if ( !val1.shared() ) {
val1.clear();
delete [] mem1;
}
Because the dynamic array does not do any memory management, there needs to be coordination
between the caller and the callee of services using them. In the above sample code, the actual data is not
deleted if it is shared. This would be the case if the code in the interface method called made a copy of
the array. In this case it is very easy for the memory that contains the data to be leaked if the caller and
the callee are not in agreement as to who is responsible for deleting the data.

SCAAny
Dynamic arrays can also be stored in SCAAny values. When a dynamic array is stored in a SCAAny, the
data is not copied. Instead the SCAAny value just contains a reference to the data in the same manner a
normal instance of the dynamic array contains a reference to the data.
// Initialize rank 1 array
SCAInt32* mem1 = new SCAInt32[10];
Array1 val1(mem1,10);
for(int i=0,i<val1.size();i++)
val1[i] = i;
cout << "Shared=" << val1.shared() << endl; (Array is not shared so
value is "false")

// Store array in a SCAAny


SCAAny any;
any <<= val1;
cout << "Shared=" << val1.shared() << endl; (Array is shared so
value is "true")

// Flush the data in the SCAAny

Main Index
CHAPTER 5 55
Supported Data Types

any.flush();
cout << "Shared=" << val1.shared() << endl; (Array is not shared so
value is "false")
It is also possible to insert data for a dynamic array directly into a SCAAny value without ever having to
create an instance of a dynamic array using the insertArray and extractArray methods of the
SCAAny class.
// Routines to directly process dynamic arrays in an Any
SCAAny& insertArray(const SCATypeCode& tc, SCAVoid* values, SCAUInt32
numEnt1, SCAUInt32 numEnt2);

SCABool extractArray(SCATypeCode& tc, SCAVoid** values, SCAUInt32&


numEnt1, SCAUInt32& numEnt2);
This can be useful if you need to pass an array of data through an interface call and the actual format of
the data is only known at run-time. You cannot define the structure of the data in IDL at compilation time
in this situation. Instead, you can create a SCATypeCode at runtime to describe the data and then insert
the array directly into the array using insertArray.
In the example below, a runtime SCATypeCode is created for a structure which contains a
SCAReal32 and a SCAReal64 value. An array of 50 of these values is initialized and then inserted
into a SCAAny.
// Create array of data
char* data = new char[50*sizeof(SCAReal32)+50*sizeof(SCAReal64)];
char* ptr = data;
for ( int j=0; j<50; j++ ) {
SCAReal32 rval = 10.0f*j + j;
memcpy(ptr,&rval,sizeof(SCAReal32));
ptr += sizeof(SCAReal32);
SCAReal64 dval = 100.0*j + j;
memcpy(ptr,&dval,sizeof(SCAReal64));
ptr += sizeof(SCAReal64);
}

// Create SCATypeCode describing data


TypeCodes::SCAStructMemberSeq tmems;
TypeCodes::SCAStructMember mem;
mem.name = "mem1";
mem.type = "SCA.SCAReal32";
mems.push_back(mem);
mem.name = "mem2";
mem.type = "SCA.SCAReal64";
mems.push_back(mem);
SCATypeCode tc = defineStructTypeCode("My.Struct",mems);

// Insert data into SCAAny


SCAAny anyval;
anyval.insertArray(tc,data,50,0);

Main Index
56 SCA Service Guide
Supported Types

Once the data has been inserted in the SCAAny, the value can be passed through any normal interface
call. The callee can then extract and process the data. If the callee does not know the format of the data,
they can interrogate the SCATypeCode value to determine it.
SCAResult MyService:myMethod(SCAAny& anyval)
{
SCAVoid* ptr;
SCAUInt32 size1,size2;
SCATypeCode tc;
if ( anyval1.extractArray(tc,&ptr,size1,size2) ) {
// Memory pointed to my ptr contains data
// Values size1 and size2 contain the array dimensions
} else {
cout << "Error: SCAAny does does contain a dynamic array value" <<
endl;
}
}
Using the SCAAny <<= and >>= operators with dynamic arrays and using the insertArray and
extractArray methods will not make any copies of the data. In those cases the SCAAny only
contains a reference to the data, and the user is responsible for managing this memory.

Sequence

Sequence Characteristics
Memory Management Automatically by Sequence
Type Definition Compile-time or IDL
Length Definition Not required
Length Change Yes
When to Use Using variable-length collection of data

Variable-length arrays are available using the SCA sequence container class. The memory for the
sequence is entirely managed by the sequence itself and can expand or contract as required. Sequences
may be defined in the IDL as separate data types or as members in a structure definition. Only sequences
of rank 1 are supported but you can store a sequence in a sequence to simulate a rank 2 object. Like fixed-
length arrays, sequence types must be defined in a typedef statement, except the length is not required.
// Define sequence data types
typedef sequence<SCA::SCAInt32> SeqInt32;

// Define structure that contains sequences


struct MyStruct {
sequence<SCA::SCAInt32> data1;
SeqInt32 data2;
};
Sequences in C++ are an extension of the vector class provided in the Standard Template Library and add
copy-on-write semantics. This allows sequences to be efficiently copied and shared without having to be

Main Index
CHAPTER 5 57
Supported Data Types

duplicated. If one instance of the sequence tries to modify its contents, a separate copy is made at that
time.
Sequences are accessed using the normal std::vector operators; however, the names of some
methods have been changed to distinguish between read and write operations. For example, sequences
have r_at and w_at methods instead of a single at method. Sequences contain a large number of
methods for accessing and manipulating their contents. Consult the std::vector documentation for
details.
// Use a sequence
SeqInt32 val1;
val1.push_back(1);

// Use a sequence in a structure


MyStruct struct;
struct.data1.push_back(1);
struct.data2.push_back(1);
For convenience, there are some standard SCASequence definitions for the various basic IDL data types.
These types can be used anywhere in the IDL without further definition.

Name Sequence Type


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

Structure
The structure type is similar to the C++ struct and can be defined in the IDL as shown below.

Main Index
58 SCA Service Guide
Supported Types

structure myStructure
{
SCAInt32 longValue;
SCABool boolValue;
SCAString stringValue;
};

SCA Result Type


A special type called SCAResult is provided, which is a structure containing information defining an
error that was encountered. It should be used as the return value for each method defined in an interface
when the design reports errors by return values. An alternative to this approach is using exceptions. An
example using SCAResult in an interface definition is shown below.
interface SCAIMyInterface : SCAIService
{
SCAResult myMethod( );
};

SCASuccess
SCA::SCASuccess is a constant object of SCAResult type. It is equivalent to a SCAResult object
with all fields being set to zero. A method can return SCA::SCASuccess if there are no errors.

API
The public interface to the SCAResult class consists of the member functions shown below.
// Adds error parameter to SCAResult parameter list.
void addParam(SCAInt8 t );
void addParam(SCAUInt8 t );
void addParam(SCAInt16 t );
void addParam(SCAUInt16 t );
void addParam(SCAInt32 t );
void addParam(SCAUInt32 t );
void addParam(SCAInt64 t );
void addParam(SCAUInt64 t );
void addParam(SCAReal32 t );
void addParam(SCAReal64 t );
void addParam(SCAChar t );
void addParam(SCAWChar t );
void addParam(SCAUChar t );
void addParam(SCAString t );
void addParam(SCAWString t );

// Compares all fields of SCAResult data.


bool equals(const SCAResult &sr );

// Returns the error code.


SCAInt32 getErrorCode() const;

// Returns the Message table ID.

Main Index
CHAPTER 5 59
Supported Data Types

SCAInt32 getMsgTableID() const;

// Returns the message ID.


SCAInt32 getMessageID() const;

// Checks if there is no error, error code = 0.


SCABool isOk() const;

SCA Exception Types


Special exception types are provided to support exception handling across language boundaries. An
exception is defined by the user through IDL and is available to the SCA languages that support
exceptions. This allows a SCA exception to be thrown from code written in one programming language
and caught by code written in another programming language.
Three exceptions, SCA::SCAException, SCA::SCASystemException, and
SCA::SCAUserException, are predefined in the SCA Framework. User defined exceptions must
inherit SCA::SCAUserException or another user-defined exception. Only single inheritance is
allowed.

SCAException
The SCAException is the base for all exceptions. It contains a SCAString that the user can set to
describe the nature of the exception. Each language mapping for the SCASytstemException
provides a way to set and fetch the value of this string. The individual language mappings for the
SCASystemException may contain other information required by the SCA Framework but these are
not made available to the user.

SCAUserException
The SCAUserException is the (direct or indirect) base for user defined exceptions. It does not
contain any data member. Its purpose is for users to separate user defined exceptions from
SCASystemException.

SCASystemException
SCASystemException is used to handle system related errors. Even if a method does not have a
raises clause, the SCASystemException may still be thrown. SCASystemException is defined
in the example below.
module SCA {
exception SCASystemException: SCAException{
SCAInt32 id;
};
};

Main Index
60 SCA Service Guide
Supported Types

A SCASystemException carries a SCA system error ID that is defined as an error in the table below.

SCA System Error ID SCA System Error Description


SCA_ERR_UNKNOWN Unknown error
SCA_ERR_INTERFACE Invalid interface
SCA_ERR_METHOD Invalid method
SCA_ERR_PARAM Invalid parameter(s)
SCA_ERR_TYPECODE Undefined type code
SCA_ERR_COMM Communication failure
SCA_ERR_DATACONV Data conversion error
SCA_ERR_MEM Memory error
SCA_ERR_NOIMPL Implementation not available
SCA_ERR_EXCEPTION Invalid exception thrown
SCA_ERR_TYPECODE_READ Error reading type codes
SCA_ERR_CORBA_BRIDGE Error in CORBA Rpc bridge
SCA_ERR_CPP_BRIDGE Error in C++ bridge
SCA_ERR_CPP_CAST C++ interface cast failed
SCA_ERR_XML_TYPECODE XML TypeCode processing error
SCA_ERR_PYTHON_BRIDGE Error in Python bridge
SCA_ERR_MARSHALL Marshalling error
SCA_ERR_SCABINARY SCABinary processing error
SCA_ERR_INTERNAL Internal Error
SCA_ERR_JAVA_BRIDGE Error in Java bridge

Exception versus SCAResult


Reporting errors through exceptions and reporting errors through return values are two different error
handling approaches. They are reflected in SCA Framework with the SCA exception and SCAResult
types. Mixing them may cause confusion and is not recommended. We recommend the conventions
below.
• If an interface method defines raises of any explicit exceptions, the method should not define
a SCAResult or any other variable that indicates an error.
• If an interface method returns SCAResult or any other value as an error indicator, it should not
have raises clause and it should not throw any exceptions.
• Throw user-defined exceptions instead of any of the predefined base exceptions.
• Keep in mind that even if you choose to use the SCAResult form of error handling, calls to
SCA interface methods may still throw SCASystemExceptions if the call crosses language
or process boundaries. This is because the SCA Framework may need report errors such as
argument values that can not be converted between languages or communication errors and the
only universal way for them to do this is to throw exceptions.

Main Index
CHAPTER 5 61
Supported Data Types

Define an Exception
SCA exceptions are similar to the struct and may contain zero or more data members. Exception data
members can be of any SCA IDL type except SCAException. SCA exceptions may not be used as
data arguments. Therefore it may not be inserted or extracted from a SCAAny type.
Example exception definition is shown below.
module Test{
exception MyException : SCAUserException {
SCA::SCAInt32 myint;
SCA::SCAString mystr;
};
};

Define Raising an Exception


An interface method may have an optional raises clause. The raises clause defines what type of
exceptions the method may throw. In addition to any user defined IDL exceptions, a method can always
throw a SCASystemException. User may not specify SCASystemException or
SCAException in the raises clause. The example demonstrates the raises clause.
module Test {
interface TestInterface {
// Exception1 and Exception2 have been defined before this.
SCAVoid testEx() raises (Exception1, Exception2)
};
};

API
The SCAException provides a specific API for accessing the base data contained in all exceptions.
The example below shows the API in C++. Each language specific mapping may provide other methods
outside of this API to process the exceptions. Those methods should not be used because they are only
for internal use and are subject to change.
// Sets raw text string for this exception
SCAVoid setText(const SCAString text) throw();

// Gets raw text string for this exception


SCAString getText() const throw();

// Returns description of the exception


SCAString what() const throw();

// Retrieves SCATypeCode for this exception


SCATypeCode getTypeCode() const throw();

// Throws this exception


virtual void throwit();

Main Index
62 SCA Service Guide
Supported Types

Propagation Rules
An IDL exception thrown from the callee can be caught by the caller even if the callee and the caller are
coded in different languages. The following rules apply when an exception is thrown from language L1
and caught in language L2:
• Exception types that are defined in the raises clause always passes through the language
boundary
• Exception that inherits (directly or indirectly) from an exception in the raises clause always
passes through the language boundary
• Users may define their own non SCA exception classes that inherit from the SCA exception
classes. If these exceptions are thrown, only data defined through SCA IDL exception
definitions will be passed. Any data in the non SCA exception class will be lost.
• The SCASystemException always passes through the language boundary.
• All other exceptions are blocked at the language boundary, and a SCASystemException is
thrown instead

Example
An example of using a SCA exception in C++ is presented below.

IDL
#ifndef TEST_IDL_INCLUDED
#define TEST_IDL_INCLUDED

#include "SCA/Service.idl"

module Test {
exception NotFoundException: SCA::SCAUserException {
::SCA::SCAInt32 zip;
};

interface SCAITestEx : SCA::SCAIService


{
::SCA::SCAString lookup( in SCA::SCAInt32 zip) raises
(NotFoundException);
};

};
#endif

C++ Callee
namespace Test {
SCA::SCAString TestService::lookup(const SCA::SCAInt32 zip)
{
if( zip == 48105 ) return "Ann Arbor";
if( zip == 92707 ) return "Santa Ana";

Main Index
CHAPTER 5 63
Supported Data Types

Test::NotFoundException e;
e.setText("name not found in TestService::lookup");
e.zip=zip;
e.throwit();
}
}

C++ Caller
//setup SCAITestEx inf
try{
inf->lookup(12345);
}catch(NotFoundException &ex){
std::cout<<"caught exception:"<<ex.what()<<std::endl;

Main Index
64 SCA Service Guide
Supported Types

Main Index

You might also like