001/* 002 * ============================================================================ 003 * Copyright © 2002-2021 by Thomas Thrien. 004 * All Rights Reserved. 005 * ============================================================================ 006 * Licensed to the public under the agreements of the GNU Lesser General Public 007 * License, version 3.0 (the "License"). You may obtain a copy of the License at 008 * 009 * http://www.gnu.org/licenses/lgpl.html 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 014 * License for the specific language governing permissions and limitations 015 * under the License. 016 */ 017 018package org.tquadrat.foundation.config; 019 020import static java.lang.String.format; 021import static org.apiguardian.api.API.Status.STABLE; 022import static org.tquadrat.foundation.lang.CommonConstants.PROPERTY_IS_DEBUG; 023import static org.tquadrat.foundation.lang.Objects.nonNull; 024import static org.tquadrat.foundation.lang.Objects.requireNonNullArgument; 025 026import java.io.Serial; 027import java.util.Optional; 028 029import org.apiguardian.api.API; 030import org.tquadrat.foundation.annotation.ClassVersion; 031import org.tquadrat.foundation.config.internal.Commons; 032import org.tquadrat.foundation.config.spi.CLIDefinition; 033import org.tquadrat.foundation.exception.ValidationException; 034import org.tquadrat.foundation.i18n.Message; 035import org.tquadrat.foundation.i18n.Translation; 036import org.tquadrat.foundation.util.stringconverter.FileStringConverter; 037 038/** 039 * <p>{@summary Signals an error in the user input.}</p> 040 * <p>The message keys corresponds to the current default message by the 041 * suffix: the default message for 042 * {@link #MSGKEY_Aborted} 043 * is 044 * {@link #MSG_Aborted} 045 * and so on.</p> 046 * 047 * @extauthor Thomas Thrien - thomas.thrien@tquadrat.org 048 * @thanks Kohsuke Kawaguchi - kk@kohsuke.org 049 * @version $Id: CmdLineException.java 1078 2023-10-19 14:39:47Z tquadrat $ 050 * @since 0.0.1 051 * 052 * @UMLGraph.link 053 */ 054@SuppressWarnings( "ClassWithTooManyConstructors" ) 055@ClassVersion( sourceVersion = "$Id: CmdLineException.java 1078 2023-10-19 14:39:47Z tquadrat $" ) 056@API( status = STABLE, since = "0.0.1" ) 057public final class CmdLineException extends ValidationException 058{ 059 /*-----------*\ 060 ====** Constants **======================================================== 061 \*-----------*/ 062 /** 063 * The default error message: {@value}. 064 */ 065 public static final String MSG_Aborted = "The command line parsing was aborted due to an exception: %1$s"; 066 067 /** 068 * The error message for an argument that is missing on the command line: 069 * {@value}. 070 */ 071 public static final String MSG_ArgumentMissing = "The mandatory argument '%1$s' is missing on the command line"; 072 073 /** 074 * The error message for an illegal option argument: {@value}. 075 */ 076 public static final String MSG_IllegalOperand = "'%2$s' is not a valid value for '%1$s'"; 077 078 /** 079 * The error message for an invalid file name on the command line: 080 * {@value}. 081 */ 082 public static final String MSG_InvalidFileName = FileStringConverter.MSG_InvalidFileName; 083 084 /** 085 * The error message for an invalid format: {@value}. 086 */ 087 public static final String MSG_InvalidFormat = "The date format pattern '%1$s' is not valid"; 088 089 /** 090 * The error message for a missing option argument: {@value}. 091 */ 092 public static final String MSG_MissingOperand = "Option '%1$s' requires an argument"; 093 094 /** 095 * The error message for an argument where none is allowed: {@value}. 096 */ 097 public static final String MSG_NoArgumentAllowed = "No arguments allowed: %1$s"; 098 099 /** 100 * The error message for an invalid option: {@value}. 101 */ 102 public static final String MSG_OptionInvalid = "The option '%1$s' is invalid"; 103 104 /** 105 * The error message for a mandatory option that is missing on the command 106 * line: {@value}. 107 */ 108 public static final String MSG_OptionMissing = "The mandatory option '%1$s' is missing on the command line"; 109 110 /** 111 * The message for an unspecified failure of the command line parsing: 112 * {@value}. 113 */ 114 public static final String MSG_ParseFailed = "Parsing the command line failed"; 115 116 /** 117 * The error message for too many arguments on the command line: {@value}. 118 */ 119 public static final String MSG_TooManyArguments = "Too many arguments provided: %1$s"; 120 121 /** 122 * The message key for the default error message. 123 * 124 * @see #MSG_Aborted 125 */ 126 @Message 127 ( 128 description = "The default error message", 129 translations = 130 { 131 @Translation( language = "en", text = MSG_Aborted ), 132 @Translation( language = "de", text = "Die Auswertung der Kommandozeile wurde mit einer Exception abgebrochen: %1$s" ) 133 } 134 ) 135 public static final int MSGKEY_Aborted = 3; 136 137 /** 138 * The message key for the error message about an argument that is missing 139 * on the command line. 140 * 141 * @see #MSG_ArgumentMissing 142 */ 143 @SuppressWarnings( "StaticMethodOnlyUsedInOneClass" ) 144 @Message 145 ( 146 description = "The error message about an argument that is missing on the command line.", 147 translations = 148 { 149 @Translation( language = "en", text = MSG_ArgumentMissing ), 150 @Translation( language = "de", text = "Das notwendige Argument '%1$s' fehlt auf der Kommandozeile" ) 151 } 152 ) 153 public static final int MSGKEY_ArgumentMissing = 4; 154 155 /** 156 * The message key for an error message about an illegal operand. 157 * 158 * @see #MSG_IllegalOperand 159 */ 160 @SuppressWarnings( "StaticMethodOnlyUsedInOneClass" ) 161 @Message 162 ( 163 description = "The error message about an illegal operand.", 164 translations = 165 { 166 @Translation( language = "en", text = MSG_IllegalOperand ), 167 @Translation( language = "de", text = "'%2$s' ist kein gültiger Wert für '%1$s'" ) 168 } 169 ) 170 public static final int MSGKEY_IllegalOperand = 5; 171 172 /** 173 * The resource bundle key for the message about an invalid file name 174 * String on the command line. 175 */ 176 @Message 177 ( 178 description = "The error message for an invalid file name on the command line.", 179 translations = 180 { 181 @Translation( language = "en", text = FileStringConverter.MSG_InvalidFileName ), 182 @Translation( language = "de", text = "'%2$s' ist kein gültiger Wert für '%1$s'" ) 183 } 184 ) 185 public static final int MSGKEY_InvalidFileName = 6; 186 187 /** 188 * The message key for an error message about an invalid format. 189 * 190 * @see #MSG_InvalidFormat 191 */ 192 @SuppressWarnings( "StaticMethodOnlyUsedInOneClass" ) 193 @Message 194 ( 195 description = "The error message about an invalid format.", 196 translations = 197 { 198 @Translation( language = "en", text = MSG_InvalidFormat ), 199 @Translation( language = "de", text = "Das Format '%1$s' ist nicht gültig für eine Datums-/Zeitangabe" ) 200 } 201 ) 202 public static final int MSGKEY_InvalidFormat = 7; 203 204 /** 205 * The message key for an error message about a missing option argument. 206 * 207 * @see #MSG_MissingOperand 208 */ 209 @Message 210 ( 211 description = "The error message about a missing option argument.", 212 translations = 213 { 214 @Translation( language = "en", text = MSG_MissingOperand ), 215 @Translation( language = "de", text = "Die Option '%1$s' erfordert ein Argument" ) 216 } 217 ) 218 public static final int MSGKEY_MissingOperand = 8; 219 220 /** 221 * The message key for an error message about an argument where none is 222 * allowed. 223 * 224 * @see #MSG_NoArgumentAllowed 225 */ 226 @SuppressWarnings( "StaticMethodOnlyUsedInOneClass" ) 227 @Message 228 ( 229 description = "The error message about an argument where none is allowed.", 230 translations = 231 { 232 @Translation( language = "en", text = MSG_NoArgumentAllowed ), 233 @Translation( language = "de", text = "Keine Argumente zulässig: %1$s" ) 234 } 235 ) 236 public static final int MSGKEY_NoArgumentAllowed = 9; 237 238 /** 239 * The message key for the error message about an invalid option. 240 * 241 * @see #MSG_OptionInvalid 242 */ 243 @SuppressWarnings( "StaticMethodOnlyUsedInOneClass" ) 244 @Message 245 ( 246 description = "The error message about an invalid option.", 247 translations = 248 { 249 @Translation( language = "en", text = MSG_OptionInvalid ), 250 @Translation( language = "de", text = "Die Option '%1$s' ist ungültig" ) 251 } 252 ) 253 public static final int MSGKEY_OptionInvalid = 10; 254 255 /** 256 * The message key for the error message about an option that is missing 257 * on the command line. 258 * 259 * @see #MSG_OptionMissing 260 */ 261 @SuppressWarnings( "StaticMethodOnlyUsedInOneClass" ) 262 @Message 263 ( 264 description = "The error message about an option that is missing on the command line.", 265 translations = 266 { 267 @Translation( language = "en", text = MSG_OptionMissing ), 268 @Translation( language = "de", text = "Die erforderliche Option '%1$s' fehlt auf der Kommandozeile" ) 269 } 270 ) 271 public static final int MSGKEY_OptionMissing = 11; 272 273 /** 274 * The message key for the message about an unspecified failure of the 275 * parsing. 276 * 277 * @see #MSG_ParseFailed 278 */ 279 @Message 280 ( 281 description = "The error message about aan unspecified failure of the parsing.", 282 translations = 283 { 284 @Translation( language = "en", text = MSG_ParseFailed ), 285 @Translation( language = "de", text = "Die Auswertung der Kommandozeile ist fehlgeschlagen" ) 286 } 287 ) 288 public static final int MSGKEY_ParseFailed = 12; 289 290 /** 291 * The message key for the error message about too many arguments on the 292 * command line. 293 * 294 * @see #MSG_TooManyArguments 295 */ 296 @SuppressWarnings( "StaticMethodOnlyUsedInOneClass" ) 297 @Message 298 ( 299 description = "The error message about an unspecified failure of the parsing.", 300 translations = 301 { 302 @Translation( language = "en", text = MSG_TooManyArguments ), 303 @Translation( language = "de", text = "Zu viele Argumente auf der Kommandozeile: %1$s" ) 304 } 305 ) 306 public static final int MSGKEY_TooManyArguments = 13; 307 308 /*------------*\ 309 ====** Attributes **======================================================= 310 \*------------*/ 311 /** 312 * The CLI definition for the argument/option that caused this exception. 313 * 314 * @serial 315 */ 316 @SuppressWarnings( "OptionalUsedAsFieldOrParameterType" ) 317 private final Optional<CLIDefinition> m_CLIDefinition; 318 319 /** 320 * The arguments for the message that is retrieved with the 321 * {@link #m_MessageKey}. 322 * 323 * @serial 324 */ 325 private final Object [] m_MessageArguments; 326 327 /** 328 * The message key. 329 * 330 * @serial 331 */ 332 private final int m_MessageKey; 333 334 /*------------------------*\ 335 ====** Static Initialisations **=========================================== 336 \*------------------------*/ 337 /** 338 * The serial version UID for objects of this class: {@value}. 339 */ 340 @Serial 341 private static final long serialVersionUID = -8574071211991372980L; 342 343 /*--------------*\ 344 ====** Constructors **===================================================== 345 \*--------------*/ 346 /** 347 * Creates a new {@code CmdLineException} instance. 348 * 349 * @param message The error message. 350 * @param messageKey The resource bundle key for an alternative message. 351 * @param messageArguments The arguments for the generation of the 352 * alternative message. 353 */ 354 public CmdLineException( final String message, final int messageKey, final Object... messageArguments ) 355 { 356 this( null, message, messageKey, messageArguments ); 357 } // CmdLineException() 358 359 /** 360 * Creates a new {@code CmdLineException} instance. 361 * 362 * @param cliDefinition The CLI definition for the argument/option that 363 * caused this exception. 364 * @param message The error message. 365 * @param messageKey The resource bundle key for an alternative message. 366 * @param messageArguments The arguments for the generation of the 367 * alternative message. 368 */ 369 public CmdLineException( final CLIDefinition cliDefinition, final String message, final int messageKey, final Object... messageArguments ) 370 { 371 super( format( requireNonNullArgument( message, "message" ), messageArguments ) ); 372 373 m_CLIDefinition = Optional.ofNullable( cliDefinition ); 374 375 m_MessageArguments = messageArguments.clone(); 376 m_MessageKey = messageKey; 377 } // CmdLineException() 378 379 /** 380 * Creates a new {@code CmdLineException} instance. 381 * 382 * @param message The error message. 383 * @param cause The exception that caused this exception. 384 * @param messageKey The resource bundle key for an alternative message. 385 * @param messageArguments The arguments for the generation of the 386 * alternative message. 387 */ 388 public CmdLineException( final String message, final Throwable cause, final int messageKey, final Object... messageArguments ) 389 { 390 this( null, message, cause, messageKey, messageArguments ); 391 } // CmdLineException() 392 393 /** 394 * Creates a new {@code CmdLineException} instance. 395 * 396 * @param cliDefinition The CLI definition for the argument/option that 397 * caused this exception. 398 * @param message The error message. 399 * @param cause The exception that caused this exception. 400 * @param messageKey The resource bundle key for an alternative message. 401 * @param messageArguments The arguments for the generation of the 402 * alternative message. 403 */ 404 public CmdLineException( final CLIDefinition cliDefinition, final String message, final Throwable cause, final int messageKey, final Object... messageArguments ) 405 { 406 super( format( requireNonNullArgument( message, "message" ), messageArguments ), cause ); 407 408 m_CLIDefinition = Optional.ofNullable( cliDefinition ); 409 410 m_MessageArguments = messageArguments.clone(); 411 m_MessageKey = messageKey; 412 } // CmdLineException() 413 414 /** 415 * Creates a new {@code CmdLineException} instance. 416 * 417 * @param cause The exception that caused this exception. 418 */ 419 public CmdLineException( final Throwable cause ) 420 { 421 this( Optional.empty(), cause ); 422 } // CmdLineException() 423 424 /** 425 * Creates a new {@code CmdLineException} instance. 426 * 427 * @param cliDefinition The CLI definition for the argument/option that 428 * caused this exception. 429 * @param cause The exception that caused this exception. 430 */ 431 public CmdLineException( final CLIDefinition cliDefinition, final Throwable cause ) 432 { 433 this( Optional.of( requireNonNullArgument( cliDefinition, "cliDefinition" ) ), cause ); 434 } // CmdLineException() 435 436 /** 437 * Creates a new {@code CmdLineException} instance. 438 * 439 * @param cliDefinition An instance of 440 * {@link Optional} 441 * that holds the CLI definition for the argument/option that caused 442 * this exception. 443 * @param cause The exception that caused this exception. 444 */ 445 @SuppressWarnings( "OptionalUsedAsFieldOrParameterType" ) 446 public CmdLineException( final Optional<CLIDefinition> cliDefinition, final Throwable cause ) 447 { 448 super( format( MSG_Aborted, nonNull( cause ) ? cause.getClass().getName() : "unknown" ), cause ); 449 450 m_CLIDefinition = requireNonNullArgument( cliDefinition, "cliDefinition" ); 451 452 m_MessageKey = MSGKEY_Aborted; 453 m_MessageArguments = new Object [] {nonNull( cause ) ? cause.getClass().getName() : "unknown"}; 454 } // CmdLineException() 455 456 /*---------*\ 457 ====** Methods **========================================================== 458 \*---------*/ 459 /** 460 * {@inheritDoc} 461 */ 462 @Override 463 public final synchronized Throwable fillInStackTrace() 464 { 465 final var retValue = Boolean.getBoolean( PROPERTY_IS_DEBUG ) 466 ? super.fillInStackTrace() 467 : this; 468 469 //---* Done *---------------------------------------------------------- 470 return retValue; 471 } // fillInStackTrace() 472 473 /** 474 * Returns the 475 * {@link CLIDefinition} 476 * that triggered the exception. 477 * 478 * @return An instance of 479 * {@link Optional} 480 * that holds the CLI definition. 481 */ 482 public final Optional<CLIDefinition> getCLIDefinition() { return m_CLIDefinition; } 483 484 /** 485 * {@inheritDoc} 486 */ 487 @Override 488 public final String getLocalizedMessage() { return Commons.retrieveMessage( m_MessageKey, false, m_MessageArguments ); } 489 490 /** 491 * Returns the message arguments. 492 * 493 * @return The message arguments. 494 */ 495 public final Object [] getMessageArguments() { return m_MessageArguments.clone(); } 496 497 /** 498 * Returns the resource bundle key for the alternative message. 499 * 500 * @return The message key. 501 */ 502 public final int getMessageKey() { return m_MessageKey; } 503} 504// class CmdLineException 505 506/* 507 * End of File 508 */