1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.files.ccsds.ndm.adm.apm;
18
19 import java.util.ArrayList;
20 import java.util.List;
21 import java.util.function.Function;
22
23 import org.orekit.data.DataContext;
24 import org.orekit.files.ccsds.ndm.ParsedUnitsBehavior;
25 import org.orekit.files.ccsds.ndm.adm.AdmCommonMetadataKey;
26 import org.orekit.files.ccsds.ndm.adm.AdmHeader;
27 import org.orekit.files.ccsds.ndm.adm.AdmMetadata;
28 import org.orekit.files.ccsds.ndm.adm.AdmMetadataKey;
29 import org.orekit.files.ccsds.ndm.adm.AdmParser;
30 import org.orekit.files.ccsds.section.CommentsContainer;
31 import org.orekit.files.ccsds.section.HeaderProcessingState;
32 import org.orekit.files.ccsds.section.MetadataKey;
33 import org.orekit.files.ccsds.section.Segment;
34 import org.orekit.files.ccsds.section.XmlStructureProcessingState;
35 import org.orekit.files.ccsds.utils.ContextBinding;
36 import org.orekit.files.ccsds.utils.FileFormat;
37 import org.orekit.files.ccsds.utils.lexical.ParseToken;
38 import org.orekit.files.ccsds.utils.lexical.TokenType;
39 import org.orekit.files.ccsds.utils.parsing.ErrorState;
40 import org.orekit.files.ccsds.utils.parsing.ProcessingState;
41 import org.orekit.time.AbsoluteDate;
42 import org.orekit.utils.IERSConventions;
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58 public class ApmParser extends AdmParser<Apm, ApmParser> {
59
60
61 private AdmHeader header;
62
63
64 private List<Segment<AdmMetadata, ApmData>> segments;
65
66
67 private AdmMetadata metadata;
68
69
70 private ContextBinding context;
71
72
73
74
75 private AbsoluteDate epoch;
76
77
78 private CommentsContainer commentsBlock;
79
80
81 private ApmQuaternion quaternionBlock;
82
83
84 private Euler eulerBlock;
85
86
87
88
89 private AngularVelocity angularVelocityBlock;
90
91
92 private SpinStabilized spinStabilizedBlock;
93
94
95
96
97 private Inertia inertiaBlock;
98
99
100 private Maneuver currentManeuver;
101
102
103 private List<Maneuver> maneuvers;
104
105
106 private ProcessingState structureProcessor;
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123 public ApmParser(final IERSConventions conventions, final boolean simpleEOP, final DataContext dataContext,
124 final AbsoluteDate missionReferenceDate, final ParsedUnitsBehavior parsedUnitsBehavior,
125 final Function<ParseToken, List<ParseToken>>[] filters) {
126 super(Apm.ROOT, Apm.FORMAT_VERSION_KEY, conventions, simpleEOP, dataContext,
127 missionReferenceDate, parsedUnitsBehavior, filters);
128 }
129
130
131 @Override
132 public AdmHeader getHeader() {
133 return header;
134 }
135
136
137 @Override
138 public void reset(final FileFormat fileFormat) {
139 header = new AdmHeader();
140 segments = new ArrayList<>();
141 metadata = null;
142 context = null;
143 quaternionBlock = null;
144 eulerBlock = null;
145 spinStabilizedBlock = null;
146 inertiaBlock = null;
147 currentManeuver = null;
148 maneuvers = new ArrayList<>();
149 if (fileFormat == FileFormat.XML) {
150 structureProcessor = new XmlStructureProcessingState(Apm.ROOT, this);
151 reset(fileFormat, structureProcessor);
152 } else {
153 structureProcessor = new ErrorState();
154 reset(fileFormat, new HeaderProcessingState(this));
155 }
156 }
157
158
159 @Override
160 public boolean prepareHeader() {
161 anticipateNext(new HeaderProcessingState(this));
162 return true;
163 }
164
165
166 @Override
167 public boolean inHeader() {
168 anticipateNext(getFileFormat() == FileFormat.XML ? structureProcessor : this::processMetadataToken);
169 return true;
170 }
171
172
173 @Override
174 public boolean finalizeHeader() {
175 header.validate(header.getFormatVersion());
176 return true;
177 }
178
179
180 @Override
181 public boolean prepareMetadata() {
182 if (metadata != null) {
183 return false;
184 }
185 metadata = new AdmMetadata();
186 context = new ContextBinding(this::getConventions, this::isSimpleEOP,
187 this::getDataContext, this::getParsedUnitsBehavior,
188 this::getMissionReferenceDate,
189 metadata::getTimeSystem, () -> 0.0, () -> 1.0);
190 anticipateNext(this::processMetadataToken);
191 return true;
192 }
193
194
195 @Override
196 public boolean inMetadata() {
197 anticipateNext(getFileFormat() == FileFormat.XML ? structureProcessor : this::processDataToken);
198 return true;
199 }
200
201
202 @Override
203 public boolean finalizeMetadata() {
204 metadata.validate(header.getFormatVersion());
205 return true;
206 }
207
208
209 @Override
210 public boolean prepareData() {
211 commentsBlock = new CommentsContainer();
212 anticipateNext(getFileFormat() == FileFormat.KVN && header.getFormatVersion() < 2.0 ?
213 this::processDataToken : this::processDataSubStructureToken);
214 return true;
215 }
216
217
218 @Override
219 public boolean inData() {
220 return true;
221 }
222
223
224 @Override
225 public boolean finalizeData() {
226 if (metadata != null) {
227 final ApmData data = new ApmData(commentsBlock, epoch, quaternionBlock, eulerBlock,
228 angularVelocityBlock, spinStabilizedBlock, inertiaBlock);
229 if (currentManeuver != null) {
230
231 maneuvers.add(currentManeuver);
232 currentManeuver = null;
233 }
234 for (final Maneuver maneuver : maneuvers) {
235 data.addManeuver(maneuver);
236 }
237 data.validate(header.getFormatVersion());
238 segments.add(new Segment<>(metadata, data));
239 }
240 metadata = null;
241 context = null;
242 quaternionBlock = null;
243 eulerBlock = null;
244 angularVelocityBlock = null;
245 spinStabilizedBlock = null;
246 inertiaBlock = null;
247 currentManeuver = null;
248 return true;
249 }
250
251
252 @Override
253 public Apm build() {
254
255
256 finalizeData();
257 final Apm file = new Apm(header, segments, getConventions(), getDataContext());
258 return file;
259 }
260
261
262
263
264
265 boolean addGeneralComment(final String comment) {
266 return commentsBlock.addComment(comment);
267 }
268
269
270
271
272
273 void setEpoch(final AbsoluteDate epoch) {
274 this.epoch = epoch;
275 }
276
277
278
279
280
281
282 boolean manageQuaternionSection(final boolean starting) {
283 anticipateNext(starting ? this::processQuaternionToken : structureProcessor);
284 return true;
285 }
286
287
288
289
290
291
292 boolean manageEulerElementsSection(final boolean starting) {
293 anticipateNext(starting ? this::processEulerToken : structureProcessor);
294 return true;
295 }
296
297
298
299
300
301
302
303 boolean manageAngularVelocitylementsSection(final boolean starting) {
304 anticipateNext(starting ? this::processAngularVelocityToken : structureProcessor);
305 return true;
306 }
307
308
309
310
311
312
313 boolean manageSpinElementsSection(final boolean starting) {
314 anticipateNext(starting ? this::processSpinStabilizedToken : structureProcessor);
315 return true;
316 }
317
318
319
320
321
322
323
324 boolean manageInertiaSection(final boolean starting) {
325 anticipateNext(starting ? this::processInertiaToken : structureProcessor);
326 return true;
327 }
328
329
330
331
332
333
334 boolean manageManeuverParametersSection(final boolean starting) {
335 anticipateNext(starting ? this::processManeuverToken : structureProcessor);
336 return true;
337 }
338
339
340
341
342
343 private boolean processMetadataToken(final ParseToken token) {
344 if (metadata == null) {
345
346
347 prepareMetadata();
348 }
349 inMetadata();
350 try {
351 return token.getName() != null &&
352 MetadataKey.valueOf(token.getName()).process(token, context, metadata);
353 } catch (IllegalArgumentException iaeM) {
354 try {
355 return AdmMetadataKey.valueOf(token.getName()).process(token, context, metadata);
356 } catch (IllegalArgumentException iaeD) {
357 try {
358 return AdmCommonMetadataKey.valueOf(token.getName()).process(token, context, metadata);
359 } catch (IllegalArgumentException iaeC) {
360
361 return false;
362 }
363 }
364 }
365 }
366
367
368
369
370
371 private boolean processDataSubStructureToken(final ParseToken token) {
372 try {
373 return token.getName() != null &&
374 ApmDataSubStructureKey.valueOf(token.getName()).process(token, context, this);
375 } catch (IllegalArgumentException iae) {
376
377 return false;
378 }
379 }
380
381
382
383
384
385 private boolean processDataToken(final ParseToken token) {
386 if (commentsBlock == null) {
387
388
389 finalizeMetadata();
390
391
392 prepareData();
393 }
394 anticipateNext(getFileFormat() == FileFormat.KVN && header.getFormatVersion() < 2.0 ?
395 this::processQuaternionToken : this::processDataSubStructureToken);
396 if ("COMMENT".equals(token.getName())) {
397 if (token.getType() == TokenType.ENTRY) {
398 commentsBlock.addComment(token.getContentAsNormalizedString());
399 }
400 return true;
401 } else if ("EPOCH".equals(token.getName())) {
402 if (token.getType() == TokenType.ENTRY) {
403 token.processAsDate(date -> epoch = date, context);
404 }
405 return true;
406 } else {
407 return false;
408 }
409 }
410
411
412
413
414
415 private boolean processQuaternionToken(final ParseToken token) {
416 commentsBlock.refuseFurtherComments();
417 if (quaternionBlock == null) {
418 quaternionBlock = new ApmQuaternion();
419 }
420 anticipateNext(getFileFormat() == FileFormat.KVN && header.getFormatVersion() < 2.0 ?
421 this::processEulerToken : this::processDataSubStructureToken);
422 try {
423 return token.getName() != null &&
424 ApmQuaternionKey.valueOf(token.getName()).process(token, context, quaternionBlock, this::setEpoch);
425 } catch (IllegalArgumentException iae) {
426
427 return false;
428 }
429 }
430
431
432
433
434
435 private boolean processEulerToken(final ParseToken token) {
436 commentsBlock.refuseFurtherComments();
437 if (eulerBlock == null) {
438 eulerBlock = new Euler();
439 if (moveCommentsIfEmpty(quaternionBlock, eulerBlock)) {
440
441 quaternionBlock = null;
442 }
443 }
444 anticipateNext(getFileFormat() == FileFormat.KVN && header.getFormatVersion() < 2.0 ?
445 this::processAngularVelocityToken : this::processDataSubStructureToken);
446 try {
447 return token.getName() != null &&
448 EulerKey.valueOf(token.getName()).process(token, context, eulerBlock);
449 } catch (IllegalArgumentException iae) {
450
451 return false;
452 }
453 }
454
455
456
457
458
459
460 private boolean processAngularVelocityToken(final ParseToken token) {
461 commentsBlock.refuseFurtherComments();
462 if (angularVelocityBlock == null) {
463 angularVelocityBlock = new AngularVelocity();
464 if (moveCommentsIfEmpty(eulerBlock, angularVelocityBlock)) {
465
466 eulerBlock = null;
467 }
468 }
469 anticipateNext(getFileFormat() == FileFormat.KVN && header.getFormatVersion() < 2.0 ?
470 this::processSpinStabilizedToken : this::processDataSubStructureToken);
471 try {
472 return token.getName() != null &&
473 AngularVelocityKey.valueOf(token.getName()).process(token, context, angularVelocityBlock);
474 } catch (IllegalArgumentException iae) {
475
476 return false;
477 }
478 }
479
480
481
482
483
484 private boolean processSpinStabilizedToken(final ParseToken token) {
485 commentsBlock.refuseFurtherComments();
486 if (spinStabilizedBlock == null) {
487 spinStabilizedBlock = new SpinStabilized();
488 if (moveCommentsIfEmpty(angularVelocityBlock, spinStabilizedBlock)) {
489
490 angularVelocityBlock = null;
491 }
492 }
493 anticipateNext(getFileFormat() == FileFormat.KVN && header.getFormatVersion() < 2.0 ?
494 this::processInertiaToken : this::processDataSubStructureToken);
495 try {
496 return token.getName() != null &&
497 SpinStabilizedKey.valueOf(token.getName()).process(token, context, spinStabilizedBlock);
498 } catch (IllegalArgumentException iae) {
499
500 return false;
501 }
502 }
503
504
505
506
507
508 private boolean processInertiaToken(final ParseToken token) {
509 commentsBlock.refuseFurtherComments();
510 if (inertiaBlock == null) {
511 inertiaBlock = new Inertia();
512 if (moveCommentsIfEmpty(spinStabilizedBlock, inertiaBlock)) {
513
514 spinStabilizedBlock = null;
515 }
516 }
517 anticipateNext(getFileFormat() == FileFormat.KVN && header.getFormatVersion() < 2.0 ?
518 this::processManeuverToken : this::processDataSubStructureToken);
519 try {
520 return token.getName() != null &&
521 InertiaKey.valueOf(token.getName()).process(token, context, inertiaBlock);
522 } catch (IllegalArgumentException iae) {
523
524 return false;
525 }
526 }
527
528
529
530
531
532 private boolean processManeuverToken(final ParseToken token) {
533 commentsBlock.refuseFurtherComments();
534 if (currentManeuver == null) {
535 currentManeuver = new Maneuver();
536 if (moveCommentsIfEmpty(inertiaBlock, currentManeuver)) {
537
538 inertiaBlock = null;
539 }
540 }
541 anticipateNext(getFileFormat() == FileFormat.KVN && header.getFormatVersion() < 2.0 ?
542 new ErrorState() : this::processDataSubStructureToken);
543 try {
544 return token.getName() != null &&
545 ManeuverKey.valueOf(token.getName()).process(token, context, currentManeuver);
546 } catch (IllegalArgumentException iae) {
547
548 maneuvers.add(currentManeuver);
549 currentManeuver = null;
550 return false;
551 }
552 }
553
554
555
556
557
558
559 private boolean moveCommentsIfEmpty(final CommentsContainer origin, final CommentsContainer destination) {
560 if (origin != null && origin.acceptComments()) {
561
562 for (final String comment : origin.getComments()) {
563 destination.addComment(comment);
564 }
565 return true;
566 } else {
567 return false;
568 }
569 }
570
571 }