org.yamcs.artemis.RealtimeArtemisParameterService 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.artemis;
import static org.yamcs.api.artemis.Protocol.DATA_TO_HEADER_NAME;
import static org.yamcs.api.artemis.Protocol.REPLYTO_HEADER_NAME;
import static org.yamcs.api.artemis.Protocol.REQUEST_TYPE_HEADER_NAME;
import java.util.List;
import org.apache.activemq.artemis.api.core.ActiveMQException;
import org.apache.activemq.artemis.api.core.SimpleString;
import org.apache.activemq.artemis.api.core.client.ClientMessage;
import org.yamcs.InvalidIdentification;
import org.yamcs.InvalidRequestIdentification;
import org.yamcs.NoPermissionException;
import org.yamcs.Processor;
import org.yamcs.YamcsException;
import org.yamcs.api.artemis.ArtemisApiException;
import org.yamcs.api.artemis.Protocol;
import org.yamcs.api.artemis.YamcsClient;
import org.yamcs.api.artemis.YamcsSession;
import org.yamcs.logging.Log;
import org.yamcs.parameter.ParameterRequestManager;
import org.yamcs.parameter.ParameterValue;
import org.yamcs.parameter.ParameterValueWithId;
import org.yamcs.parameter.ParameterWithIdConsumer;
import org.yamcs.parameter.ParameterWithIdRequestHelper;
import org.yamcs.protobuf.Pvalue.ParameterData;
import org.yamcs.protobuf.Yamcs.NamedObjectId;
import org.yamcs.protobuf.Yamcs.NamedObjectList;
import org.yamcs.protobuf.Yamcs.ProtoDataType;
import org.yamcs.protobuf.Yamcs.StringMessage;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Maps;
/**
* Provides realtime parameter subscription via artemis.
*
* Each connected client has one queue.
*
* @author nm
*
*/
public class RealtimeArtemisParameterService implements ParameterWithIdConsumer {
Processor processor;
YamcsClient yclient;
Log log;
// maps subscription ids <-> addresses
BiMap subscriptions = Maps.synchronizedBiMap(HashBiMap. create());
ParameterWithIdRequestHelper prh;
YamcsSession yamcsSession;
public RealtimeArtemisParameterService(Processor proc) throws ActiveMQException, ArtemisApiException {
this.processor = proc;
prh = new ParameterWithIdRequestHelper(proc.getParameterRequestManager(), this);
log = new Log(getClass(), proc.getInstance());
log.setContext(proc.getName());
yamcsSession = YamcsSession.newBuilder().build();
SimpleString rpcAddress = Protocol.getParameterRealtimeAddress(proc.getInstance());
yclient = yamcsSession.newClientBuilder().setRpcAddress(rpcAddress).setDataProducer(true).build();
yclient.rpcConsumer.setMessageHandler(message -> {
try {
processRequest(message);
} catch (Exception e) {
log.error("got error when processing request", e);
}
});
}
private void processRequest(ClientMessage msg) throws ArtemisApiException {
SimpleString replyto = msg.getSimpleStringProperty(REPLYTO_HEADER_NAME);
if (replyto == null) {
log.warn("did not receive a replyto header. Ignoring the request");
return;
}
String request = msg.getStringProperty(REQUEST_TYPE_HEADER_NAME);
log.debug("received a new request: {}", request);
SimpleString dataAddress = msg.getSimpleStringProperty(DATA_TO_HEADER_NAME);
if (dataAddress == null) {
yclient.sendErrorReply(replyto, "subscribe has to come with a data address (to send data to)");
return;
}
if ("subscribe".equalsIgnoreCase(request)) {
subscribe(replyto, dataAddress, msg);
} else if ("subscribeAll".equalsIgnoreCase(request)) {
subscribeAll(replyto, dataAddress, msg);
} else if ("unsubscribe".equalsIgnoreCase(request)) {
unsubscribe(replyto, dataAddress, msg);
} else if ("unsubscribeAll".equalsIgnoreCase(request)) {
unsubscribeAll(replyto, dataAddress, msg);
} else {
yclient.sendErrorReply(replyto, "unknown request '" + request + "'");
}
}
private void subscribe(SimpleString replyto, SimpleString dataAddress, ClientMessage msg)
throws ArtemisApiException {
List paraList = null;
try {
paraList = ((NamedObjectList) Protocol.decode(msg, NamedObjectList.newBuilder())).getListList();
} catch (ArtemisApiException e) {
log.warn("Could not decode the parameter list", e);
return;
}
try {
if (subscriptions.containsValue(dataAddress)) {
int subscriptionId = subscriptions.inverse().get(dataAddress);
prh.addItemsToRequest(subscriptionId, paraList, null);
} else {
// TODO configure non-blocking
int subscriptionId = prh.addRequest(paraList, null);
subscriptions.put(subscriptionId, dataAddress);
}
yclient.sendReply(replyto, "OK", null);
} catch (InvalidIdentification e) {
NamedObjectList nol = NamedObjectList.newBuilder().addAllList(e.getInvalidParameters()).build();
yclient.sendErrorReply(replyto, new YamcsException("InvalidIdentification", "Invalid Identification", nol));
} catch (InvalidRequestIdentification e) {
log.error("got invalid subscription id", e);
yclient.sendErrorReply(replyto, "internal error: " + e.toString());
} catch (NoPermissionException e) {
log.error("No permission.", e);
yclient.sendErrorReply(replyto, e);
}
}
private void unsubscribe(SimpleString replyto, SimpleString dataAddress, ClientMessage msg)
throws ArtemisApiException {
List paraList = null;
try {
paraList = ((NamedObjectList) Protocol.decode(msg, NamedObjectList.newBuilder())).getListList();
} catch (ArtemisApiException e) {
log.warn("Could not decode the parameter list");
return;
}
if (subscriptions.containsValue(dataAddress)) {
int subscriptionId = subscriptions.inverse().get(dataAddress);
try {
prh.removeItemsFromRequest(subscriptionId, paraList, null);
yclient.sendReply(replyto, "OK", null);
} catch (NoPermissionException e) {
log.error("No permission.", e);
yclient.sendErrorReply(replyto, e);
}
} else {
yclient.sendErrorReply(replyto, "not subscribed to anything");
return;
}
yclient.sendReply(replyto, "OK", null);
}
private void subscribeAll(SimpleString replyto, SimpleString dataAddress, ClientMessage msg)
throws ArtemisApiException {
String namespace = null;
try {
namespace = ((StringMessage) Protocol.decode(msg, StringMessage.newBuilder())).getMessage();
} catch (ArtemisApiException e) {
log.warn("Could not decode the namespace");
return;
}
if (subscriptions.containsValue(dataAddress)) {
yclient.sendErrorReply(replyto, "already subscribed for this address");
return;
}
int subscriptionId = 0;
try {
subscriptionId = prh.subscribeAll(null);
subscriptions.put(subscriptionId, dataAddress);
yclient.sendReply(replyto, "OK", null);
} catch (NoPermissionException e) {
log.error("No permission.", e);
yclient.sendErrorReply(replyto, e);
}
}
private void unsubscribeAll(SimpleString replyto, SimpleString dataAddress, ClientMessage msg)
throws ArtemisApiException {
if (!subscriptions.containsValue(dataAddress)) {
yclient.sendErrorReply(replyto, "not subscribed for this address");
return;
}
ParameterRequestManager prm = processor.getParameterRequestManager();
int subscriptionId = subscriptions.inverse().get(dataAddress);
boolean r = prm.unsubscribeAll(subscriptionId);
if (r) {
yclient.sendReply(replyto, "OK", null);
subscriptions.remove(subscriptionId);
} else {
yclient.sendErrorReply(replyto, "not a subscribeAll subscription for this address");
}
}
@Override
public void update(int subscriptionId, List paramList) {
SimpleString addr = subscriptions.get(subscriptionId);
ParameterData.Builder pd = ParameterData.newBuilder();
for (ParameterValueWithId pvwi : paramList) {
ParameterValue pv = pvwi.getParameterValue();
org.yamcs.protobuf.Pvalue.ParameterValue gpv = pv.toGpb(pvwi.getId());
pd.addParameter(gpv);
}
try {
yclient.sendData(addr, ProtoDataType.PARAMETER, pd.build());
} catch (ArtemisApiException e) {
subscriptions.remove(addr);
log.warn("got error when sending parameter updates, removing any subscription of " + addr, e);
}
}
public void quit() {
try {
yamcsSession.close();
} catch (ActiveMQException e) {
log.warn("Error when closing yamcsSession", e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy