package railo.runtime.type.util; import java.sql.Types; import java.text.Collator; import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Set; import railo.commons.lang.ArrayUtilException; import railo.commons.lang.SizeOf; import railo.commons.lang.StringUtil; import railo.runtime.PageContext; import railo.runtime.engine.ThreadLocalPageContext; import railo.runtime.exp.CasterException; import railo.runtime.exp.ExpressionException; import railo.runtime.exp.PageException; import railo.runtime.op.Caster; import railo.runtime.op.Decision; import railo.runtime.op.Operator; import railo.runtime.type.Array; import railo.runtime.type.QueryColumn; import railo.runtime.type.comparator.NumberComparator; import railo.runtime.type.comparator.SortRegister; import railo.runtime.type.comparator.TextComparator; /** * Util for diffrent methods to manipulate arrays */ public final class ArrayUtil { public static final Object[] OBJECT_EMPTY = new Object[]{}; /** * trims all value of a String Array * @param arr * @return trimmed array */ public static String[] trim(String[] arr) { for(int i=0;i<arr.length;i++) { arr[i]=arr[i].trim(); } return arr; } /** * @param list * @return array */ public static SortRegister[] toSortRegisterArray(ArrayList list) { SortRegister[] arr=new SortRegister[list.size()]; for(int i=0;i<arr.length;i++) { arr[i]=new SortRegister(i,list.get(i)); } return arr; } /** * @param column * @return array */ public static SortRegister[] toSortRegisterArray(QueryColumn column) { SortRegister[] arr=new SortRegister[column.size()]; int type = column.getType(); for(int i=0;i<arr.length;i++) { arr[i]=new SortRegister(i,toSortRegisterArray(column.get(i+1,null),type)); } return arr; } private static Object toSortRegisterArray(Object value, int type) { Object mod=null; // Date if(Types.TIMESTAMP==type) { mod= Caster.toDate(value, true, null,null); } // Double else if(Types.DOUBLE==type) { mod= Caster.toDouble(value,null); } // Boolean else if(Types.BOOLEAN==type) { mod= Caster.toBoolean(value,null); } // Varchar else if(Types.VARCHAR==type) { mod= Caster.toString(value,null); } else return value; if(mod!=null) return mod; return value; } /** * swap to values of the array * @param array * @param left left value to swap * @param right right value to swap * @throws ExpressionException */ public static void swap(Array array, int left, int right) throws ExpressionException { int len=array.size(); if(len==0) throw new ExpressionException("array is empty"); if(left<1 || left>len) throw new ExpressionException("invalid index ["+left+"]","valid indexes are from 1 to "+len); if(right<1 || right>len) throw new ExpressionException("invalid index ["+right+"]","valid indexes are from 1 to "+len); try { Object leftValue=array.get(left,null); Object rightValue=array.get(right,null); array.setE(left,rightValue); array.setE(right,leftValue); } catch (PageException e) { throw new ExpressionException("can't swap values of array",e.getMessage()); } } /** * find a object in array * @param array * @param object object to find * @return position in array or 0 */ public static int find(Array array, Object object) { int len=array.size(); for(int i=1;i<=len;i++) { Object tmp=array.get(i,null); try { if(tmp !=null && Operator.compare(object,tmp)==0) return i; } catch (PageException e) {} } return 0; } /** * average of all values of the array, only work when all values are numeric * @param array * @return average of all values * @throws ExpressionException */ public static double avg(Array array) throws ExpressionException { if(array.size()==0)return 0; return sum(array)/array.size(); } /** * sum of all values of a array, only work when all values are numeric * @param array Array * @return sum of all values * @throws ExpressionException */ public static double sum(Array array) throws ExpressionException { if(array.getDimension()>1) throw new ExpressionException("can only get sum/avg from 1 dimensional arrays"); double rtn=0; int len=array.size(); //try { for(int i=1;i<=len;i++) { rtn+=_toDoubleValue(array,i); } /*} catch (PageException e) { throw new ExpressionException("exception while execute array operation: "+e.getMessage()); }*/ return rtn; } private static double _toDoubleValue(Array array, int i) throws ExpressionException { Object obj = array.get(i,null); if(obj==null)throw new ExpressionException("there is no element at position ["+i+"] or the element is null"); double tmp = Caster.toDoubleValue(obj,Double.NaN); if(Double.isNaN(tmp)) throw new CasterException(obj,Double.class); return tmp; } /** * the smallest value, of all values inside the array, only work when all values are numeric * @param array * @return the smallest value * @throws PageException */ public static double min(Array array) throws PageException { if(array.getDimension()>1) throw new ExpressionException("can only get max value from 1 dimensional arrays"); if(array.size()==0) return 0; double rtn=_toDoubleValue(array,1); int len=array.size(); try { for(int i=2;i<=len;i++) { double v=_toDoubleValue(array,i); if(rtn>v)rtn=v; } } catch (PageException e) { throw new ExpressionException("exception while execute array operation: "+e.getMessage()); } return rtn; } /** * the greatest value, of all values inside the array, only work when all values are numeric * @param array * @return the greatest value * @throws PageException */ public static double max(Array array) throws PageException { if(array.getDimension()>1) throw new ExpressionException("can only get max value from 1 dimensional arrays"); if(array.size()==0) return 0; double rtn=_toDoubleValue(array,1); int len=array.size(); try { for(int i=2;i<=len;i++) { double v=_toDoubleValue(array,i); if(rtn<v)rtn=v; } } catch (PageException e) { throw new ExpressionException("exception while execute array operation: "+e.getMessage()); } return rtn; } /** * return index of given value in Array or -1 * @param arr * @param value * @return index of position in array */ public static int indexOf(String[] arr, String value) { for(int i=0;i<arr.length;i++) { if(arr[i].equals(value)) return i; } return -1; } /** * return index of given value in Array or -1 * @param arr * @param value * @return index of position in array */ public static int indexOfIgnoreCase(String[] arr, String value) { for(int i=0;i<arr.length;i++) { if(arr[i].equalsIgnoreCase(value)) return i; } return -1; } /** * convert a primitive array (value type) to Object Array (reference type). * @param primArr value type Array * @return reference type Array */ public static Boolean[] toReferenceType(boolean[] primArr) { Boolean[] refArr=new Boolean[primArr.length]; for(int i=0;i<primArr.length;i++)refArr[i]=Caster.toBoolean(primArr[i]); return refArr; } /** * convert a primitive array (value type) to Object Array (reference type). * @param primArr value type Array * @return reference type Array */ public static Byte[] toReferenceType(byte[] primArr) { Byte[] refArr=new Byte[primArr.length]; for(int i=0;i<primArr.length;i++)refArr[i]=new Byte(primArr[i]); return refArr; } /** * convert a primitive array (value type) to Object Array (reference type). * @param primArr value type Array * @return reference type Array */ public static Character[] toReferenceType(char[] primArr) { Character[] refArr=new Character[primArr.length]; for(int i=0;i<primArr.length;i++)refArr[i]=new Character(primArr[i]); return refArr; } /** * convert a primitive array (value type) to Object Array (reference type). * @param primArr value type Array * @return reference type Array */ public static Short[] toReferenceType(short[] primArr) { Short[] refArr=new Short[primArr.length]; for(int i=0;i<primArr.length;i++)refArr[i]=Short.valueOf(primArr[i]); return refArr; } /** * convert a primitive array (value type) to Object Array (reference type). * @param primArr value type Array * @return reference type Array */ public static Integer[] toReferenceType(int[] primArr) { Integer[] refArr=new Integer[primArr.length]; for(int i=0;i<primArr.length;i++)refArr[i]=Integer.valueOf(primArr[i]); return refArr; } /** * convert a primitive array (value type) to Object Array (reference type). * @param primArr value type Array * @return reference type Array */ public static Long[] toReferenceType(long[] primArr) { Long[] refArr=new Long[primArr.length]; for(int i=0;i<primArr.length;i++)refArr[i]=Long.valueOf(primArr[i]); return refArr; } /** * convert a primitive array (value type) to Object Array (reference type). * @param primArr value type Array * @return reference type Array */ public static Float[] toReferenceType(float[] primArr) { Float[] refArr=new Float[primArr.length]; for(int i=0;i<primArr.length;i++)refArr[i]=new Float(primArr[i]); return refArr; } /** * convert a primitive array (value type) to Object Array (reference type). * @param primArr value type Array * @return reference type Array */ public static Double[] toReferenceType(double[] primArr) { Double[] refArr=new Double[primArr.length]; for(int i=0;i<primArr.length;i++)refArr[i]=new Double(primArr[i]); return refArr; } /** * gets a value of a array at defined index * @param o * @param index * @return value at index position * @throws ArrayUtilException */ public static Object get(Object o,int index) throws ArrayUtilException { o=get(o,index,null); if(o!=null) return o; throw new ArrayUtilException("Object is not a array, or index is invalid"); } /** * gets a value of a array at defined index * @param o * @param index * @return value of the variable */ public static Object get(Object o,int index, Object defaultValue) { if(index<0) return null; if(o instanceof Object[]) { Object[] arr=((Object[])o); if(arr.length>index)return arr[index]; } else if(o instanceof boolean[]) { boolean[] arr=((boolean[])o); if(arr.length>index)return arr[index]?Boolean.TRUE:Boolean.FALSE; } else if(o instanceof byte[]) { byte[] arr=((byte[])o); if(arr.length>index)return new Byte(arr[index]); } else if(o instanceof char[]) { char[] arr=((char[])o); if(arr.length>index)return ""+(arr[index]); } else if(o instanceof short[]) { short[] arr=((short[])o); if(arr.length>index)return Short.valueOf(arr[index]); } else if(o instanceof int[]) { int[] arr=((int[])o); if(arr.length>index)return Integer.valueOf(arr[index]); } else if(o instanceof long[]) { long[] arr=((long[])o); if(arr.length>index)return Long.valueOf(arr[index]); } else if(o instanceof float[]) { float[] arr=((float[])o); if(arr.length>index)return new Float(arr[index]); } else if(o instanceof double[]) { double[] arr=((double[])o); if(arr.length>index)return new Double(arr[index]); } return defaultValue; } /** * sets a value to a array at defined index * @param o * @param index * @param value * @return value setted * @throws ArrayUtilException */ public static Object set(Object o,int index, Object value) throws ArrayUtilException { if(index<0) throw invalidIndex(index,0); if(o instanceof Object[]) { Object[] arr=((Object[])o); if(arr.length>index)return arr[index]=value; throw invalidIndex(index,arr.length); } else if(o instanceof boolean[]) { boolean[] arr=((boolean[])o); if(arr.length>index) { arr[index]=Caster.toBooleanValue(value,false); return arr[index]?Boolean.TRUE:Boolean.FALSE; } throw invalidIndex(index,arr.length); } else if(o instanceof byte[]) { byte[] arr=((byte[])o); if(arr.length>index) { double v=Caster.toDoubleValue(value,Double.NaN); if(Decision.isValid(v)) { return new Byte(arr[index]=(byte)v); } } throw invalidIndex(index,arr.length); } else if(o instanceof short[]) { short[] arr=((short[])o); if(arr.length>index) { double v=Caster.toDoubleValue(value,Double.NaN); if(Decision.isValid(v)) { return Short.valueOf(arr[index]=(short)v); } } throw invalidIndex(index,arr.length); } else if(o instanceof int[]) { int[] arr=((int[])o); if(arr.length>index) { double v=Caster.toDoubleValue(value,Double.NaN); if(Decision.isValid(v)) { return Integer.valueOf(arr[index]=(int)v); } } throw invalidIndex(index,arr.length); } else if(o instanceof long[]) { long[] arr=((long[])o); if(arr.length>index) { double v=Caster.toDoubleValue(value,Double.NaN); if(Decision.isValid(v)) { return Long.valueOf(arr[index]=(long)v); } } throw invalidIndex(index,arr.length); } else if(o instanceof float[]) { float[] arr=((float[])o); if(arr.length>index) { double v=Caster.toDoubleValue(value,Double.NaN); if(Decision.isValid(v)) { return new Float(arr[index]=(float)v); } } throw invalidIndex(index,arr.length); } else if(o instanceof double[]) { double[] arr=((double[])o); if(arr.length>index) { double v=Caster.toDoubleValue(value,Double.NaN); if(Decision.isValid(v)) { return new Double(arr[index]=v); } } throw invalidIndex(index,arr.length); } else if(o instanceof char[]) { char[] arr=((char[])o); if(arr.length>index) { String str=Caster.toString(value,null); if(str!=null && str.length()>0) { char c=str.charAt(0); arr[index]=c; return str; } } throw invalidIndex(index,arr.length); } throw new ArrayUtilException("Object ["+Caster.toClassName(o)+"] is not a Array"); } private static ArrayUtilException invalidIndex(int index, int length) { return new ArrayUtilException("Invalid index ["+index+"] for native Array call, Array has a Size of "+length); } /** * sets a value to a array at defined index * @param o * @param index * @param value * @return value setted */ public static Object setEL(Object o,int index, Object value) { try { return set(o,index,value); } catch (ArrayUtilException e) { return null; } } public static boolean isEmpty(List list) { return list==null || list.isEmpty(); } public static boolean isEmpty(Object[] array) { return array==null || array.length==0; } public static boolean isEmpty(boolean[] array) { return array==null || array.length==0; } public static boolean isEmpty(char[] array) { return array==null || array.length==0; } public static boolean isEmpty(double[] array) { return array==null || array.length==0; } public static boolean isEmpty(long[] array) { return array==null || array.length==0; } public static boolean isEmpty(int[] array) { return array==null || array.length==0; } public static boolean isEmpty(float[] array) { return array==null || array.length==0; } public static boolean isEmpty(byte[] array) { return array==null || array.length==0; } public static int size(Object[] array) { if(array==null) return 0; return array.length; } public static int size(boolean[] array) { if(array==null) return 0; return array.length; } public static int size(char[] array) { if(array==null) return 0; return array.length; } public static int size(double[] array) { if(array==null) return 0; return array.length; } public static int size(long[] array) { if(array==null) return 0; return array.length; } public static int size(int[] array) { if(array==null) return 0; return array.length; } public static int size(float[] array) { if(array==null) return 0; return array.length; } public static int size(byte[] array) { if(array==null) return 0; return array.length; } public static boolean[] toBooleanArray(Object obj) throws PageException { if(obj instanceof boolean[]) return (boolean[]) obj; Array arr = Caster.toArray(obj); boolean[] tarr=new boolean[arr.size()]; for(int i=0;i<tarr.length;i++) { tarr[i]=Caster.toBooleanValue(arr.getE(i+1)); } return tarr; } public static byte[] toByteArray(Object obj) throws PageException { if(obj instanceof byte[]) return (byte[]) obj; Array arr = Caster.toArray(obj); byte[] tarr=new byte[arr.size()]; for(int i=0;i<tarr.length;i++) { tarr[i]=Caster.toByteValue(arr.getE(i+1)); } return tarr; } public static short[] toShortArray(Object obj) throws PageException { if(obj instanceof short[]) return (short[]) obj; Array arr = Caster.toArray(obj); short[] tarr=new short[arr.size()]; for(int i=0;i<tarr.length;i++) { tarr[i]=Caster.toShortValue(arr.getE(i+1)); } return tarr; } public static int[] toIntArray(Object obj) throws PageException { if(obj instanceof int[]) return (int[]) obj; Array arr = Caster.toArray(obj); int[] tarr=new int[arr.size()]; for(int i=0;i<tarr.length;i++) { tarr[i]=Caster.toIntValue(arr.getE(i+1)); } return tarr; } public static Object[] toNullArray(Object obj) throws PageException { Array arr = Caster.toArray(obj); Object[] tarr=new Object[arr.size()]; for(int i=0;i<tarr.length;i++) { tarr[i]=Caster.toNull(arr.getE(i+1)); } return tarr; } public static long[] toLongArray(Object obj) throws PageException { if(obj instanceof long[]) return (long[]) obj; Array arr = Caster.toArray(obj); long[] tarr=new long[arr.size()]; for(int i=0;i<tarr.length;i++) { tarr[i]=Caster.toLongValue(arr.getE(i+1)); } return tarr; } public static float[] toFloatArray(Object obj) throws PageException { if(obj instanceof float[]) return (float[]) obj; Array arr = Caster.toArray(obj); float[] tarr=new float[arr.size()]; for(int i=0;i<tarr.length;i++) { tarr[i]=Caster.toFloatValue(arr.getE(i+1)); } return tarr; } public static double[] toDoubleArray(Object obj) throws PageException { if(obj instanceof double[]) return (double[]) obj; Array arr = Caster.toArray(obj); double[] tarr=new double[arr.size()]; for(int i=0;i<tarr.length;i++) { tarr[i]=Caster.toDoubleValue(arr.getE(i+1)); } return tarr; } public static char[] toCharArray(Object obj) throws PageException { if(obj instanceof char[]) return (char[]) obj; Array arr = Caster.toArray(obj); char[] tarr=new char[arr.size()]; for(int i=0;i<tarr.length;i++) { tarr[i]=Caster.toCharValue(arr.getE(i+1)); } return tarr; } public static int arrayContainsIgnoreEmpty(Array arr, String value, boolean ignoreCase) { int count=0; int len=arr.size(); for(int i=1;i<=len;i++) { String item=arr.get(i,"").toString(); if(ignoreCase) { if(StringUtil.indexOfIgnoreCase(item,value)!=-1) return count; } else { if(item.indexOf(value)!=-1) return count; } count++; } return -1; } public static Object[] toReferenceType(Object obj) throws CasterException { Object[] ref = toReferenceType(obj,null); if(ref!=null) return ref; throw new CasterException(obj,Object[].class); } public static Object[] toReferenceType(Object obj,Object[] defaultValue) { if(obj instanceof Object[]) return (Object[])obj; else if(obj instanceof boolean[]) return toReferenceType((boolean[])obj); else if(obj instanceof byte[]) return toReferenceType((byte[])obj); else if(obj instanceof char[]) return toReferenceType((char[])obj); else if(obj instanceof short[]) return toReferenceType((short[])obj); else if(obj instanceof int[]) return toReferenceType((int[])obj); else if(obj instanceof long[]) return toReferenceType((long[])obj); else if(obj instanceof float[]) return toReferenceType((float[])obj); else if(obj instanceof double[]) return toReferenceType((double[])obj); return defaultValue; } public static Object[] clone(Object[] src, Object[] trg) { for(int i=0;i<src.length;i++){ trg[i]=src[i]; } return trg; } public static Object[] keys(Map map) { if(map==null) return new Object[0]; Set set = map.keySet(); if(set==null) return new Object[0]; Object[] arr = set.toArray(); if(arr==null) return new Object[0]; return arr; } public static Object[] values(Map map) { if(map==null) return new Object[0]; return map.values().toArray(); } public static long sizeOf(List list) { ListIterator it = list.listIterator(); long size=0; while(it.hasNext()){ size+=SizeOf.size(it.next()); } return size; } public static long sizeOf(Array array) { Iterator it = array.valueIterator(); long size=0; while(it.hasNext()){ size+=SizeOf.size(it.next()); } return size; } /** * creates a native array out of the input list, if all values are from the same type, this type is used for the array, otherwise object * @param list */ public static Object[] toArray(List<?> list) { Iterator<?> it = list.iterator(); Class clazz=null; while(it.hasNext()){ Object v = it.next(); if(v==null) continue; if(clazz==null) clazz=v.getClass(); else if(clazz!=v.getClass()) return list.toArray(); } if(clazz==Object.class || clazz==null) return list.toArray(); Object arr = java.lang.reflect.Array.newInstance(clazz, list.size()); return list.toArray((Object[]) arr); } public static Comparator toComparator(PageContext pc,String sortType, String sortOrder, boolean localeSensitive) throws PageException { // check sortorder boolean isAsc=true; if(sortOrder.equalsIgnoreCase("asc"))isAsc=true; else if(sortOrder.equalsIgnoreCase("desc"))isAsc=false; else throw new ExpressionException("invalid sort order type ["+sortOrder+"], sort order types are [asc and desc]"); // text if(sortType.equalsIgnoreCase("text")) { if(localeSensitive)return toCollator(pc,Collator.IDENTICAL); return new TextComparator(isAsc,false); } // text no case else if(sortType.equalsIgnoreCase("textnocase")) { if(localeSensitive)return toCollator(pc,Collator.TERTIARY); return new TextComparator(isAsc,true); } // numeric else if(sortType.equalsIgnoreCase("numeric")) { return new NumberComparator(isAsc); } else { throw new ExpressionException("invalid sort type ["+sortType+"], sort types are [text, textNoCase, numeric]"); } } private static Comparator toCollator(PageContext pc, int strength) { Collator c=Collator.getInstance(ThreadLocalPageContext.getLocale(pc)); c.setStrength(strength); c.setDecomposition(Collator.CANONICAL_DECOMPOSITION); return c; } public static <E> List<E> merge(E[] a1, E[] a2) { List<E> list=new ArrayList<E>(); for(int i=0;i<a1.length;i++){ list.add(a1[i]); } for(int i=0;i<a2.length;i++){ list.add(a2[i]); } return list; } }