... | ... | @@ -13,7 +13,7 @@ public class JavaApp { |
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
// Initialise the Cameo application represented by This.
|
|
|
// Initialize the Cameo application represented by This.
|
|
|
This.init(args);
|
|
|
|
|
|
// Infinite printing loop.
|
... | ... | @@ -44,16 +44,16 @@ In C++, we can get the string result: |
|
|
int main(int argc, char *argv[]) {
|
|
|
|
|
|
// Define the reference to the Cameo server in B.
|
|
|
cameo::Server server("tcp://B:7000");
|
|
|
std::unique_ptr<cameo::Server> server = cameo::Server::create("tcp://B:7000");
|
|
|
|
|
|
// Start the application "App2" and obtain a reference to the running app.
|
|
|
std::unique_ptr<cameo::application::Instance> app2 = server.start("App2");
|
|
|
std::unique_ptr<cameo::App> app2 = server.start("App2");
|
|
|
|
|
|
// Wait for the end of the app and get the terminal state.
|
|
|
cameo::application::State state = app2->waitFor();
|
|
|
cameo::State state = app2->waitFor();
|
|
|
|
|
|
// Get the result and display it.
|
|
|
std::optional<std::string> result = resultApplication->getResult();
|
|
|
std::optional<std::string> result = app2->getResult();
|
|
|
if (result.has_value()) {
|
|
|
std::cout << "Result " << result.value() << std::endl;
|
|
|
}
|
... | ... | @@ -65,7 +65,7 @@ int main(int argc, char *argv[]) { |
|
|
}
|
|
|
```
|
|
|
|
|
|
In Java and Python, you also have the *getResult()* method and function to retrieve the string result. If you need to set and get a binary result, use the related *setBinaryResult()* and *getBinaryResult()* methods and functions.
|
|
|
In Java and Python, you have the *getStringResult()* method and function to retrieve the string result. If you need to set and get a binary result, use the related *setResult()* and *getResult()* methods and functions.
|
|
|
|
|
|
Use the return value can be very helpful to use an app as a function. However it is **not recommended** to use it in those cases:
|
|
|
* The execution of the app is very short and it is executed lots of time.
|
... | ... | @@ -80,23 +80,26 @@ If you need to setup a request/response mechanism between different apps then us |
|
|
An example of a responder in a C++ application registered as *ResApp* in the Cameo server:
|
|
|
```cpp
|
|
|
// Define a responder.
|
|
|
std::unique_ptr<coms::Responder> responder;
|
|
|
std::unique_ptr<coms::basic::Responder> responder;
|
|
|
|
|
|
try {
|
|
|
// Create the responder with name "the-responder".
|
|
|
responder = coms::Responder::create("the-responder");
|
|
|
responder = coms::basic::Responder::create("the-responder");
|
|
|
|
|
|
// Initialize the responder.
|
|
|
responder->init();
|
|
|
|
|
|
std::cout << "Created responder " << *responder << std::endl;
|
|
|
}
|
|
|
catch (const coms::ResponderCreationException& e) {
|
|
|
std::cout << "Responder error" << std::endl;
|
|
|
return -1;
|
|
|
catch (const coms::InitException& e) {
|
|
|
std::cout << "Responder cannot be created" << std::endl;
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
// Loop on the requests.
|
|
|
while (true) {
|
|
|
// Receive the simple request.
|
|
|
std::unique_ptr<coms::Request> request = responder->receive();
|
|
|
std::unique_ptr<coms::basic::Request> request = responder->receive();
|
|
|
if (!request) {
|
|
|
std::cout << "Responder is canceled" << std::endl;
|
|
|
break;
|
... | ... | @@ -110,17 +113,21 @@ request->reply("Done"); |
|
|
```
|
|
|
The responder is created with the name "the-responder" to identify it.
|
|
|
The pre-condition for the creation of the responder is that *This* must have been initialized.
|
|
|
Like the return value, it is possible to get the request as **binary** data using the *getBinary()* function or method. It is also possible to reply binary data using the *replyBinary()* method or function.
|
|
|
The requests can also be a **two-part message** and the second part can be get with the *getSecondBinaryPart()* method or function.
|
|
|
Like the return value, it is possible to get the request as **binary** data using the *get()* function or method. It is also possible to reply binary data using the *reply()* method or function.
|
|
|
The requests can also be a **two-part message** and the second part can be get with the *getSecondPart()* method or function.
|
|
|
|
|
|
Let's see an example of requester in Java:
|
|
|
```java
|
|
|
try {
|
|
|
// Connect to the app RespApp which hosts a responder.
|
|
|
Instance responderApp = server.connect("RespApp");
|
|
|
App responderApp = server.connect("RespApp");
|
|
|
|
|
|
// Create a requester to the responder "the-responder".
|
|
|
Requester requester = Requester.create(responderApp, "the-responder");
|
|
|
|
|
|
// Initialize the requester.
|
|
|
requester.init();
|
|
|
|
|
|
System.out.println("Created requester " + requester);
|
|
|
|
|
|
for (int i = 0; i < N; ++i) {
|
... | ... | @@ -134,17 +141,12 @@ try { |
|
|
// Terminate the requester.
|
|
|
requester.terminate();
|
|
|
}
|
|
|
catch (RemoteException e) {
|
|
|
catch (InitException e) {
|
|
|
System.out.println("Requester error:" + e);
|
|
|
}
|
|
|
```
|
|
|
|
|
|
The requester is created by connecting to the responder named "the-responder" living in the *RespApp* application. Once connected, the requester can send requests and receive the responses. Here again the pre-condition for the creation of the requester is that *This* must have been initialized.
|
|
|
|
|
|
The requester application can terminate unexpectedly whereas the responder is responding to it. In that case the responder may block indefinitely. That is why it is possible to set a **timeout** in milliseconds:
|
|
|
```cpp
|
|
|
// Set the request timeout with 1s.
|
|
|
request->setTimeout(1000);
|
|
|
The requester is created by connecting the responder named "the-responder" living in the *RespApp* application. Once connected, the requester can send requests and receive the responses. Here again the pre-condition for the creation of the requester is that *This* must have been initialized.
|
|
|
|
|
|
// Reply a string to the requester.
|
|
|
bool res = request->reply("Done");
|
... | ... | @@ -152,8 +154,6 @@ if (!res) { |
|
|
std::cout << "Timeout occurred" << std::endl;
|
|
|
}
|
|
|
```
|
|
|
This timeout can be set in Java and Python with the same method and function. But be careful, having a timeout does not mean that the reply was not received by the requester.
|
|
|
|
|
|
You can notice that no port was provided to define the requester and responder. Only a name was provided. The **ports** are **assigned dynamically** internally but the programmer does not have to care about.
|
|
|
|
|
|
# Publisher/Subscriber
|
... | ... | @@ -166,7 +166,7 @@ try { |
|
|
Publisher publisher = Publisher.create("the-publisher", 1);
|
|
|
|
|
|
// Synchronize with the subscriber(s). Wait for the subscriber to connect.
|
|
|
publisher.waitForSubscribers();
|
|
|
publisher.init();
|
|
|
|
|
|
// Send data.
|
|
|
for (int i = 0; i < 100; ++i) {
|
... | ... | @@ -176,22 +176,25 @@ try { |
|
|
// Terminate the publisher.
|
|
|
publisher.terminate();
|
|
|
}
|
|
|
catch (PublisherCreationException e) {
|
|
|
catch (InitException e) {
|
|
|
System.out.println("Publisher error:" + e);
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Here again, *This* must have been initialized before creating the publisher. We provide a synchronization feature with the second argument of the *Publisher.create()* method: the number of subscribers can be provided. The call to *Publisher.waitForSubscribers()* is blocking until the required number of subscribers has been reached. This allows to have subscribers that will receive all the messages: The publisher is **synchronized**.
|
|
|
Default value is 0 and in that case *Publisher.waitForSubscribers()* immediately returns. Then the publisher is **not** synchronized and some messages may be lost.
|
|
|
Here again, *This* must have been initialized before creating the publisher. We provide a synchronization feature with the second argument of the *Publisher.create()* method: the number of subscribers can be provided. The call to *Publisher.init()* is blocking until the required number of subscribers has been reached. This allows to have subscribers that will receive all the messages: The publisher is **synchronized**.
|
|
|
Default value is 0 and in that case *Publisher.init()* immediately returns. Then the publisher is **not** synchronized and some messages may be lost.
|
|
|
|
|
|
Let's give an example of a subcriber in C++:
|
|
|
```cpp
|
|
|
// Connect to the app PubApp which hosts a publisher.
|
|
|
std::unique_ptr<application::Instance> publisherApp = server.connect("PubApp");
|
|
|
std::unique_ptr<application::App> publisherApp = server.connect("PubApp");
|
|
|
|
|
|
// Create a subscriber to the application.
|
|
|
std::unique_ptr<coms::Subscriber> subscriber = coms::Subscriber::create(*publisherApp, "publisher");
|
|
|
|
|
|
// Initialize the subscriber.
|
|
|
subscriber.init();
|
|
|
|
|
|
// Receive data.
|
|
|
while (true) {
|
|
|
std::optional<std::string> message = subscriber->receive();
|
... | ... | |