summaryrefslogtreecommitdiffstats
path: root/sca-cpp/branches/cpp-M1/sca/doc/CreatingSCACPPComponents.txt
blob: 17f6430b79c6e79c33b92a2a98ee397e7b4c29ff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
Creating SCA Components in Tuscany SCA C++
==========================================

This document describes how to create and run SCA components in Tuscany SCA C++ 
milestone release 1.


Creating and deploying an SCA C++ Component
===========================================

Each SCA C++ component needs:
 o A service header file that defines the operations that can be invoked on the 
   component
 o An implementation header file that defines the implementation and extends 
   the service header file
 o A C++ implementation of the service that implements the operations defined 
   in the service header file
 o Proxy and wrapper header and implementation files generated by the Tuscany 
   C++ SCAGEN tool
 o A component definition in the module sca.module file
 o A service definition in a .componentType file
 o A module component definition in a sca.subsystem file


In this section we will use the Calculator sample as a worked example. 
The Calculator code and files can be found at samples/Calculator and has been 
developed further than the details specified below. In the interests of 
readability, the example used below takes the simplest path.


1.  Create the service header file that defines the operations your component 
    will implement. E.g. Calculator.h contains the following:

#ifndef CALCULATOR_H
#define CALCULATOR_H
class Calculator  
{
public:
    virtual float add(float arg1, float arg2) = 0;
    virtual float sub(float arg1, float arg2) = 0;
    virtual float mul(float arg1, float arg2) = 0;
    virtual float div(float arg1, float arg2) = 0;
};

#endif


2.  Create the implementation header file that extends the service header file. 
    E.g. CalculatorImpl.h contains the following:

#ifndef CALCULATORIMPL_H
#define CALCULATORIMPL_H

#include "Calculator.h"

class CalculatorImpl : public Calculator
{
public:
    CalculatorImpl();
    virtual ~CalculatorImpl();

    // Calculator interface
    virtual float add(float arg1, float arg2);
    virtual float sub(float arg1, float arg2);
    virtual float mul(float arg1, float arg2);
    virtual float div(float arg1, float arg2);
};

#endif


3.  Create the implementation for the component based on the implementation 
    header file. E.g. CalculatorImpl.cpp contains the following code:

#include "CalculatorImpl.h"
#include <stdio.h>

CalculatorImpl::CalculatorImpl()
{
}
    
CalculatorImpl::~CalculatorImpl()
{
}

// Calculator interface
float CalculatorImpl::add(float arg1, float arg2)
{
    float result = arg1 + arg2;

    printf("CalculatorImpl::add %f + %f = %f\n", arg1, arg2, result);
    return result;
}

float CalculatorImpl::sub(float arg1, float arg2)
{
    float result = arg1 - arg2;
    printf("CalculatorImpl::sub %f - %f = %f\n", arg1, arg2, result);
    return result;
}

float CalculatorImpl::div(float arg1, float arg2)
{
    float result = arg1 / arg2;
    printf("CalculatorImpl::div %f / %f = %f\n", arg1, arg2, result);
    return result;
}
	
float CalculatorImpl::mul(float arg1, float arg2)
{
    float result = arg1 * arg2;
    printf("CalculatorImpl::mul %f * %f = %f\n", arg1, arg2, result);
    return result;
}


4.  Create the componentType file for your component to define the service that 
    your component provides. The file must be named after your implementation 
    class and specifies the name of the service and the service header file 
    (which describes the service operations). E.g. CalculatorImpl.componentType 
    contains the following XML:

<?xml version="1.0" encoding="ASCII"?>
<componentType xmlns="http://www.osoa.org/xmlns/sca/0.9"
               xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <service name="CalculatorService">
        <interface.cpp header="Calculator.h"/>
    </service>
</componentType>


5.  Create the sca.module file for your module and define your component within 
    it. The component definition specifies the implementation library to use (a 
    .dll file on Windows and a .so file on Linux) and the implementation header 
    file (which describes the implementation class). Component properties and 
    references to other services can also be specified here. E.g. the 
    Calculator sca.module file contains the following XML:

<?xml version="1.0" encoding="ASCII"?>
<module xmlns="http://www.osoa.org/xmlns/sca/0.9" 
	xmlns:v="http://www.osoa.org/xmlns/sca/values/0.9"        
	name="CalculatorModule">

    <!-- The Calculator component -->
    <component name="CalculatorServiceComponent">
    	<implementation.cpp dll="Calculator.dll" header="CalculatorImpl.h"/>
        <properties></properties>
    	<references></references>
    </component>
</module>        


6.  Generate the proxy and wrapper classes and header files using the SCAGEN 
    tool. These classes are used by the Tuscany SCA C++ runtime to enable 
    service implementations to be invoked from a client or another component. 
    Run the SCAGEN tool, specifying the directory where your header files,
    sca.module and componentType file are and the directory where you 
    want the generated files to be placed. E.g. on Windows, the 
    following command is run from the directory where Tuscany SCA is deployed:

