org.red5.server.service.ConversionUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.red5.server.service.ConversionUtils.java

Source

package org.red5.server.service;

/*
 * RED5 Open Source Flash Server - http://www.osflash.org/red5
 * 
 * Copyright (c) 2006-2007 by respective authors (see below). All rights reserved.
 * 
 * This library 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 2.1 of the License, or (at your option) any later 
 * version. 
 * 
 * This library 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 Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along 
 * with this library; if not, write to the Free Software Foundation, Inc., 
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 */

import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConversionException;
import org.red5.io.object.Deserializer;
import org.red5.server.api.IConnection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Misc utils for convertions
 * 
 * @author The Red5 Project (red5@osflash.org)
 * @author Luke Hubbard, Codegent Ltd (luke@codegent.com)
 */
public class ConversionUtils {

    protected static Logger log = LoggerFactory.getLogger(Deserializer.class);

    private static final Class<?>[] PRIMITIVES = { boolean.class, byte.class, char.class, short.class, int.class,
            long.class, float.class, double.class };

    private static final Class<?>[] WRAPPERS = { Boolean.class, Byte.class, Character.class, Short.class,
            Integer.class, Long.class, Float.class, Double.class };

    /**
     * Parameter chains
     */
    private static final Class<?>[][] PARAMETER_CHAINS = { { boolean.class, null }, { byte.class, Short.class },
            { char.class, Integer.class }, { short.class, Integer.class }, { int.class, Long.class },
            { long.class, Float.class }, { float.class, Double.class }, { double.class, null } };

    /** Mapping of primitives to wrappers */
    private static Map<Class<?>, Class<?>> primitiveMap = new HashMap<Class<?>, Class<?>>();

    /** Mapping of wrappers to primitives */
    private static Map<Class<?>, Class<?>> wrapperMap = new HashMap<Class<?>, Class<?>>();

    /** 
     * Mapping from wrapper class to appropriate parameter types (in order) 
     * Each entry is an array of Classes, the last of which is either null
     * (for no chaining) or the next class to try
     */
    private static Map<Class<?>, Class<?>[]> parameterMap = new HashMap<Class<?>, Class<?>[]>();

    static {
        for (int i = 0; i < PRIMITIVES.length; i++) {
            primitiveMap.put(PRIMITIVES[i], WRAPPERS[i]);
            wrapperMap.put(WRAPPERS[i], PRIMITIVES[i]);
            parameterMap.put(WRAPPERS[i], PARAMETER_CHAINS[i]);
        }
    }

    /**
     * Convert source to given class
     * @param source         Source object
     * @param target         Target class
     * @return               Converted object
     * @throws ConversionException           If object can't be converted
     *
     */
    public static Object convert(Object source, Class<?> target) throws ConversionException {
        if (target == null) {
            throw new ConversionException("Unable to perform conversion");
        }
        if (source == null) {
            if (target.isPrimitive()) {
                throw new ConversionException("Unable to convert null to primitive value");
            }
            return source;
        } else if ((source instanceof Float && ((Float) source).isNaN())
                || (source instanceof Double && ((Double) source).isNaN())) {
            // Don't convert NaN values
            return source;
        }

        if (IConnection.class.isAssignableFrom(source.getClass()) && !target.equals(IConnection.class)) {
            throw new ConversionException("IConnection must match exact.");
        }
        if (target.isInstance(source)) {
            return source;
        }
        if (target.isAssignableFrom(source.getClass())) {
            return source;
        }
        if (target.isArray()) {
            return convertToArray(source, target);
        }
        if (target.equals(String.class)) {
            return source.toString();
        }
        if (target.isPrimitive()) {
            return convertToWrappedPrimitive(source, primitiveMap.get(target));
        }
        if (wrapperMap.containsKey(target)) {
            return convertToWrappedPrimitive(source, target);
        }
        if (target.equals(Map.class)) {
            return convertBeanToMap(source);
        }
        if (target.equals(List.class) || target.equals(Collection.class)) {
            if (source.getClass().equals(LinkedHashMap.class)) {
                return convertMapToList((LinkedHashMap<?, ?>) source);
            } else if (source.getClass().isArray()) {
                return convertArrayToList((Object[]) source);
            }
        }
        if (target.equals(Set.class) && source.getClass().isArray()) {
            return convertArrayToSet((Object[]) source);
        }
        throw new ConversionException("Unable to preform conversion");
    }

    /**
     * Convert to array
     * @param source         Source object
     * @param target         Target class
     * @return               Converted object
     * @throws ConversionException           If object can't be converted
     */
    public static Object convertToArray(Object source, Class<?> target) throws ConversionException {
        try {
            Object[] targetInstance = (Object[]) Array.newInstance(target.getComponentType(), 0);
            if (source.getClass().isArray()) {
                Object[] sourceArray = (Object[]) source;
                Class<?> targetType = target.getComponentType();
                List<Object> list = new ArrayList<Object>(sourceArray.length);
                for (Object element : sourceArray) {
                    list.add(convert(element, targetType));
                }
                source = list;
            }
            if (source instanceof Collection) {
                return ((Collection<?>) source).toArray(targetInstance);
            } else {
                throw new ConversionException("Unable to convert to array");
            }
        } catch (Exception ex) {
            throw new ConversionException("Error converting to array", ex);
        }
    }

    public static List<Object> convertMapToList(Map<?, ?> map) {
        List<Object> list = new ArrayList<Object>(map.size());
        list.addAll(map.values());
        return list;
    }

