package org.yamcs.xtceproc; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.yamcs.xtce.ContainerEntry; import org.yamcs.xtce.DynamicIntegerValue; import org.yamcs.xtce.Parameter; import org.yamcs.xtce.ParameterEntry; import org.yamcs.xtce.SequenceContainer; import org.yamcs.xtce.SequenceEntry; import org.yamcs.xtce.XtceDb; /** * keeps track of the parameters and containers subscribed (because we only want to extract those) * * * @author nm * */ public class Subscription { //Maps the packet definitions to the entries we actually need from these packets private final Map<SequenceContainer, TreeSet<SequenceEntry>> container2EntryMap = new HashMap<>(); //For each container list the derived containers which have to be processed also private final Map<SequenceContainer, HashSet<SequenceContainer>> container2InheritingContainerMap = new HashMap<>(); Logger log = LoggerFactory.getLogger(Subscription.class); XtceDb xtcedb; Subscription(XtceDb xtcedb) { this.xtcedb=xtcedb; } public void addSequenceContainer(SequenceContainer seq) { //if there is a base container, add that one to the subscription and the parameters which have to be // extracted from the base in order to know if the inheritance condition applies if(seq.getBaseContainer()!=null) { addContainer2InheritingContainer(seq.getBaseContainer(), seq); //it can be that the inheritance condition parameters are not from the baseContainer, so we need to add // it explicitely addSequenceContainer(seq.getBaseContainer()); for(Parameter p:seq.getRestrictionCriteria().getDependentParameters()) { addParameter(p); } } //if this container is part of another containers through aggregation, then add those List<ContainerEntry> entries=xtcedb.getContainerEntries(seq); if(entries!=null) { for(ContainerEntry ce:entries) { addSequenceEntry(ce); } if(seq.getSizeInBits()<0) { //desperately add all parameters from this container in order for the parent to know the size addAll(seq); } } } /** * Called in the cases when seq is part of other containers through aggregation. * The parent container will need to know the size of this one so we add all entries of seq. * @param seq */ public void addAll(SequenceContainer seq) { for(SequenceEntry se:seq.getEntryList()) { addContainer2Entry(seq, se); if(se instanceof ContainerEntry) { addAll(((ContainerEntry)se).getRefContainer()); } } List<SequenceContainer> inheriting=xtcedb.getInheritingContainers(seq); if(inheriting!=null) { for(SequenceContainer sc:inheriting) { addContainer2InheritingContainer(seq, sc); addAll(sc); } } } public void addSequenceEntry(SequenceEntry se) { boolean containerAlreadyAdded=container2EntryMap.containsKey(se.getSequenceContainer()); addContainer2Entry(se.getSequenceContainer(), se); SequenceEntry setmp=se; SequenceContainer sctmp=se.getSequenceContainer(); //if this entry's location is relative to the previous one, then we have to add also that one in the list if(setmp.getReferenceLocation()==SequenceEntry.ReferenceLocationType.previousEntry) { if(setmp.getIndex()>0) { setmp = sctmp.getEntryList().get(setmp.getIndex()-1); } else { //continue with the basecontainer if we are at the first entry sctmp = sctmp.getBaseContainer(); setmp = sctmp.getEntryList().get(sctmp.getEntryList().size()-1); } addSequenceEntry(setmp); } if((se.getRepeatEntry()!=null) && (se.getRepeatEntry().getCount() instanceof DynamicIntegerValue)) { addParameter(((DynamicIntegerValue) se.getRepeatEntry().getCount()).getParameterInstnaceRef().getParameter()); } if(!containerAlreadyAdded) { addSequenceContainer(se.getSequenceContainer()); } } /** * Add to the subscription all the entries and containers on which this parameter depends * @param parameter */ public void addParameter(Parameter parameter) { List<ParameterEntry> tpips=xtcedb.getParameterEntries(parameter); if(tpips==null) { log.warn("Parameter not part of any container: {}", parameter); return; } for(ParameterEntry pe:tpips) { addSequenceEntry(pe); } } private void addContainer2Entry(SequenceContainer sc, SequenceEntry se) { TreeSet<SequenceEntry> ts=container2EntryMap.get(sc); if(ts==null) { ts = new TreeSet<SequenceEntry>(); container2EntryMap.put(sc,ts); } ts.add(se); } private void addContainer2InheritingContainer(SequenceContainer container, SequenceContainer inheritedContainer) { HashSet<SequenceContainer> hs=container2InheritingContainerMap.get(container); if(hs==null) { hs = new HashSet<>(); container2InheritingContainerMap.put(container, hs); } hs.add(inheritedContainer); } public SortedSet<SequenceEntry> getEntries(SequenceContainer container) { return container2EntryMap.get(container); } public Set<SequenceContainer> getInheritingContainers(SequenceContainer container) { return container2InheritingContainerMap.get(container); } /** * Get the set of all containers subscribed * @return set of containers subscribed */ public Collection<SequenceContainer> getContainers() { Set<SequenceContainer> r = new HashSet<SequenceContainer>(); r.addAll(container2InheritingContainerMap.keySet()); for(HashSet<SequenceContainer> hs:container2InheritingContainerMap.values()) { r.addAll(hs); } r.addAll(container2EntryMap.keySet()); return r; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("Current list of parameter subscribed:\n"); for(SequenceContainer sc:container2EntryMap.keySet()) { sb.append(sc); sb.append(" with entries:\n"); for(SequenceEntry se:container2EntryMap.get(sc)){ sb.append("\t").append(se).append("\n"); } } sb.append("-----------------------------------\n"); sb.append("Container inheritance dependency\n"); for(SequenceContainer sc:container2InheritingContainerMap.keySet()) { sb.append(sc.getName()); sb.append("-->"); for(SequenceContainer sc1:container2InheritingContainerMap.get(sc)) { sb.append(sc1.getName()+" "); } sb.append("\n\n"); } return sb.toString(); } }