All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.yamcs.cascading.YamcsParameterLink Maven / Gradle / Ivy

There is a newer version: 5.10.9
Show newest version
package org.yamcs.cascading;

import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicLong;

import org.yamcs.YConfiguration;
import org.yamcs.client.Page;
import org.yamcs.client.ParameterSubscription;
import org.yamcs.client.YamcsClient;
import org.yamcs.client.base.WebSocketClient;
import org.yamcs.client.mdb.MissionDatabaseClient.ListOptions;
import org.yamcs.mdb.Mdb;
import org.yamcs.mdb.MdbFactory;
import org.yamcs.parameter.BasicParameterValue;
import org.yamcs.parameter.ParameterValue;
import org.yamcs.parameter.SystemParametersService;
import org.yamcs.protobuf.Mdb.ParameterInfo;
import org.yamcs.protobuf.Pvalue;
import org.yamcs.protobuf.SubscribeParametersRequest;
import org.yamcs.protobuf.Yamcs.NamedObjectId;
import org.yamcs.tctm.AbstractLink;
import org.yamcs.tctm.AggregatedDataLink;
import org.yamcs.tctm.ParameterDataLink;
import org.yamcs.tctm.ParameterSink;
import org.yamcs.utils.ValueUtility;
import org.yamcs.xtce.Parameter;
import org.yamcs.xtce.SpaceSystem;

