001 package railo.runtime.type.util; 002 003 import java.sql.Types; 004 import java.util.ArrayList; 005 import java.util.Iterator; 006 import java.util.List; 007 import java.util.ListIterator; 008 import java.util.Map; 009 import java.util.Set; 010 011 import railo.commons.lang.ArrayUtilException; 012 import railo.commons.lang.SizeOf; 013 import railo.commons.lang.StringUtil; 014 import railo.runtime.exp.CasterException; 015 import railo.runtime.exp.ExpressionException; 016 import railo.runtime.exp.PageException; 017 import railo.runtime.op.Caster; 018 import railo.runtime.op.Decision; 019 import railo.runtime.op.Operator; 020 import railo.runtime.type.Array; 021 import railo.runtime.type.QueryColumn; 022 import railo.runtime.type.comparator.SortRegister; 023 024 /** 025 * Util for diffrent methods to manipulate arrays 026 */ 027 public final class ArrayUtil { 028 029 public static final Object[] OBJECT_EMPTY = new Object[]{}; 030 /** 031 * trims all value of a String Array 032 * @param arr 033 * @return trimmed array 034 */ 035 public static String[] trim(String[] arr) { 036 for(int i=0;i<arr.length;i++) { 037 arr[i]=arr[i].trim(); 038 } 039 return arr; 040 } 041 042 043 /** 044 * @param list 045 * @return array 046 */ 047 public static SortRegister[] toSortRegisterArray(ArrayList list) { 048 SortRegister[] arr=new SortRegister[list.size()]; 049 for(int i=0;i<arr.length;i++) { 050 arr[i]=new SortRegister(i,list.get(i)); 051 } 052 return arr; 053 } 054 055 /** 056 * @param column 057 * @return array 058 */ 059 public static SortRegister[] toSortRegisterArray(QueryColumn column) { 060 SortRegister[] arr=new SortRegister[column.size()]; 061 int type = column.getType(); 062 for(int i=0;i<arr.length;i++) { 063 arr[i]=new SortRegister(i,toSortRegisterArray(column.get(i+1,null),type)); 064 } 065 return arr; 066 } 067 068 private static Object toSortRegisterArray(Object value, int type) { 069 070 Object mod=null; 071 // Date 072 if(Types.TIMESTAMP==type) { 073 mod= Caster.toDate(value, true, null,null); 074 } 075 // Double 076 else if(Types.DOUBLE==type) { 077 mod= Caster.toDouble(value,null); 078 } 079 // Boolean 080 else if(Types.BOOLEAN==type) { 081 mod= Caster.toBoolean(value,null); 082 } 083 // Varchar 084 else if(Types.VARCHAR==type) { 085 mod= Caster.toString(value,null); 086 } 087 else return value; 088 089 if(mod!=null) return mod; 090 return value; 091 } 092 093 /** 094 * swap to values of the array 095 * @param array 096 * @param left left value to swap 097 * @param right right value to swap 098 * @throws ExpressionException 099 */ 100 public static void swap(Array array, int left, int right) throws ExpressionException { 101 102 try { 103 Object leftValue=array.getE(left); 104 Object rightValue=array.getE(right); 105 array.setE(left,rightValue); 106 array.setE(right,leftValue); 107 } catch (PageException e) { 108 throw new ExpressionException("can't swap values of array",e.getMessage()); 109 } 110 111 } 112 113 /** 114 * find a object in array 115 * @param array 116 * @param object object to find 117 * @return position in array or 0 118 */ 119 public static int find(Array array, Object object) { 120 int len=array.size(); 121 for(int i=1;i<=len;i++) { 122 Object tmp=array.get(i,null); 123 try { 124 if(tmp !=null && Operator.compare(object,tmp)==0) 125 return i; 126 } catch (PageException e) {} 127 } 128 return 0; 129 } 130 131 /** 132 * average of all values of the array, only work when all values are numeric 133 * @param array 134 * @return average of all values 135 * @throws ExpressionException 136 */ 137 public static double avg(Array array) throws ExpressionException { 138 if(array.size()==0)return 0; 139 return sum(array)/array.size(); 140 } 141 142 /** 143 * sum of all values of a array, only work when all values are numeric 144 * @param array Array 145 * @return sum of all values 146 * @throws ExpressionException 147 */ 148 public static double sum(Array array) throws ExpressionException { 149 if(array.getDimension()>1) 150 throw new ExpressionException("can only get sum/avg from 1 dimensional arrays"); 151 152 double rtn=0; 153 int len=array.size(); 154 try { 155 for(int i=1;i<=len;i++) { 156 rtn+=Caster.toDoubleValue(array.getE(i)); 157 } 158 } 159 catch (PageException e) { 160 throw new ExpressionException("exception while execute array operation: "+e.getMessage()); 161 } 162 return rtn; 163 } 164 165 /** 166 * the smallest value, of all values inside the array, only work when all values are numeric 167 * @param array 168 * @return the smallest value 169 * @throws PageException 170 */ 171 public static double min(Array array) throws PageException { 172 if(array.getDimension()>1) 173 throw new ExpressionException("can only get max value from 1 dimensional arrays"); 174 if(array.size()==0) return 0; 175 176 double rtn=Caster.toDoubleValue(array.getE(1)); 177 int len=array.size(); 178 try { 179 for(int i=2;i<=len;i++) { 180 double v=Caster.toDoubleValue(array.getE(i)); 181 if(rtn>v)rtn=v; 182 183 } 184 } catch (PageException e) { 185 throw new ExpressionException("exception while execute array operation: "+e.getMessage()); 186 } 187 return rtn; 188 } 189 190 /** 191 * the greatest value, of all values inside the array, only work when all values are numeric 192 * @param array 193 * @return the greatest value 194 * @throws PageException 195 */ 196 public static double max(Array array) throws PageException { 197 if(array.getDimension()>1) 198 throw new ExpressionException("can only get max value from 1 dimensional arrays"); 199 if(array.size()==0) return 0; 200 201 double rtn=Caster.toDoubleValue(array.getE(1)); 202 int len=array.size(); 203 try { 204 for(int i=2;i<=len;i++) { 205 double v=Caster.toDoubleValue(array.getE(i)); 206 if(rtn<v)rtn=v; 207 208 } 209 } catch (PageException e) { 210 throw new ExpressionException("exception while execute array operation: "+e.getMessage()); 211 } 212 return rtn; 213 } 214 215 /** 216 * return index of given value in Array or -1 217 * @param arr 218 * @param value 219 * @return index of position in array 220 */ 221 public static int indexOf(String[] arr, String value) { 222 for(int i=0;i<arr.length;i++) { 223 if(arr[i].equals(value)) return i; 224 } 225 return -1; 226 } 227 228 /** 229 * return index of given value in Array or -1 230 * @param arr 231 * @param value 232 * @return index of position in array 233 */ 234 public static int indexOfIgnoreCase(String[] arr, String value) { 235 for(int i=0;i<arr.length;i++) { 236 if(arr[i].equalsIgnoreCase(value)) return i; 237 } 238 return -1; 239 } 240 241 242 243 /** 244 * convert a primitive array (value type) to Object Array (reference type). 245 * @param primArr value type Array 246 * @return reference type Array 247 */ 248 public static Boolean[] toReferenceType(boolean[] primArr) { 249 Boolean[] refArr=new Boolean[primArr.length]; 250 for(int i=0;i<primArr.length;i++)refArr[i]=Caster.toBoolean(primArr[i]); 251 return refArr; 252 } 253 254 /** 255 * convert a primitive array (value type) to Object Array (reference type). 256 * @param primArr value type Array 257 * @return reference type Array 258 */ 259 public static Byte[] toReferenceType(byte[] primArr) { 260 Byte[] refArr=new Byte[primArr.length]; 261 for(int i=0;i<primArr.length;i++)refArr[i]=new Byte(primArr[i]); 262 return refArr; 263 } 264 265 /** 266 * convert a primitive array (value type) to Object Array (reference type). 267 * @param primArr value type Array 268 * @return reference type Array 269 */ 270 public static Character[] toReferenceType(char[] primArr) { 271 Character[] refArr=new Character[primArr.length]; 272 for(int i=0;i<primArr.length;i++)refArr[i]=new Character(primArr[i]); 273 return refArr; 274 } 275 276 /** 277 * convert a primitive array (value type) to Object Array (reference type). 278 * @param primArr value type Array 279 * @return reference type Array 280 */ 281 public static Short[] toReferenceType(short[] primArr) { 282 Short[] refArr=new Short[primArr.length]; 283 for(int i=0;i<primArr.length;i++)refArr[i]=Short.valueOf(primArr[i]); 284 return refArr; 285 } 286 287 /** 288 * convert a primitive array (value type) to Object Array (reference type). 289 * @param primArr value type Array 290 * @return reference type Array 291 */ 292 public static Integer[] toReferenceType(int[] primArr) { 293 Integer[] refArr=new Integer[primArr.length]; 294 for(int i=0;i<primArr.length;i++)refArr[i]=Integer.valueOf(primArr[i]); 295 return refArr; 296 } 297 298 /** 299 * convert a primitive array (value type) to Object Array (reference type). 300 * @param primArr value type Array 301 * @return reference type Array 302 */ 303 public static Long[] toReferenceType(long[] primArr) { 304 Long[] refArr=new Long[primArr.length]; 305 for(int i=0;i<primArr.length;i++)refArr[i]=Long.valueOf(primArr[i]); 306 return refArr; 307 } 308 309 /** 310 * convert a primitive array (value type) to Object Array (reference type). 311 * @param primArr value type Array 312 * @return reference type Array 313 */ 314 public static Float[] toReferenceType(float[] primArr) { 315 Float[] refArr=new Float[primArr.length]; 316 for(int i=0;i<primArr.length;i++)refArr[i]=new Float(primArr[i]); 317 return refArr; 318 } 319 320 /** 321 * convert a primitive array (value type) to Object Array (reference type). 322 * @param primArr value type Array 323 * @return reference type Array 324 */ 325 public static Double[] toReferenceType(double[] primArr) { 326 Double[] refArr=new Double[primArr.length]; 327 for(int i=0;i<primArr.length;i++)refArr[i]=new Double(primArr[i]); 328 return refArr; 329 } 330 331 /** 332 * gets a value of a array at defined index 333 * @param o 334 * @param index 335 * @return value at index position 336 * @throws ArrayUtilException 337 */ 338 public static Object get(Object o,int index) throws ArrayUtilException { 339 o=get(o,index,null); 340 if(o!=null) return o; 341 throw new ArrayUtilException("Object is not a array, or index is invalid"); 342 } 343 344 /** 345 * gets a value of a array at defined index 346 * @param o 347 * @param index 348 * @return value of the variable 349 */ 350 public static Object get(Object o,int index, Object defaultValue) { 351 if(index<0) return null; 352 if(o instanceof Object[]) { 353 Object[] arr=((Object[])o); 354 if(arr.length>index)return arr[index]; 355 } 356 else if(o instanceof boolean[]) { 357 boolean[] arr=((boolean[])o); 358 if(arr.length>index)return arr[index]?Boolean.TRUE:Boolean.FALSE; 359 } 360 else if(o instanceof byte[]) { 361 byte[] arr=((byte[])o); 362 if(arr.length>index)return new Byte(arr[index]); 363 } 364 else if(o instanceof char[]) { 365 char[] arr=((char[])o); 366 if(arr.length>index)return ""+(arr[index]); 367 } 368 else if(o instanceof short[]) { 369 short[] arr=((short[])o); 370 if(arr.length>index)return Short.valueOf(arr[index]); 371 } 372 else if(o instanceof int[]) { 373 int[] arr=((int[])o); 374 if(arr.length>index)return Integer.valueOf(arr[index]); 375 } 376 else if(o instanceof long[]) { 377 long[] arr=((long[])o); 378 if(arr.length>index)return Long.valueOf(arr[index]); 379 } 380 else if(o instanceof float[]) { 381 float[] arr=((float[])o); 382 if(arr.length>index)return new Float(arr[index]); 383 } 384 else if(o instanceof double[]) { 385 double[] arr=((double[])o); 386 if(arr.length>index)return new Double(arr[index]); 387 } 388 return defaultValue; 389 } 390 391 /** 392 * sets a value to a array at defined index 393 * @param o 394 * @param index 395 * @param value 396 * @return value setted 397 * @throws ArrayUtilException 398 */ 399 public static Object set(Object o,int index, Object value) throws ArrayUtilException { 400 if(index<0) 401 throw invalidIndex(index,0); 402 if(o instanceof Object[]) { 403 Object[] arr=((Object[])o); 404 if(arr.length>index)return arr[index]=value; 405 throw invalidIndex(index,arr.length); 406 } 407 else if(o instanceof boolean[]) { 408 boolean[] arr=((boolean[])o); 409 if(arr.length>index) { 410 arr[index]=Caster.toBooleanValue(value,false); 411 return arr[index]?Boolean.TRUE:Boolean.FALSE; 412 } 413 throw invalidIndex(index,arr.length); 414 } 415 else if(o instanceof byte[]) { 416 byte[] arr=((byte[])o); 417 if(arr.length>index) { 418 double v=Caster.toDoubleValue(value,Double.NaN); 419 if(Decision.isValid(v)) { 420 return new Byte(arr[index]=(byte)v); 421 } 422 } 423 throw invalidIndex(index,arr.length); 424 } 425 else if(o instanceof short[]) { 426 short[] arr=((short[])o); 427 if(arr.length>index) { 428 double v=Caster.toDoubleValue(value,Double.NaN); 429 if(Decision.isValid(v)) { 430 return Short.valueOf(arr[index]=(short)v); 431 } 432 } 433 throw invalidIndex(index,arr.length); 434 } 435 else if(o instanceof int[]) { 436 int[] arr=((int[])o); 437 if(arr.length>index) { 438 double v=Caster.toDoubleValue(value,Double.NaN); 439 if(Decision.isValid(v)) { 440 return Integer.valueOf(arr[index]=(int)v); 441 } 442 } 443 throw invalidIndex(index,arr.length); 444 } 445 else if(o instanceof long[]) { 446 long[] arr=((long[])o); 447 if(arr.length>index) { 448 double v=Caster.toDoubleValue(value,Double.NaN); 449 if(Decision.isValid(v)) { 450 return Long.valueOf(arr[index]=(long)v); 451 } 452 } 453 throw invalidIndex(index,arr.length); 454 } 455 else if(o instanceof float[]) { 456 float[] arr=((float[])o); 457 if(arr.length>index) { 458 double v=Caster.toDoubleValue(value,Double.NaN); 459 if(Decision.isValid(v)) { 460 return new Float(arr[index]=(float)v); 461 } 462 } 463 throw invalidIndex(index,arr.length); 464 } 465 else if(o instanceof double[]) { 466 double[] arr=((double[])o); 467 if(arr.length>index) { 468 double v=Caster.toDoubleValue(value,Double.NaN); 469 if(Decision.isValid(v)) { 470 return new Double(arr[index]=v); 471 } 472 } 473 throw invalidIndex(index,arr.length); 474 } 475 else if(o instanceof char[]) { 476 char[] arr=((char[])o); 477 if(arr.length>index) { 478 String str=Caster.toString(value,null); 479 if(str!=null && str.length()>0) { 480 char c=str.charAt(0); 481 arr[index]=c; 482 return str; 483 } 484 } 485 throw invalidIndex(index,arr.length); 486 } 487 throw new ArrayUtilException("Object ["+Caster.toClassName(o)+"] is not a Array"); 488 } 489 490 491 private static ArrayUtilException invalidIndex(int index, int length) { 492 return new ArrayUtilException("Invalid index ["+index+"] for native Array call, Array has a Size of "+length); 493 } 494 495 /** 496 * sets a value to a array at defined index 497 * @param o 498 * @param index 499 * @param value 500 * @return value setted 501 */ 502 public static Object setEL(Object o,int index, Object value) { 503 try { 504 return set(o,index,value); 505 } catch (ArrayUtilException e) { 506 return null; 507 } 508 } 509 510 public static boolean isEmpty(List list) { 511 return list==null || list.isEmpty(); 512 } 513 514 public static boolean isEmpty(Object[] array) { 515 return array==null || array.length==0; 516 } 517 public static boolean isEmpty(boolean[] array) { 518 return array==null || array.length==0; 519 } 520 public static boolean isEmpty(char[] array) { 521 return array==null || array.length==0; 522 } 523 public static boolean isEmpty(double[] array) { 524 return array==null || array.length==0; 525 } 526 public static boolean isEmpty(long[] array) { 527 return array==null || array.length==0; 528 } 529 public static boolean isEmpty(int[] array) { 530 return array==null || array.length==0; 531 } 532 public static boolean isEmpty(float[] array) { 533 return array==null || array.length==0; 534 } 535 public static boolean isEmpty(byte[] array) { 536 return array==null || array.length==0; 537 } 538 539 540 541 542 543 544 545 546 547 548 public static int size(Object[] array) { 549 if(array==null) return 0; 550 return array.length; 551 } 552 public static int size(boolean[] array) { 553 if(array==null) return 0; 554 return array.length; 555 } 556 public static int size(char[] array) { 557 if(array==null) return 0; 558 return array.length; 559 } 560 public static int size(double[] array) { 561 if(array==null) return 0; 562 return array.length; 563 } 564 public static int size(long[] array) { 565 if(array==null) return 0; 566 return array.length; 567 } 568 public static int size(int[] array) { 569 if(array==null) return 0; 570 return array.length; 571 } 572 public static int size(float[] array) { 573 if(array==null) return 0; 574 return array.length; 575 } 576 public static int size(byte[] array) { 577 if(array==null) return 0; 578 return array.length; 579 } 580 581 582 public static boolean[] toBooleanArray(Object obj) throws PageException { 583 if(obj instanceof boolean[]) return (boolean[]) obj; 584 585 Array arr = Caster.toArray(obj); 586 boolean[] tarr=new boolean[arr.size()]; 587 for(int i=0;i<tarr.length;i++) { 588 tarr[i]=Caster.toBooleanValue(arr.getE(i+1)); 589 } 590 return tarr; 591 } 592 593 public static byte[] toByteArray(Object obj) throws PageException { 594 if(obj instanceof byte[]) return (byte[]) obj; 595 596 Array arr = Caster.toArray(obj); 597 byte[] tarr=new byte[arr.size()]; 598 for(int i=0;i<tarr.length;i++) { 599 tarr[i]=Caster.toByteValue(arr.getE(i+1)); 600 } 601 return tarr; 602 } 603 604 public static short[] toShortArray(Object obj) throws PageException { 605 if(obj instanceof short[]) return (short[]) obj; 606 607 Array arr = Caster.toArray(obj); 608 short[] tarr=new short[arr.size()]; 609 for(int i=0;i<tarr.length;i++) { 610 tarr[i]=Caster.toShortValue(arr.getE(i+1)); 611 } 612 return tarr; 613 } 614 615 public static int[] toIntArray(Object obj) throws PageException { 616 if(obj instanceof int[]) return (int[]) obj; 617 618 Array arr = Caster.toArray(obj); 619 int[] tarr=new int[arr.size()]; 620 for(int i=0;i<tarr.length;i++) { 621 tarr[i]=Caster.toIntValue(arr.getE(i+1)); 622 } 623 return tarr; 624 } 625 626 public static Object[] toNullArray(Object obj) throws PageException { 627 Array arr = Caster.toArray(obj); 628 Object[] tarr=new Object[arr.size()]; 629 for(int i=0;i<tarr.length;i++) { 630 tarr[i]=Caster.toNull(arr.getE(i+1)); 631 } 632 return tarr; 633 } 634 635 public static long[] toLongArray(Object obj) throws PageException { 636 if(obj instanceof long[]) return (long[]) obj; 637 638 Array arr = Caster.toArray(obj); 639 long[] tarr=new long[arr.size()]; 640 for(int i=0;i<tarr.length;i++) { 641 tarr[i]=Caster.toLongValue(arr.getE(i+1)); 642 } 643 return tarr; 644 } 645 646 public static float[] toFloatArray(Object obj) throws PageException { 647 if(obj instanceof float[]) return (float[]) obj; 648 649 Array arr = Caster.toArray(obj); 650 float[] tarr=new float[arr.size()]; 651 for(int i=0;i<tarr.length;i++) { 652 tarr[i]=Caster.toFloatValue(arr.getE(i+1)); 653 } 654 return tarr; 655 } 656 657 public static double[] toDoubleArray(Object obj) throws PageException { 658 if(obj instanceof double[]) return (double[]) obj; 659 660 Array arr = Caster.toArray(obj); 661 double[] tarr=new double[arr.size()]; 662 for(int i=0;i<tarr.length;i++) { 663 tarr[i]=Caster.toDoubleValue(arr.getE(i+1)); 664 } 665 return tarr; 666 } 667 668 public static char[] toCharArray(Object obj) throws PageException { 669 if(obj instanceof char[]) return (char[]) obj; 670 671 Array arr = Caster.toArray(obj); 672 char[] tarr=new char[arr.size()]; 673 for(int i=0;i<tarr.length;i++) { 674 tarr[i]=Caster.toCharValue(arr.getE(i+1)); 675 } 676 return tarr; 677 } 678 679 680 public static int arrayContainsIgnoreEmpty(Array arr, String value, boolean ignoreCase) { 681 int count=0; 682 int len=arr.size(); 683 684 for(int i=1;i<=len;i++) { 685 String item=arr.get(i,"").toString(); 686 if(ignoreCase) { 687 if(StringUtil.indexOfIgnoreCase(item,value)!=-1) return count; 688 } 689 else { 690 if(item.indexOf(value)!=-1) return count; 691 } 692 count++; 693 } 694 return -1; 695 } 696 697 698 public static Object[] toReferenceType(Object obj) throws CasterException { 699 Object[] ref = toReferenceType(obj,null); 700 if(ref!=null) return ref; 701 throw new CasterException(obj,Object[].class); 702 703 } 704 public static Object[] toReferenceType(Object obj,Object[] defaultValue) { 705 if(obj instanceof Object[]) return (Object[])obj; 706 else if(obj instanceof boolean[]) return toReferenceType((boolean[])obj); 707 else if(obj instanceof byte[]) return toReferenceType((byte[])obj); 708 else if(obj instanceof char[]) return toReferenceType((char[])obj); 709 else if(obj instanceof short[]) return toReferenceType((short[])obj); 710 else if(obj instanceof int[]) return toReferenceType((int[])obj); 711 else if(obj instanceof long[]) return toReferenceType((long[])obj); 712 else if(obj instanceof float[]) return toReferenceType((float[])obj); 713 else if(obj instanceof double[]) return toReferenceType((double[])obj); 714 return defaultValue; 715 } 716 717 718 public static Object[] clone(Object[] src, Object[] trg) { 719 for(int i=0;i<src.length;i++){ 720 trg[i]=src[i]; 721 } 722 return trg; 723 } 724 725 726 public static Object[] keys(Map map) { 727 if(map==null) return new Object[0]; 728 Set set = map.keySet(); 729 if(set==null) return new Object[0]; 730 Object[] arr = set.toArray(); 731 if(arr==null) return new Object[0]; 732 return arr; 733 } 734 735 public static Object[] values(Map map) { 736 if(map==null) return new Object[0]; 737 return map.values().toArray(); 738 } 739 740 741 public static long sizeOf(List list) { 742 ListIterator it = list.listIterator(); 743 long size=0; 744 while(it.hasNext()){ 745 size+=SizeOf.size(it.next()); 746 } 747 return size; 748 } 749 750 public static long sizeOf(Array array) { 751 Iterator it = array.valueIterator(); 752 long size=0; 753 while(it.hasNext()){ 754 size+=SizeOf.size(it.next()); 755 } 756 return size; 757 } 758 759 760 /** 761 * 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 762 * @param list 763 */ 764 public static Object[] toArray(List<?> list) { 765 Iterator<?> it = list.iterator(); 766 Class clazz=null; 767 while(it.hasNext()){ 768 Object v = it.next(); 769 if(v==null) continue; 770 if(clazz==null) clazz=v.getClass(); 771 else if(clazz!=v.getClass()) return list.toArray(); 772 } 773 if(clazz==Object.class || clazz==null) 774 return list.toArray(); 775 776 Object arr = java.lang.reflect.Array.newInstance(clazz, list.size()); 777 return list.toArray((Object[]) arr); 778 } 779 }