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