1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.files.ccsds.ndm.adm.aem;
18
19 import java.util.ArrayList;
20 import java.util.List;
21 import java.util.function.Function;
22 import java.util.regex.Pattern;
23
24 import org.orekit.data.DataContext;
25 import org.orekit.data.DataSource;
26 import org.orekit.errors.OrekitException;
27 import org.orekit.errors.OrekitMessages;
28 import org.orekit.files.ccsds.ndm.ParsedUnitsBehavior;
29 import org.orekit.files.ccsds.ndm.adm.AdmCommonMetadataKey;
30 import org.orekit.files.ccsds.ndm.adm.AdmHeader;
31 import org.orekit.files.ccsds.ndm.adm.AdmMetadataKey;
32 import org.orekit.files.ccsds.ndm.adm.AdmParser;
33 import org.orekit.files.ccsds.section.HeaderProcessingState;
34 import org.orekit.files.ccsds.section.KvnStructureProcessingState;
35 import org.orekit.files.ccsds.section.MetadataKey;
36 import org.orekit.files.ccsds.section.XmlStructureProcessingState;
37 import org.orekit.files.ccsds.utils.ContextBinding;
38 import org.orekit.files.ccsds.utils.FileFormat;
39 import org.orekit.files.ccsds.utils.lexical.ParseToken;
40 import org.orekit.files.ccsds.utils.lexical.TokenType;
41 import org.orekit.files.ccsds.utils.parsing.ProcessingState;
42 import org.orekit.files.general.AttitudeEphemerisFileParser;
43 import org.orekit.time.AbsoluteDate;
44 import org.orekit.utils.IERSConventions;
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 public class AemParser extends AdmParser<Aem, AemParser> implements AttitudeEphemerisFileParser<Aem> {
61
62
63 private static final Pattern SPLIT_AT_BLANKS = Pattern.compile("\\s+");
64
65
66 private AdmHeader header;
67
68
69 private List<AemSegment> segments;
70
71
72 private AemMetadata metadata;
73
74
75 private ContextBinding context;
76
77
78 private AemData currentBlock;
79
80
81 private int defaultInterpolationDegree;
82
83
84 private ProcessingState structureProcessor;
85
86
87 private AttitudeEntry currentEntry;
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105 public AemParser(final IERSConventions conventions, final boolean simpleEOP,
106 final DataContext dataContext, final AbsoluteDate missionReferenceDate,
107 final int defaultInterpolationDegree, final ParsedUnitsBehavior parsedUnitsBehavior,
108 final Function<ParseToken, List<ParseToken>>[] filters) {
109 super(Aem.ROOT, Aem.FORMAT_VERSION_KEY, conventions, simpleEOP, dataContext,
110 missionReferenceDate, parsedUnitsBehavior, filters);
111 this.defaultInterpolationDegree = defaultInterpolationDegree;
112 }
113
114
115 @Override
116 public Aem parse(final DataSource source) {
117 return parseMessage(source);
118 }
119
120
121 @Override
122 public AdmHeader getHeader() {
123 return header;
124 }
125
126
127 @Override
128 public void reset(final FileFormat fileFormat) {
129 header = new AdmHeader();
130 segments = new ArrayList<>();
131 metadata = null;
132 context = null;
133 if (fileFormat == FileFormat.XML) {
134 structureProcessor = new XmlStructureProcessingState(Aem.ROOT, this);
135 reset(fileFormat, structureProcessor);
136 } else {
137 structureProcessor = new KvnStructureProcessingState(this);
138 reset(fileFormat, new HeaderProcessingState(this));
139 }
140 }
141
142
143 @Override
144 public boolean prepareHeader() {
145 anticipateNext(new HeaderProcessingState(this));
146 return true;
147 }
148
149
150 @Override
151 public boolean inHeader() {
152 anticipateNext(structureProcessor);
153 return true;
154 }
155
156
157 @Override
158 public boolean finalizeHeader() {
159 header.validate(header.getFormatVersion());
160 return true;
161 }
162
163
164 @Override
165 public boolean prepareMetadata() {
166 if (metadata != null) {
167 return false;
168 }
169 metadata = new AemMetadata(defaultInterpolationDegree);
170 context = new ContextBinding(this::getConventions, this::isSimpleEOP,
171 this::getDataContext, this::getParsedUnitsBehavior,
172 this::getMissionReferenceDate,
173 metadata::getTimeSystem, () -> 0.0, () -> 1.0);
174 anticipateNext(this::processMetadataToken);
175 return true;
176 }
177
178
179 @Override
180 public boolean inMetadata() {
181 anticipateNext(getFileFormat() == FileFormat.XML ? structureProcessor : this::processKvnDataToken);
182 return true;
183 }
184
185
186 @Override
187 public boolean finalizeMetadata() {
188 metadata.validate(header.getFormatVersion());
189 return true;
190 }
191
192
193 @Override
194 public boolean prepareData() {
195 currentBlock = new AemData();
196 anticipateNext(getFileFormat() == FileFormat.XML ? this::processXmlSubStructureToken : this::processMetadataToken);
197 return true;
198 }
199
200
201 @Override
202 public boolean inData() {
203 anticipateNext(structureProcessor);
204 return true;
205 }
206
207
208 @Override
209 public boolean finalizeData() {
210 if (metadata != null) {
211 currentBlock.validate(header.getFormatVersion());
212 segments.add(new AemSegment(metadata, currentBlock));
213 }
214 metadata = null;
215 context = null;
216 return true;
217 }
218
219
220 @Override
221 public Aem build() {
222 return new Aem(header, segments, getConventions(), getDataContext());
223 }
224
225
226
227
228
229
230 boolean manageXmlAttitudeStateSection(final boolean starting) {
231 if (starting) {
232 currentEntry = new AttitudeEntry(metadata);
233 anticipateNext(this::processXmlDataToken);
234 } else {
235 currentBlock.addData(currentEntry.getCoordinates());
236 currentEntry = null;
237 anticipateNext(structureProcessor);
238 }
239 return true;
240 }
241
242
243
244
245
246 boolean addDataComment(final String comment) {
247 currentBlock.addComment(comment);
248 return true;
249 }
250
251
252
253
254
255 private boolean processMetadataToken(final ParseToken token) {
256 inMetadata();
257 try {
258 return token.getName() != null &&
259 MetadataKey.valueOf(token.getName()).process(token, context, metadata);
260 } catch (IllegalArgumentException iaeM) {
261 try {
262 return AdmMetadataKey.valueOf(token.getName()).process(token, context, metadata);
263 } catch (IllegalArgumentException iaeD) {
264 try {
265 return AdmCommonMetadataKey.valueOf(token.getName()).process(token, context, metadata);
266 } catch (IllegalArgumentException iaeC) {
267 try {
268 return AemMetadataKey.valueOf(token.getName()).process(token, context, metadata);
269 } catch (IllegalArgumentException iaeE) {
270
271 return false;
272 }
273 }
274 }
275 }
276 }
277
278
279
280
281
282 private boolean processXmlSubStructureToken(final ParseToken token) {
283 try {
284 return token.getName() != null &&
285 XmlSubStructureKey.valueOf(token.getName()).process(token, this);
286 } catch (IllegalArgumentException iae) {
287
288 return false;
289 }
290 }
291
292
293
294
295
296 private boolean processKvnDataToken(final ParseToken token) {
297 inData();
298 if ("COMMENT".equals(token.getName())) {
299 return token.getType() == TokenType.ENTRY ? currentBlock.addComment(token.getContentAsNormalizedString()) : true;
300 } else if (token.getType() == TokenType.RAW_LINE) {
301 try {
302 if (metadata.getAttitudeType() == null) {
303 throw new OrekitException(OrekitMessages.CCSDS_MISSING_KEYWORD,
304 AemMetadataKey.ATTITUDE_TYPE.name(), token.getFileName());
305 }
306 return currentBlock.addData(metadata.getAttitudeType().parse(metadata.isFirst(),
307 metadata.getEndpoints().isExternal2SpacecraftBody(),
308 metadata.getEulerRotSeq(),
309 metadata.isSpacecraftBodyRate(),
310 context, SPLIT_AT_BLANKS.split(token.getRawContent().trim())));
311 } catch (NumberFormatException nfe) {
312 throw new OrekitException(nfe, OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
313 token.getLineNumber(), token.getFileName(), token.getRawContent());
314 }
315 } else {
316
317 return false;
318 }
319 }
320
321
322
323
324
325 private boolean processXmlDataToken(final ParseToken token) {
326 anticipateNext(this::processXmlSubStructureToken);
327 try {
328 return token.getName() != null &&
329 AttitudeEntryKey.valueOf(token.getName()).process(token, context, currentEntry);
330 } catch (IllegalArgumentException iae) {
331
332 return false;
333 }
334 }
335
336 }