package org.jtheque.errors; import org.jtheque.errors.Error.Level; import org.jtheque.i18n.InternationalizableException; import org.jtheque.i18n.LanguageService; import org.jtheque.utils.StringUtils; import org.jtheque.utils.annotations.Immutable; import org.jtheque.utils.collections.ArrayUtils; /* * Copyright JTheque (Baptiste Wicht) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * A builder for Error objects. * * @author Baptiste Wicht * @see Error */ public final class Errors { private static final Object[] EMPTY_REPLACES = ArrayUtils.EMPTY_ARRAY; /** * Utility class, not instantiable. */ private Errors() { throw new AssertionError(); } /** * Construct a new Error with a simple message. * * @param title The message of the error. * * @return The created error. */ public static Error newError(String title) { return new JThequeError(title, Level.ERROR, null, null); } /** * Construct a new Error with a message and a specific level of error. * * @param title The title of the error. * @param level The level of error. * * @return The created error. */ public static Error newError(String title, Level level) { return new JThequeError(title, level, null, null); } /** * Construct a new Error with a message and some details. * * @param title The message of the error. * @param details Some details about the error. * * @return The created error. */ public static Error newError(String title, String details) { return new JThequeError(title, Level.ERROR, details, null); } /** * Construct a new Error from an existing exception. The message of the error will be the message of the exception. * * @param exception The existing exception. * * @return The created error. */ public static Error newError(Throwable exception) { if(exception instanceof InternationalizableException){ InternationalizableException i18nException = (InternationalizableException) exception; if(StringUtils.isNotEmpty(i18nException.getI18nMessage())){ return newI18nError(i18nException.getI18nMessage()); } } return new JThequeError(exception.getMessage(), Level.ERROR, null, exception); } /** * Construct a new Error from an existing exception with a specific message. * * @param title The message. * @param exception The exception to encapsulate in the error. * * @return The created error. */ public static Error newError(String title, Throwable exception) { return new JThequeError(title, Level.ERROR, null, exception); } /** * Construct a new i18n Error. * * @param message The message key. * * @return The created error. */ public static Error newI18nError(String message) { return new InternationalizedError(message, EMPTY_REPLACES, null, EMPTY_REPLACES); } /** * Construct a new i18n Error. * * @param message The message key. * @param replaces The replaces for the internationalization variable arguments of the message. * * @return The created error. */ public static Error newI18nError(String message, Object[] replaces) { return new InternationalizedError(message, replaces, null, EMPTY_REPLACES); } /** * Construct a new i18n Error. * * @param message The message key. * @param replaces The replaces for the internationalization variable arguments of the message. * @param details The details key. * * @return The created error. */ public static Error newI18nError(String message, Object[] replaces, String details) { return new InternationalizedError(message, replaces, details, EMPTY_REPLACES); } /** * Construct a new i18n Error. * * @param message The message key. * @param replaces The replaces for the internationalization variable arguments of the message. * @param details The details key. * @param replacesDetails The replaces for the internationalization variable arguments of the details. * * @return The created error. */ public static Error newI18nError(String message, Object[] replaces, String details, Object[] replacesDetails) { return new InternationalizedError(message, replaces, details, replacesDetails); } /** * Create a new I18n error with a specific message key and the details obtained from the throwable trace. * * @param message The i18n message key. * @param throwable The throwable for the details. * * @return The created error. */ public static Error newI18nError(String message, Throwable throwable) { return new InternationalizedError(message, EMPTY_REPLACES, throwable); } /** * Create a new I18n error with a specific message key and the details obtained from the throwable trace. * * @param message The i18n message key. * @param replaces The i18n replaces. * @param throwable The throwable for the details. * * @return The created error. */ public static Error newI18nError(String message, Object[] replaces, Throwable throwable) { return new InternationalizedError(message, replaces, throwable); } /** * A basic error implementation. This class is immutable. * * @author Baptiste Wicht * @see Errors */ @Immutable private static class JThequeError implements Error { private final String title; private final Throwable exception; private final String details; private final Level level; /** * Create a new error. * * @param title The title of the error. * @param level The level of error. * @param details The details of the error. * @param exception The exception that caused this error. */ private JThequeError(String title, Level level, String details, Throwable exception) { super(); this.title = title; this.level = level; this.details = details; this.exception = exception; } @Override public Level getLevel() { return level; } @Override public String getTitle(LanguageService languageService) { return title; } @Override public String getDetails(LanguageService languageService) { if (exception != null) { return details == null ? "" : details + '\n' + exception.getMessage() + '\n' + getCustomStackTrace(exception); } return details; } /** * Return the base title of the error. * * @return The base title of the error. */ String getTitle() { return title; } /** * Return the base details of the error. * * @return The base details of the error. */ String getDetails() { return details; } /** * Return the base details of the error. * * @return The base details of the error. */ Throwable getException() { return exception; } /** * Return the stack trace into a String. * * @param throwable The throwable to extract the stack trace from. * * @return A String representing the stack trace. */ static String getCustomStackTrace(Throwable throwable) { final StringBuilder result = new StringBuilder(500); result.append(throwable.toString()); result.append('\n'); for (StackTraceElement element : throwable.getStackTrace()) { result.append(element); result.append('\n'); } return result.toString(); } } /** * An internationalized error implementation. This class is immutable. * * @author Baptiste Wicht * @see Errors */ @Immutable private static final class InternationalizedError extends JThequeError { private final Object[] titleReplaces; private final Object[] detailsReplaces; /** * Construct a new InternationalizedError. * * @param message The message key. * @param replaces The replaces for the internationalization variable arguments of the message. * @param details The details key. * @param replacesDetails The replaces for the internationalization variable arguments of the details. */ private InternationalizedError(String message, Object[] replaces, String details, Object[] replacesDetails) { super(message, Level.ERROR, details, null); titleReplaces = ArrayUtils.copyOf(replaces); detailsReplaces = ArrayUtils.copyOf(replacesDetails); } /** * Construct a new InternationalizedError. * * @param message The message key. * @param replaces The replaces for the internationalization variable arguments of the message. * @param exception The exception that produces this error. */ private InternationalizedError(String message, Object[] replaces, Throwable exception) { super(message, Level.ERROR, "", exception); titleReplaces = ArrayUtils.copyOf(replaces); detailsReplaces = ArrayUtils.EMPTY_ARRAY; } @Override public String getTitle(LanguageService languageService) { return languageService.getMessage(getTitle(), titleReplaces); } @Override public String getDetails(LanguageService languageService) { if (getException() != null) { return getException().getLocalizedMessage() + '\n' + getCustomStackTrace(getException()); } return languageService.getMessage(getDetails(), detailsReplaces); } } }