/**
* 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.business.integration.java;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import org.apache.commons.lang.math.NumberUtils;
import com.qualogy.qafe.bind.commons.type.Parameter;
import com.qualogy.qafe.bind.core.application.ApplicationContext;
import com.qualogy.qafe.bind.core.messages.HasMessage;
import com.qualogy.qafe.bind.integration.service.Method;
import com.qualogy.qafe.bind.integration.service.Service;
import com.qualogy.qafe.bind.resource.JavaResource;
import com.qualogy.qafe.business.integration.Processor;
import com.qualogy.qafe.business.integration.adapter.AdaptedToService;
import com.qualogy.qafe.business.integration.filter.Filters;
import com.qualogy.qafe.business.integration.filter.page.Page;
import com.qualogy.qafe.business.integration.filter.sort.ComparatorFactory;
import com.qualogy.qafe.business.integration.filter.sort.Sort;
import com.qualogy.qafe.business.integration.filter.sort.comparators.SortComparator;
import com.qualogy.qafe.business.resource.ResourcePool;
import com.qualogy.qafe.business.resource.java.JavaClass;
import com.qualogy.qafe.core.datastore.DataIdentifier;
import com.qualogy.qafe.core.datastore.DataStore;
import com.qualogy.qafe.core.errorhandling.ExternalException;
/**
* actual executer of the method on the service
* @author Marc van der Wurff
*
*/
public class JavaServiceProcessor extends Processor {
public final static Logger logger = Logger.getLogger(JavaServiceProcessor.class.getName());
protected void postProcess(DataIdentifier dataId, Method method, Filters filters) throws ExternalException {
if (filters != null) {
if (filters.getSort() != null) {
processSorting(dataId, method.getOutput(), filters.getSort());
}
if (filters.getPage() != null) {
processPaging(dataId, method.getOutput(), filters.getPage());
}
}
}
private void processSorting(DataIdentifier dataId, List outputMapping, Sort sort) {
if ((outputMapping != null) && (sort != null)) {
String sortColumn = sort.getColumn();
boolean sortAscending = Sort.ASCENDING.equalsIgnoreCase(sort.getSortOrder());
if (sortColumn != null) {
for (Iterator iter1=outputMapping.iterator(); iter1.hasNext();) {
Parameter param = (Parameter)iter1.next();
if (param.getName() != null) {
Object value = DataStore.getValue(dataId, param.getName());
if (value instanceof List) {
List valueList = (List)value;
if (valueList.size() > 0) {
Object entry = valueList.get(0);
Object item = SortComparator.getValue(entry, sortColumn);
Comparator sortComparator = ComparatorFactory.createComparator(sortColumn, sortAscending, item);
if (sortComparator != null) {
Collections.sort(valueList, sortComparator);
}
}
}
}
}
}
}
}
private void processPaging(DataIdentifier dataId, List outputMapping, Page page) {
if ((outputMapping != null) && (page.getMaxRows() > 0)) {
int offsetStart;
int offsetEnd;
int pageSize = page.getMaxRows();
int currentPage = page.getOffset();
for (Iterator iter1=outputMapping.iterator(); iter1.hasNext();) {
Parameter param = (Parameter)iter1.next();
if (param.getName() != null) {
Object value = DataStore.getValue(dataId, param.getName());
if (value instanceof List) {
List valueList = (List)value;
if (page.getOffset() == Integer.MAX_VALUE) {
int totalCount = valueList.size();
currentPage = Math.round(((float) totalCount / (float) pageSize) - 0.6f);
page.setOffset(currentPage);
}
offsetStart = Math.max(currentPage * pageSize, 0);
offsetEnd = offsetStart + pageSize - 1;
List newValueList = null;
if (offsetStart < valueList.size()) {
if (offsetEnd < valueList.size()) {
newValueList = valueList.subList(offsetStart, offsetEnd + 1);
} else {
newValueList = valueList.subList(offsetStart, valueList.size());
}
} else {
newValueList = new ArrayList();
}
DataStore.store(dataId, param.getName(), newValueList);
}
}
}
}
}
protected Object execute(ApplicationContext context, Service service, Method method, Map paramsIn, Filters filters, DataIdentifier dataId) throws ExternalException {
String actualMethodName = method.getName();
if(paramsIn == null)
throw new IllegalArgumentException("expecting a non-null paramsIn list");
//1. create instance
if(service.getResourceRef()==null || service.getResourceRef().getRef()==null || !(service.getResourceRef().getRef() instanceof JavaResource))
throw new IllegalArgumentException("resource 'javaclass' for javaservice must be set");
JavaClass resource = (JavaClass)ResourcePool.getInstance().get(context.getId(), service.getResourceRef().getRef().getId());
//2. determine param types and names
AdaptedToService methodParams[] = filterMethodParams(paramsIn);
Class[] parameterClasses = new Class[methodParams.length];
Object[] parameters = new Object[methodParams.length];
for (int i = 0; i < methodParams.length; i++) {
AdaptedToService adapted = methodParams[i];
if(adapted!=null){
parameters[i] = adapted.getValue();
// if(adapted.getClazz()==null){
// throw new UnableToProcessException("class for param [] cannot be determined");
// }
parameterClasses[i] = adapted.getClazz();
}
}
//3. execute method
return executeMethod(resource, actualMethodName, parameterClasses, parameters, context);
}
/**
* The actual method calll is processed in this method
* @param clazz
* @param parameterTypes
* @param instance
* @param parameters
* @param context
* @throws thrown when anything goes wrong upon calling the method
* @return the outcome
*/
private Object executeMethod(JavaClass resource, String actualMethodName, Class[] parameterClasses, Object[] parameters, ApplicationContext context) throws ExternalException{
Object instance = resource.getInstance();
Object result = null;
try{
result = resource.getMethod(actualMethodName, parameterClasses).invoke(instance, parameters);
if(instance instanceof HasMessage){
HasMessage hasMessage = (HasMessage)instance;
List<String> messages = hasMessage.getMessages();
for(String message: messages){
context.getWarningMessages().add(message);
}
}
}catch(NoSuchMethodException e){
String errorMessage = resolveErrorMessage(e);
throw new ExternalException(errorMessage, errorMessage, e);
}catch(InvocationTargetException e){
String errorMessage = resolveErrorMessage(e.getTargetException());
throw new ExternalException(e.getMessage(), errorMessage, e.getTargetException());
}catch(IllegalAccessException e){
String errorMessage = resolveErrorMessage(e);
throw new ExternalException(e.getMessage(), errorMessage, e.getCause());
}catch(Exception e){
String errorMessage = resolveErrorMessage(e);
throw new ExternalException(e.getMessage(), errorMessage, e.getCause());
}
return result;
}
/**
* method iterates through the entire input filtering the actual method
* params denoted by a method param order.
* @param paramsIn
* @return
*/
protected AdaptedToService[] filterMethodParams(Map paramsIn){
Map<String, AdaptedToService> methodParams = new HashMap<String, AdaptedToService>();
int highest = -1;
for (Iterator iter = paramsIn.keySet().iterator(); iter.hasNext();) {
String key = (String)iter.next();
if(NumberUtils.isNumber(key)){
int index = Integer.parseInt(key);
if(index > highest)
highest = index;
AdaptedToService adapted = (AdaptedToService)paramsIn.get(key);
methodParams.put(key, adapted);
}else{
logger.info("Ignoring attribute ["+key+"] for javaservice. Javaservices only accept numbered parameters");
}
}
int size = highest + 1;
AdaptedToService[] params = new AdaptedToService[size];
for (int j = 0; j < params.length; j++) {
params[j] = (AdaptedToService)methodParams.get("" + j);
}
return params;
}
@Override
protected String filterToString(Filters filters){
return null;
}
private static String resolveErrorMessage(Throwable cause) {
String errorMessage = null;
if (cause instanceof NullPointerException) {
StackTraceElement[] stackTraceElements = ((NullPointerException)cause).getStackTrace();
StackTraceElement stackTraceElement = stackTraceElements[0];
errorMessage = cause.toString() + ": " + stackTraceElement.toString();
} else {
errorMessage = cause.getMessage();
}
if (errorMessage != null) {
errorMessage = errorMessage.trim();
}
return errorMessage;
}
}