/**
 * 
 * Yamcs Parameter link - receives parameters from a Yamcs upstream server.
 * 

* The parameters have to be defined in the local MDB and have the same name like in the remote MDB. This restriction * may be lifted in the new versions. * */ public class YamcsParameterLink extends AbstractLink implements ParameterDataLink { YamcsLink parentLink; List parameters; ParameterSubscription subscription; ParameterSink paraSink; AtomicLong paraCount = new AtomicLong(); int seqCount; Mdb mdb; // when subscribing to remote Yamcs parameters, we rename them to include the upstream name into their name Map remoteYamcsParams; public YamcsParameterLink(YamcsLink parentLink) { this.parentLink = parentLink; } public void init(String instance, String name, YConfiguration config) { config = YamcsTmLink.swapConfig(config, "ppRealtimeStream", "ppStream", "pp_realtime"); super.init(instance, name, config); this.parameters = config.getList("parameters"); this.mdb = MdbFactory.getInstance(instance); } @Override protected void doStart() { if (!isEffectivelyDisabled()) { doEnable(); } notifyStarted(); } @Override public void doDisable() { if (subscription != null) { subscription.cancel(true); subscription = null; } } @Override public void doEnable() { if (subscription != null && !subscription.isDone()) { return; } WebSocketClient wsclient = parentLink.getClient().getWebSocketClient(); if (wsclient.isConnected()) { subscribeParameters(); } } public void subscribeParameters() { YamcsClient yclient = parentLink.getClient(); subscription = yclient.createParameterSubscription(); subscription.addListener(new ParameterSubscription.Listener() { @Override public void onData(List values) { processParameters(values); } @Override public void onInvalidIdentification(NamedObjectId id) { log.warn("Parameter subscription raised invalid identification(could be lack of permission): {}", id); } }); SubscribeParametersRequest.Builder request = SubscribeParametersRequest.newBuilder() .setInstance(parentLink.getUpstreamInstance()) .setProcessor(parentLink.getUpstreamProcessor()) .setSendFromCache(false); HashSet toAdd = new HashSet<>(); List requestedYamcsParamsFilter = new ArrayList<>(); boolean requestAllRemoteYamcsParams = false; for(String p: parameters) { if (p.equals("/yamcs/") || p.equals("/yamcs")) { requestAllRemoteYamcsParams = true; requestedYamcsParamsFilter.add(p); } else if (p.startsWith("/yamcs/")) { requestedYamcsParamsFilter.add(p); } else if (p.endsWith("/")) { SpaceSystem sps = mdb.getSpaceSystem(p.substring(0, p.length() - 1)); if (sps == null) { log.warn("Cannot find space system {} in local MDB; ignoring", p); continue; } sps.getParameters().forEach(pdef -> toAdd.add(pdef.getQualifiedName())); } else { PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:" + p); boolean added = false; for (Parameter param : mdb.getParameters()) { if (matcher.matches(Path.of(param.getQualifiedName()))) { toAdd.add(param.getQualifiedName()); added = true; } } if (!added) { log.warn("Cannot find parameter {} in local MDB; ignoring", p); } } } toAdd.forEach(name -> request.addId(NamedObjectId.newBuilder().setName(name).build())); log.debug("Sending parameter subcription {}", request); subscription.sendMessage(request.build()); if (requestAllRemoteYamcsParams || !requestedYamcsParamsFilter.isEmpty()) { if (requestAllRemoteYamcsParams) { requestedYamcsParamsFilter.clear(); requestedYamcsParamsFilter.add("**"); } remoteYamcsParams = new HashMap<>(); var mdbClient = parentLink.getClient().createMissionDatabaseClient(parentLink.getUpstreamInstance()); collectRemoteYamcsParameters(requestedYamcsParamsFilter, mdbClient.listParameters(ListOptions.details(false), ListOptions.system("/yamcs"), ListOptions.q("/"))); } } private void collectRemoteYamcsParameters(List requestedYamcsParamsFilter, CompletableFuture> cf) { cf.whenComplete((page, t) -> { if (t != null) { log.warn("Failed to retrieve yamcs parameter names"); } else { for (String p : requestedYamcsParamsFilter) { PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:" + p); boolean match = false; for (ParameterInfo pi : page) { if (!pi.getQualifiedName().startsWith("/yamcs/")) { log.warn("Remote yamcs parameter that does not start with /yamcs/?? '{}'", pi.getQualifiedName()); continue; } if (matcher.matches(Path.of(pi.getQualifiedName()))) { String name = pi.getQualifiedName().replaceFirst("/yamcs/", "/yamcs/"+parentLink.getUpstreamName()+"_"); remoteYamcsParams.put(pi.getQualifiedName(), name); match = true; } } if (!match) { log.info("No Yamcs parameter matching " + p + " found on the upstream server"); } } if (page.hasNextPage()) { collectRemoteYamcsParameters(requestedYamcsParamsFilter, page.getNextPage()); } else { subscribeYamcsParameters(); } } }); } void subscribeYamcsParameters() { log.debug("Subscribing to the following yamcs parameters from upstream: {}", remoteYamcsParams.keySet()); SubscribeParametersRequest.Builder request = SubscribeParametersRequest.newBuilder() .setInstance(parentLink.getUpstreamInstance()) .setProcessor(parentLink.getUpstreamProcessor()) .setSendFromCache(false); remoteYamcsParams.keySet().forEach(name -> request.addId(NamedObjectId.newBuilder().setName(name).build())); subscription.sendMessage(request.build()); } private void processParameters(List values) { // group by time and group (although it's very likely they are already grouped by time) Map>> vmap = new HashMap<>(); for (Pvalue.ParameterValue gpv : values) { Parameter pdef; if (gpv.getId().getName().startsWith("/yamcs")) { String newName = remoteYamcsParams.get(gpv.getId().getName()); if (newName == null) { log.warn("Received system parameter not subscribed " + gpv); continue; } pdef = mdb.getParameter(newName); if (pdef == null) { pdef = SystemParametersService.createSystemParameter(mdb, newName, ValueUtility.fromGpb(gpv.getEngValue())); } } else { pdef = mdb.getParameter(gpv.getId()); } if (pdef == null) { log.warn("Ignoring unknown parameter {}", gpv.getId()); continue; } String group = pdef.getRecordingGroup(); ParameterValue pv = BasicParameterValue.fromGpb(pdef, gpv); List l = vmap.computeIfAbsent(pv.getGenerationTime(), x -> new HashMap<>()) .computeIfAbsent(group, x -> new ArrayList<>()); l.add(pv); } for (Map.Entry>> me : vmap.entrySet()) { long gentime = me.getKey(); for (Map.Entry> me1 : me.getValue().entrySet()) { paraSink.updateParameters(gentime, me1.getKey(), seqCount, me1.getValue()); paraCount.addAndGet(me1.getValue().size()); } seqCount++; } } @Override protected void doStop() { if (!isDisabled()) { doDisable(); } notifyStopped(); } @Override protected Status connectionStatus() { Status parentStatus = parentLink.connectionStatus(); if (parentStatus == Status.OK) { boolean ok = subscription != null && !subscription.isDone(); return ok ? Status.OK : Status.UNAVAIL; } else { return parentStatus; } } @Override public AggregatedDataLink getParent() { return parentLink; } @Override public long getDataInCount() { return paraCount.get(); } @Override public long getDataOutCount() { return 0; } @Override public void resetCounters() { paraCount.set(0); } @Override public void setParameterSink(ParameterSink parameterSink) { this.paraSink = parameterSink; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy