1   /* Copyright 2013-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.rugged.errors;
18  
19  import java.io.IOException;
20  import java.io.InputStream;
21  import java.io.InputStreamReader;
22  import java.net.URL;
23  import java.net.URLConnection;
24  import java.util.Locale;
25  import java.util.MissingResourceException;
26  import java.util.PropertyResourceBundle;
27  import java.util.ResourceBundle;
28  
29  import org.hipparchus.exception.Localizable;
30  
31  
32  /**
33   * Enumeration for localized messages formats.
34   * <p>
35   * The constants in this enumeration represent the available
36   * formats as localized strings. These formats are intended to be
37   * localized using simple properties files, using the constant
38   * name as the key and the property value as the message format.
39   * The source English format is provided in the constants themselves
40   * to serve both as a reminder for developers to understand the parameters
41   * needed by each format, as a basis for translators to create
42   * localized properties files, and as a default format if some
43   * translation is missing.
44   * </p>
45   * <p>
46   * This class is heavily based on {@code OrekitMessages},
47   * which is distributed under the terms of the Apache License V2.
48   * </p>
49   */
50  public enum RuggedMessages implements Localizable {
51  
52      // CHECKSTYLE: stop JavadocVariable check
53  
54      INTERNAL_ERROR("internal error, please notify development team by creating an issue at {0}"),
55      OUT_OF_TILE_INDICES("no data at indices [{0}, {1}], tile only covers from [0, 0] to [{2}, {3}] (inclusive)"),
56      OUT_OF_TILE_ANGLES("no data at latitude {0} and longitude {1}, tile covers only latitudes {2} to {3} and longitudes {4} to {5}"),
57      NO_DEM_DATA("no Digital Elevation Model data at latitude {0} and longitude {1}"),
58      TILE_WITHOUT_REQUIRED_NEIGHBORS_SELECTED("the tile selected for latitude {0} and longitude {1} does not contain required point neighborhood"),
59      OUT_OF_TIME_RANGE("date {0} is out of time span [{1}, {2}] (UTC)"),
60      UNINITIALIZED_CONTEXT("general context has not been initialized (missing call to {0})"),
61      EMPTY_TILE("tile is empty: {0} ⨉ {1}"),
62      UNKNOWN_SENSOR("unknown sensor {0}"),
63      LINE_OF_SIGHT_DOES_NOT_REACH_GROUND("line-of-sight does not reach ground"),
64      LINE_OF_SIGHT_NEVER_CROSSES_LATITUDE("line-of-sight never crosses latitude {0}"),
65      LINE_OF_SIGHT_NEVER_CROSSES_LONGITUDE("line-of-sight never crosses longitude {0}"),
66      LINE_OF_SIGHT_NEVER_CROSSES_ALTITUDE("line-of-sight never crosses altitude {0}"),
67      DEM_ENTRY_POINT_IS_BEHIND_SPACECRAFT("line-of-sight enters the Digital Elevation Model behind spacecraft!"),
68      FRAMES_MISMATCH_WITH_INTERPOLATOR_DUMP("frame {0} does not match frame {1} from interpolator dump"),
69      NOT_INTERPOLATOR_DUMP_DATA("data is not an interpolator dump"),
70      DEBUG_DUMP_ALREADY_ACTIVE("debug dump is already active for this thread"),
71      DEBUG_DUMP_ACTIVATION_ERROR("unable to active debug dump with file {0}: {1}"),
72      DEBUG_DUMP_NOT_ACTIVE("debug dump is not active for this thread"),
73      CANNOT_PARSE_LINE("cannot parse line {0}, file {1}: {2}"),
74      LIGHT_TIME_CORRECTION_REDEFINED("light time correction redefined, line {0}, file {1}: {2}"),
75      ABERRATION_OF_LIGHT_CORRECTION_REDEFINED("aberration of light correction redefined, line {0}, file {1}: {2}"),
76      ATMOSPHERIC_REFRACTION_REDEFINED("atmospheric refraction correction redefined, line {0}, file {1}: {2}"),
77      TILE_ALREADY_DEFINED("tile {0} already defined, line {1}, file {2}: {3}"),
78      UNKNOWN_TILE("unknown tile {0}, line {1}, file {2}: {3}"),
79      NO_PARAMETERS_SELECTED("no parameters have been selected for estimation"),
80      NO_REFERENCE_MAPPINGS("no reference mappings for parameters estimation"),
81      DUPLICATED_PARAMETER_NAME("a different parameter with name {0} already exists"),
82      INVALID_RUGGED_NAME("invalid rugged name"),
83      UNSUPPORTED_REFINING_CONTEXT("refining using {0} rugged instance is not handled"),
84      NO_LAYER_DATA("no atmospheric layer data at altitude {0} (lowest altitude: {1})"),
85      INVALID_STEP("step {0} is not valid : {1}"),
86      INVALID_RANGE_FOR_LINES("range between min line {0} and max line {1} is invalid {2}");
87  
88      // CHECKSTYLE: resume JavadocVariable check
89  
90      /** Base name of the resource bundle in classpath. */
91      private static final String RESOURCE_BASE_NAME = "assets/org/orekit/rugged/RuggedMessages";
92  
93      /** Source English format. */
94      private final String sourceFormat;
95  
96      /** Simple constructor.
97       * @param sourceFormat source English format to use when no
98       * localized version is available
99       */
100     RuggedMessages(final String sourceFormat) {
101         this.sourceFormat = sourceFormat;
102     }
103 
104     /** {@inheritDoc} */
105     @Override
106     public String getSourceString() {
107         return sourceFormat;
108     }
109 
110     /** {@inheritDoc} */
111     @Override
112     public String getLocalizedString(final Locale locale) {
113         try {
114             final ResourceBundle bundle =
115                     ResourceBundle.getBundle(RESOURCE_BASE_NAME, locale, new UTF8Control());
116             if (bundle.getLocale().getLanguage().equals(locale.getLanguage())) {
117                 final String translated = bundle.getString(name());
118                 if ((translated != null) &&
119                     (translated.length() > 0) &&
120                     (!translated.toLowerCase(locale).contains("missing translation"))) {
121                     // the value of the resource is the translated format
122                     return translated;
123                 }
124             }
125 
126         } catch (MissingResourceException mre) {
127             // do nothing here
128         }
129 
130         // either the locale is not supported or the resource is not translated or
131         // it is unknown: don't translate and fall back to using the source format
132         return sourceFormat;
133 
134     }
135 
136     /** Control class loading properties in UTF-8 encoding.
137      * <p>
138      * This class has been very slightly adapted from BalusC answer to question: <a
139      * href="http://stackoverflow.com/questions/4659929/how-to-use-utf-8-in-resource-properties-with-resourcebundle">
140      * How to use UTF-8 in resource properties with ResourceBundle</a>.
141      * </p>
142      */
143     public static class UTF8Control extends ResourceBundle.Control {
144 
145         /** {@inheritDoc} */
146         @Override
147         public ResourceBundle newBundle(final String baseName, final Locale locale, final String format,
148                                         final ClassLoader loader, final boolean reload) throws IOException {
149             // The below is a copy of the default implementation.
150             final String bundleName = toBundleName(baseName, locale);
151             final String resourceName = toResourceName(bundleName, "utf8");
152             ResourceBundle bundle = null;
153             InputStream stream = null;
154             if (reload) {
155                 final URL url = loader.getResource(resourceName);
156                 if (url != null) {
157                     final URLConnection connection = url.openConnection();
158                     if (connection != null) {
159                         connection.setUseCaches(false);
160                         stream = connection.getInputStream();
161                     }
162                 }
163             } else {
164                 stream = loader.getResourceAsStream(resourceName);
165             }
166             if (stream != null) {
167                 try {
168                     // Only this line is changed to make it to read properties files as UTF-8.
169                     bundle = new PropertyResourceBundle(new InputStreamReader(stream, "UTF-8"));
170                 } finally {
171                     stream.close();
172                 }
173             }
174             return bundle;
175         }
176 
177     }
178 
179 }