org.debux.webmotion.server.handler.ExecutorParametersConvertorHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.debux.webmotion.server.handler.ExecutorParametersConvertorHandler.java

Source

/*
 * #%L
 * Webmotion server
 * 
 * $Id$
 * $HeadURL$
 * %%
 * Copyright (C) 2011 - 2015 Debux
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as 
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public 
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */
package org.debux.webmotion.server.handler;

import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.ConvertUtilsBean;
import org.apache.commons.beanutils.Converter;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.debux.webmotion.server.WebMotionException;
import org.debux.webmotion.server.WebMotionHandler;
import org.debux.webmotion.server.call.Call;
import org.debux.webmotion.server.call.Call.ParameterTree;
import org.debux.webmotion.server.call.Executor;
import org.debux.webmotion.server.call.ServerContext;
import org.debux.webmotion.server.call.UploadFile;
import org.debux.webmotion.server.mapping.Mapping;
import org.debux.webmotion.server.tools.ReflectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.lang.reflect.*;
import java.util.*;
import org.apache.commons.lang3.reflect.FieldUtils;

/**
 * Store in the call object, all parameters converted depending action method 
 * invoked. Use apache ConvertUtilsBean to process.
 * 
 * All following convertion is possible :
 * <ul>
 * <li>java.lang.BigDecimal (no default value)</li>
 * <li>java.lang.BigInteger (no default value)</li>
 * <li>boolean & java.lang.Boolean (default to false)</li>
 * <li>byte & java.lang.Byte (default to zero)</li>
 * <li>char & java.lang.Character (default to a space)</li>
 * <li>java.lang.Class (no default value)</li>
 * <li>double & java.lang.Double (default to zero)</li>
 * <li>float & java.lang.Float (default to zero)</li>
 * <li>int & java.lang.Integer (default to zero)</li>
 * <li>long & java.lang.Long (default to zero)</li>
 * <li>short & java.lang.Short (default to zero)</li>
 * <li>java.lang.String (default to null)</li>
 * <li>java.io.File (no default value)</li>
 * <li>java.net.URL (no default value)</li>
 * <li>java.sql.Date (no default value) (string format [yyyy-MM-dd])</li>
 * <li>java.sql.Time (no default value) (string format [HH:mm:ss])</li>
 * <li>java.sql.Timestamp (no default value) (string format [yyyy-MM-dd HH:mm:ss.fffffffff])</li>
 * <li>POJO (no default value)</li>
 * <li>java.util.Map (no default value)</li>
 * <li>java.util.Set (no default value)</li>
 * <li>Arrays (no default value)</li>
 * </ul>
 * 
 * You can add injector in server context.
 * 
 * @author julien
 */
public class ExecutorParametersConvertorHandler extends AbstractHandler implements WebMotionHandler {

    private static final Logger log = LoggerFactory.getLogger(ExecutorParametersConvertorHandler.class);

    protected BeanUtilsBean beanUtil;
    protected ConvertUtilsBean converter;
    protected PropertyUtilsBean propertyUtils;

    @Override
    public void handlerCreated(Mapping mapping, ServerContext context) {
        beanUtil = context.getBeanUtil();
        converter = context.getConverter();
        propertyUtils = beanUtil.getPropertyUtils();
    }

