ITRFVersionLoader.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.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.      * @exception OrekitException if configuration file cannot be loaded
  72.      */
  73.     ITRFVersionLoader(final String supportedNames) throws OrekitException {
  74.         this.configurations = new ArrayList<>();
  75.         DataProvidersManager.getInstance().feed(supportedNames, new Parser());
  76.     }

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

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

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

  91.     }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  179.                     }

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

  186.         }

  187.     }

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

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

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

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

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

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

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

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

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

  233.     }

  234. }