    /**
     * Convert to wrapped primitive
     * @param source            Source object
     * @param wrapper           Primitive wrapper type
     * @return                  Converted object
     */
    public static Object convertToWrappedPrimitive(Object source, Class<?> wrapper) {
        if (source == null || wrapper == null) {
            return null;
        }
        if (wrapper.isInstance(source)) {
            return source;
        }
        if (wrapper.isAssignableFrom(source.getClass())) {
            return source;
        }
        if (source instanceof Number) {
            return convertNumberToWrapper((Number) source, wrapper);
        } else {
            return convertStringToWrapper(source.toString(), wrapper);
        }
    }

    /**
     * Convert string to primitive wrapper like Boolean or Float
     * @param str               String to convert
     * @param wrapper           Primitive wrapper type
     * @return                  Converted object
     */
    public static Object convertStringToWrapper(String str, Class<?> wrapper) {
        if (wrapper.equals(String.class)) {
            return str;
        } else if (wrapper.equals(Boolean.class)) {
            return new Boolean(str);
        } else if (wrapper.equals(Double.class)) {
            return new Double(str);
        } else if (wrapper.equals(Long.class)) {
            return new Long(str);
        } else if (wrapper.equals(Float.class)) {
            return new Float(str);
        } else if (wrapper.equals(Integer.class)) {
            return new Integer(str);
        } else if (wrapper.equals(Short.class)) {
            return new Short(str);
        } else if (wrapper.equals(Byte.class)) {
            return new Byte(str);
        }
        throw new ConversionException("Unable to convert string to: " + wrapper);
    }

    /**
     * Convert number to primitive wrapper like Boolean or Float
     * @param num               Number to conver
     * @param wrapper           Primitive wrapper type
     * @return                  Converted object
     */
    public static Object convertNumberToWrapper(Number num, Class<?> wrapper) {
        //XXX Paul: Using valueOf will reduce object creation
        if (wrapper.equals(String.class)) {
            return num.toString();
        } else if (wrapper.equals(Boolean.class)) {
            return Boolean.valueOf(num.intValue() == 1);
        } else if (wrapper.equals(Double.class)) {
            return Double.valueOf(num.doubleValue());
        } else if (wrapper.equals(Long.class)) {
            return Long.valueOf(num.longValue());
        } else if (wrapper.equals(Float.class)) {
            return Float.valueOf(num.floatValue());
        } else if (wrapper.equals(Integer.class)) {
            return Integer.valueOf(num.intValue());
        } else if (wrapper.equals(Short.class)) {
            return Short.valueOf(num.shortValue());
        } else if (wrapper.equals(Byte.class)) {
            return Byte.valueOf(num.byteValue());
        }
        throw new ConversionException("Unable to convert number to: " + wrapper);
    }

    /**
     * Find method by name and number of parameters
     * @param object            Object to find method on
     * @param method            Method name
     * @param numParam          Number of parameters
     * @return                  List of methods that match by name and number of parameters
     */
    public static List<Method> findMethodsByNameAndNumParams(Object object, String method, int numParam) {
        LinkedList<Method> list = new LinkedList<Method>();
        Method[] methods = object.getClass().getMethods();
        for (Method m : methods) {
            if (log.isDebugEnabled()) {
                log.debug("Method name: " + m.getName());
            }
            if (!m.getName().equals(method)) {
                log.debug("Method name not the same");
                continue;
            }
            if (m.getParameterTypes().length != numParam) {
                log.debug("Param length not the same");
                continue;
            }
            list.add(m);
        }
        return list;
    }

    /**
     * Convert parameters using methods of this utility class
     * @param source                Array of source object
     * @param target                Array of target classes
     * @return                      Array of converted objects
     * @throws ConversionException  If object can't be converted
     */
    public static Object[] convertParams(Object[] source, Class<?>[] target) throws ConversionException {
        Object[] converted = new Object[target.length];
        for (int i = 0; i < target.length; i++) {
            converted[i] = convert(source[i], target[i]);
        }
        return converted;
    }

    /**
     *
     * @param source
     * @return
     * @throws ConversionException
     */
    public static List<?> convertArrayToList(Object[] source) throws ConversionException {
        List<Object> list = new ArrayList<Object>(source.length);
        for (Object element : source) {
            list.add(element);
        }
        return list;
    }

    /**
     * Convert map to bean
     * @param source                Source map
     * @param target                Target class
     * @return                      Bean of that class
     * @throws ConversionException
     */
    public static Object convertMapToBean(Map<?, ?> source, Class<?> target) throws ConversionException {
        Object bean = newInstance(target.getClass().getName());
        if (bean == null) {
            throw new ConversionException("Unable to create bean using empty constructor");
        }
        try {
            BeanUtils.populate(bean, source);
        } catch (Exception e) {
            throw new ConversionException("Error populating bean", e);
        }
        return bean;
    }

    /**
     * Convert bean to map
     * @param source      Source bean
     * @return            Converted map
     */
    public static Map<?, ?> convertBeanToMap(Object source) {
        return new BeanMap(source);
    }

    /**
     * Convert array to set, removing duplicates
     * @param source      Source array
     * @return            Set
     */
    public static Set<?> convertArrayToSet(Object[] source) {
        Set<Object> set = new HashSet<Object>();
        for (Object element : source) {
            set.add(element);
        }
        return set;
    }

    /**
     * Create new class instance
     * @param className   Class name; may not be loaded by JVM yet
     * @return            Instance of given class
     */
    protected static Object newInstance(String className) {
        Object instance = null;
        try {
            Class<?> clazz = Thread.currentThread().getContextClassLoader().loadClass(className);
            instance = clazz.newInstance();
        } catch (Exception ex) {
            log.error("Error loading class: " + className, ex);
        }
        return instance;
    }

}