1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.files.ccsds.utils.lexical;
18
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.List;
22 import java.util.Locale;
23 import java.util.regex.Pattern;
24 import java.util.stream.Collectors;
25 import java.util.stream.Stream;
26
27 import org.hipparchus.geometry.euclidean.threed.RotationOrder;
28 import org.hipparchus.geometry.euclidean.threed.Vector3D;
29 import org.orekit.bodies.CelestialBodies;
30 import org.orekit.bodies.CelestialBody;
31 import org.orekit.errors.OrekitException;
32 import org.orekit.errors.OrekitMessages;
33 import org.orekit.files.ccsds.definitions.BodyFacade;
34 import org.orekit.files.ccsds.definitions.CelestialBodyFrame;
35 import org.orekit.files.ccsds.definitions.CenterName;
36 import org.orekit.files.ccsds.definitions.FrameFacade;
37 import org.orekit.files.ccsds.definitions.OrbitRelativeFrame;
38 import org.orekit.files.ccsds.definitions.SpacecraftBodyFrame;
39 import org.orekit.files.ccsds.definitions.TimeSystem;
40 import org.orekit.files.ccsds.ndm.ParsedUnitsBehavior;
41 import org.orekit.files.ccsds.ndm.cdm.Maneuvrable;
42 import org.orekit.files.ccsds.utils.ContextBinding;
43 import org.orekit.time.AbsoluteDate;
44 import org.orekit.utils.units.Unit;
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 public class ParseToken {
60
61
62 private static final Pattern DASH = Pattern.compile("-");
63
64
65 private static final Pattern SPACE = Pattern.compile("\\p{Space}+");
66
67
68 private static final Pattern SPLIT_AT_COMMAS = Pattern.compile("\\p{Space}*,\\p{Space}*");
69
70
71 private static final Pattern SPLIT_AT_COMMAS_NO_SPACE = Pattern.compile(",");
72
73
74 private static final Pattern BOOLEAN_TRUE = Pattern.compile("(?:yes)|(?:true)",
75 Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
76
77
78 private static final Pattern BOOLEAN_FALSE = Pattern.compile("(?:no)|(?:false)",
79 Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
80
81
82 private TokenType type;
83
84
85 private final String name;
86
87
88 private final String content;
89
90
91 private final Unit units;
92
93
94 private final int lineNumber;
95
96
97 private final String fileName;
98
99
100
101
102
103
104
105
106
107 public ParseToken(final TokenType type, final String name, final String content, final Unit units,
108 final int lineNumber, final String fileName) {
109 this.type = type;
110 this.name = name;
111 this.content = content;
112 this.units = units;
113 this.lineNumber = lineNumber;
114 this.fileName = fileName;
115 }
116
117
118
119
120 public TokenType getType() {
121 return type;
122 }
123
124
125
126
127 public String getName() {
128 return name;
129 }
130
131
132
133
134 public String getRawContent() {
135 return content;
136 }
137
138
139
140
141
142
143
144
145 public String getContentAsNormalizedString() {
146 return SPACE.matcher(content.replace('_', ' ')).replaceAll(" ").trim();
147 }
148
149
150
151
152
153 public List<String> getContentAsFreeTextList() {
154 return Arrays.asList(SPLIT_AT_COMMAS.split(getRawContent()));
155 }
156
157
158
159
160
161
162
163
164 public List<String> getContentAsNormalizedList() {
165 return Arrays.asList(SPLIT_AT_COMMAS.split(getContentAsNormalizedString()));
166 }
167
168
169
170
171 public String getContentAsUppercaseString() {
172 return getContentAsNormalizedString().toUpperCase(Locale.US);
173 }
174
175
176
177
178 public List<String> getContentAsUppercaseList() {
179 return Arrays.asList(SPLIT_AT_COMMAS.split(getContentAsUppercaseString()));
180 }
181
182
183
184
185
186
187 public <T extends Enum<T>> T getContentAsEnum(final Class<T> cls) {
188 return toEnum(cls, getRawContent());
189 }
190
191
192
193
194
195
196 public <T extends Enum<T>> List<T> getContentAsEnumList(final Class<T> cls) {
197 final String[] elements = SPLIT_AT_COMMAS.split(getRawContent());
198 final List<T> list = new ArrayList<>(elements.length);
199 for (String element : elements) {
200 list.add(toEnum(cls, element));
201 }
202 return list;
203 }
204
205
206
207
208 public double getContentAsDouble() {
209 try {
210 return Double.parseDouble(content);
211 } catch (NumberFormatException nfe) {
212 throw generateException(nfe);
213 }
214 }
215
216
217
218
219 public Vector3D getContentAsVector() {
220 try {
221 final String[] fields = SPACE.split(content);
222 if (fields.length == 3) {
223 return new Vector3D(Double.parseDouble(fields[0]),
224 Double.parseDouble(fields[1]),
225 Double.parseDouble(fields[2]));
226 }
227 } catch (NumberFormatException nfe) {
228
229 }
230 throw generateException(null);
231 }
232
233
234
235
236 public boolean getContentAsBoolean() {
237 if (BOOLEAN_TRUE.matcher(content).matches()) {
238 return true;
239 } else if (BOOLEAN_FALSE.matcher(content).matches()) {
240 return false;
241 } else {
242 throw generateException(null);
243 }
244 }
245
246
247
248
249 public int getContentAsInt() {
250 try {
251 return Integer.parseInt(content);
252 } catch (NumberFormatException nfe) {
253 throw generateException(nfe);
254 }
255 }
256
257
258
259
260 public char getContentAsUppercaseCharacter() {
261 try {
262 return getContentAsUppercaseString().charAt(0);
263 } catch (NumberFormatException nfe) {
264 throw generateException(nfe);
265 }
266 }
267
268
269
270
271 public Unit getUnits() {
272 return units;
273 }
274
275
276
277
278 public int getLineNumber() {
279 return lineNumber;
280 }
281
282
283
284
285 public String getFileName() {
286 return fileName;
287 }
288
289
290
291
292
293
294 public boolean processAsNormalizedString(final StringConsumer consumer) {
295 if (type == TokenType.ENTRY) {
296 consumer.accept(getContentAsNormalizedString());
297 }
298 return true;
299 }
300
301
302
303
304
305
306 public boolean processAsUppercaseString(final StringConsumer consumer) {
307 if (type == TokenType.ENTRY) {
308 consumer.accept(getContentAsUppercaseString());
309 }
310 return true;
311 }
312
313
314
315
316
317
318 public boolean processAsIndexedNormalizedString(final int index, final IndexedStringConsumer consumer) {
319 if (type == TokenType.ENTRY) {
320 consumer.accept(index, getContentAsNormalizedString());
321 }
322 return true;
323 }
324
325
326
327
328
329
330 public boolean processAsIndexedUppercaseString(final int index, final IndexedStringConsumer consumer) {
331 if (type == TokenType.ENTRY) {
332 consumer.accept(index, getContentAsUppercaseString());
333 }
334 return true;
335 }
336
337
338
339
340
341
342 public boolean processAsFreeTextList(final StringListConsumer consumer) {
343 if (type == TokenType.ENTRY) {
344 consumer.accept(getContentAsFreeTextList());
345 }
346 return true;
347 }
348
349
350
351
352
353 public boolean processAsNormalizedList(final StringListConsumer consumer) {
354 if (type == TokenType.ENTRY) {
355 consumer.accept(getContentAsNormalizedList());
356 }
357 return true;
358 }
359
360
361
362
363
364 public boolean processAsUppercaseList(final StringListConsumer consumer) {
365 if (type == TokenType.ENTRY) {
366 consumer.accept(getContentAsUppercaseList());
367 }
368 return true;
369 }
370
371
372
373
374
375
376
377 public <T extends Enum<T>> boolean processAsEnum(final Class<T> cls, final EnumConsumer<T> consumer) {
378 if (type == TokenType.ENTRY) {
379 consumer.accept(getContentAsEnum(cls));
380 }
381 return true;
382 }
383
384
385
386
387
388
389
390 public <T extends Enum<T>> boolean processAsEnumsList(final Class<T> cls, final EnumListConsumer<T> consumer) {
391 if (type == TokenType.ENTRY) {
392 consumer.accept(getContentAsEnumList(cls));
393 }
394 return true;
395 }
396
397
398
399
400
401 public boolean processAsBoolean(final BooleanConsumer consumer) {
402 if (type == TokenType.ENTRY) {
403 consumer.accept(getContentAsBoolean());
404 }
405 return true;
406 }
407
408
409
410
411
412 public boolean processAsInteger(final IntConsumer consumer) {
413 if (type == TokenType.ENTRY) {
414 consumer.accept(getContentAsInt());
415 }
416 return true;
417 }
418
419
420
421
422
423
424
425 public boolean processAsIndexedInteger(final int index, final IndexedIntConsumer consumer) {
426 if (type == TokenType.ENTRY) {
427 consumer.accept(index, getContentAsInt());
428 }
429 return true;
430 }
431
432
433
434
435
436 public boolean processAsIntegerArrayNoSpace(final IntegerArrayConsumer consumer) {
437 try {
438 if (type == TokenType.ENTRY) {
439
440 final String[] fields = SPLIT_AT_COMMAS_NO_SPACE.split(getRawContent());
441 final int[] integers = new int[fields.length];
442 for (int i = 0; i < fields.length; ++i) {
443 integers[i] = Integer.parseInt(fields[i]);
444 }
445 consumer.accept(integers);
446 }
447 return true;
448 } catch (NumberFormatException nfe) {
449 throw generateException(nfe);
450 }
451 }
452
453
454
455
456
457 public boolean processAsIntegerArray(final IntegerArrayConsumer consumer) {
458 try {
459 if (type == TokenType.ENTRY) {
460 final String[] fields = SPACE.split(getRawContent());
461 final int[] integers = new int[fields.length];
462 for (int i = 0; i < fields.length; ++i) {
463 integers[i] = Integer.parseInt(fields[i]);
464 }
465 consumer.accept(integers);
466 }
467 return true;
468 } catch (NumberFormatException nfe) {
469 throw generateException(nfe);
470 }
471 }
472
473
474
475
476
477 public boolean processAsNormalizedCharacter(final CharConsumer consumer) {
478 if (type == TokenType.ENTRY) {
479 consumer.accept(getContentAsUppercaseCharacter());
480 }
481 return true;
482 }
483
484
485
486
487
488
489
490 public boolean processAsDouble(final Unit standard, final ParsedUnitsBehavior behavior,
491 final DoubleConsumer consumer) {
492 if (type == TokenType.ENTRY) {
493 consumer.accept(behavior.select(getUnits(), standard).toSI(getContentAsDouble()));
494 }
495 return true;
496 }
497
498
499
500
501
502
503
504
505 public boolean processAsLabeledDouble(final char label,
506 final Unit standard, final ParsedUnitsBehavior behavior,
507 final LabeledDoubleConsumer consumer) {
508 if (type == TokenType.ENTRY) {
509 consumer.accept(label, behavior.select(getUnits(), standard).toSI(getContentAsDouble()));
510 }
511 return true;
512 }
513
514
515
516
517
518
519
520
521 public boolean processAsIndexedDouble(final int i,
522 final Unit standard, final ParsedUnitsBehavior behavior,
523 final IndexedDoubleConsumer consumer) {
524 if (type == TokenType.ENTRY) {
525 consumer.accept(i, behavior.select(getUnits(), standard).toSI(getContentAsDouble()));
526 }
527 return true;
528 }
529
530
531
532
533
534
535
536
537
538 public boolean processAsDoublyIndexedDouble(final int i, final int j,
539 final Unit standard, final ParsedUnitsBehavior behavior,
540 final DoublyIndexedDoubleConsumer consumer) {
541 if (type == TokenType.ENTRY) {
542 consumer.accept(i, j, behavior.select(getUnits(), standard).toSI(getContentAsDouble()));
543 }
544 return true;
545 }
546
547
548
549
550
551
552
553
554 public boolean processAsDoubleArray(final Unit standard, final ParsedUnitsBehavior behavior,
555 final DoubleArrayConsumer consumer) {
556 try {
557 if (type == TokenType.ENTRY) {
558 final String[] fields = SPACE.split(getRawContent());
559 final double[] doubles = new double[fields.length];
560 for (int i = 0; i < fields.length; ++i) {
561 doubles[i] = behavior.select(getUnits(), standard).toSI(Double.parseDouble(fields[i]));
562 }
563 consumer.accept(doubles);
564 }
565 return true;
566 } catch (NumberFormatException nfe) {
567 throw generateException(nfe);
568 }
569 }
570
571
572
573
574
575
576
577
578
579 public boolean processAsIndexedDoubleArray(final int index,
580 final Unit standard, final ParsedUnitsBehavior behavior,
581 final IndexedDoubleArrayConsumer consumer) {
582 if (type == TokenType.ENTRY) {
583 final String[] fields = SPACE.split(content);
584 final double[] values = new double[fields.length];
585 for (int i = 0; i < fields.length; ++i) {
586 values[i] = behavior.select(getUnits(), standard).toSI(Double.parseDouble(fields[i]));
587 }
588 consumer.accept(index, values);
589 }
590 return true;
591 }
592
593
594
595
596
597
598
599 public boolean processAsVector(final Unit standard, final ParsedUnitsBehavior behavior,
600 final VectorConsumer consumer) {
601 if (type == TokenType.ENTRY) {
602 final double scale = behavior.select(getUnits(), standard).getScale();
603 consumer.accept(getContentAsVector().scalarMultiply(scale));
604 }
605 return true;
606 }
607
608
609
610
611
612
613 public boolean processAsDate(final DateConsumer consumer, final ContextBinding context) {
614 if (type == TokenType.ENTRY) {
615 if (context.getTimeSystem() == null) {
616 throw new OrekitException(OrekitMessages.CCSDS_TIME_SYSTEM_NOT_READ_YET,
617 getLineNumber(), getFileName());
618 }
619 consumer.accept(context.getTimeSystem().getConverter(context).parse(content));
620 }
621 return true;
622 }
623
624
625
626
627
628 public boolean processAsTimeSystem(final TimeSystemConsumer consumer) {
629 if (type == TokenType.ENTRY) {
630 consumer.accept(TimeSystem.parse(getContentAsUppercaseString()));
631 }
632 return true;
633 }
634
635
636
637
638
639
640
641
642
643 public boolean processAsFrame(final FrameConsumer consumer, final ContextBinding context,
644 final boolean allowCelestial, final boolean allowOrbit,
645 final boolean allowSpacecraft) {
646 if (type == TokenType.ENTRY) {
647 try {
648 consumer.accept(FrameFacade.parse(DASH.
649 matcher(getContentAsUppercaseString()).
650 replaceAll("").
651 replace(' ', '_'),
652 context.getConventions(),
653 context.isSimpleEOP(), context.getDataContext(),
654 allowCelestial, allowOrbit, allowSpacecraft));
655 } catch (OrekitException oe) {
656 throw generateException(oe);
657 }
658 }
659 return true;
660 }
661
662
663
664
665
666
667 public boolean processAsCenter(final CenterConsumer consumer, final CelestialBodies celestialBodies) {
668 if (type == TokenType.ENTRY) {
669 final String centerName = getContentAsUppercaseString();
670 consumer.accept(new BodyFacade(centerName, body(centerName, celestialBodies)));
671 }
672 return true;
673 }
674
675
676
677
678
679
680 public boolean processAsCenterList(final CenterListConsumer consumer, final CelestialBodies celestialBodies) {
681 if (type == TokenType.ENTRY) {
682 final List<BodyFacade> facades = new ArrayList<>();
683 for (final String centerName : SPLIT_AT_COMMAS.split(getContentAsUppercaseString())) {
684 facades.add(new BodyFacade(centerName, body(centerName, celestialBodies)));
685 }
686 consumer.accept(facades);
687 }
688 return true;
689 }
690
691
692
693
694
695
696 public boolean processAsRotationOrder(final RotationOrderConsumer consumer) {
697 if (type == TokenType.ENTRY) {
698 try {
699 consumer.accept(RotationOrder.valueOf(getContentAsUppercaseString().
700 replace('1', 'X').
701 replace('2', 'Y').
702 replace('3', 'Z')));
703 } catch (IllegalArgumentException iae) {
704 throw new OrekitException(OrekitMessages.CCSDS_INVALID_ROTATION_SEQUENCE,
705 getContentAsUppercaseString(), getLineNumber(), getFileName());
706 }
707 }
708 return true;
709 }
710
711
712
713
714
715 public boolean processAsUnitList(final UnitListConsumer consumer) {
716 if (type == TokenType.ENTRY) {
717 final String bracketed = getContentAsNormalizedString();
718 if (bracketed.charAt(0) != '[' || bracketed.charAt(bracketed.length() - 1) != ']') {
719 throw generateException(null);
720 }
721 final String unbracketed = bracketed.substring(1, bracketed.length() - 1).trim();
722 try {
723 consumer.accept(Stream.of(SPLIT_AT_COMMAS.split(unbracketed)).
724 map(Unit::parse).
725 collect(Collectors.toList()));
726 } catch (OrekitException oe) {
727
728 throw generateException(oe);
729 }
730 }
731 return true;
732 }
733
734
735
736
737
738 public boolean processAsFreeTextString(final StringConsumer consumer) {
739 if (type == TokenType.ENTRY) {
740 consumer.accept(getRawContent());
741 }
742 return true;
743 }
744
745
746
747
748
749 public boolean processAsManeuvrableEnum(final ManeuvrableConsumer consumer) {
750 if (type == TokenType.ENTRY) {
751 consumer.accept(Maneuvrable.getEnum(getRawContent()));
752 }
753 return true;
754 }
755
756
757
758
759
760 public OrekitException generateException(final Exception cause) {
761 return new OrekitException(cause, OrekitMessages.UNABLE_TO_PARSE_ELEMENT_IN_FILE,
762 getName(), getLineNumber(), getFileName());
763 }
764
765
766
767
768
769
770 private CelestialBody body(final String centerName, final CelestialBodies celestialBodies) {
771
772
773 final String canonicalValue;
774 if (centerName.equals("SOLAR SYSTEM BARYCENTER") || centerName.equals("SSB")) {
775 canonicalValue = "SOLAR_SYSTEM_BARYCENTER";
776 } else if (centerName.equals("EARTH MOON BARYCENTER") || centerName.equals("EARTH-MOON BARYCENTER") ||
777 centerName.equals("EARTH BARYCENTER") || centerName.equals("EMB")) {
778 canonicalValue = "EARTH_MOON";
779 } else {
780 canonicalValue = centerName;
781 }
782
783 try {
784 return CenterName.valueOf(canonicalValue).getCelestialBody(celestialBodies);
785 } catch (IllegalArgumentException iae) {
786
787 return null;
788 }
789
790 }
791
792
793
794
795
796
797
798 private <T extends Enum<T>> T toEnum(final Class<T> cls, final String value) {
799
800 final String noSpace = value.replace(' ', '_');
801 try {
802
803 return Enum.valueOf(cls, noSpace);
804 } catch (IllegalArgumentException iae1) {
805 try {
806
807 return Enum.valueOf(cls, noSpace.toUpperCase(Locale.US));
808 } catch (IllegalArgumentException iae2) {
809
810 throw generateException(iae1);
811 }
812 }
813 }
814
815
816 public interface StringConsumer {
817
818
819
820 void accept(String value);
821 }
822
823
824 public interface IndexedStringConsumer {
825
826
827
828
829 void accept(int index, String value);
830 }
831
832
833 public interface StringListConsumer {
834
835
836
837 void accept(List<String> value);
838 }
839
840
841
842
843 public interface EnumConsumer<T extends Enum<T>> {
844
845
846
847 void accept(T value);
848 }
849
850
851
852
853 public interface EnumListConsumer<T extends Enum<T>> {
854
855
856
857 void accept(List<T> value);
858 }
859
860
861 public interface BooleanConsumer {
862
863
864
865 void accept(boolean value);
866 }
867
868
869 public interface IntConsumer {
870
871
872
873 void accept(int value);
874 }
875
876
877
878
879 public interface IndexedIntConsumer {
880
881
882
883
884 void accept(int index, int value);
885 }
886
887
888 public interface IntegerArrayConsumer {
889
890
891
892 void accept(int[] integers);
893 }
894
895
896 public interface CharConsumer {
897
898
899
900 void accept(char value);
901 }
902
903
904 public interface DoubleConsumer {
905
906
907
908 void accept(double value);
909 }
910
911
912 public interface LabeledDoubleConsumer {
913
914
915
916
917 void accept(char label, double value);
918 }
919
920
921 public interface IndexedDoubleConsumer {
922
923
924
925
926 void accept(int i, double value);
927 }
928
929
930 public interface DoublyIndexedDoubleConsumer {
931
932
933
934
935
936 void accept(int i, int j, double value);
937 }
938
939
940 public interface DoubleArrayConsumer {
941
942
943
944 void accept(double[] doubles);
945 }
946
947
948
949
950 public interface IndexedDoubleArrayConsumer {
951
952
953
954
955 void accept(int index, double[] value);
956 }
957
958
959 public interface VectorConsumer {
960
961
962
963 void accept(Vector3D value);
964 }
965
966
967 public interface DateConsumer {
968
969
970
971 void accept(AbsoluteDate value);
972 }
973
974
975 public interface TimeSystemConsumer {
976
977
978
979 void accept(TimeSystem value);
980 }
981
982
983 public interface FrameConsumer {
984
985
986
987 void accept(FrameFacade frameFacade);
988 }
989
990
991 public interface CenterConsumer {
992
993
994
995 void accept(BodyFacade bodyFacade);
996 }
997
998
999 public interface CenterListConsumer {
1000
1001
1002
1003 void accept(List<BodyFacade> bodyFacades);
1004 }
1005
1006
1007
1008
1009 public interface RotationOrderConsumer {
1010
1011
1012
1013 void accept(RotationOrder value);
1014 }
1015
1016
1017 public interface UnitListConsumer {
1018
1019
1020
1021 void accept(List<Unit> value);
1022 }
1023
1024
1025 public interface ManeuvrableConsumer {
1026
1027
1028
1029 void accept(Maneuvrable value);
1030 }
1031 }