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

org.yamcs.parameter.ParameterRequestManager Maven / Gradle / Ivy

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

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import org.yamcs.ConfigurationException;
import org.yamcs.InvalidIdentification;
import org.yamcs.InvalidRequestIdentification;
import org.yamcs.Processor;
import org.yamcs.logging.Log;
import org.yamcs.protobuf.Yamcs.NamedObjectId;
import org.yamcs.xtce.Parameter;

/**
 * Distributes parameters from {@link ParameterProcessorManager} to {@link ParameterConsumer}
 * 

* The consumers will subscribe to parameters, this class (we call it PRM) will subscribe itself to providers * and send to consumers each time the providers provide some values. * */ public class ParameterRequestManager { Log log; // Maps the parameters to the request(subscription id) in which they have been asked private ConcurrentHashMap param2RequestMap = new ConcurrentHashMap<>(); // Maps the request (subscription id) to the consumer private Map request2ParameterConsumerMap = new ConcurrentHashMap<>(); // contains subscribe all private SubscriptionArray subscribeAllConsumers = new SubscriptionArray(); private static AtomicInteger lastSubscriptionId = new AtomicInteger(); public final Processor processor; LastValueCache lastValueCache; ParameterProcessorManager ppm; /** * Creates a new ParameterRequestManager, configured to listen to the specified XtceTmProcessor. */ public ParameterRequestManager(ParameterProcessorManager ppm) throws ConfigurationException { this.processor = ppm.processor; this.ppm = ppm; log = new Log(getClass(), processor.getInstance()); log.setContext(processor.getName()); this.lastValueCache = processor.getLastValueCache(); } /** * called by a consumer to subscribe to all parameters */ public int subscribeAll(ParameterConsumer consumer) { int id = lastSubscriptionId.incrementAndGet(); log.debug("new subscribeAll with subscriptionId {}", id); ppm.subscribeAllToProviders(); subscribeAllConsumers.add(id); request2ParameterConsumerMap.put(id, consumer); return id; } /** * called by a consumer to remove a "subscribe all" subscription * * return true of the subscription has been removed or false if it was not there * * @param subscriptionId * @return */ public boolean unsubscribeAll(int subscriptionId) { return subscribeAllConsumers.remove(subscriptionId); } /** * Called by a consumer to create a new subscription * * @param paraList * @param tpc * @return the newly created subscription id */ public int addRequest(final Collection paraList, final ParameterConsumer tpc) { final int id = lastSubscriptionId.incrementAndGet(); log.debug("new request with subscriptionId {} with {} items", id, paraList.size()); subscribeToProviders(paraList); for (Parameter p : paraList) { log.trace("adding to subscriptionID: {} item:{} ", id, p.getQualifiedName()); addItemToRequest(id, p); } request2ParameterConsumerMap.put(id, tpc); return id; } /** * Called by a consumer to create a subscription with one parameter * * @param para * @param tpc * @return the newly created subscription id */ public int addRequest(final Parameter para, final ParameterConsumer tpc) { final int id = lastSubscriptionId.incrementAndGet(); log.debug("new request with subscriptionId {} for parameter: {}", id, para.getQualifiedName()); subscribeToProviders(para); addItemToRequest(id, para); request2ParameterConsumerMap.put(id, tpc); return id; } /** * Called by a consumer to create request with a given id. This is called when switching processors, the id is * coming from the other processor. * * @param subscriptionId * - subscription id * @param paraList * @param tpc */ public void addRequest(int subscriptionId, List paraList, ParameterConsumer tpc) { subscribeToProviders(paraList); for (int i = 0; i < paraList.size(); i++) { log.trace("creating subscriptionID:{} with item:{}", subscriptionId, paraList.get(i)); addItemToRequest(subscriptionId, paraList.get(i)); } request2ParameterConsumerMap.put(subscriptionId, tpc); } /** * Called by a consumer to add a parameter to an existing subscription. * * @param subscriptionId * @param para */ public void addItemsToRequest(final int subscriptionId, final Parameter para) throws InvalidRequestIdentification { log.debug("adding to subscriptionID {}: items: {} ", subscriptionId, para.getName()); verifySubscriptionId(subscriptionId); subscribeToProviders(para); addItemToRequest(subscriptionId, para); } /** * Called by a consumer to add parameters to an existing subscription. * * @param subscriptionId * @param paraList * list of parameters that are added to the subscription * @throws InvalidRequestIdentification */ public void addItemsToRequest(final int subscriptionId, final List paraList) throws InvalidRequestIdentification { log.debug("adding to subscriptionID {}: {} items ", subscriptionId, paraList.size()); verifySubscriptionId(subscriptionId); subscribeToProviders(paraList); for (int i = 0; i < paraList.size(); i++) { addItemToRequest(subscriptionId, paraList.get(i)); } } private void verifySubscriptionId(int subscriptionId) throws InvalidRequestIdentification { if (!request2ParameterConsumerMap.containsKey(subscriptionId)) { throw new InvalidRequestIdentification("no such subscriptionID", subscriptionId); } } /** * Called by a consumer to remove a parameter from a subscription. *

* If the parameter is not part of the subscription, the operation will have no effect. * * @param subscriptionID * @param param */ public void removeItemsFromRequest(int subscriptionID, Parameter param) { removeItemFromRequest(subscriptionID, param); } /** * Called by a consumer to remove parameters from a subscription. *

* Any parameter that is not in the subscription will be ignored. * * @param subscriptionID * @param paraList */ public void removeItemsFromRequest(int subscriptionID, List paraList) { for (int i = 0; i < paraList.size(); i++) { removeItemFromRequest(subscriptionID, paraList.get(i)); } } private void addItemToRequest(int id, Parameter para) { SubscriptionArray al_req = param2RequestMap.computeIfAbsent(para, k -> new SubscriptionArray()); al_req.add(id); } private void removeItemFromRequest(int subscriptionId, Parameter para) { if (param2RequestMap.containsKey(para)) { // is there really any request associated to this parameter? SubscriptionArray al_req = param2RequestMap.get(para); // remove the subscription from the list of this parameter if (al_req.remove(subscriptionId)) { /* * Don't remove the al_req from the map and * don't ask provider to stop providing * because it is not thread safe (maybe another thread just asked to start providing after seeing that * the list is empty * if(al_req.isEmpty()) { //nobody wants this parameter anymore * if(!cacheAll) provider.stopProviding(para); * } */ } else { log.warn("parameter removal requested for {} but not part of subscription {}", para, subscriptionId); } } else { log.warn("parameter removal requested for {} but not subscribed", para); } } /** * Removes all the parameters from a subscription and returns them into an List. * */ public List removeRequest(int subscriptionId) { log.debug("removing request for subscriptionId {}", subscriptionId); // It's a bit annoying that we have to loop through all the parameters to find the ones that // are relevant for this request. We could keep track of an additional map. ArrayList result = new ArrayList<>(); // loop through all the parameter definitions // find all the subscriptions with the requested subscriptionId and add their corresponding // itemId to the list. Iterator> it = param2RequestMap.entrySet().iterator(); while (it.hasNext()) { Map.Entry m = it.next(); Parameter param = m.getKey(); SubscriptionArray al_req = m.getValue(); if (al_req.remove(subscriptionId)) { result.add(param); } if (al_req.isEmpty()) { // nobody wants this parameter anymore /* * if(!cacheAll) { commented out because not thread safe * getProvider(param).stopProviding(param); * } */ } } request2ParameterConsumerMap.remove(subscriptionId); return result; } private void subscribeToProviders(Parameter param) throws NoProviderException { ppm.subscribeToProviders(param); } /** * Called to subscribe to providers for the given parameters. *

* Unless already subscribed, the PRM will start delivering from now on those parameters. * * * @param itemList */ public void subscribeToProviders(Collection itemList) { ppm.subscribeToProviders(itemList); } /** * returns a parameter based on fully qualified name * * @param fqn * @return * @throws InvalidIdentification */ public Parameter getParameter(String fqn) throws InvalidIdentification { return ppm.getParameter(fqn); } /** * @param paraId * @return the corresponding parameter definition for a IntemIdentification * @throws InvalidIdentification * in case no provider knows of this parameter. */ public Parameter getParameter(NamedObjectId paraId) throws InvalidIdentification { return ppm.getParameter(paraId); } /** * Called by a provider with a list of provided parameters called "current delivery". *

* The PRM will take ownership of the current delivery (and modify it!). * *

* The following steps are performed (in the provider thread, possible by multiple providers in parallel!): *

    *
  1. Run algorithms. All results from algorithms are also added to the list.
  2. *
  3. Check alarms.
  4. *
  5. Distribute to subscribers.
  6. *
  7. Add to parameter cache (if enabled).
  8. *
  9. Add to the last value cache.
  10. *
* * */ public void update(ParameterValueList pvlist) { // build the customised lists for the subscribers and send it to them HashMap> subscription = new HashMap<>(); updateSubscription(subscription, pvlist); for (Map.Entry> entry : subscription.entrySet()) { Integer subscriptionId = entry.getKey(); ArrayList al = entry.getValue(); ParameterConsumer consumer = request2ParameterConsumerMap.get(subscriptionId); if (consumer == null) { log.warn("subscriptionId {} appears in the delivery list, but there is no consumer for it", subscriptionId); } else { consumer.updateItems(subscriptionId, al); } } } /** * adds the passed parameters to the subscription * * @param subscription * @param currentDelivery */ private void updateSubscription(HashMap> subscription, Collection currentDelivery) { if (currentDelivery == null) { return; } for (Iterator it = currentDelivery.iterator(); it.hasNext();) { ParameterValue pv = it.next(); Parameter pDef = pv.getParameter(); SubscriptionArray cowal = param2RequestMap.get(pDef); // now walk through the requests and add this item to their delivery list if (cowal == null) { continue; } for (int s : cowal.getArray()) { ArrayList al = subscription.get(s); if (al == null) { al = new ArrayList<>(); subscription.put(s, al); } al.add(pv); } } // update the subscribeAll subscriptions for (int id : subscribeAllConsumers.getArray()) { ArrayList al = subscription.get(id); if (al == null) { al = new ArrayList<>(); subscription.put(id, al); } for (ParameterValue pv : currentDelivery) { al.add(pv); } } } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("Current Subscription list:\n"); for (Parameter param : param2RequestMap.keySet()) { sb.append(param); sb.append("requested by ["); SubscriptionArray al_req = param2RequestMap.get(param); for (int id : al_req.getArray()) { sb.append(id); } sb.append("]\n"); } return sb.toString(); } /** * Returns the last known value for each parameter. * * @param plist * @return */ public List getValuesFromCache(Collection plist) { List al = new ArrayList<>(plist.size()); for (Parameter p : plist) { ParameterValue pv = lastValueCache.getValue(p); if (pv != null) { al.add(pv); } } return al; } /** * Get the last value from cache for a specific parameters * * @param param * @return */ public ParameterValue getLastValueFromCache(Parameter param) { return lastValueCache.getValue(param); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy