/**
* Copyright 2008-2016 Qualogy Solutions B.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qualogy.qafe.core.errorhandling;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.logging.Logger;
import org.apache.commons.lang.StringUtils;
import com.qualogy.qafe.bind.commons.error.ErrorHandler;
import com.qualogy.qafe.bind.commons.error.ServiceError;
import com.qualogy.qafe.bind.core.application.ApplicationContext;
import com.qualogy.qafe.bind.item.Item;
import com.qualogy.qafe.bind.presentation.component.Window;
import com.qualogy.qafe.bind.presentation.event.Event;
import com.qualogy.qafe.bind.presentation.event.function.EventRef;
import com.qualogy.qafe.core.datastore.DataIdentifier;
import com.qualogy.qafe.core.datastore.DataStore;
import com.qualogy.qafe.core.i18n.MessagesHandler;
public class ErrorProcessor {
private final static Logger logger = Logger.getLogger(ErrorProcessor.class.getName());
public static ErrorResult processError(ListIterator<? extends Item> itrItem, Item triggeredItem, ApplicationContext context, DataIdentifier dataId, ExternalException externalException) {
ErrorResult errorResult = processError(itrItem, triggeredItem, context, null, dataId, externalException, logger);
return errorResult;
}
public static ErrorResult processError(ListIterator<? extends Item> itrItem, Item triggeredItem, ApplicationContext context, Window window, DataIdentifier dataId, ExternalException externalException, Logger log) {
if (externalException == null) {
throw new IllegalArgumentException("ExternalException is null, and therefore cannot be processed");
}
if (externalException.getCause() == null) {
throw new IllegalArgumentException("ExternalException cause is null, and therefore cannot be processed");
}
ErrorResult errorResult = new ErrorResult();
ErrorHandler errorHandler = null;
try {
if (itrItem != null) {
List<ErrorHandler> errorHandlerList = getErrorHandlers(itrItem, context, window);
errorHandler = resolveErrorHandler(errorHandlerList, externalException);
if (errorHandler != null) {
log.fine("ErrorHandler found for exception [" + externalException.getCause().getClass() + "], continue in alternative path");
logError(errorHandler, context, dataId, log);
errorResult.setItems(errorHandler.getResultItems());
// Go to the position of the errorHandler,
// so further processing can be continued
goBackToItemPosition(itrItem, errorHandler, context, window);
}
}
} finally {
// Rethrow if handler is not defined (no action specified)
// or handler specifies that the exception should be rethrown
errorResult = resolveRethrow(errorResult, errorHandler, externalException);
if (externalException.getCause() != null) {
String errorMessage = externalException.getErrorMessage();
if (errorMessage == null) {
errorMessage = externalException.getMessage();
}
DataStore.store(dataId, DataStore.KEY_ERROR_MESSAGE, errorMessage);
}
}
return errorResult;
}
private static ErrorResult resolveRethrow(ErrorResult errorResult, ErrorHandler errorHandler, ExternalException externalException) {
if ((errorHandler == null) || ErrorHandler.FINALLY_RETHROW.equals(errorHandler.getFinalAction())) {
errorResult.setExternalException(externalException);
}
return errorResult;
}
private static ErrorHandler resolveErrorHandler(List<ErrorHandler> errorHandlers, ExternalException externalException) {
ErrorHandler errorHandler = null;
if ((errorHandlers != null) && (externalException != null)) {
String exceptionMessage = externalException.getCause().toString();
Map<String,Class<?>> exceptionClassHierarchy = resolveExceptionClassHierarchy(externalException);
for (ErrorHandler handler : errorHandlers) {
if (handler instanceof ErrorHandler){
ServiceError serviceError = ((ErrorHandler)handler).getErrorRef().getRef();
String exception = serviceError.getException();
boolean found = false;
if ((exceptionClassHierarchy != null) && exceptionClassHierarchy.containsKey(exception)) {
found = true;
} else if ((exceptionMessage != null) && exceptionMessage.contains(exception)) {
found = true;
}
if (found) {
errorHandler = handler;
break;
}
}
}
}
return errorHandler;
}
private static Map<String,Class<?>> resolveExceptionClassHierarchy(ExternalException externalException) {
Map<String,Class<?>> exceptionClassHierarchy = new LinkedHashMap<String,Class<?>>();
if (externalException != null) {
Class<?> exceptionClass = externalException.getCause().getClass();
while (exceptionClass != null) {
String qualifiedClassName = exceptionClass.getName();
exceptionClassHierarchy.put(qualifiedClassName, exceptionClass);
exceptionClass = exceptionClass.getSuperclass();
if (exceptionClass.equals(Object.class)) {
exceptionClass = null;
}
}
}
return exceptionClassHierarchy;
}
private static List<ErrorHandler> getErrorHandlers(ListIterator<? extends Item> itrItem, ApplicationContext context, Window window) {
List<ErrorHandler> errorHandlerList = new ArrayList<ErrorHandler>();
if (itrItem != null) {
while (itrItem.hasNext()) {
Item item = itrItem.next();
if (item instanceof ErrorHandler) {
errorHandlerList.add((ErrorHandler)item);
} else if (item instanceof EventRef) {
EventRef eventRef = (EventRef)item;
String eventId = eventRef.getEvent();
Event event = getEvent(eventId, context, window);
if (event != null) {
List<ErrorHandler> errorHandlers = getErrorHandlers(event.getEventItems().listIterator(), context, window);
if (errorHandlers != null) {
errorHandlerList.addAll(errorHandlers);
}
}
}
}
}
return errorHandlerList;
}
private static void goBackToItemPosition(ListIterator<? extends Item> itrItem, Item targetItem, ApplicationContext context, Window window) {
if (itrItem != null) {
boolean found = false;
while (itrItem.hasPrevious()) {
Item item = itrItem.previous();
if (item == targetItem) {
found = true;
} else if (item instanceof EventRef) {
found = containsItem((EventRef)item, targetItem, context, window);
}
if (found) {
itrItem.next();
break;
}
}
}
}
private static boolean containsItem(EventRef eventRef, Item targetItem, ApplicationContext context, Window window) {
boolean result = false;
if (eventRef == null) {
return result;
}
String eventId = eventRef.getEvent();
Event event = getEvent(eventId, context, window);
if (event != null) {
Iterator<? extends Item> itrItem = event.getEventItems().iterator();
while (itrItem.hasNext()) {
Item item = itrItem.next();
if (item == targetItem) {
result = true;
} else if (item instanceof EventRef) {
result = containsItem((EventRef)item, targetItem, context, window);
}
if (result) {
break;
}
}
}
return result;
}
private static Event getEvent(String eventId, ApplicationContext context, Window window) {
Event event = null;
if (window != null) {
event = window.getEventsMap().get(eventId);
}
if (event == null) {
event = context.getApplicationMapping().getPresentationTier().getEventsMap().get(eventId);
}
return event;
}
private static void logError(ErrorHandler errorHandler, ApplicationContext context, DataIdentifier dataId, Logger log) {
if ((errorHandler.getErrorRef() != null) && (errorHandler.getErrorRef().getRef() != null)) {
ServiceError serviceError = errorHandler.getErrorRef().getRef();
if (serviceError.getLoggingSettings() != null) {
String message = "";
String messageKey = serviceError.getLoggingSettings().getMessageKey();
if (messageKey != null) {
message += MessagesHandler.getMessage(context, dataId, messageKey);
}
String solutionKey = serviceError.getLoggingSettings().getSolutionKey();
if(solutionKey != null) {
message += MessagesHandler.getMessage(context, dataId, solutionKey);
}
String errorMessage = serviceError.getLoggingSettings().getErrorMessage();
if (StringUtils.isBlank(message) && (errorMessage != null)) {
message += errorMessage;
}
if(!StringUtils.isBlank(message)) {
log.severe(message);
}
}
}
}
// TBD
// /**
// * Method processes the items accordingly to the ErrorHandler if the exception caught applies to this errorhandler
// * @param context
// * @param id
// * @param iter
// * @param t
// * @throws UnableToProcessException
// */
// public static ErrorResult processError(ApplicationContext context, DataIdentifier id, ListIterator<?> iter, ExternalException externalException){
//
// if(externalException == null)
// throw new IllegalArgumentException("null externalException cannot be processed");
//
// if(externalException.getCause() == null)
// throw new IllegalArgumentException("externalexception cause is null, and therefore cannot be processed");
//
// ErrorResult result = new ErrorResult();
// ErrorHandler handler = null;
// try{
// if(iter!=null && iter.hasNext()){
// List<Item> handlers = getHandlers(iter);
//
// handler = selectHandler(handlers, externalException.getCause().getClass(), 0);
//
// if(handler!=null){
//
// logger.debug("handler found for exception ["+externalException.getCause().getClass()+"], continue in alternative path");
// logError(handler, context, id);
//
// result.setItems(handler.getResultItems());
//
// }
// }
// }finally{
// result = handleException(result, handler, externalException);
// if(externalException.getCause()!=null)
// DataStore.store(id, DataStore.KEY_ERROR_MESSAGE, externalException.getCause().getMessage());
// }
// return result;
// }
//
// private static ErrorHandler selectHandler(List<Item> handlers, Class<?> exceptionClass, int level) {
// ErrorHandler handler = null;
// Class<?> classToCheck = getExceptionClass(exceptionClass, level);
//
// if(classToCheck!=null){
// for (Item item : handlers) {
// if (item instanceof ErrorHandler){
// ErrorHandler aHandler = (ErrorHandler) item;
// Class<?> handlerClass = aHandler.getErrorRef().getRef().getErrorClass();
//
// if(handlerClass.equals(classToCheck)){
// handler = aHandler;
// }
// }
// }
//
//
// if(handler==null)
// selectHandler(handlers, exceptionClass, 1+level);
// }
// return handler;
// }
//
// private static Class<?> getExceptionClass(Class<?> exceptionClass, int level) {
// Class<?> clazz = exceptionClass;
// for (int i = 0; i < level; i++) {
// clazz = clazz.getSuperclass();
// if(clazz.equals(Object.class)){
// clazz = null;
// break;
// }
// }
// return clazz;
// }
//
// private static List<Item> getHandlers(ListIterator<?> iter) {
// List<Item> handlers = new ArrayList<Item>();
// while(iter.hasNext()) {
// Object o = iter.next();
// if (o instanceof Item){
// Item item = (Item)o;
// if(!(item instanceof ErrorHandler)){
// if(iter.hasPrevious())iter.previous();//reset to last position
// break;
// }
// handlers.add(item);
// }
// }
// return handlers;
// }
//
// private static void logError(ErrorHandler handler, ApplicationContext context, DataIdentifier id) {
// if(handler.getErrorRef()!=null && handler.getErrorRef().getRef()!=null){
// ServiceError error = handler.getErrorRef().getRef();
// if(error.getLoggingSettings()!=null){
// String message = "";
//
// if(error.getLoggingSettings().getMessageKey()!=null)
// message += MessagesHandler.getMessage(context, id, error.getLoggingSettings().getMessageKey());
// if(error.getLoggingSettings().getSolutionKey()!=null)
// message += MessagesHandler.getMessage(context, id, error.getLoggingSettings().getSolutionKey());
// if(StringUtils.isBlank(message) && error.getLoggingSettings().getErrorMessage()!=null)
// message += error.getLoggingSettings().getErrorMessage();
//
// if(!StringUtils.isBlank(message))
// logger.error(message);
// }
// }
// }
//
// /**
// * If handler is null (no action specified) or handler specifies the exception should be
// * rethrown this method throws the exception given, otherwise swallows the exception.
// * @param handler
// * @param t
// */
// private static ErrorResult handleException(ErrorResult result, ErrorHandler handler, ExternalException externalException){
// if(handler == null || ErrorHandler.FINALLY_RETHROW.equals(handler.getFinalAction())){
// result.setExternalException(externalException);
// }
// return result;
// }
}