TdmParser.java

  1. /* Copyright 2002-2022 CS GROUP
  2.  * Licensed to CS GROUP (CS) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * CS licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *   http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.orekit.files.ccsds.ndm.tdm;

  18. import java.util.ArrayList;
  19. import java.util.List;

  20. import org.orekit.data.DataContext;
  21. import org.orekit.files.ccsds.ndm.ParsedUnitsBehavior;
  22. import org.orekit.files.ccsds.section.Header;
  23. import org.orekit.files.ccsds.section.HeaderProcessingState;
  24. import org.orekit.files.ccsds.section.KvnStructureProcessingState;
  25. import org.orekit.files.ccsds.section.MetadataKey;
  26. import org.orekit.files.ccsds.section.Segment;
  27. import org.orekit.files.ccsds.section.XmlStructureProcessingState;
  28. import org.orekit.files.ccsds.utils.ContextBinding;
  29. import org.orekit.files.ccsds.utils.FileFormat;
  30. import org.orekit.files.ccsds.utils.lexical.ParseToken;
  31. import org.orekit.files.ccsds.utils.parsing.AbstractConstituentParser;
  32. import org.orekit.files.ccsds.utils.parsing.ProcessingState;
  33. import org.orekit.utils.IERSConventions;


  34. /**
  35.  * Class for CCSDS Tracking Data Message parsers.
  36.  * <p>
  37.  * Note than starting with Orekit 11.0, CCSDS message parsers are
  38.  * mutable objects that gather the data being parsed, until the
  39.  * message is complete and the {@link #parseMessage(org.orekit.data.DataSource)
  40.  * parseMessage} method has returned. This implies that parsers
  41.  * should <em>not</em> be used in a multi-thread context. The recommended
  42.  * way to use parsers is to either dedicate one parser for each message
  43.  * and drop it afterwards, or to use a single-thread loop.
  44.  * </p>
  45.  *
  46.  * <p>References:<p>
  47.  *  - <a href="https://public.ccsds.org/Pubs/503x0b1c1.pdf">CCSDS 503.0-B-1 recommended standard</a> ("Tracking Data Message", Blue Book, Issue 1, November 2007).<p>
  48.  *  - <a href="https://public.ccsds.org/Pubs/505x0b1.pdf">CCSDS 505.0-B-1 recommended standard</a> ("XML Specification for Navigation Data Message", Blue Book, Issue 1, December 2010).<p>
  49.  *
  50.  * @author Maxime Journot
  51.  * @since 9.0
  52.  */
  53. public class TdmParser extends AbstractConstituentParser<Tdm, TdmParser> {

  54.     /** Converter for {@link RangeUnits#RU Range Units} (may be null). */
  55.     private final RangeUnitsConverter converter;

  56.     /** Metadata for current observation block. */
  57.     private TdmMetadata metadata;

  58.     /** Context binding valid for current metadata. */
  59.     private ContextBinding context;

  60.     /** Current Observation Block being parsed. */
  61.     private ObservationsBlock observationsBlock;

  62.     /** File header. */
  63.     private Header header;

  64.     /** File segments. */
  65.     private List<Segment<TdmMetadata, ObservationsBlock>> segments;

  66.     /** Processor for global message structure. */
  67.     private ProcessingState structureProcessor;

  68.     /** Complete constructor.
  69.      * <p>
  70.      * Calling this constructor directly is not recommended. Users should rather use
  71.      * {@link org.orekit.files.ccsds.ndm.ParserBuilder#buildTdmParser()
  72.      * parserBuilder.buildTdmParser()}.
  73.      * </p>
  74.      * @param conventions IERS Conventions
  75.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  76.      * @param dataContext used to retrieve frames, time scales, etc.
  77.      * @param parsedUnitsBehavior behavior to adopt for handling parsed units
  78.      * @param converter converter for {@link RangeUnits#RU Range Units} (may be null if there
  79.      * are no range observations in {@link RangeUnits#RU Range Units})
  80.      */
  81.     public TdmParser(final IERSConventions conventions, final boolean simpleEOP, final DataContext dataContext,
  82.                      final ParsedUnitsBehavior parsedUnitsBehavior, final RangeUnitsConverter converter) {
  83.         super(Tdm.ROOT, Tdm.FORMAT_VERSION_KEY, conventions, simpleEOP, dataContext, parsedUnitsBehavior);
  84.         this.converter = converter;
  85.     }

  86.     /** {@inheritDoc} */
  87.     @Override
  88.     public Header getHeader() {
  89.         return header;
  90.     }

  91.     /** {@inheritDoc} */
  92.     @Override
  93.     public void reset(final FileFormat fileFormat) {
  94.         header             = new Header(2.0);
  95.         segments           = new ArrayList<>();
  96.         metadata           = null;
  97.         context            = null;
  98.         observationsBlock  = null;
  99.         if (fileFormat == FileFormat.XML) {
  100.             structureProcessor = new XmlStructureProcessingState(Tdm.ROOT, this);
  101.             reset(fileFormat, structureProcessor);
  102.         } else {
  103.             structureProcessor = new KvnStructureProcessingState(this);
  104.             reset(fileFormat, new HeaderProcessingState(this));
  105.         }
  106.     }

  107.     /** {@inheritDoc} */
  108.     @Override
  109.     public Tdm build() {
  110.         return new Tdm(header, segments, getConventions(), getDataContext());
  111.     }

  112.     /** {@inheritDoc} */
  113.     @Override
  114.     public boolean prepareHeader() {
  115.         anticipateNext(new HeaderProcessingState(this));
  116.         return true;
  117.     }

  118.     /** {@inheritDoc} */
  119.     @Override
  120.     public boolean inHeader() {
  121.         anticipateNext(structureProcessor);
  122.         return true;
  123.     }

  124.     /** {@inheritDoc} */
  125.     @Override
  126.     public boolean finalizeHeader() {
  127.         header.validate(header.getFormatVersion());
  128.         return true;
  129.     }

  130.     /** {@inheritDoc} */
  131.     @Override
  132.     public boolean prepareMetadata() {
  133.         if (metadata != null) {
  134.             return false;
  135.         }
  136.         metadata  = new TdmMetadata();
  137.         context   = new ContextBinding(
  138.             this::getConventions, this::isSimpleEOP,
  139.             this::getDataContext, this::getParsedUnitsBehavior,
  140.             () -> null, metadata::getTimeSystem, () -> 0.0, () -> 1.0);
  141.         anticipateNext(this::processMetadataToken);
  142.         return true;
  143.     }

  144.     /** {@inheritDoc} */
  145.     @Override
  146.     public boolean inMetadata() {
  147.         anticipateNext(structureProcessor);
  148.         return true;
  149.     }

  150.     /** {@inheritDoc} */
  151.     @Override
  152.     public boolean finalizeMetadata() {
  153.         metadata.validate(header.getFormatVersion());
  154.         return true;
  155.     }

  156.     /** {@inheritDoc} */
  157.     @Override
  158.     public boolean prepareData() {
  159.         observationsBlock = new ObservationsBlock();
  160.         anticipateNext(this::processDataToken);
  161.         return true;
  162.     }

  163.     /** {@inheritDoc} */
  164.     @Override
  165.     public boolean inData() {
  166.         anticipateNext(structureProcessor);
  167.         return true;
  168.     }

  169.     /** {@inheritDoc} */
  170.     @Override
  171.     public boolean finalizeData() {
  172.         segments.add(new Segment<>(metadata, observationsBlock));
  173.         metadata          = null;
  174.         context           = null;
  175.         observationsBlock = null;
  176.         return true;
  177.     }

  178.     /** Process one metadata token.
  179.      * @param token token to process
  180.      * @return true if token was processed, false otherwise
  181.      */
  182.     private boolean processMetadataToken(final ParseToken token) {
  183.         inMetadata();
  184.         try {
  185.             return token.getName() != null &&
  186.                    MetadataKey.valueOf(token.getName()).process(token, context, metadata);
  187.         } catch (IllegalArgumentException iaeM) {
  188.             try {
  189.                 return TdmMetadataKey.valueOf(token.getName()).process(token, context, metadata);
  190.             } catch (IllegalArgumentException iaeT) {
  191.                 // token has not been recognized
  192.                 return false;
  193.             }
  194.         }
  195.     }

  196.     /** Process one data token.
  197.      * @param token token to process
  198.      * @return true if token was processed, false otherwise
  199.      */
  200.     private boolean processDataToken(final ParseToken token) {
  201.         try {
  202.             inData();
  203.             try {
  204.                 // global tokens (observation wrapper, comments, epoch in XML)
  205.                 return token.getName() != null &&
  206.                        TdmDataKey.valueOf(token.getName()).process(token, context, observationsBlock);
  207.             } catch (IllegalArgumentException iae) {
  208.                 // observation
  209.                 return ObservationType.valueOf(token.getName()).process(token, context, converter, metadata, observationsBlock);
  210.             }
  211.         } catch (IllegalArgumentException iae) {
  212.             // token has not been recognized
  213.             return false;
  214.         }
  215.     }

  216. }