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();
}
}