KeyValue.java

  1. /* Copyright 2002-2018 CS Systèmes d'Information
  2.  * Licensed to CS Systèmes d'Information (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;

  18. import java.util.Locale;
  19. import java.util.regex.Matcher;
  20. import java.util.regex.Pattern;

  21. import org.orekit.errors.OrekitException;
  22. import org.orekit.errors.OrekitMessages;

  23. /** Holder for key-value pair.
  24.  * <p>
  25.  * The syntax for key-value lines in CCSDS files is:
  26.  * </p>
  27.  * <pre>
  28.  * KEY = value [unit]
  29.  * </pre>
  30.  * <p>
  31.  * The "[unit]" part (with the square brackets included) is optional.
  32.  * The COMMENT keyword is an exception and does not have an '=' but directly
  33.  * the value as free form text. The META_START, META_STOP, COVARIANCE_START
  34.  * and COVARIANCE_STOP keywords are other exception and do not have anything
  35.  * else following them on the line.
  36.  * </p>
  37.  * @author Luc Maisonobe
  38.  * @since 6.1
  39.  */
  40. class KeyValue {

  41.     /** Regular expression for splitting lines. */
  42.     private final Pattern PATTERN =
  43.             Pattern.compile("\\p{Space}*([A-Z][A-Z_0-9]*)\\p{Space}*=?\\p{Space}*(.*?)\\p{Space}*(?:\\[.*\\])?\\p{Space}*");

  44.     /** Regular expression for user defined keywords. */
  45.     private final Pattern USER_DEFINED_KEYWORDS =
  46.             Pattern.compile("USER_DEFINED_[A-Z][A-Z_]*");

  47.     /** Line from which pair is extracted. */
  48.     private final String line;

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

  51.     /** Name of the file. */
  52.     private final String fileName;

  53.     /** Keyword enum corresponding to parsed key. */
  54.     private final Keyword keyword;

  55.     /** Key part of the pair. */
  56.     private final String key;

  57.     /** Value part of the line. */
  58.     private final String value;

  59.     /** Build a pair by splitting a key-value line.
  60.      * <p>
  61.      * The splitting is very basic and only extracts words using a regular
  62.      * expression ignoring the '=' sign and the optional unit. No attempt
  63.      * is made to recognize the special keywords. The key and value parts
  64.      * may be empty if not matched, and the keyword may be null.
  65.      * </p>
  66.      * <p> The value part may be upper case or lower case. This constructor
  67.      * converts all lower case values to upper case.
  68.      * @param line to split
  69.      * @param lineNumber number of the line in the CCSDS data message
  70.      * @param fileName name of the file
  71.      */
  72.     KeyValue(final String line, final int lineNumber, final String fileName) {

  73.         this.line       = line;
  74.         this.lineNumber = lineNumber;
  75.         this.fileName   = fileName;

  76.         final Matcher matcher = PATTERN.matcher(line);
  77.         if (matcher.matches()) {
  78.             key   = matcher.group(1);
  79.             final String rawValue = matcher.group(2);
  80.             Keyword recognized;
  81.             try {
  82.                 recognized = Keyword.valueOf(key);
  83.             } catch (IllegalArgumentException iae) {
  84.                 if (USER_DEFINED_KEYWORDS.matcher(key).matches()) {
  85.                     recognized = Keyword.USER_DEFINED_X;
  86.                 } else {
  87.                     recognized = null;
  88.                 }
  89.             }
  90.             keyword = recognized;
  91.             if (recognized == Keyword.COMMENT) {
  92.                 value = rawValue;
  93.             } else {
  94.                 value = rawValue.
  95.                         toUpperCase(Locale.US).
  96.                         replace('_', ' ').
  97.                         replaceAll("\\p{Space}+", " ");
  98.             }
  99.         } else {
  100.             key     = "";
  101.             value   = key;
  102.             keyword = null;
  103.         }
  104.     }

  105.     /** Build a pair by giving the input arguments.
  106.      *  This is essentially used while parsing XML files.
  107.      *  It is made to be allow the use of the class KeyValue for both Keyvalue and XML file formats.
  108.      *  Thus common functions can be used for the parsing.
  109.      * <p>
  110.      * The splitting is very basic and only extracts words using a regular
  111.      * expression ignoring the '=' sign and the optional unit. No attempt
  112.      * is made to recognize the special keywords. The key and value parts
  113.      * may be empty if not matched, and the keyword may be null.
  114.      * </p>
  115.      * <p> The value part may be upper case or lower case. This constructor
  116.      * converts all lower case values to upper case.
  117.      * @param keyword the keyword
  118.      * @param value the value attached to the keyword
  119.      * @param line the line where the keyword was found
  120.      * @param lineNumber number of the line in the CCSDS data message
  121.      * @param fileName name of the file
  122.      */
  123.     KeyValue(final Keyword keyword, final String value,
  124.              final String line, final int lineNumber,
  125.              final String fileName) {
  126.         this.keyword = keyword;
  127.         this.key = keyword.name();
  128.         this.value = value;
  129.         this.lineNumber = lineNumber;
  130.         this.line = line;
  131.         this.fileName = fileName;
  132.     }

  133.     /** Keyword corresponding to the parsed key.
  134.      * @return keyword corresponding to the parsed key
  135.      * (null if not recognized)
  136.      */
  137.     public Keyword getKeyword() {
  138.         return keyword;
  139.     }

  140.     /** Get the key.
  141.      * @return key
  142.      */
  143.     public String getKey() {
  144.         return key;
  145.     }

  146.     /** Get the value.
  147.      * @return value
  148.      */
  149.     public String getValue() {
  150.         return value;
  151.     }

  152.     /** Get the value as a double number.
  153.      * @return value
  154.      * @exception OrekitException if value is not a number
  155.      */
  156.     public double getDoubleValue() throws OrekitException {
  157.         try {
  158.             return Double.parseDouble(value);
  159.         } catch (NumberFormatException nfe) {
  160.             throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
  161.                                       lineNumber, fileName, line);
  162.         }
  163.     }

  164.     /** Get the value as an integer number.
  165.      * @return value
  166.      * @exception OrekitException if value is not a number
  167.      */
  168.     public int getIntegerValue() throws OrekitException {
  169.         try {
  170.             return Integer.parseInt(value);
  171.         } catch (NumberFormatException nfe) {
  172.             throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
  173.                                       lineNumber, fileName, line);
  174.         }
  175.     }

  176. }