C++ Programmer Guide
C++ Programmer Guide
COPYRIGHT NOTICE
No part of this publication may be reproduced, stored in a retrieval system or transmitted, in any form or by any
means, photocopying, recording or otherwise, without prior written consent of IONA Technologies PLC. No third
party intellectual property right liability is assumed with respect to the use of the information contained herein.
IONA Technologies PLC assumes no responsibility for errors or omissions contained in this book. This publication
and features described herein are subject to change without notice.
All products or services mentioned in this manual are covered by the trademarks, service marks, or product
names as designated by the companies who market those products.
Updated: 31-Oct-2003
M 3 1 1 6
Contents
List of Tables vii
Preface ix
iii
CONTENTS
iv
CONTENTS
Index 227
v
CONTENTS
vi
List of Tables
Table 1: Artix Import Libraries for Linking with an Application 17
Table 2: Artix Exception Error Codes 27
Table 3: Pattern of create_server() Calls in Various Threading Models 59
Table 4: Transport Schemas with Message Attributes 95
Table 5: Simple Schema Type to Simple Bus Type Mapping 121
Table 6: Member Fields of IT_Bus::DateTime 125
Table 7: Operators Supported by IT_Bus::Decimal 126
Table 8: Schema to Bus Mapping for the Binary Types 128
Table 9: Nillable Atomic Types 172
Table 10: Member Functions Not Defined in IT_Vector 203
Table 11: Member Types Defined in IT_Vector<T> 206
Table 12: Iterator Member Functions of IT_Vector<T> 207
Table 13: Element Access Operations for IT_Vector<T> 207
Table 14: Stack Operations for IT_Vector<T> 207
Table 15: List Operations for IT_Vector<T> 208
Table 16: Other Operations for IT_Vector<T> 208
Table 17: Artix Mapping of IDL Basic Types to C++ 212
vii
LIST OF TABLES
viii
Preface
Audience This guide is intended for Artix C++ programmers. In addition to a
knowledge of C++, this guide assumes that the reader is familiar with
WSDL and XML schemas.
Related documentation The document set for Artix includes the following:
• Getting Started with Artix
• Artix User’s Guide
• Artix Tutorial Guide
The latest updates to the Artix documentation can be found at http://
iona.com/docs.
Reading path If you are new to Artix, you should read the documentation in the following
order:
1. Getting Started with Artix
The getting started book describes the basic concepts behind Artix. It
also provides details on installing the system and a detailed walk
through for developing a C++ client for a Web Service.
2. Artix User’s Guide
The user’s guide describes the development pattern for designing and
deploying Artix enabled systems. It provides detailed examples for a
number of typical use cases.
3. Artix Tutorial Guide
ix
PREFACE
Help resources If you need help with this or any other IONA products, contact IONA at
[email protected]. Comments on IONA documentation can be sent to
.
Additional resources The IONA knowledge base contains helpful articles, written by IONA
experts, about the Orbix and other products. You can access the knowledge
base at the following location:
http://www.iona.com/support/kb/
The IONA update center contains the latest releases and patches for IONA
products:
http://www.iona.com/support/update/
x
PREFACE
xi
PREFACE
Keying conventions This guide may use the following keying conventions:
No prompt When a command’s format is the same for multiple
platforms, a prompt is not used.
% A percent sign represents the UNIX command shell
prompt for a command that does not require root
privileges.
# A number sign represents the UNIX command shell
prompt for a command that requires root privileges.
> The notation > represents the DOS, Windows NT,
Windows 95, or Windows 98 command prompt.
... Horizontal or vertical ellipses in format and syntax
. descriptions indicate that material has been
. eliminated to simplify a discussion.
.
[] Brackets enclose optional items in format and syntax
descriptions.
{} Braces enclose a list from which you must choose an
item in format and syntax descriptions.
| A vertical bar separates items in a list of choices
enclosed in {} (braces) in format and syntax
descriptions.
xii
CHAPTER 1
Developing Artix
Enabled Clients
and Servers
Artix generates stub and skeleton code that provides a
developer with a simple model to develop transport
independent applications.
1
CHAPTER 1 | Developing Artix Enabled Clients and Servers
Generated files The Artix code generator produces seven files from the Artix contract. They
are named according to the port type name specified in the logical portion of
the Artix contract. The files are as follows:
PortTypeName.h defines the superclass from which the client and server are
implemented. It represents the API used by the service defined in the
contract.
2
Generating Stub and Skeleton Code
Generating code from the You can generate code at the command line using the command:
command line
You must specify the location of a valid WSDL contract file, WSDL_URL, for
the code generator to work. You can also supply the following optional
parameters:
-i port_type Specifies the name of the port type for which the tool
will generate code. The default is to use the first port
type listed in the contract.
-e web_service_name Specifies the name of the service for which the tool
will generate code. The default is to use the first
service listed in the contract.
-t port Specifies the name of the port for which code is
generated. The default is to used the first port listed
in the contract.
-b binding_name Specifies the name of the binding to use when
generating code. The default is the first binding listed
in the contract.
-d output_dir Specifies the directory to which the generated code is
written. The default is the current working directory.
-n namespace Specifies the C++ namespace to use for the
generated code.
-impl Generates the skeleton code for implementing the
server defined by the contract.
-m {NMAKE | UNIX} Used in combination with -impl to generate a
makefile for the specified platform (NMAKE for
Windows or UNIX for UNIX). For example, the
options, -impl -m NMAKE, would generate a Windows
makefile.
-f Deprecated—No longer used (was needed to support
routing in earlier versions.
-sample Generates code for a sample implementation of a
client and a server.
3
CHAPTER 1 | Developing Artix Enabled Clients and Servers
4
C++ Namespaces
C++ Namespaces
Artix namespaces Two built-in C++ namespaces widely used by the Artix runtime
infrastructure are: IT_Bus, and IT_WSDL. The first namespace is used for the
callable APIs and declarations, and the second is used for the functions that
parse the WSDL at runtime; these are needed only by highly dynamic
applications.
Solution specific namespaces You can optionally instruct the C++ client proxy generator to put the proxy
classes and complex data types into a custom C++ namespace. This is
useful if you plan on using many Web services from a single client
application. Consider the following sample application, where the GroupB
service was put into a namespace called GroupB. Also note the use of the
IT_Bus namespace for the data types.
#include "GroupBClient.h"
#include "GroupBClientTypes.h"
GroupB::SOAPStruct ssSend;
ssSend.setvarFloat(IT_Bus::Float(5.67));
ssSend.setvarInt(1234);
ssSend.setvarString(IT_Bus::String("Embedded struct string"));
IT_Bus::Int intValue = 0;
IT_Bus::Float floatValue = IT_Bus::Float(0.0);
IT_StringPtr pstring(bc.echoStructAsSimpleTypes(ssSend,
intValue, floatValue));
}
5
CHAPTER 1 | Developing Artix Enabled Clients and Servers
Restrictions The following restrictions currently apply when defining a WSDL interface
for Artix applications:
• Some simple atomic types are not supported—see “Unsupported
Simple Types” on page 133.
• Derived complex types are not supported, apart from the special case
of SOAP arrays.
WSDL example Example 1 shows the WSDL for a HelloWorld port type, which defines two
operations, greetMe and sayHi.
// C++
<?xml version="1.0" encoding="UTF-8"?>
<definitions name="HelloWorldService"
targetNamespace="http://xmlbus.com/HelloWorld"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://xmlbus.com/HelloWorld"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
<message name="greetMe">
<part name="stringParam0" type="xsd:string"/>
</message>
<message name="greetMeResponse">
<part name="return" type="xsd:string"/>
</message>
<message name="sayHi"/>
<message name="sayHiResponse">
<part name="return" type="xsd:string"/>
</message>
<portType name="HelloWorldPortType">
<operation name="greetMe">
6
Defining a WSDL Interface
7
CHAPTER 1 | Developing Artix Enabled Clients and Servers
Developing a Server
Overview The Artix code generator generates server skeleton code and the
implementation shell that serves as the starting point for developing a server
that uses the Artix Bus. This skeleton code hides the transport details from
the application developer, allowing them to focus on business logic.
Generating the server The Artix code generator utility, wsdltocpp, will generate an implementation
implementation class class for your server when passed the -impl command flag.
PortTypeNameImpl.h contains the signatures and data types needed for the
server implementation.
Completing the server You must provide the logic for the operations specified in the contract that
implementation defines the server. To do this you edit the empty methods provided in
PortTypeNameImpl.cxx. The generated impl class, HelloWorldImpl.cxx, for
the contract defined in this chapter would resemble Example 2. The
majority of the code in Example 2 is auto-generated by the WSDL-to-C++
compiler. Only the code portions highlighted in bold (in the bodies of the
greetMe() and sayHi() functions) must be inserted by the programmer.
// C++
#include "HelloWorldImpl.h"
#include <it_cal/cal.h>
IT_USING_NAMESPACE_STD
using namespace IT_Bus;
8
Developing a Server
HelloWorldImpl::HelloWorldImpl(IT_Bus::Bus_ptr bus,
IT_Bus::Port* port)
: HelloWorldServer(bus,port)
{
}
HelloWorldImpl::~HelloWorldImpl()
{
}
void
HelloWorldImpl::greetMe(
const IT_Bus::String & stringParam0,
IT_Bus::String & Response
) IT_THROW_DECL((IT_Bus::Exception))
{
cout << "HelloWorldImpl::greetMe called with message: "
<< stringParam0 << endl;
Response = IT_Bus::String("Hello Artix User: ")+stringParam0;
}
void
HelloWorldImpl::sayHi(
IT_Bus::String & Response
) IT_THROW_DECL((IT_Bus::Exception))
{
cout << "HelloWorldImpl::sayHi called" << endl;
Response = IT_Bus::String("Greetings from the Artix
HelloWorld Server");
}
HelloWorldImplFactory global_HelloWorldImplFactory;
HelloWorldImplFactory::HelloWorldImplFactory()
{
m_wsdl_location = IT_Bus::String("HelloWorld.wsdl");
IT_Bus::QName service_name("", "HelloWorldService",
"http://xmlbus.com/HelloWorld");
IT_Bus::Bus::register_server_factory(
service_name,
this
);
}
HelloWorldImplFactory::~HelloWorldImplFactory()
9
CHAPTER 1 | Developing Artix Enabled Clients and Servers
{
IT_Bus::QName service_name("", "HelloWorldService",
"http://xmlbus.com/HelloWorld");
IT_Bus::Bus::deregister_server_factory(service_name);
//cleanup();
}
IT_Bus::ServerStubBase*
HelloWorldImplFactory::create_server(IT_Bus::Bus_ptr bus,
IT_Bus::Port* port)
{
return new HelloWorldImpl(bus, port);
}
void
HelloWorldImplFactory::destroy_server(IT_Bus::ServerStubBase*
server)
{
if (server != 0)
{
delete IT_DYNAMIC_CAST(HelloWorldImpl*, server);
}
}
Writing the server main() The server main() handles the initialization of the Artix Bus, the running of
the Artix Bus, and the shutdown of the Artix Bus.
Initializing the Bus
The Bus is initialized using IT_Bus::init(). The method has the following
signature:
10
Developing a Server
Completed server main() Example 3 on page 11 shows how the main() for the server defined by the
Converter contract might look.
// C++
#include <it_bus/bus.h>
#include <it_bus/Exception.h>
#include <it_bus/fault_exception.h>
IT_USING_NAMESPACE_STD
using namespace IT_Bus;
try
{
IT_Bus::init(argc, argv);
IT_Bus::run();
}
catch (IT_Bus::Exception& e)
{
cout << "Error occurred: " << e.Error() << endl;
return -1;
}
return 0;
}
11
CHAPTER 1 | Developing Artix Enabled Clients and Servers
Developing a Client
Overview The stub code for a client implementation for the service defined by the
contract is contained in the files PortTypeNameClient.h and
PortTypeNameClient.cxx. You should never make any modifications to the
generated code in these files. You also need to reference the files
PortTypeName.h and PortTypeNameTypes.h in your client code.
To access the operations defined in the port type, the client initializes the
Artix bus, instantiates an object of the generated client proxy class,
PortTypeNameClient, and makes method calls on the object. When the
client is finished, it then shuts down the bus.
Initializing the Bus Client applications initialize the bus in the same manner as server
applications, by calling IT_Bus::init(). Client applications, however, do
not need to make a call to IT_Bus::run().
Instantiating the client object The generated HelloWorld client proxy object has three constructors as
shown in Example 4 on page 12.
HelloWorldClient();
No argument constructor
The first constructor for the client proxy class takes no parameters. When
using this constructor, the client requires that the contract defining its
behavior be located in the same directory as the executable. The client uses
the port and service specified at code generation time using the -t and -b
flags.
12
Developing a Client
The client code is binding and transport neutral. Hence, the only restriction
in specifying the port to use is that it have the same portType as the
generated proxy. The port details are read in from the WSDL contract file at
runtime. For example, if the contract for the conversion service is modified
to include a service definition like the one shown in Example 5 on page 13,
you could instantiate the client proxy to use either HTTP or Tuxedo.
<service name="HelloWorldService2">
<port name="HelloWorldHTTPPort"
binding="tns:HelloWorldBinding">
<soap:address location="http:\\localhost:8081"/>
</port>
<port name="HelloWorldTuxedoPort"
binding="tns:HelloWorldBinding">
<tuxedo:address serviceName="TuxQueue"/>
</port>
</service>
13
CHAPTER 1 | Developing Artix Enabled Clients and Servers
To specify that the proxy client is to connect to the server using the Tuxedo
server TuxQueue, you would instantiate the client using the following
constructor:
Invoking the operations To invoke the operations offered by the service, the client calls the methods
of the client proxy object. The generated client proxy class contains one
method for each operation defined in the contract. The generated methods
all return void. Any response messages are passed by reference as a
parameter to the method. For example, the greetMe operation defined in
Example 1 generates a method with the following signature:
void greetMe(
const IT_Bus::String & stringParam0,
IT_Bus::String & var_return
) IT_THROW_DECL((IT_Bus::Exception));
Shutting the bus down Unlike a server that must shut down the bus from a separate thread, clients
do not typically make a call to IT_Bus::run() and can simply call
IT_Bus::shutdown() before the main thread exits. It is advisable to pass
TRUE to IT_Bus:shutdown() to ensure that the bus is fully shutdown before
exiting.
Full client code A client developed to access the service defined by the HelloWorldService
contract will look similar to Example 6.
// C++
#include <it_bus/bus.h>
#include <it_bus/Exception.h>
#include <it_cal/iostream.h>
1 #include "HelloWorldClient.h"
IT_USING_NAMESPACE_STD
using namespace IT_Bus;
14
Developing a Client
try
{
2 IT_Bus::init(argc, argv);
3 HelloWorldClient hw;
String string_in;
String string_out;
4 hw.sayHi(string_out);
cout << "sayHi method returned: " << string_out << endl;
if (argc > 1) {
string_in = argv[1];
} else {
string_in = "Early Adopter";
}
hw.greetMe(string_in, string_out);
cout << "greetMe method returned: " << string_out << endl;
}
5 catch(IT_Bus::Exception& e)
{
cout << endl << "Caught Unexpected Exception: "
<< endl << e.Message()
<< endl;
return -1;
}
return 0;
}
15
CHAPTER 1 | Developing Artix Enabled Clients and Servers
16
Compiling and Linking an Artix Application
-I"$(IT_PRODUCT_DIR)\artix\$(IT_PRODUCT_VER)\include"
Linker Requirements A number of Artix libraries are required to link with an application built using
Artix. The following directives should be given to the linker:
Table 1 shows the libraries that are required for linking an Artix application
and their function.
it_afc.lib libit_afc.so The Artix foundation classes provide Artix specific data
libit_afc.sl type extensions such as IT_Bus::Float, etc. Required for
libit_afc.a all applications that use Artix functionality.
it_ifc.lib libit_ifc.so The IONA foundation classes provide IONA specific data
libit_ifc.sl types and exceptions.
libit_ifc.a
17
CHAPTER 1 | Developing Artix Enabled Clients and Servers
Runtime Requirements The following directories need to be in the path, either by copying them into
a location already in the path, or by adding their locations to the path. The
following lists the required libraries and their location in the distribution files
(all paths are relative to the root directory of the distribution):
"$(IT_PRODUCT_DIR)\artix\$(IT_PRODUCT_VER)\bin"
and
"$(IT_PRODUCT_DIR)\bin"
18
Building Artix Stub Libraries on Windows
Generating stubs with declaration To generate Artix stubs with declaration specifiers, use the -declspec option
specifiers to the WSDL-to-C++ compiler, as follows:
wsdltocpp -declspec MY_DECL_SPEC BaseService.wsdl
In this example, the -declspec option would add the following preprocessor
macro definition to the top of the generated header files:
#if !defined(MY_DECL_SPEC)
#if defined(MY_DECL_SPEC_EXPORT)
#define MY_DECL_SPEC IT_DECLSPEC_EXPORT
#else
#define MY_DECL_SPEC IT_DECLSPEC_IMPORT
#endif
#endif
Where the IT_DECLSPEC_EXPORT macro is defined as _declspec(dllexport)
and the IT_DECLSPEC_IMPORT macro is _declspec(dllimport).
Each class in the header file is declared as follows:
class MY_DECL_SPEC ClassName { ... };
Compiling stubs with declaration If you are about to package your stubs in a DLL library, compile your C++
specifiers stub files, StubFile.cxx, with a command like the following:
cl -DMY_DECLSPEC_EXPORT ... StubFile.cxx
By setting the MY_DECLSPEC_EXPORT macro on the command line,
_declspec(dllexport) declarations are inserted in front of the public class
declarations in the stub. This ensures that applications will be able to
import the public definitions from the stub DLL.
19
CHAPTER 1 | Developing Artix Enabled Clients and Servers
20
CHAPTER 2
Artix Programming
Considerations
Several areas must be considered when programming complex
Artix applications.
Exceptions page 26
Multi-Threading page 51
21
CHAPTER 2 | Artix Programming Considerations
Parameter direction in WSDL WSDL operation parameters can be sent either as input parameters (that is,
in the client-to-server direction or as output parameters (that is, in the
server-to-client direction). Hence, the following kinds of parameter can be
defined:
• in parameter—declared as an input parameter, but not as an output
parameter.
• out parameter—declared as an output parameter, but not as an input
parameter.
• inout parameter—declared both as an input and as an output
parameter.
How to declare WSDL operations You can declare a WSDL operation as follows:
1. Declare a multi-part input message, including all of the in and inout
parameters for the new operation (for example, the testParams
message in Example 7 on page 22).
2. Declare a multi-part output message, including all of the out and inout
parameters for the operation (for example, the testParamsResponse
message in Example 7 on page 22).
3. Within the scope of <portType>, declare a single operation which
includes a single input message and a single output message.
WSDL declaration of testParams Example 7 shows an example of a simple operation, testParams, which
takes two input parameters, inInt and inoutInt, and two output
parameters, inoutInt and outFloat.
22
Operations and Parameters
<definitions ...>
...
<message name="testParams">
<part name="inInt" type="xsd:int"/>
<part name="inoutInt" type="xsd:int"/>
</message>
<message name="testParamsResponse">
<part name="inoutInt" type="xsd:int"/>
<part name="outFloat" type="xsd:float"/>
</message>
...
<portType name="BasePortType">
<operation name="testParams">
<input message="tns:testParams" name="testParams"/>
<output message="tns:testParamsResponse"
name="testParamsResponse"/>
</operation>
...
</definitions>
C++ mapping of testParams Example 8 shows how the preceding WSDL testParams operation (from
Example 7 on page 22) maps to C++.
// C++
void testParams(
const IT_Bus::Int inInt,
IT_Bus::Int & inoutInt,
IT_Bus::Float & outFloat
) IT_THROW_DECL((IT_Bus::Exception));
Mapped parameters When the testParams WSDL operation maps to C++, the resulting
testParams() C++ function signature starts with the in and inout
parameters, followed by the out parameters. The parameters are mapped as
follows:
• in parameters—are passed by value and declared const.
• inout parameters—are passed by reference.
• out parameters—are passed by reference.
23
CHAPTER 2 | Artix Programming Considerations
C++ mapping of Example 10 shows how the preceding WSDL testReverseParams operation
testReverseParams (from Example 9 on page 24) maps to C++.
// C++
void testReverseParams(
IT_Bus::Int & inoutInt
const IT_Bus::Int inInt,
IT_Bus::Float & outFloat,
) IT_THROW_DECL((IT_Bus::Exception));
24
Operations and Parameters
Order of in, inout and out In C++, the order of the in and inout parameters in the function signature is
parameters the same as the order of the parts in the input message. The order of the out
parameters in the function signature is the same as the order of the parts in
the output message.
Note: The parameter order is not affected by the relative order of the
<input> and <output> tags in the declaration of <operation>. In the
mapped C++ signature, the in and inout parameters always appear
before the out parameters.
25
CHAPTER 2 | Artix Programming Considerations
Exceptions
Overview Artix provides a variety of built-in exceptions, which can alert users to
problems with network connectivity, parameter marshalling, and so on. In
addition, Artix allows users to define their own exceptions, which can be
propagated across the network by declaring fault exceptions in WSDL.
26
Exceptions
Non-Propagating Exceptions
Overview The Artix libraries and generated code generate exceptions from classes
based on IT_Bus::Exception, defined in <it_bus/Exception.h>.
IT_Bus::Exception provides all Artix generated exceptions with two
methods for providing information back to the user:
IT_Bus::Exception::Message()
Message() returns an informative description of the error which generated
the exception. It has the following signature:
IT_Bus::Exception::Error()
Error() returns an error code, if one is assigned to the exception, that
identifies the exception. It has the following signature:
Currently only the following exceptions have been given error codes:
27
CHAPTER 2 | Artix Programming Considerations
28
Exceptions
Propagating Exceptions
Overview Artix servers propagate certain exceptions, such as serialization and
deserialization exceptions, back to their clients so the client can handle the
error gracefully. This is done using the IT_Bus::FaultException class,
defined in <it_bus/fault_exception.h>. FaultException extends
Exception to provide connection awareness and serialization.
Artix propagates user-defined exceptions back to client processes. To specify
that an exception is to be propagated, you must declare the exception as a
fault in WSDL. The WSDL-to-C++ compiler then generates the stub code
that you need to raise and catch the exception.
Declaring a fault in WSDL Example 11 shows an example of a WSDL fault which can be raised on the
echoInteger operation. The format of the fault message is specified by the
tns:SampleFault message.
29
CHAPTER 2 | Artix Programming Considerations
<output message="tns:echoIntegerResponse"
name="echoIntegerResponse"/>
3 <fault message="tns:SampleFault"
name="SampleFault"/>
</operation>
</portType>
...
</definitions>
Raising a fault exception in a Example 12 shows how to raise the SampleFault fault in the server code.
server The implementation of echoInteger now checks the input integer to see if it
exceeds the given bounds.
The WSDL maps to C++ as follows:
• The WSDL SampleFaultData type maps to a C++ SampleFaultData
class.
• The WSDL SampleFault message maps to a C++
SampleFaultException class. This follows the general pattern that
ExceptionMessage maps to ExceptionMessageException.
// C++
void BaseImpl::echoInteger(const IT_Bus::Int
inputInteger,IT_Bus::Int& Response)
30
Exceptions
IT_THROW_DECL((IT_Bus::Exception))
{
if (inputInteger<0 || 100<inputInteger)
{
// Create and initialize the SampleFaultData
SampleFaultData ex_data;
ex_data.setlowerBound(0);
ex_data.setupperBound(100);
Catching a fault exception in a Example 13 shows how to catch the SampleFault fault on the client side.
client The client uses the proxy instance, bc, to call the echoInteger operation
remotely.
// C++
...
try {
Int int_out = 0;
bc.echoInteger(int_in,int_out);
if (int_in != int_out)
{
cout << endl << "echoInteger PASSED" << endl;
}
}
catch (SampleFaultException &ex)
{
cout << "Bounds exceeded:" << endl;
cout << "lower bound = "
<< ex.getexceptionData().getlowerBound() << endl;
cout << "upper bound = "
<< ex.getexceptionData().getupperBound() << endl;
31
CHAPTER 2 | Artix Programming Considerations
}
catch (IT_Bus::FaultException &ex)
{
/* Handle other fault exceptions ... */
}
catch (...)
{
/* Handle all other exceptions ... */
}
32
Memory Management
Memory Management
Overview This section discusses the memory management rules for Artix types,
particularly for generated complex types.
Deallocating page 41
33
CHAPTER 2 | Artix Programming Considerations
Managing Parameters
Overview This subsection discusses the guidelines for managing the memory for
parameters of complex type. In Artix, memory management of parameters is
relatively straightforward, because the Artix C++ mapping passes
parameters by reference.
Memory management rules There are just two important memory management rules to remember when
writing an Artix client or server:
1. The client is responsible for deallocating parameters.
2. If the server needs to keep a copy of parameter data, it must make a
copy of the parameter. In general, parameters are deallocated as soon
as an operation returns.
Example 14: WSDL Example with in, inout and out Parameters
34
Memory Management
Example 14: WSDL Example with in, inout and out Parameters
</types>
...
<message name="testSeqParams">
<part name="inSeq" type="xsd1:SequenceType"/>
<part name="inoutSeq" type="xsd1:SequenceType"/>
</message>
<message name="testSeqParamsResponse">
<part name="inoutSeq" type="xsd1:SequenceType"/>
<part name="outSeq" type="xsd1:SequenceType"/>
</message>
...
<portType name="BasePortType">
<operation name="testSeqParams">
<input message="tns:testSeqParams"
name="testSeqParams"/>
<output message="tns:testSeqParamsResponse"
name="testSeqParamsResponse"/>
</operation>
...
</portType>
...
</definitions>
Client example Example 15 shows how to allocate, initialize, and deallocate parameters
when calling the testSeqParams operation.
// C++
try
{
IT_Bus::init(argc, argv);
1 BaseClient bc;
35
CHAPTER 2 | Artix Programming Considerations
inoutSeq.setvarInt(12345);
inoutSeq.setvarString("Four, five, six");
4 // End of scope:
// Implicit deallocation of inSeq, inoutSeq, and outSeq.
}
catch(IT_Bus::Exception& e)
{
cout << endl << "Caught Unexpected Exception: "
<< endl << e.Message()
<< endl;
return -1;
}
Server example Example 16 shows how the parameters are used on the server side, in the
C++ implementation of the testSeqParams operation.
// C++
void
BaseImpl::testSeqParams(
const SequenceType & inSeq,
SequenceType & inoutSeq,
SequenceType & outSeq
) IT_THROW_DECL((IT_Bus::Exception))
36
Memory Management
{
cout << "BaseImpl::testSeqParams called" << endl;
1 // Print inSeq
cout << "inSeq.varFloat = " << inSeq.getvarFloat() << endl;
cout << "inSeq.varInt = " << inSeq.getvarInt() << endl;
cout << "inSeq.varString = " << inSeq.getvarString() << endl;
4 // Initialize outSeq
outSeq.setvarFloat(3.0);
outSeq.setvarInt(3);
outSeq.setvarString("Three");
}
37
CHAPTER 2 | Artix Programming Considerations
4. You should initialize each of the out parameters (otherwise they will be
returned with default initial values).
38
Memory Management
Copy constructor The WSDL-to-C++ compiler generates a copy constructor for complex
types. For example, the SequenceType type declared in Example 14 on
page 34 has the following copy constructor:
// C++
SequenceType(const SequenceType& copy);
This enables you to initialize SequenceType data as follows:
// C++
SequenceType original;
original.setvarFloat(1.23);
original.setvarInt(321);
original.setvarString("One, two, three.");
SequenceType copy_1(original);
SequenceType copy_2 = original;
Assignment operator The WSDL-to-C++ compiler generates an assignment operator for complex
types. For example, the generated assignment operator enables you to
assign a SequenceType instance as follows:
// C++
SequenceType original;
original.setvarFloat(1.23);
original.setvarInt(321);
original.setvarString("One, two, three.");
SequenceType assign_to;
assign_to = original;
39
CHAPTER 2 | Artix Programming Considerations
Recursive copying In WSDL, complex types can be nested inside each other to an arbitrary
degree. When such a nested complex type is mapped to C++ by Artix, the
copy constructor and assignment operators are designed to copy the nested
members recursively (deep copy).
40
Memory Management
Deallocating
Using delete In C++, if you allocate a complex type on the heap (that is, using pointers
and new), you can generally delete the data instance using the delete
operator. It is usually better, however, to use smart pointers in this
context—see “Smart Pointers” on page 42.
Recursive deallocation The Artix C++ types are designed to support recursive deallocation.
That is, if you have an instance, T, of a complex type which has other
complex types nested inside it, the entire memory for the complex type
including its nested members would be deallocated when you delete T. This
works for complex types nested to an arbitrary degree.
41
CHAPTER 2 | Artix Programming Considerations
Smart Pointers
Overview To help you avoid memory leaks when using pointers, the WSDL-to-C++
compiler generates a smart pointer class, ComplexTypePtr, for every
generated complex type, ComplexType. The following aspects of smart
pointers are discussed here:
• What is a smart pointer?
• Artix smart pointers.
• Assignment semantics.
• Client example using simple pointers.
• Client example using smart pointers.
What is a smart pointer? A smart pointer class is a C++ class that overloads the * (dereferencing)
and -> (member access) operators, in order to imitate the syntax of an
ordinary C++ pointer.
Artix smart pointers Artix smart pointers are defined using a template class, IT_AutoPtr<T>,
which has the same API as the standard auto pointer template,
auto_ptr<T>, from the C++ standard template library. If the standard
library is supported on the platform, IT_AutoPtr is simply a typedef of
std::auto_ptr.
For example, the SequenceTypePtr smart pointer class is defined by the
following generated typedef:
// C++
typedef IT_AutoPtr<SequenceType> SequenceTypePtr;
The key feature that makes this pointer type smart is that the destructor
always deletes the memory the pointer is pointing at. This feature ensures
that you cannot leak memory when it is referenced by a smart pointer.
42
Memory Management
Assignment semantics The auto_ptr smart pointer types have destructive copy semantics. For
example, consider the following assignment between smart pointers of
SequenceTypePtr type:
// C++
SequenceTypePtr assign_from = new SequenceType();
// Initialize assign_from (not shown) ...
// Assignment Statement
assign_to = assign_from;
Note: If you are familiar with the CORBA IDL-to-C++ mapping, you
should note that these assignment semantics are different from the
CORBA _var types’ assignment semantics.
Client example using simple Example 17 shows how to call the testSeqParams operation using
pointers parameters that are allocated on the heap and referenced by simple
pointers
// C++
try
{
IT_Bus::init(argc, argv);
BaseClient bc;
43
CHAPTER 2 | Artix Programming Considerations
2 // End of scope:
delete inSeqP;
delete inoutSeqP;
delete outSeqP;
}
catch(IT_Bus::Exception& e)
{
cout << endl << "Caught Unexpected Exception: "
<< endl << e.Message()
<< endl;
return -1;
}
Client example using smart Example 18 shows how to call the testSeqParams operation using
pointers parameters that are allocated on the heap and referenced by smart pointers
// C++
try
{
IT_Bus::init(argc, argv);
BaseClient bc;
44
Memory Management
2 // End of scope:
// Parameter data automatically deallocated by smart pointers
}
catch(IT_Bus::Exception& e)
{
cout << endl << "Caught Unexpected Exception: "
<< endl << e.Message()
<< endl;
return -1;
}
45
CHAPTER 2 | Artix Programming Considerations
Server factory features By writing a custom server factory implementation, you can exploit the
following features of the server factory design:
• Override the WSDL location.
• Register a server factory against multiple services.
• Register multiple ports per service.
• Create multiple servants per port or share one servant between ports.
Default server factory When you run the wsdltocpp utility with the -impl flag, it generates a
default implementation of a servant class and a server factory class in the
files PortTypeImpl.h and PortTypeImpl.cxx.
The default server factory, generated by wsdltocpp, has the following
general characteristics:
• A global static instance of the server factory is declared in the
PortTypeImpl.cxx file.
• The server factory registers itself against a single service and a single
port (as specified by the -e and -t parameters of wsdltocpp).
• The threading model defaults to MULTI_INSTANCE.
46
Implementing a Server Factory
Sample WSDL Example 19 shows an extract from a WSDL contract that defines multiple
services and ports for the HelloWorld port type. The
SOAPHelloWorldService service defines a single port that exposes
HelloWorld as a SOAP service and the HW.HelloWorldService service
defines two ports that expose HelloWorld as a CORBA service.
Server factory example Example 20 shows an example of a server factory class that is customized
to register multiple services and ports. This server factory implementation is
based on the WSDL contract from Example 19 on page 47.
// C++
...
1 HW_HelloWorldImplFactory global_HW_HelloWorldImplFactory;
HW_HelloWorldImplFactory::HW_HelloWorldImplFactory()
{
m_wsdl_location = IT_Bus::String("HelloWorld.wsdl");
47
CHAPTER 2 | Artix Programming Considerations
HW_HelloWorldImplFactory::~HW_HelloWorldImplFactory()
{
IT_Bus::QName service_name("", "HW.HelloWorldService",
"http://schemas.iona.com/idl/HelloWorld.idl");
5 IT_Bus::Bus::deregister_server_factory(service_name);
}
6 IT_Bus::ServerStubBase* HW_HelloWorldImplFactory::create_server(
IT_Bus::Bus_ptr bus, IT_Bus::Port* port)
{
return new HW_HelloWorldImpl(bus, port);
}
IT_Bus::ThreadingModel
8 HW_HelloWorldImplFactory::get_threading_model() const
{
48
Implementing a Server Factory
return IT_Bus::MULTI_INSTANCE;
}
9 void HW_HelloWorldImplFactory::destroy_server(
IT_Bus::ServerStubBase* server
)
{
if (server != 0)
{
delete IT_DYNAMIC_CAST(HW_HelloWorldImpl*, server);
}
}
49
CHAPTER 2 | Artix Programming Considerations
50
Multi-Threading
Multi-Threading
Overview This section provides an overview of threading in Artix and describes the
issues affecting multi-threaded clients and servers in Artix.
51
CHAPTER 2 | Artix Programming Considerations
Single client proxy in two threads Example 21 below is a correctly written example featuring a single client
proxy instance called from two different threads (assume T1func and T2func
are called from two different threads):
#include <it_ts/mutex.h>
#include <it_ts/locker.h>
#include "BaseClient.h"
#include "BaseClientTypes.h"//nested inside BaseClient.h, may be
omitted
BaseClient g_bc;
IT_Mutex mutexBC;
T1func()
{
IT_Locker<IT_Mutex> lock(mutexBC);
g_bc.echoVoid();
}
T2func()
{
IT_Locker<IT_Mutex> lock(mutexBC);
g_bc.echoVoid();
}
52
Multi-Threading
Two client proxies in two threads Example 22 below is another correctly written sample featuring two client
proxy instances called from two different threads (assume T1func and
T2func are called from two different threads):
#include "BaseClient.h"
#include "BaseClientTypes.h"
//nested inside BaseClient.h, may be omitted
T1func()
{
BaseClient bc;
bc.echoVoid();
}
T2func()
{
BaseClient bc;
bc.echoVoid();
}
53
CHAPTER 2 | Artix Programming Considerations
Servant
Port 1 R1 R2 R3 ... RN
Service
Work Queue 2 Thread pool for port 2
Port 2 R1 R2 R3 ... RN
54
Multi-Threading
Port 1 R1 R2 R3 ... RN
Servant
Service
Work Queue 2 Thread pool for port 2
Port 2 R1 R2 R3 ... RN
Thread pool settings The thread pool for each port is controlled by the following parameters
(which can be set in the configuration):
• Initial threads—the number of threads initially created for each port.
• Low water mark—the size of the dynamically allocated pool of threads
will not fall below this level.
• High water mark—the size of the dynamically allocated pool of threads
will not rise above this level.
Thread pools are configured by adding to or editing the settings in the
ArtixInstallDir/artix/Version/etc/domains/artix.cfg configuration file. In
the following examples, it is assumed that the Artix application specifies its
configuration scope to be sample_config.
Note: You can specify the configuration scope at the command line by
passing the switch -ORBname ConfigScopeName to the Artix executable.
Command-line arguments are normally passed to IT_Bus::init().
55
CHAPTER 2 | Artix Programming Considerations
Thread pool configuration levels Thread pools can be configured at several levels, where the more specific
configuration settings take precedence over the less specific, as follows:
• Global level.
• Service name level.
• Qualified service name level.
Global level The variables shown in Example 23 can be used to configure thread pools at
the global level; that is, these settings would apply to all services by default.
sample_config {
...
# Thread pool settings at global level
thread_pool:initial_threads = "3";
thread_pool:low_water_mark = "5";
thread_pool:high_water_mark = "10";
};
Service name level To configure thread pools at the service name level (that is, overriding the
global settings for a specific service only), set the following configuration
variables:
thread_pool:ServiceName:initial_threads
thread_pool:ServiceName:low_water_mark
thread_pool:ServiceName:high_water_mark
Where ServiceName is the name of the particular service to configure, as it
appears in the WSDL <service name="ServiceName"> tag.
56
Multi-Threading
For example, the settings in Example 24 show how to configure the thread
pool for a service named SessionManager.
sample_config {
...
# Thread pool settings at Service name level
thread_pool:SessionManager:initial_threads = "1";
thread_pool:SessionManager:low_water_mark = "5";
thread_pool:SessionManager:high_water_mark = "10";
};
Qualified service name level Occasionally, if the service names from two different namespaces clash, it
might be necessary to identify a service by its fully-qualified service name.
To configure thread pools at the qualified service name level, set the
following configuration variables:
thread_pool:NamespaceURI:ServiceName:initial_threads
thread_pool:NamespaceURI:ServiceName:low_water_mark
thread_pool:NamespaceURI:ServiceName:high_water_mark
Where NamespaceURI is the namespace URI in which ServiceName is
defined.
For example, the settings in Example 25 show how to configure the thread
pool for a service named SessionManager in the //my.tns1/ namespace
URI.
Example 25: Thread Pool Settings at the Qualified Service Name Level
sample_config {
...
# Thread pool settings at Service name level
thread_pool:http://my.tns1/:SessionManager:initial_threads =
"1";
thread_pool:http://my.tns1/:SessionManager:low_water_mark =
"5";
thread_pool:http://my.tns1/:SessionManager:high_water_mark =
"10";
};
57
CHAPTER 2 | Artix Programming Considerations
Threading model options The it_bus/threading_model.h header file defines the following threading
model options, as shown in Example 26.
namespace IT_Bus
{
enum ThreadingModel
{
MULTI_INSTANCE = 0,
MULTI_THREADED = 1,
SINGLE_THREADED = 2
};
};
ServerFactoryBase class The ServerFactoryBase class, as shown in Example 27, defines the server
factory API. All of the member functions are abstract, except for
get_threading_model(), which has a default implementation that returns
IT_Bus::MULTI_INSTANCE.
// C++
class IT_BUS_API ServerFactoryBase
{
public:
ServerFactoryBase();
virtual ~ServerFactoryBase();
virtual ServerStubBase*
create_server(Bus_ptr bus, Port* port) = 0;
58
Multi-Threading
virtual ThreadingModel
get_threading_model() const;
};
create_server() function Artix calls the create_service() function whenever a new service instance
is needed. The pattern of create_server() calls depends on the chosen
threading model, as described in Table 3.
59
CHAPTER 2 | Artix Programming Considerations
Overriding get_threading_model() To change the threading model for a particular service, you should override
the default implementation of get_threading_model().
For example, if you have a service of HelloWorld port type, the wsdltocpp
generates a default implementation of the server factory,
HelloWorldImplFactory, in the files HelloWorldImpl.h and
HelloWorldImpl.cxx. To change the threading model to MULTI_THREADED in
this case, perform the following steps:
1. Edit the HelloWorldImpl.h file, adding a declaration of the
get_threading_model() function to the HelloWorldImplFactory class:
// C++
class HelloWorldImplFactory : public
IT_Bus::ServerFactoryBase
{
public:
...
virtual ThreadingModel get_threading_model() const;
};
// C++
IT_Bus::ThreadingModel
HelloWorldImplFactory::get_threading_model() const
{
return IT_Bus::MULTI_THREADED;
}
60
CHAPTER 3
Artix References
An Artix reference is a handle to a particular port on a
particular service. Because references can be passed around
as parameters, they provide a convenient and flexible way of
identifying and locating specific services.
61
CHAPTER 3 | Artix References
Introduction to References
Overview An Artix reference encapsulates the location information for a particular
WSDL port on a particular WSDL service. When compared with storing
location information in WSDL, references have the following advantages:
• References are more dynamic—that is, the information encapsulated
in a reference is only partially dependent on the WSDL contract.
Hence, reference details can change at runtime.
• References can be sent across the wire as parameters of or return
values from operations.
• References can be stored in a central repository, facilitating features
such as load balancing and directory enquiries.
XML representation of a reference The XML representation of a reference is defined by the following schema:
ArtixInstallDir/artix/Version/schemas/references.xsd
The XML representation is used when marshaling or unmarshaling a
reference as a WSDL parameter.
62
Introduction to References
Static references A static reference is a reference for which all of the port and service details
appear explicitly in the WSDL contract. The static reference, therefore,
delegates most of the details to the WSDL contract. Figure 3 illustrates the
relationship between a static reference and the WSDL contract.
Static Reference
IT_Bus::Reference
WSDL Contract
...
<binding>
...
</binding>
...
<service>
<port>
...
</port>
...
</service>
...
63
CHAPTER 3 | Artix References
Transient references A transient reference stores all of its service and port attributes explicitly in
a properties list, rather than referring to the WSDL contract. Hence, a
transient reference is more flexible, because it can refer to endpoints created
at runtime. Figure 4 illustrates the relationship between a transient
reference and the WSDL contract.
Transient Reference
IT_Bus::Reference
Embedded properties
WSDL Contract
...
<binding>
...
</binding>
...
<service>
<port>
...
</port>
...
</service>
...
64
The IT_Bus::Reference Class
Setting and getting basic The following IT_Bus::Reference member functions enable you to get and
reference properties set a reference’s service QName, port name, binding QName and WSDL file
location:
Getting binding-specific The following IT_Bus::Reference member function enables you to get a list
properties of binding-specific properties:
65
CHAPTER 3 | Artix References
66
Using the Artix Locator
Artix Locator
Service A A1, A2, A3, A4, A5
Service B B1, B2
Ports
A1
Artix Client Service A A2
Artix Server X
A3
B1
Service B
B2
locator_endpoint
A4
plug-in
Service A
A5
Artix Server Y
locator_endpoint
plug-in
Locator demonstration The a locator demonstration, which forms the basis of the examples in this
section, is located in the following directory:
ArtixInstallDir/artix/Version/demos/locator
67
CHAPTER 3 | Artix References
Locator service There are two basic options for deploying the locator service, as follows:
• Standalone deployment—the locator is deployed as an independent
server process (as shown in Figure 5). This approach is described in
detail in the “Using the Artix Locator Service” chapter from the Artix
User’s Guide. Sample source code for such a standalone locator
service is provided in the demos/locator demonstration.
• Embedded deployment—the locator is deployed by embedding it
within another Artix server process. This approach is possible because
the locator is implemented as a plug-in, which can be loaded into any
Artix application.
Registering endpoints An Artix endpoint is a particular WSDL port in a particular WSDL service. A
server registers its endpoints (that is, WSDL ports) with the locator in order
to make them accessible to Artix clients. When a server registers an
endpoint in the locator, it creates an entry in the locator that associates a
service QName with an Artix reference for that endpoint.
Looking up references An Artix client looks up a reference in the locator in order to find an endpoint
associated with a particular service. After retrieving the reference from the
locator, the client can then establish a remote connection to the relevant
server by instantiating a client proxy object. This procedure is independent
of the type of binding or transport protocol.
Load balancing with the locator If multiple ports are registered against a single service QName in the locator,
the locator will employ a round-robin algorithm to pick one of the ports.
Hence, the locator effectively load balances a service over all of its
registered ports.
For example, Figure 5 on page 67 shows the Service A service with five
ports registered against it, A1, A2, A3, A4, and A5. When the Artix client looks
up a reference for Service A, it obtains an Artix reference, Ax, to whichever
endpoint is next in the sequence.
68
Using the Artix Locator
Locator WSDL
Overview The locator WSDL contract, locator.wsdl, defines the public interface of
the locator through which the service can be accessed either locally or
remotely. This section shows extracts from the locator WSDL that are
relevant to normal user applications. The following aspects of the locator
WSDL are described here:
• Binding and protocol.
• WSDL contract.
• C++ mapping.
Binding and protocol The locator service is normally accessed through the SOAP binding and over
the HTTP protocol.
Note: Currently, the locator service is limited by the fact that most Artix
bindings do not support endpoint references. In future releases of Artix,
when the support for references is extended to other bindings, it should be
possible to use the locator with other bindings and transports.
WSDL contract Example 28 shows an extract from the locator WSDL contract that focuses
on the aspects of the contract relevant to an Artix application programmer.
There is just one WSDL operation, lookup_endpoint, that an Artix client
typically needs to call.
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:ref="http://schemas.iona.com/references"
xmlns:ls="http://ws.iona.com/locator"
targetNamespace="http://ws.iona.com/locator">
<types>
<xs:schema targetNamespace="http://ws.iona.com/locator">
1 <xs:import
schemaLocation="../../../schemas/references.xsd"
namespace="http://schemas.iona.com/references"/>
...
69
CHAPTER 3 | Artix References
2 <xs:element name="lookupEndpoint">
<xs:complexType>
<xs:sequence>
<xs:element name="service_qname"
type="xs:QName"/>
</xs:sequence>
</xs:complexType>
</xs:element>
3 <xs:element name="lookupEndpointResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="service_endpoint"
type="ref:Reference"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType
name="EndpointNotExistFaultException">
<xs:sequence>
<xs:element name="error" type="xs:string"/>
</xs:sequence>
</xs:complexType>
4 <xs:element name="EndpointNotExistFault"
type="ls:EndpointNotExistFaultException"/>
</xs:schema>
</types>
...
<message name="lookupEndpointInput">
<part name="parameters" element="ls:lookupEndpoint"/>
</message>
<message name="lookupEndpointOutput">
<part name="parameters"
element="ls:lookupEndpointResponse"/>
</message>
<message name="endpointNotExistFault">
<part name="parameters"
element="ls:EndpointNotExistFault"/>
</message>
5 <portType name="LocatorService">
...
6 <operation name="lookup_endpoint">
<input message="ls:lookupEndpointInput"/>
<output message="ls:lookupEndpointOutput"/>
<fault name="fault"
70
Using the Artix Locator
message="ls:endpointNotExistFault"/>
</operation>
</portType>
<binding name="LocatorServiceBinding"
type="ls:LocatorService">
...
</binding>
<service name="LocatorService">
<port name="LocatorServicePort"
binding="ls:LocatorServiceBinding">
<soap:address
7 location="http://localhost:0/services/locator/LocatorService"/>
</port>
</service>
</definitions>
71
CHAPTER 3 | Artix References
C++ mapping Example 29 shows an extract from the C++ mapping of the
LocatorService port type. This extract shows only the lookup_endpoint
WSDL operation—the other WSDL operations in this class are normally not
needed by user applications.
// C++
#include "LocatorService.h"
#include <it_bus/service.h>
#include <it_bus/bus.h>
#include <it_bus/reference.h>
#include <it_bus/types.h>
#include <it_bus/operation.h>
namespace IT_Bus_Services
{
class LocatorServiceClient : public LocatorService, public
IT_Bus::ClientProxyBase
{
private:
public:
LocatorServiceClient(
IT_Bus::Bus_ptr bus = 0
);
LocatorServiceClient(
const IT_Bus::String & wsdl,
IT_Bus::Bus_ptr bus = 0
);
LocatorServiceClient(
const IT_Bus::String & wsdl,
const IT_Bus::QName & service_name,
const IT_Bus::String & port_name,
72
Using the Artix Locator
IT_Bus::Bus_ptr bus = 0
);
LocatorServiceClient(
IT_Bus::Reference & reference,
IT_Bus::Bus_ptr bus = 0
);
~LocatorServiceClient();
...
virtual void
lookup_endpoint(
const IT_Bus_Services::lookupEndpoint &
lookupEndpoint_in,
IT_Bus_Services::lookupEndpointResponse &
lookupEndpointResponse_out
) IT_THROW_DECL((IT_Bus::Exception));
};
};
The lookupEndpoint type The input parameter for the lookup_endpoint operation is of
lookupEndpoint type, which maps to C++ as follows:
// C++
namespace IT_Bus_Services
{
class lookupEndpoint : public IT_Bus::SequenceComplexType
{
public:
lookupEndpoint();
lookupEndpoint(const lookupEndpoint& copy);
virtual ~lookupEndpoint();
73
CHAPTER 3 | Artix References
// C++
namespace IT_Bus_Services
{
class lookupEndpointResponse
: public IT_Bus::SequenceComplexType
{
public:
lookupEndpointResponse();
lookupEndpointResponse(const lookupEndpointResponse&
copy);
virtual ~lookupEndpointResponse();
...
const IT_Bus::Reference & getservice_endpoint() const;
IT_Bus::Reference & getservice_endpoint();
void setservice_endpoint(const IT_Bus::Reference & val);
...
};
};
74
Using the Artix Locator
Configuring a server to register A server that is to register its endpoints with the locator must be configured
endpoints to include the soap, http, and locator_endpoint plug-ins, as shown in the
following demo.locator.server configuration scope from artix.cfg:
References For more details about configuring a server to register endpoints, see the
following references:
• “Using the Artix Locator Service” chapter from the Artix User’s Guide.
• The Artix locator demonstration in artix/Version/demos/locator.
75
CHAPTER 3 | Artix References
Artix Locator
SOAPHTTPService P1
... ...
2 lookup_endpoint()
Artix
Artix Client 1 Locator proxy
SimpleService
Server
3 SimpleService proxy
SOAPHTTPService
P1
4 Invoke operation
locator_endpoint
plug-in
Programming steps The main programming steps needed to read a reference from the locator,
as shown in Figure 6, are as follows:
1. Construct a locator service proxy.
2. Use the locator proxy to invoke the lookup_reference operation.
3. Use the reference returned from lookup_reference to construct a
SimpleService proxy.
4. Invoke an operation using the SimpleService proxy.
76
Using the Artix Locator
Example Example 30 shows an example of the code for an Artix client that retrieves a
reference to a SimpleService service from the Artix locator.
// C++
#include <it_bus/bus.h>
#include <it_bus/Exception.h>
#include <it_cal/iostream.h>
#include "SimpleServiceClient.h"
#include "LocatorServiceClient.h"
IT_USING_NAMESPACE_STD
using namespace IT_Bus;
using namespace IT_Bus_Services;
using namespace SimpleServiceNS;
int
main(int argc, char* argv[])
{
cout << " SimpleService Client" << endl;
try
{
int my_argc = 2;
const char * my_argv [] = {
"-ORBname",
"demo.locator.client"
};
2 QName service_name(
"","LocatorService", "http://ws.iona.com/locator"
);
3 QName sh_service_name(
"","SOAPHTTPService", "http://www.iona.com/bus/tests"
);
4 String port_name("LocatorServicePort");
77
CHAPTER 3 | Artix References
);
// 2. Invoke on locator
6 m_locator_client->lookup_endpoint(
sh_input,
sh_output
);
78
Using the Artix Locator
Note: If there is more than one WSDL port registered for the
SOAPHTTPService server, the locator service employs a round-robin
algorithm to choose one of the ports to use as the returned endpoint.
// C++
SimpleClient(
IT_Bus::Reference & reference,
IT_Bus::Bus_ptr bus = 0
);
8. You can now use the simple client proxy to make invocations on the
remote Artix server.
79
CHAPTER 3 | Artix References
IT_Bus::Service pause and The IT_Bus::Service class provides the following member functions for
resume functions pausing and resuming an Artix service:
IT_Bus::Service::reached_capacity()
Call the reached_capacity() function to pause a service’s endpoints. The
locator_endpoint plug-in listens for this event and, when the function is
called, the locator_endpoint plug-in deregisters the service’s endpoints
(ports) from the locator.
IT_Bus::Service::below_capacity()
Call the below_capacity() function to resume a service’s endpoints. The
locator_endpoint plug-in listens for this event and, when the function is
called, the locator_endpoint plug-in re-registers the service’s endpoints
with the locator.
80
Using the Artix Locator
C++ server example Example 31 shows how to pause and resume the endpoints for a
BookService service.
// C++
// Get handle to Service from Bus if available
IT_Bus::QName service_name(“”, “BookService”, “http://books”);
IT_Bus::Service* = bus->get_service(service_name);
81
CHAPTER 3 | Artix References
82
CHAPTER 4
Transactions in
Artix
This chapter discusses the Artix support for distributed
transaction processing.
83
CHAPTER 4 | Transactions in Artix
Introduction to Transactions
Overview Artix supports a pluggable model of transaction support, which is currently
restricted to the CORBA Object Transaction Service (OTS) only and, by
default, supports client-side transaction demarcation only. Other transaction
services (such as MQ series transactions) will be supported in a future
release. The following transaction features are supported by Artix:
• Client-side transaction support.
• Compatibility with Orbix ASP.
• Pluggable transaction factory.
Client-side transaction support By default, Artix has only client-side support for CORBA OTS-based
transactions. Transaction demarcation functions (begin(), commit() and
rollback()) can be used on the client side to control transactions that are
hosted on a remote CORBA OTS server, as shown in Figure 7.
Transaction
Factory
In Figure 7, the resource and the transaction factory are located on the
server side (in an Orbix ASP domain). Artix currently does not have the
capability to manage resources on the client side.
84
Introduction to Transactions
Compatibility with Orbix ASP The Artix transaction facility is fully compatible with CORBA OTS in Orbix
ASP. Hence, if you already have a transactional server implemented with
Orbix ASP, you can easily integrate this with an Artix client.
Pluggable transaction factory The underlying transaction factory used by Artix can be replaced within a
pluggable framework. In future, Artix will support multiple factories (for
example, OTS, MQ series, and so on). Currently, only the following
transaction factory is supported:
• ots
85
CHAPTER 4 | Transactions in Artix
Transaction API
Overview The Artix transaction API is provided by the following classes and modules:
• IT_Bus::Bus
Note: You can also gain access to interfaces from the CosTransactions
module, which is part of CORBA OTS, if you have IONA’s Orbix ASP
product. This is not included with Artix.
IT_Bus::Bus member functions The IT_Bus::Bus class has the following member functions, which are used
to manage transactions:
// C++
void begin(const char* factory_name);
CosTransactions::Coordinator*
get_coordinator(const char* factory_name);
Factory name parameter The factory name parameter, which is passed to each of the preceding API
functions, identifies the kind of transaction factory that is used. Currently,
only the CORBA OTS transaction factory is supported, which is specified by
the string, ots.
86
Transaction API
Client transaction functions The begin(), commit(), and rollback() functions are used to demarcate
transactions on the client side. The commit() function ends the transaction
normally, making any changes permanent. The rollback() function aborts
the transaction, rolling back any changes.
The within_transaction() function, which can be called in an execution
context on the server side, returns TRUE if the current operation is executing
within a transaction scope.
Server transaction functions The rollback_only() function can be called on the server side to mark the
current transaction for rollback. After this function is called, the current
transaction can only be rolled back, not committed.
Timeouts A client can use the set_timeout() function to impose a timeout on the
transactions it initiates. If the timeout is exceeded, the transaction is
automatically rolled back.
87
CHAPTER 4 | Transactions in Artix
Client Example
Overview This section describes a transactional Artix client that connects to a remote
CORBA OTS server. The client uses the Artix transactional API to delimit
transactions, where the transactional resource and the transaction factory
are both located in the CORBA OTS server. This simple Artix client cannot
manage a transactional resource on its own.
WSDL sample Example 32 defines a WSDL port type, AccountPortType, with two
operations withdraw and deposit, which are used for withdrawing money
from or depositing money into personal accounts on the server.
88
Client Example
// C++
...
IT_Bus::Bus_var bvar = IT_Bus::Bus::create_reference();
1 AccountClient acc;
try {
// start a txn
2 bvar->begin("ots");
acc.withdraw("Bill", 1000);
acc.deposit("Ben", 1000);
3 bvar->commit(IT_TRUE,"ots");
cout << "Transaction completed successfully." << endl;
}
catch(IT_Bus::Exception& e) {
4 bvar->rollback("ots");
cout << endl << "Caught Unexpected Exception: "
<< endl << e.Message() << endl;
return -1;
}
89
CHAPTER 4 | Transactions in Artix
90
CHAPTER 5
Message
Attributes
This chapter describes how to program message attributes,
which enable you to send extra data in a WSDL message during
an operation call.
Schemas page 95
91
CHAPTER 5 | Message Attributes
Message attribute categories Message attributes are properties that are set on an instance of a WSDL
port. They are defined in a WSDL schema and are usually transport-specific.
They can be divided into the following categories:
• Attributes that can be sent from the client to the server (input message
attributes).
• Attributes that can be sent from the server to the client (output
message attributes).
Additionally, the following kinds of message attribute can only be set locally
and are not transmitted between applications:
• Attributes that configure the WSDL port on the client side (not
transmitted).
• Attributes that configure the WSDL port on the server side (not
transmitted).
92
Introduction to Message Attributes
Input and output messages Figure 8 shows how message attributes are sent in the input message
header, from client to server, and in the output message header, from server
to client.
Artix Artix
Binding Binding
request
message message
parts attributes
Client interception points A client can access message attributes at the following interception points:
• Pre-invoke—write input message attributes prior to an operation call.
• Post-invoke—read output message attributes after an operation call.
Server interception points A server can access message attributes within the body of an operation
implementation to do either of the following:
• Read the input message attributes received from the client.
• Write output message attributes to send to the client.
Oneway operations A WSDL oneway operation defines only an input message. Hence, in a
oneway operation it is only possible to define input message attributes.
93
CHAPTER 5 | Message Attributes
Setting message attributes in It is possible to specify message attributes in configuration, by adding WSDL
configuration extension elements to the <port> element of the WSDL contract.
For example, the HelloWorld MQ Soap example (located in
ArtixInstallDir\artix\Version\demos\hello_world\mq_soap) defines the
<port> element in its WSDL contract as follows:
<mq:server QueueManager="MY_DEF_QM"
QueueName="HW_REQUEST"
ReplyQueueManager="MY_DEF_QM"
ReplyQueueName="HW_REPLY"
AccessMode="receive"
/>
</port>
</service>
</definitions>
The attributes in the preceding example define the name and properties of
an MQ series message queue both on the client side and the server side.
Setting message attributes by Artix also allows you to set message attributes by programming. This gives
programming you finer control over message attributes, enabling you to set them
per-invocation instead of per-connection.
There are two styles of API for accessing and modifying message attributes
by programming, as discussed in the following sections:
• “Name-Value API” on page 97.
• “Transport-Specific API” on page 101.
94
Schemas
Schemas
Overview The various kinds of message attributes are defined in a collection of XML
schema definitions (one schema file for each transport type), located in the
following directory:
ArtixInstallDir/artix/Version/schemas
Schema documentation For documentation on the message attribute settings, see the relevant
sections of the Artix User’s Guide concerning HTTP Transport Attributes,
MQSeries Transport Attributes and Tibco Transport Attributes.
Schemas for message attributes The message attributes supported by Artix are defined by transport-specific
XSLT schema files, located in the ArtixInstallDir/artix/Version/schemas
directory. The transport schemas with message attributes are listed in
Table 4.
HTTP ArtixInstallDir/artix/Version/schemas/http-conf.xsd
MQ Series ArtixInstallDir/artix/Version/schemas/mq.xsd
Tibco ArtixInstallDir/artix/Version/schemas/tibrv.xsd
95
CHAPTER 5 | Message Attributes
HTTP schema example Example 34 shows an extract from the HTTP schema, http-conf.xsd,
showing some message attributes that can be set on the client side (that is,
input message attributes).
The UserName and Password input message attributes can be used to send
authentication data to a server. By default, these message attributes are
sent in a BASIC HTTP authentication header.
96
Name-Value API
Name-Value API
Overview The name-value API is a transport-neutral API for setting and getting
message attributes, where the attributes are stored in a table of name-value
pairs. Attributes are identified by passing a string argument to one of the
set_Type() or get_Type() functions (for a complete list of attribute
identifiers, see the relevant schema in “Schemas for message attributes” on
page 95).
This subsection discusses the following aspects of the name-value API:
• Inheritance hierarchy.
• MessageAttributes class.
• NamedAttributes class.
Inheritance hierarchy Figure 9 shows the inheritance hierarchy for the classes involved in the
name-value API for message attributes.
IT_Bus::NamedAttributes
IT_Bus::MessageAttributes
MessageAttributes class The IT_Bus::MessageAttributes class inherits functions for getting and
setting name-value pairs from IT_Bus::NamedAttributes, but it does not
define any new member functions of its own. The MessageAttribute class is
used as the base class for transport-specific message attribute classes and
instances of a MessageAttribute type encapsulate the settings for a specific
transport.
97
CHAPTER 5 | Message Attributes
// C++
IT_Bus::Boolean get_boolean(const IT_Bus::String& name) const
IT_THROW_DECL((WrongTypeException, NoSuchAttributeException));
void set_boolean(
const IT_Bus::String& name,
IT_Bus::Boolean data
);
IT_Bus::Byte get_byte(
const IT_Bus::String& name
) const
IT_THROW_DECL((WrongTypeException, NoSuchAttributeException));
void set_byte(
const IT_Bus::String& name,
IT_Bus::Byte data
);
IT_Bus::Short get_short(
const IT_Bus::String& name
) const
IT_THROW_DECL((WrongTypeException, NoSuchAttributeException));
void set_short(
const IT_Bus::String& name,
IT_Bus::Short data
);
IT_Bus::Int get_int(
const IT_Bus::String& name
) const
IT_THROW_DECL((WrongTypeException, NoSuchAttributeException));
void set_int(
const IT_Bus::String& name,
IT_Bus::Int data
);
IT_Bus::Long get_long(
const IT_Bus::String& name
98
Name-Value API
) const
IT_THROW_DECL((WrongTypeException, NoSuchAttributeException));
void set_long(
const IT_Bus::String& name,
IT_Bus::Long data
);
IT_Bus::UByte get_ubyte(
const IT_Bus::String& name
) const
IT_THROW_DECL((WrongTypeException, NoSuchAttributeException));
void set_ubyte(
const IT_Bus::String& name,
IT_Bus::UByte data
);
IT_Bus::UShort get_ushort(
const IT_Bus::String& name
) const
IT_THROW_DECL((WrongTypeException, NoSuchAttributeException));
void set_ushort(
const IT_Bus::String& name,
IT_Bus::UShort data
);
IT_Bus::UInt get_uint(
const IT_Bus::String& name
) const
IT_THROW_DECL((WrongTypeException, NoSuchAttributeException));
void set_uint(
const IT_Bus::String& name,
IT_Bus::UInt data
);
IT_Bus::ULong get_ulong(
const IT_Bus::String& name
) const
IT_THROW_DECL((WrongTypeException, NoSuchAttributeException));
void set_ulong(
const IT_Bus::String& name,
99
CHAPTER 5 | Message Attributes
IT_Bus::ULong data
);
IT_Bus::Float get_float(
const IT_Bus::String& name
) const
IT_THROW_DECL((WrongTypeException, NoSuchAttributeException));
void set_float(
const IT_Bus::String& name,
IT_Bus::Float data
);
IT_Bus::Double get_double(
const IT_Bus::String& name
) const
IT_THROW_DECL((WrongTypeException, NoSuchAttributeException));
void set_double(
const IT_Bus::String& name,
IT_Bus::Double data
);
IT_Bus::String get_string(
const IT_Bus::String& name
) const
IT_THROW_DECL((WrongTypeException, NoSuchAttributeException));
void set_string(
const IT_Bus::String& name,
const IT_Bus::String& data
);
...
const IT_Bus::NamedAttributes::StringList& get_names();
void clear_name_values();
100
Transport-Specific API
Transport-Specific API
Overview In addition to the neutral API for setting message attributes (as defined by
IT_Bus::NamedAttributes), Artix also provides a transport-specific API for
certain transports. This subsection describes the following aspects of
transport-specific APIs:
• Inheritance hierarchy.
• Transports with a message attribute API.
• Tibco transport example.
Inheritance hierarchy Figure 10 shows the inheritance hierarchy for the classes involved in the
transport-specific API for message attributes.
IT_Bus::NamedAttributes
IT_Bus::MessageAttributes
HTTPClientAttributes MQAttributes
HTTPServerAttributes IT_Bus::TibrvMessageAttributes
101
CHAPTER 5 | Message Attributes
Transports with a message The following transports provide a message attributes API:
attribute API • HTTP—there are two parts to this API, as follows:
♦ Client side—defined by the HTTPClientAttributes class in the
<it_bus_config/http_wsdl_client.h> header
♦ Server side—defined by the HTTPServerAttributes class in the
<it_bus_config/http_wsdl_server.h> header.
• MQ Series—defined by the MQAttributes class in the
<it_bus_config/mq_wsdl_port.h> header.
• Tibco—defined by the IT_Bus::TibrvMessageAttributes class in the
<it_bus_config/tibrv_message_attributes.h> header.
// C++
namespace IT_Bus
{
class IT_BUS_API TibrvMessageAttributes
: public virtual MessageAttributes
{
public:
...
virtual const String& get_send_subject();
virtual void set_send_subject(const String&
send_subject);
102
Transport-Specific API
103
CHAPTER 5 | Message Attributes
How to use message attributes in To use message attributes on the client side, perform the following steps:
a client
Step Action
C++ example To use message attributes in a sample client, you can modify the
HelloWorld HTTP Soap client as shown in Example 37. Edit the client.cxx
file, which is located in the
ArtixInstallDir/artix/Version/demos/hellow_world/http_soap/client
directory. In Example 37, the client sets two input message attributes,
UserName and Password, prior to the WSDL operation call and reads a single
output message attribute, ContentType, after the call.
// C++
...
104
Using Message Attributes in a Client
try
{
IT_Bus::init(argc, argv);
HelloWorldClient hw;
String string_in;
String string_out;
3 hw.sayHi(string_out);
cout << "sayHi method returned: " << string_out << endl;
105
CHAPTER 5 | Message Attributes
106
Using Message Attributes in a Server
How to use message attributes in To use message attributes on the server side, perform the following steps:
a server
Step Action
107
CHAPTER 5 | Message Attributes
C++ example To use message attributes in a server, you can modify the HelloWorld HTTP
Soap server as shown in Example 38. Edit the HelloWorldImpl.cxx file,
which is located in the
ArtixInstallDir/artix/Version/demos/hellow_world/http_soap/server
directory. In Example 38, the client sets two input message attributes,
UserName and Password, prior to the WSDL operation call and reads a single
output message attribute, ContentType, after the call.
// C++
#include "HelloWorldImpl.h"
#include <it_cal/cal.h>
IT_USING_NAMESPACE_STD
using namespace IT_Bus;
HelloWorldImpl::HelloWorldImpl(IT_Bus::Bus_ptr bus,
IT_Bus::Port* port)
: HelloWorldServer(bus,port)
{
1 get_port().use_input_message_attributes();
get_port().use_output_message_attributes();
}
void
HelloWorldImpl::sayHi(
IT_Bus::String & Response
) IT_THROW_DECL((IT_Bus::Exception))
{
// Read input message attributes.
IT_Bus::MessageAttributes& hw_input =
2 get_port().get_input_message_attributes();
try {
3 IT_Bus::String user_name =
hw_input.get_string("UserName");
IT_Bus::String password =
hw_input.get_string("Password");
cout << "Message attributes received:" << endl;
cout << " username = " << user_name
<< ", password = " << password << endl;
}
4 catch (IT_Bus::NoSuchAttributeException) { }
108
Using Message Attributes in a Server
Note: You cannot call get_port() on the server stub if you are using
the MULTI_THREADED threading model when the servant
implementation is registered against multiple ports. The get_port()
operation is currently supported for the following scenarios only:
• MULTI_INSTANCE threading model with multiple ports.
• MULTI_THREADED threading model with only a single port.
2. To read the input message attribute object on the server side, call
get_input_message_attributes() on the server port object.
3. In this example, the server peeks at the value of the UserName and
Password attributes. Normally, however, you would not bother to read
the UserName and Password at this point because they would
automatically be processed by the server’s transport layer.
4. The IT_Bus::NoSuchAttributeException exception is thrown here if
you try to read an input attribute that was not sent by the client.
5. You can send output message attributes back to the client by setting
attributes on the output message attributes object, hw_output.
109
CHAPTER 5 | Message Attributes
110
CHAPTER 6
Dynamic
Configuration
This section describes how you can dynamically modify a
WSDL port’s connection parameters by parsing and modifying
the WSDL contract.
111
CHAPTER 6 | Dynamic Configuration
WSDL
WSDL
Template
Process of dynamic configuration The process of dynamic configuration shown in Figure 11 can be described
as follows:
Stage Description
3 The server writes out the modified WSDL to a new WSDL file,
which is the form of the WSDL contract to be exposed to
clients.
112
Introduction to Dynamic Configuration
Stage Description
113
CHAPTER 6 | Dynamic Configuration
Process for dynamically allocating The process for dynamically allocating IP ports can be described as follows:
IP ports
Stage Description
4 When an Artix client starts up, it reads the modified WSDL file
that is created in step 3, not the original WSDL file.
114
Dynamically Allocating IP Ports
Modifying the HelloWorld The example discussed here shows how you can modify the HelloWorld
demonstration demonstration to perform dynamic IP port allocation. The source code to
modify can be found in the following directory:
ArtixInstallDir/artix/Version/demos/HelloWorld/http_soap
How to implement dynamic IP To implement dynamic IP port allocation, perform the following steps:
port allocation 1. Modify the address in the WSDL contract to use IP port 0.
2. Add some code after IT_Bus::init() in the server.cxx file that writes
the WSDL contract to a new file, HelloWorld_written.wsdl. For
example, you could modify the main function of HelloWorld’s
server.cxx file as shown in Example 39.
// C++
...
int
main(int argc, char* argv[])
{
cout << "HelloWorld Server" << endl;
try
{
IT_Bus::init(argc, argv);
IT_CurrentThread::sleep(2000);
115
CHAPTER 6 | Dynamic Configuration
IT_Bus::FileOutputStream stream(
"HelloWorld_written.wsdl"
);
IT_Bus::XMLOutputStream xml_stream(stream, true);
definitions.write(xml_stream);
stream.close();
IT_Bus::run();
}
catch (IT_Bus::Exception& e)
{
cout << "Error occurred: " << e.Error() << endl;
return -1;
}
return 0;
}
116
Dynamically Allocating IP Ports
int
main(int argc, char* argv[])
{
cout << "HelloWorld Client" << endl;
try
{
IT_Bus::init(argc, argv);
HelloWorldClient hw(
"HelloWorldServerDir/HelloWorld_written.wsdl"
);
...
}
117
CHAPTER 6 | Dynamic Configuration
118
CHAPTER 7
119
CHAPTER 7 | Artix Data Types
Simple Types
Overview This section describes the WSDL-to-C++ mapping for simple types. Simple
types are defined within an XML schema and they are subject to the
restriction that they cannot contain elements and they cannot carry any
attributes.
120
Simple Types
Atomic Types
Overview For unambiguous, portable type resolution, a number of data types are
defined in the Artix foundation classes, specified in it_bus/types.h. The
Artix data types map closely to WSDL type names, and should be used by
client applications.
xsd:boolean IT_Bus::Boolean
xsd:byte IT_Bus::Byte
xsd:unsignedByte IT_Bus::UByte
xsd:short IT_Bus::Short
xsd:unsignedShort IT_Bus::UShort
xsd:int IT_Bus::Int
xsd:unsignedInt IT_Bus::UInt
xsd:long IT_Bus::Long
xsd:unsignedLong IT_Bus::ULong
xsd:float IT_Bus::Float
xsd:double IT_Bus::Double
xsd:string IT_Bus::String
xsd:dateTime IT_Bus::DateTime
xsd:decimal IT_Bus::Decimal
xsd:base64Binary IT_Bus::BinaryBuffer
xsd:hexBinary IT_Bus::BinaryBuffer
121
CHAPTER 7 | Artix Data Types
String Type
Overview xsd:string maps to IT_Bus::String. IT_Bus::String is a typedef of the
IT_String class (declared in it_dsa/string.h), which is an IONA
implementation of the standard ANSI String class.
Codeset Strings are assumed to be in the local codeset. If Artix writes a string as
XML, however, it transcodes the string to the UTF-8 codeset.
IT_Bus::String class The IT_Bus::String class is modelled on the standard ANSI string class.
Hence, the IT_Bus::String class overloads the + and += operators for
concatenation, the [] operator for indexing characters, and the ==, !=, >, <,
>=, <= operators for comparisons. The following member functions are useful
when converting IT_Bus::Strings to ordinary C-style strings:
size_t length() const;
const char* c_str() const;
The corresponding string iterator class is IT_Bus::String::iterator.
C++ example The following C++ example shows how to perform some basic string
manipulation with IT_Bus::String:
// C++
IT_Bus::String s = "A C++ ANSI string."
s += " And here is some string concatenation."
Reference For more details about C++ ANSI strings, see The C++ Programming
Language, third edition, by Bjarne Stroustrup.
122
Simple Types
QName Type
Overview xsd:QName maps to IT_Bus::QName. A qualified name, or QName, is the
unique name of a tag appearing in an XML document, consisting of a
namespace URI and a local part.
QName constructor The usual way to construct an IT_Bus::QName object is by calling the
following constructor:
// C++
QName::QName(
const String & namespace_prefix,
const String & local_part,
const String & namespace_uri
)
Because the namespace prefix is relatively unimportant, you can leave it
blank. For example, to create a QName for the <soap:address> element:
// C++
IT_Bus::QName soap_address = new IT_Bus::QName(
"",
"address",
"http://schemas.xmlsoap.org/wsdl/soap"
);
QName member functions The IT_Bus::QName class has the following public member functions:
const IT_Bus::String &
get_namespace_prefix() const;
123
CHAPTER 7 | Artix Data Types
QName equality The == operator can be used to test for equality of IT_Bus::QName objects.
QNames are tested for equality as follows:
1. Assuming that a namespace URI is defined for the QNames, the
QNames are equal if their namespace URIs match and the local part of
their element names match.
2. If one of the QNames lacks a namespace URI (empty string), the
QNames are equal if their namespace prefixes match and the local part
of their element names match.
124
Simple Types
The default constructor takes no parameters and initializes all of the fields to
zero. An alternative constructor is provided, which accepts all of the
individual date/time fields, as follows:
125
CHAPTER 7 | Artix Data Types
Decimal Type
Overview xsd:decimal maps to IT_Bus::Decimal, which is implemented by the IONA
foundation class IT_FixedPoint, defined in <it_dsa/fixed_point.h>.
IT_FixedPoint provides full fixed point decimal calculation logic using the
standard C++ operators.
Description Operators
126
Simple Types
C++ example The following C++ example shows how to perform some elementary
arithmetic using the IT_Bus::Decimal type.
// C++
IT_Bus::Decimal d1 = "123.456";
IT_Bus::Decimal d2 = "87654.321";
IT_Bus::Decimal d3 = d1+d2;
d3 *= d1;
if (d3 > 100000) {
cout << "d3 = " << d3;
}
127
CHAPTER 7 | Artix Data Types
Binary Types
Overview There are two WSDL binary types, which map to C++ as shown in Table 8:
xsd:base64Binary IT_Bus::Base64Binary
xsd:hexBinary IT_Bus::HexBinary
Encoding The only difference between HexBinary and Base64Binary is the way they
are encoded for transmission. The Base64Binary encoding is more compact
because it uses a larger set of symbols in the encoding. The encodings can
be compared as follows:
• HexBinary—the hex encoding uses a set of 16 symbols [0-9a-fA-F],
ignoring case, and each character can encode 4 bits. Hence, two
characters represent 1 byte (8 bits).
• Base64Binary—the base 64 encoding uses a set of 64 symbols and
each character can encode 6 bits. Hence, four characters represent 3
bytes (24 bits).
IT_Bus::Base64Binary and Both the IT_Bus::Base64Binary and the IT_Bus::HexBinary classes expose
IT_Bus::HexBinary classes a similar set of member functions, as follows:
// C++
size_t get_length() const;
void set_data(
IT_Bus::Byte data[],
size_t data_length,
bool take_ownership = false
);
128
Simple Types
C++ example Consider a port type that defines an echoHexBinary operation. The
echoHexBinary operation takes an IT_Bus::HexBinary type as an in
parameter and then echoes this value in the response. Example 40 shows
how a server might implement the echoHexBinary operation.
// C++
using namespace IT_Bus;
...
void BaseImpl::echoHexBinary(
const IT_Bus::HexBinaryInParam & inputHexBinary,
IT_Bus::HexBinaryOutParam& Response
)
IT_THROW_DECL((IT_Bus::Exception))
{
cout << "BaseImpl::echoHexBinary called" << endl;
size_t length = inputHexBinary.get_length();
Byte * the_data = new Byte[length];
129
CHAPTER 7 | Artix Data Types
Unchecked facets The following facets can be used, but are not checked at runtime:
• length
• minLength
• maxLength
• pattern
• enumeration
• whiteSpace
• maxInclusive
• maxExclusive
• minInclusive
• minExclusive
• totalDigits
• fractionDigits
Checked facets The following facets are supported and checked at runtime:
• enumeration
130
Simple Types
Restriction with an enumeration Artix supports the restriction of simple types using the enumeration facet.
facet The base simple type can be any simple type except xsd:boolean.
When an enumeration type is mapped to C++, the C++ implementation of
the type ensures that instances of this type can only be set to one of the
enumerated values. If set_value() is called with an illegal value, it throws
an IT_Bus::Exception exception.
WSDL example of enumeration Example 41 shows an example of a ColorEnum type, which is defined by
facet restriction from the xsd:string type using the enumeration facet. When
defined in this way, the ColorEnum restricted type is only allowed to take on
one of the string values RED, GREEN, or BLUE.
131
CHAPTER 7 | Artix Data Types
C++ mapping of enumeration The WSDL-to-C++ compiler maps the ColorEnum restricted type to the
facet ColorEnum C++ class, as shown in Example 42. The only values that can
legally be set using the set_value() member function are the strings RED,
GREEN, or BLUE.
// C++
class ColorEnum : public IT_Bus::AnySimpleType
{
...
public:
ColorEnum();
ColorEnum(const IT_Bus::String & value);
...
132
Simple Types
133
CHAPTER 7 | Artix Data Types
Complex Types
Overview This section describes the WSDL-to-C++ mapping for complex types.
Complex types are defined within an XML schema. In contrast to simple
types, complex types can contain elements and carry attributes.
134
Complex Types
Occurrence constraints Occurrence constraints, which are specified using the minOccurs and
maxOccurs attributes, are supported for sequence complex types. See
“Occurrence Constraints” on page 154.
<schema targetNamespace="http://soapinterop.org/xsd"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<complexType name="SequenceType">
<sequence>
<element name="varFloat" type="xsd:float"/>
<element name="varInt" type="xsd:int"/>
<element name="varString" type="xsd:string"/>
</sequence>
</complexType>
...
</schema>
135
CHAPTER 7 | Artix Data Types
C++ mapping The WSDL-to-C++ compiler maps the preceding WSDL (Example 43) to
the SequenceType C++ class. An outline of this class is shown in
Example 44.
// C++
class SequenceType : public IT_Bus::SequenceComplexType
{
public:
SequenceType();
SequenceType(const SequenceType& copy);
virtual ~SequenceType();
...
virtual const IT_Bus::QName & get_type() const;
private:
...
};
136
Complex Types
C++ example Consider a port type that defines an echoSequence operation. The
echoSequence operation takes a SequenceType type as an in parameter and
then echoes this value in the response. Example 45 shows how a client
could use a proxy instance, bc, to invoke the echoSequence operation.
// C++
SequenceType seqIn, seqResult;
seqIn.setvarFloat(3.14159);
seqIn.setvarInt(54321);
seqIn.setvarString("You can use a string constant here.");
try {
bc.echoSequence(seqIn, seqResult);
if((seqResult.getvarInt() != seqIn.getvarInt()) ||
(seqResult.getvarFloat() != seqIn.getvarFloat()) ||
(seqResult.getvarString().compare(seqIn.getvarString()) !=
0))
{
cout << endl << "echoSequence FAILED" << endl;
return;
}
} catch (IT_Bus::FaultException &ex)
{
cout << "Caught Unexpected FaultException" << endl;
cout << ex.get_description().c_str() << endl;
}
137
CHAPTER 7 | Artix Data Types
Occurrence constraints Occurrence constraints are currently not supported for choice complex
types.
WSDL example Example 46 shows an example of a choice complex type, ChoiceType, with
three elements.
<schema targetNamespace="http://soapinterop.org/xsd"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<complexType name="ChoiceType">
<choice>
<element name="varFloat" type="xsd:float"/>
<element name="varInt" type="xsd:int"/>
<element name="varString" type="xsd:string"/>
</choice>
</complexType>
...
</schema>
138
Complex Types
C++ mapping The WSDL-to-C++ compiler maps the preceding WSDL (Example 46) to
the SequenceType C++ class. An outline of this class is shown in
Example 47.
// C++
class ChoiceType : public IT_Bus::ChoiceComplexType
{
public:
ChoiceType();
ChoiceType(const ChoiceType& copy);
virtual ~ChoiceType();
...
virtual const IT_Bus::QName & get_type() const ;
139
CHAPTER 7 | Artix Data Types
enum ChoiceTypeDiscriminator
{
varFloat,
varInt,
varString,
ChoiceType_MAXLONG=-1L
} m_discriminator;
private:
...
};
C++ example Consider a port type that defines an echoChoice operation. The echoChoice
operation takes a ChoiceType type as an in parameter and then echoes this
value in the response. Example 48 shows how a client could use a proxy
instance, bc, to invoke the echoChoice operation.
// C++
ChoiceType cIn, cResult;
// Initialize and select the ChoiceType::varString label.
cIn.setvarString("You can use a string constant here.");
try {
140
Complex Types
bc.echoChoice(cIn, cResult);
if (fail) {
cout << endl << "echoChoice FAILED" << endl;
return;
}
} catch (IT_Bus::FaultException &ex)
{
cout << "Caught Unexpected FaultException" << endl;
cout << ex.get_description().c_str() << endl;
}
141
CHAPTER 7 | Artix Data Types
Note: An all complex type can only be declared as the outermost group of
a complex type. Hence, you cannot nest an all model group, <all>,
directly inside other model groups, <all>, <sequence>, or <choice>. You
may, however, define an all complex type and then declare an element of
that type within the scope of another model group.
Occurrence constraints Occurrence constraints are supported for the elements of XML schema all
complex types.
WSDL example Example 49 shows an example of an all complex type, AllType, with three
elements.
<schema targetNamespace="http://soapinterop.org/xsd"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<complexType name="AllType">
<all>
<element name="varFloat" type="xsd:float"/>
<element name="varInt" type="xsd:int"/>
<element name="varString" type="xsd:string"/>
</all>
</complexType>
...
</schema>
142
Complex Types
C++ mapping The WSDL-to-C++ compiler maps the preceding WSDL (Example 49) to
the AllType C++ class. An outline of this class is shown in Example 50.
// C++
class AllType : public IT_Bus::AllComplexType
{
public:
AllType();
AllType(const AllType& copy);
virtual ~AllType();
private:
...
};
143
CHAPTER 7 | Artix Data Types
C++ example Consider a port type that defines an echoAll operation. The echoAll
operation takes an AllType type as an in parameter and then echoes this
value in the response. Example 51 shows how a client could use a proxy
instance, bc, to invoke the echoAll operation.
// C++
AllType allIn, allResult;
allIn.setvarFloat(3.14159);
allIn.setvarInt(54321);
allIn.setvarString("You can use a string constant here.");
try {
bc.echoAll(allIn, allResult);
if((allResult.getvarInt() != allIn.getvarInt()) ||
(allResult.getvarFloat() != allIn.getvarFloat()) ||
(allResult.getvarString().compare(allIn.getvarString()) !=
0))
{
cout << endl << "echoAll FAILED" << endl;
return;
}
} catch (IT_Bus::FaultException &ex)
{
cout << "Caught Unexpected FaultException" << endl;
cout << ex.get_description().c_str() << endl;
}
144
Complex Types
Attributes
Overview Artix supports the use of <attribute> declarations within the scope of a
<complexType> definition. For example, you can include attributes in the
definitions of an all complex type, sequence complex type, and choice
complex type. The declaration of an attribute in a complex type must
conform to the following syntax:
<attribute name="AttrName" type="AttrType"/>
WSDL example Example 52 shows how to define a sequence type with a single attribute,
prop, of xsd:string type.
<complexType name="SequenceType">
<sequence>
<element name="varFloat" type="xsd:float"/>
<element name="varInt" type="xsd:int"/>
<element name="varString" type="xsd:string"/>
</sequence>
<attribute name="prop" type="xsd:string"/>
</complexType>
145
CHAPTER 7 | Artix Data Types
C++ mapping Example 53 shows an outline of the C++ SequenceType class generated
from Example 52 on page 145, which defines accessor and modifier
functions for the prop attribute.
// C++
class SequenceType : public IT_Bus::SequenceComplexType
{
public:
SequenceType();
...
const IT_Bus::String & getprop() const;
IT_Bus::String & getprop();
146
Complex Types
Avoiding anonymous types In general, it is a good idea to name types that are nested inside other types,
instead of using anonymous types. This results in simpler code when the
types are mapped to C++.
For an example of the recommended style of declaration, with a named
nested type, see Example 54.
WSDL example Example 54 shows an example of a nested complex type, which features a
choice complex type, NestedChoiceType, nested inside a sequence complex
type, SeqOfChoiceType.
<schema targetNamespace="http://soapinterop.org/xsd"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<complexType name="NestedChoiceType">
<choice>
<element name="varFloat" type="xsd:float"/>
<element name="varInt" type="xsd:int"/>
</choice>
</complexType>
<complexType name="SeqOfChoiceType">
<sequence>
<element name="varString" type="xsd:string"/>
<element name="varChoice" type="xsd1:NestedChoiceType"/>
</sequence>
</complexType>
...
</schema>
147
CHAPTER 7 | Artix Data Types
C++ mapping of The XML schema choice complex type, NestedChoiceType, is a simple
NestedChoiceType choice complex type, which is mapped to C++ in the standard way.
Example 55 shows an outline of the generated C++ NestedChoiceType
class.
// C++
class NestedChoiceType : public IT_Bus::ChoiceComplexType
{
...
public:
NestedChoiceType();
NestedChoiceType(const NestedChoiceType& copy);
virtual ~NestedChoiceType();
private:
...
};
C++ mapping of The XML schema sequence complex type, SeqOfChoiceType, has the
SeqOfChoiceType NestedChoiceType nested inside it. Example 56 shows an outline of the
generated C++ SeqOfChoiceType class, which shows how the nested
complex type is mapped within a sequence complex type.
// C++
class SeqOfChoiceType : public IT_Bus::SequenceComplexType
{
...
148
Complex Types
public:
SeqOfChoiceType();
SeqOfChoiceType(const SeqOfChoiceType& copy);
virtual ~SeqOfChoiceType();
...
virtual const IT_Bus::QName & get_type() const;
private:
...
};
C++ example Consider a port type that defines an echoSeqOfChoice operation. The
echoSeqOfChoice operation takes a SeqOfChoiceType type as an in
parameter and then echoes this value in the response. Example 51 shows
how a client could use a proxy instance, bc, to invoke the echoSeqOfChoice
operation.
// C++
NestedChoiceType nested;
nested.setvarFloat(3.14159);
149
CHAPTER 7 | Artix Data Types
if(
(seqResult.getvarString().compare(seqIn.getvarString()) != 0)
||
(seqResult.getvarChoice().get_discriminator()
!=seqIn.getvarChoice().get_discriminator()))
{
cout << endl << "echoSeqOfChoice FAILED" << endl;
return;
}
} catch (IT_Bus::FaultException &ex)
{
cout << "Caught Unexpected FaultException" << endl;
cout << ex.get_description().c_str() << endl;
}
150
Complex Types
<xsd:complexType name="orderNumber">
<xsd:simpleContent>
<xsd:restriction base="xsd:decimal">
<xsd:maxExclusive value="1000000"/>
</xsd:restriction>
</xsd:simpleContent>
</xsd:complexType>
The <simpleContent> tag indicates that the new type does not contain any
sub-elements and the <restriction> tag defines the derivation by
restriction from xsd:decimal.
151
CHAPTER 7 | Artix Data Types
<xsd:complexType name="internationalPrice">
<xsd:simpleContent>
<xsd:extension base="xsd:decimal">
<xsd:attribute name="currency" type="xsd:string"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
The <simpleContent> tag indicates that the new type does not contain any
sub-elements and the <extension> tag defines the derivation by extension
from xsd:decimal.
// C++
class internationalPrice : public
IT_Bus::SimpleContentComplexType
{
...
public:
internationalPrice();
internationalPrice(const internationalPrice& copy);
virtual ~internationalPrice();
...
virtual const IT_Bus::QName & get_type() const;
152
Complex Types
153
CHAPTER 7 | Artix Data Types
Occurrence Constraints
Overview You define occurrence constraints on a schema element by setting the
minOccurs and maxOccurs attributes for the element. Hence, the definition
of an element with occurrence constraints in an XML schema has the
following form:
<element name="ElemName" type="ElemType" minOccurs="LowerBound"
maxOccurs="UpperBound"/>
Limitations In the current version of Artix, occurrence constraints can be used only
within the following complex types:
• all complex types,
• sequence complex types.
Occurrence constraints are not supported within the scope of the following:
• choice complex types.
Element lists Lists of elements appearing within a sequence complex type are represented
in C++ by the IT_Bus::ElementListT template. For most purposes, you
can treat the element list types as if they were IT_Vector (see “IT_Vector
Template Class” on page 202). The IT_Bus::ElementListT types
automatically convert to and from IT_Vector types.
In addition to the standard member functions and operators defined by
IT_Vector, the element list types support the following member functions:
// C++
size_t get_min_occurs() const;
154
Complex Types
WSDL example Example 61 shows the definition of a sequence type, SequenceType, which
contains a list of integer elements followed by a list of string elements.
C++ mapping Example 62 shows an outline of the C++ SequenceType class generated
from Example 61 on page 155, which defines accessor and modifier
functions for the varInt and varString elements.
// C++
class SequenceType : public IT_Bus::SequenceComplexType
{
public:
...
virtual const IT_Bus::QName &
get_type() const;
155
CHAPTER 7 | Artix Data Types
const IT_Bus::ElementListT<IT_Bus::String,
&m_varString_qname, 0, -1> & getvarString() const;
IT_Bus::ElementListT<IT_Bus::String, &m_varString_qname, 0,
-1> & getvarString();
private:
...
};
C++ example The following code fragment shows how to allocate and initialize an
instance of SequenceType type containing two varInt elements and two
varString elements:
// C++
SequenceType seq;
seq.getvarInt().set_size(2);
seq.getvarInt()[0] = 10;
seq.getvarInt()[1] = 20;
seq.getvarString().set_size(2);
seq.getvarString()[0] = "Zero";
seq.getvarString()[1] = "One";
156
Complex Types
Note how the set_size() function and [] operator are invoked directly on
the member vectors, which are accessed by getvarInt() and
getvarString() respectively. This is more efficient than creating a vector
and passing it to setvarInt() or setvarString(), because it avoids
creating unnecessary temporary vectors.
Alternatively, you could assign the member vectors, seq.getvarInt() and
seq.getvarString(), to references of IT_Vector type and manipulate the
references, v1 and v2, instead. This is shown in the following code example:
// C++
SequenceType seq;
v1.push_back(10);
v1.push_back(20);
v2.push_back("Zero");
v2.push_back("One");
In this example, the vectors are initialized using the push_back() stack
operation (adds an element to the end of the vector).
Note: The IT_Vector class template does not provide the set_size()
function. Hence, you cannot invoke set_size() on v1 or v2.
157
CHAPTER 7 | Artix Data Types
Arrays
Overview This subsection describes how to define and use basic Artix array types. In
addition to these basic array types, Artix also supports SOAP arrays, which
are discussed in “SOAP Arrays” on page 190.
Array definition syntax An array is a sequence complex type that satisfies the following special
conditions:
• The sequence complex type schema defines a single element only.
• The element definition has a maxOccurs attribute with a value greater
than 1.
Mapping to IT_Vector When a sequence complex type declaration satisfies the special conditions
to be an array, it is mapped to C++ differently from a regular sequence
complex type. The principal difference is that the C++ array class,
ArrayName, can be treated as a vector.
For example, the C++ array class, ArrayName, supports the size()
member function and individual elements can be accessed using the []
operator.
158
Complex Types
WSDL array example Example 63 shows how to define a one-dimensional string array,
ArrayOfString, whose size can lie anywhere in the range 0 to unbounded.
C++ mapping Example 64 shows how the ArrayOfString string array (from Example 63
on page 159) maps to C++.
// C++
class ArrayOfString : public IT_Bus::ArrayT<IT_Bus::String,
&ArrayOfString_varString_qname, 0, -1>
{
public:
ArrayOfString();
ArrayOfString(size_t dimensions[]);
ArrayOfString(size_t dimension0);
ArrayOfString(const ArrayOfString& copy);
virtual ~ArrayOfString();
const IT_Bus::ElementListT<IT_Bus::String,
&ArrayOfString_varString_qname, 0, -1> & getvarString()
const;
159
CHAPTER 7 | Artix Data Types
IT_Bus::ElementListT<IT_Bus::String,
&ArrayOfString_varString_qname, 0, -1> & getvarString();
};
// C++
// Array of String
ArrayOfString a(4);
a[0] = "One";
a[1] = "Two";
a[2] = "Three";
a[3] = "Four";
160
Complex Types
Multi-dimensional arrays You can define multi-dimensional arrays by nesting array definitions (see
“Nesting Complex Types” on page 147 for a discussion of nested types).
Example 66 shows an example of how to define a two-dimensional string
array, ArrayOfArrayOfString.
Both the nested array type, ArrayOfArrayOfString, and the sub-array type,
ArrayOfString, must conform to the standard array definition syntax.
Multi-dimensional arrays can be nested to an arbitrary degree, but each
sub-array must be a named type (that is, anonymous nested array types are
not supported).
C++ example for Example 67 shows an example of how to allocate and initialize a
multidimensional array multi-dimensional array, of ArrayOfArrayOfString type.
// C++
// Array of array of String
ArrayOfArrayOfString a2(2,2);
161
CHAPTER 7 | Artix Data Types
a2[0][0] = "ZeroZero";
a2[0][1] = "ZeroOne";
a2[1][0] = "OneZero";
a2[1][1] = "OneOne";
// C++
size_t extents[] = {2, 2};
ArrayOfArrayOfString a2(extents);
cout << v_a2[0][0] << " " << v_a2[0][1] << " "
<< v_a2[1][0] << " " << v_a2[1][1] << endl;
cout << "v_a2.size() = " << v_a2.size() << endl;
162
Complex Types
163
CHAPTER 7 | Artix Data Types
anyType Type
Overview In an XML schema, the xsd:anyType is the base type from which other
simple and complex types are derived. Hence, an element declared to be of
xsd:anyType type can contain any XML type.
Prerequisite for using anyType A prerequisite for using the xsd:anyType is that your application must be
built with the WSDLFileName_wsdlTypesFactory.cxx source file. This file
is generated automatically by the WSDL-to-C++ compiler utility.
C++ mapping The WSDL-to-C++ compiler maps the xsd:anyType type to the
IT_Bus::AnyHolder class in C++.
The IT_Bus::AnyHolder class provides member functions to insert and
extract data values, as follows:
• Inserting and extracting atomic types.
• Inserting and extracting user-defined types.
164
anyType Type
Inserting and extracting atomic To insert and extract atomic types to and from an IT_Bus::AnyHolder, use
types the member functions of the following form:
void set_AtomicTypeFunc(const AtomicTypeName&);
AtomicTypeName& get_AtomicTypeFunc();
const AtomicTypeName& get_AtomicTypeFunc();
For a complete list of the functions for the basic atomic types, see
“AnyHolder API” on page 167.
For example, you can insert and extract an xsd:short integer to and from an
IT_Bus::AnyHolder as follows:
// C++
// Insert an xsd:short value into an xsd:anyType.
IT_Bus::AnyHolder aH;
aH.set_short(1234);
...
// Extract an xsd:short value from an xsd:anyType.
IT_Bus::Short sh = aH.get_short();
Inserting and extracting To insert and extract user-defined types from an IT_Bus::AnyHolder, use
user-defined types the following functions:
void set_any_type(const IT_Bus::AnyType &);
IT_Bus::AnyType& get_any_type();
const IT_Bus::AnyType& get_any_type();
Note that all user-defined types inherit from IT_Bus::AnyType. There are no
type-specific insertion or extraction functions generated for user-defined
types.
Memory management for these functions is handled as follows:
• The set_any_type() function copies the inserted data.
• The get_any_type() functions do not copy the return value, rather
they return either a writable (non-const) or read-only (const) reference
to the data inside the IT_Bus::AnyHolder.
165
CHAPTER 7 | Artix Data Types
// C++
// Create an instance of SequenceType type.
SequenceType seq;
seq.setvarFloat(3.14);
seq.setvarInt(1234);
seq.setvarString("This is a sample SequenceType.");
// C++
...
// Extract the SequenceType value from the IT_Bus::AnyHolder.
IT_Bus::AnyType base_extract = aH.get_any_type();
Accessing the type information You can find out what type of data is contained in an IT_Bus::AnyHolder
instance by calling the following member function:
const IT_Bus::QName & get_type() const;
Type information is set whenever an IT_Bus::AnyHolder instance is
initialized. For example, if you initialize an IT_Bus::AnyHolder by calling
set_boolean(), the type is set to be xsd:boolean. If you call
set_any_type() with an argument of SequenceType, the type would be set
to xsd1:SequenceType.
166
anyType Type
AnyHolder API Example 69 shows the public API from the IT_Bus::AnyHolder class,
including all of the function for inserting and extracting data values.
// C++
namespace IT_Bus
{
class IT_BUS_API AnyHolder : public AnyType
{
public:
AnyHolder();
virtual ~AnyHolder() ;
...
virtual const QName & get_type() const ;
...
//Set Methods
void set_boolean(const IT_Bus::Boolean &);
void set_byte(const IT_Bus::Byte &);
void set_short(const IT_Bus::Short &);
void set_int(const IT_Bus::Int &);
void set_long(const IT_Bus::Long &);
void set_string(const IT_Bus::String &);
void set_float(const IT_Bus::Float &);
void set_double(const IT_Bus::Double &);
void set_ubyte(const IT_Bus::UByte &);
void set_ushort(const IT_Bus::UShort &);
void set_uint(const IT_Bus::UInt &);
void set_ulong(const IT_Bus::ULong &);
void set_decimal(const IT_Bus::Decimal &);
//GET METHODS
IT_Bus::Boolean & get_boolean();
IT_Bus::Byte & get_byte();
IT_Bus::Short & get_short();
IT_Bus::Int & get_int();
IT_Bus::Long & get_long();
IT_Bus::String & get_string();
IT_Bus::Float & get_float();
IT_Bus::Double & get_double();
IT_Bus::UByte & get_ubyte() ;
IT_Bus::UShort & set_ushort();
IT_Bus::UInt & get_uint();
IT_Bus::ULong & set_ulong();
167
CHAPTER 7 | Artix Data Types
AnyType& get_any_type();
168
Nillable Types
Nillable Types
Overview This section describes how to define and use nillable types; that is, XML
elements defined with xsd:nillable="true".
169
CHAPTER 7 | Artix Data Types
On-the-wire format On the wire, a nil value for an <ElementName> element is represented by
the following XML fragment:
<ElementName xsi:nil="true"></ElementName>
Where the xsi: prefix represents the XML schema instance namespace,
http://www.w3.org/2001/XMLSchema-instance.
C++ API for nillable types Example 70 shows the public member functions of the
IT_Bus::NillableValue class, which provides the C++ API for nillable
types.
// C++
namespace IT_Bus
{
template <class T, const QName* TYPE>
class NillableValue : public Nillable
{
public:
NillableValue();
NillableValue(const NillableValue& other);
explicit NillableValue(const T& other);
virtual ~NillableValue();
...
virtual const QName& get_type() const;
virtual Boolean is_nil() const;
170
Nillable Types
...
virtual const T&
get() const IT_THROW_DECL((NoDataException));
virtual T&
get() IT_THROW_DECL((NoDataException));
171
CHAPTER 7 | Artix Data Types
Table of nillable atomic types Table 9 shows how the XML schema atomic types map to C++ when the
xsd:nillable flag is set to true.
xsd:boolean IT_Bus::BooleanNillable
xsd:byte IT_Bus::ByteNillable
xsd:unsignedByte IT_Bus::UByteNillable
xsd:short IT_Bus::ShortNillable
xsd:unsignedShort IT_Bus::UShortNillable
xsd:int IT_Bus::IntNillable
xsd:unsignedInt IT_Bus::UIntNillable
xsd:long IT_Bus::LongNillable
xsd:unsignedLong IT_Bus::ULongNillable
xsd:float IT_Bus::FloatNillable
xsd:double IT_Bus::DoubleNillable
xsd:string IT_Bus::StringNillable
xsd:QName IT_Bus::QNameNillable
172
Nillable Types
xsd:dateTime IT_Bus::DateTimeNillable
xsd:decimal IT_Bus::DecimalNillable
xsd:base64Binary IT_Bus::BinaryBufferNillable
xsd:hexBinary IT_Bus::BinaryBufferNillable
173
CHAPTER 7 | Artix Data Types
</message>
<message name="NilPartResponse">
<part name="return" element="xsd1:test_int_return"/>
<part name="y" element="xsd1:test_short_y"/>
<part name="z" element="xsd1:test_float_z"/>
</message>
...
<portType name="BasePortType">
<operation name="send_receive_nil_part">
<input name="doclit_nil_part_request"
message="tns:NilPartRequest"/>
<output name="doclit_nil_part_response"
message="tns:NilPartResponse"/>
</operation>
</portType>
...
// C++
IT_Bus::StringNillable x("String for sending");
IT_Bus::ShortNillable y(321);
IT_Bus::IntNillable var_return;
IT_Bus::FloatNillable z;
try {
// bc is a client proxy for the BasePortType port type.
bc.send_receive_nil_part(x, y, var_return, z);
}
catch (IT_Bus::FaultException &ex) {
// ... deal with the exception (not shown)
}
if (! var_return.is_nil()) {
cout << "var_return = " << var_return.get() << endl;
}
174
Nillable Types
175
CHAPTER 7 | Artix Data Types
WSDL example Example 73 shows the definition of an XML schema all complex type,
named SOAPStruct. This is a complex type with ordinary (that is,
non-nillable) member elements.
176
Nillable Types
C++ mapping Example 74 shows how the SOAPStruct type maps to C++. In addition to
the regular mapping, which produces the C++ SOAPStruct and
SOAPStructPtr classes, the WSDL-to-C++ compiler also generates a
nillable type, SOAPStructNillable, and an associated smart pointer type,
SOAPStructNillablePtr.
// C++
namespace INTEROP
{
class SOAPStruct : public IT_Bus::AllComplexType { ... }
typedef IT_AutoPtr<SOAPStruct> SOAPStructPtr;
C++ example The following C++ example shows how to initialize an instance of
SOAPStructNillable type, s_nillable. The nillable type is created in two
steps: first of all, a SOAPStruct instance, s, is initialized; then the
SOAPStruct instance is used to initialize a SOAPStructNillable instance.
// C++
// Initialize a SOAPStruct instance.
INTEROP::SOAPStruct s;
s.setvarFloat(3.14);
s.setvarInt(1234);
s.setvarString("Hello world!");
177
CHAPTER 7 | Artix Data Types
The next C++ example shows how to access the contents of the
SOAPStructNillable type. Note that before attempting to access the value
of the SOAPStructNillable using get(), you should check that the value is
not nil using is_nil().
// C++
if (! s_nillable.is_nil()) {
cout << "varFloat = " << s_nillable.get().getvarFloat()
<< endl;
cout << "varInt = " << s_nillable.get().getvarInt()
<< endl;
cout << "varString = " << s_nillable.get().getvarString()
<< endl;
}
178
Nillable Types
WSDL example Example 75 defines a sequence complex type, Nil_SOAPStruct, which has
some nillable elements, varInt, varFloat, and varString.
179
CHAPTER 7 | Artix Data Types
C++ mapping Example 76 shows how the Nil_SOAPStruct sequence complex type is
mapped to C++. Note how the modifiers and accessors for the nillable
member elements, setElementName() and getElementName(), take
pointer arguments and return pointers instead of actual values. For example,
the getvarInt() function returns a pointer to an IT_Bus::Int rather an
IT_Bus::Int value.
// C++
namespace INTEROP {
class Nil_SOAPStruct : public IT_Bus::SequenceComplexType
{
public:
Nil_SOAPStruct();
Nil_SOAPStruct(const Nil_SOAPStruct& copy);
virtual ~Nil_SOAPStruct();
...
const IT_Bus::Int * getvarInt() const;
IT_Bus::Int * getvarInt();
void setvarInt(const IT_Bus::Int * val);
180
Nillable Types
};
typedef IT_Bus::NillableValue<Nil_SOAPStruct,
&Nil_SOAPStructQName> Nil_SOAPStructNillable;
typedef IT_Bus::NillablePtr<Nil_SOAPStruct,
&Nil_SOAPStructQName> Nil_SOAPStructNillablePtr;
...
};
C++ example The following C++ example shows how to create and initialize a
Nil_SOAPStruct instance. Notice, for example, how the argument to
setvarInt() is a pointer value, &i.
// C++
Nil_SOAPStruct nil_s;
IT_Bus::Float f = 3.14;
IT_Bus::Int i = 1234;
IT_Bus::String s = "A non-nil string.";
nil_s.setvarInt(&i);
nil_s.setvarFloat(&f);
nil_s.setvarString(&s);
The next C++ example shows how to read the nillable elements of the
Nil_SOAPStruct instance. Note how the elements are checked for nilness by
comparing the result of calling getElementName() with 0.
181
CHAPTER 7 | Artix Data Types
// C++
if (nil_s.getvarInt() != 0) {
cout << "varInt = " << *nil_s.getvarInt() << endl;
}
if (nil_s.getvarFloat() != 0) {
cout << "varFloat = " << *nil_s.getvarFloat() << endl;
}
if (nil_s.getvarString() != 0) {
cout << "varString = " << *nil_s.getvarString() << endl;
}
182
Nillable Types
Example 77: WSDL Example of a Nillable All Type inside a Sequence Type
183
CHAPTER 7 | Artix Data Types
Example 77: WSDL Example of a Nillable All Type inside a Sequence Type
</complexType>
...
<complexType name="Nil_NestedSOAPStruct">
<sequence>
<element name="varInt" nillable="true"
type="xsd:int"/>
<element name="varSOAP" nillable="true"
type="xsd1:SOAPStruct"/>
</sequence>
</complexType>
...
</schema>
</types>
...
C++ mapping Example 78 shows how the Nil_NestedSOAPStruct sequence complex type
is mapped to C++. Note how the getvarSOAP() function returns a pointer
to a SOAPStruct rather a SOAPStruct value. Likewise, the setvarSOAP()
function takes a SOAPStruct pointer as its argument.
// C++
class Nil_NestedSOAPStruct : public IT_Bus::SequenceComplexType
{
public:
Nil_NestedSOAPStruct();
Nil_NestedSOAPStruct(const Nil_NestedSOAPStruct& copy);
virtual ~Nil_NestedSOAPStruct();
...
const IT_Bus::Int * getvarInt() const;
IT_Bus::Int * getvarInt();
void setvarInt(const IT_Bus::Int * val);
184
Nillable Types
NillablePtr types To help you manage the memory associated with nillable elements of
user-defined type, UserType, the WSDL-to-C++ utility generates a nillable
smart pointer type, UserTypeNillablePtr. The NillablePtr template types
are similar to the std::auto_ptr<> template types from the Standard
Template Library—see “Smart Pointers” on page 42.
For example, the following extract from the generated
WSDLFileName_wsdlTypes.h header file defines a SOAPStructNillablePtr
type, which is used to represent SOAPStruct nillable pointers:
// C++
typedef IT_Bus::NillablePtr<SOAPStruct, &SOAPStructQName>
SOAPStructNillablePtr;
// C++
namespace IT_Bus
{
/**
* Template implementation of Nillable as an auto_ptr.
* T is the C++ type of data, TYPE is the data type qname.
*/
template <class T, const QName* TYPE>
class NillablePtr : public Nillable, public IT_AutoPtr<T>
{
public:
NillablePtr();
NillablePtr(const NillablePtr& other);
NillablePtr(T* data);
virtual ~NillablePtr();
...
void set(const T* data);
185
CHAPTER 7 | Artix Data Types
...
};
C++ example The following C++ example shows how to create and initialize a
Nil_NestedSOAPStruct instance. Notice, for example, how the argument
passed to setvarSOAP() is a pointer, &nillable_struct.
// C++
// Construct a smart nillable pointer.
// The SOAPStruct memory is owned by the smart nillable pointer.
SOAPStruct nillable_struct;
nillable_struct.setvarFloat(3.14);
nillable_struct.setvarInt(4321);
nillable_struct.setvarString("Nillable struct element.");
The next C++ example shows how to read the nillable elements of the
Nil_NestedSOAPStruct instance. Note how the varSOAP element is checked
for nilness by calling is_nil().
// C++
IT_Bus::Int * int_p = outer_struct.getvarInt();
if (int_p != 0) {
cout << "varInt = " << *int_p << endl;
}
if (!nillable_struct_p.is_nil() ) {
cout << "varSOAP = " << *nillable_struct_p << endl;
}
186
Nillable Types
WSDL example Example 80 shows defines an array complex type, Nil_SOAPArray (the
name indicates that the type is used in a SOAP example, not that it is
defined using SOAP array syntax) which has nillable array elements, item.
187
CHAPTER 7 | Artix Data Types
<complexType name="Nil_SOAPArray">
<sequence>
<element name="item" nillable="true"
type="xsd:short" minOccurs="10"
maxOccurs="10"/>
</sequence>
</complexType>
...
</schema>
</types>
...
C++ mapping Example 81 shows how the Nil_SOAPArray array complex type is mapped
to C++. Note that the array elements are of IT_Bus::ShortNillable type.
// C++
namespace INTEROP {
class Nil_SOAPArray
: public IT_Bus::ArrayT<IT_Bus::ShortNillable,
&Nil_SOAPArray_item_qname, 10, 10>
{
public:
Nil_SOAPArray();
Nil_SOAPArray(const Nil_SOAPArray& copy);
Nil_SOAPArray(size_t dimensions[]);
Nil_SOAPArray(size_t dimension0);
virtual ~Nil_SOAPArray();
...
const IT_Bus::ElementListT<IT_Bus::ShortNillable,
&Nil_SOAPArray_item_qname, 10, 10> &
getitem() const;
IT_Bus::ElementListT<IT_Bus::ShortNillable,
&Nil_SOAPArray_item_qname, 10, 10> &
getitem();
void
setitem(const IT_Vector<IT_Bus::ShortNillable> & val);
188
Nillable Types
get_type() const;
};
typedef IT_Bus::NillableValue<Nil_SOAPArray,
&Nil_SOAPArrayQName> Nil_SOAPArrayNillable;
typedef IT_Bus::NillablePtr<Nil_SOAPArray,
&Nil_SOAPArrayQName> Nil_SOAPArrayNillablePtr;
};
C++ example The following C++ example shows how to create and initialize a
Nil_SOAPArray instance. Because each array element is of
IT_Bus::ShortNillable type, the array elements must be initialized using
the set() member function. Any elements not explicitly initialized are nil by
default.
// C++
Nil_SOAPArray nil_s(10);
nil_s[0].set(10);
nil_s[1].set(20);
nil_s[2].set(30);
nil_s[3].set(40);
nil_s[4].set(50);
// The remaining five element values are left as nil.
The next C++ example shows how to access the nillable array elements.
You should check each of the array elements for nilness using the is_nil()
member function before attempting to read an array element value.
// C++
for (size_t i=0; i<10; i++) {
if (! nil_s[i].is_nil()) {
cout << "Nil_SOAPArray[" << i << "] = "
<< nil_s[i].get() << endl;
}
}
189
CHAPTER 7 | Artix Data Types
SOAP Arrays
Overview In addition to the basic array types described in “Arrays” on page 158, Artix
also provides support for SOAP arrays. SOAP arrays have a relatively rich
feature set, including support for sparse arrays and partially transmitted
arrays. Consequently, Artix implements a distinct C++ mapping specifically
for SOAP arrays, which is different from the C++ mapping described in the
“Arrays” section.
190
SOAP Arrays
Syntax In general, SOAP array types are defined by deriving from the
SOAP-ENC:Array base type (deriving by restriction). The type definition must
conform to the following syntax:
<complexType name="<SOAPArrayType>">
<complexContent>
<restriction base="SOAP-ENC:Array">
<attribute ref="SOAP-ENC:arrayType"
wsdl:arrayType="<ElementType><ArrayBounds>"/>
</restriction>
</complexContent>
</complexType>
Note: In the current version of Artix, the preceding syntax is the only case
where derivation from a complex type is supported. Definition of a SOAP
array is treated as a special case.
191
CHAPTER 7 | Artix Data Types
C++ mapping A given SOAPArrayType array maps to a C++ class of the same name,
which inherits from the IT_Bus::SoapEncArrayT<> template class. The
SOAPArrayType C++ class overloads the [] operator to provide access to
the array elements. The size of the array is returned by the get_extents()
member function.
<definitions name="BaseService"
targetNamespace="http://soapinterop.org/"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://soapinterop.org/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsd1="http://soapinterop.org/xsd">
<types>
<schema targetNamespace="http://soapinterop.org/xsd"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<complexType name="ArrayOfSOAPString">
<complexContent>
<restriction base="SOAP-ENC:Array">
<attribute ref="SOAP-ENC:arrayType"
wsdl:arrayType="xsd:string[]"/>
</restriction>
</complexContent>
</complexType>
...
</definitions>
192
SOAP Arrays
1 <ArrayOfSOAPString SOAP-ENC:arrayType="xsd:string[2]">
2 <item>Hello</item>
<item>world!</item>
</ArrayOfSOAPString>
C++ example Example 84 shows a C++ example of how to allocate and initialize an
ArrayOfSOAPString instance with four elements.
// C++
// Allocate SOAP array of String
const size_t extents[] = {4};
1 ArrayOfSOAPString a_str(extents);
2 a_str[0] = "Hello";
a_str[1] = "to";
a_str[2] = "the";
a_str[3] = "world!";
193
CHAPTER 7 | Artix Data Types
Note: Be sure to initialize every element in the array, unless you want to
create a sparse array (see “Sparse Arrays” on page 198). There are no
default element values. Uninitialized elements are flagged as empty.
194
SOAP Arrays
Multi-Dimensional Arrays
Overview The syntax for SOAP arrays allows you to define the dimensions of a
multi-dimensional array using two slightly different syntaxes:
• A comma-separated list between square brackets, for example [,] and
[,,].
• Multiple square brackets, for example [][] and [][][].
Artix makes no distinction between the two styles of array definition. In both
cases, the array is flattened for transmission and the C++ mapping is the
same.
195
CHAPTER 7 | Artix Data Types
Sample encoding of Example 86 shows the encoding of a sample Array2OfInt instance, which
multi-dimensional SOAP array is how the array instance might look when transmitted as part of a WSDL
operation.
<Array2OfInt SOAP-ENC:arrayType="xsd:int[2,3]">
<i>1</i>
<i>2</i>
<i>3</i>
<i>4</i>
<i>5</i>
<i>6</i>
</Array2OfInt>
The dimensions of this array instance are specified as [2,3], giving a total
of six elements. Notice that the encoded array is effectively flat, because no
distinction is made between rows and columns of the two-dimensional
array.
Given an array instance with dimensions, [I_MAX,J_MAX], a particular
position in the array, [i,j], corresponds with the i*J_MAX+j element of the
flattened array. In other words, the right most index of [i,j,...,k] is the
fastest changing as you iterate over the elements of a flattened array.
C++ example of a Example 87 shows a C++ example of how to allocate and initialize an
multi-dimensional SOAP array Array2OfInt instance with dimensions, [2,3].
// C++
1 const size_t extents2[] = {2, 3};
Array2OfInt a2_soap(extents2);
size_t position[2];
2 size_t i_max = a2_soap.get_extents()[0];
size_t j_max = a2_soap.get_extents()[1];
for (size_t i=0; i<i_max; i++) {
position[0] = i;
for (size_t j=0; j<j_max; j++) {
position[1] = j;
3 a2_soap[position] = (IT_Bus::Int) (i+1)*(j+1);
}
196
SOAP Arrays
197
CHAPTER 7 | Artix Data Types
Sparse Arrays
Overview Sparse arrays are fully supported in Artix. Every SOAP array instance stores
an array of status flags, one flag for each array element. The status of each
array element is initially empty, flipping to non-empty the first time an array
element is accessed or initialized.
Note: Sparse arrays are not optimized for minimization of storage space.
Hence, a sparse array with dimensions [1000,1000] would always allocate
storage for one million elements, irrespective of how many elements in the
array are actually non-empty.
Sample encoding Example 88 shows the encoding of a sparse Array2OfInt instance, which is
how the array instance might look when transmitted as part of a WSDL
operation.
<Array2OfInt SOAP-ENC:arrayType="xsd:int[10,10]">
<item SOAP-ENC:position="[3,0]">30</item>
<item SOAP-ENC:position="[2,1]">21</item>
<item SOAP-ENC:position="[1,2]">12</item>
<item SOAP-ENC:position="[0,3]">3</item>
</Array2OfInt>
198
SOAP Arrays
Initializing a sparse array Example 89 shows an example of how to initialize a sparse array of
Array2OfInt type.
// C++
const size_t extents2[] = {10, 10};
Array2OfInt a2_soap(extents2);
size_t position[2];
position[0] = 3;
position[1] = 0;
a2_soap[position] = 30;
position[0] = 2;
position[1] = 1;
a2_soap[position] = 21;
position[0] = 1;
position[1] = 2;
a2_soap[position] = 12;
position[0] = 0;
position[1] = 3;
a2_soap[position] = 3;
This example does not differ much from the case of initializing an ordinary
non-sparse array (compare, for example, Example 87 on page 196). The
only significant difference is that the majority of array elements are not
initialized, hence they are flagged as empty by default.
Note: The state of an array element flips from empty to non-empty the
first time it is accessed using the [] operator. Hence, attempting to read
the value of an uninitialized array element can have the unintended side
effect of flipping the array element status.
199
CHAPTER 7 | Artix Data Types
Reading a sparse array Example 90 shows an example of how to read a sparse array of
Array2OfInt type.
// C++
...
size_t p2[2];
1 size_t i_max = a2_out.get_extents()[0];
size_t j_max = a2_out.get_extents()[1];
for (size_t i=0; i<i_max; i++) {
p2[0] = i;
for (size_t j=0; j<j_max; j++) {
p2[1] = j;
2 if (!a2_out.is_empty(p2)) {
cout << "a[" << i << "][" << j << "] = "
<< a2_out[p2] << endl;
}
}
}
200
SOAP Arrays
<ArrayOfSOAPString SOAP-ENC:arrayType="xsd:string[10]"
SOAP-ENC:offset="[2]">
<item>The third element</item>
<item>The fourth element</item>
<item SOAP-ENC:position="[6]">The seventh element</item>
<item>The eighth element</item>
</ArrayOfSOAPString>
In this example, only the third, fourth, seventh, and eighth elements of a
ten-element string array are actually transmitted. The SOAP-ENC:offset
attribute is used to specify the index of the first transmitted array element.
The default value of SOAP-ENC:offset is [0]. The SOAP-ENC:position
attribute specifies the start of a new block within the array. If an <item>
element does not have a position attribute, it is assumed to represent the
next element in the array.
201
CHAPTER 7 | Artix Data Types
202
IT_Vector Template Class
Introduction to IT_Vector
Overview This section provides a brief introduction to programming with the
IT_Vector template type, which is modelled on the std::vector template
type from the C++ Standard Template Library (STL).
Differences between IT_Vector Although IT_Vector is modelled closely on the STL vector type,
and std::vector std::vector, there are some differences. In particular, IT_Vector does not
provide the following types:
IT_Vector<T>::allocator_type
Where T is the vector’s element type. Hence, the IT_Vector type does not
support an allocator_type optional final argument in its constructors.
The IT_Vector type does not support the following operations:
!=, <
The member functions listed in Table 10 are not defined in IT_Vector.
assign() Assignment
resize()
Size and capacity
max_size()
Although clear() is not defined, you can easily get the same effect for a
vector, v, by calling erase() as follows:
v.erase(v.begin(), v.end());
This has the effect of erasing all the elements in v, leaving an array of size 0.
203
CHAPTER 7 | Artix Data Types
Basic usage of IT_Vector The size() member function and the indexing operator [] is all that you
need to perform basic manipulation of vectors. Example 92 shows how to
use these basic vector operations to initialize an integer vector with the first
one hundred integer squares.
// C++
// Allocate a vector with 100 elements
IT_Vector<IT_Bus::Int> v(100);
Iterators Instead of indexing vector elements using the operator [], you can use a
vector iterator. A vector iterator, of IT_Vector<T>::iterator type, gives you
pointer-style access to a vector’s elements. The following operations are
supported by IT_Vector<T>::iterator:
++, --, *, =, ==, !=
An iterator instance remembers its current position within the element list.
The iterator can advance to the next element using ++, step back to the
previous element using --, and access the current element using *.
The IT_Vector template also provides a reverse iterator, of
IT_Vector<T>::reverse_iterator type. The reverse iterator differs from the
regular iterator in that it starts at the end of the element list and traverses
the list backwards. That is the meanings of ++ and -- are reversed.
204
IT_Vector Template Class
Example using iterators Example 92 on page 204 can be written in a more idiomatic style using
vector iterators, as shown in Example 93.
// C++
// Allocate a vector with 100 elements
IT_Vector<IT_Bus::Int> v(100);
IT_Vector<IT_Bus::Int>::iterator p = v.begin();
IT_Bus k_int = 0;
while (p != v.end())
{
*p = k_int*k_int;
++p;
++k_int;
}
205
CHAPTER 7 | Artix Data Types
206
IT_Vector Template Class
207
CHAPTER 7 | Artix Data Types
Operation Description
208
CHAPTER 8
209
CHAPTER 8 | Artix IDL to C++ Mapping
Alternative C++ mappings If you are already familiar with CORBA technology, you will know that there
is an existing standard for mapping IDL to C++ directly, which is defined by
the Object Management Group (OMG). Hence, two alternatives exist for
mapping IDL to C++, as follows:
• Artix IDL-to-C++ mapping—this is a two stage mapping, consisting of
IDL-to-WSDL and WSDL-to-C++. It is an IONA-proprietary mapping.
• CORBA IDL-to-C++ mapping—as specified in the OMG C++
Language Mapping document (http://www.omg.org). This mapping is
used, for example, by the IONA’s Orbix.
210
Introduction to IDL Mapping
Artix
IDL-to-WSDL Artix
WSDL WSDL-to-C++
C++
Contract
Stubs
IDL File
CORBA
IDL-to-C++ CORBA
C++
Stubs
Figure 12: Artix and CORBA Alternatives for IDL to C++ Mapping
Unsupported IDL types The following IDL types are not supported by the Artix C++ mapping:
• wchar.
• wstring.
• long double.
• Value types.
• Boxed values.
• Local interfaces.
• Abstract interfaces.
• forward-declared interfaces.
211
CHAPTER 8 | Artix IDL to C++ Mapping
212
IDL Complex Type Mapping
enum type Consider the following definition of an IDL enum type, SampleTypes::Shape:
// IDL
module SampleTypes {
enum Shape { Square, Circle, Triangle };
...
};
<xsd:simpleType name="SampleTypes.Shape">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="Square"/>
<xsd:enumeration value="Circle"/>
<xsd:enumeration value="Triangle"/>
</xsd:restriction>
</xsd:simpleType>
213
CHAPTER 8 | Artix IDL to C++ Mapping
The value of the enumeration type can be accessed and modified using the
get_value() and set_value() member functions.
union type Consider the following definition of an IDL union type, SampleTypes::Poly:
// IDL
module SampleTypes {
union Poly switch(short) {
case 1: short theShort;
case 2: string theString;
};
...
};
<xsd:complexType name="SampleTypes.Poly">
<xsd:choice>
<xsd:element name="theShort" type="xsd:short"/>
<xsd:element name="theString" type="xsd:string"/>
</xsd:choice>
</xsd:complexType>
214
IDL Complex Type Mapping
// C++
class SampleTypes_Poly : public IT_Bus::ChoiceComplexType
{
public:
...
const IT_Bus::Short gettheShort() const;
void settheShort(const IT_Bus::Short& val);
enum PolyDiscriminator
{
theShort,
theString,
Poly_MAXLONG=-1L
} m_discriminator;
The value of the union can be modified and accessed using the
getUnionMember() and setUnionMember() pairs of functions. The union
discriminator can be accessed through the get_discriminator() and
get_discriminator_as_uint() functions.
215
CHAPTER 8 | Artix IDL to C++ Mapping
// IDL
module SampleTypes {
struct SampleStruct {
string theString;
long theLong;
};
...
};
<xsd:complexType name="SampleTypes.SampleStruct">
<xsd:sequence>
<xsd:element name="theString" type="xsd:string"/>
<xsd:element name="theLong" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
216
IDL Complex Type Mapping
The members of the struct can be accessed and modified using the
getStructMember() and setStructMember() pairs of functions.
// IDL
module SampleTypes {
typedef sequence< SampleStruct > SeqOfStruct;
...
};
<xsd:complexType name="SampleTypes.SeqOfStruct">
<xsd:sequence>
<xsd:element name="item"
type="xsd1:SampleTypes.SampleStruct"
minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
217
CHAPTER 8 | Artix IDL to C++ Mapping
// IDL
module SampleTypes {
typedef SampleStruct ArrOfStruct[10];
...
};
<xsd:complexType name="SampleTypes.ArrOfStruct">
<xsd:sequence>
<xsd:element name="item"
type="xsd1:SampleTypes.SampleStruct"
minOccurs="10" maxOccurs="10"/>
</xsd:sequence>
</xsd:complexType>
218
IDL Complex Type Mapping
// IDL
module SampleTypes {
exception GenericExc {
string reason;
};
...
};
<xsd:complexType name="SampleTypes.GenericExc">
<xsd:sequence>
<xsd:element name="reason" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
...
<xsd:element name="SampleTypes.GenericExc"
type="xsd1:SampleTypes.GenericExc"/>
...
<message name="_exception.SampleTypes.GenericExc">
<part name="exception"
element="xsd1:SampleTypes.GenericExc"/>
</message>
219
CHAPTER 8 | Artix IDL to C++ Mapping
// C++
class SampleTypes_GenericExc : public
IT_Bus::SequenceComplexType
{
public:
SampleTypes_GenericExc();
...
const IT_Bus::String & getreason() const;
IT_Bus::String & getreason();
void setreason(const IT_Bus::String & val);
};
...
class _exception_SampleTypes_GenericExcException : public
IT_Bus::UserFaultException
{
public:
_exception_SampleTypes_GenericExcException();
...
const SampleTypes_GenericExc & getexception() const;
SampleTypes_GenericExc & getexception();
void setexception(const SampleTypes_GenericExc & val);
...
};
typedef of a simple type Consider the following IDL typedef that defines an alias of a float,
SampleTypes::FloatAlias:
// IDL
module SampleTypes {
typedef float FloatAlias;
...
};
220
IDL Complex Type Mapping
The WSDL-to-C++ compiler then maps the xsd:float type directly to the
IT_Bus::Float C++ type. Hence, no C++ typedef is generated for the
float type.
typedef of a complex type Consider the following IDL typedef that defines an alias of a struct,
SampleTypes::SampleStructAlias:
// IDL
module SampleTypes {
typedef SampleStruct SampleStructAlias;
...
};
221
CHAPTER 8 | Artix IDL to C++ Mapping
Module mapping An IDL identifier appearing within the scope of an IDL module,
ModuleName::Identifier, maps to a C++ identifier of the form
ModuleName_Identifier. That is, the IDL scoping operator, ::, maps to an
underscore, _, in C++.
Although IDL modules do not map to namespaces under the Artix C++
mapping, it is possible nevertheless to put generated C++ code into a
namespace using the -n switch to the WSDL-to-C++ compiler (see
“Generating Stub and Skeleton Code” on page 2). For example, if you pass a
namespace, TEST, to the WSDL-to-C++ -n switch, the
ModuleName::Identifier IDL identifier would map to
TEST::ModuleName_Identifier.
Interface mapping An IDL interface, InterfaceName, maps to a C++ class of the same name,
InterfaceName. If the interface is defined in the scope of a module, that is
ModuleName::InterfaceName, the interface maps to the
ModuleName_InterfaceName C++ class.
If an IDL data type, TypeName, is defined within the scope of an IDL
interface, that is ModuleName::InterfaceName::TypeName, the type
maps to the ModuleName_InterfaceName_TypeName C++ class.
222
IDL Module and Interface Mapping
Object reference mapping When an IDL interface is used as an operation parameter or return type, it is
mapped to the IT_Bus::Reference C++ type.
For example, consider an operation, get_foo(), that returns a reference to a
Foo interface as follows:
// IDL
interface Foo {};
interface Bar {
Foo get_foo();
};
The get_foo() IDL operation then maps to the following C++ function:
// C++
void get_foo(
IT_Bus::Reference & var_return
) IT_THROW_DECL((IT_Bus::Exception));
Note that this mapping is very different from the OMG IDL-to-C++
mapping. In the Artix mapping, the get_foo() operation does not return a
pointer to a Foo proxy object. Instead, you must construct the Foo proxy
object in a separate step, by passing the IT_Bus::Reference object into the
FooClient constructor.
See “Artix References” on page 61 for more details.
223
CHAPTER 8 | Artix IDL to C++ Mapping
Operation mapping Example 94 shows two IDL operations defined within the
SampleTypes::Foo interface. The first operation is a regular IDL operation,
test_op(), and the second operation is a oneway operation,
test_oneway().
// IDL
module SampleTypes {
...
interface Foo {
...
SampleStruct test_op(
in SampleStruct in_struct,
inout SampleStruct inout_struct,
out SampleStruct out_struct
) raises (GenericExc);
The operations from the preceding IDL, Example 94 on page 224, map to
C++ as shown in Example 95,
// C++
class SampleTypes_Foo
{
public:
...
1 virtual void test_op(
const TEST::SampleTypes_SampleStruct & in_struct,
TEST::SampleTypes_SampleStruct & inout_struct,
TEST::SampleTypes_SampleStruct & var_return,
TEST::SampleTypes_SampleStruct & out_struct
) IT_THROW_DECL((IT_Bus::Exception)) = 0;
224
IDL Module and Interface Mapping
Attribute mapping Example 96 shows two IDL attributes defined within the SampleTypes::Foo
interface. The first attribute is readable and writable, str_attr, and the
second attribute is readonly, struct_attr.
// IDL
module SampleTypes {
...
interface Foo {
...
attribute string str_attr;
readonly attribute SampleStruct struct_attr;
};
};
225
CHAPTER 8 | Artix IDL to C++ Mapping
The attributes from the preceding IDL, Example 96 on page 225, map to
C++ as shown in Example 97,
// C++
class SampleTypes_Foo
{
public:
...
1 virtual void _get_str_attr(
IT_Bus::String & var_return
) IT_THROW_DECL((IT_Bus::Exception)) = 0;
226
Index
Symbols nillable example 173
<extension> tag 152 nillable types 172
<fault> tag 30 attributes
<port> element 94 mapping 145
<restriction> tag 151 auto_ptr template 42
<simpleContent> tag 151
B
A Base64Binary type 128
abstract interface type 211 base64Binary type
all complex type nillable 173
nillable example 176 BASIC authentication 96
AllComplexType class 142 begin() 87, 89
all groups 142 below_capacity() function 80
anonymous types binary types 128
avoiding 147 get_data() 128
AnyHolder class 164 set_data() 128
get_any_type() function 165 binding name
get_type() function 166 specifying to code generator 3
inserting and extracting atomic types 165 boolean type
inserting and extracting user types 165 nillable 172
set_any_type() function 165 bounded sequences 218
AnyType class 165 boxed value type 211
anyType type 164 building Artix applications 164
nillable 172 Bus library 17
anyURI 133 byte type
arrays nillable 172
multi-dimensional native 161
native 158 C
SOAP 190 C++ mapping
arrayType attribute 192 parameter order 24
array types parameters 23
nillable elements 187 checked facets 130
artix.cfg file 55 choice complex type 147
Artix foundation classes 17 ChoiceComplexType class 138
Artix locator choice complex types 138
overview 66 clear() 203
Artix namespaces 5 client
Artix services developing 12
locator 69 proxy object 12
ART library 17 stub code, files 2
assign() 203 client proxies
at() 203 and multi-threading 53
atomic types 121
227
INDEX
228
INDEX
229
INDEX
230
INDEX
231
INDEX
232
INDEX
http 75 transient 64
locator_endpoint 75 XML schema 62
locator_endpoint plug-in 80 register_server_factory() 49
soap 75 resize() 203
port resources
specifying on the client side 12 server side 84
specifying to code generator 3 rollback() 87, 89
port object rollback_only() 87
use_input_message_attributes() 104, 107 round() 126
use_output_message_attributes() 107 run() function 11, 12
ports Running the Bus 11
and endpoints 68
port type S
specifying to code generator 3 scale() 126
positiveInteger 133 schema
propagating exceptions 29 for references 71
properties schemas 95
in a reference 65 for references 62
proxies sequence complex type 147
constructor for references 79 SequenceComplexType class 135
proxy object sequence complex types 135
and multi-threading 53 and arrays 158
constructors 12 sequence type 217
Serialization type 28
Q servant
QName 133 and threading models 54
QName type servants
nillable 172 multiple per port 46
server
R developing 8
reached_capacity() function 80 implementation class 8
recursive copying 40 main() function 10
recursive deallocating 41 skeleton code, files 2
ref:Reference type 71 server factory
reference creating 49
to an endpoint 62 default implementation 46
references deregistering services 49
constructor for client proxies 79 implementing 46
CORBA mapping 223 multiple ports 46
IT_Bus multiple services 46
registering a service 49
ServerFactoryBase class 58
Reference class 65 ServerFactoryBase class 58
looking up in the locator 68 server skeleton code 2
properties 65 server stub
reading from the locator 76 get_port() 107
ref:Reference type 71 service
schema 71 registering in a server factory 49
static 63 specifying on the client side 12
233
INDEX
234
INDEX
235
INDEX
xsd:NMTOKENS 145
xsd:NOTATION 145
xsdl
integer 133
xsi:nil attribute 170
xsi namespace 170
236
INDEX
237
INDEX
238