-
Notifications
You must be signed in to change notification settings - Fork 109
/
README
167 lines (127 loc) · 6.72 KB
/
README
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
=== Example 03: Methods
Franca attributes represent status variables or data sets of services which shall be accessible by the clients of the service. In contrast, methods can be used for example to start a process in the service or to query for certain information (e.g., from a database). See the following example 3:
[source,java]
----
package commonapi.examples
interface E03Methods {
version { major 1 minor 2 }
method foo {
in {
Int32 x1
String x2
}
out {
Int32 y1
String y2
}
error {
stdErrorTypeEnum
}
}
broadcast myStatus {
out {
Int32 myCurrentValue
}
}
enumeration stdErrorTypeEnum {
NO_FAULT
MY_FAULT
}
}
----
Basically Franca methods have input parameters and output parameters and can return an optional application error which reports for example if the started process in the service could be finished successfully or not. Input and output parameters can have arbitrarily complex types, a separate definition of so-called InOut arguments of functions was not considered necessary.
A special case are broadcasts. They can be used like readonly attributes. But there are several output parameters allowed (and no input parameters). Another difference is the additional optional keyword selective, which indicates that only selected clients can register on the broadcast see example 4).
Another optional keyword (only for methods) is fireAndForget which indicates that neither return values nor a call status is expected.
The implementation of the service class is straight:
[source,{cppstr}]
----
void E03MethodsStubImpl::foo(const std::shared_ptr<CommonAPI::ClientId> _client,
int32_t _x1,
std::string _x2,
fooReply_t _reply) {
E03Methods::fooError methodError = (E03Methods::fooError)
E03Methods::stdErrorTypeEnum::MY_FAULT;
int32_t y1 = 42;
std::string y2 = "xyz";
_reply(methodError, y1, y2);
}
----
The input parameters are available as values, the output parameter are wrapped in a generated reply object with the type fooReply_t. This is slightly different to earlier versions of CommonAPI where the return values were passed as references.
In the example there is another function incCounter implemented which sends the broadcast myStatus via the generated method fireMyStatusEvent:
[source,{cppstr}]
----
void E03MethodsStubImpl::incCounter() {
cnt++;
fireMyStatusEvent((int32_t) cnt);
std::cout << "New counter value = " << cnt << "!" << std::endl;
}
----
The subscription to the broadcast is nearly identical to the subscription to the change of the value of an attribute. The example shows further an asynchronous and a synchronous call of the function foo; in the asynchronous case the callback function +recv_cb+ is defined.
[source,{cppstr}]
----
#include <iostream>
#include <unistd.h>
#include <CommonAPI/CommonAPI.hpp>
#include <v1/commonapi/examples/E03MethodsProxy.hpp>
using namespace v1_2::commonapi::examples;
void recv_cb(const CommonAPI::CallStatus& callStatus,
const E03Methods::stdErrorTypeEnum& methodError,
const int32_t& y1,
const std::string& y2) {
std::cout << "Result of asynchronous call of foo: " << std::endl;
std::cout << " callStatus: " << ((callStatus == CommonAPI::CallStatus::SUCCESS) ? "SUCCESS" : "NO_SUCCESS")
<< std::endl;
std::cout << " error: "
<< ((methodError == E03Methods::stdErrorTypeEnum::NO_FAULT) ? "NO_FAULT" :
"MY_FAULT") << std::endl;
std::cout << " Output values: y1 = " << y1 << ", y2 = " << y2 << std::endl;
}
int main() {
CommonAPI::Runtime::setProperty("LogContext", "E03C");
CommonAPI::Runtime::setProperty("LibraryBase", "E03Methods");
std::shared_ptr<CommonAPI::Runtime> runtime = CommonAPI::Runtime::get();
std::string domain = "local";
std::string instance = "commonapi.examples.Methods";
std::shared_ptr<E03MethodsProxy<>> myProxy = runtime->buildProxy < E03MethodsProxy > (domain, instance, "client-sample");
while (!myProxy->isAvailable()) {
std::this_thread::sleep_for(std::chrono::microseconds(10));
}
// Subscribe to broadcast
myProxy->getMyStatusEvent().subscribe([&](const int32_t& val) {
std::cout << "Received status event: " << val << std::endl;
});
while (true) {
int32_t inX1 = 5;
std::string inX2 = "abc";
CommonAPI::CallStatus callStatus;
E03Methods::stdErrorTypeEnum methodError;
int32_t outY1;
std::string outY2;
// Synchronous call
std::cout << "Call foo with synchronous semantics ..." << std::endl;
myProxy->foo(inX1, inX2, callStatus, methodError, outY1, outY2);
std::cout << "Result of synchronous call of foo: " << std::endl;
std::cout << " callStatus: " << ((callStatus == CommonAPI::CallStatus::SUCCESS) ? "SUCCESS" : "NO_SUCCESS")
<< std::endl;
std::cout << " error: "
<< ((methodError == E03Methods::stdErrorTypeEnum::NO_FAULT) ? "NO_FAULT" : "MY_FAULT")
<< std::endl;
std::cout << " Input values: x1 = " << inX1 << ", x2 = " << inX2 << std::endl;
std::cout << " Output values: y1 = " << outY1 << ", y2 = " << outY2 << std::endl;
// Asynchronous call
std::cout << "Call foo with asynchronous semantics ..." << std::endl;
std::function<
void(const CommonAPI::CallStatus&,
const E03Methods::stdErrorTypeEnum&,
const int32_t&,
const std::string&)> fcb = recv_cb;
myProxy->fooAsync(inX1, inX2, recv_cb);
std::this_thread::sleep_for(std::chrono::seconds(5));
}
return 0;
}
----
A frequently asked question is what happens if the service does not answer. In this case, the callback function +recv_cb+ is called anyway, but the +callStatus+ has the value +REMOTE_ERROR+. It is however the responsibility of the specific middleware to implement this behavior. The CommonAPI specification says:
- *NOT* considered to be a remote error is an application level error that is defined in the corresponding Franca interface, because from the point of view of the transport layer the service still returned a valid answer.
- It *IS* considered to be a remote error if no answer for a sent remote method call is returned within a defined time. It is discouraged to allow the sending of any method calls without a defined timeout. This timeout may be middleware specific. This timeout may also be configurable by means of a Franca Deployment Model. It is *NOT* configurable at runtime by means of the Common API.
The timeout of function calls can be set by the optional +CallInfo+ argument on client side.