1 /* Copyright 2002-2026 CS GROUP
2 * Licensed to CS GROUP (CS) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * CS licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.orekit.files.ccsds.utils.generation;
18
19 import java.io.IOException;
20 import java.util.List;
21 import java.util.Optional;
22
23 import org.orekit.files.ccsds.definitions.TimeConverter;
24 import org.orekit.files.ccsds.utils.FileFormat;
25 import org.orekit.time.AbsoluteDate;
26 import org.orekit.time.DateComponents;
27 import org.orekit.time.DateTimeComponents;
28 import org.orekit.time.TimeComponents;
29 import org.orekit.utils.Formatter;
30 import org.orekit.utils.units.Unit;
31
32 /** Generation interface for CCSDS messages.
33 * @author Luc Maisonobe
34 * @since 11.0
35 */
36 public interface Generator extends AutoCloseable {
37
38 /** Get the name of the output (for error messages).
39 * @return name of the output
40 */
41 String getOutputName();
42
43 /** Get the generated file format.
44 * @return generated file format
45 */
46 FileFormat getFormat();
47
48 /**
49 * Used to format dates and doubles to string.
50 * @return formatter
51 */
52 Formatter getFormatter();
53
54 /** Start CCSDS message.
55 * @param messageTypeKey key for message type
56 * @param root root element for XML files
57 * @param version format version
58 * @throws IOException if an I/O error occurs.
59 */
60 void startMessage(String root, String messageTypeKey, double version) throws IOException;
61
62 /** End CCSDS message.
63 * @param root root element for XML files
64 * @throws IOException if an I/O error occurs.
65 */
66 void endMessage(String root) throws IOException;
67
68 /** Write comment lines.
69 * @param comments comments to write
70 * @throws IOException if an I/O error occurs.
71 */
72 void writeComments(List<String> comments) throws IOException;
73
74 /** Write a single key/value entry.
75 * @param key the keyword to write
76 * @param value the value to write
77 * @param unit output unit (may be null)
78 * @param mandatory if true, null values triggers exception; otherwise they are silently ignored
79 * @throws IOException if an I/O error occurs.
80 */
81 void writeEntry(String key, String value, Unit unit, boolean mandatory) throws IOException;
82
83 /** Write a single key/value entry.
84 * <p>
85 * This method is a convenience method that allows to write an optional String value
86 * without having to call {@code orElse(null)} on it.
87 * </p>
88 * @param key the keyword to write
89 * @param value the optional value to write
90 * @param unit output unit (may be null)
91 * @param mandatory if true, null values triggers exception; otherwise they are silently ignored
92 * @throws IOException if an I/O error occurs.
93 */
94 @SuppressWarnings("OptionalUsedAsFieldOrParameterType") // we want to use Optional here to avoid having to call orElse(null) everywhere
95 default void writeOptionalStringEntry(final String key, final Optional<String> value,
96 final Unit unit, final boolean mandatory) throws IOException {
97 writeEntry(key, value.orElse(null), unit, mandatory);
98 }
99
100 /** Write a single key/value entry.
101 * @param key the keyword to write
102 * @param value the value to write
103 * @param mandatory if true, null values triggers exception; otherwise they are silently ignored
104 * @throws IOException if an I/O error occurs.
105 */
106 void writeEntry(String key, List<String> value, boolean mandatory) throws IOException;
107
108 /** Write a single key/value entry.
109 * @param key the keyword to write
110 * @param value the value to write
111 * @param mandatory if true, null values triggers exception; otherwise they are silently ignored
112 * @throws IOException if an I/O error occurs.
113 */
114 void writeEntry(String key, Enum<?> value, boolean mandatory) throws IOException;
115
116 /** Write a single key/value entry.
117 * <p>
118 * This method is a convenience method that allows to write an optional enum value
119 * without having to map on it.
120 * </p>
121 * @param key the keyword to write
122 * @param value the optional value to write
123 * @param mandatory if true, null values triggers exception; otherwise they are silently ignored
124 * @throws IOException if an I/O error occurs.
125 */
126 @SuppressWarnings("OptionalUsedAsFieldOrParameterType") // we want to use Optional here to avoid having to call value.map(Enum::name) everywhere
127 default void writeOptionalEnumEntry(final String key, final Optional<? extends Enum<?>> value,
128 final boolean mandatory) throws IOException {
129 writeEntry(key, value.map(Enum::name).orElse(null), null, mandatory);
130 }
131
132 /** Write a single key/value entry.
133 * @param key the keyword to write
134 * @param converter converter to use for dates
135 * @param date the date to write
136 * @param forceCalendar if true, the date is forced to calendar format
137 * @param mandatory if true, null values triggers exception; otherwise they are silently ignored
138 * @throws IOException if an I/O error occurs.
139 */
140 void writeEntry(String key, TimeConverter converter, AbsoluteDate date, boolean forceCalendar, boolean mandatory) throws IOException;
141
142 /** Write a single key/value entry.
143 * <p>
144 * This method is a convenience method that allows to write an optional String value
145 * without having to call {@code orElse(null)} on it.
146 * </p>
147 * @param key the keyword to write
148 * @param converter converter to use for dates
149 * @param date the date to write
150 * @param forceCalendar if true, the date is forced to calendar format
151 * @param mandatory if true, null values triggers exception; otherwise they are silently ignored
152 * @throws IOException if an I/O error occurs.
153 */
154 @SuppressWarnings("OptionalUsedAsFieldOrParameterType") // we want to use Optional here to avoid having to call orElse(null) everywhere
155 default void writeOptionalDateEntry(final String key, final TimeConverter converter,
156 final Optional<AbsoluteDate> date, final boolean forceCalendar,
157 final boolean mandatory) throws IOException {
158 writeEntry(key, converter, date.orElse(null), forceCalendar, mandatory);
159 }
160
161 /** Write a single key/value entry.
162 * @param key the keyword to write
163 * @param value the value to write
164 * @param mandatory if true, null values triggers exception; otherwise they are silently ignored
165 * @throws IOException if an I/O error occurs.
166 */
167 void writeEntry(String key, char value, boolean mandatory) throws IOException;
168
169 /**
170 * Write a single key/value entry.
171 *
172 * <p>Note that the {@code mandatory} flag has no effect and a value is always written
173 * because the whole domain of {@code value} is treated as valid. Use {@link
174 * #writeEntry(String, Integer, boolean)} for integer values that may not be present.
175 *
176 * @param key the keyword to write
177 * @param value the value to write
178 * @param mandatory if true, null values triggers exception; otherwise they are silently ignored.
179 * @throws IOException if an I/O error occurs.
180 * @see #writeEntry(String, Integer, boolean)
181 */
182 void writeEntry(String key, int value, boolean mandatory) throws IOException;
183
184 /** Write a single key/value entry.
185 * @param key the keyword to write
186 * @param value the value to write
187 * @param mandatory if true, null values triggers exception; otherwise they are silently ignored
188 * @throws IOException if an I/O error occurs.
189 */
190 default void writeEntry(final String key, final Integer value, final boolean mandatory) throws IOException {
191 writeEntry(key, value == null ? null : value.toString(), null, mandatory);
192 }
193
194 /** Write a single key/value entry.
195 * <p>
196 * This method is a convenience method that allows to write an optional value
197 * without having to check presence on it.
198 * </p>
199 * @param key the keyword to write
200 * @param value the optional value to write
201 * @param mandatory if true, null values triggers exception; otherwise they are silently ignored
202 * @throws IOException if an I/O error occurs.
203 */
204 @SuppressWarnings("OptionalUsedAsFieldOrParameterType") // we want to use Optional here to avoid having to call value.isPresent() everywhere
205 default void writeOptionalIntEntry(final String key, final Optional<Integer> value,
206 final boolean mandatory) throws IOException {
207 writeEntry(key, value.map(integer -> Integer.toString(integer)).orElse(null), null, mandatory);
208 }
209
210 /** Write a single key/value entry.
211 * @param key the keyword to write
212 * @param value the value to write (in SI units)
213 * @param unit output unit
214 * @param mandatory if true, null values triggers exception, otherwise they are silently ignored
215 * @throws IOException if an I/O error occurs.
216 */
217 void writeEntry(String key, double value, Unit unit, boolean mandatory) throws IOException;
218
219 /** Write a single key/value entry.
220 * @param key the keyword to write
221 * @param value the value to write (in SI units)
222 * @param unit output unit
223 * @param mandatory if true, null values triggers exception, otherwise they are silently ignored
224 * @throws IOException if an I/O error occurs.
225 */
226 void writeEntry(String key, Double value, Unit unit, boolean mandatory) throws IOException;
227
228 /** Write a single key/value entry.
229 * <p>
230 * This method is a convenience method that allows to write an optional value
231 * without having to call {@code orElse(Double.NaN)} on it.
232 * </p>
233 * @param key the keyword to write
234 * @param value the optional value to write
235 * @param unit output unit (may be null)
236 * @param mandatory if true, null values triggers exception, otherwise they are silently ignored
237 * @throws IOException if an I/O error occurs.
238 */
239 @SuppressWarnings("OptionalUsedAsFieldOrParameterType") // we want to use Optional here to avoid having to call orElse(Double.NaN) everywhere
240 default void writeOptionalDoubleEntry(final String key, final Optional<Double> value,
241 final Unit unit, final boolean mandatory) throws IOException {
242 writeEntry(key, value.orElse(Double.NaN), unit, mandatory);
243 }
244
245 /** Finish current line.
246 * @throws IOException if an I/O error occurs.
247 */
248 void newLine() throws IOException;
249
250 /** Write raw data.
251 * @param data raw data to write
252 * @throws IOException if an I/O error occurs.
253 */
254 void writeRawData(char data) throws IOException;
255
256 /** Write raw data.
257 * @param data raw data to write
258 * @throws IOException if an I/O error occurs.
259 */
260 void writeRawData(CharSequence data) throws IOException;
261
262 /** Enter into a new section.
263 * @param name section name
264 * @throws IOException if an I/O error occurs.
265 */
266 void enterSection(String name) throws IOException;
267
268 /** Exit last section.
269 * @return section name
270 * @throws IOException if an I/O error occurs.
271 */
272 String exitSection() throws IOException;
273
274 /** Close the generator.
275 * @throws IOException if an I/O error occurs.
276 */
277 void close() throws IOException;
278
279 /** Convert a date to string value with high precision.
280 * @param converter converter for dates
281 * @param date date to write
282 * @return date as a string (may be either a relative date or a calendar date)
283 */
284 String dateToString(TimeConverter converter, AbsoluteDate date);
285
286 /** Convert a date to calendar string value with high precision.
287 * @param converter converter for dates
288 * @param date date to write
289 * @return date as a calendar string
290 * @since 12.0
291 */
292 String dateToCalendarString(TimeConverter converter, AbsoluteDate date);
293
294 /**
295 * Convert a date to string value with high precision.
296 * @param dt date and time components to write
297 * @return date as a string
298 * @since 13.1.6
299 */
300 default String dateToString(final DateTimeComponents dt) {
301 final DateComponents date = dt.getDate();
302 final TimeComponents time = dt.getTime();
303 return dateToString(date.getYear(), date.getMonth(), date.getDay(),
304 time.getHour(), time.getMinute(), time.getSecond());
305 }
306
307 /** Convert a date to string value with high precision.
308 * @param year year
309 * @param month month
310 * @param day day
311 * @param hour hour
312 * @param minute minute
313 * @param seconds seconds
314 * @return date as a string
315 */
316 String dateToString(int year, int month, int day, int hour, int minute, double seconds);
317
318 /** Convert a double to string value with high precision.
319 * <p>
320 * We don't want to loose internal accuracy when writing doubles
321 * but we also don't want to have ugly representations like STEP = 1.25000000000000000
322 * so we try a few simple formats first and fall back to scientific notation
323 * if it doesn't work.
324 * </p>
325 * @param value value to format
326 * @return formatted value, with all original value accuracy preserved, or null
327 * if value is null or {@code Double.NaN}
328 */
329 String doubleToString(double value);
330
331 /** Convert a list of units to a bracketed string.
332 * @param units lists to output (may be null or empty)
333 * @return bracketed string (null if units list is null or empty)
334 */
335 String unitsListToString(List<Unit> units);
336
337 /** Convert a SI unit name to a CCSDS name.
338 * @param siName si unit name
339 * @return CCSDS name for the unit
340 */
341 String siToCcsdsName(String siName);
342
343 }