1 /* Copyright 2002-2023 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.errors; 18 19 import java.text.MessageFormat; 20 import java.util.Locale; 21 22 import org.hipparchus.exception.Localizable; 23 import org.hipparchus.exception.MathRuntimeException; 24 25 /** This class is the base class for all specific exceptions thrown by 26 * the Orekit classes. 27 28 * <p>When the Orekit classes throw exceptions that are specific to 29 * the package, these exceptions are always subclasses of 30 * OrekitException. When exceptions that are already covered by the 31 * standard java API should be thrown, like 32 * ArrayIndexOutOfBoundsException or InvalidParameterException, these 33 * standard exceptions are thrown rather than the Hipparchus specific 34 * ones.</p> 35 * <p>This class also provides utility methods to throw some standard 36 * java exceptions with localized messages.</p> 37 * 38 * @author Luc Maisonobe 39 40 */ 41 42 public class OrekitException extends RuntimeException implements LocalizedException { 43 44 /** Serializable UID. */ 45 private static final long serialVersionUID = 20150611L; 46 47 /** Format specifier (to be translated). */ 48 private final Localizable specifier; 49 50 /** Parts to insert in the format (no translation). */ 51 private final Object[] parts; 52 53 /** Simple constructor. 54 * Build an exception with a translated and formatted message 55 * @param specifier format specifier (to be translated) 56 * @param parts parts to insert in the format (no translation) 57 */ 58 public OrekitException(final Localizable specifier, final Object... parts) { 59 this.specifier = specifier; 60 this.parts = (parts == null) ? new Object[0] : parts.clone(); 61 } 62 63 /** Copy constructor. 64 * @param exception exception to copy from 65 * @since 5.1 66 */ 67 public OrekitException(final OrekitException exception) { 68 super(exception); 69 this.specifier = exception.specifier; 70 this.parts = exception.parts.clone(); 71 } 72 73 /** Simple constructor. 74 * Build an exception from a cause and with a specified message 75 * @param message descriptive message 76 * @param cause underlying cause 77 */ 78 public OrekitException(final Localizable message, final Throwable cause) { 79 super(cause); 80 this.specifier = message; 81 this.parts = new Object[0]; 82 } 83 84 /** Simple constructor. 85 * Build an exception from a cause and with a translated and formatted message 86 * @param cause underlying cause 87 * @param specifier format specifier (to be translated) 88 * @param parts parts to insert in the format (no translation) 89 */ 90 public OrekitException(final Throwable cause, final Localizable specifier, 91 final Object... parts) { 92 super(cause); 93 this.specifier = specifier; 94 this.parts = (parts == null) ? new Object[0] : parts.clone(); 95 } 96 97 /** Simple constructor. 98 * Build an exception from an Hipparchus exception 99 * @param exception underlying Hipparchus exception 100 * @since 6.0 101 */ 102 public OrekitException(final MathRuntimeException exception) { 103 super(exception); 104 this.specifier = exception.getSpecifier(); 105 this.parts = exception.getParts(); 106 } 107 108 /** {@inheritDoc} */ 109 @Override 110 public String getMessage(final Locale locale) { 111 return buildMessage(locale); 112 } 113 114 /** {@inheritDoc} */ 115 @Override 116 public String getMessage() { 117 return getMessage(Locale.US); 118 } 119 120 /** {@inheritDoc} */ 121 @Override 122 public String getLocalizedMessage() { 123 return getMessage(Locale.getDefault()); 124 } 125 126 /** {@inheritDoc} */ 127 @Override 128 public Localizable getSpecifier() { 129 return specifier; 130 } 131 132 /** {@inheritDoc} */ 133 @Override 134 public Object[] getParts() { 135 return parts.clone(); 136 } 137 138 /** Recover a OrekitException, possibly embedded in a {@link MathRuntimeException}. 139 * <p> 140 * If the {@code MathRuntimeException} does not embed a OrekitException, a 141 * new one will be created. 142 * </p> 143 * @param exception MathRuntimeException to analyze 144 * @return a (possibly embedded) OrekitException 145 */ 146 public static OrekitException unwrap(final MathRuntimeException exception) { 147 148 for (Throwable t = exception; t != null; t = t.getCause()) { 149 if (t instanceof OrekitException) { 150 return (OrekitException) t; 151 } 152 } 153 154 return new OrekitException(exception); 155 156 } 157 158 /** 159 * Builds a message string by from a pattern and its arguments. 160 * @param locale Locale in which the message should be translated 161 * @return a message string 162 */ 163 private String buildMessage(final Locale locale) { 164 if (specifier == null) { 165 return ""; 166 } else { 167 try { 168 final String localizedString = specifier.getLocalizedString(locale); 169 if (localizedString == null) { 170 return ""; 171 } else { 172 return new MessageFormat(localizedString, locale).format(parts); 173 } 174 //CHECKSTYLE: stop IllegalCatch check 175 } catch (Throwable t) { 176 //CHECKSTYLE: resume IllegalCatch check 177 // Message formatting or localization failed 178 // Catch all exceptions to prevent the stack trace from being lost 179 // Add the exception as suppressed so the user can fix that bug too 180 this.addSuppressed(t); 181 // just use the source string as the message 182 return specifier.getSourceString(); 183 } 184 } 185 } 186 187 }