    @Override
    public void handle(Mapping mapping, Call call) {
        Executor executor = call.getCurrent();

        Method executorMethod = executor.getMethod();
        String[] parameterNames = ReflectionUtils.getParameterNames(mapping, executorMethod);

        // Sort parameters and convert
        ParameterTree parameterTree = call.getParameterTree();
        Map<String, List<ParameterTree>> parameterArray = parameterTree.getArray();
        Map<String, ParameterTree> parameterObject = parameterTree.getObject();

        Class<?>[] parameterTypes = executorMethod.getParameterTypes();
        Type[] genericParameterTypes = executorMethod.getGenericParameterTypes();
        List<String> protectedParameters = executor.getProtectedParameters();

        // Save object in call
        Map<String, Object> convertedParameters = executor.getParameters();

        for (int position = 0; position < parameterNames.length; position++) {
            String name = parameterNames[position];
            Class<?> type = parameterTypes[position];
            Type genericType = genericParameterTypes[position];

            if (!protectedParameters.contains(name)) {
                try {
                    if (parameterArray != null) {
                        List<ParameterTree> array = parameterArray.get(name);
                        if (array != null) {
                            Object value = convert(array, type, genericType);
                            convertedParameters.put(name, value);
                        }
                    }

                    if (parameterObject != null) {
                        ParameterTree object = parameterObject.get(name);

                        if (object == null && !Collection.class.isAssignableFrom(type)
                                && !Map.class.isAssignableFrom(type) && !UploadFile.class.isAssignableFrom(type)
                                && !File.class.isAssignableFrom(type) && !type.isArray()
                                && converter.lookup(type) == null) {

                            object = parameterTree;
                        }

                        if (object != null) {
                            Object value = convert(object, type, genericType);
                            convertedParameters.put(name, value);
                        }
                    }

                } catch (Exception ex) {
                    throw new WebMotionException(
                            "Error during converting parameter " + name + " before invoke the method", ex);
                }
            }
        }
    }

    protected Object convert(List<ParameterTree> parameterTrees, Class<?> type, Type genericType) throws Exception {
        Object result = null;

        if (type.isArray()) {
            Class<?> componentType = type.getComponentType();

            Object[] tabConverted = (Object[]) Array.newInstance(componentType, parameterTrees.size());

            int index = 0;
            for (ParameterTree parameterTree : parameterTrees) {
                Object objectConverted = convert(parameterTree, componentType, null);
                tabConverted[index] = objectConverted;
                index++;
            }

            result = tabConverted;

        } else if (Collection.class.isAssignableFrom(type)) {

            Collection instance;
            if (type.isInterface()) {
                if (List.class.isAssignableFrom(type)) {
                    instance = new ArrayList();

                } else if (Set.class.isAssignableFrom(type)) {
                    instance = new HashSet();

                } else if (SortedSet.class.isAssignableFrom(type)) {
                    instance = new TreeSet();

                } else {
                    instance = new ArrayList();
                }
            } else {
                instance = (Collection) type.newInstance();
            }

            Class convertType = String.class;
            if (genericType != null && genericType instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) genericType;
                convertType = (Class) parameterizedType.getActualTypeArguments()[0];
            }

            for (ParameterTree parameterTree : parameterTrees) {
                Object converted = convert(parameterTree, convertType, null);
                instance.add(converted);
            }

            result = instance;
        }

