ParseToken.java

  1. /* Copyright 2002-2022 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.lexical;

  18. import java.util.ArrayList;
  19. import java.util.Arrays;
  20. import java.util.List;
  21. import java.util.Locale;
  22. import java.util.regex.Pattern;
  23. import java.util.stream.Collectors;
  24. import java.util.stream.Stream;

  25. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  26. import org.orekit.bodies.CelestialBodies;
  27. import org.orekit.bodies.CelestialBody;
  28. import org.orekit.errors.OrekitException;
  29. import org.orekit.errors.OrekitMessages;
  30. import org.orekit.files.ccsds.definitions.BodyFacade;
  31. import org.orekit.files.ccsds.definitions.CelestialBodyFrame;
  32. import org.orekit.files.ccsds.definitions.CenterName;
  33. import org.orekit.files.ccsds.definitions.FrameFacade;
  34. import org.orekit.files.ccsds.definitions.OrbitRelativeFrame;
  35. import org.orekit.files.ccsds.definitions.SpacecraftBodyFrame;
  36. import org.orekit.files.ccsds.definitions.TimeSystem;
  37. import org.orekit.files.ccsds.ndm.ParsedUnitsBehavior;
  38. import org.orekit.files.ccsds.utils.ContextBinding;
  39. import org.orekit.time.AbsoluteDate;
  40. import org.orekit.utils.units.Unit;

  41. /** Token occurring during CCSDS file parsing.
  42.  * <p>
  43.  * Parse tokens correspond to:
  44.  * <ul>
  45.  *   <li>bloc or entry start</li>
  46.  *   <li>entry content</li>
  47.  *   <li>bloc or entry end</li>
  48.  *   <li>raw lines</li>
  49.  * </ul>
  50.  * @see MessageParser
  51.  * @author Luc Maisonobe
  52.  * @since 11.0
  53.  */
  54. public class ParseToken {

  55.     /** Pattern for dash. */
  56.     private static final Pattern DASH = Pattern.compile("-");

  57.     /** Pattern for spaces. */
  58.     private static final Pattern SPACE = Pattern.compile("\\p{Space}+");

  59.     /** Pattern for splitting comma-separated lists. */
  60.     private static final Pattern SPLIT_AT_COMMAS = Pattern.compile("\\p{Space}*,\\p{Space}*");

  61.     /** Pattern for true boolean value. */
  62.     private static final Pattern BOOLEAN_TRUE = Pattern.compile("(?:yes)|(?:true)",
  63.                                                                 Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);

  64.     /** Pattern for false boolean value. */
  65.     private static final Pattern BOOLEAN_FALSE = Pattern.compile("(?:no)|(?:false)",
  66.                                                                  Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);

  67.     /** Type of the token. */
  68.     private TokenType type;

  69.     /** Name of the entry. */
  70.     private final String name;

  71.     /** Entry content. */
  72.     private final String content;

  73.     /** Units of the entry. */
  74.     private final Unit units;

  75.     /** Number of the line from which pair is extracted. */
  76.     private final int lineNumber;

  77.     /** Name of the file. */
  78.     private final String fileName;

  79.     /** Simple constructor.
  80.      * @param type type of the token
  81.      * @param name name of the block or entry
  82.      * @param content entry content
  83.      * @param units units of the entry
  84.      * @param lineNumber number of the line in the CCSDS data message
  85.      * @param fileName name of the file
  86.      */
  87.     public ParseToken(final TokenType type, final String name, final String content, final Unit units,
  88.                       final int lineNumber, final String fileName) {
  89.         this.type       = type;
  90.         this.name       = name;
  91.         this.content    = content;
  92.         this.units      = units;
  93.         this.lineNumber = lineNumber;
  94.         this.fileName   = fileName;
  95.     }

  96.     /** Get the type of the token.
  97.      * @return type of the token
  98.      */
  99.     public TokenType getType() {
  100.         return type;
  101.     }

  102.     /** Get the name of the block or entry.
  103.      * @return name of the block or entry
  104.      */
  105.     public String getName() {
  106.         return name;
  107.     }

  108.     /** Get the raw content of the entry.
  109.      * @return entry raw content
  110.      */
  111.     public String getRawContent() {
  112.         return content;
  113.     }

  114.     /** Get the content of the entry.
  115.      * <p>
  116.      * Free-text strings are normalized by replacing all occurrences
  117.      * of '_' with space, and collapsing several spaces as one space only.
  118.      * </p>
  119.      * @return entry content
  120.      */
  121.     public String getContentAsNormalizedString() {
  122.         return SPACE.matcher(content.replace('_', ' ')).replaceAll(" ").trim();
  123.     }

  124.     /** Get the content of the entry as a list of free-text strings.
  125.      * <p>
  126.      * Free-text strings are normalized by replacing all occurrences
  127.      * of '_' with space, and collapsing several spaces as one space only.
  128.      * </p>
  129.      * @return content of the entry as a list of free-test strings
  130.      */
  131.     public List<String> getContentAsNormalizedList() {
  132.         return Arrays.asList(SPLIT_AT_COMMAS.split(getContentAsNormalizedString()));
  133.     }

  134.     /** Get the content of the entry as normalized and uppercased.
  135.      * @return entry normalized and uppercased content
  136.      */
  137.     public String getContentAsUppercaseString() {
  138.         return getContentAsNormalizedString().toUpperCase(Locale.US);
  139.     }

  140.     /** Get the content of the entry as a list of normalized and uppercased strings.
  141.      * @return content of the entry as a list of normalized and uppercased strings
  142.      */
  143.     public List<String> getContentAsUppercaseList() {
  144.         return Arrays.asList(SPLIT_AT_COMMAS.split(getContentAsUppercaseString()));
  145.     }

  146.     /** Get the content of the entry as an enum.
  147.      * @param cls enum class
  148.      * @param <T> type of the enum
  149.      * @return entry content
  150.      */
  151.     public <T extends Enum<T>> T getContentAsEnum(final Class<T> cls) {
  152.         return toEnum(cls, getRawContent());
  153.     }

  154.     /** Get the content of the entry as a list of enum.
  155.      * @param cls enum class
  156.      * @param <T> type of the enum
  157.      * @return entry content
  158.      */
  159.     public <T extends Enum<T>> List<T> getContentAsEnumList(final Class<T> cls) {
  160.         final String[] elements = SPLIT_AT_COMMAS.split(getRawContent());
  161.         final List<T> list = new ArrayList<>(elements.length);
  162.         for (int i = 0; i < elements.length; ++i) {
  163.             list.add(toEnum(cls, elements[i]));
  164.         }
  165.         return list;
  166.     }

  167.     /** Get the content of the entry as a double.
  168.      * @return content as a double
  169.      */
  170.     public double getContentAsDouble() {
  171.         try {
  172.             return Double.parseDouble(content);
  173.         } catch (NumberFormatException nfe) {
  174.             throw generateException(nfe);
  175.         }
  176.     }

  177.     /** Get the content of the entry as a vector.
  178.      * @return content as a vector
  179.      */
  180.     public Vector3D getContentAsVector() {
  181.         try {
  182.             final String[] fields = SPACE.split(content);
  183.             if (fields.length == 3) {
  184.                 return new Vector3D(Double.parseDouble(fields[0]),
  185.                                     Double.parseDouble(fields[1]),
  186.                                     Double.parseDouble(fields[2]));
  187.             }
  188.         } catch (NumberFormatException nfe) {
  189.             // ignored, error handled below, together with wrong number of fields
  190.         }
  191.         throw generateException(null);
  192.     }

  193.     /** Get the content of the entry as a boolean.
  194.      * @return content as a boolean
  195.      */
  196.     public boolean getContentAsBoolean() {
  197.         if (BOOLEAN_TRUE.matcher(content).matches()) {
  198.             return true;
  199.         } else if (BOOLEAN_FALSE.matcher(content).matches()) {
  200.             return false;
  201.         } else {
  202.             throw generateException(null);
  203.         }
  204.     }

  205.     /** Get the content of the entry as an integer.
  206.      * @return content as an integer
  207.      */
  208.     public int getContentAsInt() {
  209.         try {
  210.             return Integer.parseInt(content);
  211.         } catch (NumberFormatException nfe) {
  212.             throw generateException(nfe);
  213.         }
  214.     }

  215.     /** Get the content of the entry as an uppercase character.
  216.      * @return content as an uppercase character
  217.      */
  218.     public char getContentAsUppercaseCharacter() {
  219.         try {
  220.             return getContentAsUppercaseString().charAt(0);
  221.         } catch (NumberFormatException nfe) {
  222.             throw generateException(nfe);
  223.         }
  224.     }

  225.     /** Get the units.
  226.      * @return units of the entry (may be null)
  227.      */
  228.     public Unit getUnits() {
  229.         return units;
  230.     }

  231.     /** Get the number of the line in the CCSDS data message.
  232.      * @return number of the line in the CCSDS data message
  233.      */
  234.     public int getLineNumber() {
  235.         return lineNumber;
  236.     }

  237.     /** Get the name of the file.
  238.      * @return name of the file
  239.      */
  240.     public String getFileName() {
  241.         return fileName;
  242.     }

  243.     /** Process the content as a normalized string.
  244.      * @param consumer consumer of the normalized string
  245.      * @return always returns {@code true}
  246.      * @see #processAsUppercaseString(StringConsumer)
  247.      */
  248.     public boolean processAsNormalizedString(final StringConsumer consumer) {
  249.         if (type == TokenType.ENTRY) {
  250.             consumer.accept(getContentAsNormalizedString());
  251.         }
  252.         return true;
  253.     }

  254.     /** Process the content as a normalized uppercase string.
  255.      * @param consumer consumer of the normalized uppercase string
  256.      * @return always returns {@code true}
  257.      * @see #processAsNormalizedString(StringConsumer)
  258.      */
  259.     public boolean processAsUppercaseString(final StringConsumer consumer) {
  260.         if (type == TokenType.ENTRY) {
  261.             consumer.accept(getContentAsUppercaseString());
  262.         }
  263.         return true;
  264.     }

  265.     /** Process the content as an indexed normalized string.
  266.      * @param index index
  267.      * @param consumer consumer of the indexed normalized string
  268.      * @return always returns {@code true}
  269.      */
  270.     public boolean processAsIndexedNormalizedString(final int index, final IndexedStringConsumer consumer) {
  271.         if (type == TokenType.ENTRY) {
  272.             consumer.accept(index, getContentAsNormalizedString());
  273.         }
  274.         return true;
  275.     }

  276.     /** Process the content as an indexed normalized uppercase string.
  277.      * @param index index
  278.      * @param consumer consumer of the indexed normalized uppercase string
  279.      * @return always returns {@code true}
  280.      */
  281.     public boolean processAsIndexedUppercaseString(final int index, final IndexedStringConsumer consumer) {
  282.         if (type == TokenType.ENTRY) {
  283.             consumer.accept(index, getContentAsUppercaseString());
  284.         }
  285.         return true;
  286.     }

  287.     /** Process the content as a list of normalized strings.
  288.      * @param consumer consumer of the normalized strings list
  289.      * @return always returns {@code true}
  290.      */
  291.     public boolean processAsNormalizedList(final StringListConsumer consumer) {
  292.         if (type == TokenType.ENTRY) {
  293.             consumer.accept(getContentAsNormalizedList());
  294.         }
  295.         return true;
  296.     }

  297.     /** Process the content as a list of normalized uppercase strings.
  298.      * @param consumer consumer of the normalized uppercase strings list
  299.      * @return always returns {@code true}
  300.      */
  301.     public boolean processAsUppercaseList(final StringListConsumer consumer) {
  302.         if (type == TokenType.ENTRY) {
  303.             consumer.accept(getContentAsUppercaseList());
  304.         }
  305.         return true;
  306.     }

  307.     /** Process the content as an enum.
  308.      * @param cls enum class
  309.      * @param consumer consumer of the enum
  310.      * @param <T> type of the enum
  311.      * @return always returns {@code true}
  312.      */
  313.     public <T extends Enum<T>> boolean processAsEnum(final Class<T> cls, final EnumConsumer<T> consumer) {
  314.         if (type == TokenType.ENTRY) {
  315.             consumer.accept(getContentAsEnum(cls));
  316.         }
  317.         return true;
  318.     }

  319.     /** Process the content as a list of enums.
  320.      * @param cls enum class
  321.      * @param consumer consumer of the enums list
  322.      * @param <T> type of the enum
  323.      * @return always returns {@code true}
  324.      */
  325.     public <T extends Enum<T>> boolean processAsEnumsList(final Class<T> cls, final EnumListConsumer<T> consumer) {
  326.         if (type == TokenType.ENTRY) {
  327.             consumer.accept(getContentAsEnumList(cls));
  328.         }
  329.         return true;
  330.     }

  331.     /** Process the content as a boolean.
  332.      * @param consumer consumer of the boolean
  333.      * @return always returns {@code true}
  334.      */
  335.     public boolean processAsBoolean(final BooleanConsumer consumer) {
  336.         if (type == TokenType.ENTRY) {
  337.             consumer.accept(getContentAsBoolean());
  338.         }
  339.         return true;
  340.     }

  341.     /** Process the content as an integer.
  342.      * @param consumer consumer of the integer
  343.      * @return always returns {@code true}
  344.      */
  345.     public boolean processAsInteger(final IntConsumer consumer) {
  346.         if (type == TokenType.ENTRY) {
  347.             consumer.accept(getContentAsInt());
  348.         }
  349.         return true;
  350.     }

  351.     /** Process the content as an array of integers.
  352.      * @param consumer consumer of the array
  353.      * @return always returns {@code true}
  354.      */
  355.     public boolean processAsIntegerArray(final IntegerArrayConsumer consumer) {
  356.         try {
  357.             if (type == TokenType.ENTRY) {
  358.                 final String[] fields = SPLIT_AT_COMMAS.split(getRawContent());
  359.                 final int[] integers = new int[fields.length];
  360.                 for (int i = 0; i < fields.length; ++i) {
  361.                     integers[i] = Integer.parseInt(fields[i]);
  362.                 }
  363.                 consumer.accept(integers);
  364.             }
  365.             return true;
  366.         } catch (NumberFormatException nfe) {
  367.             throw generateException(nfe);
  368.         }
  369.     }

  370.     /** Process the content as a normalized character.
  371.      * @param consumer consumer of the normalized character
  372.      * @return always returns {@code true}
  373.      */
  374.     public boolean processAsNormalizedCharacter(final CharConsumer consumer) {
  375.         if (type == TokenType.ENTRY) {
  376.             consumer.accept(getContentAsUppercaseCharacter());
  377.         }
  378.         return true;
  379.     }

  380.     /** Process the content as a double.
  381.      * @param standard units of parsed content as specified by CCSDS standard
  382.      * @param behavior behavior to adopt for parsed unit
  383.      * @param consumer consumer of the double
  384.      * @return always returns {@code true}
  385.      */
  386.     public boolean processAsDouble(final Unit standard, final ParsedUnitsBehavior behavior,
  387.                                    final DoubleConsumer consumer) {
  388.         if (type == TokenType.ENTRY) {
  389.             consumer.accept(behavior.select(getUnits(), standard).toSI(getContentAsDouble()));
  390.         }
  391.         return true;
  392.     }

  393.     /** Process the content as an labeled double.
  394.      * @param label label
  395.      * @param standard units of parsed content as specified by CCSDS standard
  396.      * @param behavior behavior to adopt for parsed unit
  397.      * @param consumer consumer of the indexed double
  398.      * @return always returns {@code true}
  399.      */
  400.     public boolean processAsLabeledDouble(final char label,
  401.                                           final Unit standard, final ParsedUnitsBehavior behavior,
  402.                                           final LabeledDoubleConsumer consumer) {
  403.         if (type == TokenType.ENTRY) {
  404.             consumer.accept(label, behavior.select(getUnits(), standard).toSI(getContentAsDouble()));
  405.         }
  406.         return true;
  407.     }

  408.     /** Process the content as an indexed double.
  409.      * @param i index
  410.      * @param standard units of parsed content as specified by CCSDS standard
  411.      * @param behavior behavior to adopt for parsed unit
  412.      * @param consumer consumer of the indexed double
  413.      * @return always returns {@code true}
  414.      */
  415.     public boolean processAsIndexedDouble(final int i,
  416.                                           final Unit standard, final ParsedUnitsBehavior behavior,
  417.                                           final IndexedDoubleConsumer consumer) {
  418.         if (type == TokenType.ENTRY) {
  419.             consumer.accept(i, behavior.select(getUnits(), standard).toSI(getContentAsDouble()));
  420.         }
  421.         return true;
  422.     }

  423.     /** Process the content as a doubly-indexed double.
  424.      * @param i first index
  425.      * @param j second index
  426.      * @param standard units of parsed content as specified by CCSDS standard
  427.      * @param behavior behavior to adopt for parsed unit
  428.      * @param consumer consumer of the doubly-indexed double
  429.      * @return always returns {@code true}
  430.      */
  431.     public boolean processAsDoublyIndexedDouble(final int i, final int j,
  432.                                                 final Unit standard, final ParsedUnitsBehavior behavior,
  433.                                                 final DoublyIndexedDoubleConsumer consumer) {
  434.         if (type == TokenType.ENTRY) {
  435.             consumer.accept(i, j, behavior.select(getUnits(), standard).toSI(getContentAsDouble()));
  436.         }
  437.         return true;
  438.     }

  439.     /** Process the content as a vector.
  440.      * @param consumer consumer of the vector
  441.      * @return always returns {@code true} (or throws an exception)
  442.      */
  443.     public boolean processAsVector(final VectorConsumer consumer) {
  444.         if (type == TokenType.ENTRY) {
  445.             consumer.accept(getContentAsVector());
  446.         }
  447.         return true;
  448.     }

  449.     /** Process the content as a date.
  450.      * @param consumer consumer of the date
  451.      * @param context context binding
  452.      * @return always returns {@code true} (or throws an exception)
  453.      */
  454.     public boolean processAsDate(final DateConsumer consumer, final ContextBinding context) {
  455.         if (type == TokenType.ENTRY) {
  456.             if (context.getTimeSystem() == null) {
  457.                 throw new OrekitException(OrekitMessages.CCSDS_TIME_SYSTEM_NOT_READ_YET,
  458.                                           getLineNumber(), getFileName());
  459.             }
  460.             consumer.accept(context.getTimeSystem().getConverter(context).parse(content));
  461.         }
  462.         return true;
  463.     }

  464.     /** Process the content as a time system.
  465.      * @param consumer consumer of the time system
  466.      * @return always returns {@code true} (or throws an exception)
  467.      */
  468.     public boolean processAsTimeSystem(final TimeSystemConsumer consumer) {
  469.         if (type == TokenType.ENTRY) {
  470.             consumer.accept(TimeSystem.parse(getContentAsUppercaseString()));
  471.         }
  472.         return true;
  473.     }

  474.     /** Process the content as a frame.
  475.      * @param consumer consumer of the frame
  476.      * @param context context binding
  477.      * @param allowCelestial if true, {@link CelestialBodyFrame} are allowed
  478.      * @param allowOrbit if true, {@link OrbitRelativeFrame} are allowed
  479.      * @param allowSpacecraft if true, {@link SpacecraftBodyFrame} are allowed
  480.      * @return always returns {@code true}
  481.      */
  482.     public boolean processAsFrame(final FrameConsumer consumer, final ContextBinding context,
  483.                                   final boolean allowCelestial, final boolean allowOrbit,
  484.                                   final boolean allowSpacecraft) {
  485.         if (type == TokenType.ENTRY) {
  486.             try {
  487.                 consumer.accept(FrameFacade.parse(DASH.
  488.                                                   matcher(getContentAsUppercaseString()).
  489.                                                   replaceAll("").
  490.                                                   replace(' ', '_'),
  491.                                                   context.getConventions(),
  492.                                                   context.isSimpleEOP(), context.getDataContext(),
  493.                                                   allowCelestial, allowOrbit, allowSpacecraft));
  494.             } catch (OrekitException oe) {
  495.                 throw generateException(oe);
  496.             }
  497.         }
  498.         return true;
  499.     }

  500.     /** Process the content as a body center.
  501.      * @param consumer consumer of the body center
  502.      * @param celestialBodies factory for celestial bodies
  503.      * @return always returns {@code true}
  504.      */
  505.     public boolean processAsCenter(final CenterConsumer consumer, final CelestialBodies celestialBodies) {
  506.         if (type == TokenType.ENTRY) {
  507.             final String centerName = getContentAsUppercaseString();
  508.             consumer.accept(new BodyFacade(centerName, body(centerName, celestialBodies)));
  509.         }
  510.         return true;
  511.     }

  512.     /** Process the content as a body center list.
  513.      * @param consumer consumer of the body center list
  514.      * @param celestialBodies factory for celestial bodies
  515.      * @return always returns {@code true}
  516.      */
  517.     public boolean processAsCenterList(final CenterListConsumer consumer, final CelestialBodies celestialBodies) {
  518.         if (type == TokenType.ENTRY) {
  519.             final List<BodyFacade> facades = new ArrayList<>();
  520.             for (final String centerName : SPLIT_AT_COMMAS.split(getContentAsUppercaseString())) {
  521.                 facades.add(new BodyFacade(centerName, body(centerName, celestialBodies)));
  522.             }
  523.             consumer.accept(facades);
  524.         }
  525.         return true;
  526.     }

  527.     /** Process the content as a list of units.
  528.      * @param consumer consumer of the time scale
  529.      * @return always returns {@code true} (or throws an exception)
  530.      */
  531.     public boolean processAsUnitList(final UnitListConsumer consumer) {
  532.         if (type == TokenType.ENTRY) {
  533.             final String bracketed = getContentAsNormalizedString();
  534.             if (bracketed.charAt(0) != '[' || bracketed.charAt(bracketed.length() - 1) != ']') {
  535.                 throw generateException(null);
  536.             }
  537.             final String unbracketed = bracketed.substring(1, bracketed.length() - 1).trim();
  538.             try {
  539.                 consumer.accept(Stream.of(SPLIT_AT_COMMAS.split(unbracketed)).
  540.                                 map(s -> Unit.parse(s)).
  541.                                 collect(Collectors.toList()));
  542.             } catch (OrekitException oe) {
  543.                 // one unit is unknown
  544.                 throw generateException(oe);
  545.             }
  546.         }
  547.         return true;
  548.     }

  549.     /** Generate a parse exception for this entry.
  550.      * @param cause underlying cause exception (may be null)
  551.      * @return exception for this entry
  552.      */
  553.     public OrekitException generateException(final Exception cause) {
  554.         return new OrekitException(cause, OrekitMessages.UNABLE_TO_PARSE_ELEMENT_IN_FILE,
  555.                                    getName(), getLineNumber(), getFileName());
  556.     }

  557.     /** Get the body corresponding to a center name.
  558.      * @param centerName name of the center
  559.      * @param celestialBodies factory for celestial bodies
  560.      * @return celestial body corresponding to name, or null
  561.      */
  562.     private CelestialBody body(final String centerName, final CelestialBodies celestialBodies) {

  563.         // convert some known names
  564.         final String canonicalValue;
  565.         if (centerName.equals("SOLAR SYSTEM BARYCENTER") || centerName.equals("SSB")) {
  566.             canonicalValue = "SOLAR_SYSTEM_BARYCENTER";
  567.         } else if (centerName.equals("EARTH MOON BARYCENTER") || centerName.equals("EARTH-MOON BARYCENTER") ||
  568.                         centerName.equals("EARTH BARYCENTER") || centerName.equals("EMB")) {
  569.             canonicalValue = "EARTH_MOON";
  570.         } else {
  571.             canonicalValue = centerName;
  572.         }

  573.         try {
  574.             return CenterName.valueOf(canonicalValue).getCelestialBody(celestialBodies);
  575.         } catch (IllegalArgumentException iae) {
  576.             // ignored, we just let body set to null
  577.             return null;
  578.         }

  579.     }

  580.     /** Convert a value to an enum.
  581.      * @param cls enum class
  582.      * @param value value to convert to an enum
  583.      * @param <T> type of the enum
  584.      * @return enumerate corresponding to the value
  585.      */
  586.     private <T extends Enum<T>> T toEnum(final Class<T> cls, final String value) {
  587.         // first replace space characters
  588.         final String noSpace = value.replace(' ', '_');
  589.         try {
  590.             // first try without changing case, as some CCSDS enums are mixed case (like RangeUnits for TDM)
  591.             return Enum.valueOf(cls, noSpace);
  592.         } catch (IllegalArgumentException iae1) {
  593.             try {
  594.                 // second try, using more standard uppercase
  595.                 return Enum.valueOf(cls, noSpace.toUpperCase(Locale.US));
  596.             } catch (IllegalArgumentException iae2) {
  597.                 // use the first exception for the message
  598.                 throw generateException(iae1);
  599.             }
  600.         }
  601.     }

  602.     /** Interface representing instance methods that consume string values. */
  603.     public interface StringConsumer {
  604.         /** Consume a string.
  605.          * @param value value to consume
  606.          */
  607.         void accept(String value);
  608.     }

  609.     /** Interface representing instance methods that consume indexed string values. */
  610.     public interface IndexedStringConsumer {
  611.         /** Consume an indexed string.
  612.          * @param index index
  613.          * @param value value to consume
  614.          */
  615.         void accept(int index, String value);
  616.     }

  617.     /** Interface representing instance methods that consume lists of strings values. */
  618.     public interface StringListConsumer {
  619.         /** Consume a list of strings.
  620.          * @param value value to consume
  621.          */
  622.         void accept(List<String> value);
  623.     }

  624.     /** Interface representing instance methods that consume enum values.
  625.      * @param <T> type of the enum
  626.      */
  627.     public interface EnumConsumer<T extends Enum<T>> {
  628.         /** Consume an enum.
  629.          * @param value value to consume
  630.          */
  631.         void accept(T value);
  632.     }

  633.     /** Interface representing instance methods that consume lists of enum values.
  634.      * @param <T> type of the enum
  635.      */
  636.     public interface EnumListConsumer<T extends Enum<T>> {
  637.         /** Consume an enum.
  638.          * @param value value to consume
  639.          */
  640.         void accept(List<T> value);
  641.     }

  642.     /** Interface representing instance methods that consume boolean values. */
  643.     public interface BooleanConsumer {
  644.         /** Consume a boolean.
  645.          * @param value value to consume
  646.          */
  647.         void accept(boolean value);
  648.     }

  649.     /** Interface representing instance methods that consume integer values. */
  650.     public interface IntConsumer {
  651.         /** Consume an integer.
  652.          * @param value value to consume
  653.          */
  654.         void accept(int value);
  655.     }

  656.     /** Interface representing instance methods that consume integer array. */
  657.     public interface IntegerArrayConsumer {
  658.         /** Consume an array of integers.
  659.          * @param integers array of integers
  660.          */
  661.         void accept(int[] integers);
  662.     }

  663.     /** Interface representing instance methods that consume character values. */
  664.     public interface CharConsumer {
  665.         /** Consume a character.
  666.          * @param value value to consume
  667.          */
  668.         void accept(char value);
  669.     }

  670.     /** Interface representing instance methods that consume double values. */
  671.     public interface DoubleConsumer {
  672.         /** Consume a double.
  673.          * @param value value to consume
  674.          */
  675.         void accept(double value);
  676.     }

  677.     /** Interface representing instance methods that consume labeled double values. */
  678.     public interface LabeledDoubleConsumer {
  679.         /** Consume an indexed double.
  680.          * @param label label
  681.          * @param value value to consume
  682.          */
  683.         void accept(char label, double value);
  684.     }

  685.     /** Interface representing instance methods that consume indexed double values. */
  686.     public interface IndexedDoubleConsumer {
  687.         /** Consume an indexed double.
  688.          * @param i index
  689.          * @param value value to consume
  690.          */
  691.         void accept(int i, double value);
  692.     }

  693.     /** Interface representing instance methods that consume doubly-indexed double values. */
  694.     public interface DoublyIndexedDoubleConsumer {
  695.         /** Consume a doubly indexed double.
  696.          * @param i first index
  697.          * @param j second index
  698.          * @param value value to consume
  699.          */
  700.         void accept(int i, int j, double value);
  701.     }

  702.     /** Interface representing instance methods that consume vector values. */
  703.     public interface VectorConsumer {
  704.         /** Consume a vector.
  705.          * @param value value to consume
  706.          */
  707.         void accept(Vector3D value);
  708.     }

  709.     /** Interface representing instance methods that consume date values. */
  710.     public interface DateConsumer {
  711.         /** Consume a date.
  712.          * @param value value to consume
  713.          */
  714.         void accept(AbsoluteDate value);
  715.     }

  716.     /** Interface representing instance methods that consume time systems values. */
  717.     public interface TimeSystemConsumer {
  718.         /** Consume a time system.
  719.          * @param value value to consume
  720.          */
  721.         void accept(TimeSystem value);
  722.     }

  723.     /** Interface representing instance methods that consume frame values. */
  724.     public interface FrameConsumer {
  725.         /** Consume a frame.
  726.          * @param frameFacade facade in front of several frames types
  727.          */
  728.         void accept(FrameFacade frameFacade);
  729.     }

  730.     /** Interface representing instance methods that consume center values. */
  731.     public interface CenterConsumer {
  732.         /** Consume a body center.
  733.          * @param bodyFacade facade for celestial body name and body
  734.          */
  735.         void accept(BodyFacade bodyFacade);
  736.     }

  737.     /** Interface representing instance methods that consume center lists. */
  738.     public interface CenterListConsumer {
  739.         /** Consume a body center.
  740.          * @param bodyFacades facades for celestial bodies name and bodies
  741.          */
  742.         void accept(List<BodyFacade> bodyFacades);
  743.     }

  744.     /** Interface representing instance methods that consume units lists values. */
  745.     public interface UnitListConsumer {
  746.         /** Consume a list of units.
  747.          * @param value value to consume
  748.          */
  749.         void accept(List<Unit> value);
  750.     }

  751. }