org.yamcs.artemis.RealtimeArtemisParameterService Maven / Gradle / Ivy
package org.yamcs.artemis;
import static org.yamcs.api.artemis.Protocol.*;
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.apache.activemq.artemis.api.core.client.MessageHandler;
import org.slf4j.Logger;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Maps;
import org.yamcs.*;
import org.yamcs.api.YamcsApiException;
import org.yamcs.api.artemis.Protocol;
import org.yamcs.api.artemis.YamcsClient;
import org.yamcs.api.artemis.YamcsSession;
import org.yamcs.parameter.ParameterRequestManagerImpl;
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 org.yamcs.security.AuthenticationToken;
import org.yamcs.security.HqClientMessageToken;
import org.yamcs.utils.LoggingUtils;
/**
* Provides realtime parameter subscription via artemis.
*
* Each connected client has one queue.
*
* @author nm
*
*/
public class RealtimeArtemisParameterService implements ParameterWithIdConsumer {
Processor channel;
YamcsClient yclient;
Logger log;
//maps subscription ids <-> addresses
BiMap subscriptions = Maps.synchronizedBiMap(HashBiMap.create());
ParameterWithIdRequestHelper prh;
YamcsSession yamcsSession;
public RealtimeArtemisParameterService(Processor proc) throws ActiveMQException, YamcsApiException {
this.channel=proc;
prh = new ParameterWithIdRequestHelper(proc.getParameterRequestManager(), this);
log = LoggingUtils.getLogger(this.getClass(), proc);
yamcsSession = YamcsSession.newBuilder().build();
SimpleString rpcAddress = Protocol.getParameterRealtimeAddress(proc.getInstance());
yclient=yamcsSession .newClientBuilder().setRpcAddress(rpcAddress).setDataProducer(true).build();
yclient.rpcConsumer.setMessageHandler(new MessageHandler() {
@Override
public void onMessage(ClientMessage message) {
try {
processRequest(message);
} catch (Exception e) {
log.error("got error when processing request",e);
}
}
});
}
private void processRequest(ClientMessage msg) throws YamcsApiException {
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 YamcsApiException {
List paraList=null;
try {
paraList= ((NamedObjectList)Protocol.decode(msg, NamedObjectList.newBuilder())).getListList();
} catch (YamcsApiException e) {
log.warn("Could not decode the parameter list", e);
return;
}
HqClientMessageToken authToken = new HqClientMessageToken(msg, null);
try {
if(subscriptions.containsValue(dataAddress)) {
int subscriptionId=subscriptions.inverse().get(dataAddress);
prh.addItemsToRequest(subscriptionId, paraList, authToken);
} else {
//TODO configure non-blocking
int subscriptionId=prh.addRequest(paraList, authToken);
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 YamcsApiException {
List paraList=null;
try {
paraList= ((NamedObjectList)Protocol.decode(msg, NamedObjectList.newBuilder())).getListList();
} catch (YamcsApiException e) {
log.warn("Could not decode the parameter list");
return;
}
AuthenticationToken authToken = new HqClientMessageToken(msg, null);
if(subscriptions.containsValue(dataAddress)) {
int subscriptionId=subscriptions.inverse().get(dataAddress);
try {
prh.removeItemsFromRequest(subscriptionId, paraList, authToken);
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 YamcsApiException {
String namespace=null;
try {
namespace=((StringMessage)Protocol.decode(msg, StringMessage.newBuilder())).getMessage();
} catch (YamcsApiException e) {
log.warn("Could not decode the namespace");
return;
}
if(subscriptions.containsValue(dataAddress)) {
yclient.sendErrorReply(replyto, "already subscribed for this address");
return;
}
AuthenticationToken authToken = new HqClientMessageToken(msg, null);
int subscriptionId= 0;
try {
subscriptionId = prh.subscribeAll(namespace, authToken);
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 YamcsApiException {
if(!subscriptions.containsValue(dataAddress)) {
yclient.sendErrorReply(replyto, "not subscribed for this address");
return;
}
ParameterRequestManagerImpl prm=channel.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 (YamcsApiException 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