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