RuggedMessages.java

  1. /* Copyright 2013-2025 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.rugged.errors;

  18. import java.io.IOException;
  19. import java.io.InputStream;
  20. import java.io.InputStreamReader;
  21. import java.net.URL;
  22. import java.net.URLConnection;
  23. import java.nio.charset.StandardCharsets;
  24. import java.util.Locale;
  25. import java.util.MissingResourceException;
  26. import java.util.PropertyResourceBundle;
  27. import java.util.ResourceBundle;

  28. import org.hipparchus.exception.Localizable;


  29. /**
  30.  * Enumeration for localized messages formats.
  31.  * <p>
  32.  * The constants in this enumeration represent the available
  33.  * formats as localized strings. These formats are intended to be
  34.  * localized using simple properties files, using the constant
  35.  * name as the key and the property value as the message format.
  36.  * The source English format is provided in the constants themselves
  37.  * to serve both as a reminder for developers to understand the parameters
  38.  * needed by each format, as a basis for translators to create
  39.  * localized properties files, and as a default format if some
  40.  * translation is missing.
  41.  * </p>
  42.  * <p>
  43.  * This class is heavily based on {@code OrekitMessages},
  44.  * which is distributed under the terms of the Apache License V2.
  45.  * </p>
  46.  */
  47. public enum RuggedMessages implements Localizable {


  48.     /** INTERNAL_ERROR. */
  49.     INTERNAL_ERROR("internal error, please notify development team by creating an issue at {0}"),
  50.     /** OUT_OF_TILE_INDICES. */
  51.     OUT_OF_TILE_INDICES("no data at indices [{0}, {1}], tile only covers from [0, 0] to [{2}, {3}] (inclusive)"),
  52.     /** OUT_OF_TILE_ANGLES. */
  53.     OUT_OF_TILE_ANGLES("no data at latitude {0} and longitude {1}, tile covers only latitudes {2} to {3} and longitudes {4} to {5}"),
  54.     /** NO_DEM_DATA. */
  55.     NO_DEM_DATA("no Digital Elevation Model data at latitude {0} and longitude {1}"),
  56.     /** TILE_WITHOUT_REQUIRED_NEIGHBORS_SELECTED. */
  57.     TILE_WITHOUT_REQUIRED_NEIGHBORS_SELECTED("the tile selected for latitude {0} and longitude {1} does not contain required point neighborhood"),
  58.     /** OUT_OF_TIME_RANGE. */
  59.     OUT_OF_TIME_RANGE("date {0} is out of time span [{1}, {2}] (UTC)"),
  60.     /** UNINITIALIZED_CONTEXT. */
  61.     UNINITIALIZED_CONTEXT("general context has not been initialized (missing call to {0})"),
  62.     /** EMPTY_TILE. */
  63.     EMPTY_TILE("tile is empty: {0} ⨉ {1}"),
  64.     /** UNKNOWN_SENSOR. */
  65.     UNKNOWN_SENSOR("unknown sensor {0}"),
  66.     /** LINE_OF_SIGHT_DOES_NOT_REACH_GROUND. */
  67.     LINE_OF_SIGHT_DOES_NOT_REACH_GROUND("line-of-sight does not reach ground"),
  68.     /** LINE_OF_SIGHT_NEVER_CROSSES_LATITUDE. */
  69.     LINE_OF_SIGHT_NEVER_CROSSES_LATITUDE("line-of-sight never crosses latitude {0}"),
  70.     /** LINE_OF_SIGHT_NEVER_CROSSES_LONGITUDE. */
  71.     LINE_OF_SIGHT_NEVER_CROSSES_LONGITUDE("line-of-sight never crosses longitude {0}"),
  72.     /** LINE_OF_SIGHT_NEVER_CROSSES_ALTITUDE. */
  73.     LINE_OF_SIGHT_NEVER_CROSSES_ALTITUDE("line-of-sight never crosses altitude {0}"),
  74.     /** DEM_ENTRY_POINT_IS_BEHIND_SPACECRAFT. */
  75.     DEM_ENTRY_POINT_IS_BEHIND_SPACECRAFT("line-of-sight enters the Digital Elevation Model behind spacecraft!"),
  76.     /** FRAMES_MISMATCH_WITH_INTERPOLATOR_DUMP. */
  77.     FRAMES_MISMATCH_WITH_INTERPOLATOR_DUMP("frame {0} does not match frame {1} from interpolator dump"),
  78.     /** NOT_INTERPOLATOR_DUMP_DATA. */
  79.     NOT_INTERPOLATOR_DUMP_DATA("data is not an interpolator dump"),
  80.     /** DEBUG_DUMP_ALREADY_ACTIVE. */
  81.     DEBUG_DUMP_ALREADY_ACTIVE("debug dump is already active for this thread"),
  82.     /** DEBUG_DUMP_ACTIVATION_ERROR. */
  83.     DEBUG_DUMP_ACTIVATION_ERROR("unable to active debug dump with file {0}: {1}"),
  84.     /** DEBUG_DUMP_NOT_ACTIVE. */
  85.     DEBUG_DUMP_NOT_ACTIVE("debug dump is not active for this thread"),
  86.     /** CANNOT_PARSE_LINE. */
  87.     CANNOT_PARSE_LINE("cannot parse line {0}, file {1}: {2}"),
  88.     /** LIGHT_TIME_CORRECTION_REDEFINED. */
  89.     LIGHT_TIME_CORRECTION_REDEFINED("light time correction redefined, line {0}, file {1}: {2}"),
  90.     /** ABERRATION_OF_LIGHT_CORRECTION_REDEFINED. */
  91.     ABERRATION_OF_LIGHT_CORRECTION_REDEFINED("aberration of light correction redefined, line {0}, file {1}: {2}"),
  92.     /** ATMOSPHERIC_REFRACTION_REDEFINED. */
  93.     ATMOSPHERIC_REFRACTION_REDEFINED("atmospheric refraction correction redefined, line {0}, file {1}: {2}"),
  94.     /** TILE_ALREADY_DEFINED. */
  95.     TILE_ALREADY_DEFINED("tile {0} already defined, line {1}, file {2}: {3}"),
  96.     /** UNKNOWN_TILE. */
  97.     UNKNOWN_TILE("unknown tile {0}, line {1}, file {2}: {3}"),
  98.     /** NO_PARAMETERS_SELECTED. */
  99.     NO_PARAMETERS_SELECTED("no parameters have been selected for estimation"),
  100.     /** NO_REFERENCE_MAPPINGS. */
  101.     NO_REFERENCE_MAPPINGS("no reference mappings for parameters estimation"),
  102.     /** DUPLICATED_PARAMETER_NAME. */
  103.     DUPLICATED_PARAMETER_NAME("a different parameter with name {0} already exists"),
  104.     /** INVALID_RUGGED_NAME. */
  105.     INVALID_RUGGED_NAME("invalid rugged name"),
  106.     /** UNSUPPORTED_REFINING_CONTEXT. */
  107.     UNSUPPORTED_REFINING_CONTEXT("refining using {0} rugged instance is not handled"),
  108.     /** NO_LAYER_DATA. */
  109.     NO_LAYER_DATA("no atmospheric layer data at altitude {0} (lowest altitude: {1})"),
  110.     /** INVALID_STEP. */
  111.     INVALID_STEP("step {0} is not valid : {1}"),
  112.     /** INVALID_RANGE_FOR_LINES. */
  113.     INVALID_RANGE_FOR_LINES("range between min line {0} and max line {1} is invalid {2}"),
  114.     /** SENSOR_PIXEL_NOT_FOUND_IN_RANGE_LINES. */
  115.     SENSOR_PIXEL_NOT_FOUND_IN_RANGE_LINES("impossible to find sensor pixel in given range lines (with atmospheric refraction) between lines {0} and {1}"),
  116.     /** SENSOR_PIXEL_NOT_FOUND_IN_PIXELS_LINE. */
  117.     SENSOR_PIXEL_NOT_FOUND_IN_PIXELS_LINE("impossible to find sensor pixel: pixel {0} outside interval [ {1} , {2} [ (with atmospheric refraction margin = {3})");

  118.     /** Base name of the resource bundle in classpath. */
  119.     private static final String RESOURCE_BASE_NAME = "assets/org/orekit/rugged/RuggedMessages";

  120.     /** Source English format. */
  121.     private final String sourceFormat;

  122.     /** Simple constructor.
  123.      * @param sourceFormat source English format to use when no
  124.      * localized version is available
  125.      */
  126.     RuggedMessages(final String sourceFormat) {
  127.         this.sourceFormat = sourceFormat;
  128.     }

  129.     /** {@inheritDoc} */
  130.     @Override
  131.     public String getSourceString() {
  132.         return sourceFormat;
  133.     }

  134.     /** {@inheritDoc} */
  135.     @Override
  136.     public String getLocalizedString(final Locale locale) {
  137.         try {
  138.             final ResourceBundle bundle =
  139.                     ResourceBundle.getBundle(RESOURCE_BASE_NAME, locale, new UTF8Control());
  140.             if (bundle.getLocale().getLanguage().equals(locale.getLanguage())) {
  141.                 final String translated = bundle.getString(name());
  142.                 if (translated.length() > 0 &&
  143.                     !translated.toLowerCase(locale).contains("missing translation")) {
  144.                     // the value of the resource is the translated format
  145.                     return translated;
  146.                 }
  147.             }

  148.         } catch (MissingResourceException mre) {
  149.             // do nothing here
  150.         }

  151.         // either the locale is not supported or the resource is not translated or
  152.         // it is unknown: don't translate and fall back to using the source format
  153.         return sourceFormat;

  154.     }

  155.     /** Control class loading properties in UTF-8 encoding.
  156.      * <p>
  157.      * This class has been very slightly adapted from BalusC answer to question: <a
  158.      * href="http://stackoverflow.com/questions/4659929/how-to-use-utf-8-in-resource-properties-with-resourcebundle">
  159.      * How to use UTF-8 in resource properties with ResourceBundle</a>.
  160.      * </p>
  161.      */
  162.     public static class UTF8Control extends ResourceBundle.Control {

  163.         /** {@inheritDoc} */
  164.         @Override
  165.         public ResourceBundle newBundle(final String baseName, final Locale locale, final String format,
  166.                                         final ClassLoader loader, final boolean reload) throws IOException {
  167.             // The below is a copy of the default implementation.
  168.             final String bundleName = toBundleName(baseName, locale);
  169.             final String resourceName = toResourceName(bundleName, "utf8");
  170.             ResourceBundle bundle = null;
  171.             InputStream stream = null;
  172.             if (reload) {
  173.                 final URL url = loader.getResource(resourceName);
  174.                 if (url != null) {
  175.                     final URLConnection connection = url.openConnection();
  176.                     if (connection != null) {
  177.                         connection.setUseCaches(false);
  178.                         stream = connection.getInputStream();
  179.                     }
  180.                 }
  181.             } else {
  182.                 stream = loader.getResourceAsStream(resourceName);
  183.             }
  184.             if (stream != null) {
  185.                 try (InputStreamReader inputStreamReader = new InputStreamReader(stream, StandardCharsets.UTF_8)) {
  186.                     // Only this line is changed to make it to read properties files as UTF-8.
  187.                     bundle = new PropertyResourceBundle(inputStreamReader);
  188.                 }
  189.             }
  190.             return bundle;
  191.         }

  192.     }

  193. }