org.yamcs.api.artemis.YamcsClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of yamcs-artemis Show documentation
Show all versions of yamcs-artemis Show documentation
Yamcs Artemis senders/receivers
package org.yamcs.api.artemis;
import java.io.IOException;
import java.util.UUID;
import org.apache.activemq.artemis.api.core.ActiveMQException;
import org.apache.activemq.artemis.api.core.SimpleString;
import org.apache.activemq.artemis.api.core.client.ClientConsumer;
import org.apache.activemq.artemis.api.core.client.ClientMessage;
import org.apache.activemq.artemis.api.core.client.ClientProducer;
import org.apache.activemq.artemis.api.core.client.ClientSession;
import org.yamcs.YamcsException;
import org.yamcs.api.YamcsApiException;
import org.yamcs.protobuf.Yamcs.ProtoDataType;
import org.yamcs.protobuf.Yamcs.StringMessage;
import com.google.protobuf.MessageLite;
import static org.yamcs.api.artemis.Protocol.*;
/**
* Collect here scenarios and corresponding methods for sending/receiving data:
* sendRequest via rpcProducer
* - "method" name as property and parameters as a ProtoBuf message
* - should automatically encode the replyTo address
* sendReply via rpcProducer
* - OK/NOK as property and return parameters as a ProtoBuf message
* - should somehow correlate with the request TODO
*
* executeRpc via rpcProducer/rpcConsumer
* -sendRequest and wait for replay a configurable timeout
*
* sendData via dataProducer
* - one chunk in a stream of data.
* - should manage end of stream conditions
* - should manage multiplexing different ProtoBuf message types
*
* sendEvent via dataProducer
* - event name as property and parameters as ProtoBuf message
*
*
* @author nm
*
*/
public class YamcsClient {
public final static String DATA_ADDRESS_PREFIX="tempDataAddress.";
public final static String DATA_QUEUE_PREFIX="tempDataQueue.";
public final static String RPC_ADDRESS_PREFIX="tempRpcAddress.";
public final static String RPC_QUEUE_PREFIX="tempRpcQueue.";
public ClientConsumer dataConsumer;
public SimpleString dataQueue;
public SimpleString dataAddress;
public SimpleString rpcAddress; //this is my own address, messages are received via the consumer
public SimpleString rpcQueue;
public ClientConsumer rpcConsumer;
public ClientProducer rpcProducer;
private ClientProducer dataProducer;
public long rpcTimeout=10000;
long dataTimeout=10000;
private final YamcsSession yamcsSession;
YamcsClient(YamcsSession yamcsSession) {
this.yamcsSession=yamcsSession;
}
public void sendErrorReply(SimpleString replyto, String message) throws YamcsApiException {
synchronized(yamcsSession) {
ClientMessage replyMsg = yamcsSession.session.createMessage(false);
replyMsg.putStringProperty(MSG_TYPE_HEADER_NAME, "ERROR");
replyMsg.putStringProperty(ERROR_MSG_HEADER_NAME, message);
try {
rpcProducer.send(replyto, replyMsg);
} catch (ActiveMQException e1) {
throw new YamcsApiException("Failed to send message to "+replyto, e1);
}
}
}
/**
* Sends a ActiveMQ message containing an YamcsException.
* The exception type and string message are encoded in the headers while the extra payload (if any) is encoded in the body
*
* The exception extra arguments are encoded as
* @param replyto
* @param e
* @throws YamcsApiException
*/
public void sendErrorReply(SimpleString replyto, YamcsException e) throws YamcsApiException {
synchronized(yamcsSession) {
ClientMessage replyMsg = yamcsSession.session.createMessage(false);
replyMsg.putStringProperty(MSG_TYPE_HEADER_NAME, "ERROR");
replyMsg.putStringProperty(ERROR_MSG_HEADER_NAME, e.getMessage());
String type=e.getType();
if(type!=null) {
replyMsg.putStringProperty(ERROR_TYPE_HEADER_NAME, type);
}
byte[] body=e.getExtra();
if(body!=null) {
replyMsg.getBodyBuffer().writeBytes(body);;
}
try {
rpcProducer.send(replyto, replyMsg);
} catch (ActiveMQException e1) {
throw new YamcsApiException("Failed to send message to "+replyto, e1);
}
}
}
public void sendReply(SimpleString replyto, String response, MessageLite body) throws YamcsApiException {
synchronized(yamcsSession) {
ClientMessage replyMsg = yamcsSession.session.createMessage(false);
replyMsg.putStringProperty(MSG_TYPE_HEADER_NAME, response);
if(body!=null) {
encode(replyMsg, body);
}
try {
rpcProducer.send(replyto, replyMsg);
} catch (ActiveMQException e) {
throw new YamcsApiException("Cannot send data to "+replyto, e);
}
}
}
public void sendRequest(SimpleString toAddress, String request, MessageLite body) throws YamcsApiException {
synchronized(yamcsSession) {
ClientMessage msg=yamcsSession.session.createMessage(false);
msg.putStringProperty(REPLYTO_HEADER_NAME, rpcAddress);
if(dataAddress!=null)
msg.putStringProperty(DATA_TO_HEADER_NAME, dataAddress);
msg.putStringProperty(REQUEST_TYPE_HEADER_NAME, request);
if(body!=null) {
encode(msg,body);
}
try {
rpcProducer.send(toAddress, msg);
} catch (ActiveMQException e) {
throw new YamcsApiException("Cannot send data to "+toAddress, e);
}
}
}
public MessageLite executeRpc(SimpleString toAddress, String request, MessageLite body, MessageLite.Builder responseBuilder) throws YamcsApiException, YamcsException {
synchronized(yamcsSession) {
try {
sendRequest(toAddress, request, body);
ClientMessage msg = rpcConsumer.receive(rpcTimeout);
if(msg==null) {
throw new YamcsApiException("did not receive a response to "+request+" in "+rpcTimeout+" milliseconds");
}
String resp=msg.getStringProperty(MSG_TYPE_HEADER_NAME);
if("ERROR".equals(resp)) {
String type=null;
if(msg.containsProperty(ERROR_TYPE_HEADER_NAME)) {
type=msg.getStringProperty(ERROR_TYPE_HEADER_NAME);
}
String errormsg=msg.getStringProperty(ERROR_MSG_HEADER_NAME);
int size=msg.getBodySize();
byte[] extra=null;
if(size>0) {
extra=new byte[size];
msg.getBodyBuffer().readBytes(extra);
}
throw new YamcsException(type, errormsg, extra);
}
if(responseBuilder==null) {
return null;
}
else return decode(msg, responseBuilder);
} catch (ActiveMQException e) {
throw new YamcsApiException(e.getMessage(), e);
}
}
}
public void close() throws ActiveMQException {
if(rpcProducer!=null) {
rpcProducer.close();
}
if(rpcConsumer!=null) {
rpcConsumer.close();
}
if(dataConsumer!=null) {
dataConsumer.close();
}
if(dataProducer!=null) {
dataProducer.close();
}
}
public void sendDataError(SimpleString toAddress, String message) throws IOException, YamcsApiException {
synchronized(yamcsSession) {
sendData(toAddress, ProtoDataType.DT_ERROR, StringMessage.newBuilder().setMessage(message).build());
}
}
public void sendData(SimpleString toAddress, org.yamcs.protobuf.Yamcs.ProtoDataType type, MessageLite data) throws YamcsApiException {
synchronized(yamcsSession) {
ClientMessage msg=yamcsSession.session.createMessage(false);
msg.putIntProperty(DATA_TYPE_HEADER_NAME, type.getNumber());
if(data!=null){
encode(msg,data);
}
try {
dataProducer.send(toAddress, msg);
} catch (ActiveMQException e) {
throw new YamcsApiException("Cannot send data to "+toAddress, e);
}
}
}
public void sendDataEnd(SimpleString toAddress) throws YamcsApiException {
synchronized(yamcsSession) {
ClientMessage msg=yamcsSession.session.createMessage(false);
msg.putIntProperty(DATA_TYPE_HEADER_NAME, ProtoDataType.STATE_CHANGE.getNumber());
try {
dataProducer.send(toAddress,msg);
} catch (ActiveMQException e) {
throw new YamcsApiException("Failed to send data to "+toAddress, e);
}
}
}
/**
* Receives and decodes data
* Returns null if the FINISH message is received
*/
public MessageLite receiveData(MessageLite.Builder dataBuilder) throws YamcsException, YamcsApiException, ActiveMQException {
ClientMessage msg = dataConsumer.receive(dataTimeout);
if(msg==null) {
throw new YamcsException("did not received a data message, timeout"+dataTimeout);
}
int dt=msg.getIntProperty(DATA_TYPE_HEADER_NAME);
if(dt==ProtoDataType.STATE_CHANGE.getNumber()){
return null;
} else if(dt==ProtoDataType.DT_ERROR.getNumber()) {
StringMessage errormsg=(StringMessage) decode(msg, StringMessage.newBuilder());
throw new YamcsException(errormsg.getMessage());
}
return decode(msg,dataBuilder);
}
public MessageLite receiveImmediate(MessageLite.Builder dataBuilder) throws YamcsException, YamcsApiException {
ClientMessage msg;
try {
msg = dataConsumer.receive(dataTimeout);
} catch (ActiveMQException e) {
throw new YamcsApiException("Exception receiving data", e);
}
if(msg==null) {
return null;
}
int dt = msg.getIntProperty(DATA_TYPE_HEADER_NAME);
if(dt==ProtoDataType.STATE_CHANGE.getNumber()){
return null;
} else if(dt==ProtoDataType.DT_ERROR.getNumber()) {
StringMessage errormsg=(StringMessage) decode(msg, StringMessage.newBuilder());
throw new YamcsException(errormsg.getMessage());
}
return decode(msg,dataBuilder);
}
/**
* sends an event via the dataProducer
* @param toAddress
* @param eventName name of the event to be encoded in the {@value Protocol#HDR_EVENT_NAME} header
* @param data
* @throws ActiveMQException
*/
public void sendEvent(SimpleString toAddress, String eventName, MessageLite data) throws ActiveMQException {
synchronized(yamcsSession) {
ClientMessage msg=yamcsSession.session.createMessage(false);
msg.putStringProperty(HDR_EVENT_NAME, eventName);
if(data!=null){
encode(msg,data);
}
dataProducer.send(toAddress, msg);
}
}
public YamcsSession getYamcsSession() {
return yamcsSession;
}
public static class ClientBuilder {
boolean invm=true;
boolean dataProducer=false;
boolean dataConsumer=false;
boolean rpc=false;
SimpleString rpcAddress;
SimpleString rpcQueue;
SimpleString dataAddress;
SimpleString dataQueue;
SimpleString filter=null;
final YamcsSession yamcsSession;
private boolean browseOnly=false;
public ClientBuilder(YamcsSession yamcsSession) {
if(yamcsSession.session==null) {
throw new IllegalArgumentException();
}
this.yamcsSession=yamcsSession;
}
/**
* mark this as a rpc client
* @param rpc
* @return
*/
public ClientBuilder setRpc(boolean rpc) {
this.rpc=rpc;
return this;
}
/**
* mark this as a rpc server and set the rpc address
* @param address
* @return
*/
public ClientBuilder setRpcAddress(SimpleString address) {
this.rpc=true;
this.rpcAddress=address;
return this;
}
/**
* Create a data producer. The address to send to is specified when sending each message
* @param b
* @return
*/
public ClientBuilder setDataProducer(boolean b) {
dataProducer=b;
return this;
}
/**
* Create a data consumer from the specified address and queue.
* Both can be null in which case a temporary address and/or a temporary queue are created,
* @param address
* @param queue
* @return
*/
public ClientBuilder setDataConsumer(SimpleString address, SimpleString queue) {
this.dataConsumer=true;
this.dataAddress = address;
this.dataQueue = queue;
return this;
}
/**
* Sets a filter for the data consumer
* @param filter
* @return
*/
public ClientBuilder setFilter(SimpleString filter) {
this.filter=filter;
return this;
}
/**
* Sets the data consumer browseOnly property
* @param b
* @return
*/
public ClientBuilder setBrowseOnly(boolean b) {
this.browseOnly=b;
return this;
}
public YamcsClient build() throws YamcsApiException {
try {
YamcsClient c=new YamcsClient(yamcsSession);
if(rpc) {
c.rpcAddress = (rpcAddress==null)?new SimpleString(RPC_ADDRESS_PREFIX + UUID.randomUUID().toString()):rpcAddress;
c.rpcQueue = (rpcQueue==null)?new SimpleString(RPC_QUEUE_PREFIX + UUID.randomUUID().toString()):rpcQueue;
createAddressAndQueue(yamcsSession.session, c.rpcAddress, c.rpcQueue, filter);
c.rpcConsumer = yamcsSession.session.createConsumer(c.rpcQueue);
c.rpcProducer = yamcsSession.session.createProducer();
}
if(dataConsumer) {
c.dataAddress = (dataAddress==null)?new SimpleString(DATA_ADDRESS_PREFIX + UUID.randomUUID().toString()):dataAddress;
c.dataQueue = (dataQueue==null)?new SimpleString(DATA_QUEUE_PREFIX + UUID.randomUUID().toString()):dataQueue;
createAddressAndQueue(yamcsSession.session, c.dataAddress, c.dataQueue, filter);
c.dataConsumer = yamcsSession.session.createConsumer(c.dataQueue, browseOnly);
}
if(dataProducer) {
c.dataProducer = yamcsSession.session.createProducer();
}
return c;
} catch (ActiveMQException e) {
throw new YamcsApiException("cannot create yamcs client: "+e.getMessage(), e);
}
}
static void createAddressAndQueue(ClientSession session, SimpleString a, SimpleString q, SimpleString filter) throws ActiveMQException {
if(!session.queueQuery(q).isExists()) {
if(filter==null) {
session.createTemporaryQueue(a, q);
} else {
session.createTemporaryQueue(a, q, filter);
}
}
}
}
/**
* Send message to the address using the data producer.
*
* @param hornetAddress
* @param msg
* @throws YamcsApiException
*/
public synchronized void sendData(SimpleString hornetAddress, ClientMessage msg) throws YamcsApiException {
synchronized(yamcsSession) {
try {
dataProducer.send(hornetAddress, msg);
} catch (ActiveMQException e) {
throw new YamcsApiException("Failed to send message to "+hornetAddress, e);
}
}
}
public ClientProducer getDataProducer() {
return dataProducer;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy