1   /* Copyright 2002-2021 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;
18  
19  import java.util.ArrayList;
20  import java.util.List;
21  import java.util.Map;
22  import java.util.function.Supplier;
23  
24  import org.orekit.errors.OrekitException;
25  import org.orekit.errors.OrekitMessages;
26  import org.orekit.files.ccsds.section.CommentsContainer;
27  import org.orekit.files.ccsds.utils.FileFormat;
28  import org.orekit.files.ccsds.utils.lexical.ParseToken;
29  import org.orekit.files.ccsds.utils.lexical.XmlTokenBuilder;
30  import org.orekit.files.ccsds.utils.parsing.AbstractMessageParser;
31  
32  /** A parser for the CCSDS NDM (Navigation Data Message).
33   * @author Luc Maisonobe
34   * @since 11.0
35   */
36  public class NdmParser extends AbstractMessageParser<Ndm> {
37  
38      /** Builder for the constituents parsers. */
39      private final ParserBuilder builder;
40  
41      /** Current constituent parser. */
42      private AbstractMessageParser<? extends NdmConstituent<?, ?>> constituentParser;
43  
44      /** Container for comments. */
45      private CommentsContainer comments;
46  
47      /** Container for constituents. */
48      private List<NdmConstituent<?, ?>> constituents;
49  
50      /** Simple constructor.
51       * <p>
52       * Calling this constructor directly is not recommended. Users should rather use
53       * {@link org.orekit.files.ccsds.ndm.ParserBuilder#buildNdmParser()
54       * parserBuilder.buildNdmParser()}.
55       * </p>
56       * @param builder builder for the constituents parsers
57       */
58      public NdmParser(final ParserBuilder builder) {
59          super(NdmStructureKey.ndm.name(), null);
60          this.builder = builder;
61      }
62  
63      /** {@inheritDoc} */
64      @Override
65      public Map<String, XmlTokenBuilder> getSpecialXmlElementsBuilders() {
66          final Map<String, XmlTokenBuilder> builders = super.getSpecialXmlElementsBuilders();
67  
68          // special handling of root elements for all constituents
69          builders.putAll(builder.buildTdmParser().getSpecialXmlElementsBuilders());
70          builders.putAll(builder.buildOpmParser().getSpecialXmlElementsBuilders());
71          builders.putAll(builder.buildOmmParser().getSpecialXmlElementsBuilders());
72          builders.putAll(builder.buildOemParser().getSpecialXmlElementsBuilders());
73          builders.putAll(builder.buildOcmParser().getSpecialXmlElementsBuilders());
74          builders.putAll(builder.buildApmParser().getSpecialXmlElementsBuilders());
75          builders.putAll(builder.buildAemParser().getSpecialXmlElementsBuilders());
76  
77          return builders;
78  
79      }
80  
81      /** {@inheritDoc} */
82      @Override
83      public void reset(final FileFormat fileFormat) {
84          reset(fileFormat, this::processToken);
85          constituentParser = null;
86          comments          = new CommentsContainer();
87          constituents      = new ArrayList<>();
88      }
89  
90      /** {@inheritDoc} */
91      @Override
92      public Ndm build() {
93          // build the file from parsed comments and constituents
94          return new Ndm(comments.getComments(), constituents);
95      }
96  
97      /**
98       * Add comment.
99       * <p>
100      * Comments are accepted only at start. Once
101      * other content is stored in the same section, comments are refused.
102      * </p>
103      * @param comment comment line
104      * @return true if comment was accepted
105      */
106     public boolean addComment(final String comment) {
107         return comments.addComment(comment);
108     }
109 
110     /** Prepare parsing of a TDM constituent.
111      * @return always return true
112      */
113     boolean manageTdmConstituent() {
114         return manageConstituent(builder::buildTdmParser);
115     }
116 
117     /** Prepare parsing of an OPM constituent.
118      * @return always return true
119      */
120     boolean manageOpmConstituent() {
121         return manageConstituent(builder::buildOpmParser);
122     }
123 
124     /** Prepare parsing of an OMM constituent.
125      * @return always return true
126      */
127     boolean manageOmmConstituent() {
128         return manageConstituent(builder::buildOmmParser);
129     }
130 
131     /** Prepare parsing of an OEM constituent.
132      * @return always return true
133      */
134     boolean manageOemConstituent() {
135         return manageConstituent(builder::buildOemParser);
136     }
137 
138     /** Prepare parsing of an OCM constituent.
139      * @return always return true
140      */
141     boolean manageOcmConstituent() {
142         return manageConstituent(builder::buildOcmParser);
143     }
144 
145     /** Prepare parsing of an APM constituent.
146      * @return always return true
147      */
148     boolean manageApmConstituent() {
149         return manageConstituent(builder::buildApmParser);
150     }
151 
152     /** Prepare parsing of a AEM constituent.
153      * @return always return true
154      */
155     boolean manageAemConstituent() {
156         return manageConstituent(builder::buildAemParser);
157     }
158 
159     /** Prepare parsing of a constituent.
160      * @param parserSupplier supplier for constituent parser
161      * @return always return true
162      */
163     boolean manageConstituent(final Supplier<AbstractMessageParser<? extends NdmConstituent<?, ?>>> parserSupplier) {
164 
165         // as we have started parsing constituents, we cannot accept any further comments
166         comments.refuseFurtherComments();
167 
168         // create a parser for the constituent
169         constituentParser = parserSupplier.get();
170         constituentParser.reset(getFileFormat());
171 
172         return true;
173 
174     }
175 
176     /** Process one token.
177      * @param token token to process
178      * @return true if token was processed, false otherwise
179      */
180     private boolean processToken(final ParseToken token) {
181 
182         if (getFileFormat() == FileFormat.KVN) {
183             // NDM combined instantiation can only be formatted as XML messages
184             throw new OrekitException(OrekitMessages.UNSUPPORTED_FILE_FORMAT, token.getFileName());
185         }
186 
187         if (constituentParser == null) {
188             // we are in the global NDM structure
189             try {
190                 return NdmStructureKey.valueOf(token.getName()).process(token, this);
191             } catch (IllegalArgumentException iae) {
192                 // token has not been recognized
193                 return false;
194             }
195         } else {
196             // we are inside one constituent
197             constituentParser.process(token);
198             if (constituentParser.wasEndTagSeen()) {
199                 // we have seen the end tag, we must go back global structure parsing
200                 constituents.add(constituentParser.build());
201                 constituentParser = null;
202             }
203             return true;
204         }
205 
206     }
207 
208 }