bin/scagen.cmd -dir samples/Calculator/CalculatorModule -output samples/Calculator/CalculatorModule

    which produces the following files:

CalculatorImpl_CalculatorService_Proxy.h
CalculatorImpl_CalculatorService_Proxy.cpp
CalculatorImpl_CalculatorService_Wrapper.h
CalculatorImpl_CalculatorService_Wrapper.cpp


7.  Compile and link the code that has been written and generated. This will 
    produce a .dll or .so library file. The name should match the library name 
    specified in the sca.module file.


8.  Create the sca.subsystem file and define your module component within it. 
    The module component definition should specify the service name used in the 
    componentType file and the module name used in the sca.module file. E.g. 
    the Calculator sca.subsystem file contains the following XML:

<?xml version="1.0" encoding="ASCII"?>
<subsystem xmlns="http://www.osoa.org/xmlns/sca/0.9" 
           name="CalculatorSubsystem">
	
    <moduleComponent name="CalculatorService" module="CalculatorModule"/>
</subsystem>


9.  Deploy the various files into the SCA directory structure, as follows:

<deploy_root>/modules/ModuleName/ServiceHeader.h
<deploy_root>/modules/ModuleName/ImplementationHeader.h
<deploy_root>/modules/ModuleName/sca.module
<deploy_root>/modules/ModuleName/Implementation.componentType
<deploy_root>/modules/ModuleName/Implementation.dll (or .so on Linux)
<deploy_root>/subsystems/SubsystemName/sca.subsystem

    E.g. for the Calculator sample the structure is:

samples/Calculator/deploy/modules/CalculatorModule/Calculator.h
samples/Calculator/deploy/modules/CalculatorModule/CalculatorImpl.h
samples/Calculator/deploy/modules/CalculatorModule/sca.module
samples/Calculator/deploy/modules/CalculatorModule/CalculatorImpl.componentType
samples/Calculator/deploy/modules/CalculatorModule/Calculator.dll
samples/Calculator/deploy/subsystems/CalculatorSubsystem/sca.subsystem


10. Your component, module and subsystem are now ready to be invoked. Create a 
    client that will call the service. E.g. the Calculator client (in the 
    Calc.cpp file) contains code similar to the following:

try
{
    // Define and start the Tuscany runtime:
    // Set the system root path that contains the SCA directory structure, set 
    // the default module component that will be used based on the format 
    // <SubsystemName>/<ModuleComponentName> and then start the runtime 
    TuscanyRuntime rt; 
    rt.setSystemRoot("C:/tuscany_sca/samples/Calculator/deploy");
    rt.setDefaultModuleComponent("CalculatorSubsystem/CalculatorService");
    rt.start();


    // Locate the service
    ModuleContext myContext = ModuleContext::getCurrent();
    Calculator *calcService = (Calculator*) myContext.locateService("CalculatorServiceComponent");
    if (calcService == 0)
    {
        cout << "MyCalculatorClient.exe: Unable to find Calculator service" << endl;
    }
    else
    {
        result = calcService->add(arg1, arg2);
        cout << "Calculator: add(" << arg1 << "," << arg2 << ") = " << result << endl; 
    }
}
catch (ServiceRuntimeException& ex)
{
    cout << "MyCalculatorClient.exe: Error whilst starting or invoking Tuscany: " << 
            ex.getMessageText() << endl; 
}


11. Compile, link and run the client that has been created. You should 
    (hopefully!) see your component invoked. Remember you will need to have the 
    TUSCANY_SCACPP, TUSCANY_SDOCPP and AXIS2C_HOME environment variables set, 
    as well as the SCA and SDO bin directories and the Axis2C lib directory on 
    your PATH (or LD_LIBRARY_PATH on Linux). E.g. on Windows run the following 
    commands:

set TUSCANY_SCACPP=C:/tuscany_sca
set TUSCANY_SDOCPP=C:/tuscany_sdo
set AXIS2C_HOME=C:/axis2c-bin-0.92-win32
set PATH=%PATH%;C:/tuscany_sca/bin;C:/tuscany_sdo/bin;C:/axis2c-bin-0.92-win32/lib
./MyCalculatorClient.exe


12. Optionally, enable Tuscany logging by setting the TUSCANY_SCACPP_LOGGING 
    environment variable with the level you wish to log at (0 for minimal 
    logging, up to 9 for more detailed logging) and the TUSCANY_SCACPP_LOG 
    environment variable to define the file to log to (if this is not set, 
    logging will go to the console). E.g. on Windows run the following 
    commands: 

set TUSCANY_SCACPP_LOGGING=5
set TUSCANY_SCACPP_LOG=C:/tuscany/mylogfile.txt


Further Steps
-------------

The Calculator sample has been developed further than the details specified 
above. In particular, it demonstrates how two services can be wired together 
such that one references and invokes the other. It also demonstrates how to 
expose the Calculator component service as an Axis2C Web Service. See the 
WSEntrypoint.txt document for more details on exposing components as Web
Services.