Commands
Command — a declarative description of an action to be performed on a remote service or locally.
Commands in Citeck use RabbitMQ queues as transport. Commands can be used in both synchronous and asynchronous modes.
Commands can target:
A service type (ecos-process, ecos-uiserv, alfresco, etc.). The command is executed by one of the instances of that service.
A service instance (each service type can have multiple instances).
All service types (broadcast commands). The command source service sends a broadcast command to RabbitMQ, and it is processed by all currently active services.
Command execution is performed using the CommandService service, specifically its execute and executeSync methods:
Commands can be either local (executed within a single service) or remote (the command is sent to another microservice; in this case, you must specify the microservice ID to which the command will be sent).
To implement a remote command:
Create a DTO in the service FROM which the command will be sent and where it will be executed. For example, if you need to send a command from alfresco to the integrations microservice, you need to create 2 identical classes — one in alfresco and one in the integrations microservice:
@Data
@CommandType("execute-spark-method")
public class SparkServiceMethodCommand {
private String dataSourceId;
private String methodName;
private Map<String, String> methodAttributes;
}
Make sure to specify the CommandType annotation with a unique command name (it determines which Executor the command will be assigned to — see step 3).
A response DTO is also required and must be implemented in both services.
Essentially, we send a DTO with data that gets converted to JSON, then sent to the target microservice where it is converted back to a DTO and processed by the executor. After processing, the executor must return a response DTO, which is also converted to JSON and sent back to where the command was originally invoked, where it is once again transformed from JSON into a ResponseDTO. For example, the response expected from executing the command with the DTO shown above:
@AllArgsConstructor
@NoArgsConstructor
@Data
public class SparkServiceMethodCommandResponse {
private String status;
private String xmlContent;
}
In the service TO WHICH the command is sent, you need to implement an Executor that will process the DTO.
In the executor, you need to implement the CommandExecutor<E> interface, where E is the incoming DTO (step 1).
You also need to implement the execute(E) method, which contains the actual command processing logic. It accepts the request DTO (step 1) as input, retrieves data from it, processes it, and then forms and returns a response DTO.
Example:
public class CallSparkServiceCommandExecutor implements CommandExecutor<SparkServiceMethodCommand> {
@Override
public SparkServiceMethodCommandResponse execute(SparkServiceMethodCommand executeServiceMethodCommand) {
String statusString = "Error";
String methodName = executeServiceMethodCommand.getMethodName();
if (methodName.equals("Complete")) {
statusString = "Done";
}
SparkServiceMethodCommandResponse response = new SparkServiceMethodCommandResponse();
response.setStatus(statusString);
response.setXmlContent("<?xml version=\"1.0\" encoding=\"UTF-8\"?><TestTag>Test</TestTag>");
return response;
}
}
An example of logic that simply checks the method name and forms a response DTO.
In the service FROM which we send the command request, we use CommandService to send the command, example:
public String sendSparkRequest(String dataSourceId, String methodName, Map<String, String> attributes) {
SparkServiceMethodCommand command = new SparkServiceMethodCommand();
command.setDataSourceId(dataSourceId);
command.setMethodName(methodName);
command.setMethodAttributes(attributes);
SparkServiceMethodCommandResponse result = commandsService.executeSync(command, "integrations")
.getResultAs(SparkServiceMethodCommandResponse.class);
return result.getXmlContent();
}
In this example, we form a DTO (a builder can also be used) and send the command to the integrations microservice, explicitly specifying this in the second parameter.
In the response, we expect a SparkServiceMethodCommandResponse DTO and use the .getResultAs method for automatic conversion of the response to a convenient DTO.