ITRFVersionLoader.java

  1. /* Copyright 2002-2019 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.frames;

  18. import java.io.BufferedReader;
  19. import java.io.IOException;
  20. import java.io.InputStream;
  21. import java.io.InputStreamReader;
  22. import java.util.ArrayList;
  23. import java.util.List;
  24. import java.util.regex.Matcher;
  25. import java.util.regex.Pattern;

  26. import org.orekit.data.DataLoader;
  27. import org.orekit.data.DataProvidersManager;
  28. import org.orekit.errors.OrekitException;
  29. import org.orekit.errors.OrekitMessages;
  30. import org.orekit.time.DateComponents;

  31. /** Loader for ITRF version configuration file.
  32.  * <p>
  33.  * The ITRF version configuration file specifies
  34.  * the {@link ITRFVersion ITRF versions} that each
  35.  * type of Earth Orientation Parameter file contains
  36.  * for each date. This configuration file is used to
  37.  * interpret {@link EOPC04FilesLoader EOP C04} files,
  38.  * {@link BulletinAFilesLoader Bulletin A} files,
  39.  * {@link BulletinBFilesLoader Bulletin B} files,
  40.  * {@link RapidDataAndPredictionColumnsLoader rapid data
  41.  * and prediction files in columns format} files,
  42.  * {@link RapidDataAndPredictionXMLLoader rapid data
  43.  * and prediction files in XML format} files...
  44.  * </p>
  45.  * <p>This file is an Orekit-specific configuration file.
  46.  * </p>
  47.  * <p>
  48.  * This class is immutable and hence thread-safe
  49.  * </p>
  50.  * @see EOPC04FilesLoader
  51.  * @see BulletinAFilesLoader
  52.  * @see BulletinBFilesLoader
  53.  * @see RapidDataAndPredictionColumnsLoader
  54.  * @see RapidDataAndPredictionXMLLoader
  55.  * @author Luc Maisonobe
  56.  * @since 9.2
  57.  */
  58. class ITRFVersionLoader {

  59.     /** Regular expression for supported files names. */
  60.     public static final String SUPPORTED_NAMES = "itrf-versions.conf";

  61.     /** Regular expression matching anything. */
  62.     private static final String ANYTHING  = ".*";

  63.     /** Default entry to use if no suitable configuration is found. */
  64.     private static final ITRFVersionConfiguration DEFAULT =
  65.                     new ITRFVersionConfiguration(Pattern.compile(ANYTHING), ITRFVersion.ITRF_2014,
  66.                                                  Integer.MIN_VALUE, Integer.MAX_VALUE);

  67.     /** Configuration. */
  68.     private final List<ITRFVersionConfiguration> configurations;

  69.     /** Build a loader for ITRF version configuration file.
  70.      * @param supportedNames regular expression for supported files names
  71.      */
  72.     ITRFVersionLoader(final String supportedNames) {
  73.         this.configurations = new ArrayList<>();
  74.         DataProvidersManager.getInstance().feed(supportedNames, new Parser());
  75.     }

  76.     /** Get the ITRF version configuration defined by a given file at specified date.
  77.      * @param name EOP file name
  78.      * @param mjd date of the EOP in modified Julian day
  79.      * @return configuration valid around specified date in the file
  80.      */
  81.     public ITRFVersionConfiguration getConfiguration(final String name, final int mjd) {

  82.         for (final ITRFVersionConfiguration configuration : configurations) {
  83.             if (configuration.appliesTo(name) && configuration.isValid(mjd)) {
  84.                 // we have found a matching configuration
  85.                 return configuration;
  86.             }
  87.         }

  88.         // no suitable configuration found, use the default value
  89.         return DEFAULT;

  90.     }

  91.     /** Internal class performing the parsing. */
  92.     private class Parser implements DataLoader {

  93.         /** Regular expression matching start of line. */
  94.         private static final String START  = "^";

  95.         /** Regular expression matching a non-blank field (for names regexp). */
  96.         private static final String NON_BLANK_FIELD = "(\\S+)";

  97.         /** Regular expression matching a calendar date. */
  98.         private static final String CALENDAR_DATE  = "\\s+(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)";

  99.         /** Regular expression matching a date at infinity. */
  100.         private static final String INFINITY_DATE  = "\\s+-+";

  101.         /** Regular expression matching an ITRF version. */
  102.         private static final String ITRF  = "\\s+(ITRF-\\d\\d(?:\\d\\d)?)";

  103.         /** Regular expression matching end of line. */
  104.         private static final String END  = "$";

  105.         /** {@inheritDoc} */
  106.         public boolean stillAcceptsData() {
  107.             return configurations.isEmpty();
  108.         }

  109.         /** {@inheritDoc} */
  110.         public void loadData(final InputStream input, final String name)
  111.             throws IOException {

  112.             // regular expressions for date lines
  113.             final Pattern patternII = Pattern.compile(START + NON_BLANK_FIELD + INFINITY_DATE + INFINITY_DATE + ITRF + END);
  114.             final Pattern patternID = Pattern.compile(START + NON_BLANK_FIELD + INFINITY_DATE + CALENDAR_DATE + ITRF + END);
  115.             final Pattern patternDI = Pattern.compile(START + NON_BLANK_FIELD + CALENDAR_DATE + INFINITY_DATE + ITRF + END);
  116.             final Pattern patternDD = Pattern.compile(START + NON_BLANK_FIELD + CALENDAR_DATE + CALENDAR_DATE + ITRF + END);

  117.             // set up a reader for line-oriented bulletin A files
  118.             final BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
  119.             int lineNumber =  0;
  120.             String line = null;

  121.             try {
  122.                 for (line = reader.readLine(); line != null; line = reader.readLine()) {

  123.                     lineNumber++;
  124.                     line = line.trim();
  125.                     if (!(line.startsWith("#") || line.isEmpty())) {
  126.                         Pattern pattern     = null;
  127.                         ITRFVersion version = null;
  128.                         int validityStart   = Integer.MIN_VALUE;
  129.                         int validityEnd     = Integer.MAX_VALUE;
  130.                         final Matcher matcherII = patternII.matcher(line);
  131.                         if (matcherII.matches()) {
  132.                             // both start and end of validity are at infinity
  133.                             // the ITRF version applies throughout history
  134.                             pattern = Pattern.compile(ANYTHING + matcherII.group(1));
  135.                             version = ITRFVersion.getITRFVersion(matcherII.group(2));
  136.                         } else {
  137.                             final Matcher matcherID = patternID.matcher(line);
  138.                             if (matcherID.matches()) {
  139.                                 // both start of validity is at infinity
  140.                                 // the ITRF version applies in the far past
  141.                                 pattern     = Pattern.compile(ANYTHING + matcherID.group(1));
  142.                                 validityEnd = new DateComponents(Integer.parseInt(matcherID.group(2)),
  143.                                                                  Integer.parseInt(matcherID.group(3)),
  144.                                                                  Integer.parseInt(matcherID.group(4))).getMJD();
  145.                                 version     = ITRFVersion.getITRFVersion(matcherID.group(5));
  146.                             } else {
  147.                                 final Matcher matcherDI = patternDI.matcher(line);
  148.                                 if (matcherDI.matches()) {
  149.                                     // both end of validity is at infinity
  150.                                     // the ITRF version applies to the upcoming future
  151.                                     pattern       = Pattern.compile(ANYTHING + matcherDI.group(1));
  152.                                     validityStart = new DateComponents(Integer.parseInt(matcherDI.group(2)),
  153.                                                                        Integer.parseInt(matcherDI.group(3)),
  154.                                                                        Integer.parseInt(matcherDI.group(4))).getMJD();
  155.                                     version       = ITRFVersion.getITRFVersion(matcherDI.group(5));
  156.                                 } else {
  157.                                     final Matcher matcherDD = patternDD.matcher(line);
  158.                                     if (matcherDD.matches()) {
  159.                                         // the ITRF version applies during a limited range
  160.                                         pattern       = Pattern.compile(ANYTHING + matcherDD.group(1));
  161.                                         validityStart = new DateComponents(Integer.parseInt(matcherDD.group(2)),
  162.                                                                            Integer.parseInt(matcherDD.group(3)),
  163.                                                                            Integer.parseInt(matcherDD.group(4))).getMJD();
  164.                                         validityEnd   = new DateComponents(Integer.parseInt(matcherDD.group(5)),
  165.                                                                            Integer.parseInt(matcherDD.group(6)),
  166.                                                                            Integer.parseInt(matcherDD.group(7))).getMJD();
  167.                                         version       = ITRFVersion.getITRFVersion(matcherDD.group(8));
  168.                                     } else {
  169.                                         // data line was not recognized
  170.                                         throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
  171.                                                                   lineNumber, name, line);
  172.                                     }
  173.                                 }
  174.                             }
  175.                         }

  176.                         // store the parsed entry
  177.                         configurations.add(new ITRFVersionConfiguration(pattern, version, validityStart, validityEnd));

  178.                     }

  179.                 }
  180.             } catch (IllegalArgumentException e) {
  181.                 throw new OrekitException(e,
  182.                                           OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
  183.                                           lineNumber, name, line);
  184.             }

  185.         }

  186.     }

  187.     /** ITRF version configuration entry. */
  188.     public static class ITRFVersionConfiguration {

  189.         /** File names to which this configuration applies. */
  190.         private final Pattern pattern;

  191.         /** ITRF version. */
  192.         private final ITRFVersion version;

  193.         /** Start of validity. */
  194.         private final int validityStart;

  195.         /** End of validity. */
  196.         private final int validityEnd;

  197.         /** Simple constructor.
  198.          * @param pattern file names to which this configuration applies
  199.          * @param version ITRF version
  200.          * @param validityStart start of validity (included)
  201.          * @param validityEnd end of validity (excluded)
  202.          */
  203.         ITRFVersionConfiguration(final Pattern pattern,
  204.                                  final ITRFVersion version,
  205.                                  final int validityStart,
  206.                                  final int validityEnd) {
  207.             this.pattern       = pattern;
  208.             this.version       = version;
  209.             this.validityStart = validityStart;
  210.             this.validityEnd   = validityEnd;
  211.         }

  212.         /** Check if this entry applies to a file name.
  213.          * @param name file name to check
  214.          * @return true if the configuration applies to the specified file
  215.          */
  216.         boolean appliesTo(final String name) {
  217.             return pattern.matcher(name).matches();
  218.         }

  219.         /** Get ITRF version.
  220.          * @return ITRF version
  221.          */
  222.         public ITRFVersion getVersion() {
  223.             return version;
  224.         }

  225.         /** Check if configuration entry is valid for a date.
  226.          * @param mjd date to check in modified Julian day
  227.          * @return true if entry is valid for the specified date
  228.          */
  229.         public boolean isValid(final int mjd) {
  230.             return validityStart <= mjd && mjd < validityEnd;
  231.         }

  232.     }

  233. }