Skip to content

Commit b4123c7

Browse files
committed
Release 0.2.0
1 parent 717c520 commit b4123c7

36 files changed

+1771
-661
lines changed

Documentation/MATLABInterface.md

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# RabbitMQ MATLAB Interface
2+
3+
## Installation
4+
5+
### Building the Java package
6+
Refer to the [Getting Started Section in
7+
README.md](../README.md#build-rabbitmq-matlab-java-client-package) for
8+
instructions on building the required JAR-file.
9+
10+
### Configuring MATLABPATH and Java class path `startup.m`
11+
Before using the package in MATLAB, the Java client library needs to be loaded
12+
on the MATLAB Java class path and the `Software/MATLAB/app` directory needs to
13+
be added to the MATLABPATH. This can be accomplished by running the `startup`
14+
function from the `Software/MATLAB` directory.
15+
16+
Note that this will load the JAR-file on the *dynamic* class path. Not all
17+
functionality is supported when the JAR-file is loaded on the dynamic class
18+
path, see below. See the [MATLAB
19+
documentation](https://www.mathworks.com/help/matlab/matlab_external/java-class-path.html)
20+
to learn more about the Java class path in general and on how to add the
21+
JAR-file to the static class path if desired/needed.
22+
23+
## Usage
24+
25+
### Connection Properties
26+
When working with `rabbitmq.Producer` and `rabbitmq.Consumer` in MATLAB, various
27+
connection properties need to be specified. These can be specified with the help
28+
of the `rabbitmq.ConnectorProperties` class or using YAML configuration files.
29+
30+
#### `rabbitmq.ConnectorProperties`
31+
`rabbitmq.ConnectorProperties` takes various Name-Value pairs as inputs. All
32+
options are optional, if not specified their default value is used.
33+
34+
|Property Name | Default Value | Description |
35+
|-------------------|---------------|---------------------------------------|
36+
|**'host'** | 'localhost' | Hostname or IP of the RabbitMQ Server |
37+
|**'port'** | 5672 | Port the RabbitMQ Server runs on |
38+
|**'virtualhost'** | '/' | RabbitMQ Virtual Host |
39+
|**'exchange'** | 'amq.topic' | Exchange to work with on RabbitMQ |
40+
|**'queuename'** | 'RabbitMQ' | Name of the Queue on RabbitMQ Server |
41+
|**'username'** | 'guest' | RabbitMQ username |
42+
|**'password'** | 'guest' | RabbitMQ password |
43+
|**'routingkey'** | 'test-topic' | Routing key to subscribe to or poll on - only used for Consumer, when working with Producer the routing key is specified on a per message basis when publishing a message |
44+
45+
For example:
46+
47+
```matlab
48+
% Create a configuration with mostly default options but custom host and
49+
% routingkey settings
50+
configuration = rabbitmq.ConnectorProperties('host','myhost',...
51+
'routingkey','my-key');```
52+
```
53+
54+
#### Configuration Files
55+
56+
The configuration file follows the same RabbitMQ related options as the
57+
configuration file for the MATLAB Production Server interface:
58+
59+
```yaml
60+
# Messaging connection and routing properties
61+
messageQueue:
62+
queueName: RabbitMQ # Name of the Queue on RabbitMQ Server
63+
host: localhost # Hostname or IP of the RabbitMQ Server
64+
port: 5672 # Port the RabbitMQ Server runs on
65+
virtualhost: / # RabbitMQ Virtual Host
66+
credentials:
67+
username: guest # RabbitMQ username
68+
password: guest # RabbitMQ password
69+
exchange: amq.topic # Exchange to work with on RabbitMQ
70+
routingkey: test-topic # Routing key to subscribe to or poll on,
71+
# only relevant/required/used when working with
72+
# Consumer, when working with Producer, the
73+
# routingkey is specified on a per message basis
74+
# when publishing the message
75+
```
76+
77+
### RabbitMQ Producer for publishing messages `rabbitmq.Producer`
78+
To work with `rabbitmq.Producer` in MATLAB, first create an instance with
79+
`rabbitmq.ConnectorProperties` or configuration YAML-file as input:
80+
81+
```matlab
82+
% Create a Producer based on a configuration file
83+
producer = rabbitmq.Producer(fullfile(rabbitMQProjectRoot,'config','example.yaml'));
84+
% Or alternatively using ConnectorProperties
85+
configuration = rabbitmq.ConnectorProperties();
86+
producer = rabbitmq.Producer(configuration);
87+
```
88+
89+
Then to send a message use `sendMessage` with a routingkey and the actual
90+
message as input:
91+
92+
```matlab
93+
producer.sendMessage('my-routing-key','Hello World');
94+
```
95+
96+
### RabbitMQ Consumer for receiving messages `rabbitmq.Consumer`
97+
`rabbitmq.Consumer` offers two approaches for receiving messages from RabbitMQ
98+
in MATLAB. An event-based approach and a polling approach. These two different
99+
approaches correspond to the push- and pull approaches respectively, as
100+
[described in the RabbitMQ Java
101+
API](https://www.rabbitmq.com/api-guide.html#consuming). As noted in this
102+
RabbitMQ Java API documentation the push (i.e. in MATLAB event based approach)
103+
is recommended. However, in MATLAB this will require the JAR-file to be loaded
104+
on the *static* Java class path rather than on the *dynamic* Java class path.
105+
106+
#### Event Based Approach
107+
108+
```matlab
109+
function consumer = EventBasedConsumerExample
110+
% Create the Consumer with configuration file as input. Working with
111+
% rabbitmq.ConnectorProperties is supported here as well. Further set
112+
% eventBased = true to indicate to work with the event based approach
113+
consumer = rabbitmq.Consumer( ...
114+
fullfile(rabbitMQProjectRoot,'config','example.yaml'), ...
115+
true);
116+
117+
% Add a listener to the MessageReceived event
118+
addlistener(consumer,'MessageReceived',@onMessageReceived)
119+
120+
121+
function onMessageReceived(~,message)
122+
% In the listener, as an example simply print the message
123+
fprintf('Message received: %s\n',message.message);
124+
```
125+
126+
#### Polling Approach
127+
128+
```matlab
129+
function PollBasedConsumerExample
130+
% Create the Consumer with configuration file as input working with
131+
% rabbitmq.ConnectorProperties is supported here as well. Further set
132+
% eventBased = false to indicate to work with the polling approach
133+
consumer = rabbitmq.Consumer( ...
134+
fullfile(rabbitMQProjectRoot,'config','example.yaml'), ...
135+
false);
136+
% Now actually start polling
137+
138+
% In this example receive up to 3 messages then stop
139+
numReceived = 0;
140+
fprintf('Polling for messages...');
141+
% As long as we have not received three messages yet
142+
while numReceived < 3
143+
% Poll for a message
144+
message = consumer.pollMessage();
145+
if ~isempty(message) % If a message was received
146+
% Display it
147+
fprintf('\nMessage Received: %s\n',message);
148+
% Increase the counter
149+
numReceived = numReceived + 1;
150+
fprintf('Polling for messages...');
151+
end
152+
fprintf('.')
153+
% Pause for a second before polling again
154+
pause(1);
155+
end
156+
% After 3 messages have been received
157+
fprintf('stopped.\n');
158+
```
159+
160+
## Deployment
161+
162+
When using this MATLAB Package in a MATLAB function deployed to MATLAB
163+
Production Server in order to send back replies/results to a RabbitMQ client (or
164+
in any other MATLAB Compiler (SDK) deployed component) it is important the
165+
correct functionality gets compiled into the deployed component. The MATLAB
166+
Compiler (SDK) dependency analysis should be able to automatically detect and
167+
include the MATLAB dependencies by itself but the JAR-file must be added
168+
manually to the component by adding it to the "Additional files required for
169+
your component to run" in the Compiler App or by using the `-a` option when
170+
working with `mcc` on the command line.
171+
172+
Any JAR-file compiled into a deployed component will be automatically added to
173+
the Java class path at runtime and any functions compiled into the component
174+
will be automatically on the MATLABPATH at runtime; so there is no need then to
175+
explicitly call `startup` in the deployed component. If possible the JAR-file is
176+
added to the *static* class path but there may be circumstances in which this is
177+
not possible and then it is loaded on the *dynamic* class path; this may make
178+
the event based consumer approach unavailable.
179+
180+
[//]: # (Copyright 2022 The MathWorks, Inc.)

Documentation/MessageBroker.md

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
# RabbitMQ `MessageBroker` for MATLAB Production Server
2+
3+
## Architecture
4+
`MessageBroker`, is essentially a RabbitMQ (AMQP) Consumer which can receive
5+
messages from a RabbitMQ Server which it then passes along as input to a
6+
function deployed ot MATLAB Production Server. The MATLAB function is assumed to
7+
have exactly one input which is the message as character array.
8+
9+
```mermaid
10+
flowchart
11+
client(Message Producer) -- publish message --> server[(RabbitMQ Server)]-- deliver message --> MessageBroker[MessageBroker] --"call with message as input"--> mps(MATLAB Production Server)
12+
MessageBroker -. subscribe .-> server
13+
```
14+
15+
As RabbitMQ supports various protocols (AMQP as native protocol but also MQTT
16+
and STOMP as plugins), the Message Producer can be any client supporting any of
17+
those protocols.
18+
19+
## Message Datatype
20+
RabbitMQ messages _in general_ are simply raw bytes, this package implicitly
21+
assumes however that all messages are UTF-8 encoded strings. Consider encoding
22+
your messages in JSON format if "more complex" data structures need to be
23+
represented in the messages. On the MATLAB end the `jsondecode` function can be
24+
used to parse the JSON string into a MATLAB structure.
25+
26+
## Dataflow
27+
A full workflow with this package could look like the following:
28+
29+
```mermaid
30+
sequenceDiagram
31+
autonumber
32+
participant MessageSender
33+
participant RabbitMQ Server
34+
participant MessageBroker
35+
participant MATLAB Production Server
36+
note over MessageSender,MATLAB Production Server: MessageBroker Startup
37+
MessageBroker-->>RabbitMQ Server: subscribes
38+
note over MessageSender,MATLAB Production Server: For each message/request sent by MessageSender
39+
opt
40+
MessageSender-->>RabbitMQ Server: binds
41+
end
42+
MessageSender->>RabbitMQ Server: message
43+
RabbitMQ Server->>+MessageBroker: message
44+
MessageBroker->>+MATLAB Production Server: message
45+
opt
46+
MATLAB Production Server->>-RabbitMQ Server: reply
47+
deactivate MessageBroker
48+
RabbitMQ Server->>MessageSender: reply
49+
end
50+
```
51+
52+
1. Upon startup `MessageBroker` connects to the configured RabbitMQ Server and
53+
subscribes to the specified `queue` on the specified `exchange` with
54+
specified `routingkey`.
55+
56+
2. If a MessageSender expects a reply of the function deployed to MATLAB
57+
Production Server through RabbitMQ, it first subscribes to the RabbitMQ
58+
server as well, if using the same `queue` on the same `exchange` make sure to
59+
use a different `routingkey` (to avoid infinite loops where the response
60+
would trigger another MATLAB Production Server call).
61+
62+
3. The MessageSender (this can literally be the `MessageSender` example client
63+
included in this package or any other RabbitMQ Client) sends a message with a
64+
`routingkey` to a `queue` on the RabbitMQ Server.
65+
66+
4. If the `queue` and `routingkey` match the ones `MessageBroker` has subscribed
67+
to, the RabbitMQ Server delivers to message to `MessageBroker`.
68+
69+
5. `MessageBroker` uses MATLAB Production Server Java client to call the
70+
specified `function` in the specified `archive` with the message as input.
71+
MATLAB Production Server will then process this request. If the package is
72+
used to simply trigger a function call without outputs the flow ends here.
73+
74+
6. If the MATLAB code needs to return an output to the client, the MATLAB code
75+
can use `rabbitmq.Producer` to send a message with the `routingkey` the
76+
client is bound to, to the RabbitMQ Server.
77+
78+
> Note: this bypasses `MessageBroker`. `MessageBroker` does not do anything
79+
> with the "MATLAB style output" of the function deployed to MATLAB
80+
> Production Server. The MATLAB code deployed to MATLAB Production Server
81+
> has to explicitly use `rabbitmq.Producer` in the MATLAB code if a reply is
82+
> to be send over RabbitMQ.
83+
84+
7. If the `routingkey`, `queue` and `exchange` match the one the client has
85+
subscribed to, the RabbitMQ server will deliver the reply to the client.
86+
87+
## Installation
88+
### Building the Java package
89+
Refer to the [Getting Started Section in
90+
README.md](../README.md#build-rabbitmq-matlab-java-client-package) for
91+
instructions on building the required JAR-file.
92+
93+
### Further configuration and testing the setup
94+
95+
1. Before continuing it is good to verify that the RabbitMQ Server is up and
96+
running correctly and can be accessed, for example by accessing the Web Admin
97+
console which typically runs on port 15672, so for a local server check
98+
http://localhost:15672/.
99+
100+
> Please see the [RabbitMQ Authentication, Authorization, Access Control
101+
> documentation](https://www.rabbitmq.com/access-control.html) on how to
102+
> configure credentials for remote access, TLS support, authentication, etc.
103+
104+
2. For an initial test, MATLAB Compiler SDK's MATLAB Production Server testing
105+
interface can be used rather than an actual MATLAB Production Server
106+
instance running compiled CTF archives:
107+
108+
1. In MATLAB start the `Production Server Compiler` App.
109+
2. Enter `demo` as archive name.
110+
3. Add `Software/MATLAB/examples/MPSreceive.m` as exported function.
111+
4. Click `Test Client`.
112+
5. Click `Start` to start the test server.
113+
114+
3. Open `Software/Java/RabbitMQClient/src/main/resources/mps.yaml` and update
115+
the options to match your configuration.
116+
117+
```yaml
118+
# MATLAB Production Server connection properties
119+
mps:
120+
protocol: http # Protocol used by the MPS Instance
121+
host: localhost # Hostname or IP of the MPS Instance
122+
port: 9910 # Port the MPS Instance runs on
123+
archive: demo # Name of the CTF containing the function which
124+
# is to be called on MPS when a message received
125+
function: MPSreceive # Function inside the archive which is to be called
126+
timeoutms: 120000 # Timeout on the request to MATLAB Production Server
127+
# MessageBroker will log an error if the request
128+
# to MATLAB Production Server did not complete within
129+
# this time
130+
131+
# Messaging connection and routing properties
132+
messageQueue:
133+
queueName: RabbitMQ # Name of the Queue on RabbitMQ Server
134+
host: localhost # Hostname or IP of the RabbitMQ Server
135+
port: 5672 # Port the RabbitMQ Server runs on
136+
virtualhost: / # RabbitMQ Virtual Host
137+
credentials:
138+
username: guest # RabbitMQ username
139+
password: guest # RabbitMQ password
140+
exchange: amq.topic # Exchange to work with on RabbitMQ
141+
routingkey: test-topic # Routing key to subscribe to
142+
```
143+
144+
If indeed working with the MATLAB Compiler SDK MATLAB Production Server testing
145+
interface on your local machine configured as described in step 4, the `MATLAB
146+
Production Server connection properties` settings should be correct already.
147+
148+
4. To verify it is possible to successfully send a message to the RabbitMQ
149+
Server using this configuration, the `MessageSender` application can be used. It
150+
can be started using `MessageSenderStartup.bat` on Windows or using mvn on any
151+
system:
152+
153+
```
154+
mvn exec:java -Dexec.mainClass=com.mathworks.messaging.MessageSender -Dexec.args="src/main/resources/mps.yaml"
155+
```
156+
157+
In the client enter a message and routingkey, then in the RabbitMQ Admin Web Console
158+
verify that indeed a message was received on the configured `queue`. (Ctrl+C can be
159+
used to stop the application).
160+
161+
5. To complete the workflow, start `MessageBroker` by running
162+
`MessageBrokerStartup.bat` on Windows or alternatively run it using mvn:
163+
164+
```
165+
mvn exec:java -Dexec.mainClass=com.mathworks.messaging.MessageBroker -Dexec.args="src/main/resources/mps.yaml"
166+
```
167+
168+
This will receive messages from the message queue and then forward these to MATLAB
169+
Production Server to invoke the designated MATLAB `function`. The consumer will keep
170+
running, waiting for messages (Use Ctrl+C to stop the application).
171+
172+
6. Now when using `MessageSender` to send a message with the correct
173+
`routingkey` it should be received by `MessageBroker` which should then call
174+
the MATLAB Production Server (test) server. If indeed working with the test
175+
server inside MATLAB, the message should be displayed in the MATLAB Command
176+
Window.
177+
178+
[//]: # (Copyright 2022 The MathWorks, Inc.)

0 commit comments

Comments
 (0)