| package de.ids_mannheim.korap.response; |
| |
| import static de.ids_mannheim.korap.util.KrillString.quote; |
| |
| import com.fasterxml.jackson.annotation.*; |
| import com.fasterxml.jackson.annotation.JsonInclude.Include; |
| import com.fasterxml.jackson.databind.ObjectMapper; |
| import com.fasterxml.jackson.databind.JsonNode; |
| import com.fasterxml.jackson.databind.node.*; |
| |
| import java.util.*; |
| import java.io.*; |
| import de.ids_mannheim.korap.response.Message; |
| import de.ids_mannheim.korap.response.Messages; |
| import de.ids_mannheim.korap.util.QueryException; |
| import de.ids_mannheim.korap.util.StatusCodes; |
| |
| /** |
| * A unified notification class for KorAP related errors, |
| * warnings and messages. |
| * |
| * <p> |
| * The object contains lists of errors, warnings and messages |
| * and new warnings, errors or messages are appended to these lists. |
| * |
| * <p> |
| * <blockquote><pre> |
| * Notifications n = new Notifications(); |
| * n.addWarning(456, "Something went wrong"); |
| * if (n.hasWarnings()) { |
| * for (Message msg : n.getWarnings()) |
| * System.err.out(msg.getCode() + ": " + msg.getMessage()); |
| * }; |
| * System.err.println(n.toJsonString()); |
| * </pre></blockquote> |
| * |
| * @author Nils Diewald |
| * @see de.ids_mannheim.korap.response.Messages |
| */ |
| /* |
| * This will be inherited most of the time as Java does not support roles |
| * and I have no idea how to do this more elegantly. |
| */ |
| @JsonInclude(Include.NON_NULL) |
| @JsonIgnoreProperties(ignoreUnknown = true) |
| public class Notifications { |
| |
| // Create object mapper for JSON generation |
| ObjectMapper mapper = new ObjectMapper(); |
| |
| private Messages warnings, errors, messages; |
| |
| |
| /** |
| * Check for warnings. |
| * |
| * @return <tt>true</tt> in case there are warnings, otherwise |
| * <tt>false</tt> |
| */ |
| public boolean hasWarnings () { |
| if (this.warnings == null || this.warnings.size() == 0) |
| return false; |
| return true; |
| }; |
| |
| |
| /** |
| * Return all warnings. |
| * |
| * @return {@link Messages} representing all warnings |
| */ |
| @JsonIgnore |
| public Messages getWarnings () { |
| return this.warnings; |
| }; |
| |
| |
| /** |
| * Set warnings by means of a {@link JsonNode}. |
| * |
| * @param msgs |
| * JSON array of warnings. |
| * @return {@link Notifications} object for chaining. |
| */ |
| public Notifications setWarnings (JsonNode msgs) { |
| for (JsonNode msg : msgs) |
| this.addWarning(msg); |
| return this; |
| }; |
| |
| |
| |
| /** |
| * Return a specific warning based on an index. |
| * |
| * @param index |
| * The index of the warning in the list of warnings. |
| * @return The message in case it exists, otherwise |
| * <code>null</code> |
| */ |
| @JsonIgnore |
| public Message getWarning (int index) { |
| if (this.warnings != null) |
| return this.warnings.get(index); |
| return (Message) null; |
| }; |
| |
| |
| /** |
| * Appends a new warning. |
| * |
| * @param code |
| * Integer code representation of the warning |
| * @param msg |
| * String representation of the warning |
| * @param terms |
| * Optional strings of additional information |
| * @return Notification object for chaining |
| */ |
| public Notifications addWarning (int code, String msg, String ... terms) { |
| |
| if (this.warnings == null) { |
| this.warnings = new Messages(); |
| }; |
| |
| this.warnings.add(code, msg, terms); |
| |
| return this; |
| }; |
| |
| |
| /** |
| * Appends a new warning. |
| * |
| * @param node |
| * {@link JsonNode} representing a warning message |
| * @return Notification object for chaining |
| */ |
| public Notifications addWarning (JsonNode node) { |
| if (this.warnings == null) |
| this.warnings = new Messages(); |
| |
| try { |
| this.warnings.add(node); |
| } |
| catch (QueryException qe) { |
| this.warnings.add(qe.getErrorCode(), qe.getMessage()); |
| }; |
| |
| return this; |
| }; |
| |
| |
| /** |
| * Appends new warnings. |
| * |
| * @param msgs |
| * {@link Messages} representing multiple warnings |
| * @return Notification object for chaining |
| */ |
| public Notifications addWarnings (Messages msgs) { |
| if (this.warnings == null) |
| this.warnings = msgs; |
| else |
| this.warnings.add(msgs); |
| return this; |
| }; |
| |
| |
| /** |
| * Return all errors. |
| * |
| * @return The {@link Messages} object representing all errors |
| */ |
| @JsonIgnore |
| public Messages getErrors () { |
| return this.errors; |
| }; |
| |
| |
| /** |
| * Set errors by means of a {@link JsonNode}. |
| * |
| * @param msgs |
| * JSON array of errors. |
| * @return Notifications object for chaining. |
| */ |
| public Notifications setErrors (JsonNode msgs) { |
| for (JsonNode msg : msgs) |
| this.addError(msg); |
| return this; |
| }; |
| |
| |
| /** |
| * Return a specific error based on an index. |
| * |
| * @param index |
| * The index of the error in the list of errors. |
| * @return The message in case it exists, otherwise |
| * <code>null</code> |
| */ |
| @JsonIgnore |
| public Message getError (int index) { |
| if (this.errors != null) |
| return this.errors.get(index); |
| return (Message) null; |
| }; |
| |
| |
| /** |
| * Check for errors. |
| * |
| * @return <tt>true</tt> in case there are errors, otherwise |
| * <tt>false</tt> |
| */ |
| public boolean hasErrors () { |
| if (this.errors == null || this.errors.size() == 0) |
| return false; |
| return true; |
| }; |
| |
| |
| /** |
| * Appends a new error. |
| * |
| * @param code |
| * Integer code representation of the error |
| * @param msg |
| * String representation of the error |
| * @param terms |
| * Optional strings of additional information |
| * @return Notification object for chaining |
| */ |
| public Notifications addError (int code, String msg, String ... terms) { |
| if (this.errors == null) |
| this.errors = new Messages(); |
| this.errors.add(code, msg, terms); |
| return this; |
| }; |
| |
| public Notifications addError (int code, String[] terms) { |
| if (this.errors == null) |
| this.errors = new Messages(); |
| this.errors.add(code, terms[0], Arrays.copyOfRange(terms, 1, terms.length)); |
| return this; |
| } |
| |
| /** |
| * Appends a new error. |
| * |
| * @param node |
| * {@link JsonNode} representing an error message |
| * @return Notification object for chaining |
| */ |
| public Notifications addError (JsonNode msg) { |
| if (this.errors == null) |
| this.errors = new Messages(); |
| try { |
| this.errors.add(msg); |
| } |
| catch (QueryException qe) { |
| this.errors.add(qe.getErrorCode(), qe.getMessage()); |
| }; |
| |
| return this; |
| }; |
| |
| |
| /** |
| * Appends new errors. |
| * |
| * @param msgs |
| * {@link Messages} representing multiple errors |
| * @return Notification object for chaining |
| */ |
| public Notifications addErrors (Messages msgs) { |
| if (this.errors == null) |
| this.errors = msgs; |
| else |
| this.errors.add(msgs); |
| return this; |
| }; |
| |
| |
| /** |
| * Return all messages. |
| * |
| * @return {@link Messages} representing all messages |
| */ |
| @JsonIgnore |
| public Messages getMessages () { |
| return this.messages; |
| }; |
| |
| |
| /** |
| * Set messages by means of a {@link JsonNode}. |
| * |
| * @param msgs |
| * JSON array of messages. |
| * @return Notifications object for chaining. |
| */ |
| public Notifications setMessages (JsonNode msgs) { |
| for (JsonNode msg : msgs) |
| this.addMessage(msg); |
| return this; |
| }; |
| |
| |
| /** |
| * Return a specific message based on an index. |
| * |
| * @param index |
| * The index of the message in the list of messages. |
| * @return The message in case it exists, otherwise |
| * <code>null</code> |
| */ |
| @JsonIgnore |
| public Message getMessage (int index) { |
| if (this.messages != null) |
| return this.messages.get(index); |
| return (Message) null; |
| }; |
| |
| |
| /** |
| * Check for messages. |
| * |
| * @return <tt>true</tt> in case there are messages, otherwise |
| * <tt>false</tt> |
| */ |
| public boolean hasMessages () { |
| if (this.messages == null || this.messages.size() == 0) |
| return false; |
| return true; |
| }; |
| |
| |
| /** |
| * Appends a new message. |
| * |
| * @param code |
| * Integer code representation of the message |
| * @param msg |
| * String representation of the message |
| * @param terms |
| * Optional strings of additional information |
| * @return Notification object for chaining |
| */ |
| public Notifications addMessage (int code, String msg, String ... terms) { |
| if (this.messages == null) |
| this.messages = new Messages(); |
| this.messages.add(code, msg, terms); |
| return this; |
| }; |
| |
| |
| /** |
| * Appends a new message. |
| * |
| * @param node |
| * {@link JsonNode} representing a message |
| * @return Notification object for chaining |
| */ |
| public Notifications addMessage (JsonNode msg) { |
| if (this.messages == null) |
| this.messages = new Messages(); |
| try { |
| this.messages.add(msg); |
| } |
| catch (QueryException qe) { |
| this.messages.add(qe.getErrorCode(), qe.getMessage()); |
| }; |
| return this; |
| }; |
| |
| |
| /** |
| * Appends new messages. |
| * |
| * @param msgs |
| * {@link Messages} representing multiple messages |
| * @return Notification object for chaining |
| */ |
| public Notifications addMessages (Messages msgs) { |
| if (this.messages == null) |
| this.messages = msgs; |
| else |
| this.messages.add(msgs); |
| return this; |
| }; |
| |
| |
| /** |
| * Copy notifications from another notification object. |
| * |
| * @param notes |
| * Notification object to copy notifications from. |
| * @return Notification object for chaining |
| */ |
| public Notifications copyNotificationsFrom (Notifications notes) { |
| try { |
| if (notes.hasErrors()) |
| this.addErrors((Messages) notes.getErrors().clone()); |
| if (notes.hasWarnings()) |
| this.addWarnings((Messages) notes.getWarnings().clone()); |
| if (notes.hasMessages()) |
| this.addMessages((Messages) notes.getMessages().clone()); |
| } |
| catch (CloneNotSupportedException cnse) {}; |
| return this; |
| }; |
| |
| |
| /** |
| * Copy notifications from a {@link JsonNode} object. |
| * |
| * @param request |
| * Notifications containing {@link JsonNode}. |
| * @return Notification object for chaining |
| */ |
| public Notifications copyNotificationsFrom (JsonNode request) { |
| |
| // Add warnings from JSON |
| if (request.has("warnings") && request.get("warnings").isArray()) { |
| JsonNode msgs = request.get("warnings"); |
| for (JsonNode msg : msgs) |
| this.addWarning(msg); |
| }; |
| |
| // Add messages from JSON |
| if (request.has("messages") && request.get("messages").isArray()) { |
| JsonNode msgs = request.get("messages"); |
| if (msgs.isArray()) |
| for (JsonNode msg : msgs) |
| this.addMessage(msg); |
| }; |
| |
| // Add errors from JSON |
| if (request.has("errors") && request.get("errors").isArray()) { |
| JsonNode msgs = request.get("errors"); |
| if (msgs.isArray()) |
| for (JsonNode msg : msgs) |
| this.addError(msg); |
| }; |
| |
| return this; |
| }; |
| |
| |
| /** |
| * Move notifications from a passed {@link Notification} object |
| * to the invocant. |
| * |
| * @param notes |
| * Notification object. |
| * @return The invocant object for chaining |
| */ |
| public Notifications moveNotificationsFrom (Notifications notes) { |
| this.copyNotificationsFrom(notes); |
| notes.clearNotifications(); |
| return this; |
| }; |
| |
| |
| /** |
| * Clear all notifications. |
| * |
| * @return Notification object for chaining |
| */ |
| public Notifications clearNotifications () { |
| if (this.warnings != null) |
| this.warnings.clear(); |
| if (this.messages != null) |
| this.messages.clear(); |
| if (this.errors != null) |
| this.errors.clear(); |
| return this; |
| }; |
| |
| |
| |
| /** |
| * Serialize Notifications as a {@link JsonNode}. |
| * |
| * @return {@link JsonNode} representation of all warnings, |
| * errors, and messages. |
| */ |
| public JsonNode toJsonNode () { |
| ObjectNode json = mapper.createObjectNode(); |
| |
| // Add messages |
| if (this.hasWarnings()) |
| json.put("warnings", this.getWarnings().toJsonNode()); |
| if (this.hasErrors()) |
| json.put("errors", this.getErrors().toJsonNode()); |
| if (this.hasMessages()) |
| json.put("messages", this.getMessages().toJsonNode()); |
| |
| return (JsonNode) json; |
| }; |
| |
| |
| /** |
| * Serialize Notifications as a JSON string. |
| * <p> |
| * <blockquote><pre> |
| * { |
| * "errors": [ |
| * [123, "You are not allowed to serialize these messages"], |
| * [124, "Your request was invalid"] |
| * ], |
| * "messages" : [ |
| * [125, "Class is deprecated", "Notifications"] |
| * ] |
| * } |
| * </pre></blockquote> |
| * |
| * @return String representation of all warnings, errors, and |
| * messages |
| */ |
| public String toJsonString () { |
| String msg = ""; |
| try { |
| JsonNode node = this.toJsonNode(); |
| if (node == null) |
| return "{}"; |
| return mapper.writeValueAsString(node); |
| } |
| catch (Exception e) { |
| // Bad in case the message contains quotes! |
| msg = ", " + quote(e.getLocalizedMessage()); |
| }; |
| |
| return "{\"errors\" : [" + "[620, " + "\"Unable to generate JSON\"" |
| + msg + "]" + "]}"; |
| }; |
| }; |