        return result;
    }

    protected Object convert(ParameterTree parameterTree, Class<?> type, Type genericType) throws Exception {
        Object result = null;

        if (parameterTree == null) {
            return null;
        }

        if (genericType == null) {
            genericType = type.getGenericSuperclass();
        }

        Map<String, List<ParameterTree>> parameterArray = parameterTree.getArray();
        Map<String, ParameterTree> parameterObject = parameterTree.getObject();
        Object value = parameterTree.getValue();

        Converter lookup = converter.lookup(type);
        if (lookup != null) {

            // converter found, use it
            result = lookup.convert(type, value);
            return result;
        }

        // Manage enums
        if (type.isEnum()) {
            Object name = value == null ? null : ((Object[]) value)[0];
            if (name != null) {
                result = Enum.valueOf((Class<? extends Enum>) type, name.toString());
            }

            // Manage collection
        } else if (Collection.class.isAssignableFrom(type)) {

            Collection instance;
            if (type.isInterface()) {
                if (List.class.isAssignableFrom(type)) {
                    instance = new ArrayList();

                } else if (Set.class.isAssignableFrom(type)) {
                    instance = new HashSet();

                } else if (SortedSet.class.isAssignableFrom(type)) {
                    instance = new TreeSet();

                } else {
                    instance = new ArrayList();
                }
            } else {
                instance = (Collection) type.newInstance();
            }

            Class convertType = String.class;
            if (genericType != null && genericType instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) genericType;
                convertType = (Class) parameterizedType.getActualTypeArguments()[0];
            }

            if (parameterObject != null) {
                for (Map.Entry<String, ParameterTree> entry : parameterObject.entrySet()) {
                    ParameterTree object = entry.getValue();
                    Object converted = convert(object, convertType, null);
                    instance.add(converted);
                }
            } else {
                Object[] tab = (Object[]) value;
                for (Object object : tab) {
                    Object converted = converter.convert(object, convertType);
                    instance.add(converted);
                }
            }

            result = instance;

            // Manage map
        } else if (Map.class.isAssignableFrom(type)) {
            Map instance;
            if (type.isInterface()) {
                if (SortedMap.class.isAssignableFrom(type)) {
                    instance = new TreeMap();

                } else {
                    instance = new HashMap();
                }
            } else {
                instance = (Map) type.newInstance();
            }

            Class convertKeyType = String.class;
            Class convertValueType = String.class;
            if (genericType != null && genericType instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) genericType;
                convertKeyType = (Class) parameterizedType.getActualTypeArguments()[0];
                convertValueType = (Class) parameterizedType.getActualTypeArguments()[1];
            }

            for (Map.Entry<String, ParameterTree> entry : parameterObject.entrySet()) {
                String mapKey = entry.getKey();
                ParameterTree mapValue = entry.getValue();

                Object convertedKey = converter.convert(mapKey, convertKeyType);
                Object convertedValue = convert(mapValue, convertValueType, null);

                instance.put(convertedKey, convertedValue);
            }

            result = instance;

            // Manage simple object
        } else if (type.isArray()) {
            Class<?> componentType = type.getComponentType();

            if (parameterObject != null) {
                Object[] tabConverted = (Object[]) Array.newInstance(componentType, parameterObject.size());
                result = tabConverted;

                int index = 0;
                for (Map.Entry<String, ParameterTree> entry : parameterObject.entrySet()) {
                    ParameterTree object = entry.getValue();
                    Object objectConverted = convert(object, componentType, null);
                    tabConverted[index] = objectConverted;
                    index++;
                }

            } else {
                Object[] tab = (Object[]) value;
                Object[] tabConverted = (Object[]) Array.newInstance(componentType, tab.length);
                result = tabConverted;

                for (int index = 0; index < tab.length; index++) {
                    Object object = tab[index];
                    Object objectConverted = converter.convert(object, componentType);
                    tabConverted[index] = objectConverted;
                }
            }

        } else if (value instanceof UploadFile) {
            if (File.class.isAssignableFrom(type)) {
                UploadFile uploadFile = (UploadFile) value;
                result = uploadFile.getFile();
            } else {
                result = value;
            }

            // Manage simple object
        } else {
            Object instance = type.newInstance();
            boolean one = false;

            if (parameterObject != null) {
                for (Map.Entry<String, ParameterTree> attribut : parameterObject.entrySet()) {
                    String attributeName = attribut.getKey();
                    ParameterTree attributeValue = attribut.getValue();

                    boolean writeable = propertyUtils.isWriteable(instance, attributeName);
                    if (writeable) {
                        one = true;

                        Field field = FieldUtils.getField(type, attributeName, true);
                        Class<?> attributeType = field.getType();

                        genericType = field.getGenericType();
                        Object attributeConverted = convert(attributeValue, attributeType, genericType);
                        beanUtil.setProperty(instance, attributeName, attributeConverted);
                    }
                }
            }

            if (parameterArray != null) {
                for (Map.Entry<String, List<ParameterTree>> entry : parameterArray.entrySet()) {
                    String attributeName = entry.getKey();
                    List<ParameterTree> attributeValues = entry.getValue();

                    boolean writeable = propertyUtils.isWriteable(instance, attributeName);
                    if (writeable) {
                        one = true;

                        Field field = FieldUtils.getField(type, attributeName, true);
                        Class<?> attributeType = field.getType();

                        genericType = field.getGenericType();
                        Object attributeConverted = convert(attributeValues, attributeType, genericType);
                        beanUtil.setProperty(instance, attributeName, attributeConverted);
                    }
                }
            }

            if (one) {
                result = instance;

            } else {
                result = null;
            }
        }

        return result;
    }

}