com.sm.query.utils.QueryUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.sm.query.utils.QueryUtils.java

Source

/*
 *
 *
 * Copyright 2012-2015 Viant.
 *
 * 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.sm.query.utils;

import com.sm.query.Result;
import com.sm.query.Result.Type;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import voldemort.utils.Pair;

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;

import static com.sm.query.utils.QueryUtils.Comparator.getComparator;

public class QueryUtils {
    private static Log logger = LogFactory.getLog(QueryUtils.class);
    public final static String[] CLASS_PREFIX_ARY = { "com.sm.", "com.specificmedia.", "test" };
    public static final String DOT4R = "\\."; //for regular express of split

    public static Pair<Object, FieldInfo> findObjectId(String objectId, Object source,
            Map<String, ClassInfo> metaData) {
        if (source == null) {
            throw new ObjectIdException("source is null");
        }
        ClassInfo classInfo = findClassInfo(source, metaData);
        //
        String[] fields = objectId.split(DOT4R);
        if (fields.length == 1) {
            return findField(objectId, source, classInfo);
        } else {
            Pair<Object, FieldInfo> pair = findObjectId(fields[0], source, metaData);
            try {
                Object obj = pair.getSecond().getField().get(pair.getFirst());
                if (obj != null) {
                    String id = extract(fields);
                    return findObjectId(id, obj, metaData);
                } else {
                    return pair;
                }
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        }
    }

    public static String extract(String[] fields) {
        if (fields.length < 1)
            throw new RuntimeException("field length " + fields.length + " less than 1 ");
        StringBuilder sb = new StringBuilder();
        for (int i = 1; i < fields.length; i++) {
            if (i == 1)
                sb.append(fields[i]);
            else
                sb.append(".").append(fields[i]);
        }
        return sb.toString();
    }

    public static Pair<Object, FieldInfo> findField(String fieldName, Object source, ClassInfo classInfo) {
        if (source.getClass().isPrimitive() || classInfo == null) {
            throw new RuntimeException(source.getClass().getName() + " is primitive or classInfo is null");
        }
        for (FieldInfo each : classInfo.getFieldInfos()) {
            if (each.getField().getName().equals(fieldName)) {
                return new Pair(source, each);
            }
        }
        throw new ObjectIdException("no such field " + fieldName);
    }

    public static Object createInstance(Class<?> cls) throws Exception {
        Constructor<?> constructor = null;
        Object[] constructorArgs = null;
        Constructor<?>[] constructors = cls.getDeclaredConstructors();
        //take the first constructor
        if (constructors.length > 0) {
            constructor = constructors[0];
            constructor.setAccessible(true);
            Class<?>[] params = constructor.getParameterTypes();
            constructorArgs = new Object[params.length];
            for (int i = 0; i < params.length; i++) {
                constructorArgs[i] = getParamArg(params[i]);
            }
            return constructor.newInstance(constructorArgs);
        } else
            return cls.newInstance();
    }

    public static Object getParamArg(Class<?> cl) {
        if (!cl.isPrimitive())
            return null;
        else if (boolean.class.equals(cl))
            return Boolean.FALSE;
        else if (byte.class.equals(cl))
            return new Byte((byte) 0);
        else if (short.class.equals(cl))
            return new Short((short) 0);
        else if (char.class.equals(cl))
            return new Character((char) 0);
        else if (int.class.equals(cl))
            return Integer.valueOf(0);
        else if (long.class.equals(cl))
            return Long.valueOf(0);
        else if (float.class.equals(cl))
            return Float.valueOf(0);
        else if (double.class.equals(cl))
            return Double.valueOf(0);
        else
            throw new UnsupportedOperationException();
    }

    public static enum Comparator {
        Equal, Greater, Less, NotEqual, GreaterEq, LessEq, In, Range;
        public static Comparator getComparator(String value) {
            if (value.equals("="))
                return Equal;
            else if (value.equals(">"))
                return Greater;
            else if (value.equals("<"))
                return Less;
            else if (value.equals("!="))
                return NotEqual;
            else if (value.equals(">="))
                return GreaterEq;
            else if (value.equals("<="))
                return LessEq;
            else if (value.equals("in"))
                return In;
            else if (value.endsWith("[]"))
                return Range;
            else
                throw new QueryException("invalidate operator " + value);
        }
    }

    public static enum BinaryOp {
        Plus, Minus, Multiply, Divide, Mod;
        public static BinaryOp getBinaryOp(String value) {
            if (value.equals("+"))
                return Plus;
            else if (value.equals("-"))
                return Minus;
            else if (value.equals("*"))
                return Multiply;
            else if (value.equals("/"))
                return Divide;
            else if (value.equals("%"))
                return Mod;
            else
                throw new QueryException("invalidate binary op " + value);
        }
    }

    public static boolean isInList(Result result, List<Result> list) {
        for (Result each : list) {
            if (compare(result, "=", each))
                return true;
        }
        return false;
    }

    public static boolean compareResults(Result left, Result right) {
        if (left.getType() == Type.STRING)
            return ((String) left.getValue()).equals(((String) right.getValue()));

        else {
            if (determineType(left, right) == Type.LONG)
                return convertLong(left) == convertLong(right);
            else
                return convertDouble(left) == convertDouble(right);
        }
    }

    public static Result binaryOp(Result left, String binaryOperator, Result right) {
        Type type = determineType(left, right);
        if (type == Type.LONG)
            return new Result(binaryOpLong(left, binaryOperator, right));
        else
            return new Result(binaryOpDouble(left, binaryOperator, right));
    }

    public static Double binaryOpDouble(Result left, String binaryOperator, Result right) {
        BinaryOp binaryOp = BinaryOp.getBinaryOp(binaryOperator);
        double lf = convertDouble(left);
        double rt = convertDouble(right);
        switch (binaryOp) {
        case Plus:
            return lf + rt;
        case Minus:
            return lf - rt;
        case Multiply:
            return lf * rt;
        case Divide:
            return lf / rt;
        case Mod:
            return lf % rt;
        default:
            throw new QueryException("invalidate binary op " + binaryOperator);
        }
    }

    public static long binaryOpLong(Result left, String binaryOperator, Result right) {
        BinaryOp binaryOp = BinaryOp.getBinaryOp(binaryOperator);

        long lf = convertLong(left);
        long rt = convertLong(right);
        switch (binaryOp) {
        case Plus:
            return lf + rt;
        case Minus:
            return lf - rt;
        case Multiply:
            return lf * rt;
        case Divide:
            return lf / rt;
        case Mod:
            return lf % rt;
        default:
            throw new QueryException("invalidate binary op " + binaryOperator);
        }
    }

    public static boolean compare(Result left, String operator, Result right) {
        Comparator comparator = getComparator(operator);
        if (left.getType() == Type.STRING) {
            if (left.getValue() != null && right.getValue() != null) {
                String leftValue = (String) left.getValue();
                String rightValue = (String) right.getValue();
                switch (comparator) {
                case Equal:
                    return leftValue.equals(rightValue);
                case NotEqual:
                    return !leftValue.equals(rightValue);
                case Greater:
                    return (leftValue.compareTo(rightValue) > 0);
                case GreaterEq:
                    return (leftValue.compareTo(rightValue) >= 0);
                case Less:
                    return (leftValue.compareTo(rightValue) < 0);
                case LessEq:
                    return (leftValue.compareTo(rightValue) <= 0);
                default:
                    throw new QueryException("invalid " + comparator.toString() + " for String");
                }
            } else if (left.getValue() == null && right.getValue() == null)
                return true;
            else
                return false;
        } else if (left.getType() == Type.NULL || right.getType() == Type.NULL) {
            switch (comparator) {
            case Equal:
                return (left.getValue() == null && right.getValue() == null);
            case NotEqual:
                return !(left.getValue() == null && right.getValue() == null);
            // return false,instead of exception
            default:
                return false;
            }
        } else if (left.getType() == Type.BOOLEAN || left.getType() == Type.BOOLEANS) {
            switch (comparator) {
            case Equal:
                return ((Boolean) left.getValue()).equals(((Boolean) right.getValue()));
            case NotEqual:
                return !((Boolean) left.getValue()).equals(((Boolean) right.getValue()));
            default:
                throw new QueryException("invalid " + comparator.toString() + " for boolean");
            }
        } else {
            if (isObjectType(left.getType()))
                throw new QueryException("comparator not for " + left.getType().toString());
            else { //this is no number type
                if (determineType(left, right) == Type.LONG) {
                    long lf = convertLong(left);
                    long rt = convertLong(right);
                    long diff = lf - rt;
                    return deterMineLong(diff, comparator);
                } else {
                    double lf = convertDouble(left);
                    double rt = convertDouble(right);
                    double diff = lf - rt;
                    return deterMineDouble(diff, comparator);
                }

            }

        }
    }

    public static boolean deterMineLong(long diff, Comparator comparator) {
        if (diff == 0) {
            switch (comparator) {
            case Equal:
            case GreaterEq:
            case LessEq:
                return true;
            default:
                return false;
            }
        } else if (diff < 0) {
            switch (comparator) {
            case Less:
            case LessEq:
            case NotEqual:
                return true;
            default:
                return false;
            }
        } else {
            switch (comparator) {
            case Greater:
            case GreaterEq:
            case NotEqual:
                return true;
            default:
                return false;
            }
        }
    }

    public static boolean deterMineDouble(double diff, Comparator comparator) {
        if (diff == 0) {
            switch (comparator) {
            case Equal:
            case GreaterEq:
            case LessEq:
                return true;
            default:
                return false;
            }
        } else if (diff < 0) {
            switch (comparator) {
            case Less:
            case LessEq:
                return true;
            default:
                return false;
            }
        } else {
            switch (comparator) {
            case Greater:
            case GreaterEq:
                return true;
            default:
                return false;
            }
        }
    }

    public static Object convertType(Type type, String value) {
        switch (type) {
        case STRING:
            return value;
        case INTS:
        case INT:
            return Integer.valueOf(value);
        case SHORT:
        case SHORTS:
            return Short.valueOf(value);
        case LONG:
        case LONGS:
            return Long.valueOf(value);
        case NUMBER:
            return Long.valueOf(value);
        default:
            throw new ObjectIdException("wrong type to convert long " + type);
        }
    }

    public static long convertLong(Result result) {
        Type type = result.getType();
        switch (type) {
        case INTS:
        case INT:
            return (long) (Integer) result.getValue();
        case SHORT:
        case SHORTS:
            return (long) (Short) result.getValue();
        case LONG:
        case LONGS:
            return (Long) result.getValue();
        case NUMBER:
            return new Long((String) result.getValue());
        default:
            throw new ObjectIdException("wrong type to convert long " + type);
        }

    }

    public static double convertDouble(Result result) {
        Type type = result.getType();
        switch (type) {
        case FLOAT:
        case FLOATS:
            return (double) (Float) result.getValue();
        case DOUBLE:
        case DOUBLES:
            return (Double) result.getValue();
        case NUMBER:
            return new Double((String) result.getValue());
        default:
            throw new ObjectIdException("wrong type to convert long " + type);
        }
    }

    public static Type determineType(Result left, Result right) {
        Type type = left.getType();
        switch (type) {
        case DOUBLE:
        case DOUBLES:
        case FLOAT:
        case FLOATS:
            return Type.DOUBLE;
        case NUMBER:
            if (right.getType() == Type.NUMBER) {
                if (((String) left.getValue()).indexOf(".") < 0 || ((String) right.getValue()).indexOf(".") < 0)
                    return Type.LONG;
                else
                    return Type.DOUBLE;
            } else
                break;
        default:
            return Type.LONG;
        }
        type = right.getType();
        switch (type) {
        case DOUBLE:
        case DOUBLES:
        case FLOAT:
        case FLOATS:
            return Type.DOUBLE;
        case NUMBER:
            if (((String) right.getValue()).indexOf(".") < 0)
                return Type.LONG;
            else
                return Type.DOUBLE;

        default:
            return Type.LONG;
        }

    }

    public static boolean isObjectType(Type type) {
        if (type == Type.ARRAY || type == Type.HASHSET || type == Type.OBJECT || type == Type.JOBJECT
                || type == Type.MAP || type == Type.LIST)
            return true;
        else
            return false;
    }

    /**
     * @param object
     * @param metaData  - hashmap of ClassInfo
     * @return ClassInfo which represent
     * use getSimpleName() instead of getName()
     */
    public static ClassInfo findClassInfo(Object object, Map<String, ClassInfo> metaData) {
        String className = object.getClass().getName();
        //getSimpleName without package name space
        String keyName = object.getClass().getSimpleName();
        ClassInfo info = metaData.get(keyName);
        if (info == null) {
            Type type = getType(className);
            Object obj;
            Collection values;
            switch (type) {
            case ARRAY:
                obj = Array.get(object, 0);
                //info = findClassInfo(object, cacheMetaData);
                assert (obj != null);
                info = findClassInfo(obj, metaData);
                break;
            case MAP:
                values = ((Map) object).values();
                obj = values.iterator().next();
                assert (obj != null);
                info = findClassInfo(obj, metaData);
                break;
            case HASHSET:
            case LIST:
                Iterator v = ((Collection) object).iterator();
                obj = v.next();
                info = findClassInfo(obj, metaData);
                break;
            case OBJECT:
                List<FieldInfo> list = new ArrayList<FieldInfo>();
                Class<?> cls = object.getClass();
                while (cls != null && cls != Object.class) {
                    Field[] fields = cls.getDeclaredFields();
                    for (Field field : fields) {
                        if (!isSkipField(field)) {
                            field.setAccessible(true);
                            String fieldClsName = field.getType().getName();
                            Type fieldType = getType(fieldClsName);
                            list.add(new FieldInfo(field, fieldType, fieldClsName));
                        }
                    }
                    cls = cls.getSuperclass();
                }
                if (list.size() > 0) {
                    FieldInfo[] fieldArray = new FieldInfo[list.size()];
                    fieldArray = list.toArray(fieldArray);
                    info = new ClassInfo(className, type, fieldArray);
                }
                break;
            default:
                logger.error("Wrong type =" + type + " in createClassInfo object className " + className
                        + " simple name " + keyName);
            } // switch

            metaData.put(keyName, info);
        }
        return info;

    }

    public final static Map<String, Type> typeMap = new HashMap<String, Type>();
    static {
        typeMap.put("short", Type.SHORT);
        typeMap.put("S", Type.SHORT);
        typeMap.put("java.lang.Short", Type.SHORTS);
        typeMap.put("int", Type.INT);
        typeMap.put("I", Type.INT);
        typeMap.put("java.lang.Integer", Type.INTS);
        typeMap.put("long", Type.LONG);
        typeMap.put("L", Type.LONG);
        typeMap.put("java.lang.Long", Type.LONGS);
        typeMap.put("float", Type.FLOAT);
        typeMap.put("F", Type.FLOAT);
        typeMap.put("java.lang.Float", Type.FLOATS);
        typeMap.put("double", Type.DOUBLE);
        typeMap.put("D", Type.DOUBLE);
        typeMap.put("java.lang.Double", Type.DOUBLES);
        typeMap.put("char", Type.CHAR);
        typeMap.put("C", Type.CHAR);
        typeMap.put("java.lang.Character", Type.CHARS);
        typeMap.put("byte", Type.BYTE);
        typeMap.put("B", Type.BYTE);
        typeMap.put("java.lang.Byte", Type.BYTES);
        typeMap.put("boolean", Type.BOOLEAN);
        typeMap.put("Z", Type.BOOLEAN);
        typeMap.put("java.lang.Boolean", Type.BOOLEANS);
        typeMap.put("java.lang.String", Type.STRING);
        typeMap.put("java.lang.Object", Type.OBJECT);
        typeMap.put("java.util.ArrayList", Type.LIST);
        typeMap.put("java.util.List", Type.LIST);
        typeMap.put("java.util.concurrent.CopyOnWriteArrayList", Type.LIST);
        typeMap.put("java.util.HashMap", Type.MAP);
        typeMap.put("java.util.Map", Type.MAP);
        typeMap.put("java.util.concurrent.ConcurrentHashMap", Type.MAP);
        typeMap.put("java.util.HashSet", Type.HASHSET);
        typeMap.put("java.util.Set", Type.HASHSET);
    }

    public static Map<String, Type> getTypeMap() {
        return typeMap;
    }

    public final static char ARRAY_CHAR = '[';

    public static Type getType(String typeName) {
        Type type = Type.OBJECT;
        if (typeName.charAt(0) == ARRAY_CHAR) {
            // do not check class_prefix
            //if ( typeName.indexOf(CacheEnum.CLASS_PREFIX) >= 0)
            type = Type.ARRAY;
        } else {
            // this look up map for predefine Type
            type = getTypeMap().get(typeName);
            if (type == null) {
                // check if it is class from us to be explored
                // skip third party and anything else
                // add support for special case for Object[]
                if (isCustomObject(typeName))
                    type = Type.OBJECT;
                else
                    type = Type.SKIP;
            }
        }
        return type;
    }

    public static boolean isPrimitive(Type type) {
        if (type == Type.OBJECT || type == Type.SKIP || type == Type.JOBJECT || type == Type.MAP
                || type == Type.LIST || type == Type.ARRAY || type == Type.HASHSET || type == Type.STRING)
            return false;
        else
            return true;

    }

    /**
     * @param field
     * @return true - for write able field
     */
    public static boolean isSkipField(Field field) {
        int modifier = field.getModifiers();
        if (Modifier.isFinal(modifier) || Modifier.isStatic(modifier) || Modifier.isNative(modifier)
                || Modifier.isTransient(modifier))
            return true;
        else
            return false;
    }

    public static boolean isCustomObject(String typename) {
        // next scan prefix_array
        //        for ( String each : CLASS_PREFIX_ARY )  {
        //            if ( typename.indexOf( each ) >= 0)
        //                return true;
        //        }
        //always return true
        return true;
    }

    public static boolean isSameType(Type left, Type right) {
        if (left == right)
            return true;
        else if (left.toString().contains(right.toString()) || right.toString().contains(left.toString()))
            return true;
        else
            return false;
    }

    public static Object convert(Type type, Result result) {
        if (isSameType(type, result.getType()))
            return result.getValue();
        switch (type) {
        case INT:
        case INTS:
            return Integer.valueOf((String) result.getValue());
        case SHORT:
        case SHORTS:
            return Short.valueOf((String) result.getValue());
        case LONG:
        case LONGS:
            return Long.valueOf((String) result.getValue());
        case FLOAT:
        case FLOATS:
            return Float.valueOf((String) result.getValue());
        case DOUBLE:
        case DOUBLES:
            return Double.valueOf((String) result.getValue());
        case BOOLEAN:
        case BOOLEANS:
            return Boolean.valueOf((String) result.getValue());
        default:
            throw new QueryException(type.toString() + " is not supported yet");
        }
    }

    public static Result inferValue(Result left, String text) {
        switch (left.getType()) {
        case BOOLEANS:
            return new Result(Boolean.valueOf(text));
        case SHORT:
        case SHORTS:
        case INT:
        case INTS:
        case LONG:
        case LONGS:
            return new Result(Long.valueOf(text));
        case FLOAT:
        case FLOATS:
        case DOUBLE:
        case DOUBLES:
            return new Result(Double.valueOf(text));
        case STRING:
            String str = text.substring(1, text.length() - 1);
            return new Result(str);
        default:
            throw new QueryException("wrong type " + left.getType());
        }
    }

    public static Collection collectObjectField(String fieldId, Collection collection, Map<String, FieldInfo> idMap,
            Map<String, ClassInfo> classInfoMap) {
        //first is object, second is field
        Collection list = new ArrayList();
        Iterator iterator = collection.iterator();
        while (iterator.hasNext()) {
            Pair<Object, FieldInfo> pair = findObjectId(fieldId, iterator.next(), classInfoMap);
            idMap.put(fieldId, pair.getSecond());
            try {
                list.add(pair.getSecond().getField().get(pair.getFirst()));
            } catch (IllegalAccessException e) {
                throw new ObjectIdException(e.getMessage(), e);
            }
        }
        return list;
    }

    public static boolean existInIt(Collection collection, Result right) {
        boolean toReturn = false;
        Iterator iterator = collection.iterator();
        while (iterator.hasNext()) {
            Result lt = null;
            Object obj = iterator.next();
            if (obj instanceof Collection) {
                //check for HashSet
                if (obj instanceof Set) {
                    if (((Set) obj).contains(right.getValue()))
                        return true;
                    else
                        return false;
                } else { //go through loop
                    Iterator inside = ((Collection) obj).iterator();
                    while (inside.hasNext()) {
                        lt = new Result(inside.next());
                        if (QueryUtils.compare(lt, "=", right))
                            return true;
                    }
                    //none above match
                    return false;
                } //else HashSet
            } else //else non collection, primitive attribute
                lt = new Result(obj);
            if (collection instanceof Set) {
                if (collection.contains(determineColValue(obj, right)))
                    return true;
                else
                    return false;
            } else { //go through loop
                if (QueryUtils.compare(lt, "=", right)) {
                    toReturn = true;
                    break;
                }
            }
        }
        return toReturn;
    }

    public static Object determineColValue(Object object, Result right) {
        Type type = determineTrueType(object);
        return convert(type, right);
    }

    public static Type determineTrueType(Object object) {
        if (object instanceof Integer)
            return Type.INTS;
        else if (object instanceof Short)
            return Type.SHORTS;
        else if (object instanceof Long)
            return Type.LONGS;
        else if (object instanceof Double)
            return Type.DOUBLES;
        else if (object instanceof Float)
            return Type.FLOATS;
        else if (object instanceof String)
            return Type.STRING;
        else if (object instanceof HashSet)
            return Type.HASHSET;
        else if (object instanceof Map)
            return Type.MAP;
        else if (object instanceof List)
            return Type.LIST;
        else
            return Type.OBJECT;
    }

    public static Result existInIterator(Iterator iterator, Result right) {
        return new Result(existInIt(iterator, right));
    }

    public static boolean existInIt(Iterator iterator, Result right) {
        boolean toReturn = false;
        while (iterator.hasNext()) {
            Result lt = null;
            Object obj = iterator.next();
            if (obj instanceof Collection) {
                //check for HashSet
                if (obj instanceof Map) {
                    if (((Map) obj).containsKey(determineColValue(obj, right)))
                        return true;
                    else
                        return false;
                } else { //go through loop
                    Iterator inside = ((Collection) obj).iterator();
                    while (inside.hasNext()) {
                        lt = new Result(inside.next());
                        if (QueryUtils.compare(lt, "=", right))
                            return true;
                    }
                    //none above match
                    return false;
                } //else HashSet
            } else //else non collection, primitive attribute
                lt = new Result(obj);
            if (iterator instanceof Map) {
                if (((Map) obj).containsKey(determineColValue(obj, right)))
                    return true;
                else
                    return false;
            } else { //go through loop
                if (QueryUtils.compare(lt, "=", right)) {
                    toReturn = true;
                    break;
                }
            }
        }
        return toReturn;
    }

}