1   /* Copyright 2002-2013 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.errors;
18  
19  import java.text.MessageFormat;
20  import java.text.ParseException;
21  import java.util.Locale;
22  
23  import org.apache.commons.math3.exception.util.ExceptionContext;
24  import org.apache.commons.math3.exception.util.ExceptionContextProvider;
25  import org.apache.commons.math3.exception.util.Localizable;
26  
27  /** This class is the base class for all specific exceptions thrown by
28   * the orekit classes.
29  
30   * <p>When the orekit classes throw exceptions that are specific to
31   * the package, these exceptions are always subclasses of
32   * OrekitException. When exceptions that are already covered by the
33   * standard java API should be thrown, like
34   * ArrayIndexOutOfBoundsException or InvalidParameterException, these
35   * standard exceptions are thrown rather than the commons-math specific
36   * ones.</p>
37   * <p>This class also provides utility methods to throw some standard
38   * java exceptions with localized messages.</p>
39   *
40   * @author Luc Maisonobe
41  
42   */
43  
44  public class OrekitException extends Exception {
45  
46      /** Serializable UID. */
47      private static final long serialVersionUID = 3366757982695469677L;
48  
49      /** Exception context (may be null). */
50      private final ExceptionContext context;
51  
52      /** Format specifier (to be translated). */
53      private final Localizable specifier;
54  
55      /** Parts to insert in the format (no translation). */
56      private final Object[] parts;
57  
58      /** Simple constructor.
59       * Build an exception with a translated and formatted message
60       * @param specifier format specifier (to be translated)
61       * @param parts parts to insert in the format (no translation)
62       */
63      public OrekitException(final Localizable specifier, final Object ... parts) {
64          this.context   = null;
65          this.specifier = specifier;
66          this.parts     = (parts == null) ? new Object[0] : parts.clone();
67      }
68  
69      /** Copy constructor.
70       * @param exception exception to copy from
71       * @since 5.1
72       */
73      public OrekitException(final OrekitException exception) {
74          super(exception);
75          this.context   = exception.context;
76          this.specifier = exception.specifier;
77          this.parts     = exception.parts.clone();
78      }
79  
80      /** Simple constructor.
81       * Build an exception from a cause and with a specified message
82       * @param message descriptive message
83       * @param cause underlying cause
84       */
85      public OrekitException(final Localizable message, final Throwable cause) {
86          super(cause);
87          this.context   = null;
88          this.specifier = message;
89          this.parts     = new Object[0];
90      }
91  
92      /** Simple constructor.
93       * Build an exception from a cause and with a translated and formatted message
94       * @param cause underlying cause
95       * @param specifier format specifier (to be translated)
96       * @param parts parts to insert in the format (no translation)
97       */
98      public OrekitException(final Throwable cause, final Localizable specifier,
99                             final Object ... parts) {
100         super(cause);
101         this.context   = null;
102         this.specifier = specifier;
103         this.parts     = (parts == null) ? new Object[0] : parts.clone();
104     }
105 
106     /** Simple constructor.
107      * Build an exception from an Apache Commons Math exception context context
108      * @param provider underlying exception context provider
109      * @since 6.0
110      */
111     public OrekitException(final ExceptionContextProvider provider) {
112         super(provider.getContext().getThrowable());
113         this.context   = provider.getContext();
114         this.specifier = null;
115         this.parts     = new Object[0];
116     }
117 
118     /** Gets the message in a specified locale.
119      * @param locale Locale in which the message should be translated
120      * @return localized message
121      * @since 5.0
122      */
123     public String getMessage(final Locale locale) {
124         return (context != null) ?
125                 context.getMessage(locale) :
126                 buildMessage(locale, specifier, parts);
127     }
128 
129     /** {@inheritDoc} */
130     @Override
131     public String getMessage() {
132         return getMessage(Locale.US);
133     }
134 
135     /** {@inheritDoc} */
136     @Override
137     public String getLocalizedMessage() {
138         return getMessage(Locale.getDefault());
139     }
140 
141     /** Get the localizable specifier of the error message.
142      * @return localizable specifier of the error message
143      * @since 5.1
144      */
145     public Localizable getSpecifier() {
146         return specifier;
147     }
148 
149     /** Get the variable parts of the error message.
150      * @return a copy of the variable parts of the error message
151      * @since 5.1
152      */
153     public Object[] getParts() {
154         return parts.clone();
155     }
156 
157     /**
158      * Builds a message string by from a pattern and its arguments.
159      * @param locale Locale in which the message should be translated
160      * @param specifier format specifier (to be translated)
161      * @param parts parts to insert in the format (no translation)
162      * @return a message string
163      */
164     private static String buildMessage(final Locale locale, final Localizable specifier,
165                                        final Object ... parts) {
166         return (specifier == null) ? "" : new MessageFormat(specifier.getLocalizedString(locale), locale).format(parts);
167     }
168 
169     /** Create an {@link java.lang.IllegalArgumentException} with localized message.
170      * @param specifier format specifier (to be translated)
171      * @param parts parts to insert in the format (no translation)
172      * @return an {@link java.lang.IllegalArgumentException} with localized message
173      */
174     public static IllegalArgumentException createIllegalArgumentException(final Localizable specifier,
175                                                                           final Object ... parts) {
176         return new IllegalArgumentException() {
177 
178             /** Serializable UID. */
179             private static final long serialVersionUID = 2601215225271704045L;
180 
181             /** {@inheritDoc} */
182             @Override
183             public String getMessage() {
184                 return buildMessage(Locale.US, specifier, parts);
185             }
186 
187             /** {@inheritDoc} */
188             @Override
189             public String getLocalizedMessage() {
190                 return buildMessage(Locale.getDefault(), specifier, parts);
191             }
192 
193         };
194 
195     }
196 
197     /** Create an {@link java.lang.IllegalStateException} with localized message.
198      * @param specifier format specifier (to be translated)
199      * @param parts parts to insert in the format (no translation)
200      * @return an {@link java.lang.IllegalStateException} with localized message
201      */
202     public static IllegalStateException createIllegalStateException(final Localizable specifier,
203                                                                     final Object ... parts) {
204 
205         return new IllegalStateException() {
206 
207             /** Serializable UID. */
208             private static final long serialVersionUID = -5527779242879685212L;
209 
210             /** {@inheritDoc} */
211             @Override
212             public String getMessage() {
213                 return buildMessage(Locale.US, specifier, parts);
214             }
215 
216             /** {@inheritDoc} */
217             @Override
218             public String getLocalizedMessage() {
219                 return buildMessage(Locale.getDefault(), specifier, parts);
220             }
221 
222         };
223 
224     }
225 
226     /** Create an {@link java.text.ParseException} with localized message.
227      * @param specifier format specifier (to be translated)
228      * @param parts parts to insert in the format (no translation)
229      * @return an {@link java.text.ParseException} with localized message
230      */
231     public static ParseException createParseException(final Localizable specifier,
232                                                       final Object ... parts) {
233 
234         return new ParseException("", 0) {
235 
236             /** Serializable UID. */
237             private static final long serialVersionUID = 4771367217940584391L;
238 
239             /** {@inheritDoc} */
240             @Override
241             public String getMessage() {
242                 return buildMessage(Locale.US, specifier, parts);
243             }
244 
245             /** {@inheritDoc} */
246             @Override
247             public String getLocalizedMessage() {
248                 return buildMessage(Locale.getDefault(), specifier, parts);
249             }
250 
251         };
252 
253     }
254 
255     /** Create an {@link java.lang.RuntimeException} for an internal error.
256      * @param cause underlying cause
257      * @return an {@link java.lang.RuntimeException} for an internal error
258      */
259     public static RuntimeException createInternalError(final Throwable cause) {
260 
261         /** Format specifier (to be translated). */
262         final Localizable specifier = OrekitMessages.INTERNAL_ERROR;
263 
264         /** Parts to insert in the format (no translation). */
265         final String parts     = "orekit@c-s.fr";
266 
267         return new RuntimeException() {
268 
269             /** Serializable UID. */
270             private static final long serialVersionUID = -6493358459835909138L;
271 
272             /** {@inheritDoc} */
273             @Override
274             public String getMessage() {
275                 return buildMessage(Locale.US, specifier, parts);
276             }
277 
278             /** {@inheritDoc} */
279             @Override
280             public String getLocalizedMessage() {
281                 return buildMessage(Locale.getDefault(), specifier, parts);
282             }
283 
284         };
285 
286     }
287 
288 }