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