package ameba.message.error; import ameba.core.Requests; import ameba.i18n.Messages; import ameba.util.ClassUtils; import ameba.util.Result; import com.fasterxml.jackson.annotation.JsonIgnore; import com.google.common.collect.Lists; import com.google.common.hash.Hashing; import org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException; import javax.ws.rs.InternalServerErrorException; import javax.ws.rs.WebApplicationException; import javax.ws.rs.container.ResourceInfo; import java.io.FileNotFoundException; import java.util.List; /** * <p>ErrorMessage class.</p> * * @author icode * */ public class ErrorMessage extends Result { /** * Constant <code>LOCALE_FILE="ameba.message.error.http"</code> */ @JsonIgnore public final static String LOCALE_FILE = "ameba.message.error.http"; @JsonIgnore private Throwable throwable; private int status; /** * <p>Constructor for ErrorMessage.</p> */ public ErrorMessage() { super(false); } /** * <p>Constructor for ErrorMessage.</p> * * @param message a {@link java.lang.String} object. * @param errors a {@link java.util.List} object. */ public ErrorMessage(String message, List<Error> errors) { super(message, errors); } /** * <p>Constructor for ErrorMessage.</p> * * @param code a {@link java.lang.String} object. * @param message a {@link java.lang.String} object. * @param description a {@link java.lang.String} object. * @param errors a {@link java.util.List} object. */ public ErrorMessage(String code, String message, String description, List<Error> errors) { super(code, message, description, errors); } /** * <p>Constructor for ErrorMessage.</p> * * @param success a boolean. * @param message a {@link java.lang.String} object. */ public ErrorMessage(boolean success, String message) { super(success, message); } /** * <p>Constructor for ErrorMessage.</p> * * @param success a boolean. * @param code a {@link java.lang.String} object. * @param message a {@link java.lang.String} object. */ public ErrorMessage(boolean success, String code, String message) { super(success, code, message); } /** * <p>Constructor for ErrorMessage.</p> * * @param message a {@link java.lang.String} object. * @param description a {@link java.lang.String} object. * @param errors a {@link java.util.List} object. */ public ErrorMessage(String message, String description, List<Error> errors) { super(message, description, errors); } /** * <p>getLocaleMessage.</p> * * @param key a {@link java.lang.String} object. * @return a {@link java.lang.String} object. */ public static String getLocaleMessage(String key) { return Messages.get(LOCALE_FILE, key, null); } /** * <p>getLocaleMessage.</p> * * @param status a int. * @return a {@link java.lang.String} object. */ public static String getLocaleMessage(int status) { return getLocaleMessage(status + ".error.message"); } /** * <p>getLocaleMessage.</p> * * @return a {@link java.lang.String} object. */ public static String getLocaleMessage() { return getLocaleMessage("default.error.message"); } /** * <p>getLocaleDescription.</p> * * @return a {@link java.lang.String} object. */ public static String getLocaleDescription() { return getLocaleMessage("default.error.description"); } /** * <p>getLocaleDescription.</p> * * @param status a int. * @return a {@link java.lang.String} object. */ public static String getLocaleDescription(int status) { return getLocaleMessage(status + ".error.description"); } /** * <p>fromStatus.</p> * * @param status a int. * @return a {@link ameba.message.error.ErrorMessage} object. */ public static ErrorMessage fromStatus(int status) { ErrorMessage errorMessage = new ErrorMessage(); errorMessage.setStatus(status); errorMessage.setMessage(parseMessage(status)); errorMessage.setDescription(parseDescription(status)); return errorMessage; } /** * <p>parseHttpStatus.</p> * * @param exception a {@link java.lang.Throwable} object. * @return a int. */ public static int parseHttpStatus(Throwable exception) { int status = 500; Exception ex = Requests.getProperty(DefaultExceptionMapper.BEFORE_EXCEPTION_KEY); if (ex != null) { exception = ex; } if (exception instanceof InternalServerErrorException) { if (exception.getCause() instanceof MessageBodyProviderNotFoundException) { MessageBodyProviderNotFoundException e = (MessageBodyProviderNotFoundException) exception.getCause(); if (e.getMessage().startsWith("MessageBodyReader")) { status = 415; } else if (e.getMessage().startsWith("MessageBodyWriter")) { status = 406; } } } else if (exception instanceof WebApplicationException) { status = ((WebApplicationException) exception).getResponse().getStatus(); } else if (exception instanceof FileNotFoundException) { status = 404; } return status; } /** * <p>parseErrors.</p> * * @param exception a {@link java.lang.Throwable} object. * @param status a int. * @return a {@link java.util.List} object. */ public static List<Result.Error> parseErrors(Throwable exception, int status) { List<Result.Error> errors = Lists.newArrayList(); if (status == 500 || status == 400) { Throwable cause = exception; while (cause != null) { StackTraceElement[] stackTraceElements = cause.getStackTrace(); if (stackTraceElements != null && stackTraceElements.length > 0) { Result.Error error = new Result.Error( Hashing.murmur3_32().hashUnencodedChars(exception.getClass().getName()).toString(), cause.getMessage()); if (status == 500) { StringBuilder descBuilder = new StringBuilder(); for (StackTraceElement element : stackTraceElements) { descBuilder .append(element.toString()) .append("\n"); } error.setDescription(descBuilder.toString()); } StackTraceElement stackTraceElement = stackTraceElements[0]; String source = stackTraceElement.toString(); error.setSource(source); errors.add(error); } cause = cause.getCause(); } } return errors; } /** * <p>parseMessage.</p> * * @param status a int. * @return a {@link java.lang.String} object. */ public static String parseMessage(int status) { String msg = null; if (status < 500) { if (status == 402 || (status > 417 && status < 421) || status > 424) { msg = ErrorMessage.getLocaleMessage(400); } else { msg = ErrorMessage.getLocaleMessage(status); } } else { switch (status) { case 501: msg = ErrorMessage.getLocaleMessage(status); break; } } if (msg == null) { msg = ErrorMessage.getLocaleMessage(); } return msg; } /** * <p>parseDescription.</p> * * @param status a int. * @return a {@link java.lang.String} object. */ public static String parseDescription(int status) { String desc = null; if (status < 500) { if (status == 402 || (status > 417 && status < 421) || status > 424) { desc = ErrorMessage.getLocaleDescription(400); } else { desc = ErrorMessage.getLocaleDescription(status); } } else { switch (status) { case 501: desc = ErrorMessage.getLocaleDescription(status); break; } } if (desc == null) { desc = ErrorMessage.getLocaleDescription(); } return desc; } /** * <p>parseSource.</p> * * @param resourceInfo a {@link javax.ws.rs.container.ResourceInfo} object. * @return a {@link java.lang.String} object. */ public static String parseSource(ResourceInfo resourceInfo) { if (resourceInfo != null) { Class clazz = resourceInfo.getResourceClass(); if (clazz != null) return ClassUtils.toString(clazz, resourceInfo.getResourceMethod()); } return null; } /** * <p>Getter for the field <code>throwable</code>.</p> * * @return a {@link java.lang.Throwable} object. */ public Throwable getThrowable() { return throwable; } /** * <p>Setter for the field <code>throwable</code>.</p> * * @param throwable a {@link java.lang.Throwable} object. */ public void setThrowable(Throwable throwable) { this.throwable = throwable; } /** * <p>Getter for the field <code>status</code>.</p> * * @return a int. */ public int getStatus() { return status; } /** * <p>Setter for the field <code>status</code>.</p> * * @param status a int. */ public void setStatus(int status) { this.status = status; } /** * <p>toString.</p> * * @return a {@link java.lang.String} object. */ public String toString() { return Messages.get("error.code") + ": " + getCode() + "\n" + Messages.get("error.message") + ": " + getMessage() + "\n" + Messages.get("error.description") + ": " + getDescription(); } }