| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 org.apache.hcatalog.data; |
| |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.TreeMap; |
| import java.util.Map.Entry; |
| |
| |
| public abstract class DataType { |
| |
| public static final byte NULL = 1; |
| public static final byte BOOLEAN = 5; |
| public static final byte BYTE = 6; |
| public static final byte INTEGER = 10; |
| public static final byte SHORT = 11; |
| public static final byte LONG = 15; |
| public static final byte FLOAT = 20; |
| public static final byte DOUBLE = 25; |
| public static final byte STRING = 55; |
| public static final byte BINARY = 60; |
| |
| public static final byte MAP = 100; |
| public static final byte STRUCT = 110; |
| public static final byte LIST = 120; |
| public static final byte ERROR = -1; |
| |
| /** |
| * Determine the datatype of an object. |
| * @param o Object to test. |
| * @return byte code of the type, or ERROR if we don't know. |
| */ |
| public static byte findType(Object o) { |
| if (o == null) { |
| return NULL; |
| } |
| |
| Class<?> clazz = o.getClass(); |
| |
| // Try to put the most common first |
| if (clazz == String.class) { |
| return STRING; |
| } else if (clazz == Integer.class) { |
| return INTEGER; |
| } else if (clazz == Long.class) { |
| return LONG; |
| } else if (clazz == Float.class) { |
| return FLOAT; |
| } else if (clazz == Double.class) { |
| return DOUBLE; |
| } else if (clazz == Boolean.class) { |
| return BOOLEAN; |
| } else if (clazz == Byte.class) { |
| return BYTE; |
| } else if (clazz == Short.class) { |
| return SHORT; |
| } else if (o instanceof List<?>) { |
| return LIST; |
| } else if (o instanceof Map<?, ?>) { |
| return MAP; |
| } else if (o instanceof byte[]) { |
| return BINARY; |
| } else { |
| return ERROR; |
| } |
| } |
| |
| public static int compare(Object o1, Object o2) { |
| |
| return compare(o1, o2, findType(o1), findType(o2)); |
| } |
| |
| public static int compare(Object o1, Object o2, byte dt1, byte dt2) { |
| if (dt1 == dt2) { |
| switch (dt1) { |
| case NULL: |
| return 0; |
| |
| case BOOLEAN: |
| return ((Boolean) o1).compareTo((Boolean) o2); |
| |
| case BYTE: |
| return ((Byte) o1).compareTo((Byte) o2); |
| |
| case INTEGER: |
| return ((Integer) o1).compareTo((Integer) o2); |
| |
| case LONG: |
| return ((Long) o1).compareTo((Long) o2); |
| |
| case FLOAT: |
| return ((Float) o1).compareTo((Float) o2); |
| |
| case DOUBLE: |
| return ((Double) o1).compareTo((Double) o2); |
| |
| case STRING: |
| return ((String) o1).compareTo((String) o2); |
| |
| case SHORT: |
| return ((Short) o1).compareTo((Short) o2); |
| |
| case BINARY: |
| return compareByteArray((byte[]) o1, (byte[]) o2); |
| |
| case LIST: |
| List<?> l1 = (List<?>) o1; |
| List<?> l2 = (List<?>) o2; |
| int len = l1.size(); |
| if (len != l2.size()) { |
| return len - l2.size(); |
| } else { |
| for (int i = 0; i < len; i++) { |
| int cmpVal = compare(l1.get(i), l2.get(i)); |
| if (cmpVal != 0) { |
| return cmpVal; |
| } |
| } |
| return 0; |
| } |
| |
| case MAP: { |
| Map<?, ?> m1 = (Map<?, ?>) o1; |
| Map<?, ?> m2 = (Map<?, ?>) o2; |
| int sz1 = m1.size(); |
| int sz2 = m2.size(); |
| if (sz1 < sz2) { |
| return -1; |
| } else if (sz1 > sz2) { |
| return 1; |
| } else { |
| // This is bad, but we have to sort the keys of the maps in order |
| // to be commutative. |
| TreeMap<Object, Object> tm1 = new TreeMap<Object, Object>(m1); |
| TreeMap<Object, Object> tm2 = new TreeMap<Object, Object>(m2); |
| Iterator<Entry<Object, Object>> i1 = tm1.entrySet().iterator(); |
| Iterator<Entry<Object, Object>> i2 = tm2.entrySet().iterator(); |
| while (i1.hasNext()) { |
| Map.Entry<Object, Object> entry1 = i1.next(); |
| Map.Entry<Object, Object> entry2 = i2.next(); |
| int c = compare(entry1.getValue(), entry2.getValue()); |
| if (c != 0) { |
| return c; |
| } else { |
| c = compare(entry1.getValue(), entry2.getValue()); |
| if (c != 0) { |
| return c; |
| } |
| } |
| } |
| return 0; |
| } |
| } |
| |
| default: |
| throw new RuntimeException("Unkown type " + dt1 + |
| " in compare"); |
| } |
| } else { |
| return dt1 < dt2 ? -1 : 1; |
| } |
| } |
| |
| private static int compareByteArray(byte[] o1, byte[] o2) { |
| |
| for (int i = 0; i < o1.length; i++) { |
| if (i == o2.length) { |
| return 1; |
| } |
| if (o1[i] == o2[i]) { |
| continue; |
| } |
| if (o1[i] > o1[i]) { |
| return 1; |
| } else { |
| return -1; |
| } |
| } |
| |
| //bytes in o1 are same as o2 |
| //in case o2 was longer |
| if (o2.length > o1.length) { |
| return -1; |
| } |
| return 0; //equals |
| } |
| |
| } |