package com.joe.utilities.core.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
/**
* A ReturnStatus can be commonly used to return the status of a function. The status is composed of zero or more status items that
* contribute to the general Return Status. Zero elements would indicate that the return status is completely OK. The one or more
* ReturnStatusItem instance may each point to a error, warning condition, or informational message Errors will block the current flow of
* business logic. Warnings will usually lead to an interactive decision by the presentation layer to treat the condition as an error or not
* or possibly identify a condition that will turn into an error later in a workflow. Informational status items refer to successful
* execution but with an advisory message included in the return. The ReturnStatus will determine a general status based on the presence and
* status of its component items.
*
* @author Dave Ousey Creation date: 1/16/2007 9 AM Copyright (c) 2007 MEDecision, Inc. All rights reserved.
*/
public class ReturnStatus {
public enum Status {
OK, WARNING, ERROR, INFORMATIONAL, UNKNOWN
};
/**
* Contains map from unique status item code to the status item. This allows status items to be added and removed more easily based on
* their unique code.
*/
private TreeMap<String, ReturnStatusItem[]> statusItems = new TreeMap<String, ReturnStatusItem[]>();
/**
* Simple constructor
*/
public ReturnStatus() {}
/**
* Constructs this ReturnStatus using another as a starting point
*
* @param existingStatus
*/
public ReturnStatus(ReturnStatus existingStatus) {
appendStatusItems(existingStatus);
}
/**
* Method getStatus. Return status derived from the state of the contained status items. If any errors exist then general status is
* Error. Else if any warnings exist then general status is Warning Else if any informational items exist then general status is
* Informational Else Status is OK
*
* @return Status
*/
public Status getStatus() {
boolean warningsExist = false;
boolean informationalMessagesExist = false;
for (ReturnStatusItem[] items : statusItems.values()) {
for (ReturnStatusItem item : items) {
// If one error exists, then general status is an error
if (!item.isSuccess()) {
return Status.ERROR;
}
if (item.getStatus() == Status.WARNING) {
warningsExist = true;
} else if (item.getStatus() == Status.INFORMATIONAL)
informationalMessagesExist = true;
}
}
if (warningsExist) {
return Status.WARNING;
} else if (informationalMessagesExist) {
return Status.INFORMATIONAL;
} else
return Status.OK;
}
/**
* Method addError. Create and add an error return status item
*
* @param code
* @return ReturnStatusItem
*/
public ReturnStatusItem addError(String code) {
return addReturnStatusItem(code, Status.ERROR, null, null);
}
/**
* Method addError.
*
* @param code
* @param description
* @return ReturnStatusItem
*/
public ReturnStatusItem addError(String code, String description) {
return addReturnStatusItem(code, Status.ERROR, description, null);
}
/**
* Method addError.
*
* @param code
* @param description
* @param parameterMap
* @return ReturnStatusItem
*/
public ReturnStatusItem addError(String code, String description, Map<String, String> parameterMap) {
return addReturnStatusItem(code, Status.ERROR, description, parameterMap);
}
/**
* Method addWarning. Create and add a warning return status item
*
* @param code
* @return ReturnStatusItem
*/
public ReturnStatusItem addWarning(String code) {
return addReturnStatusItem(code, Status.WARNING, null, null);
}
/**
* Method addWarning.
*
* @param code
* @param description
* @return ReturnStatusItem
*/
public ReturnStatusItem addWarning(String code, String description) {
return addReturnStatusItem(code, Status.WARNING, description, null);
}
/**
* Adds / Replaces the current warning based on code. This assumes that this code/description is the most accurate. If an
* error/information message was added with the same code then this method will replace that message with the new warning.
*
* @param code Unique Code to identify the warning
* @param description The description associated with the code.
* @return ReturnStatusItem The latest return status item.
*/
public ReturnStatusItem addReplaceUniqueWarning(String code, String description) {
if (hasItemWithCode(code)) {
clearItemWithCode(code);
}
return addWarning(code, description);
}
/**
* Method addWarning.
*
* @param code
* @param description
* @param parameterMap
* @return ReturnStatusItem
*/
public ReturnStatusItem addWarning(String code, String description, Map<String, String> parameterMap) {
return addReturnStatusItem(code, Status.WARNING, description, parameterMap);
}
/**
* Adds the <code>ReturnStatusItem</code> given by the parameters to the map of statusItems. If the status code already exists in the
* map, it adds the newly created <code>ReturnStatusItem</code> to the <code>ReturnStatusItem[]</code>. This allows the addition of
* multiple status messages for one error code.
*
* @param code <code>String</code> error code.
* @param description <code>String</code> error description.
* @param parameterMap <code>Map</string> (<code>String, String</code>) containing the parameters to inject into the status message.
* @return ReturnStatusItem the <code>ReturnStatusItem</code> given by the parameters.
*/
public ReturnStatusItem addReturnStatusItem(String code, Status status, String description, Map<String, String> parameterMap) {
ReturnStatusItem item = new ReturnStatusItem(code, status, description, parameterMap);
addReturnStatusItemInternal(code, item);
return item;
}
/**
* Adds the <code>ReturnStatusItem</code> given by the parameters to the map of statusItems. If the status code already exists in the
* map, it adds the newly created <code>ReturnStatusItem</code> to the <code>ReturnStatusItem[]</code>. This allows the addition of
* multiple status messages for one error code.
*
* @param code <code>String</code> error code.
* @param description <code>String</code> error description.
* @param parameterMap <code>Map</string> (<code>String, String</code>) containing the parameters to inject into the status message.
* @return ReturnStatusItem the <code>ReturnStatusItem</code> given by the parameters.
*/
public ReturnStatusItem addReturnStatusItem(String code, Status status, String description, Map<String, String> parameterMap, String ruleResult) {
ReturnStatusItem item = new ReturnStatusItem(code, status, description, parameterMap);
addReturnStatusItemInternal(code, item);
return item;
}
/**
* Internal little method that is used by {@link #addReturnStatusItem(String, Status, String, Map)} and {@link #addReturnStatusItem(String, Status, String, Map, String)}
* @param code
* @param item
*/
private void addReturnStatusItemInternal(String code, ReturnStatusItem item) {
if (statusItems.get(code) != null) {
ReturnStatusItem[] items = statusItems.get(code);
ReturnStatusItem[] newItems = new ReturnStatusItem[items.length + 1];
System.arraycopy(items, 0, newItems, 0, items.length);
newItems[newItems.length - 1] = item;
statusItems.put(code, newItems);
} else {
statusItems.put(code, new ReturnStatusItem[] { item });
}
}
/**
* Takes the list of errors/warnings/messages/information associated with the return status object and adds those to the current status
* item. The values in the input list take priority and will overwrite the values in the internal class list.
*
* @param returnStatus the list of errors/warnings/messages/information to be placed in the current list.
*/
public void appendStatusItems(ReturnStatus returnStatus) {
if ( returnStatus == null ||
returnStatus.statusItems == null
){
return;
}
statusItems.putAll(returnStatus.statusItems);
}
/**
* Takes the list of errors/warnings/messages/information associated with the return status object and adds those to the current status
* item. If an key for a code is in both lists then the return status items will be merged. The final list will contain return status
* items from the original and the input list.
*
* @param returnStatus the list of errors/warnings/messages/information to be placed in the current list.
*/
public void mergeStatusItems(ReturnStatus returnStatus) {
if (returnStatus == null) {
return;
}
for (String key : returnStatus.getStatusItemCodes()) {
if (!(this.statusItems.containsKey(key))) {
this.statusItems.put(key, returnStatus.getReturnStatusItemsForCode(key));
} else {
Set<ReturnStatusItem> thisStatusItems = setFromArray(this.getReturnStatusItemsForCode(key));
Set<ReturnStatusItem> paramStatusItems = setFromArray(returnStatus.getReturnStatusItemsForCode(key));
thisStatusItems.addAll(paramStatusItems);
this.statusItems.put(key, thisStatusItems.toArray(new ReturnStatusItem[thisStatusItems.size()]));
}
}
}
private Set<ReturnStatusItem> setFromArray(ReturnStatusItem[] items) {
Set<ReturnStatusItem> set = new TreeSet<ReturnStatusItem>();
for (ReturnStatusItem item : items) {
set.add(item);
}
return set;
}
/**
* /** Method hasErrors.
*
* @return boolean
*/
public boolean hasErrors() {
for (ReturnStatusItem item : this.getResultStatusItems()) {
if (item.getStatus() == Status.ERROR) {
return true;
}
}
return false;
}
/**
* Method hasErrorsOrWarnings.
*
* @return boolean
*/
public boolean hasErrorsOrWarnings() {
for (ReturnStatusItem item : this.getResultStatusItems()) {
if (item.getStatus() == Status.ERROR || item.getStatus() == Status.WARNING) {
return true;
}
}
return false;
}
/**
* Method hasWarnings.
*
* @return boolean
*/
public boolean hasWarnings() {
for (ReturnStatusItem item : this.getResultStatusItems()) {
if (item.getStatus() == Status.WARNING) {
return true;
}
}
return false;
}
/**
* Method isSuccess. If any status items are not successful, then return false; else true
*
* @return boolean
*/
public boolean isSuccess() {
for (ReturnStatusItem item : this.getResultStatusItems()) {
if (!item.isSuccess()) {
return false;
}
}
return true;
}
/**
* Method getResultStatusItems. Return the items
*
* @return ReturnStatusItem[]
*/
public ReturnStatusItem[] getResultStatusItems() {
List<ReturnStatusItem> itemList = new ArrayList<ReturnStatusItem>();
for (ReturnStatusItem[] items : statusItems.values()) {
for (ReturnStatusItem item : items) {
itemList.add(item);
}
}
return itemList.toArray(new ReturnStatusItem[itemList.size()]);
}
/**
* Method getErrorResultStatusItems. Get errors
*
* @return ReturnStatusItem[]
*/
public ReturnStatusItem[] getErrorResultStatusItems() {
return getResultStatusItemsWithStatus(Status.ERROR);
}
/**
* Method getWarningResultStatusItems. Get errors
*
* @return ReturnStatusItem[]
*/
public ReturnStatusItem[] getWarningResultStatusItems() {
return getResultStatusItemsWithStatus(Status.WARNING);
}
/**
* Method getInformationalResultStatusItems. Get errors
*
* @return ReturnStatusItem[]
*/
public ReturnStatusItem[] getInformationalResultStatusItems() {
return getResultStatusItemsWithStatus(Status.INFORMATIONAL);
}
/**
* Method getStatusItemCode.
*
* @return Set<String>
*/
public Set<String> getStatusItemCodes() {
return Collections.unmodifiableSet(statusItems.keySet());
}
/**
* Method hasItemWithCode. Determines if given code exists in the set.
*
* @param code
* @return boolean
*/
public boolean hasItemWithCode(String code) {
return statusItems.containsKey(code);
}
/**
* Method hasAnyItemsInCodeSet.
*
* @param codes
* @return boolean
*/
public boolean hasAnyItemsInCodeSet(Set<String> codes) {
if (codes == null) {
return false;
}
for (String code : codes) {
if (statusItems.keySet().contains(code)) {
return true;
}
}
return false;
}
/**
* Returns the array of <code>ReturnStatusItem</code>'s associated with the given status code.
*
* @param code status code used to retrieve the status items with.
* @return <code>ReturnStatusItem[]</code> that corresponds to the given status code.
*/
public ReturnStatusItem[] getReturnStatusItemsForCode(String code) {
return this.statusItems.get(code);
}
/**
* Method clearItemWithCode. Deletes the item with the given code
*
* @param code
* @return void
*/
public void clearItemWithCode(String code) {
statusItems.remove(code);
}
/**
* Method getResultStatusItemsWithStatus. Return the items
*
* @return ReturnStatusItem[]
*/
private ReturnStatusItem[] getResultStatusItemsWithStatus(Status status) {
List<ReturnStatusItem> itemList = new ArrayList<ReturnStatusItem>();
for (ReturnStatusItem item : this.getResultStatusItems()) {
if (item.getStatus() == status) {
itemList.add(item);
}
}
return itemList.toArray(new ReturnStatusItem[itemList.size()]);
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuffer returnValue = new StringBuffer(this.getClass().getName());
returnValue.append("(");
for (ReturnStatusItem[] items : statusItems.values()) {
for (ReturnStatusItem item : items) {
returnValue.append(item);
returnValue.append(",");
}
returnValue.append(";");
}
returnValue.append(")");
return returnValue.toString();
}
/**
* Method createErrorReturnStatus. Convenience method to create
*
* @param errorCode
* @param defaultMessage
* @return ReturnStatus
*/
public static ReturnStatus createErrorReturnStatus(String errorCode, String defaultMessage) {
ReturnStatus returnStatus = new ReturnStatus();
returnStatus.addError(errorCode, defaultMessage);
return returnStatus;
}
public void appendStatusItems(Collection<ReturnStatusItem> items) {
if ( items == null || items.size() == 0){
return;
}
for(ReturnStatusItem item: items){
addReturnStatusItem(item.getCode(), item.getStatus(), item.getDefaultMessage(), item.getParameterMap());
}
}
}