From 207304932a610f686a16b30e4efe9c30814f42e8 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Mon, 8 Feb 2021 22:43:27 +0100 Subject: [PATCH] [Major] Better exception handling for AccessDeniedExceptions --- .../persistence/api/AbstractTransaction.java | 30 +++++++++-- .../java/li/strolch/search/StrolchSearch.java | 49 ++++++++++++++---- .../li/strolch/search/StrolchValueSearch.java | 16 ------ .../service/api/DefaultServiceHandler.java | 50 +++++++++++++------ .../main/resources/strolch-agent.properties | 5 +- .../StrolchAccessDeniedException.java | 32 ++++-------- .../model/i18n/I18nMessageToJsonVisitor.java | 1 + .../java/li/strolch/model/log/LogMessage.java | 11 ++-- .../strolch/rest/StrolchRestfulConstants.java | 1 + .../rest/StrolchRestfulExceptionMapper.java | 21 ++------ .../li/strolch/rest/helper/ResponseUtil.java | 23 ++------- .../java/li/strolch/utils/I18nMessage.java | 17 +++++++ 12 files changed, 143 insertions(+), 113 deletions(-) diff --git a/li.strolch.agent/src/main/java/li/strolch/persistence/api/AbstractTransaction.java b/li.strolch.agent/src/main/java/li/strolch/persistence/api/AbstractTransaction.java index db2d995a1..5d0e0d465 100644 --- a/li.strolch.agent/src/main/java/li/strolch/persistence/api/AbstractTransaction.java +++ b/li.strolch.agent/src/main/java/li/strolch/persistence/api/AbstractTransaction.java @@ -52,13 +52,13 @@ import li.strolch.policy.PolicyHandler; import li.strolch.policy.StrolchPolicy; import li.strolch.privilege.base.AccessDeniedException; import li.strolch.privilege.base.PrivilegeException; -import li.strolch.privilege.base.PrivilegeModelException; import li.strolch.privilege.model.Certificate; import li.strolch.privilege.model.PrivilegeContext; import li.strolch.privilege.model.Restrictable; import li.strolch.runtime.privilege.PrivilegeHandler; import li.strolch.runtime.privilege.TransactedRestrictable; import li.strolch.service.api.Command; +import li.strolch.utils.I18nMessage; import li.strolch.utils.collections.MapOfMaps; import li.strolch.utils.dbc.DBC; import li.strolch.utils.helper.StringHelper; @@ -401,10 +401,30 @@ public abstract class AbstractTransaction implements StrolchTransaction { private void assertQueryAllowed(StrolchQuery query) { try { getPrivilegeContext().validateAction(query); - } catch (PrivilegeModelException e) { - throw e; - } catch (PrivilegeException e) { - throw new StrolchAccessDeniedException(this.certificate, query, getExceptionMessage(e), e); + } catch (AccessDeniedException e) { + + String username = getCertificate().getUsername(); + if (getContainer().hasComponent(OperationsLog.class)) { + String realmName = getRealmName(); + String queryName = query.getPrivilegeValue().equals(INTERNAL) ? + (getClass().getName() + " (INTERNAL)") : + query.getPrivilegeValue().toString(); + LogMessage logMessage = new LogMessage(realmName, username, + Locator.valueOf(AGENT, PrivilegeHandler.class.getSimpleName(), query.getPrivilegeName(), + queryName), LogSeverity.Exception, LogMessageState.Information, + ResourceBundle.getBundle("strolch-agent"), "agent.query.failed.access.denied") + .value("user", username).value("query", queryName).withException(e); + + OperationsLog operationsLog = getContainer().getComponent(OperationsLog.class); + operationsLog.addMessage(logMessage); + } + + String queryName = query.getPrivilegeValue().equals(INTERNAL) ? + (getClass().getSimpleName() + " (INTERNAL)") : + query.getClass().getSimpleName(); + I18nMessage i18n = new I18nMessage(ResourceBundle.getBundle("strolch-agent", getCertificate().getLocale()), + "agent.search.failed.access.denied").value("user", username).value("query", queryName); + throw new StrolchAccessDeniedException(this.certificate, query, i18n, e); } } diff --git a/li.strolch.agent/src/main/java/li/strolch/search/StrolchSearch.java b/li.strolch.agent/src/main/java/li/strolch/search/StrolchSearch.java index e60404d26..a86344638 100644 --- a/li.strolch.agent/src/main/java/li/strolch/search/StrolchSearch.java +++ b/li.strolch.agent/src/main/java/li/strolch/search/StrolchSearch.java @@ -1,17 +1,26 @@ package li.strolch.search; +import static li.strolch.model.StrolchModelConstants.INTERNAL; +import static li.strolch.model.Tags.AGENT; + import java.util.Collection; +import java.util.ResourceBundle; import java.util.stream.Stream; import li.strolch.exception.StrolchAccessDeniedException; +import li.strolch.handler.operationslog.OperationsLog; +import li.strolch.model.Locator; import li.strolch.model.StrolchModelConstants; import li.strolch.model.StrolchRootElement; +import li.strolch.model.log.LogMessage; +import li.strolch.model.log.LogMessageState; +import li.strolch.model.log.LogSeverity; import li.strolch.persistence.api.StrolchTransaction; -import li.strolch.privilege.base.PrivilegeException; -import li.strolch.privilege.base.PrivilegeModelException; +import li.strolch.privilege.base.AccessDeniedException; import li.strolch.privilege.model.Restrictable; +import li.strolch.runtime.privilege.PrivilegeHandler; +import li.strolch.utils.I18nMessage; import li.strolch.utils.dbc.DBC; -import li.strolch.utils.helper.ExceptionHelper; /** * Class to perform searches on Strolch elements @@ -71,7 +80,7 @@ public abstract class StrolchSearch * @return this object for chaining */ public StrolchSearch internal() { - this.privilegeValue = StrolchModelConstants.INTERNAL; + this.privilegeValue = INTERNAL; return this; } @@ -86,11 +95,33 @@ public abstract class StrolchSearch public RootElementSearchResult search(StrolchTransaction tx) { try { tx.getPrivilegeContext().validateAction(this); - } catch (PrivilegeModelException e) { - throw e; - } catch (PrivilegeException e) { - throw new StrolchAccessDeniedException(tx.getCertificate(), this, ExceptionHelper.getExceptionMessage(e), - e); + } catch (AccessDeniedException e) { + + String username = tx.getCertificate().getUsername(); + + if (tx.getContainer().hasComponent(OperationsLog.class)) { + String realmName = tx.getRealmName(); + String searchName = this.privilegeValue.equals(INTERNAL) ? + (getClass().getName() + " (INTERNAL)") : + this.privilegeValue; + LogMessage logMessage = new LogMessage(realmName, username, + Locator.valueOf(AGENT, PrivilegeHandler.class.getSimpleName(), getPrivilegeName(), searchName), + LogSeverity.Exception, LogMessageState.Information, ResourceBundle.getBundle("strolch-agent"), + "agent.search.failed.access.denied").value("user", username).value("search", searchName) + .withException(e); + + OperationsLog operationsLog = tx.getContainer().getComponent(OperationsLog.class); + operationsLog.addMessage(logMessage); + } + + String searchName = this.privilegeValue.equals(INTERNAL) ? + (getClass().getSimpleName() + " (INTERNAL)") : + getClass().getSimpleName(); + I18nMessage i18n = new I18nMessage( + ResourceBundle.getBundle("strolch-agent", tx.getCertificate().getLocale()), + "agent.search.failed.access.denied").value("user", username).value("search", searchName); + + throw new StrolchAccessDeniedException(tx.getCertificate(), this, i18n, e); } // first prepare diff --git a/li.strolch.agent/src/main/java/li/strolch/search/StrolchValueSearch.java b/li.strolch.agent/src/main/java/li/strolch/search/StrolchValueSearch.java index 04a9691c9..09fadb655 100644 --- a/li.strolch.agent/src/main/java/li/strolch/search/StrolchValueSearch.java +++ b/li.strolch.agent/src/main/java/li/strolch/search/StrolchValueSearch.java @@ -1,15 +1,9 @@ package li.strolch.search; -import static li.strolch.utils.helper.ExceptionHelper.getExceptionMessage; - import java.util.Collection; import java.util.stream.Stream; -import li.strolch.exception.StrolchAccessDeniedException; import li.strolch.model.StrolchModelConstants; -import li.strolch.privilege.base.PrivilegeException; -import li.strolch.privilege.base.PrivilegeModelException; -import li.strolch.privilege.model.PrivilegeContext; import li.strolch.privilege.model.Restrictable; public class StrolchValueSearch extends ValueSearch implements Restrictable { @@ -47,16 +41,6 @@ public class StrolchValueSearch extends ValueSearch implements Restrictabl return this; } - protected void assertHasPrivilege(PrivilegeContext ctx) { - try { - ctx.validateAction(this); - } catch (PrivilegeModelException e) { - throw e; - } catch (PrivilegeException e) { - throw new StrolchAccessDeniedException(ctx.getCertificate(), this, getExceptionMessage(e), e); - } - } - @Override public SearchResult search(Stream stream) { return super.search(stream); diff --git a/li.strolch.agent/src/main/java/li/strolch/service/api/DefaultServiceHandler.java b/li.strolch.agent/src/main/java/li/strolch/service/api/DefaultServiceHandler.java index 20c87eee9..3e8c1b9c7 100644 --- a/li.strolch.agent/src/main/java/li/strolch/service/api/DefaultServiceHandler.java +++ b/li.strolch.agent/src/main/java/li/strolch/service/api/DefaultServiceHandler.java @@ -27,11 +27,11 @@ import li.strolch.agent.api.ComponentContainer; import li.strolch.agent.api.StrolchComponent; import li.strolch.exception.StrolchAccessDeniedException; import li.strolch.exception.StrolchException; +import li.strolch.handler.operationslog.OperationsLog; +import li.strolch.model.Locator; import li.strolch.model.log.LogMessage; import li.strolch.model.log.LogMessageState; import li.strolch.model.log.LogSeverity; -import li.strolch.handler.operationslog.OperationsLog; -import li.strolch.model.Locator; import li.strolch.privilege.base.PrivilegeException; import li.strolch.privilege.base.PrivilegeModelException; import li.strolch.privilege.model.Certificate; @@ -39,6 +39,7 @@ import li.strolch.privilege.model.PrivilegeContext; import li.strolch.runtime.configuration.ComponentConfiguration; import li.strolch.runtime.configuration.RuntimeConfiguration; import li.strolch.runtime.privilege.PrivilegeHandler; +import li.strolch.utils.I18nMessage; import li.strolch.utils.dbc.DBC; /** @@ -89,28 +90,44 @@ public class DefaultServiceHandler extends StrolchComponent implements ServiceHa long end = System.nanoTime(); String msg = "User {0}: Service {1} failed after {2} due to {3}"; //$NON-NLS-1$ - msg = MessageFormat.format(msg, username, service.getClass().getName(), formatNanoDuration(end - start), - e.getMessage()); + String svcName = service.getClass().getName(); + msg = MessageFormat.format(msg, username, svcName, formatNanoDuration(end - start), e.getMessage()); logger.error(msg); + if (getContainer().hasComponent(OperationsLog.class)) { + String realmName = getRealmName(argument, certificate); + LogMessage logMessage = new LogMessage(realmName, username, + Locator.valueOf(AGENT, PrivilegeHandler.class.getSimpleName(), service.getPrivilegeName(), + svcName), LogSeverity.Exception, LogMessageState.Information, + ResourceBundle.getBundle("strolch-agent"), "agent.service.failed.access.denied") + .value("user", username).value("service", svcName).withException(e); + + OperationsLog operationsLog = getContainer().getComponent(OperationsLog.class); + operationsLog.addMessage(logMessage); + } + + I18nMessage i18n = new I18nMessage(ResourceBundle.getBundle("strolch-agent", certificate.getLocale()), + "agent.service.failed.access.denied").value("user", username) + .value("service", service.getClass().getSimpleName()); + if (!this.throwOnPrivilegeFail && service instanceof AbstractService) { logger.error(e.getMessage(), e); AbstractService abstractService = (AbstractService) service; @SuppressWarnings("unchecked") - U arg = (U) abstractService.getResultInstance(); - arg.setState(e instanceof PrivilegeModelException ? + U result = (U) abstractService.getResultInstance(); + result.setState(e instanceof PrivilegeModelException ? ServiceResultState.EXCEPTION : ServiceResultState.ACCESS_DENIED); - arg.setMessage(e.getMessage()); - arg.setThrowable(e); - return arg; + result.setMessage(i18n.getMessage()); + result.i18n(i18n); + result.setThrowable(e); + return result; } if (e instanceof PrivilegeModelException) - throw new StrolchException(e.getMessage(), e); - else - throw new StrolchAccessDeniedException(certificate, service, e.getMessage(), e); + throw new StrolchException(i18n.getMessage(), e); + throw new StrolchAccessDeniedException(certificate, service, i18n, e); } try { @@ -220,12 +237,13 @@ public class DefaultServiceHandler extends StrolchComponent implements ServiceHa ResourceBundle bundle = ResourceBundle.getBundle("strolch-agent"); if (throwable == null) { logMessage = new LogMessage(realmName, username, Locator.valueOf(AGENT, svcName, getUniqueId()), - LogSeverity.Exception, LogMessageState.Information, bundle, "agent.service.failed").value("service", svcName) - .value("reason", reason); + LogSeverity.Exception, LogMessageState.Information, bundle, "agent.service.failed") + .value("service", svcName).value("reason", reason); } else { logMessage = new LogMessage(realmName, username, Locator.valueOf(AGENT, svcName, getUniqueId()), - LogSeverity.Exception, LogMessageState.Information, bundle, "agent.service.failed.ex").withException(throwable) - .value("service", svcName).value("reason", reason).value("exception", throwable); + LogSeverity.Exception, LogMessageState.Information, bundle, "agent.service.failed.ex") + .withException(throwable).value("service", svcName).value("reason", reason) + .value("exception", throwable); } OperationsLog operationsLog = getContainer().getComponent(OperationsLog.class); diff --git a/li.strolch.agent/src/main/resources/strolch-agent.properties b/li.strolch.agent/src/main/resources/strolch-agent.properties index 935c09cf7..768cb3694 100644 --- a/li.strolch.agent/src/main/resources/strolch-agent.properties +++ b/li.strolch.agent/src/main/resources/strolch-agent.properties @@ -5,4 +5,7 @@ agent.observers.update.failed=Observer handler action '{type}' failed due to: {r agent.service.failed=Service {service} has failed due to {reason} agent.service.failed.ex=Service {service} has failed due to {reason} due to: {exception} strolchjob.failed=Execution of Job {jobName} has failed due to {reason} -operationsLog.persist.failed=Failed to persist OperationsLog due to: {reason} \ No newline at end of file +operationsLog.persist.failed=Failed to persist OperationsLog due to: {reason} +agent.query.failed.access.denied=User {user} may not perform query {query} +agent.search.failed.access.denied=User {user} may not perform search {search} +agent.service.failed.access.denied=User {user} may not perform service {service} \ No newline at end of file diff --git a/li.strolch.model/src/main/java/li/strolch/exception/StrolchAccessDeniedException.java b/li.strolch.model/src/main/java/li/strolch/exception/StrolchAccessDeniedException.java index 4b2d16040..dfd965f94 100644 --- a/li.strolch.model/src/main/java/li/strolch/exception/StrolchAccessDeniedException.java +++ b/li.strolch.model/src/main/java/li/strolch/exception/StrolchAccessDeniedException.java @@ -17,37 +17,23 @@ package li.strolch.exception; import li.strolch.privilege.model.Certificate; import li.strolch.privilege.model.Restrictable; +import li.strolch.utils.I18nMessage; /** * @author Robert von Burg */ public class StrolchAccessDeniedException extends StrolchException { - private Certificate certificate; - private Restrictable restrictable; + private final Certificate certificate; + private final Restrictable restrictable; + private final I18nMessage i18n; - /** - * @param certificate - * @param restrictable - * @param message - * @param cause - */ - public StrolchAccessDeniedException(Certificate certificate, Restrictable restrictable, String message, + public StrolchAccessDeniedException(Certificate certificate, Restrictable restrictable, I18nMessage i18n, Throwable cause) { - super(message, cause); - this.certificate = certificate; - this.restrictable = restrictable; - } - - /** - * @param certificate - * @param restrictable - * @param message - */ - public StrolchAccessDeniedException(Certificate certificate, Restrictable restrictable, String message) { - super(message); + super(i18n.getMessage(), cause); this.certificate = certificate; this.restrictable = restrictable; + this.i18n = i18n; } public Certificate getCertificate() { @@ -57,4 +43,8 @@ public class StrolchAccessDeniedException extends StrolchException { public Restrictable getRestrictable() { return restrictable; } + + public I18nMessage getI18n() { + return this.i18n; + } } diff --git a/li.strolch.model/src/main/java/li/strolch/model/i18n/I18nMessageToJsonVisitor.java b/li.strolch.model/src/main/java/li/strolch/model/i18n/I18nMessageToJsonVisitor.java index 8ccf5ff52..57315eef6 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/i18n/I18nMessageToJsonVisitor.java +++ b/li.strolch.model/src/main/java/li/strolch/model/i18n/I18nMessageToJsonVisitor.java @@ -15,6 +15,7 @@ public class I18nMessageToJsonVisitor implements I18nMessageVisitor json.addProperty(Tags.Json.KEY, message.getKey()); json.addProperty(Tags.Json.MESSAGE, message.getMessage()); + json.addProperty(Tags.Json.EXCEPTION, message.getStackTrace()); Properties values = message.getValues(); if (!values.isEmpty()) { diff --git a/li.strolch.model/src/main/java/li/strolch/model/log/LogMessage.java b/li.strolch.model/src/main/java/li/strolch/model/log/LogMessage.java index 26d9f5bf1..349c9a772 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/log/LogMessage.java +++ b/li.strolch.model/src/main/java/li/strolch/model/log/LogMessage.java @@ -10,7 +10,6 @@ import com.google.gson.JsonObject; import li.strolch.model.Locator; import li.strolch.model.Tags.Json; import li.strolch.utils.I18nMessage; -import li.strolch.utils.helper.ExceptionHelper; import li.strolch.utils.helper.StringHelper; import li.strolch.utils.iso8601.ISO8601; @@ -23,7 +22,6 @@ public class LogMessage extends I18nMessage { private final Locator locator; private final LogSeverity severity; private LogMessageState state; - private String stackTrace; public LogMessage(String realm, String username, Locator locator, LogSeverity severity, LogMessageState state, I18nMessage i18nMessage) { @@ -100,22 +98,19 @@ public class LogMessage extends I18nMessage { } public LogMessage withException(Throwable t) { - this.stackTrace = ExceptionHelper.formatException(t); + super.withException(t); return this; } - public String getStackTrace() { - return this.stackTrace; - } - @Override public LogMessage value(String key, Object value) { super.value(key, value); return this; } + @Override public LogMessage value(String key, Throwable e) { - super.value(key, ExceptionHelper.getExceptionMessageWithCauses(e)); + super.value(key, e); return this; } diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/StrolchRestfulConstants.java b/li.strolch.rest/src/main/java/li/strolch/rest/StrolchRestfulConstants.java index c06e8e5b7..827d4b593 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/StrolchRestfulConstants.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/StrolchRestfulConstants.java @@ -30,6 +30,7 @@ public class StrolchRestfulConstants { public static final String STROLCH_AUTHORIZATION_EXPIRATION_DATE = "strolch.authorization.expirationDate"; //$NON-NLS-1$ public static final String MSG = "msg"; + public static final String I18N = "i18n"; public static final String EXCEPTION_MSG = "exceptionMsg"; public static final String DATA = Tags.Json.DATA; public static final String LAST_OFFSET = "lastOffset"; diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/StrolchRestfulExceptionMapper.java b/li.strolch.rest/src/main/java/li/strolch/rest/StrolchRestfulExceptionMapper.java index 214f7c462..8a90ad0bc 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/StrolchRestfulExceptionMapper.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/StrolchRestfulExceptionMapper.java @@ -25,7 +25,6 @@ import java.text.MessageFormat; import li.strolch.exception.StrolchAccessDeniedException; import li.strolch.exception.StrolchNotAuthenticatedException; -import li.strolch.privilege.model.Restrictable; import li.strolch.rest.helper.ResponseUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,24 +44,10 @@ public class StrolchRestfulExceptionMapper implements ExceptionMapper if (ex instanceof StrolchAccessDeniedException) { StrolchAccessDeniedException e = (StrolchAccessDeniedException) ex; - StringBuilder sb = new StringBuilder(); - sb.append("User "); - sb.append(e.getCertificate().getUsername()); - sb.append(" does not have access to "); - Restrictable restrictable = e.getRestrictable(); - if (restrictable == null) { - // sb.append(StringHelper.NULL); - // use the message - sb.append(e.getMessage()); - } else { - sb.append(restrictable.getPrivilegeName()); - sb.append(" - "); - sb.append(restrictable.getPrivilegeValue()); - } + return ResponseUtil.toResponse(Status.FORBIDDEN, e.getI18n()); + } - return Response.status(Status.FORBIDDEN).entity(sb.toString()).type(MediaType.TEXT_PLAIN).build(); - - } else if (ex instanceof StrolchNotAuthenticatedException) { + if (ex instanceof StrolchNotAuthenticatedException) { StrolchNotAuthenticatedException e = (StrolchNotAuthenticatedException) ex; logger.error("User tried to access resource, but was not authenticated: " + ex.getMessage()); return Response.status(Status.UNAUTHORIZED).entity(e.getMessage()).type(MediaType.TEXT_PLAIN).build(); diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/helper/ResponseUtil.java b/li.strolch.rest/src/main/java/li/strolch/rest/helper/ResponseUtil.java index 2f9941c6d..a010434b4 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/helper/ResponseUtil.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/helper/ResponseUtil.java @@ -15,6 +15,7 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import li.strolch.exception.StrolchElementNotFoundException; +import li.strolch.model.i18n.I18nMessageToJsonVisitor; import li.strolch.privilege.base.AccessDeniedException; import li.strolch.privilege.base.PrivilegeException; import li.strolch.privilege.base.PrivilegeModelException; @@ -32,27 +33,22 @@ public class ResponseUtil { public static Response toResponse() { JsonObject response = new JsonObject(); response.addProperty(MSG, StringHelper.DASH); - String json = new Gson().toJson(response); - return Response.ok(json, MediaType.APPLICATION_JSON).build(); } - public static Response toResponse(I18nMessage msg) { + public static Response toResponse(Status status, I18nMessage msg) { JsonObject response = new JsonObject(); response.addProperty(MSG, msg.getMessage()); - + response.add(I18N, msg.accept(new I18nMessageToJsonVisitor())); String json = new Gson().toJson(response); - - return Response.serverError().entity(json).type(MediaType.APPLICATION_JSON).build(); + return Response.status(status).entity(json).type(MediaType.APPLICATION_JSON).build(); } public static Response toResponse(String errorMsg) { JsonObject response = new JsonObject(); response.addProperty(MSG, errorMsg); - String json = new Gson().toJson(response); - return Response.serverError().entity(json).type(MediaType.APPLICATION_JSON).build(); } @@ -60,9 +56,7 @@ public class ResponseUtil { JsonObject response = new JsonObject(); response.addProperty(MSG, StringHelper.DASH); response.addProperty(prop, value); - String json = new Gson().toJson(response); - return Response.ok(json, MediaType.APPLICATION_JSON).build(); } @@ -71,9 +65,7 @@ public class ResponseUtil { response.addProperty(MSG, StringHelper.DASH); response.addProperty(prop1, value1); response.addProperty(prop2, value2); - String json = new Gson().toJson(response); - return Response.ok(json, MediaType.APPLICATION_JSON).build(); } @@ -82,9 +74,7 @@ public class ResponseUtil { response.addProperty(MSG, StringHelper.DASH); response.addProperty(prop1, value1); response.add(DATA, data); - String json = new Gson().toJson(response); - return Response.ok(json, MediaType.APPLICATION_JSON).build(); } @@ -96,9 +86,7 @@ public class ResponseUtil { JsonObject response = new JsonObject(); response.addProperty(MSG, StringHelper.DASH); response.add(member, jsonElement); - String json = new Gson().toJson(response); - return Response.ok(json, MediaType.APPLICATION_JSON).build(); } @@ -125,7 +113,6 @@ public class ResponseUtil { response.add(member, arrayJ); String json = new Gson().toJson(response); - return Response.ok(json, MediaType.APPLICATION_JSON).build(); } @@ -136,7 +123,6 @@ public class ResponseUtil { } public static Response toResponse(ServiceResult svcResult) { - Throwable t = svcResult.getThrowable(); JsonObject response = svcResult.toJson(); String json = new Gson().toJson(response); @@ -186,7 +172,6 @@ public class ResponseUtil { JsonObject response = new JsonObject(); response.addProperty(MSG, getExceptionMessageWithCauses(t, false)); String json = new Gson().toJson(response); - return Response.status(status).entity(json).type(MediaType.APPLICATION_JSON).build(); } diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/I18nMessage.java b/li.strolch.utils/src/main/java/li/strolch/utils/I18nMessage.java index 7a0a211d8..de71b604f 100644 --- a/li.strolch.utils/src/main/java/li/strolch/utils/I18nMessage.java +++ b/li.strolch.utils/src/main/java/li/strolch/utils/I18nMessage.java @@ -2,6 +2,8 @@ package li.strolch.utils; import static java.util.Collections.emptySet; import static li.strolch.utils.collections.SynchronizedCollections.synchronizedMapOfSets; +import static li.strolch.utils.helper.ExceptionHelper.formatException; +import static li.strolch.utils.helper.ExceptionHelper.getExceptionMessageWithCauses; import static li.strolch.utils.helper.StringHelper.EMPTY; import static li.strolch.utils.helper.StringHelper.isEmpty; @@ -33,6 +35,7 @@ public class I18nMessage { private final Properties values; private final ResourceBundle bundle; private String message; + protected String stackTrace; public I18nMessage(ResourceBundle bundle, String key) { DBC.INTERIM.assertNotNull("bundle may not be null!", bundle); @@ -137,6 +140,20 @@ public class I18nMessage { return this; } + public I18nMessage value(String key, Throwable e) { + value(key, getExceptionMessageWithCauses(e)); + return this; + } + + public I18nMessage withException(Throwable t) { + this.stackTrace = formatException(t); + return this; + } + + public String getStackTrace() { + return this.stackTrace; + } + public String formatMessage() { if (this.message != null) return this.message;