The messaging is very advanced as REST, JMS, AMQP, SOAP
Messages are the working fuel of the
Example of a record definition in JSON:
{ "records": [ { "id": "be125fa3-b4a7-493c-ad9a-5fa1a23be84d", "name": "NOTIFY_REMOTE_NODE_ADDED", "isService": "true", "namespaces": "SYSTEM", "description": "Notification that a remote node has been added.^It is now possible to send messages to the remote node.", "slots": [ { "key": "1", "name": "REMOTE_NODE", "direction": "REQUEST", "mandatory": "true", "type": "NODE_ADDRESS", "description": "The remote node." }, { "key": "2", "name": "TYPE", "direction": "REQUEST", "mandatory": "true", "type": "STRING", "description": "The type of the remote node, see ETypeOfNode." } ] } ] }
Example sending this message:
final CEnvelope env = CEnvelope.forLocalNanoService(CRecordNotifyRemoteNodeAdded.ID); final CRecord rec = CRecordNotifyRemoteNodeAdded.create(); CRecordNotifyRemoteNodeAdded.setRemoteNode(rec, nodeAddress); CRecordNotifyRemoteNodeAdded.setType(rec, aNodeInfo.isClient() ? ETypeOfNode.CLIENT.name() : ETypeOfNode.SERVER.name()); sendNotification(env, rec);
Messages are always sent asynchronously. The sender can therefore not wait synchronously for a response, but implements simple message handler functions that are called by the system when a message arrives.
Example of how to handle this message:
// install message handlers void init() { addMessageHandler(CRecordNotifyRemoteNodeAdded.ID, this::asyncNotifyRemoteNodeAdded); } // is called when this message comes in private boolean asyncNotifyRemoteNodeAdded(@NotNull final CEnvelope aEnvelope, @NotNull final CRecord aRecord) throws CException { if (aEnvelope.isAnswer()) { return false; // not handled } else { final CNodeAddress node = CRecordNotifyRemoteNodeAdded.getRemoteNode(aRecord, null); if (node != null) { // do something with node // ... aEnvelope.setResultSuccess(); } else { aEnvelope.setResult(CResultCode.MISSING_ARGUMENT, "Missing Node Address"); } return true; // handled } }
Messages will always arrive in the same thread, which means there is no risk of errors due to concurrency. This means that targets that have been registered for the same thread will always get messages delivered one after the other. An internal exchange of data between these targets remains possible without danger.
Messages are composed of an envelope and a record. While the envelope contains all the data for delivery, as in a written letter, the record will contain the user data.
In principle, the record is a map with keys and values. For example, it can be manipulated by the recipient as desired (add data, delete data) before it is sent back again.
The envelope, on the other hand, contains many switches that control the transport, e.g. response requested, compression or encryption requested, result code, result text, transaction number, forwarding requested, logging undesired, priority, etc.).
Sending messages works across the entire
An important feature of messages is the way they are addressed. They usually contain the network-wide unique address of a receiver and that of the sender. Messages are directional and pass from the sender object to the receiver object.
After handling the message, the system automatically returns it to the sender.
Automatic return can be prevented by sender or receiver.
The reply contains a status code and, if necessary, an error text.
In the event of an error, the sender is informed of the processing status (okay, recipient unknown, message was not
processed, and so on).
This handshake is a key feature of
For the use of patterns such as broadcasts or observers, there are other mechanisms which build on that principle on top.
Messages can be put on hold so that they are not automatically returned to the sender. This is useful if, for example, the recipient in turn needs to send messages to fulfill the request. After complete processing, the message can be returned manually.
Another feature is the forwarding of messages if the request is not processed immediately.
Messages for recipients on other nodes are passed from node to node until they reach their destination. Each node knows the state of the entire network, which means all other nodes and the connections between them. Each route between two nodes has a "cost" (ping duration or fixed cost). Therefore, each node can forward the message to the destination node along the most favorable route (Dijkstra's algorithm).
Messages have a priority. In case of heavy traffic, messages with high priority are given priority. Answers, for example, have an automatically high priority, while LOG messages or file snippets get a low priority. The user can explicitly set the desired priority for each message.
Messages can be compressed and encrypted. The corresponding flags can be set explicitly per message or per node. If messages are encrypted, the sender and receiver node exchange public keys beforehand (RSA).